blob: 713bced68a802a11ac8c81327e7641c82b1da7ae [file] [log] [blame]
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Dalvik.h"
18#include "libdex/DexOpcodes.h"
19
20#include "../../CompilerInternals.h"
21#include "MipsLIR.h"
22#include "Codegen.h"
23#include <unistd.h> /* for cacheflush */
24#include <sys/mman.h> /* for protection change */
25
26#define MAX_ASSEMBLER_RETRIES 10
27
28/*
29 * opcode: MipsOpCode enum
30 * skeleton: pre-designated bit-pattern for this opcode
31 * k0: key to applying ds/de
32 * ds: dest start bit position
33 * de: dest end bit position
34 * k1: key to applying s1s/s1e
35 * s1s: src1 start bit position
36 * s1e: src1 end bit position
37 * k2: key to applying s2s/s2e
38 * s2s: src2 start bit position
39 * s2e: src2 end bit position
40 * operands: number of operands (for sanity check purposes)
41 * name: mnemonic name
42 * fmt: for pretty-printing
43 */
44#define ENCODING_MAP(opcode, skeleton, k0, ds, de, k1, s1s, s1e, k2, s2s, s2e, \
45 k3, k3s, k3e, flags, name, fmt, size) \
46 {skeleton, {{k0, ds, de}, {k1, s1s, s1e}, {k2, s2s, s2e}, \
47 {k3, k3s, k3e}}, opcode, flags, name, fmt, size}
48
49/* Instruction dump string format keys: !pf, where "!" is the start
50 * of the key, "p" is which numeric operand to use and "f" is the
51 * print format.
52 *
53 * [p]ositions:
54 * 0 -> operands[0] (dest)
55 * 1 -> operands[1] (src1)
56 * 2 -> operands[2] (src2)
57 * 3 -> operands[3] (extra)
58 *
59 * [f]ormats:
60 * h -> 4-digit hex
61 * d -> decimal
62 * E -> decimal*4
63 * F -> decimal*2
64 * c -> branch condition (beq, bne, etc.)
65 * t -> pc-relative target
66 * T -> pc-region target
67 * u -> 1st half of bl[x] target
68 * v -> 2nd half ob bl[x] target
69 * R -> register list
70 * s -> single precision floating point register
71 * S -> double precision floating point register
72 * m -> Thumb2 modified immediate
73 * n -> complimented Thumb2 modified immediate
74 * M -> Thumb2 16-bit zero-extended immediate
75 * b -> 4-digit binary
76 *
77 * [!] escape. To insert "!", use "!!"
78 */
79/* NOTE: must be kept in sync with enum MipsOpcode from MipsLIR.h */
80MipsEncodingMap EncodingMap[kMipsLast] = {
81 ENCODING_MAP(kMips32BitData, 0x00000000,
82 kFmtBitBlt, 31, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
83 kFmtUnused, -1, -1, IS_UNARY_OP,
84 "data", "0x!0h(!0d)", 2),
85 ENCODING_MAP(kMipsAddiu, 0x24000000,
86 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
87 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
88 "addiu", "!0r,!1r,0x!2h(!2d)", 2),
89 ENCODING_MAP(kMipsAddu, 0x00000021,
90 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
91 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
92 "addu", "!0r,!1r,!2r", 2),
93 ENCODING_MAP(kMipsAnd, 0x00000024,
94 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
95 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
96 "and", "!0r,!1r,!2r", 2),
97 ENCODING_MAP(kMipsAndi, 0x30000000,
98 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
99 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
100 "andi", "!0r,!1r,0x!2h(!2d)", 2),
101 ENCODING_MAP(kMipsB, 0x10000000,
102 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
103 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH,
104 "b", "!0t", 2),
105 ENCODING_MAP(kMipsBal, 0x04110000,
106 kFmtBitBlt, 15, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
107 kFmtUnused, -1, -1, NO_OPERAND | IS_BRANCH | REG_DEF_LR,
108 "bal", "!0t", 2),
109 ENCODING_MAP(kMipsBeq, 0x10000000,
110 kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
111 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01,
112 "beq", "!0r,!1r,!2t", 2),
113 ENCODING_MAP(kMipsBeqz, 0x10000000, /* same as beq above with t = $zero */
114 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
115 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
116 "beqz", "!0r,!1t", 2),
117 ENCODING_MAP(kMipsBgez, 0x04010000,
118 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
119 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
120 "bgez", "!0r,!1t", 2),
121 ENCODING_MAP(kMipsBgtz, 0x1C000000,
122 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
123 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
124 "bgtz", "!0r,!1t", 2),
125 ENCODING_MAP(kMipsBlez, 0x18000000,
126 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
127 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
128 "blez", "!0r,!1t", 2),
129 ENCODING_MAP(kMipsBltz, 0x04000000,
130 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
131 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
132 "bltz", "!0r,!1t", 2),
133 ENCODING_MAP(kMipsBnez, 0x14000000, /* same as bne below with t = $zero */
134 kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
135 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
136 "bnez", "!0r,!1t", 2),
137 ENCODING_MAP(kMipsBne, 0x14000000,
138 kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0,
139 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_USE01,
140 "bne", "!0r,!1r,!2t", 2),
141 ENCODING_MAP(kMipsDiv, 0x0000001a,
142 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtBitBlt, 25, 21,
143 kFmtBitBlt, 20, 16, IS_QUAD_OP | REG_DEF01 | REG_USE23,
144 "div", "!2r,!3r", 2),
145#if __mips_isa_rev>=2
146 ENCODING_MAP(kMipsExt, 0x7c000000,
147 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 10, 6,
148 kFmtBitBlt, 15, 11, IS_QUAD_OP | REG_DEF0 | REG_USE1,
149 "ext", "!0r,!1r,!2d,!3D", 2),
150#endif
151 ENCODING_MAP(kMipsJal, 0x0c000000,
152 kFmtBitBlt, 25, 0, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
153 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_DEF_LR,
154 "jal", "!0T(!0E)", 2),
155 ENCODING_MAP(kMipsJalr, 0x00000009,
156 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
157 kFmtUnused, -1, -1, IS_BINARY_OP | IS_BRANCH | REG_DEF0_USE1,
158 "jalr", "!0r,!1r", 2),
159 ENCODING_MAP(kMipsJr, 0x00000008,
160 kFmtBitBlt, 25, 21, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
161 kFmtUnused, -1, -1, IS_UNARY_OP | IS_BRANCH | REG_USE0,
162 "jr", "!0r", 2),
163 ENCODING_MAP(kMipsLahi, 0x3C000000,
164 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
165 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
166 "lahi/lui", "!0r,0x!1h(!1d)", 2),
167 ENCODING_MAP(kMipsLalo, 0x34000000,
168 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
169 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
170 "lalo/ori", "!0r,!1r,0x!2h(!2d)", 2),
171 ENCODING_MAP(kMipsLui, 0x3C000000,
172 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtUnused, -1, -1,
173 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
174 "lui", "!0r,0x!1h(!1d)", 2),
175 ENCODING_MAP(kMipsLb, 0x80000000,
176 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
177 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
178 "lb", "!0r,!1d(!2r)", 2),
179 ENCODING_MAP(kMipsLbu, 0x90000000,
180 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
181 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
182 "lbu", "!0r,!1d(!2r)", 2),
183 ENCODING_MAP(kMipsLh, 0x84000000,
184 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
185 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
186 "lh", "!0r,!1d(!2r)", 2),
187 ENCODING_MAP(kMipsLhu, 0x94000000,
188 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
189 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
190 "lhu", "!0r,!1d(!2r)", 2),
191 ENCODING_MAP(kMipsLw, 0x8C000000,
192 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
193 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
194 "lw", "!0r,!1d(!2r)", 2),
195 ENCODING_MAP(kMipsMfhi, 0x00000010,
196 kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
197 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
198 "mfhi", "!0r", 2),
199 ENCODING_MAP(kMipsMflo, 0x00000012,
200 kFmtBitBlt, 15, 11, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
201 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
202 "mflo", "!0r", 2),
203 ENCODING_MAP(kMipsMove, 0x00000025, /* or using zero reg */
204 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtUnused, -1, -1,
205 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
206 "move", "!0r,!1r", 2),
207 ENCODING_MAP(kMipsMovz, 0x0000000a,
208 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
209 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
210 "movz", "!0r,!1r,!2r", 2),
211 ENCODING_MAP(kMipsMul, 0x70000002,
212 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
213 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
214 "mul", "!0r,!1r,!2r", 2),
215 ENCODING_MAP(kMipsNop, 0x00000000,
216 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
217 kFmtUnused, -1, -1, NO_OPERAND,
218 "nop", "", 2),
219 ENCODING_MAP(kMipsNor, 0x00000027, /* used for "not" too */
220 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
221 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
222 "nor", "!0r,!1r,!2r", 2),
223 ENCODING_MAP(kMipsOr, 0x00000025,
224 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
225 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
226 "or", "!0r,!1r,!2r", 2),
227 ENCODING_MAP(kMipsOri, 0x34000000,
228 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
229 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
230 "ori", "!0r,!1r,0x!2h(!2d)", 2),
231 ENCODING_MAP(kMipsPref, 0xCC000000,
232 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
233 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE2,
234 "pref", "!0d,!1d(!2r)", 2),
235 ENCODING_MAP(kMipsSb, 0xA0000000,
236 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
237 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
238 "sb", "!0r,!1d(!2r)", 2),
239#if __mips_isa_rev>=2
240 ENCODING_MAP(kMipsSeb, 0x7c000420,
241 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
242 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
243 "seb", "!0r,!1r", 2),
244 ENCODING_MAP(kMipsSeh, 0x7c000620,
245 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtUnused, -1, -1,
246 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
247 "seh", "!0r,!1r", 2),
248#endif
249 ENCODING_MAP(kMipsSh, 0xA4000000,
250 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
251 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
252 "sh", "!0r,!1d(!2r)", 2),
253 ENCODING_MAP(kMipsSll, 0x00000000,
254 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
255 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
256 "sll", "!0r,!1r,0x!2h(!2d)", 2),
257 ENCODING_MAP(kMipsSllv, 0x00000004,
258 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
259 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
260 "sllv", "!0r,!1r,!2r", 2),
261 ENCODING_MAP(kMipsSlt, 0x0000002a,
262 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
263 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
264 "slt", "!0r,!1r,!2r", 2),
265 ENCODING_MAP(kMipsSlti, 0x28000000,
266 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
267 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
268 "slti", "!0r,!1r,0x!2h(!2d)", 2),
269 ENCODING_MAP(kMipsSltu, 0x0000002b,
270 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
271 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
272 "sltu", "!0r,!1r,!2r", 2),
273 ENCODING_MAP(kMipsSra, 0x00000003,
274 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
275 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
276 "sra", "!0r,!1r,0x!2h(!2d)", 2),
277 ENCODING_MAP(kMipsSrav, 0x00000007,
278 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
279 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
280 "srav", "!0r,!1r,!2r", 2),
281 ENCODING_MAP(kMipsSrl, 0x00000002,
282 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 10, 6,
283 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
284 "srl", "!0r,!1r,0x!2h(!2d)", 2),
285 ENCODING_MAP(kMipsSrlv, 0x00000006,
286 kFmtBitBlt, 15, 11, kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21,
287 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
288 "srlv", "!0r,!1r,!2r", 2),
289 ENCODING_MAP(kMipsSubu, 0x00000023, /* used for "neg" too */
290 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
291 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
292 "subu", "!0r,!1r,!2r", 2),
293 ENCODING_MAP(kMipsSw, 0xAC000000,
294 kFmtBitBlt, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
295 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
296 "sw", "!0r,!1d(!2r)", 2),
297 ENCODING_MAP(kMipsXor, 0x00000026,
298 kFmtBitBlt, 15, 11, kFmtBitBlt, 25, 21, kFmtBitBlt, 20, 16,
299 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
300 "xor", "!0r,!1r,!2r", 2),
301 ENCODING_MAP(kMipsXori, 0x38000000,
302 kFmtBitBlt, 20, 16, kFmtBitBlt, 25, 21, kFmtBitBlt, 15, 0,
303 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE1,
304 "xori", "!0r,!1r,0x!2h(!2d)", 2),
305#ifdef __mips_hard_float
306 ENCODING_MAP(kMipsFadds, 0x46000000,
307 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
308 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
309 "add.s", "!0s,!1s,!2s", 2),
310 ENCODING_MAP(kMipsFsubs, 0x46000001,
311 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
312 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
313 "sub.s", "!0s,!1s,!2s", 2),
314 ENCODING_MAP(kMipsFmuls, 0x46000002,
315 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
316 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
317 "mul.s", "!0s,!1s,!2s", 2),
318 ENCODING_MAP(kMipsFdivs, 0x46000003,
319 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtSfp, 20, 16,
320 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
321 "div.s", "!0s,!1s,!2s", 2),
322 ENCODING_MAP(kMipsFaddd, 0x46200000,
323 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
324 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
325 "add.d", "!0S,!1S,!2S", 2),
326 ENCODING_MAP(kMipsFsubd, 0x46200001,
327 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
328 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
329 "sub.d", "!0S,!1S,!2S", 2),
330 ENCODING_MAP(kMipsFmuld, 0x46200002,
331 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
332 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
333 "mul.d", "!0S,!1S,!2S", 2),
334 ENCODING_MAP(kMipsFdivd, 0x46200003,
335 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtDfp, 20, 16,
336 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE12,
337 "div.d", "!0S,!1S,!2S", 2),
338 ENCODING_MAP(kMipsFcvtsd, 0x46200020,
339 kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
340 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
341 "cvt.s.d", "!0s,!1S", 2),
342 ENCODING_MAP(kMipsFcvtsw, 0x46800020,
343 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
344 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
345 "cvt.s.w", "!0s,!1s", 2),
346 ENCODING_MAP(kMipsFcvtds, 0x46000021,
347 kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
348 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
349 "cvt.d.s", "!0S,!1s", 2),
350 ENCODING_MAP(kMipsFcvtdw, 0x46800021,
351 kFmtDfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
352 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
353 "cvt.d.w", "!0S,!1s", 2),
354 ENCODING_MAP(kMipsFcvtws, 0x46000024,
355 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
356 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
357 "cvt.w.s", "!0s,!1s", 2),
358 ENCODING_MAP(kMipsFcvtwd, 0x46200024,
359 kFmtSfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
360 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
361 "cvt.w.d", "!0s,!1S", 2),
362 ENCODING_MAP(kMipsFmovs, 0x46000006,
363 kFmtSfp, 10, 6, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
364 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
365 "mov.s", "!0s,!1s", 2),
366 ENCODING_MAP(kMipsFmovd, 0x46200006,
367 kFmtDfp, 10, 6, kFmtDfp, 15, 11, kFmtUnused, -1, -1,
368 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
369 "mov.d", "!0S,!1S", 2),
370 ENCODING_MAP(kMipsFlwc1, 0xC4000000,
371 kFmtSfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
372 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
373 "lwc1", "!0s,!1d(!2r)", 2),
374 ENCODING_MAP(kMipsFldc1, 0xD4000000,
375 kFmtDfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
376 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_DEF0_USE2 | IS_LOAD,
377 "ldc1", "!0S,!1d(!2r)", 2),
378 ENCODING_MAP(kMipsFswc1, 0xE4000000,
379 kFmtSfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
380 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
381 "swc1", "!0s,!1d(!2r)", 2),
382 ENCODING_MAP(kMipsFsdc1, 0xF4000000,
383 kFmtDfp, 20, 16, kFmtBitBlt, 15, 0, kFmtBitBlt, 25, 21,
384 kFmtUnused, -1, -1, IS_TERTIARY_OP | REG_USE02 | IS_STORE,
385 "sdc1", "!0S,!1d(!2r)", 2),
386 ENCODING_MAP(kMipsMfc1, 0x44000000,
387 kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
388 kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0_USE1,
389 "mfc1", "!0r,!1s", 2),
390 ENCODING_MAP(kMipsMtc1, 0x44800000,
391 kFmtBitBlt, 20, 16, kFmtSfp, 15, 11, kFmtUnused, -1, -1,
392 kFmtUnused, -1, -1, IS_BINARY_OP | REG_USE0 | REG_DEF1,
393 "mtc1", "!0r,!1s", 2),
394#endif
395 ENCODING_MAP(kMipsUndefined, 0x64000000,
396 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
397 kFmtUnused, -1, -1, NO_OPERAND,
398 "undefined", "", 2),
399};
400
401/* Track the number of times that the code cache is patched */
402#if defined(WITH_JIT_TUNING)
403#define UPDATE_CODE_CACHE_PATCHES() (gDvmJit.codeCachePatches++)
404#else
405#define UPDATE_CODE_CACHE_PATCHES()
406#endif
407
408/* Write the numbers in the constant and class pool to the output stream */
409static void installLiteralPools(CompilationUnit *cUnit)
410{
411 int *dataPtr = (int *) ((char *) cUnit->baseAddr + cUnit->dataOffset);
412 /* Install number of class pointer literals */
413 *dataPtr++ = cUnit->numClassPointers;
414 MipsLIR *dataLIR = (MipsLIR *) cUnit->classPointerList;
415 while (dataLIR) {
416 /*
417 * Install the callsiteinfo pointers into the cells for now. They will
418 * be converted into real pointers in dvmJitInstallClassObjectPointers.
419 */
420 *dataPtr++ = dataLIR->operands[0];
421 dataLIR = NEXT_LIR(dataLIR);
422 }
423 dataLIR = (MipsLIR *) cUnit->literalList;
424 while (dataLIR) {
425 *dataPtr++ = dataLIR->operands[0];
426 dataLIR = NEXT_LIR(dataLIR);
427 }
428}
429
430/*
431 * Assemble the LIR into binary instruction format. Note that we may
432 * discover that pc-relative displacements may not fit the selected
433 * instruction. In those cases we will try to substitute a new code
434 * sequence or request that the trace be shortened and retried.
435 */
436static AssemblerStatus assembleInstructions(CompilationUnit *cUnit,
437 intptr_t startAddr)
438{
439 int *bufferAddr = (int *) cUnit->codeBuffer;
440 MipsLIR *lir;
441
442 for (lir = (MipsLIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
443 if (lir->opcode < 0) {
444 continue;
445 }
446
447
448 if (lir->flags.isNop) {
449 continue;
450 }
451
452 if (lir->opcode == kMipsB || lir->opcode == kMipsBal) {
453 MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
454 intptr_t pc = lir->generic.offset + 4;
455 intptr_t target = targetLIR->generic.offset;
456 int delta = target - pc;
457 if (delta & 0x3) {
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -0700458 ALOGE("PC-rel distance is not multiple of 4: %d", delta);
Raghu Gandhama8b91c52012-05-02 14:27:16 -0700459 dvmAbort();
460 }
461 if (delta > 131068 || delta < -131069) {
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -0700462 ALOGE("Unconditional branch distance out of range: %d", delta);
Raghu Gandhama8b91c52012-05-02 14:27:16 -0700463 dvmAbort();
464 }
465 lir->operands[0] = delta >> 2;
466 } else if (lir->opcode >= kMipsBeqz && lir->opcode <= kMipsBnez) {
467 MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
468 intptr_t pc = lir->generic.offset + 4;
469 intptr_t target = targetLIR->generic.offset;
470 int delta = target - pc;
471 if (delta & 0x3) {
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -0700472 ALOGE("PC-rel distance is not multiple of 4: %d", delta);
Raghu Gandhama8b91c52012-05-02 14:27:16 -0700473 dvmAbort();
474 }
475 if (delta > 131068 || delta < -131069) {
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -0700476 ALOGE("Conditional branch distance out of range: %d", delta);
Raghu Gandhama8b91c52012-05-02 14:27:16 -0700477 dvmAbort();
478 }
479 lir->operands[1] = delta >> 2;
480 } else if (lir->opcode == kMipsBeq || lir->opcode == kMipsBne) {
481 MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
482 intptr_t pc = lir->generic.offset + 4;
483 intptr_t target = targetLIR->generic.offset;
484 int delta = target - pc;
485 if (delta & 0x3) {
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -0700486 ALOGE("PC-rel distance is not multiple of 4: %d", delta);
Raghu Gandhama8b91c52012-05-02 14:27:16 -0700487 dvmAbort();
488 }
489 if (delta > 131068 || delta < -131069) {
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -0700490 ALOGE("Conditional branch distance out of range: %d", delta);
Raghu Gandhama8b91c52012-05-02 14:27:16 -0700491 dvmAbort();
492 }
493 lir->operands[2] = delta >> 2;
494 } else if (lir->opcode == kMipsJal) {
495 intptr_t curPC = (startAddr + lir->generic.offset + 4) & ~3;
496 intptr_t target = lir->operands[0];
497 /* ensure PC-region branch can be used */
498 assert((curPC & 0xF0000000) == (target & 0xF0000000));
499 if (target & 0x3) {
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -0700500 ALOGE("Jump target is not multiple of 4: %d", target);
Raghu Gandhama8b91c52012-05-02 14:27:16 -0700501 dvmAbort();
502 }
503 lir->operands[0] = target >> 2;
504 } else if (lir->opcode == kMipsLahi) { /* load address hi (via lui) */
505 MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
506 intptr_t target = startAddr + targetLIR->generic.offset;
507 lir->operands[1] = target >> 16;
508 } else if (lir->opcode == kMipsLalo) { /* load address lo (via ori) */
509 MipsLIR *targetLIR = (MipsLIR *) lir->generic.target;
510 intptr_t target = startAddr + targetLIR->generic.offset;
511 lir->operands[2] = lir->operands[2] + target;
512 }
513
514
515 MipsEncodingMap *encoder = &EncodingMap[lir->opcode];
516 u4 bits = encoder->skeleton;
517 int i;
518 for (i = 0; i < 4; i++) {
519 u4 operand;
520 u4 value;
521 operand = lir->operands[i];
522 switch(encoder->fieldLoc[i].kind) {
523 case kFmtUnused:
524 break;
525 case kFmtBitBlt:
526 if (encoder->fieldLoc[i].start == 0 && encoder->fieldLoc[i].end == 31) {
527 value = operand;
528 } else {
529 value = (operand << encoder->fieldLoc[i].start) &
530 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
531 }
532 bits |= value;
533 break;
534 case kFmtDfp: {
535 assert(DOUBLEREG(operand));
536 assert((operand & 0x1) == 0);
537 value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) &
538 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
539 bits |= value;
540 break;
541 }
542 case kFmtSfp:
543 assert(SINGLEREG(operand));
544 value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) &
545 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
546 bits |= value;
547 break;
548 default:
549 assert(0);
550 }
551 }
552 assert(encoder->size == 2);
553 *bufferAddr++ = bits;
554 }
555 return kSuccess;
556}
557
558static int assignLiteralOffsetCommon(LIR *lir, int offset)
559{
560 for (;lir != NULL; lir = lir->next) {
561 lir->offset = offset;
562 offset += 4;
563 }
564 return offset;
565}
566
567/* Determine the offset of each literal field */
568static int assignLiteralOffset(CompilationUnit *cUnit, int offset)
569{
570 /* Reserved for the size field of class pointer pool */
571 offset += 4;
572 offset = assignLiteralOffsetCommon(cUnit->classPointerList, offset);
573 offset = assignLiteralOffsetCommon(cUnit->literalList, offset);
574 return offset;
575}
576
577/*
578 * Translation layout in the code cache. Note that the codeAddress pointer
579 * in JitTable will point directly to the code body (field codeAddress). The
580 * chain cell offset codeAddress - 4, and the address of the trace profile
581 * counter is at codeAddress - 8.
582 *
583 * +----------------------------+
584 * | Trace Profile Counter addr | -> 4 bytes (PROF_COUNTER_ADDR_SIZE)
585 * +----------------------------+
586 * +--| Offset to chain cell counts| -> 4 bytes (CHAIN_CELL_OFFSET_SIZE)
587 * | +----------------------------+
588 * | | Trace profile code | <- entry point when profiling
589 * | . - - - - - - - .
590 * | | Code body | <- entry point when not profiling
591 * | . .
592 * | | |
593 * | +----------------------------+
594 * | | Chaining Cells | -> 16/20 bytes, 4 byte aligned
595 * | . .
596 * | . .
597 * | | |
598 * | +----------------------------+
599 * | | Gap for large switch stmt | -> # cases >= MAX_CHAINED_SWITCH_CASES
600 * | +----------------------------+
601 * +->| Chaining cell counts | -> 8 bytes, chain cell counts by type
602 * +----------------------------+
603 * | Trace description | -> variable sized
604 * . .
605 * | |
606 * +----------------------------+
607 * | # Class pointer pool size | -> 4 bytes
608 * +----------------------------+
609 * | Class pointer pool | -> 4-byte aligned, variable size
610 * . .
611 * . .
612 * | |
613 * +----------------------------+
614 * | Literal pool | -> 4-byte aligned, variable size
615 * . .
616 * . .
617 * | |
618 * +----------------------------+
619 *
620 */
621
622#define PROF_COUNTER_ADDR_SIZE 4
623#define CHAIN_CELL_OFFSET_SIZE 4
624
625/*
626 * Utility functions to navigate various parts in a trace. If we change the
627 * layout/offset in the future, we just modify these functions and we don't need
628 * to propagate the changes to all the use cases.
629 */
630static inline char *getTraceBase(const JitEntry *p)
631{
632 return (char*)p->codeAddress -
633 (PROF_COUNTER_ADDR_SIZE + CHAIN_CELL_OFFSET_SIZE);
634}
635
636/* Handy function to retrieve the profile count */
637static inline JitTraceCounter_t getProfileCount(const JitEntry *entry)
638{
639 if (entry->dPC == 0 || entry->codeAddress == 0 ||
640 entry->codeAddress == dvmCompilerGetInterpretTemplate())
641 return 0;
642
643 JitTraceCounter_t **p = (JitTraceCounter_t **) getTraceBase(entry);
644
645 return **p;
646}
647
648/* Handy function to reset the profile count */
649static inline void resetProfileCount(const JitEntry *entry)
650{
651 if (entry->dPC == 0 || entry->codeAddress == 0 ||
652 entry->codeAddress == dvmCompilerGetInterpretTemplate())
653 return;
654
655 JitTraceCounter_t **p = (JitTraceCounter_t **) getTraceBase(entry);
656
657 **p = 0;
658}
659
660/* Get the pointer of the chain cell count */
661static inline ChainCellCounts* getChainCellCountsPointer(const char *base)
662{
663 /* 4 is the size of the profile count */
664 u4 *chainCellOffsetP = (u4 *) (base + PROF_COUNTER_ADDR_SIZE);
665 u4 chainCellOffset = *chainCellOffsetP;
666 return (ChainCellCounts *) ((char *) chainCellOffsetP + chainCellOffset);
667}
668
669/* Get the size of all chaining cells */
670static inline u4 getChainCellSize(const ChainCellCounts* pChainCellCounts)
671{
672 int cellSize = 0;
673 int i;
674
675 /* Get total count of chain cells */
676 for (i = 0; i < kChainingCellGap; i++) {
677 if (i != kChainingCellInvokePredicted) {
678 cellSize += pChainCellCounts->u.count[i] *
679 (CHAIN_CELL_NORMAL_SIZE >> 2);
680 } else {
681 cellSize += pChainCellCounts->u.count[i] *
682 (CHAIN_CELL_PREDICTED_SIZE >> 2);
683 }
684 }
685 return cellSize;
686}
687
688/* Get the starting pointer of the trace description section */
689static JitTraceDescription* getTraceDescriptionPointer(const char *base)
690{
691 ChainCellCounts* pCellCounts = getChainCellCountsPointer(base);
692 return (JitTraceDescription*) ((char*)pCellCounts + sizeof(*pCellCounts));
693}
694
695/* Get the size of a trace description */
696static int getTraceDescriptionSize(const JitTraceDescription *desc)
697{
698 int runCount;
699 /* Trace end is always of non-meta type (ie isCode == true) */
700 for (runCount = 0; ; runCount++) {
701 if (desc->trace[runCount].isCode &&
702 desc->trace[runCount].info.frag.runEnd)
703 break;
704 }
705 return sizeof(JitTraceDescription) + ((runCount+1) * sizeof(JitTraceRun));
706}
707
708#if defined(SIGNATURE_BREAKPOINT)
709/* Inspect the assembled instruction stream to find potential matches */
710static void matchSignatureBreakpoint(const CompilationUnit *cUnit,
711 unsigned int size)
712{
713 unsigned int i, j;
714 u4 *ptr = (u4 *) cUnit->codeBuffer;
715
716 for (i = 0; i < size - gDvmJit.signatureBreakpointSize + 1; i++) {
717 if (ptr[i] == gDvmJit.signatureBreakpoint[0]) {
718 for (j = 1; j < gDvmJit.signatureBreakpointSize; j++) {
719 if (ptr[i+j] != gDvmJit.signatureBreakpoint[j]) {
720 break;
721 }
722 }
723 if (j == gDvmJit.signatureBreakpointSize) {
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -0700724 ALOGD("Signature match starting from offset %#x (%d words)",
Raghu Gandhama8b91c52012-05-02 14:27:16 -0700725 i*4, gDvmJit.signatureBreakpointSize);
726 int descSize = getTraceDescriptionSize(cUnit->traceDesc);
727 JitTraceDescription *newCopy =
728 (JitTraceDescription *) malloc(descSize);
729 memcpy(newCopy, cUnit->traceDesc, descSize);
730 dvmCompilerWorkEnqueue(NULL, kWorkOrderTraceDebug, newCopy);
731 break;
732 }
733 }
734 }
735}
736#endif
737
738/*
739 * Go over each instruction in the list and calculate the offset from the top
740 * before sending them off to the assembler. If out-of-range branch distance is
741 * seen rearrange the instructions a bit to correct it.
742 */
743void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info)
744{
745 MipsLIR *mipsLIR;
746 int offset = 0;
747 int i;
748 ChainCellCounts chainCellCounts;
749 int descSize = (cUnit->jitMode == kJitMethod) ?
750 0 : getTraceDescriptionSize(cUnit->traceDesc);
751 int chainingCellGap = 0;
752
753 info->instructionSet = cUnit->instructionSet;
754
755 /* Beginning offset needs to allow space for chain cell offset */
756 for (mipsLIR = (MipsLIR *) cUnit->firstLIRInsn;
757 mipsLIR;
758 mipsLIR = NEXT_LIR(mipsLIR)) {
759 mipsLIR->generic.offset = offset;
760 if (mipsLIR->opcode >= 0 && !mipsLIR->flags.isNop) {
761 mipsLIR->flags.size = EncodingMap[mipsLIR->opcode].size * 2;
762 offset += mipsLIR->flags.size;
763 }
764 /* Pseudo opcodes don't consume space */
765 }
766
767 /* Const values have to be word aligned */
768 offset = (offset + 3) & ~3;
769
770 u4 chainCellOffset = offset;
771 MipsLIR *chainCellOffsetLIR = NULL;
772
773 if (cUnit->jitMode != kJitMethod) {
774 /*
775 * Get the gap (# of u4) between the offset of chaining cell count and
776 * the bottom of real chaining cells. If the translation has chaining
777 * cells, the gap is guaranteed to be multiples of 4.
778 */
779 chainingCellGap = (offset - cUnit->chainingCellBottom->offset) >> 2;
780
781 /* Add space for chain cell counts & trace description */
782 chainCellOffsetLIR = (MipsLIR *) cUnit->chainCellOffsetLIR;
783 assert(chainCellOffsetLIR);
784 assert(chainCellOffset < 0x10000);
785 assert(chainCellOffsetLIR->opcode == kMips32BitData &&
786 chainCellOffsetLIR->operands[0] == CHAIN_CELL_OFFSET_TAG);
787
788 /*
789 * Adjust the CHAIN_CELL_OFFSET_TAG LIR's offset to remove the
790 * space occupied by the pointer to the trace profiling counter.
791 */
792 chainCellOffsetLIR->operands[0] = chainCellOffset - 4;
793
794 offset += sizeof(chainCellCounts) + descSize;
795
796 assert((offset & 0x3) == 0); /* Should still be word aligned */
797 }
798
799 /* Set up offsets for literals */
800 cUnit->dataOffset = offset;
801
802 /*
803 * Assign each class pointer/constant an offset from the beginning of the
804 * compilation unit.
805 */
806 offset = assignLiteralOffset(cUnit, offset);
807
808 cUnit->totalSize = offset;
809
810 if (gDvmJit.codeCacheByteUsed + cUnit->totalSize > gDvmJit.codeCacheSize) {
811 gDvmJit.codeCacheFull = true;
812 info->discardResult = true;
813 return;
814 }
815
816 /* Allocate enough space for the code block */
817 cUnit->codeBuffer = (unsigned char *)dvmCompilerNew(chainCellOffset, true);
818 if (cUnit->codeBuffer == NULL) {
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -0700819 ALOGE("Code buffer allocation failure");
Raghu Gandhama8b91c52012-05-02 14:27:16 -0700820 info->discardResult = true;
821 return;
822 }
823
824 /*
825 * Attempt to assemble the trace. Note that assembleInstructions
826 * may rewrite the code sequence and request a retry.
827 */
828 cUnit->assemblerStatus = assembleInstructions(cUnit,
829 (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed);
830
831 switch(cUnit->assemblerStatus) {
832 case kSuccess:
833 break;
834 case kRetryAll:
835 if (cUnit->assemblerRetries < MAX_ASSEMBLER_RETRIES) {
836 if (cUnit->jitMode != kJitMethod) {
837 /* Restore pristine chain cell marker on retry */
838 chainCellOffsetLIR->operands[0] = CHAIN_CELL_OFFSET_TAG;
839 }
840 return;
841 }
842 /* Too many retries - reset and try cutting the trace in half */
843 cUnit->assemblerRetries = 0;
844 cUnit->assemblerStatus = kRetryHalve;
845 return;
846 case kRetryHalve:
847 return;
848 default:
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -0700849 ALOGE("Unexpected assembler status: %d", cUnit->assemblerStatus);
Raghu Gandhama8b91c52012-05-02 14:27:16 -0700850 dvmAbort();
851 }
852
853#if defined(SIGNATURE_BREAKPOINT)
854 if (info->discardResult == false && gDvmJit.signatureBreakpoint != NULL &&
855 chainCellOffset/4 >= gDvmJit.signatureBreakpointSize) {
856 matchSignatureBreakpoint(cUnit, chainCellOffset/4);
857 }
858#endif
859
860 /* Don't go all the way if the goal is just to get the verbose output */
861 if (info->discardResult) return;
862
863 /*
864 * The cache might disappear - acquire lock and check version
865 * Continue holding lock until translation cache update is complete.
866 * These actions are required here in the compiler thread because
867 * it is unaffected by suspend requests and doesn't know if a
868 * translation cache flush is in progress.
869 */
870 dvmLockMutex(&gDvmJit.compilerLock);
871 if (info->cacheVersion != gDvmJit.cacheVersion) {
872 /* Cache changed - discard current translation */
873 info->discardResult = true;
874 info->codeAddress = NULL;
875 dvmUnlockMutex(&gDvmJit.compilerLock);
876 return;
877 }
878
879 cUnit->baseAddr = (char *) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed;
880 gDvmJit.codeCacheByteUsed += offset;
881
882 UNPROTECT_CODE_CACHE(cUnit->baseAddr, offset);
883
884 /* Install the code block */
885 memcpy((char*)cUnit->baseAddr, cUnit->codeBuffer, chainCellOffset);
886 gDvmJit.numCompilations++;
887
888 if (cUnit->jitMode != kJitMethod) {
889 /* Install the chaining cell counts */
890 for (i=0; i< kChainingCellGap; i++) {
891 chainCellCounts.u.count[i] = cUnit->numChainingCells[i];
892 }
893
894 /* Set the gap number in the chaining cell count structure */
895 chainCellCounts.u.count[kChainingCellGap] = chainingCellGap;
896
897 memcpy((char*)cUnit->baseAddr + chainCellOffset, &chainCellCounts,
898 sizeof(chainCellCounts));
899
900 /* Install the trace description */
901 memcpy((char*) cUnit->baseAddr + chainCellOffset +
902 sizeof(chainCellCounts),
903 cUnit->traceDesc, descSize);
904 }
905
906 /* Write the literals directly into the code cache */
907 installLiteralPools(cUnit);
908
909 /* Flush dcache and invalidate the icache to maintain coherence */
910 dvmCompilerCacheFlush((long)cUnit->baseAddr,
911 (long)((char *) cUnit->baseAddr + offset), 0);
912
913 UPDATE_CODE_CACHE_PATCHES();
914
915 PROTECT_CODE_CACHE(cUnit->baseAddr, offset);
916
917 /* Translation cache update complete - release lock */
918 dvmUnlockMutex(&gDvmJit.compilerLock);
919
920 /* Record code entry point and instruction set */
921 info->codeAddress = (char*)cUnit->baseAddr + cUnit->headerSize;
922 /* transfer the size of the profiling code */
923 info->profileCodeSize = cUnit->profileCodeSize;
924}
925
926/*
927 * Returns the skeleton bit pattern associated with an opcode. All
928 * variable fields are zeroed.
929 */
930static u4 getSkeleton(MipsOpCode op)
931{
932 return EncodingMap[op].skeleton;
933}
934
935static u4 assembleChainingBranch(int branchOffset, bool thumbTarget)
936{
937 return getSkeleton(kMipsJal) | ((branchOffset & 0x0FFFFFFF) >> 2);
938}
939
940/*
941 * Perform translation chain operation.
942 * For MIPS, we'll use a JAL instruction to generate an
943 * unconditional chaining branch of up to 256M. The JAL
944 * instruction also has a restriction that the jump target
945 * must be in the same 256M page as the JAL instruction's
946 * delay slot address.
947 * If the target is out of JAL's range, don't chain.
948 * If one or more threads is suspended, don't chain.
949 */
950void* dvmJitChain(void* tgtAddr, u4* branchAddr)
951{
952 u4 newInst;
953
954 /*
955 * Only chain translations when there is no urge to ask all threads to
956 * suspend themselves via the interpreter.
957 */
958 if ((gDvmJit.pProfTable != NULL) && (gDvm.sumThreadSuspendCount == 0) &&
959 (gDvmJit.codeCacheFull == false) &&
960 ((((int) tgtAddr) & 0xF0000000) == (((int) branchAddr+4) & 0xF0000000))) {
961 gDvmJit.translationChains++;
962
963 COMPILER_TRACE_CHAINING(
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -0700964 ALOGD("Jit Runtime: chaining 0x%x to 0x%x",
Raghu Gandhama8b91c52012-05-02 14:27:16 -0700965 (int) branchAddr, (int) tgtAddr & -2));
966
967 newInst = assembleChainingBranch((int) tgtAddr & -2, 0);
968
969 UNPROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
970
971 *branchAddr = newInst;
972 dvmCompilerCacheFlush((long)branchAddr, (long)branchAddr + 4, 0);
973 UPDATE_CODE_CACHE_PATCHES();
974
975 PROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
976
977 gDvmJit.hasNewChain = true;
978 }
979
980 return tgtAddr;
981}
982
983#if !defined(WITH_SELF_VERIFICATION)
984/*
985 * Attempt to enqueue a work order to patch an inline cache for a predicted
986 * chaining cell for virtual/interface calls.
987 */
988static void inlineCachePatchEnqueue(PredictedChainingCell *cellAddr,
989 PredictedChainingCell *newContent)
990{
991 /*
992 * Make sure only one thread gets here since updating the cell (ie fast
993 * path and queueing the request (ie the queued path) have to be done
994 * in an atomic fashion.
995 */
996 dvmLockMutex(&gDvmJit.compilerICPatchLock);
997
998 /* Fast path for uninitialized chaining cell */
999 if (cellAddr->clazz == NULL &&
1000 cellAddr->branch == PREDICTED_CHAIN_BX_PAIR_INIT) {
1001
1002 UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
1003
1004 cellAddr->method = newContent->method;
1005 cellAddr->branch = newContent->branch;
1006
1007 /*
1008 * The update order matters - make sure clazz is updated last since it
1009 * will bring the uninitialized chaining cell to life.
1010 */
1011 android_atomic_release_store((int32_t)newContent->clazz,
1012 (volatile int32_t *)(void*) &cellAddr->clazz);
1013 dvmCompilerCacheFlush((long) cellAddr, (long) (cellAddr+1), 0);
1014 UPDATE_CODE_CACHE_PATCHES();
1015
1016 PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
1017
1018#if defined(WITH_JIT_TUNING)
1019 gDvmJit.icPatchInit++;
1020#endif
1021 /* Check if this is a frequently missed clazz */
1022 } else if (cellAddr->stagedClazz != newContent->clazz) {
1023 /* Not proven to be frequent yet - build up the filter cache */
1024 UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
1025
1026 cellAddr->stagedClazz = newContent->clazz;
1027
1028 UPDATE_CODE_CACHE_PATCHES();
1029 PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
1030
1031#if defined(WITH_JIT_TUNING)
1032 gDvmJit.icPatchRejected++;
1033#endif
1034 /*
1035 * Different classes but same method implementation - it is safe to just
1036 * patch the class value without the need to stop the world.
1037 */
1038 } else if (cellAddr->method == newContent->method) {
1039 UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
1040
1041 cellAddr->clazz = newContent->clazz;
1042 /* No need to flush the cache here since the branch is not patched */
1043 UPDATE_CODE_CACHE_PATCHES();
1044
1045 PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
1046
1047#if defined(WITH_JIT_TUNING)
1048 gDvmJit.icPatchLockFree++;
1049#endif
1050 /*
1051 * Cannot patch the chaining cell inline - queue it until the next safe
1052 * point.
1053 */
1054 } else if (gDvmJit.compilerICPatchIndex < COMPILER_IC_PATCH_QUEUE_SIZE) {
1055 int index = gDvmJit.compilerICPatchIndex++;
1056 const ClassObject *clazz = newContent->clazz;
1057
1058 gDvmJit.compilerICPatchQueue[index].cellAddr = cellAddr;
1059 gDvmJit.compilerICPatchQueue[index].cellContent = *newContent;
1060 gDvmJit.compilerICPatchQueue[index].classDescriptor = clazz->descriptor;
1061 gDvmJit.compilerICPatchQueue[index].classLoader = clazz->classLoader;
1062 /* For verification purpose only */
1063 gDvmJit.compilerICPatchQueue[index].serialNumber = clazz->serialNumber;
1064#if defined(WITH_JIT_TUNING)
1065 gDvmJit.icPatchQueued++;
1066#endif
1067 } else {
1068 /* Queue is full - just drop this patch request */
1069#if defined(WITH_JIT_TUNING)
1070 gDvmJit.icPatchDropped++;
1071#endif
1072 }
1073
1074 dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
1075}
1076#endif
1077
1078/*
1079 * This method is called from the invoke templates for virtual and interface
1080 * methods to speculatively setup a chain to the callee. The templates are
1081 * written in assembly and have setup method, cell, and clazz at r0, r2, and
1082 * r3 respectively, so there is a unused argument in the list. Upon return one
1083 * of the following three results may happen:
1084 * 1) Chain is not setup because the callee is native. Reset the rechain
1085 * count to a big number so that it will take a long time before the next
1086 * rechain attempt to happen.
1087 * 2) Chain is not setup because the callee has not been created yet. Reset
1088 * the rechain count to a small number and retry in the near future.
1089 * 3) Ask all other threads to stop before patching this chaining cell.
1090 * This is required because another thread may have passed the class check
1091 * but hasn't reached the chaining cell yet to follow the chain. If we
1092 * patch the content before halting the other thread, there could be a
1093 * small window for race conditions to happen that it may follow the new
1094 * but wrong chain to invoke a different method.
1095 */
1096const Method *dvmJitToPatchPredictedChain(const Method *method,
1097 Thread *self,
1098 PredictedChainingCell *cell,
1099 const ClassObject *clazz)
1100{
1101 int newRechainCount = PREDICTED_CHAIN_COUNTER_RECHAIN;
1102#if defined(WITH_SELF_VERIFICATION)
1103 newRechainCount = PREDICTED_CHAIN_COUNTER_AVOID;
1104 goto done;
1105#else
1106 PredictedChainingCell newCell;
1107 int baseAddr, tgtAddr;
1108 if (dvmIsNativeMethod(method)) {
1109 UNPROTECT_CODE_CACHE(cell, sizeof(*cell));
1110
1111 /*
1112 * Put a non-zero/bogus value in the clazz field so that it won't
1113 * trigger immediate patching and will continue to fail to match with
1114 * a real clazz pointer.
1115 */
1116 cell->clazz = (ClassObject *) PREDICTED_CHAIN_FAKE_CLAZZ;
1117
1118 UPDATE_CODE_CACHE_PATCHES();
1119 PROTECT_CODE_CACHE(cell, sizeof(*cell));
1120 goto done;
1121 }
1122
1123 tgtAddr = (int) dvmJitGetTraceAddr(method->insns);
1124 baseAddr = (int) cell + 4; // PC is cur_addr + 4
1125
1126 if ((baseAddr & 0xF0000000) != (tgtAddr & 0xF0000000)) {
1127 COMPILER_TRACE_CHAINING(
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001128 ALOGD("Jit Runtime: predicted chain %p to distant target %s ignored",
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001129 cell, method->name));
1130 goto done;
1131 }
1132
1133 /*
1134 * Compilation not made yet for the callee. Reset the counter to a small
1135 * value and come back to check soon.
1136 */
1137 if ((tgtAddr == 0) ||
1138 ((void*)tgtAddr == dvmCompilerGetInterpretTemplate())) {
1139 COMPILER_TRACE_CHAINING(
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001140 ALOGD("Jit Runtime: predicted chain %p to method %s%s delayed",
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001141 cell, method->clazz->descriptor, method->name));
1142 goto done;
1143 }
1144
1145 if (cell->clazz == NULL) {
1146 newRechainCount = self->icRechainCount;
1147 }
1148
1149 newCell.branch = assembleChainingBranch(tgtAddr, true);
1150 newCell.delay_slot = getSkeleton(kMipsNop);
1151 newCell.clazz = clazz;
1152 newCell.method = method;
1153 newCell.stagedClazz = NULL;
1154
1155 /*
1156 * Enter the work order to the queue and the chaining cell will be patched
1157 * the next time a safe point is entered.
1158 *
1159 * If the enqueuing fails reset the rechain count to a normal value so that
1160 * it won't get indefinitely delayed.
1161 */
1162 inlineCachePatchEnqueue(cell, &newCell);
1163#endif
1164done:
1165 self->icRechainCount = newRechainCount;
1166 return method;
1167}
1168
1169/*
1170 * Patch the inline cache content based on the content passed from the work
1171 * order.
1172 */
1173void dvmCompilerPatchInlineCache(void)
1174{
1175 int i;
1176 PredictedChainingCell *minAddr, *maxAddr;
1177
1178 /* Nothing to be done */
1179 if (gDvmJit.compilerICPatchIndex == 0) return;
1180
1181 /*
1182 * Since all threads are already stopped we don't really need to acquire
1183 * the lock. But race condition can be easily introduced in the future w/o
1184 * paying attention so we still acquire the lock here.
1185 */
1186 dvmLockMutex(&gDvmJit.compilerICPatchLock);
1187
1188 UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
1189
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001190 //ALOGD("Number of IC patch work orders: %d", gDvmJit.compilerICPatchIndex);
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001191
1192 /* Initialize the min/max address range */
1193 minAddr = (PredictedChainingCell *)
1194 ((char *) gDvmJit.codeCache + gDvmJit.codeCacheSize);
1195 maxAddr = (PredictedChainingCell *) gDvmJit.codeCache;
1196
1197 for (i = 0; i < gDvmJit.compilerICPatchIndex; i++) {
1198 ICPatchWorkOrder *workOrder = &gDvmJit.compilerICPatchQueue[i];
1199 PredictedChainingCell *cellAddr = workOrder->cellAddr;
1200 PredictedChainingCell *cellContent = &workOrder->cellContent;
1201 ClassObject *clazz = dvmFindClassNoInit(workOrder->classDescriptor,
1202 workOrder->classLoader);
1203
1204 assert(clazz->serialNumber == workOrder->serialNumber);
1205
1206 /* Use the newly resolved clazz pointer */
1207 cellContent->clazz = clazz;
1208
1209 COMPILER_TRACE_CHAINING(
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001210 ALOGD("Jit Runtime: predicted chain %p from %s to %s (%s) "
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001211 "patched",
1212 cellAddr,
1213 cellAddr->clazz->descriptor,
1214 cellContent->clazz->descriptor,
1215 cellContent->method->name));
1216
1217 /* Patch the chaining cell */
1218 *cellAddr = *cellContent;
1219 minAddr = (cellAddr < minAddr) ? cellAddr : minAddr;
1220 maxAddr = (cellAddr > maxAddr) ? cellAddr : maxAddr;
1221 }
1222
1223 /* Then synchronize the I/D cache */
1224 dvmCompilerCacheFlush((long) minAddr, (long) (maxAddr+1), 0);
1225 UPDATE_CODE_CACHE_PATCHES();
1226
1227 PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
1228
1229 gDvmJit.compilerICPatchIndex = 0;
1230 dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
1231}
1232
1233/*
1234 * Unchain a trace given the starting address of the translation
1235 * in the code cache. Refer to the diagram in dvmCompilerAssembleLIR.
1236 * Returns the address following the last cell unchained. Note that
1237 * the incoming codeAddr is a thumb code address, and therefore has
1238 * the low bit set.
1239 */
1240static u4* unchainSingle(JitEntry *trace)
1241{
1242 const char *base = getTraceBase(trace);
1243 ChainCellCounts *pChainCellCounts = getChainCellCountsPointer(base);
1244 int cellSize = getChainCellSize(pChainCellCounts);
1245 u4* pChainCells;
1246 int i,j;
1247 PredictedChainingCell *predChainCell;
1248
1249 if (cellSize == 0)
1250 return (u4 *) pChainCellCounts;
1251
1252 /* Locate the beginning of the chain cell region */
1253 pChainCells = ((u4 *) pChainCellCounts) - cellSize -
1254 pChainCellCounts->u.count[kChainingCellGap];
1255
1256 /* The cells are sorted in order - walk through them and reset */
1257 for (i = 0; i < kChainingCellGap; i++) {
1258 int elemSize = CHAIN_CELL_NORMAL_SIZE >> 2; /* In 32-bit words */
1259 if (i == kChainingCellInvokePredicted) {
1260 elemSize = CHAIN_CELL_PREDICTED_SIZE >> 2;
1261 }
1262
1263 for (j = 0; j < pChainCellCounts->u.count[i]; j++) {
1264 int targetOffset;
1265 switch(i) {
1266 case kChainingCellNormal:
1267 targetOffset = offsetof(Thread,
1268 jitToInterpEntries.dvmJitToInterpNormal);
1269 break;
1270 case kChainingCellHot:
1271 case kChainingCellInvokeSingleton:
1272 targetOffset = offsetof(Thread,
1273 jitToInterpEntries.dvmJitToInterpTraceSelect);
1274 break;
1275 case kChainingCellInvokePredicted:
1276 targetOffset = 0;
1277 predChainCell = (PredictedChainingCell *) pChainCells;
1278 /*
1279 * There could be a race on another mutator thread to use
1280 * this particular predicted cell and the check has passed
1281 * the clazz comparison. So we cannot safely wipe the
1282 * method and branch but it is safe to clear the clazz,
1283 * which serves as the key.
1284 */
1285 predChainCell->clazz = PREDICTED_CHAIN_CLAZZ_INIT;
1286 break;
1287#if defined(WITH_SELF_VERIFICATION)
1288 case kChainingCellBackwardBranch:
1289 targetOffset = offsetof(Thread,
1290 jitToInterpEntries.dvmJitToInterpBackwardBranch);
1291 break;
1292#else
1293 case kChainingCellBackwardBranch:
1294 targetOffset = offsetof(Thread,
1295 jitToInterpEntries.dvmJitToInterpNormal);
1296 break;
1297#endif
1298 default:
1299 targetOffset = 0; // make gcc happy
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001300 ALOGE("Unexpected chaining type: %d", i);
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001301 dvmAbort(); // dvmAbort OK here - can't safely recover
1302 }
1303 COMPILER_TRACE_CHAINING(
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001304 ALOGD("Jit Runtime: unchaining %#x", (int)pChainCells));
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001305 /*
1306 * Code sequence for a chaining cell is:
1307 * lw a0, offset(rSELF)
1308 * jalr ra, a0
1309 */
1310 if (i != kChainingCellInvokePredicted) {
1311 *pChainCells = getSkeleton(kMipsLw) | (r_A0 << 16) |
1312 targetOffset | (rSELF << 21);
1313 *(pChainCells+1) = getSkeleton(kMipsJalr) | (r_RA << 11) |
1314 (r_A0 << 21);
1315 }
1316 pChainCells += elemSize; /* Advance by a fixed number of words */
1317 }
1318 }
1319 return pChainCells;
1320}
1321
1322/* Unchain all translation in the cache. */
1323void dvmJitUnchainAll()
1324{
1325 u4* lowAddress = NULL;
1326 u4* highAddress = NULL;
1327 unsigned int i;
1328 if (gDvmJit.pJitEntryTable != NULL) {
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001329 COMPILER_TRACE_CHAINING(ALOGD("Jit Runtime: unchaining all"));
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001330 dvmLockMutex(&gDvmJit.tableLock);
1331
1332 UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
1333
1334 for (i = 0; i < gDvmJit.jitTableSize; i++) {
1335 if (gDvmJit.pJitEntryTable[i].dPC &&
1336 !gDvmJit.pJitEntryTable[i].u.info.isMethodEntry &&
1337 gDvmJit.pJitEntryTable[i].codeAddress &&
1338 (gDvmJit.pJitEntryTable[i].codeAddress !=
1339 dvmCompilerGetInterpretTemplate())) {
1340 u4* lastAddress;
1341 lastAddress = unchainSingle(&gDvmJit.pJitEntryTable[i]);
1342 if (lowAddress == NULL ||
1343 (u4*)gDvmJit.pJitEntryTable[i].codeAddress < lowAddress)
1344 lowAddress = (u4*)gDvmJit.pJitEntryTable[i].codeAddress;
1345 if (lastAddress > highAddress)
1346 highAddress = lastAddress;
1347 }
1348 }
1349
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001350 if (lowAddress && highAddress)
Dong-Yuan Chen0c2dc522012-07-03 13:13:07 -07001351 dvmCompilerCacheFlush((long)lowAddress, (long)highAddress, 0);
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001352
1353 UPDATE_CODE_CACHE_PATCHES();
1354
1355 PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
1356
1357 dvmUnlockMutex(&gDvmJit.tableLock);
1358 gDvmJit.translationChains = 0;
1359 }
1360 gDvmJit.hasNewChain = false;
1361}
1362
1363typedef struct jitProfileAddrToLine {
1364 u4 lineNum;
1365 u4 bytecodeOffset;
1366} jitProfileAddrToLine;
1367
1368
1369/* Callback function to track the bytecode offset/line number relationiship */
1370static int addrToLineCb (void *cnxt, u4 bytecodeOffset, u4 lineNum)
1371{
1372 jitProfileAddrToLine *addrToLine = (jitProfileAddrToLine *) cnxt;
1373
1374 /* Best match so far for this offset */
1375 if (addrToLine->bytecodeOffset >= bytecodeOffset) {
1376 addrToLine->lineNum = lineNum;
1377 }
1378 return 0;
1379}
1380
1381/* Dumps profile info for a single trace */
1382static int dumpTraceProfile(JitEntry *p, bool silent, bool reset,
1383 unsigned long sum)
1384{
1385 int idx;
1386
1387 if (p->codeAddress == NULL) {
1388 if (!silent)
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001389 ALOGD("TRACEPROFILE NULL");
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001390 return 0;
1391 }
1392 if (p->codeAddress == dvmCompilerGetInterpretTemplate()) {
1393 if (!silent)
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001394 ALOGD("TRACEPROFILE INTERPRET_ONLY");
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001395 return 0;
1396 }
1397
1398 JitTraceCounter_t count = getProfileCount(p);
1399 if (reset) {
1400 resetProfileCount(p);
1401 }
1402 if (silent) {
1403 return count;
1404 }
1405 JitTraceDescription *desc = getTraceDescriptionPointer(getTraceBase(p));
1406 const Method *method = desc->method;
1407 char *methodDesc = dexProtoCopyMethodDescriptor(&method->prototype);
1408 jitProfileAddrToLine addrToLine = {0, desc->trace[0].info.frag.startOffset};
1409
1410 /*
1411 * We may end up decoding the debug information for the same method
1412 * multiple times, but the tradeoff is we don't need to allocate extra
1413 * space to store the addr/line mapping. Since this is a debugging feature
1414 * and done infrequently so the slower but simpler mechanism should work
1415 * just fine.
1416 */
1417 dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile,
1418 dvmGetMethodCode(method),
1419 method->clazz->descriptor,
1420 method->prototype.protoIdx,
1421 method->accessFlags,
1422 addrToLineCb, NULL, &addrToLine);
1423
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001424 ALOGD("TRACEPROFILE 0x%08x % 10d %5.2f%% [%#x(+%d), %d] %s%s;%s",
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001425 (int) getTraceBase(p),
1426 count,
1427 ((float ) count) / sum * 100.0,
1428 desc->trace[0].info.frag.startOffset,
1429 desc->trace[0].info.frag.numInsts,
1430 addrToLine.lineNum,
1431 method->clazz->descriptor, method->name, methodDesc);
1432 free(methodDesc);
1433
1434 /* Find the last fragment (ie runEnd is set) */
1435 for (idx = 0;
1436 desc->trace[idx].isCode && !desc->trace[idx].info.frag.runEnd;
1437 idx++) {
1438 }
1439
1440 /*
1441 * runEnd must comes with a JitCodeDesc frag. If isCode is false it must
1442 * be a meta info field (only used by callsite info for now).
1443 */
1444 if (!desc->trace[idx].isCode) {
1445 const Method *method = (const Method *)
1446 desc->trace[idx+JIT_TRACE_CUR_METHOD-1].info.meta;
1447 char *methodDesc = dexProtoCopyMethodDescriptor(&method->prototype);
1448 /* Print the callee info in the trace */
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001449 ALOGD(" -> %s%s;%s", method->clazz->descriptor, method->name,
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001450 methodDesc);
1451 }
1452
1453 return count;
1454}
1455
1456/* Create a copy of the trace descriptor of an existing compilation */
1457JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc,
1458 const JitEntry *knownEntry)
1459{
1460 const JitEntry *jitEntry = knownEntry ? knownEntry
1461 : dvmJitFindEntry(pc, false);
1462 if ((jitEntry == NULL) || (jitEntry->codeAddress == 0))
1463 return NULL;
1464
1465 JitTraceDescription *desc =
1466 getTraceDescriptionPointer(getTraceBase(jitEntry));
1467
1468 /* Now make a copy and return */
1469 int descSize = getTraceDescriptionSize(desc);
1470 JitTraceDescription *newCopy = (JitTraceDescription *) malloc(descSize);
1471 memcpy(newCopy, desc, descSize);
1472 return newCopy;
1473}
1474
1475/* qsort callback function */
1476static int sortTraceProfileCount(const void *entry1, const void *entry2)
1477{
1478 const JitEntry *jitEntry1 = (const JitEntry *)entry1;
1479 const JitEntry *jitEntry2 = (const JitEntry *)entry2;
1480
1481 JitTraceCounter_t count1 = getProfileCount(jitEntry1);
1482 JitTraceCounter_t count2 = getProfileCount(jitEntry2);
1483 return (count1 == count2) ? 0 : ((count1 > count2) ? -1 : 1);
1484}
1485
1486/* Sort the trace profile counts and dump them */
1487void dvmCompilerSortAndPrintTraceProfiles()
1488{
1489 JitEntry *sortedEntries;
1490 int numTraces = 0;
1491 unsigned long sum = 0;
1492 unsigned int i;
1493
1494 /* Make sure that the table is not changing */
1495 dvmLockMutex(&gDvmJit.tableLock);
1496
1497 /* Sort the entries by descending order */
1498 sortedEntries = (JitEntry *)malloc(sizeof(JitEntry) * gDvmJit.jitTableSize);
1499 if (sortedEntries == NULL)
1500 goto done;
1501 memcpy(sortedEntries, gDvmJit.pJitEntryTable,
1502 sizeof(JitEntry) * gDvmJit.jitTableSize);
1503 qsort(sortedEntries, gDvmJit.jitTableSize, sizeof(JitEntry),
1504 sortTraceProfileCount);
1505
1506 /* Analyze the sorted entries */
1507 for (i=0; i < gDvmJit.jitTableSize; i++) {
1508 if (sortedEntries[i].dPC != 0) {
1509 sum += dumpTraceProfile(&sortedEntries[i],
1510 true /* silent */,
1511 false /* reset */,
1512 0);
1513 numTraces++;
1514 }
1515 }
1516 if (numTraces == 0)
1517 numTraces = 1;
1518 if (sum == 0) {
1519 sum = 1;
1520 }
1521
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001522 ALOGD("JIT: Average execution count -> %d",(int)(sum / numTraces));
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001523
1524 /* Dump the sorted entries. The count of each trace will be reset to 0. */
1525 for (i=0; i < gDvmJit.jitTableSize; i++) {
1526 if (sortedEntries[i].dPC != 0) {
1527 dumpTraceProfile(&sortedEntries[i],
1528 false /* silent */,
1529 true /* reset */,
1530 sum);
1531 }
1532 }
1533
1534 for (i=0; i < gDvmJit.jitTableSize && i < 10; i++) {
1535 /* Stip interpreter stubs */
1536 if (sortedEntries[i].codeAddress == dvmCompilerGetInterpretTemplate()) {
1537 continue;
1538 }
1539 JitTraceDescription* desc =
1540 dvmCopyTraceDescriptor(NULL, &sortedEntries[i]);
1541 if (desc) {
1542 dvmCompilerWorkEnqueue(sortedEntries[i].dPC,
1543 kWorkOrderTraceDebug, desc);
1544 }
1545 }
1546
1547 free(sortedEntries);
1548done:
1549 dvmUnlockMutex(&gDvmJit.tableLock);
1550 return;
1551}
1552
1553static void findClassPointersSingleTrace(char *base, void (*callback)(void *))
1554{
1555 unsigned int chainTypeIdx, chainIdx;
1556 ChainCellCounts *pChainCellCounts = getChainCellCountsPointer(base);
1557 int cellSize = getChainCellSize(pChainCellCounts);
1558 /* Scan the chaining cells */
1559 if (cellSize) {
1560 /* Locate the beginning of the chain cell region */
1561 u4 *pChainCells = ((u4 *) pChainCellCounts) - cellSize -
1562 pChainCellCounts->u.count[kChainingCellGap];
1563 /* The cells are sorted in order - walk through them */
1564 for (chainTypeIdx = 0; chainTypeIdx < kChainingCellGap;
1565 chainTypeIdx++) {
1566 if (chainTypeIdx != kChainingCellInvokePredicted) {
1567 /* In 32-bit words */
1568 pChainCells += (CHAIN_CELL_NORMAL_SIZE >> 2) *
1569 pChainCellCounts->u.count[chainTypeIdx];
1570 continue;
1571 }
1572 for (chainIdx = 0;
1573 chainIdx < pChainCellCounts->u.count[chainTypeIdx];
1574 chainIdx++) {
1575 PredictedChainingCell *cell =
1576 (PredictedChainingCell *) pChainCells;
1577 /*
1578 * Report the cell if it contains a sane class
1579 * pointer.
1580 */
1581 if (cell->clazz != NULL &&
1582 cell->clazz !=
1583 (ClassObject *) PREDICTED_CHAIN_FAKE_CLAZZ) {
1584 callback(&cell->clazz);
1585 }
1586 pChainCells += CHAIN_CELL_PREDICTED_SIZE >> 2;
1587 }
1588 }
1589 }
1590
1591 /* Scan the class pointer pool */
1592 JitTraceDescription *desc = getTraceDescriptionPointer(base);
1593 int descSize = getTraceDescriptionSize(desc);
1594 int *classPointerP = (int *) ((char *) desc + descSize);
1595 int numClassPointers = *classPointerP++;
1596 for (; numClassPointers; numClassPointers--, classPointerP++) {
1597 callback(classPointerP);
1598 }
1599}
1600
1601/*
1602 * Scan class pointers in each translation and pass its address to the callback
1603 * function. Currently such a pointers can be found in the pointer pool and the
1604 * clazz field in the predicted chaining cells.
1605 */
1606void dvmJitScanAllClassPointers(void (*callback)(void *))
1607{
1608 UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
1609
1610 /* Handle the inflight compilation first */
1611 if (gDvmJit.inflightBaseAddr)
1612 findClassPointersSingleTrace((char *) gDvmJit.inflightBaseAddr,
1613 callback);
1614
1615 if (gDvmJit.pJitEntryTable != NULL) {
1616 unsigned int traceIdx;
1617 dvmLockMutex(&gDvmJit.tableLock);
1618 for (traceIdx = 0; traceIdx < gDvmJit.jitTableSize; traceIdx++) {
1619 const JitEntry *entry = &gDvmJit.pJitEntryTable[traceIdx];
1620 if (entry->dPC &&
1621 !entry->u.info.isMethodEntry &&
1622 entry->codeAddress &&
1623 (entry->codeAddress != dvmCompilerGetInterpretTemplate())) {
1624 char *base = getTraceBase(entry);
1625 findClassPointersSingleTrace(base, callback);
1626 }
1627 }
1628 dvmUnlockMutex(&gDvmJit.tableLock);
1629 }
1630 UPDATE_CODE_CACHE_PATCHES();
1631
1632 PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
1633}
1634
1635/*
1636 * Provide the final touch on the class object pointer pool to install the
1637 * actual pointers. The thread has to be in the running state.
1638 */
1639void dvmJitInstallClassObjectPointers(CompilationUnit *cUnit, char *codeAddress)
1640{
1641 char *base = codeAddress - cUnit->headerSize;
1642
1643 /* Scan the class pointer pool */
1644 JitTraceDescription *desc = getTraceDescriptionPointer(base);
1645 int descSize = getTraceDescriptionSize(desc);
1646 intptr_t *classPointerP = (int *) ((char *) desc + descSize);
1647 int numClassPointers = *(int *)classPointerP++;
1648 intptr_t *startClassPointerP = classPointerP;
1649
1650 /*
1651 * Change the thread state to VM_RUNNING so that GC won't be happening
1652 * when the assembler looks up the class pointers. May suspend the current
1653 * thread if there is a pending request before the state is actually
1654 * changed to RUNNING.
1655 */
1656 dvmChangeStatus(gDvmJit.compilerThread, THREAD_RUNNING);
1657
1658 /*
1659 * Unprotecting the code cache will need to acquire the code cache
1660 * protection lock first. Doing so after the state change may increase the
1661 * time spent in the RUNNING state (which may delay the next GC request
1662 * should there be contention on codeCacheProtectionLock). In practice
1663 * this is probably not going to happen often since a GC is just served.
1664 * More importantly, acquiring the lock before the state change will
1665 * cause deadlock (b/4192964).
1666 */
1667 UNPROTECT_CODE_CACHE(startClassPointerP,
1668 numClassPointers * sizeof(intptr_t));
1669#if defined(WITH_JIT_TUNING)
1670 u8 startTime = dvmGetRelativeTimeUsec();
1671#endif
1672 for (;numClassPointers; numClassPointers--) {
1673 CallsiteInfo *callsiteInfo = (CallsiteInfo *) *classPointerP;
1674 ClassObject *clazz = dvmFindClassNoInit(
1675 callsiteInfo->classDescriptor, callsiteInfo->classLoader);
1676 assert(!strcmp(clazz->descriptor, callsiteInfo->classDescriptor));
1677 *classPointerP++ = (intptr_t) clazz;
1678 }
1679
1680 /*
1681 * Register the base address so that if GC kicks in after the thread state
1682 * has been changed to VMWAIT and before the compiled code is registered
1683 * in the JIT table, its content can be patched if class objects are
1684 * moved.
1685 */
1686 gDvmJit.inflightBaseAddr = base;
1687
1688#if defined(WITH_JIT_TUNING)
1689 u8 blockTime = dvmGetRelativeTimeUsec() - startTime;
1690 gDvmJit.compilerThreadBlockGCTime += blockTime;
1691 if (blockTime > gDvmJit.maxCompilerThreadBlockGCTime)
1692 gDvmJit.maxCompilerThreadBlockGCTime = blockTime;
1693 gDvmJit.numCompilerThreadBlockGC++;
1694#endif
1695 UPDATE_CODE_CACHE_PATCHES();
1696
1697 PROTECT_CODE_CACHE(startClassPointerP, numClassPointers * sizeof(intptr_t));
1698
1699 /* Change the thread state back to VMWAIT */
1700 dvmChangeStatus(gDvmJit.compilerThread, THREAD_VMWAIT);
1701}
1702
1703#if defined(WITH_SELF_VERIFICATION)
1704/*
1705 * The following are used to keep compiled loads and stores from modifying
1706 * memory during self verification mode.
1707 *
1708 * Stores do not modify memory. Instead, the address and value pair are stored
1709 * into heapSpace. Addresses within heapSpace are unique. For accesses smaller
1710 * than a word, the word containing the address is loaded first before being
1711 * updated.
1712 *
1713 * Loads check heapSpace first and return data from there if an entry exists.
1714 * Otherwise, data is loaded from memory as usual.
1715 */
1716
1717/* Used to specify sizes of memory operations */
1718enum {
1719 kSVByte,
1720 kSVSignedByte,
1721 kSVHalfword,
1722 kSVSignedHalfword,
1723 kSVWord,
1724 kSVDoubleword,
1725 kSVVariable,
1726};
1727
1728/* Load the value of a decoded register from the stack */
1729static int selfVerificationMemRegLoad(int* sp, int reg)
1730{
1731assert(0); /* MIPSTODO retarg func */
1732 return *(sp + reg);
1733}
1734
1735/* Load the value of a decoded doubleword register from the stack */
1736static s8 selfVerificationMemRegLoadDouble(int* sp, int reg)
1737{
1738assert(0); /* MIPSTODO retarg func */
1739 return *((s8*)(sp + reg));
1740}
1741
1742/* Store the value of a decoded register out to the stack */
1743static void selfVerificationMemRegStore(int* sp, int data, int reg)
1744{
1745assert(0); /* MIPSTODO retarg func */
1746 *(sp + reg) = data;
1747}
1748
1749/* Store the value of a decoded doubleword register out to the stack */
1750static void selfVerificationMemRegStoreDouble(int* sp, s8 data, int reg)
1751{
1752assert(0); /* MIPSTODO retarg func */
1753 *((s8*)(sp + reg)) = data;
1754}
1755
1756/*
1757 * Load the specified size of data from the specified address, checking
1758 * heapSpace first if Self Verification mode wrote to it previously, and
1759 * falling back to actual memory otherwise.
1760 */
1761static int selfVerificationLoad(int addr, int size)
1762{
1763assert(0); /* MIPSTODO retarg func */
1764 Thread *self = dvmThreadSelf();
1765 ShadowSpace *shadowSpace = self->shadowSpace;
1766 ShadowHeap *heapSpacePtr;
1767
1768 int data;
1769 int maskedAddr = addr & 0xFFFFFFFC;
1770 int alignment = addr & 0x3;
1771
1772 for (heapSpacePtr = shadowSpace->heapSpace;
1773 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
1774 if (heapSpacePtr->addr == maskedAddr) {
1775 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
1776 break;
1777 }
1778 }
1779
1780 switch (size) {
1781 case kSVByte:
1782 data = *((u1*) addr);
1783 break;
1784 case kSVSignedByte:
1785 data = *((s1*) addr);
1786 break;
1787 case kSVHalfword:
1788 data = *((u2*) addr);
1789 break;
1790 case kSVSignedHalfword:
1791 data = *((s2*) addr);
1792 break;
1793 case kSVWord:
1794 data = *((u4*) addr);
1795 break;
1796 default:
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001797 ALOGE("*** ERROR: BAD SIZE IN selfVerificationLoad: %d", size);
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001798 data = 0;
1799 dvmAbort();
1800 }
1801
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001802 //ALOGD("*** HEAP LOAD: Addr: %#x Data: %#x Size: %d", addr, data, size);
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001803 return data;
1804}
1805
1806/* Like selfVerificationLoad, but specifically for doublewords */
1807static s8 selfVerificationLoadDoubleword(int addr)
1808{
1809assert(0); /* MIPSTODO retarg func */
1810 Thread *self = dvmThreadSelf();
1811 ShadowSpace* shadowSpace = self->shadowSpace;
1812 ShadowHeap* heapSpacePtr;
1813
1814 int addr2 = addr+4;
1815 unsigned int data = *((unsigned int*) addr);
1816 unsigned int data2 = *((unsigned int*) addr2);
1817
1818 for (heapSpacePtr = shadowSpace->heapSpace;
1819 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
1820 if (heapSpacePtr->addr == addr) {
1821 data = heapSpacePtr->data;
1822 } else if (heapSpacePtr->addr == addr2) {
1823 data2 = heapSpacePtr->data;
1824 }
1825 }
1826
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001827 //ALOGD("*** HEAP LOAD DOUBLEWORD: Addr: %#x Data: %#x Data2: %#x",
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001828 // addr, data, data2);
1829 return (((s8) data2) << 32) | data;
1830}
1831
1832/*
1833 * Handles a store of a specified size of data to a specified address.
1834 * This gets logged as an addr/data pair in heapSpace instead of modifying
1835 * memory. Addresses in heapSpace are unique, and accesses smaller than a
1836 * word pull the entire word from memory first before updating.
1837 */
1838static void selfVerificationStore(int addr, int data, int size)
1839{
1840assert(0); /* MIPSTODO retarg func */
1841 Thread *self = dvmThreadSelf();
1842 ShadowSpace *shadowSpace = self->shadowSpace;
1843 ShadowHeap *heapSpacePtr;
1844
1845 int maskedAddr = addr & 0xFFFFFFFC;
1846 int alignment = addr & 0x3;
1847
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001848 //ALOGD("*** HEAP STORE: Addr: %#x Data: %#x Size: %d", addr, data, size);
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001849
1850 for (heapSpacePtr = shadowSpace->heapSpace;
1851 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
1852 if (heapSpacePtr->addr == maskedAddr) break;
1853 }
1854
1855 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
1856 heapSpacePtr->addr = maskedAddr;
1857 heapSpacePtr->data = *((unsigned int*) maskedAddr);
1858 shadowSpace->heapSpaceTail++;
1859 }
1860
1861 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
1862 switch (size) {
1863 case kSVByte:
1864 *((u1*) addr) = data;
1865 break;
1866 case kSVSignedByte:
1867 *((s1*) addr) = data;
1868 break;
1869 case kSVHalfword:
1870 *((u2*) addr) = data;
1871 break;
1872 case kSVSignedHalfword:
1873 *((s2*) addr) = data;
1874 break;
1875 case kSVWord:
1876 *((u4*) addr) = data;
1877 break;
1878 default:
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001879 ALOGE("*** ERROR: BAD SIZE IN selfVerificationSave: %d", size);
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001880 dvmAbort();
1881 }
1882}
1883
1884/* Like selfVerificationStore, but specifically for doublewords */
1885static void selfVerificationStoreDoubleword(int addr, s8 double_data)
1886{
1887assert(0); /* MIPSTODO retarg func */
1888 Thread *self = dvmThreadSelf();
1889 ShadowSpace *shadowSpace = self->shadowSpace;
1890 ShadowHeap *heapSpacePtr;
1891
1892 int addr2 = addr+4;
1893 int data = double_data;
1894 int data2 = double_data >> 32;
1895 bool store1 = false, store2 = false;
1896
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07001897 //ALOGD("*** HEAP STORE DOUBLEWORD: Addr: %#x Data: %#x, Data2: %#x",
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001898 // addr, data, data2);
1899
1900 for (heapSpacePtr = shadowSpace->heapSpace;
1901 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
1902 if (heapSpacePtr->addr == addr) {
1903 heapSpacePtr->data = data;
1904 store1 = true;
1905 } else if (heapSpacePtr->addr == addr2) {
1906 heapSpacePtr->data = data2;
1907 store2 = true;
1908 }
1909 }
1910
1911 if (!store1) {
1912 shadowSpace->heapSpaceTail->addr = addr;
1913 shadowSpace->heapSpaceTail->data = data;
1914 shadowSpace->heapSpaceTail++;
1915 }
1916 if (!store2) {
1917 shadowSpace->heapSpaceTail->addr = addr2;
1918 shadowSpace->heapSpaceTail->data = data2;
1919 shadowSpace->heapSpaceTail++;
1920 }
1921}
1922
1923/*
1924 * Decodes the memory instruction at the address specified in the link
1925 * register. All registers (r0-r12,lr) and fp registers (d0-d15) are stored
1926 * consecutively on the stack beginning at the specified stack pointer.
1927 * Calls the proper Self Verification handler for the memory instruction and
1928 * updates the link register to point past the decoded memory instruction.
1929 */
1930void dvmSelfVerificationMemOpDecode(int lr, int* sp)
1931{
1932assert(0); /* MIPSTODO retarg func */
1933 enum {
1934 kMemOpLdrPcRel = 0x09, // ldr(3) [01001] rd[10..8] imm_8[7..0]
1935 kMemOpRRR = 0x0A, // Full opcode is 7 bits
1936 kMemOp2Single = 0x0A, // Used for Vstrs and Vldrs
1937 kMemOpRRR2 = 0x0B, // Full opcode is 7 bits
1938 kMemOp2Double = 0x0B, // Used for Vstrd and Vldrd
1939 kMemOpStrRRI5 = 0x0C, // str(1) [01100] imm_5[10..6] rn[5..3] rd[2..0]
1940 kMemOpLdrRRI5 = 0x0D, // ldr(1) [01101] imm_5[10..6] rn[5..3] rd[2..0]
1941 kMemOpStrbRRI5 = 0x0E, // strb(1) [01110] imm_5[10..6] rn[5..3] rd[2..0]
1942 kMemOpLdrbRRI5 = 0x0F, // ldrb(1) [01111] imm_5[10..6] rn[5..3] rd[2..0]
1943 kMemOpStrhRRI5 = 0x10, // strh(1) [10000] imm_5[10..6] rn[5..3] rd[2..0]
1944 kMemOpLdrhRRI5 = 0x11, // ldrh(1) [10001] imm_5[10..6] rn[5..3] rd[2..0]
1945 kMemOpLdrSpRel = 0x13, // ldr(4) [10011] rd[10..8] imm_8[7..0]
1946 kMemOpStmia = 0x18, // stmia [11000] rn[10..8] reglist [7..0]
1947 kMemOpLdmia = 0x19, // ldmia [11001] rn[10..8] reglist [7..0]
1948 kMemOpStrRRR = 0x28, // str(2) [0101000] rm[8..6] rn[5..3] rd[2..0]
1949 kMemOpStrhRRR = 0x29, // strh(2) [0101001] rm[8..6] rn[5..3] rd[2..0]
1950 kMemOpStrbRRR = 0x2A, // strb(2) [0101010] rm[8..6] rn[5..3] rd[2..0]
1951 kMemOpLdrsbRRR = 0x2B, // ldrsb [0101011] rm[8..6] rn[5..3] rd[2..0]
1952 kMemOpLdrRRR = 0x2C, // ldr(2) [0101100] rm[8..6] rn[5..3] rd[2..0]
1953 kMemOpLdrhRRR = 0x2D, // ldrh(2) [0101101] rm[8..6] rn[5..3] rd[2..0]
1954 kMemOpLdrbRRR = 0x2E, // ldrb(2) [0101110] rm[8..6] rn[5..3] rd[2..0]
1955 kMemOpLdrshRRR = 0x2F, // ldrsh [0101111] rm[8..6] rn[5..3] rd[2..0]
1956 kMemOp2Stmia = 0xE88, // stmia [111010001000[ rn[19..16] mask[15..0]
1957 kMemOp2Ldmia = 0xE89, // ldmia [111010001001[ rn[19..16] mask[15..0]
1958 kMemOp2Stmia2 = 0xE8A, // stmia [111010001010[ rn[19..16] mask[15..0]
1959 kMemOp2Ldmia2 = 0xE8B, // ldmia [111010001011[ rn[19..16] mask[15..0]
1960 kMemOp2Vstr = 0xED8, // Used for Vstrs and Vstrd
1961 kMemOp2Vldr = 0xED9, // Used for Vldrs and Vldrd
1962 kMemOp2Vstr2 = 0xEDC, // Used for Vstrs and Vstrd
1963 kMemOp2Vldr2 = 0xEDD, // Used for Vstrs and Vstrd
1964 kMemOp2StrbRRR = 0xF80, /* str rt,[rn,rm,LSL #imm] [111110000000]
1965 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
1966 kMemOp2LdrbRRR = 0xF81, /* ldrb rt,[rn,rm,LSL #imm] [111110000001]
1967 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
1968 kMemOp2StrhRRR = 0xF82, /* str rt,[rn,rm,LSL #imm] [111110000010]
1969 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
1970 kMemOp2LdrhRRR = 0xF83, /* ldrh rt,[rn,rm,LSL #imm] [111110000011]
1971 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
1972 kMemOp2StrRRR = 0xF84, /* str rt,[rn,rm,LSL #imm] [111110000100]
1973 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
1974 kMemOp2LdrRRR = 0xF85, /* ldr rt,[rn,rm,LSL #imm] [111110000101]
1975 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
1976 kMemOp2StrbRRI12 = 0xF88, /* strb rt,[rn,#imm12] [111110001000]
1977 rt[15..12] rn[19..16] imm12[11..0] */
1978 kMemOp2LdrbRRI12 = 0xF89, /* ldrb rt,[rn,#imm12] [111110001001]
1979 rt[15..12] rn[19..16] imm12[11..0] */
1980 kMemOp2StrhRRI12 = 0xF8A, /* strh rt,[rn,#imm12] [111110001010]
1981 rt[15..12] rn[19..16] imm12[11..0] */
1982 kMemOp2LdrhRRI12 = 0xF8B, /* ldrh rt,[rn,#imm12] [111110001011]
1983 rt[15..12] rn[19..16] imm12[11..0] */
1984 kMemOp2StrRRI12 = 0xF8C, /* str(Imm,T3) rd,[rn,#imm12] [111110001100]
1985 rn[19..16] rt[15..12] imm12[11..0] */
1986 kMemOp2LdrRRI12 = 0xF8D, /* ldr(Imm,T3) rd,[rn,#imm12] [111110001101]
1987 rn[19..16] rt[15..12] imm12[11..0] */
1988 kMemOp2LdrsbRRR = 0xF91, /* ldrsb rt,[rn,rm,LSL #imm] [111110010001]
1989 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
1990 kMemOp2LdrshRRR = 0xF93, /* ldrsh rt,[rn,rm,LSL #imm] [111110010011]
1991 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
1992 kMemOp2LdrsbRRI12 = 0xF99, /* ldrsb rt,[rn,#imm12] [111110011001]
1993 rt[15..12] rn[19..16] imm12[11..0] */
1994 kMemOp2LdrshRRI12 = 0xF9B, /* ldrsh rt,[rn,#imm12] [111110011011]
1995 rt[15..12] rn[19..16] imm12[11..0] */
1996 kMemOp2 = 0xE000, // top 3 bits set indicates Thumb2
1997 };
1998
1999 int addr, offset, data;
2000 long long double_data;
2001 int size = kSVWord;
2002 bool store = false;
2003 unsigned int *lr_masked = (unsigned int *) (lr & 0xFFFFFFFE);
2004 unsigned int insn = *lr_masked;
2005
2006 int old_lr;
2007 old_lr = selfVerificationMemRegLoad(sp, 13);
2008
2009 if ((insn & kMemOp2) == kMemOp2) {
2010 insn = (insn << 16) | (insn >> 16);
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07002011 //ALOGD("*** THUMB2 - Addr: %#x Insn: %#x", lr, insn);
Raghu Gandhama8b91c52012-05-02 14:27:16 -07002012
2013 int opcode12 = (insn >> 20) & 0xFFF;
2014 int opcode6 = (insn >> 6) & 0x3F;
2015 int opcode4 = (insn >> 8) & 0xF;
2016 int imm2 = (insn >> 4) & 0x3;
2017 int imm8 = insn & 0xFF;
2018 int imm12 = insn & 0xFFF;
2019 int rd = (insn >> 12) & 0xF;
2020 int rm = insn & 0xF;
2021 int rn = (insn >> 16) & 0xF;
2022 int rt = (insn >> 12) & 0xF;
2023 bool wBack = true;
2024
2025 // Update the link register
2026 selfVerificationMemRegStore(sp, old_lr+4, 13);
2027
2028 // Determine whether the mem op is a store or load
2029 switch (opcode12) {
2030 case kMemOp2Stmia:
2031 case kMemOp2Stmia2:
2032 case kMemOp2Vstr:
2033 case kMemOp2Vstr2:
2034 case kMemOp2StrbRRR:
2035 case kMemOp2StrhRRR:
2036 case kMemOp2StrRRR:
2037 case kMemOp2StrbRRI12:
2038 case kMemOp2StrhRRI12:
2039 case kMemOp2StrRRI12:
2040 store = true;
2041 }
2042
2043 // Determine the size of the mem access
2044 switch (opcode12) {
2045 case kMemOp2StrbRRR:
2046 case kMemOp2LdrbRRR:
2047 case kMemOp2StrbRRI12:
2048 case kMemOp2LdrbRRI12:
2049 size = kSVByte;
2050 break;
2051 case kMemOp2LdrsbRRR:
2052 case kMemOp2LdrsbRRI12:
2053 size = kSVSignedByte;
2054 break;
2055 case kMemOp2StrhRRR:
2056 case kMemOp2LdrhRRR:
2057 case kMemOp2StrhRRI12:
2058 case kMemOp2LdrhRRI12:
2059 size = kSVHalfword;
2060 break;
2061 case kMemOp2LdrshRRR:
2062 case kMemOp2LdrshRRI12:
2063 size = kSVSignedHalfword;
2064 break;
2065 case kMemOp2Vstr:
2066 case kMemOp2Vstr2:
2067 case kMemOp2Vldr:
2068 case kMemOp2Vldr2:
2069 if (opcode4 == kMemOp2Double) size = kSVDoubleword;
2070 break;
2071 case kMemOp2Stmia:
2072 case kMemOp2Ldmia:
2073 case kMemOp2Stmia2:
2074 case kMemOp2Ldmia2:
2075 size = kSVVariable;
2076 break;
2077 }
2078
2079 // Load the value of the address
2080 addr = selfVerificationMemRegLoad(sp, rn);
2081
2082 // Figure out the offset
2083 switch (opcode12) {
2084 case kMemOp2Vstr:
2085 case kMemOp2Vstr2:
2086 case kMemOp2Vldr:
2087 case kMemOp2Vldr2:
2088 offset = imm8 << 2;
2089 if (opcode4 == kMemOp2Single) {
2090 rt = rd << 1;
2091 if (insn & 0x400000) rt |= 0x1;
2092 } else if (opcode4 == kMemOp2Double) {
2093 if (insn & 0x400000) rt |= 0x10;
2094 rt = rt << 1;
2095 } else {
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07002096 ALOGE("*** ERROR: UNRECOGNIZED VECTOR MEM OP: %x", opcode4);
Raghu Gandhama8b91c52012-05-02 14:27:16 -07002097 dvmAbort();
2098 }
2099 rt += 14;
2100 break;
2101 case kMemOp2StrbRRR:
2102 case kMemOp2LdrbRRR:
2103 case kMemOp2StrhRRR:
2104 case kMemOp2LdrhRRR:
2105 case kMemOp2StrRRR:
2106 case kMemOp2LdrRRR:
2107 case kMemOp2LdrsbRRR:
2108 case kMemOp2LdrshRRR:
2109 offset = selfVerificationMemRegLoad(sp, rm) << imm2;
2110 break;
2111 case kMemOp2StrbRRI12:
2112 case kMemOp2LdrbRRI12:
2113 case kMemOp2StrhRRI12:
2114 case kMemOp2LdrhRRI12:
2115 case kMemOp2StrRRI12:
2116 case kMemOp2LdrRRI12:
2117 case kMemOp2LdrsbRRI12:
2118 case kMemOp2LdrshRRI12:
2119 offset = imm12;
2120 break;
2121 case kMemOp2Stmia:
2122 case kMemOp2Ldmia:
2123 wBack = false;
2124 case kMemOp2Stmia2:
2125 case kMemOp2Ldmia2:
2126 offset = 0;
2127 break;
2128 default:
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07002129 ALOGE("*** ERROR: UNRECOGNIZED THUMB2 MEM OP: %x", opcode12);
Raghu Gandhama8b91c52012-05-02 14:27:16 -07002130 offset = 0;
2131 dvmAbort();
2132 }
2133
2134 // Handle the decoded mem op accordingly
2135 if (store) {
2136 if (size == kSVVariable) {
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07002137 ALOGD("*** THUMB2 STMIA CURRENTLY UNUSED (AND UNTESTED)");
Raghu Gandhama8b91c52012-05-02 14:27:16 -07002138 int i;
2139 int regList = insn & 0xFFFF;
2140 for (i = 0; i < 16; i++) {
2141 if (regList & 0x1) {
2142 data = selfVerificationMemRegLoad(sp, i);
2143 selfVerificationStore(addr, data, kSVWord);
2144 addr += 4;
2145 }
2146 regList = regList >> 1;
2147 }
2148 if (wBack) selfVerificationMemRegStore(sp, addr, rn);
2149 } else if (size == kSVDoubleword) {
2150 double_data = selfVerificationMemRegLoadDouble(sp, rt);
2151 selfVerificationStoreDoubleword(addr+offset, double_data);
2152 } else {
2153 data = selfVerificationMemRegLoad(sp, rt);
2154 selfVerificationStore(addr+offset, data, size);
2155 }
2156 } else {
2157 if (size == kSVVariable) {
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07002158 ALOGD("*** THUMB2 LDMIA CURRENTLY UNUSED (AND UNTESTED)");
Raghu Gandhama8b91c52012-05-02 14:27:16 -07002159 int i;
2160 int regList = insn & 0xFFFF;
2161 for (i = 0; i < 16; i++) {
2162 if (regList & 0x1) {
2163 data = selfVerificationLoad(addr, kSVWord);
2164 selfVerificationMemRegStore(sp, data, i);
2165 addr += 4;
2166 }
2167 regList = regList >> 1;
2168 }
2169 if (wBack) selfVerificationMemRegStore(sp, addr, rn);
2170 } else if (size == kSVDoubleword) {
2171 double_data = selfVerificationLoadDoubleword(addr+offset);
2172 selfVerificationMemRegStoreDouble(sp, double_data, rt);
2173 } else {
2174 data = selfVerificationLoad(addr+offset, size);
2175 selfVerificationMemRegStore(sp, data, rt);
2176 }
2177 }
2178 } else {
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07002179 //ALOGD("*** THUMB - Addr: %#x Insn: %#x", lr, insn);
Raghu Gandhama8b91c52012-05-02 14:27:16 -07002180
2181 // Update the link register
2182 selfVerificationMemRegStore(sp, old_lr+2, 13);
2183
2184 int opcode5 = (insn >> 11) & 0x1F;
2185 int opcode7 = (insn >> 9) & 0x7F;
2186 int imm = (insn >> 6) & 0x1F;
2187 int rd = (insn >> 8) & 0x7;
2188 int rm = (insn >> 6) & 0x7;
2189 int rn = (insn >> 3) & 0x7;
2190 int rt = insn & 0x7;
2191
2192 // Determine whether the mem op is a store or load
2193 switch (opcode5) {
2194 case kMemOpRRR:
2195 switch (opcode7) {
2196 case kMemOpStrRRR:
2197 case kMemOpStrhRRR:
2198 case kMemOpStrbRRR:
2199 store = true;
2200 }
2201 break;
2202 case kMemOpStrRRI5:
2203 case kMemOpStrbRRI5:
2204 case kMemOpStrhRRI5:
2205 case kMemOpStmia:
2206 store = true;
2207 }
2208
2209 // Determine the size of the mem access
2210 switch (opcode5) {
2211 case kMemOpRRR:
2212 case kMemOpRRR2:
2213 switch (opcode7) {
2214 case kMemOpStrbRRR:
2215 case kMemOpLdrbRRR:
2216 size = kSVByte;
2217 break;
2218 case kMemOpLdrsbRRR:
2219 size = kSVSignedByte;
2220 break;
2221 case kMemOpStrhRRR:
2222 case kMemOpLdrhRRR:
2223 size = kSVHalfword;
2224 break;
2225 case kMemOpLdrshRRR:
2226 size = kSVSignedHalfword;
2227 break;
2228 }
2229 break;
2230 case kMemOpStrbRRI5:
2231 case kMemOpLdrbRRI5:
2232 size = kSVByte;
2233 break;
2234 case kMemOpStrhRRI5:
2235 case kMemOpLdrhRRI5:
2236 size = kSVHalfword;
2237 break;
2238 case kMemOpStmia:
2239 case kMemOpLdmia:
2240 size = kSVVariable;
2241 break;
2242 }
2243
2244 // Load the value of the address
2245 if (opcode5 == kMemOpLdrPcRel)
2246 addr = selfVerificationMemRegLoad(sp, 4);
2247 else if (opcode5 == kMemOpStmia || opcode5 == kMemOpLdmia)
2248 addr = selfVerificationMemRegLoad(sp, rd);
2249 else
2250 addr = selfVerificationMemRegLoad(sp, rn);
2251
2252 // Figure out the offset
2253 switch (opcode5) {
2254 case kMemOpLdrPcRel:
2255 offset = (insn & 0xFF) << 2;
2256 rt = rd;
2257 break;
2258 case kMemOpRRR:
2259 case kMemOpRRR2:
2260 offset = selfVerificationMemRegLoad(sp, rm);
2261 break;
2262 case kMemOpStrRRI5:
2263 case kMemOpLdrRRI5:
2264 offset = imm << 2;
2265 break;
2266 case kMemOpStrhRRI5:
2267 case kMemOpLdrhRRI5:
2268 offset = imm << 1;
2269 break;
2270 case kMemOpStrbRRI5:
2271 case kMemOpLdrbRRI5:
2272 offset = imm;
2273 break;
2274 case kMemOpStmia:
2275 case kMemOpLdmia:
2276 offset = 0;
2277 break;
2278 default:
Raghu Gandhamfc3b0c42012-07-30 14:46:12 -07002279 ALOGE("*** ERROR: UNRECOGNIZED THUMB MEM OP: %x", opcode5);
Raghu Gandhama8b91c52012-05-02 14:27:16 -07002280 offset = 0;
2281 dvmAbort();
2282 }
2283
2284 // Handle the decoded mem op accordingly
2285 if (store) {
2286 if (size == kSVVariable) {
2287 int i;
2288 int regList = insn & 0xFF;
2289 for (i = 0; i < 8; i++) {
2290 if (regList & 0x1) {
2291 data = selfVerificationMemRegLoad(sp, i);
2292 selfVerificationStore(addr, data, kSVWord);
2293 addr += 4;
2294 }
2295 regList = regList >> 1;
2296 }
2297 selfVerificationMemRegStore(sp, addr, rd);
2298 } else {
2299 data = selfVerificationMemRegLoad(sp, rt);
2300 selfVerificationStore(addr+offset, data, size);
2301 }
2302 } else {
2303 if (size == kSVVariable) {
2304 bool wBack = true;
2305 int i;
2306 int regList = insn & 0xFF;
2307 for (i = 0; i < 8; i++) {
2308 if (regList & 0x1) {
2309 if (i == rd) wBack = false;
2310 data = selfVerificationLoad(addr, kSVWord);
2311 selfVerificationMemRegStore(sp, data, i);
2312 addr += 4;
2313 }
2314 regList = regList >> 1;
2315 }
2316 if (wBack) selfVerificationMemRegStore(sp, addr, rd);
2317 } else {
2318 data = selfVerificationLoad(addr+offset, size);
2319 selfVerificationMemRegStore(sp, data, rt);
2320 }
2321 }
2322 }
2323}
2324#endif