1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage com.android.dx.cf.code;
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
19fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.AccessFlags;
20fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.BasicBlock;
21fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.BasicBlockList;
22fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.Insn;
23fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.InsnList;
24fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.PlainCstInsn;
25fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.PlainInsn;
26fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.RegisterSpec;
27fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.RegisterSpecList;
28fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.Rop;
29fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.RopMethod;
30fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.Rops;
31fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.SourcePosition;
32fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.ThrowingCstInsn;
33fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.ThrowingInsn;
34fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dx.rop.code.TranslationAdvice;
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstInteger;
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstType;
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.Prototype;
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.StdTypeList;
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.Type;
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.TypeList;
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.Bits;
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.Hex;
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.IntList;
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.ArrayList;
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.BitSet;
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.HashMap;
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Utility that converts a basic block list into a list of register-oriented
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * blocks.
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic final class Ropper {
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** label offset for the parameter assignment block */
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int PARAM_ASSIGNMENT = -1;
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** label offset for the return block */
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int RETURN = -2;
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** label offset for the synchronized method final return block */
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int SYNCH_RETURN = -3;
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** label offset for the first synchronized method setup block */
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int SYNCH_SETUP_1 = -4;
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** label offset for the second synchronized method setup block */
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int SYNCH_SETUP_2 = -5;
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * label offset for the first synchronized method exception
7039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * handler block
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int SYNCH_CATCH_1 = -6;
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * label offset for the second synchronized method exception
7639c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * handler block
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int SYNCH_CATCH_2 = -7;
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** number of special label offsets */
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int SPECIAL_LABEL_COUNT = 7;
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
8399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} method being converted */
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final ConcreteMethod method;
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
8699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} original block list */
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final ByteBlockList blocks;
88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** max locals of the method */
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final int maxLocals;
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** max label (exclusive) of any original bytecode block */
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final int maxLabel;
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
9599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} simulation machine to use */
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final RopperMachine machine;
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
9899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} simulator to use */
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final Simulator sim;
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
10239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * {@code non-null;} sparse array mapping block labels to initial frame
10339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * contents, if known
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final Frame[] startFrames;
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
10799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} output block list in-progress */
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final ArrayList<BasicBlock> result;
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
11199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code non-null;} list of subroutine-nest labels
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * (See {@link Frame#getSubroutines} associated with each result block.
11339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * Parallel to {@link Ropper#result}.
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final ArrayList<IntList> resultSubroutines;
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
11899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code non-null;} for each block (by label) that is used as an exception
11939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * handler, the type of exception it catches
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final Type[] catchTypes;
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * whether an exception-handler block for a synchronized method was
12539c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * ever required
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean synchNeedsExceptionHandler;
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
12939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein    /**
13039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * {@code non-null;} list of subroutines indexed by label of start
13139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * address */
13239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein    private final Subroutine[] subroutines;
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
13499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** true if {@code subroutines} is non-empty */
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean hasSubroutines;
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Keeps track of subroutines that exist in java form and are inlined in
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Rop form.
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private class Subroutine {
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** list of all blocks that jsr to this subroutine */
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private BitSet callerBlocks;
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** List of all blocks that return from this subroutine */
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private BitSet retBlocks;
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** first block in this subroutine */
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private int startBlock;
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Constructs instance.
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param startBlock First block of the subroutine.
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Subroutine(int startBlock) {
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.startBlock = startBlock;
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            retBlocks = new BitSet(maxLabel);
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            callerBlocks = new BitSet(maxLabel);
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            hasSubroutines = true;
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Constructs instance.
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param startBlock First block of the subroutine.
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param retBlock one of the ret blocks (final blocks) of this
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * subroutine.
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Subroutine(int startBlock, int retBlock) {
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this(startBlock);
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            addRetBlock(retBlock);
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
17499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @return {@code >= 0;} the label of the subroutine's start block.
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int getStartBlock() {
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return startBlock;
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Adds a label to the list of ret blocks (final blocks) for this
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * subroutine.
18339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         *
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param retBlock ret block label
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        void addRetBlock(int retBlock) {
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            retBlocks.set(retBlock);
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Adds a label to the list of caller blocks for this subroutine.
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param label a block that invokes this subroutine.
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        void addCallerBlock(int label) {
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            callerBlocks.set(label);
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Generates a list of subroutine successors. Note: successor blocks
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * could be listed more than once. This is ok, because this successor
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * list (and the block it's associated with) will be copied and inlined
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * before we leave the ropper. Redundent successors will result in
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * redundent (no-op) merges.
20539c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         *
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @return all currently known successors
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * (return destinations) for that subroutine
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        IntList getSuccessors() {
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            IntList successors = new IntList(callerBlocks.size());
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
21341aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein             * For each subroutine caller, get it's target. If the
21441aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein             * target is us, add the ret target (subroutine successor)
21541aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein             * to our list
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
21841aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein            for (int label = callerBlocks.nextSetBit(0); label >= 0;
21941aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein                 label = callerBlocks.nextSetBit(label+1)) {
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                BasicBlock subCaller = labelToBlock(label);
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                successors.add(subCaller.getSuccessors().get(0));
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            successors.setImmutable();
22539c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return successors;
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Merges the specified frame into this subroutine's successors,
23199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * setting {@code workSet} as appropriate. To be called with
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * the frame of a subroutine ret block.
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
23499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param frame {@code non-null;} frame from ret block to merge
23599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param workSet {@code non-null;} workset to update
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        void mergeToSuccessors(Frame frame, int[] workSet) {
23841aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein            for (int label = callerBlocks.nextSetBit(0); label >= 0;
23941aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein                 label = callerBlocks.nextSetBit(label+1)) {
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                BasicBlock subCaller = labelToBlock(label);
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int succLabel = subCaller.getSuccessors().get(0);
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Frame subFrame = frame.subFrameForLabel(startBlock, label);
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (subFrame != null) {
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    mergeAndWorkAsNecessary(succLabel, -1, null,
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            subFrame, workSet);
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else {
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    Bits.set(workSet, label);
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Converts a {@link ConcreteMethod} to a {@link RopMethod}.
25739c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
25899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param method {@code non-null;} method to convert
25999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param advice {@code non-null;} translation advice to use
26099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the converted instance
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public static RopMethod convert(ConcreteMethod method,
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            TranslationAdvice advice) {
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Ropper r = new Ropper(method, advice);
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            r.doit();
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return r.getRopMethod();
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (SimException ex) {
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ex.addContext("...while working on method " +
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                          method.getNat().toHuman());
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw ex;
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs an instance. This class is not publicly instantiable; use
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * {@link #convert}.
27839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
27999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param method {@code non-null;} method to convert
28099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param advice {@code non-null;} translation advice to use
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private Ropper(ConcreteMethod method, TranslationAdvice advice) {
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (method == null) {
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("method == null");
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (advice == null) {
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("advice == null");
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.method = method;
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.blocks = BasicBlocker.identifyBlocks(method);
293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.maxLabel = blocks.getMaxLabel();
294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.maxLocals = method.getMaxLocals();
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.machine = new RopperMachine(this, method, advice);
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.sim = new Simulator(machine, method);
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.startFrames = new Frame[maxLabel];
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.subroutines = new Subroutine[maxLabel];
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * The "* 2 + 10" below is to conservatively believe that every
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * block is an exception handler target and should also
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * take care of enough other possible extra overhead such that
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * the underlying array is unlikely to need resizing.
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.result = new ArrayList<BasicBlock>(blocks.size() * 2 + 10);
30739c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein        this.resultSubroutines =
30839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein            new ArrayList<IntList>(blocks.size() * 2 + 10);
309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.catchTypes = new Type[maxLabel];
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.synchNeedsExceptionHandler = false;
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Set up the first stack frame with the right limits, but leave it
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * empty here (to be filled in outside of the constructor).
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        startFrames[0] = new Frame(maxLocals, method.getMaxStack());
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the first (lowest) register number to use as the temporary
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * area when unwinding stack manipulation ops.
32339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
32499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the first register to use
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*package*/ int getFirstTempStackReg() {
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * We use the register that is just past the deepest possible
329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * stack element, plus one if the method is synchronized to
330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * avoid overlapping with the synch register. We don't need to
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * do anything else special at this level, since later passes
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * will merely notice the highest register used by explicit
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * inspection.
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int regCount = getNormalRegCount();
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return isSynchronized() ? regCount + 1 : regCount;
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the label for the exception handler setup block corresponding
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * to the given label.
34239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
34399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param label {@code >= 0;} the original label
34499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the corresponding exception handler setup label
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int getExceptionSetupLabel(int label) {
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return maxLabel + label;
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the label for the given special-purpose block. The given label
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * should be one of the static constants defined by this class.
35339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
35499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param label {@code < 0;} the special label constant
35599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the actual label value to use
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int getSpecialLabel(int label) {
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * The label is bitwise-complemented so that mistakes where
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * LABEL is used instead of getSpecialLabel(LABEL) cause a
361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * failure at block construction time, since negative labels
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * are illegal. We multiply maxLabel by 2 since 0..maxLabel
363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * (exclusive) are the original blocks and
364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * maxLabel..(maxLabel*2) are reserved for exception handler
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * setup blocks (see getExceptionSetupLabel(), above).
366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return (maxLabel * 2) + ~label;
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the minimum label for unreserved use.
37239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
37399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the minimum label
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int getMinimumUnreservedLabel() {
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * The labels below ((maxLabel * 2) + SPECIAL_LABEL_COUNT) are
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * reserved for particular uses.
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return (maxLabel * 2) + SPECIAL_LABEL_COUNT;
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets an arbitrary unreserved and available label.
38639c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
38799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the label
388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int getAvailableLabel() {
390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int candidate = getMinimumUnreservedLabel();
391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (BasicBlock bb : result) {
393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int label = bb.getLabel();
394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (label >= candidate) {
395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                candidate = label + 1;
396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return candidate;
400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets whether the method being translated is synchronized.
40439c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether the method being translated is synchronized
406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
407f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean isSynchronized() {
408f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int accessFlags = method.getAccessFlags();
409f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return (accessFlags & AccessFlags.ACC_SYNCHRONIZED) != 0;
410f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
411f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
412f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
413f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets whether the method being translated is static.
41439c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether the method being translated is static
416f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean isStatic() {
418f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int accessFlags = method.getAccessFlags();
419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return (accessFlags & AccessFlags.ACC_STATIC) != 0;
420f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
421f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
422f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
423f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the total number of registers used for "normal" purposes (i.e.,
424f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * for the straightforward translation from the original Java).
42539c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
42699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the total number of registers used
427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
428f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int getNormalRegCount() {
429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return maxLocals + method.getMaxStack();
430f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
433f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the register spec to use to hold the object to synchronize on,
434f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * for a synchronized method.
43539c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
43699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the register spec
437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
438f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private RegisterSpec getSynchReg() {
439f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
440f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * We use the register that is just past the deepest possible
441c51439a513d4cc3c2be4a7cce7b3e9ae480fd5c2Dan Bornstein         * stack element, with a minimum of v1 since v0 is what's
442c51439a513d4cc3c2be4a7cce7b3e9ae480fd5c2Dan Bornstein         * always used to hold the caught exception when unwinding. We
443c51439a513d4cc3c2be4a7cce7b3e9ae480fd5c2Dan Bornstein         * don't need to do anything else special at this level, since
444c51439a513d4cc3c2be4a7cce7b3e9ae480fd5c2Dan Bornstein         * later passes will merely notice the highest register used
445c51439a513d4cc3c2be4a7cce7b3e9ae480fd5c2Dan Bornstein         * by explicit inspection.
446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
447c51439a513d4cc3c2be4a7cce7b3e9ae480fd5c2Dan Bornstein        int reg = getNormalRegCount();
448c51439a513d4cc3c2be4a7cce7b3e9ae480fd5c2Dan Bornstein        return RegisterSpec.make((reg < 1) ? 1 : reg, Type.OBJECT);
449f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
451f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
45239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * Searches {@link #result} for a block with the given label. Returns its
45339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * index if found, or returns {@code -1} if there is no such block.
45439c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param label the label to look for
45699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= -1;} the index for the block with the given label or
45799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code -1} if there is no such block
458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int labelToResultIndex(int label) {
460f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = result.size();
461f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < sz; i++) {
462f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            BasicBlock one = result.get(i);
463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (one.getLabel() == label) {
464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return i;
465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return -1;
46939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein    }
470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
47239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * Searches {@link #result} for a block with the given label. Returns it if
47339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * found, or throws an exception if there is no such block.
47439c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param label the label to look for
47699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the block with the given label
477f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
478f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private BasicBlock labelToBlock(int label) {
479f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int idx = labelToResultIndex(label);
480f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
481f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (idx < 0) {
482f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalArgumentException("no such label " +
483f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    Hex.u2(label));
484f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
485f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return result.get(idx);
487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
488f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
490f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Adds a block to the output result.
49139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
49299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param block {@code non-null;} the block to add
49339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @param subroutines {@code non-null;} subroutine label list
49439c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * as described in {@link Frame#getSubroutines}
495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
496f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void addBlock(BasicBlock block, IntList subroutines) {
497f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (block == null) {
498f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("block == null");
499f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        result.add(block);
502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        subroutines.throwIfMutable();
503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        resultSubroutines.add(subroutines);
504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Adds or replace a block in the output result. If this is a
508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * replacement, then any extra blocks that got added with the
509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * original get removed as a result of calling this method.
51039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
51199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param block {@code non-null;} the block to add or replace
51239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @param subroutines {@code non-null;} subroutine label list
51339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * as described in {@link Frame#getSubroutines}
51499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code true} if the block was replaced or
51599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code false} if it was added for the first time
516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
517f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean addOrReplaceBlock(BasicBlock block, IntList subroutines) {
518f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (block == null) {
519f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("block == null");
520f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
521f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
522f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int idx = labelToResultIndex(block.getLabel());
523f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean ret;
524f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
525f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (idx < 0) {
526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ret = false;
527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * We are replacing a pre-existing block, so find any
530f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * blocks that got added as part of the original and
531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * remove those too. Such blocks are (possibly indirect)
532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * successors of this block which are out of the range of
533f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * normally-translated blocks.
534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            removeBlockAndSpecialSuccessors(idx);
536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ret = true;
537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
539f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        result.add(block);
540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        subroutines.throwIfMutable();
541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        resultSubroutines.add(subroutines);
542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return ret;
543f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
544f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
545f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
546f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Adds or replaces a block in the output result. Do not delete
547f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * any successors.
548f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
54999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param block {@code non-null;} the block to add or replace
55039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @param subroutines {@code non-null;} subroutine label list
55139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * as described in {@link Frame#getSubroutines}
55299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code true} if the block was replaced or
55399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code false} if it was added for the first time
554f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
555f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean addOrReplaceBlockNoDelete(BasicBlock block,
556f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            IntList subroutines) {
557f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (block == null) {
558f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("block == null");
559f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
560f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
561f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int idx = labelToResultIndex(block.getLabel());
562f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean ret;
563f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
564f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (idx < 0) {
565f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ret = false;
566f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
567f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            result.remove(idx);
568f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            resultSubroutines.remove(idx);
569f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ret = true;
570f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
571f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
572f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        result.add(block);
573f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        subroutines.throwIfMutable();
574f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        resultSubroutines.add(subroutines);
575f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return ret;
576f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
577f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
578f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
579f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Helper for {@link #addOrReplaceBlock} which recursively removes
580f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the given block and all blocks that are (direct and indirect)
581f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * successors of it whose labels indicate that they are not in the
582f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * normally-translated range.
58339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
58499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param idx {@code non-null;} block to remove (etc.)
585f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
586f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void removeBlockAndSpecialSuccessors(int idx) {
587f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int minLabel = getMinimumUnreservedLabel();
588f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        BasicBlock block = result.get(idx);
589f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        IntList successors = block.getSuccessors();
590f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = successors.size();
591f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
592f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        result.remove(idx);
593f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        resultSubroutines.remove(idx);
594f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
595f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < sz; i++) {
596f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int label = successors.get(i);
597f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (label >= minLabel) {
598f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                idx = labelToResultIndex(label);
599f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (idx < 0) {
600f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new RuntimeException("Invalid label "
601f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            + Hex.u2(label));
602f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
603f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                removeBlockAndSpecialSuccessors(idx);
604f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
605f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
606f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
607f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
608f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
609f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Extracts the resulting {@link RopMethod} from the instance.
61039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
61199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the method object
612f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
613f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private RopMethod getRopMethod() {
614f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
615f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Construct the final list of blocks.
616f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
617f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = result.size();
618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        BasicBlockList bbl = new BasicBlockList(sz);
619f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < sz; i++) {
620f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            bbl.set(i, result.get(i));
621f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
622f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bbl.setImmutable();
623f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
624f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Construct the method object to wrap it all up.
625f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
626f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
627f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Note: The parameter assignment block is always the first
628f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * that should be executed, hence the second argument to the
629f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * constructor.
630f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
631f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return new RopMethod(bbl, getSpecialLabel(PARAM_ASSIGNMENT));
632f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
633f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
634f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
635f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Does the conversion.
636f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
637f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void doit() {
638f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int[] workSet = Bits.makeBitSet(maxLabel);
639f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
640f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Bits.set(workSet, 0);
641f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addSetupBlocks();
642f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setFirstFrame();
643f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
644f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (;;) {
645f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int offset = Bits.findFirst(workSet, 0);
646f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (offset < 0) {
647f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
648f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
649f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Bits.clear(workSet, offset);
650f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ByteBlock block = blocks.labelToBlock(offset);
651f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Frame frame = startFrames[offset];
652f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            try {
653f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                processBlock(block, frame, workSet);
654f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } catch (SimException ex) {
655f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.addContext("...while working on block " + Hex.u2(offset));
656f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw ex;
657f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
658f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
659f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
660f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addReturnBlock();
661f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addSynchExceptionHandlerBlock();
662f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addExceptionSetupBlocks();
663f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
664f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (hasSubroutines) {
665f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Subroutines are very rare, so skip this step if it's n/a
666f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            inlineSubroutines();
667f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
668f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
669f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
670f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
671f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Sets up the first frame to contain all the incoming parameters in
672f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * locals.
673f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
674f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void setFirstFrame() {
675f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Prototype desc = method.getEffectiveDescriptor();
676f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        startFrames[0].initializeWithParameters(desc.getParameterTypes());
677f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        startFrames[0].setImmutable();
678f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
679f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
680f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
681f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Processes the given block.
68239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
68399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param block {@code non-null;} block to process
68499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param frame {@code non-null;} start frame for the block
68539c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @param workSet {@code non-null;} bits representing work to do,
68639c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * which this method may add to
687f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
688f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void processBlock(ByteBlock block, Frame frame, int[] workSet) {
689f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Prepare the list of caught exceptions for this block.
690f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ByteCatchList catches = block.getCatches();
691f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        machine.startBlock(catches.toRopCatchList());
692f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
693f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
694f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Using a copy of the given frame, simulate each instruction,
695f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * calling into machine for each.
696f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
697f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        frame = frame.copy();
698f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sim.simulate(block, frame);
699f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        frame.setImmutable();
700f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
701f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int extraBlockCount = machine.getExtraBlockCount();
702f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ArrayList<Insn> insns = machine.getInsns();
703f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int insnSz = insns.size();
704f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
705f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
706f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Merge the frame into each possible non-exceptional
707f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * successor.
708f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
709f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
710f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int catchSz = catches.size();
711f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        IntList successors = block.getSuccessors();
712f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
713f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int startSuccessorIndex;
714f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
715f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Subroutine calledSubroutine = null;
716f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (machine.hasJsr()) {
717f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
718f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * If this frame ends in a JSR, only merge our frame with
719f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * the subroutine start, not the subroutine's return target.
720f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
721f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            startSuccessorIndex = 1;
722f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
723f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int subroutineLabel = successors.get(1);
724f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
725f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (subroutines[subroutineLabel] == null) {
72639c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein                subroutines[subroutineLabel] =
72739c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein                    new Subroutine (subroutineLabel);
728f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
72939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein
730f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            subroutines[subroutineLabel].addCallerBlock(block.getLabel());
731f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
732f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            calledSubroutine = subroutines[subroutineLabel];
733f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (machine.hasRet()) {
734f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
735f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * This block ends in a ret, which means it's the final block
736f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * in some subroutine. Ultimately, this block will be copied
737f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * and inlined for each call and then disposed of.
738f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
739f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
740f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ReturnAddress ra = machine.getReturnAddress();
741f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int subroutineLabel = ra.getSubroutineAddress();
742f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
743f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (subroutines[subroutineLabel] == null) {
744f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                subroutines[subroutineLabel]
745f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        = new Subroutine (subroutineLabel, block.getLabel());
746f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
747f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                subroutines[subroutineLabel].addRetBlock(block.getLabel());
748f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
749f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
750f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            successors = subroutines[subroutineLabel].getSuccessors();
751f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            subroutines[subroutineLabel]
752f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    .mergeToSuccessors(frame, workSet);
753f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Skip processing below since we just did it.
754f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            startSuccessorIndex = successors.size();
755f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (machine.wereCatchesUsed()) {
756f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
757f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * If there are catches, then the first successors
758f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * (which will either be all of them or all but the last one)
759f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * are catch targets.
760f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
761f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            startSuccessorIndex = catchSz;
762f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
763f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            startSuccessorIndex = 0;
764f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
765f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
766f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int succSz = successors.size();
767f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = startSuccessorIndex; i < succSz;
768f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             i++) {
769f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int succ = successors.get(i);
770f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            try {
771f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                mergeAndWorkAsNecessary(succ, block.getLabel(),
772f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        calledSubroutine, frame, workSet);
773f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } catch (SimException ex) {
774f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.addContext("...while merging to block " + Hex.u2(succ));
775f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw ex;
776f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
777f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
778f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
779f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((succSz == 0) && machine.returns()) {
780f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
781f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * The block originally contained a return, but it has
782f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * been made to instead end with a goto, and we need to
783f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * tell it at this point that its sole successor is the
784f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * return block. This has to happen after the merge loop
785f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * above, since, at this point, the return block doesn't
786f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * actually exist; it gets synthesized at the end of
787f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * processing the original blocks.
788f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
789f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            successors = IntList.makeImmutable(getSpecialLabel(RETURN));
790f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            succSz = 1;
791f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
792f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
793f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int primarySucc;
794f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
795f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (succSz == 0) {
796f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            primarySucc = -1;
797f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
798f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            primarySucc = machine.getPrimarySuccessorIndex();
799f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (primarySucc >= 0) {
800f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                primarySucc = successors.get(primarySucc);
801f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
802f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
803f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
804f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
805f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * This variable is true only when the method is synchronized and
806f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * the block being processed can possibly throw an exception.
807f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
808f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean synch = isSynchronized() && machine.canThrow();
809f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
810f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (synch || (catchSz != 0)) {
811f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
812f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Deal with exception handlers: Merge an exception-catch
813f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * frame into each possible exception handler, and
814f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * construct a new set of successors to point at the
815f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * exception handler setup blocks (which get synthesized
816f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * at the very end of processing).
817f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
818f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            boolean catchesAny = false;
819f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            IntList newSucc = new IntList(succSz);
820f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            for (int i = 0; i < catchSz; i++) {
821f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ByteCatchList.Item one = catches.get(i);
822f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                CstType exceptionClass = one.getExceptionClass();
823f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int targ = one.getHandlerPc();
824f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
825f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                catchesAny |= (exceptionClass == CstType.OBJECT);
826f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
827f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Frame f = frame.makeExceptionHandlerStartFrame(exceptionClass);
828f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
829f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                try {
830f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    mergeAndWorkAsNecessary(targ, block.getLabel(),
831f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            null, f, workSet);
832f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } catch (SimException ex) {
833f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    ex.addContext("...while merging exception to block " +
834f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                  Hex.u2(targ));
835f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw ex;
836f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
837f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
838f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
839f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * Set up the exception handler type, by setting it if
840f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * the given handler has yet to be encountered, or by
841f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * conservatively unioning if it has.
842f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
843f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Type already = catchTypes[targ];
844f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (already == null) {
845f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    catchTypes[targ] = exceptionClass.getClassType();
846f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (already != exceptionClass.getClassType()) {
847f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    catchTypes[targ] = Type.OBJECT;
848f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
849f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
850f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
851f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * The synthesized exception setup block will have the
852f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * label getExceptionSetupLabel(targ).
853f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
854f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                newSucc.add(getExceptionSetupLabel(targ));
855f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
856f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
857f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (synch && !catchesAny) {
858f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
859f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * The method is synchronized and this block doesn't
860f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * already have a catch-all handler, so add one to the
861f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * end, both in the successors and in the throwing
862f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * instruction(s) at the end of the block (which is where
863f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * the caught classes live).
864f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
865f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                newSucc.add(getSpecialLabel(SYNCH_CATCH_1));
866f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                synchNeedsExceptionHandler = true;
867f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
868f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (int i = insnSz - extraBlockCount - 1; i < insnSz; i++) {
869f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    Insn insn = insns.get(i);
870f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (insn.canThrow()) {
871f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        insn = insn.withAddedCatch(Type.OBJECT);
872f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        insns.set(i, insn);
873f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
874f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
875f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
876f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
877f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (primarySucc >= 0) {
878f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                newSucc.add(primarySucc);
879f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
880f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
881f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            newSucc.setImmutable();
882f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            successors = newSucc;
883f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
884f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
885f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Construct the final resulting block(s), and store it (them).
886f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
887f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int primarySuccListIndex = successors.indexOf(primarySucc);
888f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
889f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
890f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * If there are any extra blocks, work backwards through the
891f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * list of instructions, adding single-instruction blocks, and
892f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * resetting the successors variables as appropriate.
893f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
894f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (/*extraBlockCount*/; extraBlockCount > 0; extraBlockCount--) {
895f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
896f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Some of the blocks that the RopperMachine wants added
897f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * are for move-result insns, and these need goto insns as well.
898f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
899f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Insn extraInsn = insns.get(--insnSz);
900f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            boolean needsGoto
901f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    = extraInsn.getOpcode().getBranchingness()
902f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        == Rop.BRANCH_NONE;
903f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            InsnList il = new InsnList(needsGoto ? 2 : 1);
904f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            IntList extraBlockSuccessors = successors;
905f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
906f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            il.set(0, extraInsn);
907f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
908f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (needsGoto) {
909f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                il.set(1, new PlainInsn(Rops.GOTO,
910f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        extraInsn.getPosition(), null,
911f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        RegisterSpecList.EMPTY));
912f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
913f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * Obviously, this block won't be throwing an exception
914f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * so it should only have one successor.
915f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
916f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                extraBlockSuccessors = IntList.makeImmutable(primarySucc);
917f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
918f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            il.setImmutable();
919f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
920f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int label = getAvailableLabel();
921f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            BasicBlock bb = new BasicBlock(label, il, extraBlockSuccessors,
922f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    primarySucc);
923f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // All of these extra blocks will be in the same subroutine
924f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            addBlock(bb, frame.getSubroutines());
925f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
926f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            successors = successors.mutableCopy();
927f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            successors.set(primarySuccListIndex, label);
928f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            successors.setImmutable();
929f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            primarySucc = label;
930f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
93139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein
932f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Insn lastInsn = (insnSz == 0) ? null : insns.get(insnSz - 1);
933f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
934f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
935f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Add a goto to the end of the block if it doesn't already
936f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * end with a branch, to maintain the invariant that all
937f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * blocks end with a branch of some sort or other. Note that
938f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * it is possible for there to be blocks for which no
939f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * instructions were ever output (e.g., only consist of pop*
940f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * in the original Java bytecode).
941f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
942f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((lastInsn == null) ||
943f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            (lastInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE)) {
944f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            SourcePosition pos = (lastInsn == null) ? SourcePosition.NO_INFO :
945f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                lastInsn.getPosition();
946f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insns.add(new PlainInsn(Rops.GOTO, pos, null,
947f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                    RegisterSpecList.EMPTY));
948f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insnSz++;
949f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
95039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein
951f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
952f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Construct a block for the remaining instructions (which in
953f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * the usual case is all of them).
954f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
955f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
956f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        InsnList il = new InsnList(insnSz);
957f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < insnSz; i++) {
958f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            il.set(i, insns.get(i));
959f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
960f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        il.setImmutable();
961f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
962f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        BasicBlock bb =
963f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            new BasicBlock(block.getLabel(), il, successors, primarySucc);
964f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addOrReplaceBlock(bb, frame.getSubroutines());
965f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
966f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
967f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
968f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Helper for {@link #processBlock}, which merges frames and
969f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * adds to the work set, as necessary.
97039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
97199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param label {@code >= 0;} label to work on
97299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param pred  predecessor label; must be {@code >= 0} when
97399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code label} is a subroutine start block and calledSubroutine
974f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * is non-null. Otherwise, may be -1.
97599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param calledSubroutine {@code null-ok;} a Subroutine instance if
97699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code label} is the first block in a subroutine.
97799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param frame {@code non-null;} new frame for the labelled block
97839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @param workSet {@code non-null;} bits representing work to do,
97939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * which this method may add to
980f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
981f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void mergeAndWorkAsNecessary(int label, int pred,
982f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Subroutine calledSubroutine, Frame frame, int[] workSet) {
983f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Frame existing = startFrames[label];
984f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Frame merged;
985f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
986f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (existing != null) {
987f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
988f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Some other block also continues at this label. Merge
989f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * the frames, and re-set the bit in the work set if there
990f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * was a change.
991f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
992f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (calledSubroutine != null) {
993f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                merged = existing.mergeWithSubroutineCaller(frame,
994f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        calledSubroutine.getStartBlock(), pred);
995f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
996f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                merged = existing.mergeWith(frame);
997f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
998f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (merged != existing) {
999f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                startFrames[label] = merged;
1000f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Bits.set(workSet, label);
1001f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1002f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
1003f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // This is the first time this label has been encountered.
1004f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (calledSubroutine != null) {
1005f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                startFrames[label]
1006f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        = frame.makeNewSubroutineStartFrame(label, pred);
1007f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
1008f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                startFrames[label] = frame;
1009f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1010f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Bits.set(workSet, label);
1011f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1012f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1013f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1014f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1015f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs and adds the blocks that perform setup for the rest of
1016f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the method. This includes a first block which merely contains
1017f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * assignments from parameters to the same-numbered registers and
1018f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * a possible second block which deals with synchronization.
1019f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1020f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void addSetupBlocks() {
1021f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LocalVariableList localVariables = method.getLocalVariables();
1022f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        SourcePosition pos = method.makeSourcePosistion(0);
1023f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Prototype desc = method.getEffectiveDescriptor();
1024f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        StdTypeList params = desc.getParameterTypes();
1025f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = params.size();
1026f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        InsnList insns = new InsnList(sz + 1);
1027f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int at = 0;
1028f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1029f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < sz; i++) {
1030f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Type one = params.get(i);
103139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein            LocalVariableList.Item local =
103239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein                localVariables.pcAndIndexToLocal(0, at);
1033f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            RegisterSpec result = (local == null) ?
1034f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                RegisterSpec.make(at, one) :
1035f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                RegisterSpec.makeLocalOptional(at, one, local.getLocalItem());
1036f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1037f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Insn insn = new PlainCstInsn(Rops.opMoveParam(one), pos, result,
1038f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                         RegisterSpecList.EMPTY,
1039f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                         CstInteger.make(at));
1040f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insns.set(i, insn);
1041f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            at += one.getCategory();
1042f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1043f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
104439c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein        insns.set(sz, new PlainInsn(Rops.GOTO, pos, null,
1045f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                    RegisterSpecList.EMPTY));
1046f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns.setImmutable();
1047f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1048f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean synch = isSynchronized();
1049f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int label = synch ? getSpecialLabel(SYNCH_SETUP_1) : 0;
1050f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        BasicBlock bb =
1051f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            new BasicBlock(getSpecialLabel(PARAM_ASSIGNMENT), insns,
1052f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                           IntList.makeImmutable(label), label);
1053f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addBlock(bb, IntList.EMPTY);
1054f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1055f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (synch) {
1056f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            RegisterSpec synchReg = getSynchReg();
1057f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Insn insn;
1058f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (isStatic()) {
1059f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insn = new ThrowingCstInsn(Rops.CONST_OBJECT, pos,
1060f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                           RegisterSpecList.EMPTY,
1061f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                           StdTypeList.EMPTY,
1062f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                           method.getDefiningClass());
1063f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insns = new InsnList(1);
1064f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insns.set(0, insn);
1065f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
1066f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insns = new InsnList(2);
1067f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insn = new PlainCstInsn(Rops.MOVE_PARAM_OBJECT, pos,
1068f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                        synchReg, RegisterSpecList.EMPTY,
1069f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                        CstInteger.VALUE_0);
1070f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insns.set(0, insn);
1071f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insns.set(1, new PlainInsn(Rops.GOTO, pos, null,
1072f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                           RegisterSpecList.EMPTY));
1073f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1074f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1075f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int label2 = getSpecialLabel(SYNCH_SETUP_2);
1076f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insns.setImmutable();
1077f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            bb = new BasicBlock(label, insns,
1078f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                IntList.makeImmutable(label2), label2);
1079f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            addBlock(bb, IntList.EMPTY);
1080f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1081f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insns = new InsnList(isStatic() ? 2 : 1);
1082f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1083f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (isStatic()) {
1084f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insns.set(0, new PlainInsn(Rops.opMoveResultPseudo(synchReg),
1085f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        pos, synchReg, RegisterSpecList.EMPTY));
1086f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1087f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1088f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insn = new ThrowingInsn(Rops.MONITOR_ENTER, pos,
1089f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                    RegisterSpecList.make(synchReg),
1090f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                    StdTypeList.EMPTY);
1091f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insns.set(isStatic() ? 1 :0, insn);
1092f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insns.setImmutable();
1093f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            bb = new BasicBlock(label2, insns, IntList.makeImmutable(0), 0);
1094f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            addBlock(bb, IntList.EMPTY);
1095f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1096f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1097f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1098f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1099f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs and adds the return block, if necessary. The return
110099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * block merely contains an appropriate {@code return}
1101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * instruction.
1102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void addReturnBlock() {
1104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Rop returnOp = machine.getReturnOp();
1105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (returnOp == null) {
1107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
1108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * The method being converted never returns normally, so there's
1109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * no need for a return block.
1110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
1111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
1112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        SourcePosition returnPos = machine.getReturnPosition();
1115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int label = getSpecialLabel(RETURN);
1116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (isSynchronized()) {
1118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            InsnList insns = new InsnList(1);
1119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Insn insn = new ThrowingInsn(Rops.MONITOR_EXIT, returnPos,
1120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                         RegisterSpecList.make(getSynchReg()),
1121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                         StdTypeList.EMPTY);
1122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insns.set(0, insn);
1123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insns.setImmutable();
1124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int nextLabel = getSpecialLabel(SYNCH_RETURN);
1126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            BasicBlock bb =
1127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                new BasicBlock(label, insns,
1128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                               IntList.makeImmutable(nextLabel), nextLabel);
1129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            addBlock(bb, IntList.EMPTY);
1130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            label = nextLabel;
1132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        InsnList insns = new InsnList(1);
1135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        TypeList sourceTypes = returnOp.getSources();
1136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        RegisterSpecList sources;
1137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (sourceTypes.size() == 0) {
1139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sources = RegisterSpecList.EMPTY;
1140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
1141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            RegisterSpec source = RegisterSpec.make(0, sourceTypes.getType(0));
1142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sources = RegisterSpecList.make(source);
1143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Insn insn = new PlainInsn(returnOp, returnPos, null, sources);
1146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns.set(0, insn);
1147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns.setImmutable();
1148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        BasicBlock bb = new BasicBlock(label, insns, IntList.EMPTY, -1);
1150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addBlock(bb, IntList.EMPTY);
1151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs and adds, if necessary, the catch-all exception handler
1155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * block to deal with unwinding the lock taken on entry to a synchronized
1156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * method.
1157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void addSynchExceptionHandlerBlock() {
1159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!synchNeedsExceptionHandler) {
1160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
1161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * The method being converted either isn't synchronized or
1162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * can't possibly throw exceptions in its main body, so
1163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * there's no need for a synchronized method exception
1164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * handler.
1165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
1166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
1167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        SourcePosition pos = method.makeSourcePosistion(0);
1170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        RegisterSpec exReg = RegisterSpec.make(0, Type.THROWABLE);
1171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        BasicBlock bb;
1172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Insn insn;
1173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        InsnList insns = new InsnList(2);
1175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insn = new PlainInsn(Rops.opMoveException(Type.THROWABLE), pos,
1176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                             exReg, RegisterSpecList.EMPTY);
1177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns.set(0, insn);
1178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insn = new ThrowingInsn(Rops.MONITOR_EXIT, pos,
1179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                RegisterSpecList.make(getSynchReg()),
1180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                StdTypeList.EMPTY);
1181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns.set(1, insn);
1182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns.setImmutable();
1183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int label2 = getSpecialLabel(SYNCH_CATCH_2);
1185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bb = new BasicBlock(getSpecialLabel(SYNCH_CATCH_1), insns,
1186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            IntList.makeImmutable(label2), label2);
1187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addBlock(bb, IntList.EMPTY);
1188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns = new InsnList(1);
1190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insn = new ThrowingInsn(Rops.THROW, pos,
1191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                RegisterSpecList.make(exReg),
1192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                StdTypeList.EMPTY);
1193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns.set(0, insn);
1194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns.setImmutable();
1195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bb = new BasicBlock(label2, insns, IntList.EMPTY, -1);
1197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addBlock(bb, IntList.EMPTY);
1198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Creates the exception handler setup blocks. "maxLocals"
1202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * below is because that's the register number corresponding
1203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * to the sole element on a one-deep stack (which is the
1204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * situation at the start of an exception handler block).
1205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void addExceptionSetupBlocks() {
1207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int len = catchTypes.length;
1209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < len; i++) {
1210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Type one = catchTypes[i];
1211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (one != null) {
1212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Insn proto = labelToBlock(i).getFirstInsn();
1213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                SourcePosition pos = proto.getPosition();
1214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                InsnList il = new InsnList(2);
1215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Insn insn = new PlainInsn(Rops.opMoveException(one),
1217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                          pos,
1218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                          RegisterSpec.make(maxLocals, one),
1219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                          RegisterSpecList.EMPTY);
1220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                il.set(0, insn);
1221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insn = new PlainInsn(Rops.GOTO, pos, null,
1223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                     RegisterSpecList.EMPTY);
1224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                il.set(1, insn);
1225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                il.setImmutable();
1226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                BasicBlock bb = new BasicBlock(getExceptionSetupLabel(i),
1228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                               il,
1229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                               IntList.makeImmutable(i),
1230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                               i);
1231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                addBlock(bb, startFrames[i].getSubroutines());
1232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Checks to see if the basic block is a subroutine caller block.
1238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
123999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param bb {@code non-null;} the basic block in question
1240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return true if this block calls a subroutine
1241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean isSubroutineCaller(BasicBlock bb) {
1243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        IntList successors = bb.getSuccessors();
1244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (successors.size() < 2) return false;
1245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int subLabel = successors.get(1);
1247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return (subLabel < subroutines.length)
1249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                && (subroutines[subLabel] != null);
1250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
125339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * Inlines any subroutine calls.
1254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void inlineSubroutines() {
1256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        final IntList reachableSubroutineCallerLabels = new IntList(4);
1257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
1259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Compile a list of all subroutine calls reachable
1260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * through the normal (non-subroutine) flow.  We do this first, since
1261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * we'll be affecting the call flow as we go.
126239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         *
1263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Start at label 0 --  the param assignment block has nothing for us
1264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        forEachNonSubBlockDepthFirst(0, new BasicBlock.Visitor() {
1266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            public void visitBlock(BasicBlock b) {
1267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (isSubroutineCaller(b)) {
1268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    reachableSubroutineCallerLabels.add(b.getLabel());
1269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        });
1272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
1274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Convert the resultSubroutines list, indexed by block index,
1275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * to a label-to-subroutines mapping used by the inliner.
1276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int largestAllocedLabel = getAvailableLabel();
1278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ArrayList<IntList> labelToSubroutines
1279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                = new ArrayList<IntList>(largestAllocedLabel);
1280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < largestAllocedLabel; i++) {
1281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            labelToSubroutines.add(null);
1282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < result.size(); i++) {
1285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            BasicBlock b = result.get(i);
1286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (b == null) {
1287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                continue;
1288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            IntList subroutineList = resultSubroutines.get(i);
1290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            labelToSubroutines.set(b.getLabel(), subroutineList);
1291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
129439c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         * Inline all reachable subroutines.
129539c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         * Inner subroutines will be inlined as they are encountered.
129639c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         */
1297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = reachableSubroutineCallerLabels.size();
1298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0 ; i < sz ; i++) {
1299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int label = reachableSubroutineCallerLabels.get(i);
1300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            new SubroutineInliner(
130139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein                    new LabelAllocator(getAvailableLabel()),
130239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein                    labelToSubroutines)
1303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    .inlineSubroutineCalledFrom(labelToBlock(label));
1304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Now find the blocks that aren't reachable and remove them
1307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        deleteUnreachableBlocks();
1308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Deletes all blocks that cannot be reached. This is run to delete
1312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * original subroutine blocks after subroutine inlining.
1313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void deleteUnreachableBlocks() {
1315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        final IntList reachableLabels = new IntList(result.size());
1316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // subroutine inlining is done now and we won't update this list here
1318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        resultSubroutines.clear();
1319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        forEachNonSubBlockDepthFirst(getSpecialLabel(PARAM_ASSIGNMENT),
1321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                new BasicBlock.Visitor() {
1322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            public void visitBlock(BasicBlock b) {
1324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                reachableLabels.add(b.getLabel());
1325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        });
1327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        reachableLabels.sort();
1329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = result.size() - 1 ; i >= 0 ; i--) {
1331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (reachableLabels.indexOf(result.get(i).getLabel()) < 0) {
1332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                result.remove(i);
1333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // unnecessary here really, since subroutine inlining is done
1334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                //resultSubroutines.remove(i);
1335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Allocates labels, without requiring previously allocated labels
1341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * to have been added to the blocks list.
1342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static class LabelAllocator {
1344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int nextAvailableLabel;
1345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
1347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param startLabel available label to start allocating from
1348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LabelAllocator(int startLabel) {
1350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            nextAvailableLabel = startLabel;
1351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
1354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @return next available label
1355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int getNextLabel() {
1357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return nextAvailableLabel++;
1358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Inlines a subroutine. Start by calling
136339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * {@link #inlineSubroutineCalledFrom}.
1364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private class SubroutineInliner {
1366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
136739c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         * maps original label to the label that will be used by the
136839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         * inlined version
1369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private final HashMap<Integer, Integer> origLabelToCopiedLabel;
1371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
137239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein        /** set of original labels that need to be copied */
1373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private final BitSet workList;
1374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
137539c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein        /** the label of the original start block for this subroutine */
1376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private int subroutineStart;
1377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
137839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein        /** the label of the ultimate return block */
1379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private int subroutineSuccessor;
1380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
138139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein        /** used for generating new labels for copied blocks */
1382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private final LabelAllocator labelAllocator;
1383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
1385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * A mapping, indexed by label, to subroutine nesting list.
1386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * The subroutine nest list is as returned by
1387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * {@link Frame#getSubroutines}.
1388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private final ArrayList<IntList> labelToSubroutines;
1390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        SubroutineInliner(final LabelAllocator labelAllocator,
1392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ArrayList<IntList> labelToSubroutines) {
1393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            origLabelToCopiedLabel = new HashMap<Integer, Integer>();
1394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            workList = new BitSet(maxLabel);
1396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.labelAllocator = labelAllocator;
1398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.labelToSubroutines = labelToSubroutines;
1399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
1402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Inlines a subroutine.
140339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         *
140439c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         * @param b block where {@code jsr} occurred in the original bytecode
1405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        void inlineSubroutineCalledFrom(final BasicBlock b) {
1407f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
1408f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * The 0th successor of a subroutine caller block is where
1409f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * the subroutine should return to. The 1st successor is
1410f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * the start block of the subroutine.
1411f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
1412f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            subroutineSuccessor = b.getSuccessors().get(0);
1413f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            subroutineStart = b.getSuccessors().get(1);
1414f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
1416f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * This allocates an initial label and adds the first
1417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * block to the worklist.
1418f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
1419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int newSubStartLabel = mapOrAllocateLabel(subroutineStart);
1420f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
142141aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein            for (int label = workList.nextSetBit(0); label >= 0;
142241aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein                 label = workList.nextSetBit(0)) {
1423f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                workList.clear(label);
1424f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int newLabel = origLabelToCopiedLabel.get(label);
1425f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1426f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                copyBlock(label, newLabel);
1427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1428f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (isSubroutineCaller(labelToBlock(label))) {
1429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    new SubroutineInliner(labelAllocator, labelToSubroutines)
1430f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        .inlineSubroutineCalledFrom(labelToBlock(newLabel));
1431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1433f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1434f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
1435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Replace the original caller block, since we now have a
1436f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * new successor
1437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
1438f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1439f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            addOrReplaceBlockNoDelete(
1440f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                new BasicBlock(b.getLabel(), b.getInsns(),
1441f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    IntList.makeImmutable (newSubStartLabel),
144241aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein                            newSubStartLabel),
144341aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein                labelToSubroutines.get(b.getLabel()));
14446b386bfb92ef6efe8f963270fc5a4b756fca225ejeffhao        }
1445f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
1447f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Copies a basic block, mapping its successors along the way.
144839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         *
1449f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param origLabel original block label
1450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param newLabel label that the new block should have
1451f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
14526b386bfb92ef6efe8f963270fc5a4b756fca225ejeffhao        private void copyBlock(int origLabel, int newLabel) {
1453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1454f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            BasicBlock origBlock = labelToBlock(origLabel);
1455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1456f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            final IntList origSuccessors = origBlock.getSuccessors();
1457f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            IntList successors;
1458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int primarySuccessor = -1;
1459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Subroutine subroutine;
1460f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1461f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (isSubroutineCaller(origBlock)) {
1462f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
1463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * A subroutine call inside a subroutine call.
1464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * Set up so we can recurse. The caller block should have
1465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * it's first successor be a copied block that will be
1466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * the subroutine's return point. It's second successor will
1467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * be copied when we recurse, and remains as the original
1468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * label of the start of the inner subroutine.
1469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
1470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                successors = IntList.makeImmutable(
1472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        mapOrAllocateLabel(origSuccessors.get(0)),
1473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        origSuccessors.get(1));
1474f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // primary successor will be set when this block is replaced
1475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else if (null
1476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    != (subroutine = subroutineFromRetBlock(origLabel))) {
1477f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
1478f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * this is a ret block -- its successor
1479f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * should be subroutineSuccessor
1480f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
1481f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1482f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // Sanity check
1483f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (subroutine.startBlock != subroutineStart) {
1484f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new RuntimeException (
1485f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            "ret instruction returns to label "
1486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            + Hex.u2 (subroutine.startBlock)
1487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            + " expected: " + Hex.u2(subroutineStart));
1488f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1490f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                successors = IntList.makeImmutable(subroutineSuccessor);
1491f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                primarySuccessor = subroutineSuccessor;
1492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
1493f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // Map all the successor labels
1494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int origPrimary = origBlock.getPrimarySuccessor();
1496f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int sz = origSuccessors.size();
1497f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1498f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                successors = new IntList(sz);
1499f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (int i = 0 ; i < sz ; i++) {
1501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int origSuccLabel = origSuccessors.get(i);
1502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int newSuccLabel =  mapOrAllocateLabel(origSuccLabel);
1503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    successors.add(newSuccLabel);
1505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (origPrimary == origSuccLabel) {
1507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        primarySuccessor = newSuccLabel;
1508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
1509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1511f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                successors.setImmutable();
1512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1513f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1514f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            addBlock (
1515f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                new BasicBlock(newLabel,
1516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    filterMoveReturnAddressInsns(origBlock.getInsns()),
1517f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    successors, primarySuccessor),
1518f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    labelToSubroutines.get(newLabel));
1519f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1520f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1521f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
1522f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Checks to see if a specified label is involved in a specified
1523f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * subroutine.
1524f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
152599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param label {@code >= 0;} a basic block label
152639c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         * @param subroutineStart {@code >= 0;} a subroutine as identified
152739c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         * by the label of its start block
152839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         * @return true if the block is dominated by the subroutine call
1529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1530f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private boolean involvedInSubroutine(int label, int subroutineStart) {
1531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            IntList subroutinesList = labelToSubroutines.get(label);
15326b386bfb92ef6efe8f963270fc5a4b756fca225ejeffhao            return (subroutinesList != null && subroutinesList.size() > 0
1533f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    && subroutinesList.top() == subroutineStart);
1534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
1537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Maps the label of a pre-copied block to the label of the inlined
1538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * block, allocating a new label and adding it to the worklist
1539f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * if necessary.  If the origLabel is a "special" label, it
1540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * is returned exactly and not scheduled for duplication: copying
1541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * never proceeds past a special label, which likely is the function
1542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * return block or an immediate predecessor.
1543f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
1544f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param origLabel label of original, pre-copied block
1545f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @return label for new, inlined block
1546f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1547f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private int mapOrAllocateLabel(int origLabel) {
1548f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int resultLabel;
1549f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Integer mappedLabel = origLabelToCopiedLabel.get(origLabel);
1550f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1551f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (mappedLabel != null) {
1552f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                resultLabel = mappedLabel;
1553f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else if (!involvedInSubroutine(origLabel,subroutineStart)) {
1554f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
1555f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * A subroutine has ended by some means other than a "ret"
1556f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * (which really means a throw caught later).
1557f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
1558f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                resultLabel = origLabel;
1559f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
1560f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                resultLabel = labelAllocator.getNextLabel();
1561f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                workList.set(origLabel);
1562f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                origLabelToCopiedLabel.put(origLabel, resultLabel);
1563f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1564f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // The new label has the same frame as the original label
1565f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                while (labelToSubroutines.size() <= resultLabel) {
1566f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    labelToSubroutines.add(null);
1567f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1568f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                labelToSubroutines.set(resultLabel,
1569f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        labelToSubroutines.get(origLabel));
1570f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1571f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1572f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return resultLabel;
1573f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1574f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1575f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1576f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
157739c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * Finds a {@code Subroutine} that is returned from by a {@code ret} in
1578f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * a given block.
157939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
158039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @param label A block that originally contained a {@code ret} instruction
158139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @return {@code null-ok;} found subroutine or {@code null} if none
158239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * was found
1583f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1584f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private Subroutine subroutineFromRetBlock(int label) {
1585f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = subroutines.length - 1 ; i >= 0 ; i--) {
1586f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (subroutines[i] != null) {
1587f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Subroutine subroutine = subroutines[i];
1588f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1589f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (subroutine.retBlocks.get(label)) {
1590f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    return subroutine;
1591f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1592f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1593f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1594f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1595f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return null;
1596f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1597f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1598f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1599f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
160039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * Removes all {@code move-return-address} instructions, returning a new
160139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * {@code InsnList} if necessary. The {@code move-return-address}
160239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * insns are dead code after subroutines have been inlined.
1603f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
160439c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @param insns {@code InsnList} that may contain
160539c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * {@code move-return-address} insns
160639c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @return {@code InsnList} with {@code move-return-address} removed
1607f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1608f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private InsnList filterMoveReturnAddressInsns(InsnList insns) {
1609f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz;
1610f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int newSz = 0;
1611f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1612f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // First see if we need to filter, and if so what the new size will be
1613f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sz = insns.size();
1614f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < sz; i++) {
1615f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (insns.get(i).getOpcode() != Rops.MOVE_RETURN_ADDRESS) {
1616f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                newSz++;
1617f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1619f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1620f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (newSz == sz) {
1621f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return insns;
1622f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1623f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1624f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Make a new list without the MOVE_RETURN_ADDRESS insns
1625f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        InsnList newInsns = new InsnList(newSz);
1626f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1627f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int newIndex = 0;
1628f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < sz; i++) {
1629f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Insn insn = insns.get(i);
1630f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (insn.getOpcode() != Rops.MOVE_RETURN_ADDRESS) {
1631f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                newInsns.set(newIndex++, insn);
1632f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1633f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1634f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1635f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        newInsns.setImmutable();
1636f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return newInsns;
1637f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1638f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1639f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1640f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Visits each non-subroutine block once in depth-first successor order.
164139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
1642f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param firstLabel label of start block
1643f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param v callback interface
1644f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
164539c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein    private void forEachNonSubBlockDepthFirst(int firstLabel,
164639c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein            BasicBlock.Visitor v) {
1647f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        forEachNonSubBlockDepthFirst0(labelToBlock(firstLabel),
1648f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                v, new BitSet(maxLabel));
1649f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1650f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1651f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
165239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * Visits each block once in depth-first successor order, ignoring
165339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * {@code jsr} targets. Worker for {@link #forEachNonSubBlockDepthFirst}.
165439c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
1655f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param next next block to visit
1656f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param v callback interface
1657f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param visited set of blocks already visited
1658f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1659f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void forEachNonSubBlockDepthFirst0(
1660f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            BasicBlock next, BasicBlock.Visitor v, BitSet visited) {
1661f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        v.visitBlock(next);
1662f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        visited.set(next.getLabel());
1663f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1664f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        IntList successors = next.getSuccessors();
1665f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = successors.size();
1666f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
166739c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein        for (int i = 0; i < sz; i++) {
1668f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int succ = successors.get(i);
1669f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1670f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (visited.get(succ)) {
1671f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                continue;
1672f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1673f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1674f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (isSubroutineCaller(next) && i > 0) {
1675f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // ignore jsr targets
1676f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                continue;
1677f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1678f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1679f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
1680f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Ignore missing labels: they're successors of
1681f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * subroutines that never invoke a ret.
1682f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
1683f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int idx = labelToResultIndex(succ);
1684f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (idx >= 0) {
1685f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                forEachNonSubBlockDepthFirst0(result.get(idx), v, visited);
1686f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1687f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1688f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1689f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
1690