1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/*
2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2007 The Android Open Source Project
3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License.
6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at
7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *      http://www.apache.org/licenses/LICENSE-2.0
9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson *
10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software
11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and
14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License.
15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.android.dx.dex.code;
18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.dex.DexOptions;
20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.io.Opcodes;
21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.BasicBlock;
22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.BasicBlockList;
23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.FillArrayDataInsn;
24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.Insn;
25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.LocalVariableInfo;
26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.PlainCstInsn;
27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.PlainInsn;
28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.RegOps;
29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.RegisterSpec;
30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.RegisterSpecList;
31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.RegisterSpecSet;
32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.Rop;
33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.RopMethod;
34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.SourcePosition;
35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.SwitchInsn;
36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.ThrowingCstInsn;
37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.ThrowingInsn;
38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.Constant;
39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstInteger;
40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.Bits;
41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.IntList;
42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.ArrayList;
44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/**
46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Translator from {@link RopMethod} to {@link DalvCode}. The {@link
47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * #translate} method is the thing to call on this class.
48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */
49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic final class RopTranslator {
50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} options for dex output */
51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final DexOptions dexOptions;
52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} method to translate */
54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final RopMethod method;
55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * how much position info to preserve; one of the static
58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * constants in {@link PositionList}
59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final int positionInfo;
61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code null-ok;} local variable info to use */
63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final LocalVariableInfo locals;
64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} container for all the address objects for the method */
66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final BlockAddresses addresses;
67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} list of output instructions in-progress */
69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final OutputCollector output;
70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code non-null;} visitor to use during translation */
72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final TranslationVisitor translationVisitor;
73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code >= 0;} register count for the method */
75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final int regCount;
76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** {@code null-ok;} block output order; becomes non-null in {@link #pickOrder} */
78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private int[] order;
79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /** size, in register units, of all the parameters to this method */
81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private final int paramSize;
82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * true if the parameters to this method happen to be in proper order
85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * at the end of the frame (as the optimizer emits them)
86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private boolean paramsAreInOrder;
88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Translates a {@link RopMethod}. This may modify the given
91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * input.
92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param method {@code non-null;} the original method
94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param positionInfo how much position info to preserve; one of the
95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * static constants in {@link PositionList}
96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param locals {@code null-ok;} local variable information to use
97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param paramSize size, in register units, of all the parameters to
98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * this method
99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param dexOptions {@code non-null;} options for dex output
100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the translated version
101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    public static DalvCode translate(RopMethod method, int positionInfo,
103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            LocalVariableInfo locals, int paramSize, DexOptions dexOptions) {
104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        RopTranslator translator =
105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            new RopTranslator(method, positionInfo, locals, paramSize, dexOptions);
106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return translator.translateAndGetResult();
107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Constructs an instance. This method is private. Use {@link #translate}.
111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param method {@code non-null;} the original method
113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param positionInfo how much position info to preserve; one of the
114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * static constants in {@link PositionList}
115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param locals {@code null-ok;} local variable information to use
116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param paramSize size, in register units, of all the parameters to
117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * this method
118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param dexOptions {@code non-null;} options for dex output
119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private RopTranslator(RopMethod method, int positionInfo, LocalVariableInfo locals,
121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int paramSize, DexOptions dexOptions) {
122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.dexOptions = dexOptions;
123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.method = method;
124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.positionInfo = positionInfo;
125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.locals = locals;
126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.addresses = new BlockAddresses(method);
127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.paramSize = paramSize;
128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.order = null;
129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.paramsAreInOrder = calculateParamsAreInOrder(method, paramSize);
130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        BasicBlockList blocks = method.getBlocks();
132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int bsz = blocks.size();
133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Max possible instructions includes three code address
136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * objects per basic block (to the first and last instruction,
137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * and just past the end of the block), and the possibility of
138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * an extra goto at the end of each basic block.
139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int maxInsns = (bsz * 3) + blocks.getInstructionCount();
141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (locals != null) {
143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            /*
144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * If we're tracking locals, then there's could be another
145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * extra instruction per block (for the locals state at the
146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * start of the block) as well as one for each interblock
147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * local introduction.
148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             */
149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            maxInsns += bsz + locals.getAssignmentCount();
150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * If params are not in order, we will need register space
154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * for them before this is all over...
155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.regCount = blocks.getRegCount()
157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                + (paramsAreInOrder ? 0 : this.paramSize);
158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.output = new OutputCollector(dexOptions, maxInsns, bsz * 3, regCount);
160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (locals != null) {
162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.translationVisitor =
163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                new LocalVariableAwareTranslationVisitor(output, locals);
164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        } else {
165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.translationVisitor = new TranslationVisitor(output);
166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Checks to see if the move-param instructions that occur in this
171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * method happen to slot the params in an order at the top of the
172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * stack frame that matches dalvik's calling conventions. This will
173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * alway result in "true" for methods that have run through the
174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * SSA optimizer.
175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param paramSize size, in register units, of all the parameters
177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * to this method
178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static boolean calculateParamsAreInOrder(RopMethod method,
180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            final int paramSize) {
181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        final boolean[] paramsAreInOrder = { true };
182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        final int initialRegCount = method.getBlocks().getRegCount();
183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * We almost could just check the first block here, but the
186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * {@code cf} layer will put in a second move-param in a
187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * subsequent block in the case of synchronized methods.
188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        method.getBlocks().forEachInsn(new Insn.BaseVisitor() {
190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            @Override
191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            public void visitPlainCstInsn(PlainCstInsn insn) {
192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (insn.getOpcode().getOpcode()== RegOps.MOVE_PARAM) {
193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int param =
194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        ((CstInteger) insn.getConstant()).getValue();
195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    paramsAreInOrder[0] = paramsAreInOrder[0]
197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            && ((initialRegCount - paramSize + param)
198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                == insn.getResult().getReg());
199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        });
202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return paramsAreInOrder[0];
204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Does the translation and returns the result.
208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the result
210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private DalvCode translateAndGetResult() {
212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        pickOrder();
213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        outputInstructions();
214579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
215579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        StdCatchBuilder catches =
216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            new StdCatchBuilder(method, order, addresses);
217579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return new DalvCode(positionInfo, output.getFinisher(), catches);
219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
221579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Performs initial creation of output instructions based on the
223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * original blocks.
224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private void outputInstructions() {
226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        BasicBlockList blocks = method.getBlocks();
227579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int[] order = this.order;
228579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int len = order.length;
229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
230579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Process the blocks in output order.
231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < len; i++) {
232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int nextI = i + 1;
233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int nextLabel = (nextI == order.length) ? -1 : order[nextI];
234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            outputBlock(blocks.labelToBlock(order[i]), nextLabel);
235579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
239579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Helper for {@link #outputInstructions}, which does the processing
240579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * and output of one block.
241579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param block {@code non-null;} the block to process and output
243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param nextLabel {@code >= -1;} the next block that will be processed, or
244579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * {@code -1} if there is no next block
245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
246579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private void outputBlock(BasicBlock block, int nextLabel) {
247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Append the code address for this block.
248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        CodeAddress startAddress = addresses.getStart(block);
249579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        output.add(startAddress);
250579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
251579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Append the local variable state for the block.
252579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (locals != null) {
253579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            RegisterSpecSet starts = locals.getStarts(block);
254579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            output.add(new LocalSnapshot(startAddress.getPosition(),
255579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                         starts));
256579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
257579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
258579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Choose and append an output instruction for each original
260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * instruction.
261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        translationVisitor.setBlock(block, addresses.getLast(block));
263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        block.getInsns().forEach(translationVisitor);
264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
265579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Insert the block end code address.
266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        output.add(addresses.getEnd(block));
267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        // Set up for end-of-block activities.
269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int succ = block.getPrimarySuccessor();
271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        Insn lastInsn = block.getLastInsn();
272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Check for (and possibly correct for) a non-optimal choice of
275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * which block will get output next.
276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if ((succ >= 0) && (succ != nextLabel)) {
279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            /*
280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * The block has a "primary successor" and that primary
281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * successor isn't the next block to be output.
282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             */
283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Rop lastRop = lastInsn.getOpcode();
284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if ((lastRop.getBranchingness() == Rop.BRANCH_IF) &&
285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    (block.getSecondarySuccessor() == nextLabel)) {
286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                /*
287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * The block ends with an "if" of some sort, and its
288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * secondary successor (the "then") is in fact the
289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * next block to output. So, reverse the sense of
290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * the test, so that we can just emit the next block
291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * without an interstitial goto.
292579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 */
293579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                output.reverseBranch(1, addresses.getStart(succ));
294579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else {
295579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                /*
296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * Our only recourse is to add a goto here to get the
297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * flow to be correct.
298579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 */
299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                TargetInsn insn =
300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    new TargetInsn(Dops.GOTO, lastInsn.getPosition(),
301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            RegisterSpecList.EMPTY,
302579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            addresses.getStart(succ));
303579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                output.add(insn);
304579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
305579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
306579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
307579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
308579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
309579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Picks an order for the blocks by doing "trace" analysis.
310579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
311579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private void pickOrder() {
312579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        BasicBlockList blocks = method.getBlocks();
313579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int sz = blocks.size();
314579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int maxLabel = blocks.getMaxLabel();
315579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int[] workSet = Bits.makeBitSet(maxLabel);
316579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int[] tracebackSet = Bits.makeBitSet(maxLabel);
317579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
318579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int i = 0; i < sz; i++) {
319579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            BasicBlock one = blocks.get(i);
320579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Bits.set(workSet, one.getLabel());
321579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
322579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
323579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int[] order = new int[sz];
324579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        int at = 0;
325579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
326579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /*
327579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Starting with the designated "first label" (that is, the
328579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * first block of the method), add that label to the order,
329579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * and then pick its first as-yet unordered successor to
330579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * immediately follow it, giving top priority to the primary
331579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * (aka default) successor (if any). Keep following successors
332579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * until the trace runs out of possibilities. Then, continue
333579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * by finding an unordered chain containing the first as-yet
334579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * unordered block, and adding it to the order, and so on.
335579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
336579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        for (int label = method.getFirstLabel();
337579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             label != -1;
338579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             label = Bits.findFirst(workSet, 0)) {
339579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
340579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            /*
341579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * Attempt to trace backward from the chosen block to an
342579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * as-yet unordered predecessor which lists the chosen
343579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * block as its primary successor, and so on, until we
344579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * fail to find such an unordered predecessor. Start the
345579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * trace with that block. Note that the first block in the
346579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * method has no predecessors, so in that case this loop
347579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * will simply terminate with zero iterations and without
348579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * picking a new starter block.
349579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             */
350579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            traceBack:
351579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            for (;;) {
352579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                IntList preds = method.labelToPredecessors(label);
353579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                int psz = preds.size();
354579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
355579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                for (int i = 0; i < psz; i++) {
356579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int predLabel = preds.get(i);
357579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
358579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    if (Bits.get(tracebackSet, predLabel)) {
359579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        /*
360579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         * We found a predecessor loop; stop tracing back
361579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         * from here.
362579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                         */
363579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        break;
364579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    }
365579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
366579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    if (!Bits.get(workSet, predLabel)) {
367579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        // This one's already ordered.
368579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        continue;
369579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    }
370579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
371579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    BasicBlock pred = blocks.labelToBlock(predLabel);
372579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    if (pred.getPrimarySuccessor() == label) {
373579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        // Found one!
374579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        label = predLabel;
375579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        Bits.set(tracebackSet, label);
376579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        continue traceBack;
377579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    }
378579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
379579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
380579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                // Failed to find a better block to start the trace.
381579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                break;
382579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
383579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
384579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            /*
385579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * Trace a path from the chosen block to one of its
386579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * unordered successors (hopefully the primary), and so
387579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * on, until we run out of unordered successors.
388579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             */
389579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            while (label != -1) {
390579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                Bits.clear(workSet, label);
391579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                Bits.clear(tracebackSet, label);
392579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                order[at] = label;
393579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                at++;
394579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
395579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                BasicBlock one = blocks.labelToBlock(label);
396579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                BasicBlock preferredBlock = blocks.preferredSuccessorOf(one);
397579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
398579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (preferredBlock == null) {
399579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    break;
400579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
401579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
402579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                int preferred = preferredBlock.getLabel();
403579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                int primary = one.getPrimarySuccessor();
404579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
405579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (Bits.get(workSet, preferred)) {
406579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    /*
407579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * Order the current block's preferred successor
408579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * next, as it has yet to be scheduled.
409579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     */
410579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    label = preferred;
411579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                } else if ((primary != preferred) && (primary >= 0)
412579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        && Bits.get(workSet, primary)) {
413579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    /*
414579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * The primary is available, so use that.
415579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     */
416579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    label = primary;
417579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                } else {
418579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    /*
419579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * There's no obvious candidate, so pick the first
420579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * one that's available, if any.
421579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     */
422579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    IntList successors = one.getSuccessors();
423579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int ssz = successors.size();
424579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    label = -1;
425579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    for (int i = 0; i < ssz; i++) {
426579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        int candidate = successors.get(i);
427579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        if (Bits.get(workSet, candidate)) {
428579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            label = candidate;
429579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            break;
430579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        }
431579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    }
432579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
433579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
434579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
435579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
436579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (at != sz) {
437579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            // There was a duplicate block label.
438579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            throw new RuntimeException("shouldn't happen");
439579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
440579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
441579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        this.order = order;
442579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
443579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
444579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
445579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the complete register list (result and sources) out of a
446579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * given rop instruction. For insns that are commutative, have
447579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * two register sources, and have a source equal to the result,
448579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * place that source first.
449579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
450579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param insn {@code non-null;} instruction in question
451579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the instruction's complete register list
452579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
453579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static RegisterSpecList getRegs(Insn insn) {
454579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return getRegs(insn, insn.getResult());
455579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
456579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
457579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
458579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Gets the complete register list (result and sources) out of a
459579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * given rop instruction. For insns that are commutative, have
460579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * two register sources, and have a source equal to the result,
461579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * place that source first.
462579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     *
463579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param insn {@code non-null;} instruction in question
464579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @param resultReg {@code null-ok;} the real result to use (ignore the insn's)
465579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * @return {@code non-null;} the instruction's complete register list
466579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
467579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private static RegisterSpecList getRegs(Insn insn,
468579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            RegisterSpec resultReg) {
469579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        RegisterSpecList regs = insn.getSources();
470579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
471579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (insn.getOpcode().isCommutative()
472579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                && (regs.size() == 2)
473579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                && (resultReg.getReg() == regs.get(1).getReg())) {
474579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
475579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            /*
476579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * For commutative ops which have two register sources,
477579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * if the second source is the same register as the result,
478579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * swap the sources so that an opcode of form 12x can be selected
479579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * instead of one of form 23x
480579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             */
481579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
482579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            regs = RegisterSpecList.make(regs.get(1), regs.get(0));
483579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
484579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
485579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        if (resultReg == null) {
486579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            return regs;
487579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
488579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
489579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        return regs.withFirst(resultReg);
490579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
491579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
492579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
493579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Instruction visitor class for doing the instruction translation per se.
494579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
495579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private class TranslationVisitor implements Insn.Visitor {
496579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@code non-null;} list of output instructions in-progress */
497579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private final OutputCollector output;
498579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
499579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@code non-null;} basic block being worked on */
500579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private BasicBlock block;
501579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
502579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
503579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * {@code null-ok;} code address for the salient last instruction of the
504579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * block (used before switches and throwing instructions)
505579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
506579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private CodeAddress lastAddress;
507579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
508579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
509579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Constructs an instance.
510579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
511579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param output {@code non-null;} destination for instruction output
512579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
513579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public TranslationVisitor(OutputCollector output) {
514579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.output = output;
515579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
516579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
517579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
518579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Sets the block currently being worked on.
519579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
520579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param block {@code non-null;} the block
521579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param lastAddress {@code non-null;} code address for the salient
522579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * last instruction of the block
523579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
524579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void setBlock(BasicBlock block, CodeAddress lastAddress) {
525579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.block = block;
526579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.lastAddress = lastAddress;
527579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
528579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
529579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
530579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitPlainInsn(PlainInsn insn) {
531579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Rop rop = insn.getOpcode();
532579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (rop.getOpcode() == RegOps.MARK_LOCAL) {
533579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                /*
534579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * Ignore these. They're dealt with by
535579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 * the LocalVariableAwareTranslationVisitor
536579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                 */
537579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return;
538579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
539579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (rop.getOpcode() == RegOps.MOVE_RESULT_PSEUDO) {
540579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                // These get skipped
541579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return;
542579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
543579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
544579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            SourcePosition pos = insn.getPosition();
545579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Dop opcode = RopToDop.dopFor(insn);
546579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            DalvInsn di;
547579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
548579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            switch (rop.getBranchingness()) {
549579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                case Rop.BRANCH_NONE:
550579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                case Rop.BRANCH_RETURN:
551579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                case Rop.BRANCH_THROW: {
552579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    di = new SimpleInsn(opcode, pos, getRegs(insn));
553579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    break;
554579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
555579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                case Rop.BRANCH_GOTO: {
556579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    /*
557579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * Code in the main translation loop will emit a
558579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * goto if necessary (if the branch isn't to the
559579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * immediately subsequent block).
560579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     */
561579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    return;
562579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
563579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                case Rop.BRANCH_IF: {
564579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int target = block.getSuccessors().get(1);
565579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    di = new TargetInsn(opcode, pos, getRegs(insn),
566579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                        addresses.getStart(target));
567579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    break;
568579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
569579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                default: {
570579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    throw new RuntimeException("shouldn't happen");
571579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
572579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
573579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
574579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addOutput(di);
575579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
576579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
577579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
578579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitPlainCstInsn(PlainCstInsn insn) {
579579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            SourcePosition pos = insn.getPosition();
580579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Dop opcode = RopToDop.dopFor(insn);
581579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Rop rop = insn.getOpcode();
582579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int ropOpcode = rop.getOpcode();
583579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            DalvInsn di;
584579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
585579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (rop.getBranchingness() != Rop.BRANCH_NONE) {
586579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new RuntimeException("shouldn't happen");
587579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
588579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
589579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (ropOpcode == RegOps.MOVE_PARAM) {
590579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (!paramsAreInOrder) {
591579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    /*
592579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * Parameters are not in order at the top of the reg space.
593579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * We need to add moves.
594579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     */
595579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
596579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    RegisterSpec dest = insn.getResult();
597579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    int param =
598579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        ((CstInteger) insn.getConstant()).getValue();
599579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    RegisterSpec source =
600579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        RegisterSpec.make(regCount - paramSize + param,
601579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                dest.getType());
602579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    di = new SimpleInsn(opcode, pos,
603579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                        RegisterSpecList.make(dest, source));
604579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    addOutput(di);
605579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
606579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else {
607579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                // No moves required for the parameters
608579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList regs = getRegs(insn);
609579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                di = new CstInsn(opcode, pos, regs, insn.getConstant());
610579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                addOutput(di);
611579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
612579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
613579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
614579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
615579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitSwitchInsn(SwitchInsn insn) {
616579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            SourcePosition pos = insn.getPosition();
617579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            IntList cases = insn.getCases();
618579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            IntList successors = block.getSuccessors();
619579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int casesSz = cases.size();
620579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int succSz = successors.size();
621579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int primarySuccessor = block.getPrimarySuccessor();
622579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
623579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            /*
624579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * Check the assumptions that the number of cases is one
625579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * less than the number of successors and that the last
626579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * successor in the list is the primary (in this case, the
627579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * default). This test is here to guard against forgetting
628579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * to change this code if the way switch instructions are
629579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             * constructed also gets changed.
630579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson             */
631579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if ((casesSz != (succSz - 1)) ||
632579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                (primarySuccessor != successors.get(casesSz))) {
633579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new RuntimeException("shouldn't happen");
634579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
635579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
636579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            CodeAddress[] switchTargets = new CodeAddress[casesSz];
637579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
638579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            for (int i = 0; i < casesSz; i++) {
639579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                int label = successors.get(i);
640579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                switchTargets[i] = addresses.getStart(label);
641579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
642579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
643579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            CodeAddress dataAddress = new CodeAddress(pos);
644579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            SwitchData dataInsn =
645579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                new SwitchData(pos, lastAddress, cases, switchTargets);
646579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Dop opcode = dataInsn.isPacked() ?
647579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                Dops.PACKED_SWITCH : Dops.SPARSE_SWITCH;
648579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            TargetInsn switchInsn =
649579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                new TargetInsn(opcode, pos, getRegs(insn), dataAddress);
650579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
651579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addOutput(lastAddress);
652579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addOutput(switchInsn);
653579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
654579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addOutputSuffix(new OddSpacer(pos));
655579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addOutputSuffix(dataAddress);
656579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addOutputSuffix(dataInsn);
657579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
658579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
659579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
660579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Looks forward to the current block's primary successor, returning
661579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * the RegisterSpec of the result of the move-result-pseudo at the
662579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * top of that block or null if none.
663579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
664579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @return {@code null-ok;} result of move-result-pseudo at the beginning of
665579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * primary successor
666579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
667579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private RegisterSpec getNextMoveResultPseudo()
668579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        {
669579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            int label = block.getPrimarySuccessor();
670579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
671579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (label < 0) {
672579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return null;
673579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
674579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
675579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Insn insn
676579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    = method.getBlocks().labelToBlock(label).getInsns().get(0);
677579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
678579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (insn.getOpcode().getOpcode() != RegOps.MOVE_RESULT_PSEUDO) {
679579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return null;
680579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else {
681579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                return insn.getResult();
682579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
683579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
684579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
685579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
686579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitThrowingCstInsn(ThrowingCstInsn insn) {
687579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            SourcePosition pos = insn.getPosition();
688579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Dop opcode = RopToDop.dopFor(insn);
689579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Rop rop = insn.getOpcode();
690579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Constant cst = insn.getConstant();
691579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
692579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (rop.getBranchingness() != Rop.BRANCH_THROW) {
693579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new RuntimeException("shouldn't happen");
694579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
695579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
696579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addOutput(lastAddress);
697579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
698579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (rop.isCallLike()) {
699579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList regs = insn.getSources();
700579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                DalvInsn di = new CstInsn(opcode, pos, regs, cst);
701579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
702579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                addOutput(di);
703579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            } else {
704579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpec realResult = getNextMoveResultPseudo();
705579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
706579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                RegisterSpecList regs = getRegs(insn, realResult);
707579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                DalvInsn di;
708579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
709579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                boolean hasResult = opcode.hasResult()
710579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        || (rop.getOpcode() == RegOps.CHECK_CAST);
711579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
712579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if (hasResult != (realResult != null)) {
713579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    throw new RuntimeException(
714579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            "Insn with result/move-result-pseudo mismatch " +
715579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                            insn);
716579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
717579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
718579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                if ((rop.getOpcode() == RegOps.NEW_ARRAY) &&
719579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    (opcode.getOpcode() != Opcodes.NEW_ARRAY)) {
720579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    /*
721579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * It's a type-specific new-array-<primitive>, and
722579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * so it should be turned into a SimpleInsn (no
723579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * constant ref as it's implicit).
724579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     */
725579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    di = new SimpleInsn(opcode, pos, regs);
726579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                } else {
727579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    /*
728579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * This is the general case for constant-bearing
729579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     * instructions.
730579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                     */
731579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    di = new CstInsn(opcode, pos, regs, cst);
732579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                }
733579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
734579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                addOutput(di);
735579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
736579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
737579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
738579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
739579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitThrowingInsn(ThrowingInsn insn) {
740579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            SourcePosition pos = insn.getPosition();
741579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Dop opcode = RopToDop.dopFor(insn);
742579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Rop rop = insn.getOpcode();
743579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            RegisterSpec realResult;
744579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
745579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (rop.getBranchingness() != Rop.BRANCH_THROW) {
746579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new RuntimeException("shouldn't happen");
747579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
748579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
749579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            realResult = getNextMoveResultPseudo();
750579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
751579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (opcode.hasResult() != (realResult != null)) {
752579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new RuntimeException(
753579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        "Insn with result/move-result-pseudo mismatch" + insn);
754579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
755579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
756579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addOutput(lastAddress);
757579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
758579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            DalvInsn di = new SimpleInsn(opcode, pos,
759579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                    getRegs(insn, realResult));
760579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
761579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addOutput(di);
762579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
763579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
764579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
765579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitFillArrayDataInsn(FillArrayDataInsn insn) {
766579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            SourcePosition pos = insn.getPosition();
767579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Constant cst = insn.getConstant();
768579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            ArrayList<Constant> values = insn.getInitValues();
769579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            Rop rop = insn.getOpcode();
770579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
771579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (rop.getBranchingness() != Rop.BRANCH_NONE) {
772579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                throw new RuntimeException("shouldn't happen");
773579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
774579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            CodeAddress dataAddress = new CodeAddress(pos);
775579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            ArrayData dataInsn =
776579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                new ArrayData(pos, lastAddress, values, cst);
777579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
778579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            TargetInsn fillArrayDataInsn =
779579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                new TargetInsn(Dops.FILL_ARRAY_DATA, pos, getRegs(insn),
780579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                        dataAddress);
781579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
782579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addOutput(lastAddress);
783579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addOutput(fillArrayDataInsn);
784579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
785579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addOutputSuffix(new OddSpacer(pos));
786579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addOutputSuffix(dataAddress);
787579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addOutputSuffix(dataInsn);
788579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
789579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
790579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
791579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Adds to the output.
792579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
793579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param insn {@code non-null;} instruction to add
794579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
795579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        protected void addOutput(DalvInsn insn) {
796579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            output.add(insn);
797579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
798579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
799579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
800579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Adds to the output suffix.
801579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
802579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param insn {@code non-null;} instruction to add
803579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
804579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        protected void addOutputSuffix(DalvInsn insn) {
805579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            output.addSuffix(insn);
806579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
807579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
808579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
809579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    /**
810579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * Instruction visitor class for doing instruction translation with
811579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     * local variable tracking
812579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson     */
813579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    private class LocalVariableAwareTranslationVisitor
814579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            extends TranslationVisitor {
815579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@code non-null;} local variable info */
816579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        private LocalVariableInfo locals;
817579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
818579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
819579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Constructs an instance.
820579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
821579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param output {@code non-null;} destination for instruction output
822579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param locals {@code non-null;} the local variable info
823579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
824579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public LocalVariableAwareTranslationVisitor(OutputCollector output,
825579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                                                    LocalVariableInfo locals) {
826579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            super(output);
827579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            this.locals = locals;
828579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
829579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
830579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
831579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        @Override
832579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitPlainInsn(PlainInsn insn) {
833579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            super.visitPlainInsn(insn);
834579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addIntroductionIfNecessary(insn);
835579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
836579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
837579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
838579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        @Override
839579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitPlainCstInsn(PlainCstInsn insn) {
840579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            super.visitPlainCstInsn(insn);
841579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addIntroductionIfNecessary(insn);
842579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
843579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
844579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
845579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        @Override
846579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitSwitchInsn(SwitchInsn insn) {
847579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            super.visitSwitchInsn(insn);
848579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addIntroductionIfNecessary(insn);
849579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
850579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
851579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
852579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        @Override
853579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitThrowingCstInsn(ThrowingCstInsn insn) {
854579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            super.visitThrowingCstInsn(insn);
855579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addIntroductionIfNecessary(insn);
856579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
857579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
858579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /** {@inheritDoc} */
859579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        @Override
860579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void visitThrowingInsn(ThrowingInsn insn) {
861579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            super.visitThrowingInsn(insn);
862579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            addIntroductionIfNecessary(insn);
863579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
864579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
865579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        /**
866579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * Adds a {@link LocalStart} to the output if the given
867579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * instruction in fact introduces a local variable.
868579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         *
869579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         * @param insn {@code non-null;} instruction in question
870579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson         */
871579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        public void addIntroductionIfNecessary(Insn insn) {
872579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            RegisterSpec spec = locals.getAssignment(insn);
873579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson
874579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            if (spec != null) {
875579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson                addOutput(new LocalStart(insn.getPosition(), spec));
876579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson            }
877579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson        }
878579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson    }
879579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson}
880