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
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.code.*;
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstInteger;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.cst.CstType;
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.Prototype;
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.StdTypeList;
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.Type;
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.rop.type.TypeList;
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.Bits;
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.Hex;
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.IntList;
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.ArrayList;
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.BitSet;
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.HashMap;
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Utility that converts a basic block list into a list of register-oriented
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * blocks.
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic final class Ropper {
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** label offset for the parameter assignment block */
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int PARAM_ASSIGNMENT = -1;
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** label offset for the return block */
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int RETURN = -2;
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** label offset for the synchronized method final return block */
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int SYNCH_RETURN = -3;
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** label offset for the first synchronized method setup block */
49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int SYNCH_SETUP_1 = -4;
50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** label offset for the second synchronized method setup block */
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int SYNCH_SETUP_2 = -5;
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * label offset for the first synchronized method exception
5639c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * handler block
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int SYNCH_CATCH_1 = -6;
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * label offset for the second synchronized method exception
6239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * handler block
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int SYNCH_CATCH_2 = -7;
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** number of special label offsets */
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int SPECIAL_LABEL_COUNT = 7;
68f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
6999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} method being converted */
70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final ConcreteMethod method;
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
7299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} original block list */
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final ByteBlockList blocks;
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** max locals of the method */
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final int maxLocals;
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** max label (exclusive) of any original bytecode block */
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final int maxLabel;
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
8199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} simulation machine to use */
82f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final RopperMachine machine;
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
8499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} simulator to use */
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final Simulator sim;
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
8839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * {@code non-null;} sparse array mapping block labels to initial frame
8939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * contents, if known
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final Frame[] startFrames;
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
9399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} output block list in-progress */
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final ArrayList<BasicBlock> result;
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
9799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code non-null;} list of subroutine-nest labels
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * (See {@link Frame#getSubroutines} associated with each result block.
9939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * Parallel to {@link Ropper#result}.
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final ArrayList<IntList> resultSubroutines;
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
10499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code non-null;} for each block (by label) that is used as an exception
10539c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * handler, the type of exception it catches
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final Type[] catchTypes;
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * whether an exception-handler block for a synchronized method was
11139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * ever required
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean synchNeedsExceptionHandler;
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
11539c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein    /**
11639c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * {@code non-null;} list of subroutines indexed by label of start
11739c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * address */
11839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein    private final Subroutine[] subroutines;
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
12099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** true if {@code subroutines} is non-empty */
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean hasSubroutines;
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Keeps track of subroutines that exist in java form and are inlined in
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Rop form.
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private class Subroutine {
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** list of all blocks that jsr to this subroutine */
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private BitSet callerBlocks;
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** List of all blocks that return from this subroutine */
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private BitSet retBlocks;
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /** first block in this subroutine */
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private int startBlock;
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Constructs instance.
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param startBlock First block of the subroutine.
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Subroutine(int startBlock) {
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.startBlock = startBlock;
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            retBlocks = new BitSet(maxLabel);
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            callerBlocks = new BitSet(maxLabel);
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            hasSubroutines = true;
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Constructs instance.
149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param startBlock First block of the subroutine.
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param retBlock one of the ret blocks (final blocks) of this
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * subroutine.
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Subroutine(int startBlock, int retBlock) {
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this(startBlock);
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            addRetBlock(retBlock);
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
16099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @return {@code >= 0;} the label of the subroutine's start block.
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int getStartBlock() {
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return startBlock;
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Adds a label to the list of ret blocks (final blocks) for this
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * subroutine.
16939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         *
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param retBlock ret block label
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        void addRetBlock(int retBlock) {
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            retBlocks.set(retBlock);
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Adds a label to the list of caller blocks for this subroutine.
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param label a block that invokes this subroutine.
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        void addCallerBlock(int label) {
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            callerBlocks.set(label);
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Generates a list of subroutine successors. Note: successor blocks
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * could be listed more than once. This is ok, because this successor
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * list (and the block it's associated with) will be copied and inlined
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * before we leave the ropper. Redundent successors will result in
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * redundent (no-op) merges.
19139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         *
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @return all currently known successors
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * (return destinations) for that subroutine
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        IntList getSuccessors() {
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            IntList successors = new IntList(callerBlocks.size());
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
19941aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein             * For each subroutine caller, get it's target. If the
20041aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein             * target is us, add the ret target (subroutine successor)
20141aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein             * to our list
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
20441aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein            for (int label = callerBlocks.nextSetBit(0); label >= 0;
20541aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein                 label = callerBlocks.nextSetBit(label+1)) {
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                BasicBlock subCaller = labelToBlock(label);
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                successors.add(subCaller.getSuccessors().get(0));
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            successors.setImmutable();
21139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return successors;
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Merges the specified frame into this subroutine's successors,
21799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * setting {@code workSet} as appropriate. To be called with
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * the frame of a subroutine ret block.
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
22099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param frame {@code non-null;} frame from ret block to merge
22199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param workSet {@code non-null;} workset to update
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        void mergeToSuccessors(Frame frame, int[] workSet) {
22441aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein            for (int label = callerBlocks.nextSetBit(0); label >= 0;
22541aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein                 label = callerBlocks.nextSetBit(label+1)) {
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                BasicBlock subCaller = labelToBlock(label);
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int succLabel = subCaller.getSuccessors().get(0);
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Frame subFrame = frame.subFrameForLabel(startBlock, label);
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (subFrame != null) {
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    mergeAndWorkAsNecessary(succLabel, -1, null,
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            subFrame, workSet);
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else {
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    Bits.set(workSet, label);
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Converts a {@link ConcreteMethod} to a {@link RopMethod}.
24339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
24499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param method {@code non-null;} method to convert
24599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param advice {@code non-null;} translation advice to use
24699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the converted instance
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public static RopMethod convert(ConcreteMethod method,
249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            TranslationAdvice advice) {
250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Ropper r = new Ropper(method, advice);
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            r.doit();
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return r.getRopMethod();
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (SimException ex) {
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ex.addContext("...while working on method " +
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                          method.getNat().toHuman());
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw ex;
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs an instance. This class is not publicly instantiable; use
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * {@link #convert}.
26439c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
26599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param method {@code non-null;} method to convert
26699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param advice {@code non-null;} translation advice to use
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private Ropper(ConcreteMethod method, TranslationAdvice advice) {
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (method == null) {
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("method == null");
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (advice == null) {
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("advice == null");
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.method = method;
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.blocks = BasicBlocker.identifyBlocks(method);
279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.maxLabel = blocks.getMaxLabel();
280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.maxLocals = method.getMaxLocals();
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.machine = new RopperMachine(this, method, advice);
282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.sim = new Simulator(machine, method);
283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.startFrames = new Frame[maxLabel];
284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.subroutines = new Subroutine[maxLabel];
285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * The "* 2 + 10" below is to conservatively believe that every
288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * block is an exception handler target and should also
289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * take care of enough other possible extra overhead such that
290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * the underlying array is unlikely to need resizing.
291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.result = new ArrayList<BasicBlock>(blocks.size() * 2 + 10);
29339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein        this.resultSubroutines =
29439c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein            new ArrayList<IntList>(blocks.size() * 2 + 10);
295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.catchTypes = new Type[maxLabel];
297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.synchNeedsExceptionHandler = false;
298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Set up the first stack frame with the right limits, but leave it
301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * empty here (to be filled in outside of the constructor).
302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        startFrames[0] = new Frame(maxLocals, method.getMaxStack());
304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the first (lowest) register number to use as the temporary
308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * area when unwinding stack manipulation ops.
30939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
31099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the first register to use
311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*package*/ int getFirstTempStackReg() {
313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * We use the register that is just past the deepest possible
315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * stack element, plus one if the method is synchronized to
316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * avoid overlapping with the synch register. We don't need to
317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * do anything else special at this level, since later passes
318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * will merely notice the highest register used by explicit
319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * inspection.
320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int regCount = getNormalRegCount();
322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return isSynchronized() ? regCount + 1 : regCount;
323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the label for the exception handler setup block corresponding
327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * to the given label.
32839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
32999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param label {@code >= 0;} the original label
33099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the corresponding exception handler setup label
331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int getExceptionSetupLabel(int label) {
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return maxLabel + label;
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the label for the given special-purpose block. The given label
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * should be one of the static constants defined by this class.
33939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
34099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param label {@code < 0;} the special label constant
34199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the actual label value to use
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int getSpecialLabel(int label) {
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * The label is bitwise-complemented so that mistakes where
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * LABEL is used instead of getSpecialLabel(LABEL) cause a
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * failure at block construction time, since negative labels
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * are illegal. We multiply maxLabel by 2 since 0..maxLabel
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * (exclusive) are the original blocks and
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * maxLabel..(maxLabel*2) are reserved for exception handler
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * setup blocks (see getExceptionSetupLabel(), above).
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return (maxLabel * 2) + ~label;
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the minimum label for unreserved use.
35839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
35999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the minimum label
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int getMinimumUnreservedLabel() {
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * The labels below ((maxLabel * 2) + SPECIAL_LABEL_COUNT) are
364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * reserved for particular uses.
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return (maxLabel * 2) + SPECIAL_LABEL_COUNT;
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets an arbitrary unreserved and available label.
37239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
37399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the label
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int getAvailableLabel() {
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int candidate = getMinimumUnreservedLabel();
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (BasicBlock bb : result) {
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int label = bb.getLabel();
380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (label >= candidate) {
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                candidate = label + 1;
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return candidate;
386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets whether the method being translated is synchronized.
39039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether the method being translated is synchronized
392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean isSynchronized() {
394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int accessFlags = method.getAccessFlags();
395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return (accessFlags & AccessFlags.ACC_SYNCHRONIZED) != 0;
396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets whether the method being translated is static.
40039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return whether the method being translated is static
402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean isStatic() {
404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int accessFlags = method.getAccessFlags();
405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return (accessFlags & AccessFlags.ACC_STATIC) != 0;
406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
407f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
408f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
409f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the total number of registers used for "normal" purposes (i.e.,
410f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * for the straightforward translation from the original Java).
41139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
41299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the total number of registers used
413f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
414f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int getNormalRegCount() {
415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return maxLocals + method.getMaxStack();
416f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
418f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the register spec to use to hold the object to synchronize on,
420f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * for a synchronized method.
42139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
42299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the register spec
423f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
424f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private RegisterSpec getSynchReg() {
425f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
426f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * We use the register that is just past the deepest possible
427c51439a513d4cc3c2be4a7cce7b3e9ae480fd5c2Dan Bornstein         * stack element, with a minimum of v1 since v0 is what's
428c51439a513d4cc3c2be4a7cce7b3e9ae480fd5c2Dan Bornstein         * always used to hold the caught exception when unwinding. We
429c51439a513d4cc3c2be4a7cce7b3e9ae480fd5c2Dan Bornstein         * don't need to do anything else special at this level, since
430c51439a513d4cc3c2be4a7cce7b3e9ae480fd5c2Dan Bornstein         * later passes will merely notice the highest register used
431c51439a513d4cc3c2be4a7cce7b3e9ae480fd5c2Dan Bornstein         * by explicit inspection.
432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
433c51439a513d4cc3c2be4a7cce7b3e9ae480fd5c2Dan Bornstein        int reg = getNormalRegCount();
434c51439a513d4cc3c2be4a7cce7b3e9ae480fd5c2Dan Bornstein        return RegisterSpec.make((reg < 1) ? 1 : reg, Type.OBJECT);
435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
436f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
43839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * Searches {@link #result} for a block with the given label. Returns its
43939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * index if found, or returns {@code -1} if there is no such block.
44039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
441f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param label the label to look for
44299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= -1;} the index for the block with the given label or
44399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code -1} if there is no such block
444f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
445f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int labelToResultIndex(int label) {
446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = result.size();
447f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < sz; i++) {
448f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            BasicBlock one = result.get(i);
449f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (one.getLabel() == label) {
450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return i;
451f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
452f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
454f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return -1;
45539c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein    }
456f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
457f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
45839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * Searches {@link #result} for a block with the given label. Returns it if
45939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * found, or throws an exception if there is no such block.
46039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
461f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param label the label to look for
46299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the block with the given label
463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private BasicBlock labelToBlock(int label) {
465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int idx = labelToResultIndex(label);
466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (idx < 0) {
468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalArgumentException("no such label " +
469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    Hex.u2(label));
470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return result.get(idx);
473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
474f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Adds a block to the output result.
47739c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
47899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param block {@code non-null;} the block to add
47939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @param subroutines {@code non-null;} subroutine label list
48039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * as described in {@link Frame#getSubroutines}
481f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
482f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void addBlock(BasicBlock block, IntList subroutines) {
483f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (block == null) {
484f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("block == null");
485f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        result.add(block);
488f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        subroutines.throwIfMutable();
489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        resultSubroutines.add(subroutines);
490f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
491f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
493f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Adds or replace a block in the output result. If this is a
494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * replacement, then any extra blocks that got added with the
495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * original get removed as a result of calling this method.
49639c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
49799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param block {@code non-null;} the block to add or replace
49839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @param subroutines {@code non-null;} subroutine label list
49939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * as described in {@link Frame#getSubroutines}
50099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code true} if the block was replaced or
50199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code false} if it was added for the first time
502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean addOrReplaceBlock(BasicBlock block, IntList subroutines) {
504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (block == null) {
505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("block == null");
506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int idx = labelToResultIndex(block.getLabel());
509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean ret;
510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
511f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (idx < 0) {
512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ret = false;
513f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
514f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
515f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * We are replacing a pre-existing block, so find any
516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * blocks that got added as part of the original and
517f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * remove those too. Such blocks are (possibly indirect)
518f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * successors of this block which are out of the range of
519f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * normally-translated blocks.
520f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
521f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            removeBlockAndSpecialSuccessors(idx);
522f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ret = true;
523f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
524f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
525f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        result.add(block);
526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        subroutines.throwIfMutable();
527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        resultSubroutines.add(subroutines);
528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return ret;
529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
530f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Adds or replaces a block in the output result. Do not delete
533f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * any successors.
534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
53599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param block {@code non-null;} the block to add or replace
53639c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @param subroutines {@code non-null;} subroutine label list
53739c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * as described in {@link Frame#getSubroutines}
53899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code true} if the block was replaced or
53999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code false} if it was added for the first time
540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean addOrReplaceBlockNoDelete(BasicBlock block,
542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            IntList subroutines) {
543f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (block == null) {
544f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("block == null");
545f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
546f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
547f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int idx = labelToResultIndex(block.getLabel());
548f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean ret;
549f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
550f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (idx < 0) {
551f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ret = false;
552f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
553f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            result.remove(idx);
554f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            resultSubroutines.remove(idx);
555f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ret = true;
556f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
557f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
558f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        result.add(block);
559f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        subroutines.throwIfMutable();
560f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        resultSubroutines.add(subroutines);
561f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return ret;
562f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
563f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
564f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
565f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Helper for {@link #addOrReplaceBlock} which recursively removes
566f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the given block and all blocks that are (direct and indirect)
567f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * successors of it whose labels indicate that they are not in the
568f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * normally-translated range.
56939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
57099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param idx {@code non-null;} block to remove (etc.)
571f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
572f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void removeBlockAndSpecialSuccessors(int idx) {
573f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int minLabel = getMinimumUnreservedLabel();
574f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        BasicBlock block = result.get(idx);
575f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        IntList successors = block.getSuccessors();
576f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = successors.size();
577f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
578f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        result.remove(idx);
579f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        resultSubroutines.remove(idx);
580f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
581f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < sz; i++) {
582f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int label = successors.get(i);
583f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (label >= minLabel) {
584f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                idx = labelToResultIndex(label);
585f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (idx < 0) {
586f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new RuntimeException("Invalid label "
587f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            + Hex.u2(label));
588f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
589f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                removeBlockAndSpecialSuccessors(idx);
590f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
591f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
592f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
593f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
594f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
595f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Extracts the resulting {@link RopMethod} from the instance.
59639c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
59799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the method object
598f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
599f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private RopMethod getRopMethod() {
600f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
601f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Construct the final list of blocks.
602f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
603f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = result.size();
604f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        BasicBlockList bbl = new BasicBlockList(sz);
605f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < sz; i++) {
606f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            bbl.set(i, result.get(i));
607f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
608f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bbl.setImmutable();
609f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
610f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Construct the method object to wrap it all up.
611f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
612f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
613f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Note: The parameter assignment block is always the first
614f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * that should be executed, hence the second argument to the
615f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * constructor.
616f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
617f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return new RopMethod(bbl, getSpecialLabel(PARAM_ASSIGNMENT));
618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
619f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
620f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
621f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Does the conversion.
622f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
623f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void doit() {
624f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int[] workSet = Bits.makeBitSet(maxLabel);
625f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
626f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Bits.set(workSet, 0);
627f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addSetupBlocks();
628f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setFirstFrame();
629f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
630f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (;;) {
631f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int offset = Bits.findFirst(workSet, 0);
632f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (offset < 0) {
633f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
634f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
635f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Bits.clear(workSet, offset);
636f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ByteBlock block = blocks.labelToBlock(offset);
637f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Frame frame = startFrames[offset];
638f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            try {
639f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                processBlock(block, frame, workSet);
640f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } catch (SimException ex) {
641f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.addContext("...while working on block " + Hex.u2(offset));
642f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw ex;
643f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
644f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
645f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
646f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addReturnBlock();
647f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addSynchExceptionHandlerBlock();
648f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addExceptionSetupBlocks();
649f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
650f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (hasSubroutines) {
651f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Subroutines are very rare, so skip this step if it's n/a
652f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            inlineSubroutines();
653f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
654f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
655f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
656f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
657f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Sets up the first frame to contain all the incoming parameters in
658f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * locals.
659f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
660f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void setFirstFrame() {
661f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Prototype desc = method.getEffectiveDescriptor();
662f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        startFrames[0].initializeWithParameters(desc.getParameterTypes());
663f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        startFrames[0].setImmutable();
664f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
665f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
666f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
667f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Processes the given block.
66839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
66999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param block {@code non-null;} block to process
67099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param frame {@code non-null;} start frame for the block
67139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @param workSet {@code non-null;} bits representing work to do,
67239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * which this method may add to
673f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
674f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void processBlock(ByteBlock block, Frame frame, int[] workSet) {
675f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Prepare the list of caught exceptions for this block.
676f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ByteCatchList catches = block.getCatches();
677f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        machine.startBlock(catches.toRopCatchList());
678f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
679f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
680f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Using a copy of the given frame, simulate each instruction,
681f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * calling into machine for each.
682f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
683f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        frame = frame.copy();
684f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sim.simulate(block, frame);
685f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        frame.setImmutable();
686f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
687f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int extraBlockCount = machine.getExtraBlockCount();
688f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ArrayList<Insn> insns = machine.getInsns();
689f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int insnSz = insns.size();
690f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
691f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
692f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Merge the frame into each possible non-exceptional
693f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * successor.
694f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
695f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
696f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int catchSz = catches.size();
697f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        IntList successors = block.getSuccessors();
698f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
699f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int startSuccessorIndex;
700f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
701f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Subroutine calledSubroutine = null;
702f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (machine.hasJsr()) {
703f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
704f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * If this frame ends in a JSR, only merge our frame with
705f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * the subroutine start, not the subroutine's return target.
706f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
707f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            startSuccessorIndex = 1;
708f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
709f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int subroutineLabel = successors.get(1);
710f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
711f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (subroutines[subroutineLabel] == null) {
71239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein                subroutines[subroutineLabel] =
71339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein                    new Subroutine (subroutineLabel);
714f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
71539c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein
716f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            subroutines[subroutineLabel].addCallerBlock(block.getLabel());
717f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
718f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            calledSubroutine = subroutines[subroutineLabel];
719f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (machine.hasRet()) {
720f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
721f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * This block ends in a ret, which means it's the final block
722f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * in some subroutine. Ultimately, this block will be copied
723f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * and inlined for each call and then disposed of.
724f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
725f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
726f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            ReturnAddress ra = machine.getReturnAddress();
727f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int subroutineLabel = ra.getSubroutineAddress();
728f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
729f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (subroutines[subroutineLabel] == null) {
730f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                subroutines[subroutineLabel]
731f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        = new Subroutine (subroutineLabel, block.getLabel());
732f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
733f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                subroutines[subroutineLabel].addRetBlock(block.getLabel());
734f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
735f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
736f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            successors = subroutines[subroutineLabel].getSuccessors();
737f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            subroutines[subroutineLabel]
738f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    .mergeToSuccessors(frame, workSet);
739f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Skip processing below since we just did it.
740f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            startSuccessorIndex = successors.size();
741f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else if (machine.wereCatchesUsed()) {
742f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
743f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * If there are catches, then the first successors
744f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * (which will either be all of them or all but the last one)
745f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * are catch targets.
746f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
747f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            startSuccessorIndex = catchSz;
748f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
749f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            startSuccessorIndex = 0;
750f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
751f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
752f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int succSz = successors.size();
753f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = startSuccessorIndex; i < succSz;
754f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             i++) {
755f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int succ = successors.get(i);
756f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            try {
757f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                mergeAndWorkAsNecessary(succ, block.getLabel(),
758f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        calledSubroutine, frame, workSet);
759f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } catch (SimException ex) {
760f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ex.addContext("...while merging to block " + Hex.u2(succ));
761f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                throw ex;
762f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
763f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
764f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
765f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((succSz == 0) && machine.returns()) {
766f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
767f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * The block originally contained a return, but it has
768f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * been made to instead end with a goto, and we need to
769f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * tell it at this point that its sole successor is the
770f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * return block. This has to happen after the merge loop
771f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * above, since, at this point, the return block doesn't
772f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * actually exist; it gets synthesized at the end of
773f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * processing the original blocks.
774f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
775f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            successors = IntList.makeImmutable(getSpecialLabel(RETURN));
776f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            succSz = 1;
777f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
778f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
779f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int primarySucc;
780f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
781f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (succSz == 0) {
782f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            primarySucc = -1;
783f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
784f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            primarySucc = machine.getPrimarySuccessorIndex();
785f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (primarySucc >= 0) {
786f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                primarySucc = successors.get(primarySucc);
787f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
788f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
789f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
790f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
791f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * This variable is true only when the method is synchronized and
792f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * the block being processed can possibly throw an exception.
793f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
794f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean synch = isSynchronized() && machine.canThrow();
795f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
796f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (synch || (catchSz != 0)) {
797f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
798f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Deal with exception handlers: Merge an exception-catch
799f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * frame into each possible exception handler, and
800f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * construct a new set of successors to point at the
801f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * exception handler setup blocks (which get synthesized
802f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * at the very end of processing).
803f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
804f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            boolean catchesAny = false;
805f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            IntList newSucc = new IntList(succSz);
806f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            for (int i = 0; i < catchSz; i++) {
807f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ByteCatchList.Item one = catches.get(i);
808f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                CstType exceptionClass = one.getExceptionClass();
809f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int targ = one.getHandlerPc();
810f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
811f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                catchesAny |= (exceptionClass == CstType.OBJECT);
812f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
813f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Frame f = frame.makeExceptionHandlerStartFrame(exceptionClass);
814f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
815f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                try {
816f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    mergeAndWorkAsNecessary(targ, block.getLabel(),
817f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            null, f, workSet);
818f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } catch (SimException ex) {
819f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    ex.addContext("...while merging exception to block " +
820f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                  Hex.u2(targ));
821f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw ex;
822f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
823f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
824f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
825f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * Set up the exception handler type, by setting it if
826f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * the given handler has yet to be encountered, or by
827f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * conservatively unioning if it has.
828f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
829f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Type already = catchTypes[targ];
830f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (already == null) {
831f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    catchTypes[targ] = exceptionClass.getClassType();
832f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                } else if (already != exceptionClass.getClassType()) {
833f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    catchTypes[targ] = Type.OBJECT;
834f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
835f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
836f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
837f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * The synthesized exception setup block will have the
838f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * label getExceptionSetupLabel(targ).
839f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
840f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                newSucc.add(getExceptionSetupLabel(targ));
841f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
842f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
843f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (synch && !catchesAny) {
844f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
845f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * The method is synchronized and this block doesn't
846f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * already have a catch-all handler, so add one to the
847f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * end, both in the successors and in the throwing
848f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * instruction(s) at the end of the block (which is where
849f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * the caught classes live).
850f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
851f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                newSucc.add(getSpecialLabel(SYNCH_CATCH_1));
852f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                synchNeedsExceptionHandler = true;
853f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
854f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (int i = insnSz - extraBlockCount - 1; i < insnSz; i++) {
855f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    Insn insn = insns.get(i);
856f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (insn.canThrow()) {
857f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        insn = insn.withAddedCatch(Type.OBJECT);
858f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        insns.set(i, insn);
859f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
860f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
861f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
862f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
863f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (primarySucc >= 0) {
864f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                newSucc.add(primarySucc);
865f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
866f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
867f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            newSucc.setImmutable();
868f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            successors = newSucc;
869f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
870f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
871f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Construct the final resulting block(s), and store it (them).
872f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
873f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int primarySuccListIndex = successors.indexOf(primarySucc);
874f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
875f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
876f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * If there are any extra blocks, work backwards through the
877f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * list of instructions, adding single-instruction blocks, and
878f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * resetting the successors variables as appropriate.
879f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
880f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (/*extraBlockCount*/; extraBlockCount > 0; extraBlockCount--) {
881f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
882f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Some of the blocks that the RopperMachine wants added
883f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * are for move-result insns, and these need goto insns as well.
884f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
885f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Insn extraInsn = insns.get(--insnSz);
886f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            boolean needsGoto
887f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    = extraInsn.getOpcode().getBranchingness()
888f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        == Rop.BRANCH_NONE;
889f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            InsnList il = new InsnList(needsGoto ? 2 : 1);
890f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            IntList extraBlockSuccessors = successors;
891f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
892f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            il.set(0, extraInsn);
893f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
894f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (needsGoto) {
895f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                il.set(1, new PlainInsn(Rops.GOTO,
896f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        extraInsn.getPosition(), null,
897f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        RegisterSpecList.EMPTY));
898f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
899f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * Obviously, this block won't be throwing an exception
900f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * so it should only have one successor.
901f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
902f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                extraBlockSuccessors = IntList.makeImmutable(primarySucc);
903f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
904f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            il.setImmutable();
905f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
906f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int label = getAvailableLabel();
907f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            BasicBlock bb = new BasicBlock(label, il, extraBlockSuccessors,
908f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    primarySucc);
909f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // All of these extra blocks will be in the same subroutine
910f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            addBlock(bb, frame.getSubroutines());
911f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
912f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            successors = successors.mutableCopy();
913f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            successors.set(primarySuccListIndex, label);
914f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            successors.setImmutable();
915f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            primarySucc = label;
916f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
91739c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein
918f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Insn lastInsn = (insnSz == 0) ? null : insns.get(insnSz - 1);
919f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
920f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
921f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Add a goto to the end of the block if it doesn't already
922f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * end with a branch, to maintain the invariant that all
923f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * blocks end with a branch of some sort or other. Note that
924f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * it is possible for there to be blocks for which no
925f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * instructions were ever output (e.g., only consist of pop*
926f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * in the original Java bytecode).
927f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
928f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((lastInsn == null) ||
929f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            (lastInsn.getOpcode().getBranchingness() == Rop.BRANCH_NONE)) {
930f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            SourcePosition pos = (lastInsn == null) ? SourcePosition.NO_INFO :
931f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                lastInsn.getPosition();
932f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insns.add(new PlainInsn(Rops.GOTO, pos, null,
933f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                    RegisterSpecList.EMPTY));
934f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insnSz++;
935f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
93639c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein
937f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
938f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Construct a block for the remaining instructions (which in
939f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * the usual case is all of them).
940f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
941f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
942f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        InsnList il = new InsnList(insnSz);
943f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < insnSz; i++) {
944f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            il.set(i, insns.get(i));
945f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
946f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        il.setImmutable();
947f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
948f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        BasicBlock bb =
949f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            new BasicBlock(block.getLabel(), il, successors, primarySucc);
950f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addOrReplaceBlock(bb, frame.getSubroutines());
951f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
952f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
953f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
954f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Helper for {@link #processBlock}, which merges frames and
955f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * adds to the work set, as necessary.
95639c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
95799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param label {@code >= 0;} label to work on
95899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param pred  predecessor label; must be {@code >= 0} when
95999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code label} is a subroutine start block and calledSubroutine
960f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * is non-null. Otherwise, may be -1.
96199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param calledSubroutine {@code null-ok;} a Subroutine instance if
96299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * {@code label} is the first block in a subroutine.
96399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param frame {@code non-null;} new frame for the labelled block
96439c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @param workSet {@code non-null;} bits representing work to do,
96539c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * which this method may add to
966f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
967f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void mergeAndWorkAsNecessary(int label, int pred,
968f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Subroutine calledSubroutine, Frame frame, int[] workSet) {
969f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Frame existing = startFrames[label];
970f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Frame merged;
971f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
972f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (existing != null) {
973f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
974f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Some other block also continues at this label. Merge
975f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * the frames, and re-set the bit in the work set if there
976f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * was a change.
977f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
978f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (calledSubroutine != null) {
979f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                merged = existing.mergeWithSubroutineCaller(frame,
980f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        calledSubroutine.getStartBlock(), pred);
981f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
982f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                merged = existing.mergeWith(frame);
983f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
984f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (merged != existing) {
985f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                startFrames[label] = merged;
986f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Bits.set(workSet, label);
987f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
988f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
989f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // This is the first time this label has been encountered.
990f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (calledSubroutine != null) {
991f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                startFrames[label]
992f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        = frame.makeNewSubroutineStartFrame(label, pred);
993f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
994f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                startFrames[label] = frame;
995f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
996f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Bits.set(workSet, label);
997f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
998f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
999f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1000f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1001f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs and adds the blocks that perform setup for the rest of
1002f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the method. This includes a first block which merely contains
1003f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * assignments from parameters to the same-numbered registers and
1004f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * a possible second block which deals with synchronization.
1005f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1006f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void addSetupBlocks() {
1007f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LocalVariableList localVariables = method.getLocalVariables();
1008f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        SourcePosition pos = method.makeSourcePosistion(0);
1009f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Prototype desc = method.getEffectiveDescriptor();
1010f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        StdTypeList params = desc.getParameterTypes();
1011f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = params.size();
1012f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        InsnList insns = new InsnList(sz + 1);
1013f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int at = 0;
1014f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1015f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < sz; i++) {
1016f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Type one = params.get(i);
101739c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein            LocalVariableList.Item local =
101839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein                localVariables.pcAndIndexToLocal(0, at);
1019f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            RegisterSpec result = (local == null) ?
1020f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                RegisterSpec.make(at, one) :
1021f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                RegisterSpec.makeLocalOptional(at, one, local.getLocalItem());
1022f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1023f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Insn insn = new PlainCstInsn(Rops.opMoveParam(one), pos, result,
1024f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                         RegisterSpecList.EMPTY,
1025f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                         CstInteger.make(at));
1026f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insns.set(i, insn);
1027f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            at += one.getCategory();
1028f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1029f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
103039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein        insns.set(sz, new PlainInsn(Rops.GOTO, pos, null,
1031f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                    RegisterSpecList.EMPTY));
1032f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns.setImmutable();
1033f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1034f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean synch = isSynchronized();
1035f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int label = synch ? getSpecialLabel(SYNCH_SETUP_1) : 0;
1036f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        BasicBlock bb =
1037f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            new BasicBlock(getSpecialLabel(PARAM_ASSIGNMENT), insns,
1038f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                           IntList.makeImmutable(label), label);
1039f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addBlock(bb, IntList.EMPTY);
1040f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1041f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (synch) {
1042f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            RegisterSpec synchReg = getSynchReg();
1043f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Insn insn;
1044f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (isStatic()) {
1045f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insn = new ThrowingCstInsn(Rops.CONST_OBJECT, pos,
1046f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                           RegisterSpecList.EMPTY,
1047f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                           StdTypeList.EMPTY,
1048f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                           method.getDefiningClass());
1049f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insns = new InsnList(1);
1050f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insns.set(0, insn);
1051f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
1052f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insns = new InsnList(2);
1053f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insn = new PlainCstInsn(Rops.MOVE_PARAM_OBJECT, pos,
1054f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                        synchReg, RegisterSpecList.EMPTY,
1055f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                        CstInteger.VALUE_0);
1056f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insns.set(0, insn);
1057f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insns.set(1, new PlainInsn(Rops.GOTO, pos, null,
1058f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                           RegisterSpecList.EMPTY));
1059f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1060f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1061f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int label2 = getSpecialLabel(SYNCH_SETUP_2);
1062f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insns.setImmutable();
1063f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            bb = new BasicBlock(label, insns,
1064f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                IntList.makeImmutable(label2), label2);
1065f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            addBlock(bb, IntList.EMPTY);
1066f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1067f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insns = new InsnList(isStatic() ? 2 : 1);
1068f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1069f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (isStatic()) {
1070f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insns.set(0, new PlainInsn(Rops.opMoveResultPseudo(synchReg),
1071f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        pos, synchReg, RegisterSpecList.EMPTY));
1072f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1073f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1074f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insn = new ThrowingInsn(Rops.MONITOR_ENTER, pos,
1075f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                    RegisterSpecList.make(synchReg),
1076f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                    StdTypeList.EMPTY);
1077f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insns.set(isStatic() ? 1 :0, insn);
1078f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insns.setImmutable();
1079f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            bb = new BasicBlock(label2, insns, IntList.makeImmutable(0), 0);
1080f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            addBlock(bb, IntList.EMPTY);
1081f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1082f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1083f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1084f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1085f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs and adds the return block, if necessary. The return
108699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * block merely contains an appropriate {@code return}
1087f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * instruction.
1088f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1089f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void addReturnBlock() {
1090f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Rop returnOp = machine.getReturnOp();
1091f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1092f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (returnOp == null) {
1093f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
1094f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * The method being converted never returns normally, so there's
1095f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * no need for a return block.
1096f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
1097f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
1098f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1099f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        SourcePosition returnPos = machine.getReturnPosition();
1101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int label = getSpecialLabel(RETURN);
1102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (isSynchronized()) {
1104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            InsnList insns = new InsnList(1);
1105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Insn insn = new ThrowingInsn(Rops.MONITOR_EXIT, returnPos,
1106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                         RegisterSpecList.make(getSynchReg()),
1107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                         StdTypeList.EMPTY);
1108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insns.set(0, insn);
1109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            insns.setImmutable();
1110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int nextLabel = getSpecialLabel(SYNCH_RETURN);
1112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            BasicBlock bb =
1113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                new BasicBlock(label, insns,
1114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                               IntList.makeImmutable(nextLabel), nextLabel);
1115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            addBlock(bb, IntList.EMPTY);
1116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            label = nextLabel;
1118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        InsnList insns = new InsnList(1);
1121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        TypeList sourceTypes = returnOp.getSources();
1122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        RegisterSpecList sources;
1123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (sourceTypes.size() == 0) {
1125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sources = RegisterSpecList.EMPTY;
1126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
1127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            RegisterSpec source = RegisterSpec.make(0, sourceTypes.getType(0));
1128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sources = RegisterSpecList.make(source);
1129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Insn insn = new PlainInsn(returnOp, returnPos, null, sources);
1132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns.set(0, insn);
1133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns.setImmutable();
1134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        BasicBlock bb = new BasicBlock(label, insns, IntList.EMPTY, -1);
1136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addBlock(bb, IntList.EMPTY);
1137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs and adds, if necessary, the catch-all exception handler
1141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * block to deal with unwinding the lock taken on entry to a synchronized
1142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * method.
1143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void addSynchExceptionHandlerBlock() {
1145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!synchNeedsExceptionHandler) {
1146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
1147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * The method being converted either isn't synchronized or
1148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * can't possibly throw exceptions in its main body, so
1149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * there's no need for a synchronized method exception
1150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * handler.
1151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
1152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return;
1153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        SourcePosition pos = method.makeSourcePosistion(0);
1156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        RegisterSpec exReg = RegisterSpec.make(0, Type.THROWABLE);
1157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        BasicBlock bb;
1158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        Insn insn;
1159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        InsnList insns = new InsnList(2);
1161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insn = new PlainInsn(Rops.opMoveException(Type.THROWABLE), pos,
1162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                             exReg, RegisterSpecList.EMPTY);
1163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns.set(0, insn);
1164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insn = new ThrowingInsn(Rops.MONITOR_EXIT, pos,
1165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                RegisterSpecList.make(getSynchReg()),
1166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                StdTypeList.EMPTY);
1167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns.set(1, insn);
1168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns.setImmutable();
1169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int label2 = getSpecialLabel(SYNCH_CATCH_2);
1171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bb = new BasicBlock(getSpecialLabel(SYNCH_CATCH_1), insns,
1172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            IntList.makeImmutable(label2), label2);
1173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addBlock(bb, IntList.EMPTY);
1174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns = new InsnList(1);
1176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insn = new ThrowingInsn(Rops.THROW, pos,
1177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                RegisterSpecList.make(exReg),
1178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                StdTypeList.EMPTY);
1179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns.set(0, insn);
1180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        insns.setImmutable();
1181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bb = new BasicBlock(label2, insns, IntList.EMPTY, -1);
1183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        addBlock(bb, IntList.EMPTY);
1184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Creates the exception handler setup blocks. "maxLocals"
1188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * below is because that's the register number corresponding
1189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * to the sole element on a one-deep stack (which is the
1190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * situation at the start of an exception handler block).
1191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void addExceptionSetupBlocks() {
1193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int len = catchTypes.length;
1195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < len; i++) {
1196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Type one = catchTypes[i];
1197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (one != null) {
1198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Insn proto = labelToBlock(i).getFirstInsn();
1199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                SourcePosition pos = proto.getPosition();
1200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                InsnList il = new InsnList(2);
1201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Insn insn = new PlainInsn(Rops.opMoveException(one),
1203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                          pos,
1204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                          RegisterSpec.make(maxLocals, one),
1205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                          RegisterSpecList.EMPTY);
1206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                il.set(0, insn);
1207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                insn = new PlainInsn(Rops.GOTO, pos, null,
1209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                     RegisterSpecList.EMPTY);
1210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                il.set(1, insn);
1211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                il.setImmutable();
1212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                BasicBlock bb = new BasicBlock(getExceptionSetupLabel(i),
1214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                               il,
1215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                               IntList.makeImmutable(i),
1216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                               i);
1217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                addBlock(bb, startFrames[i].getSubroutines());
1218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Checks to see if the basic block is a subroutine caller block.
1224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
122599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param bb {@code non-null;} the basic block in question
1226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @return true if this block calls a subroutine
1227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private boolean isSubroutineCaller(BasicBlock bb) {
1229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        IntList successors = bb.getSuccessors();
1230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (successors.size() < 2) return false;
1231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int subLabel = successors.get(1);
1233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return (subLabel < subroutines.length)
1235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                && (subroutines[subLabel] != null);
1236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
123939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * Inlines any subroutine calls.
1240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void inlineSubroutines() {
1242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        final IntList reachableSubroutineCallerLabels = new IntList(4);
1243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
1245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Compile a list of all subroutine calls reachable
1246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * through the normal (non-subroutine) flow.  We do this first, since
1247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * we'll be affecting the call flow as we go.
124839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         *
1249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Start at label 0 --  the param assignment block has nothing for us
1250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        forEachNonSubBlockDepthFirst(0, new BasicBlock.Visitor() {
1252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            public void visitBlock(BasicBlock b) {
1253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (isSubroutineCaller(b)) {
1254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    reachableSubroutineCallerLabels.add(b.getLabel());
1255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        });
1258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
1260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Convert the resultSubroutines list, indexed by block index,
1261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * to a label-to-subroutines mapping used by the inliner.
1262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int largestAllocedLabel = getAvailableLabel();
1264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        ArrayList<IntList> labelToSubroutines
1265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                = new ArrayList<IntList>(largestAllocedLabel);
1266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < largestAllocedLabel; i++) {
1267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            labelToSubroutines.add(null);
1268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < result.size(); i++) {
1271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            BasicBlock b = result.get(i);
1272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (b == null) {
1273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                continue;
1274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            IntList subroutineList = resultSubroutines.get(i);
1276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            labelToSubroutines.set(b.getLabel(), subroutineList);
1277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
128039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         * Inline all reachable subroutines.
128139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         * Inner subroutines will be inlined as they are encountered.
128239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         */
1283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = reachableSubroutineCallerLabels.size();
1284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0 ; i < sz ; i++) {
1285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int label = reachableSubroutineCallerLabels.get(i);
1286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            new SubroutineInliner(
128739c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein                    new LabelAllocator(getAvailableLabel()),
128839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein                    labelToSubroutines)
1289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    .inlineSubroutineCalledFrom(labelToBlock(label));
1290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Now find the blocks that aren't reachable and remove them
1293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        deleteUnreachableBlocks();
1294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Deletes all blocks that cannot be reached. This is run to delete
1298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * original subroutine blocks after subroutine inlining.
1299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void deleteUnreachableBlocks() {
1301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        final IntList reachableLabels = new IntList(result.size());
1302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // subroutine inlining is done now and we won't update this list here
1304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        resultSubroutines.clear();
1305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        forEachNonSubBlockDepthFirst(getSpecialLabel(PARAM_ASSIGNMENT),
1307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                new BasicBlock.Visitor() {
1308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            public void visitBlock(BasicBlock b) {
1310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                reachableLabels.add(b.getLabel());
1311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        });
1313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        reachableLabels.sort();
1315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = result.size() - 1 ; i >= 0 ; i--) {
1317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (reachableLabels.indexOf(result.get(i).getLabel()) < 0) {
1318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                result.remove(i);
1319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // unnecessary here really, since subroutine inlining is done
1320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                //resultSubroutines.remove(i);
1321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Allocates labels, without requiring previously allocated labels
1327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * to have been added to the blocks list.
1328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static class LabelAllocator {
1330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int nextAvailableLabel;
1331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
1333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param startLabel available label to start allocating from
1334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LabelAllocator(int startLabel) {
1336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            nextAvailableLabel = startLabel;
1337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
1340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @return next available label
1341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int getNextLabel() {
1343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return nextAvailableLabel++;
1344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Inlines a subroutine. Start by calling
134939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * {@link #inlineSubroutineCalledFrom}.
1350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private class SubroutineInliner {
1352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
135339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         * maps original label to the label that will be used by the
135439c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         * inlined version
1355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private final HashMap<Integer, Integer> origLabelToCopiedLabel;
1357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
135839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein        /** set of original labels that need to be copied */
1359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private final BitSet workList;
1360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
136139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein        /** the label of the original start block for this subroutine */
1362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private int subroutineStart;
1363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
136439c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein        /** the label of the ultimate return block */
1365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private int subroutineSuccessor;
1366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
136739c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein        /** used for generating new labels for copied blocks */
1368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private final LabelAllocator labelAllocator;
1369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
1371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * A mapping, indexed by label, to subroutine nesting list.
1372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * The subroutine nest list is as returned by
1373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * {@link Frame#getSubroutines}.
1374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private final ArrayList<IntList> labelToSubroutines;
1376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        SubroutineInliner(final LabelAllocator labelAllocator,
1378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                ArrayList<IntList> labelToSubroutines) {
1379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            origLabelToCopiedLabel = new HashMap<Integer, Integer>();
1380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            workList = new BitSet(maxLabel);
1382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.labelAllocator = labelAllocator;
1384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            this.labelToSubroutines = labelToSubroutines;
1385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
1388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Inlines a subroutine.
138939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         *
139039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         * @param b block where {@code jsr} occurred in the original bytecode
1391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        void inlineSubroutineCalledFrom(final BasicBlock b) {
1393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
1394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * The 0th successor of a subroutine caller block is where
1395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * the subroutine should return to. The 1st successor is
1396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * the start block of the subroutine.
1397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
1398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            subroutineSuccessor = b.getSuccessors().get(0);
1399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            subroutineStart = b.getSuccessors().get(1);
1400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
1402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * This allocates an initial label and adds the first
1403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * block to the worklist.
1404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
1405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int newSubStartLabel = mapOrAllocateLabel(subroutineStart);
1406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
140741aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein            for (int label = workList.nextSetBit(0); label >= 0;
140841aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein                 label = workList.nextSetBit(0)) {
1409f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                workList.clear(label);
1410f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int newLabel = origLabelToCopiedLabel.get(label);
1411f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1412f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                copyBlock(label, newLabel);
1413f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1414f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (isSubroutineCaller(labelToBlock(label))) {
1415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    new SubroutineInliner(labelAllocator, labelToSubroutines)
1416f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        .inlineSubroutineCalledFrom(labelToBlock(newLabel));
1417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1418f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1420f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
1421f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Replace the original caller block, since we now have a
1422f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * new successor
1423f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
1424f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1425f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            addOrReplaceBlockNoDelete(
1426f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                new BasicBlock(b.getLabel(), b.getInsns(),
1427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    IntList.makeImmutable (newSubStartLabel),
142841aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein                            newSubStartLabel),
142941aecd0a6bfea1e9a6713014b2b3d56fec8c552cDan Bornstein                labelToSubroutines.get(b.getLabel()));
14306b386bfb92ef6efe8f963270fc5a4b756fca225ejeffhao        }
1431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
1433f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Copies a basic block, mapping its successors along the way.
143439c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         *
1435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param origLabel original block label
1436f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param newLabel label that the new block should have
1437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
14386b386bfb92ef6efe8f963270fc5a4b756fca225ejeffhao        private void copyBlock(int origLabel, int newLabel) {
1439f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1440f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            BasicBlock origBlock = labelToBlock(origLabel);
1441f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1442f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            final IntList origSuccessors = origBlock.getSuccessors();
1443f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            IntList successors;
1444f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int primarySuccessor = -1;
1445f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Subroutine subroutine;
1446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1447f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (isSubroutineCaller(origBlock)) {
1448f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
1449f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * A subroutine call inside a subroutine call.
1450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * Set up so we can recurse. The caller block should have
1451f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * it's first successor be a copied block that will be
1452f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * the subroutine's return point. It's second successor will
1453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * be copied when we recurse, and remains as the original
1454f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * label of the start of the inner subroutine.
1455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
1456f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1457f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                successors = IntList.makeImmutable(
1458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        mapOrAllocateLabel(origSuccessors.get(0)),
1459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        origSuccessors.get(1));
1460f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // primary successor will be set when this block is replaced
1461f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else if (null
1462f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    != (subroutine = subroutineFromRetBlock(origLabel))) {
1463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
1464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * this is a ret block -- its successor
1465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * should be subroutineSuccessor
1466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
1467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // Sanity check
1469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (subroutine.startBlock != subroutineStart) {
1470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new RuntimeException (
1471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            "ret instruction returns to label "
1472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            + Hex.u2 (subroutine.startBlock)
1473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            + " expected: " + Hex.u2(subroutineStart));
1474f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                successors = IntList.makeImmutable(subroutineSuccessor);
1477f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                primarySuccessor = subroutineSuccessor;
1478f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
1479f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // Map all the successor labels
1480f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1481f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int origPrimary = origBlock.getPrimarySuccessor();
1482f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                int sz = origSuccessors.size();
1483f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1484f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                successors = new IntList(sz);
1485f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                for (int i = 0 ; i < sz ; i++) {
1487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int origSuccLabel = origSuccessors.get(i);
1488f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    int newSuccLabel =  mapOrAllocateLabel(origSuccLabel);
1489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1490f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    successors.add(newSuccLabel);
1491f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    if (origPrimary == origSuccLabel) {
1493f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        primarySuccessor = newSuccLabel;
1494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    }
1495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1496f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1497f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                successors.setImmutable();
1498f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1499f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            addBlock (
1501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                new BasicBlock(newLabel,
1502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    filterMoveReturnAddressInsns(origBlock.getInsns()),
1503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    successors, primarySuccessor),
1504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    labelToSubroutines.get(newLabel));
1505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
1508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Checks to see if a specified label is involved in a specified
1509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * subroutine.
1510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
151199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * @param label {@code >= 0;} a basic block label
151239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         * @param subroutineStart {@code >= 0;} a subroutine as identified
151339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         * by the label of its start block
151439c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein         * @return true if the block is dominated by the subroutine call
1515f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private boolean involvedInSubroutine(int label, int subroutineStart) {
1517f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            IntList subroutinesList = labelToSubroutines.get(label);
15186b386bfb92ef6efe8f963270fc5a4b756fca225ejeffhao            return (subroutinesList != null && subroutinesList.size() > 0
1519f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    && subroutinesList.top() == subroutineStart);
1520f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1521f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1522f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /**
1523f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Maps the label of a pre-copied block to the label of the inlined
1524f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * block, allocating a new label and adding it to the worklist
1525f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * if necessary.  If the origLabel is a "special" label, it
1526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * is returned exactly and not scheduled for duplication: copying
1527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * never proceeds past a special label, which likely is the function
1528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * return block or an immediate predecessor.
1529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
1530f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @param origLabel label of original, pre-copied block
1531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * @return label for new, inlined block
1532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
1533f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        private int mapOrAllocateLabel(int origLabel) {
1534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int resultLabel;
1535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Integer mappedLabel = origLabelToCopiedLabel.get(origLabel);
1536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (mappedLabel != null) {
1538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                resultLabel = mappedLabel;
1539f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else if (!involvedInSubroutine(origLabel,subroutineStart)) {
1540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /*
1541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * A subroutine has ended by some means other than a "ret"
1542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 * (which really means a throw caught later).
1543f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                 */
1544f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                resultLabel = origLabel;
1545f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
1546f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                resultLabel = labelAllocator.getNextLabel();
1547f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                workList.set(origLabel);
1548f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                origLabelToCopiedLabel.put(origLabel, resultLabel);
1549f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1550f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // The new label has the same frame as the original label
1551f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                while (labelToSubroutines.size() <= resultLabel) {
1552f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    labelToSubroutines.add(null);
1553f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1554f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                labelToSubroutines.set(resultLabel,
1555f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        labelToSubroutines.get(origLabel));
1556f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1557f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1558f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return resultLabel;
1559f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1560f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1561f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1562f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
156339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * Finds a {@code Subroutine} that is returned from by a {@code ret} in
1564f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * a given block.
156539c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
156639c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @param label A block that originally contained a {@code ret} instruction
156739c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @return {@code null-ok;} found subroutine or {@code null} if none
156839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * was found
1569f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1570f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private Subroutine subroutineFromRetBlock(int label) {
1571f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = subroutines.length - 1 ; i >= 0 ; i--) {
1572f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (subroutines[i] != null) {
1573f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                Subroutine subroutine = subroutines[i];
1574f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1575f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (subroutine.retBlocks.get(label)) {
1576f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    return subroutine;
1577f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
1578f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1579f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1580f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1581f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return null;
1582f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1583f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1584f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1585f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
158639c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * Removes all {@code move-return-address} instructions, returning a new
158739c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * {@code InsnList} if necessary. The {@code move-return-address}
158839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * insns are dead code after subroutines have been inlined.
1589f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
159039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @param insns {@code InsnList} that may contain
159139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * {@code move-return-address} insns
159239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * @return {@code InsnList} with {@code move-return-address} removed
1593f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1594f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private InsnList filterMoveReturnAddressInsns(InsnList insns) {
1595f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz;
1596f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int newSz = 0;
1597f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1598f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // First see if we need to filter, and if so what the new size will be
1599f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sz = insns.size();
1600f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < sz; i++) {
1601f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (insns.get(i).getOpcode() != Rops.MOVE_RETURN_ADDRESS) {
1602f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                newSz++;
1603f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1604f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1605f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1606f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (newSz == sz) {
1607f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return insns;
1608f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1609f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1610f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        // Make a new list without the MOVE_RETURN_ADDRESS insns
1611f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        InsnList newInsns = new InsnList(newSz);
1612f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1613f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int newIndex = 0;
1614f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (int i = 0; i < sz; i++) {
1615f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Insn insn = insns.get(i);
1616f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (insn.getOpcode() != Rops.MOVE_RETURN_ADDRESS) {
1617f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                newInsns.set(newIndex++, insn);
1618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1619f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1620f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1621f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        newInsns.setImmutable();
1622f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return newInsns;
1623f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1624f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1625f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
1626f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Visits each non-subroutine block once in depth-first successor order.
162739c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
1628f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param firstLabel label of start block
1629f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param v callback interface
1630f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
163139c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein    private void forEachNonSubBlockDepthFirst(int firstLabel,
163239c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein            BasicBlock.Visitor v) {
1633f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        forEachNonSubBlockDepthFirst0(labelToBlock(firstLabel),
1634f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                v, new BitSet(maxLabel));
1635f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1636f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1637f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
163839c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * Visits each block once in depth-first successor order, ignoring
163939c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     * {@code jsr} targets. Worker for {@link #forEachNonSubBlockDepthFirst}.
164039c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein     *
1641f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param next next block to visit
1642f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param v callback interface
1643f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * @param visited set of blocks already visited
1644f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1645f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private void forEachNonSubBlockDepthFirst0(
1646f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            BasicBlock next, BasicBlock.Visitor v, BitSet visited) {
1647f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        v.visitBlock(next);
1648f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        visited.set(next.getLabel());
1649f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1650f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        IntList successors = next.getSuccessors();
1651f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int sz = successors.size();
1652f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
165339c5899d0359c386815f5f72991a3a2573135dbdDan Bornstein        for (int i = 0; i < sz; i++) {
1654f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int succ = successors.get(i);
1655f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1656f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (visited.get(succ)) {
1657f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                continue;
1658f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1659f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1660f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (isSubroutineCaller(next) && i > 0) {
1661f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                // ignore jsr targets
1662f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                continue;
1663f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1664f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1665f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
1666f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Ignore missing labels: they're successors of
1667f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * subroutines that never invoke a ret.
1668f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
1669f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int idx = labelToResultIndex(succ);
1670f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (idx >= 0) {
1671f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                forEachNonSubBlockDepthFirst0(result.get(idx), v, visited);
1672f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
1673f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
1674f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
1675f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
1676