2 * Copyright (C) 2009 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include "libdex/DexOpcodes.h"
20 #include "../../CompilerInternals.h"
23 #include <unistd.h> /* for cacheflush */
24 #include <sys/mman.h> /* for protection change */
26 #define MAX_ASSEMBLER_RETRIES 10
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)
42 * fmt: for pretty-printing
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}
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
54 * 0 -> operands[0] (dest)
55 * 1 -> operands[1] (src1)
56 * 2 -> operands[2] (src2)
57 * 3 -> operands[3] (extra)
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
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
77 * [!] escape. To insert "!", use "!!"
79 /* NOTE: must be kept in sync with enum MipsOpcode from MipsLIR.h */
80 MipsEncodingMap 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,
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,
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),
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,
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,
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,
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,
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),
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),
395 ENCODING_MAP(kMipsUndefined, 0x64000000,
396 kFmtUnused, -1, -1, kFmtUnused, -1, -1, kFmtUnused, -1, -1,
397 kFmtUnused, -1, -1, NO_OPERAND,
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++)
405 #define UPDATE_CODE_CACHE_PATCHES()
408 /* Write the numbers in the constant and class pool to the output stream */
409 static void installLiteralPools(CompilationUnit *cUnit)
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;
417 * Install the callsiteinfo pointers into the cells for now. They will
418 * be converted into real pointers in dvmJitInstallClassObjectPointers.
420 *dataPtr++ = dataLIR->operands[0];
421 dataLIR = NEXT_LIR(dataLIR);
423 dataLIR = (MipsLIR *) cUnit->literalList;
425 *dataPtr++ = dataLIR->operands[0];
426 dataLIR = NEXT_LIR(dataLIR);
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.
436 static AssemblerStatus assembleInstructions(CompilationUnit *cUnit,
439 int *bufferAddr = (int *) cUnit->codeBuffer;
442 for (lir = (MipsLIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
443 if (lir->opcode < 0) {
448 if (lir->flags.isNop) {
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;
458 LOGE("PC-rel distance is not multiple of 4: %d", delta);
461 if (delta > 131068 || delta < -131069) {
462 LOGE("Unconditional branch distance out of range: %d", delta);
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;
472 LOGE("PC-rel distance is not multiple of 4: %d", delta);
475 if (delta > 131068 || delta < -131069) {
476 LOGE("Conditional branch distance out of range: %d", delta);
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;
486 LOGE("PC-rel distance is not multiple of 4: %d", delta);
489 if (delta > 131068 || delta < -131069) {
490 LOGE("Conditional branch distance out of range: %d", delta);
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));
500 LOGE("Jump target is not multiple of 4: %d", target);
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;
515 MipsEncodingMap *encoder = &EncodingMap[lir->opcode];
516 u4 bits = encoder->skeleton;
518 for (i = 0; i < 4; i++) {
521 operand = lir->operands[i];
522 switch(encoder->fieldLoc[i].kind) {
526 if (encoder->fieldLoc[i].start == 0 && encoder->fieldLoc[i].end == 31) {
529 value = (operand << encoder->fieldLoc[i].start) &
530 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
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);
543 assert(SINGLEREG(operand));
544 value = ((operand & FP_REG_MASK) << encoder->fieldLoc[i].start) &
545 ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
552 assert(encoder->size == 2);
553 *bufferAddr++ = bits;
558 static int assignLiteralOffsetCommon(LIR *lir, int offset)
560 for (;lir != NULL; lir = lir->next) {
561 lir->offset = offset;
567 /* Determine the offset of each literal field */
568 static int assignLiteralOffset(CompilationUnit *cUnit, int offset)
570 /* Reserved for the size field of class pointer pool */
572 offset = assignLiteralOffsetCommon(cUnit->classPointerList, offset);
573 offset = assignLiteralOffsetCommon(cUnit->literalList, offset);
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.
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
593 * | +----------------------------+
594 * | | Chaining Cells | -> 16/20 bytes, 4 byte aligned
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
606 * +----------------------------+
607 * | # Class pointer pool size | -> 4 bytes
608 * +----------------------------+
609 * | Class pointer pool | -> 4-byte aligned, variable size
613 * +----------------------------+
614 * | Literal pool | -> 4-byte aligned, variable size
618 * +----------------------------+
622 #define PROF_COUNTER_ADDR_SIZE 4
623 #define CHAIN_CELL_OFFSET_SIZE 4
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.
630 static inline char *getTraceBase(const JitEntry *p)
632 return (char*)p->codeAddress -
633 (PROF_COUNTER_ADDR_SIZE + CHAIN_CELL_OFFSET_SIZE);
636 /* Handy function to retrieve the profile count */
637 static inline JitTraceCounter_t getProfileCount(const JitEntry *entry)
639 if (entry->dPC == 0 || entry->codeAddress == 0 ||
640 entry->codeAddress == dvmCompilerGetInterpretTemplate())
643 JitTraceCounter_t **p = (JitTraceCounter_t **) getTraceBase(entry);
648 /* Handy function to reset the profile count */
649 static inline void resetProfileCount(const JitEntry *entry)
651 if (entry->dPC == 0 || entry->codeAddress == 0 ||
652 entry->codeAddress == dvmCompilerGetInterpretTemplate())
655 JitTraceCounter_t **p = (JitTraceCounter_t **) getTraceBase(entry);
660 /* Get the pointer of the chain cell count */
661 static inline ChainCellCounts* getChainCellCountsPointer(const char *base)
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);
669 /* Get the size of all chaining cells */
670 static inline u4 getChainCellSize(const ChainCellCounts* pChainCellCounts)
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);
681 cellSize += pChainCellCounts->u.count[i] *
682 (CHAIN_CELL_PREDICTED_SIZE >> 2);
688 /* Get the starting pointer of the trace description section */
689 static JitTraceDescription* getTraceDescriptionPointer(const char *base)
691 ChainCellCounts* pCellCounts = getChainCellCountsPointer(base);
692 return (JitTraceDescription*) ((char*)pCellCounts + sizeof(*pCellCounts));
695 /* Get the size of a trace description */
696 static int getTraceDescriptionSize(const JitTraceDescription *desc)
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)
705 return sizeof(JitTraceDescription) + ((runCount+1) * sizeof(JitTraceRun));
708 #if defined(SIGNATURE_BREAKPOINT)
709 /* Inspect the assembled instruction stream to find potential matches */
710 static void matchSignatureBreakpoint(const CompilationUnit *cUnit,
714 u4 *ptr = (u4 *) cUnit->codeBuffer;
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]) {
723 if (j == gDvmJit.signatureBreakpointSize) {
724 LOGD("Signature match starting from offset %#x (%d words)",
725 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);
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.
743 void dvmCompilerAssembleLIR(CompilationUnit *cUnit, JitTranslationInfo *info)
748 ChainCellCounts chainCellCounts;
749 int descSize = (cUnit->jitMode == kJitMethod) ?
750 0 : getTraceDescriptionSize(cUnit->traceDesc);
751 int chainingCellGap = 0;
753 info->instructionSet = cUnit->instructionSet;
755 /* Beginning offset needs to allow space for chain cell offset */
756 for (mipsLIR = (MipsLIR *) cUnit->firstLIRInsn;
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;
764 /* Pseudo opcodes don't consume space */
767 /* Const values have to be word aligned */
768 offset = (offset + 3) & ~3;
770 u4 chainCellOffset = offset;
771 MipsLIR *chainCellOffsetLIR = NULL;
773 if (cUnit->jitMode != kJitMethod) {
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.
779 chainingCellGap = (offset - cUnit->chainingCellBottom->offset) >> 2;
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);
789 * Adjust the CHAIN_CELL_OFFSET_TAG LIR's offset to remove the
790 * space occupied by the pointer to the trace profiling counter.
792 chainCellOffsetLIR->operands[0] = chainCellOffset - 4;
794 offset += sizeof(chainCellCounts) + descSize;
796 assert((offset & 0x3) == 0); /* Should still be word aligned */
799 /* Set up offsets for literals */
800 cUnit->dataOffset = offset;
803 * Assign each class pointer/constant an offset from the beginning of the
806 offset = assignLiteralOffset(cUnit, offset);
808 cUnit->totalSize = offset;
810 if (gDvmJit.codeCacheByteUsed + cUnit->totalSize > gDvmJit.codeCacheSize) {
811 gDvmJit.codeCacheFull = true;
812 info->discardResult = true;
816 /* Allocate enough space for the code block */
817 cUnit->codeBuffer = (unsigned char *)dvmCompilerNew(chainCellOffset, true);
818 if (cUnit->codeBuffer == NULL) {
819 LOGE("Code buffer allocation failure");
820 info->discardResult = true;
825 * Attempt to assemble the trace. Note that assembleInstructions
826 * may rewrite the code sequence and request a retry.
828 cUnit->assemblerStatus = assembleInstructions(cUnit,
829 (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed);
831 switch(cUnit->assemblerStatus) {
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;
842 /* Too many retries - reset and try cutting the trace in half */
843 cUnit->assemblerRetries = 0;
844 cUnit->assemblerStatus = kRetryHalve;
849 LOGE("Unexpected assembler status: %d", cUnit->assemblerStatus);
853 #if defined(SIGNATURE_BREAKPOINT)
854 if (info->discardResult == false && gDvmJit.signatureBreakpoint != NULL &&
855 chainCellOffset/4 >= gDvmJit.signatureBreakpointSize) {
856 matchSignatureBreakpoint(cUnit, chainCellOffset/4);
860 /* Don't go all the way if the goal is just to get the verbose output */
861 if (info->discardResult) return;
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.
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);
879 cUnit->baseAddr = (char *) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed;
880 gDvmJit.codeCacheByteUsed += offset;
882 UNPROTECT_CODE_CACHE(cUnit->baseAddr, offset);
884 /* Install the code block */
885 memcpy((char*)cUnit->baseAddr, cUnit->codeBuffer, chainCellOffset);
886 gDvmJit.numCompilations++;
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];
894 /* Set the gap number in the chaining cell count structure */
895 chainCellCounts.u.count[kChainingCellGap] = chainingCellGap;
897 memcpy((char*)cUnit->baseAddr + chainCellOffset, &chainCellCounts,
898 sizeof(chainCellCounts));
900 /* Install the trace description */
901 memcpy((char*) cUnit->baseAddr + chainCellOffset +
902 sizeof(chainCellCounts),
903 cUnit->traceDesc, descSize);
906 /* Write the literals directly into the code cache */
907 installLiteralPools(cUnit);
909 /* Flush dcache and invalidate the icache to maintain coherence */
910 dvmCompilerCacheFlush((long)cUnit->baseAddr,
911 (long)((char *) cUnit->baseAddr + offset), 0);
913 UPDATE_CODE_CACHE_PATCHES();
915 PROTECT_CODE_CACHE(cUnit->baseAddr, offset);
917 /* Translation cache update complete - release lock */
918 dvmUnlockMutex(&gDvmJit.compilerLock);
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;
927 * Returns the skeleton bit pattern associated with an opcode. All
928 * variable fields are zeroed.
930 static u4 getSkeleton(MipsOpCode op)
932 return EncodingMap[op].skeleton;
935 static u4 assembleChainingBranch(int branchOffset, bool thumbTarget)
937 return getSkeleton(kMipsJal) | ((branchOffset & 0x0FFFFFFF) >> 2);
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.
950 void* dvmJitChain(void* tgtAddr, u4* branchAddr)
955 * Only chain translations when there is no urge to ask all threads to
956 * suspend themselves via the interpreter.
958 if ((gDvmJit.pProfTable != NULL) && (gDvm.sumThreadSuspendCount == 0) &&
959 (gDvmJit.codeCacheFull == false) &&
960 ((((int) tgtAddr) & 0xF0000000) == (((int) branchAddr+4) & 0xF0000000))) {
961 gDvmJit.translationChains++;
963 COMPILER_TRACE_CHAINING(
964 LOGD("Jit Runtime: chaining 0x%x to 0x%x",
965 (int) branchAddr, (int) tgtAddr & -2));
967 newInst = assembleChainingBranch((int) tgtAddr & -2, 0);
969 UNPROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
971 *branchAddr = newInst;
972 dvmCompilerCacheFlush((long)branchAddr, (long)branchAddr + 4, 0);
973 UPDATE_CODE_CACHE_PATCHES();
975 PROTECT_CODE_CACHE(branchAddr, sizeof(*branchAddr));
977 gDvmJit.hasNewChain = true;
983 #if !defined(WITH_SELF_VERIFICATION)
985 * Attempt to enqueue a work order to patch an inline cache for a predicted
986 * chaining cell for virtual/interface calls.
988 static void inlineCachePatchEnqueue(PredictedChainingCell *cellAddr,
989 PredictedChainingCell *newContent)
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.
996 dvmLockMutex(&gDvmJit.compilerICPatchLock);
998 /* Fast path for uninitialized chaining cell */
999 if (cellAddr->clazz == NULL &&
1000 cellAddr->branch == PREDICTED_CHAIN_BX_PAIR_INIT) {
1002 UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
1004 cellAddr->method = newContent->method;
1005 cellAddr->branch = newContent->branch;
1008 * The update order matters - make sure clazz is updated last since it
1009 * will bring the uninitialized chaining cell to life.
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();
1016 PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
1018 #if defined(WITH_JIT_TUNING)
1019 gDvmJit.icPatchInit++;
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));
1026 cellAddr->stagedClazz = newContent->clazz;
1028 UPDATE_CODE_CACHE_PATCHES();
1029 PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
1031 #if defined(WITH_JIT_TUNING)
1032 gDvmJit.icPatchRejected++;
1035 * Different classes but same method implementation - it is safe to just
1036 * patch the class value without the need to stop the world.
1038 } else if (cellAddr->method == newContent->method) {
1039 UNPROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
1041 cellAddr->clazz = newContent->clazz;
1042 /* No need to flush the cache here since the branch is not patched */
1043 UPDATE_CODE_CACHE_PATCHES();
1045 PROTECT_CODE_CACHE(cellAddr, sizeof(*cellAddr));
1047 #if defined(WITH_JIT_TUNING)
1048 gDvmJit.icPatchLockFree++;
1051 * Cannot patch the chaining cell inline - queue it until the next safe
1054 } else if (gDvmJit.compilerICPatchIndex < COMPILER_IC_PATCH_QUEUE_SIZE) {
1055 int index = gDvmJit.compilerICPatchIndex++;
1056 const ClassObject *clazz = newContent->clazz;
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++;
1068 /* Queue is full - just drop this patch request */
1069 #if defined(WITH_JIT_TUNING)
1070 gDvmJit.icPatchDropped++;
1074 dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
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.
1096 const Method *dvmJitToPatchPredictedChain(const Method *method,
1098 PredictedChainingCell *cell,
1099 const ClassObject *clazz)
1101 int newRechainCount = PREDICTED_CHAIN_COUNTER_RECHAIN;
1102 #if defined(WITH_SELF_VERIFICATION)
1103 newRechainCount = PREDICTED_CHAIN_COUNTER_AVOID;
1106 PredictedChainingCell newCell;
1107 int baseAddr, tgtAddr;
1108 if (dvmIsNativeMethod(method)) {
1109 UNPROTECT_CODE_CACHE(cell, sizeof(*cell));
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.
1116 cell->clazz = (ClassObject *) PREDICTED_CHAIN_FAKE_CLAZZ;
1118 UPDATE_CODE_CACHE_PATCHES();
1119 PROTECT_CODE_CACHE(cell, sizeof(*cell));
1123 tgtAddr = (int) dvmJitGetTraceAddr(method->insns);
1124 baseAddr = (int) cell + 4; // PC is cur_addr + 4
1126 if ((baseAddr & 0xF0000000) != (tgtAddr & 0xF0000000)) {
1127 COMPILER_TRACE_CHAINING(
1128 LOGD("Jit Runtime: predicted chain %p to distant target %s ignored",
1129 cell, method->name));
1134 * Compilation not made yet for the callee. Reset the counter to a small
1135 * value and come back to check soon.
1137 if ((tgtAddr == 0) ||
1138 ((void*)tgtAddr == dvmCompilerGetInterpretTemplate())) {
1139 COMPILER_TRACE_CHAINING(
1140 LOGD("Jit Runtime: predicted chain %p to method %s%s delayed",
1141 cell, method->clazz->descriptor, method->name));
1145 if (cell->clazz == NULL) {
1146 newRechainCount = self->icRechainCount;
1149 newCell.branch = assembleChainingBranch(tgtAddr, true);
1150 newCell.delay_slot = getSkeleton(kMipsNop);
1151 newCell.clazz = clazz;
1152 newCell.method = method;
1153 newCell.stagedClazz = NULL;
1156 * Enter the work order to the queue and the chaining cell will be patched
1157 * the next time a safe point is entered.
1159 * If the enqueuing fails reset the rechain count to a normal value so that
1160 * it won't get indefinitely delayed.
1162 inlineCachePatchEnqueue(cell, &newCell);
1165 self->icRechainCount = newRechainCount;
1170 * Patch the inline cache content based on the content passed from the work
1173 void dvmCompilerPatchInlineCache(void)
1176 PredictedChainingCell *minAddr, *maxAddr;
1178 /* Nothing to be done */
1179 if (gDvmJit.compilerICPatchIndex == 0) return;
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.
1186 dvmLockMutex(&gDvmJit.compilerICPatchLock);
1188 UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
1190 //LOGD("Number of IC patch work orders: %d", gDvmJit.compilerICPatchIndex);
1192 /* Initialize the min/max address range */
1193 minAddr = (PredictedChainingCell *)
1194 ((char *) gDvmJit.codeCache + gDvmJit.codeCacheSize);
1195 maxAddr = (PredictedChainingCell *) gDvmJit.codeCache;
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);
1204 assert(clazz->serialNumber == workOrder->serialNumber);
1206 /* Use the newly resolved clazz pointer */
1207 cellContent->clazz = clazz;
1209 COMPILER_TRACE_CHAINING(
1210 LOGD("Jit Runtime: predicted chain %p from %s to %s (%s) "
1213 cellAddr->clazz->descriptor,
1214 cellContent->clazz->descriptor,
1215 cellContent->method->name));
1217 /* Patch the chaining cell */
1218 *cellAddr = *cellContent;
1219 minAddr = (cellAddr < minAddr) ? cellAddr : minAddr;
1220 maxAddr = (cellAddr > maxAddr) ? cellAddr : maxAddr;
1223 /* Then synchronize the I/D cache */
1224 dvmCompilerCacheFlush((long) minAddr, (long) (maxAddr+1), 0);
1225 UPDATE_CODE_CACHE_PATCHES();
1227 PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
1229 gDvmJit.compilerICPatchIndex = 0;
1230 dvmUnlockMutex(&gDvmJit.compilerICPatchLock);
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
1240 static u4* unchainSingle(JitEntry *trace)
1242 const char *base = getTraceBase(trace);
1243 ChainCellCounts *pChainCellCounts = getChainCellCountsPointer(base);
1244 int cellSize = getChainCellSize(pChainCellCounts);
1247 PredictedChainingCell *predChainCell;
1250 return (u4 *) pChainCellCounts;
1252 /* Locate the beginning of the chain cell region */
1253 pChainCells = ((u4 *) pChainCellCounts) - cellSize -
1254 pChainCellCounts->u.count[kChainingCellGap];
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;
1263 for (j = 0; j < pChainCellCounts->u.count[i]; j++) {
1266 case kChainingCellNormal:
1267 targetOffset = offsetof(Thread,
1268 jitToInterpEntries.dvmJitToInterpNormal);
1270 case kChainingCellHot:
1271 case kChainingCellInvokeSingleton:
1272 targetOffset = offsetof(Thread,
1273 jitToInterpEntries.dvmJitToInterpTraceSelect);
1275 case kChainingCellInvokePredicted:
1277 predChainCell = (PredictedChainingCell *) pChainCells;
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.
1285 predChainCell->clazz = PREDICTED_CHAIN_CLAZZ_INIT;
1287 #if defined(WITH_SELF_VERIFICATION)
1288 case kChainingCellBackwardBranch:
1289 targetOffset = offsetof(Thread,
1290 jitToInterpEntries.dvmJitToInterpBackwardBranch);
1293 case kChainingCellBackwardBranch:
1294 targetOffset = offsetof(Thread,
1295 jitToInterpEntries.dvmJitToInterpNormal);
1299 targetOffset = 0; // make gcc happy
1300 LOGE("Unexpected chaining type: %d", i);
1301 dvmAbort(); // dvmAbort OK here - can't safely recover
1303 COMPILER_TRACE_CHAINING(
1304 LOGD("Jit Runtime: unchaining %#x", (int)pChainCells));
1306 * Code sequence for a chaining cell is:
1307 * lw a0, offset(rSELF)
1310 if (i != kChainingCellInvokePredicted) {
1311 *pChainCells = getSkeleton(kMipsLw) | (r_A0 << 16) |
1312 targetOffset | (rSELF << 21);
1313 *(pChainCells+1) = getSkeleton(kMipsJalr) | (r_RA << 11) |
1316 pChainCells += elemSize; /* Advance by a fixed number of words */
1322 /* Unchain all translation in the cache. */
1323 void dvmJitUnchainAll()
1325 u4* lowAddress = NULL;
1326 u4* highAddress = NULL;
1328 if (gDvmJit.pJitEntryTable != NULL) {
1329 COMPILER_TRACE_CHAINING(LOGD("Jit Runtime: unchaining all"));
1330 dvmLockMutex(&gDvmJit.tableLock);
1332 UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
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())) {
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;
1350 if (lowAddress && highAddress)
1351 dvmCompilerCacheFlush((long)lowAddress, (long)highAddress, 0);
1353 UPDATE_CODE_CACHE_PATCHES();
1355 PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
1357 dvmUnlockMutex(&gDvmJit.tableLock);
1358 gDvmJit.translationChains = 0;
1360 gDvmJit.hasNewChain = false;
1363 typedef struct jitProfileAddrToLine {
1366 } jitProfileAddrToLine;
1369 /* Callback function to track the bytecode offset/line number relationiship */
1370 static int addrToLineCb (void *cnxt, u4 bytecodeOffset, u4 lineNum)
1372 jitProfileAddrToLine *addrToLine = (jitProfileAddrToLine *) cnxt;
1374 /* Best match so far for this offset */
1375 if (addrToLine->bytecodeOffset >= bytecodeOffset) {
1376 addrToLine->lineNum = lineNum;
1381 /* Dumps profile info for a single trace */
1382 static int dumpTraceProfile(JitEntry *p, bool silent, bool reset,
1387 if (p->codeAddress == NULL) {
1389 LOGD("TRACEPROFILE NULL");
1392 if (p->codeAddress == dvmCompilerGetInterpretTemplate()) {
1394 LOGD("TRACEPROFILE INTERPRET_ONLY");
1398 JitTraceCounter_t count = getProfileCount(p);
1400 resetProfileCount(p);
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};
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
1417 dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile,
1418 dvmGetMethodCode(method),
1419 method->clazz->descriptor,
1420 method->prototype.protoIdx,
1421 method->accessFlags,
1422 addrToLineCb, NULL, &addrToLine);
1424 LOGD("TRACEPROFILE 0x%08x % 10d %5.2f%% [%#x(+%d), %d] %s%s;%s",
1425 (int) getTraceBase(p),
1427 ((float ) count) / sum * 100.0,
1428 desc->trace[0].info.frag.startOffset,
1429 desc->trace[0].info.frag.numInsts,
1431 method->clazz->descriptor, method->name, methodDesc);
1434 /* Find the last fragment (ie runEnd is set) */
1436 desc->trace[idx].isCode && !desc->trace[idx].info.frag.runEnd;
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).
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 */
1449 LOGD(" -> %s%s;%s", method->clazz->descriptor, method->name,
1456 /* Create a copy of the trace descriptor of an existing compilation */
1457 JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc,
1458 const JitEntry *knownEntry)
1460 const JitEntry *jitEntry = knownEntry ? knownEntry
1461 : dvmJitFindEntry(pc, false);
1462 if ((jitEntry == NULL) || (jitEntry->codeAddress == 0))
1465 JitTraceDescription *desc =
1466 getTraceDescriptionPointer(getTraceBase(jitEntry));
1468 /* Now make a copy and return */
1469 int descSize = getTraceDescriptionSize(desc);
1470 JitTraceDescription *newCopy = (JitTraceDescription *) malloc(descSize);
1471 memcpy(newCopy, desc, descSize);
1475 /* qsort callback function */
1476 static int sortTraceProfileCount(const void *entry1, const void *entry2)
1478 const JitEntry *jitEntry1 = (const JitEntry *)entry1;
1479 const JitEntry *jitEntry2 = (const JitEntry *)entry2;
1481 JitTraceCounter_t count1 = getProfileCount(jitEntry1);
1482 JitTraceCounter_t count2 = getProfileCount(jitEntry2);
1483 return (count1 == count2) ? 0 : ((count1 > count2) ? -1 : 1);
1486 /* Sort the trace profile counts and dump them */
1487 void dvmCompilerSortAndPrintTraceProfiles()
1489 JitEntry *sortedEntries;
1491 unsigned long sum = 0;
1494 /* Make sure that the table is not changing */
1495 dvmLockMutex(&gDvmJit.tableLock);
1497 /* Sort the entries by descending order */
1498 sortedEntries = (JitEntry *)malloc(sizeof(JitEntry) * gDvmJit.jitTableSize);
1499 if (sortedEntries == NULL)
1501 memcpy(sortedEntries, gDvmJit.pJitEntryTable,
1502 sizeof(JitEntry) * gDvmJit.jitTableSize);
1503 qsort(sortedEntries, gDvmJit.jitTableSize, sizeof(JitEntry),
1504 sortTraceProfileCount);
1506 /* Analyze the sorted entries */
1507 for (i=0; i < gDvmJit.jitTableSize; i++) {
1508 if (sortedEntries[i].dPC != 0) {
1509 sum += dumpTraceProfile(&sortedEntries[i],
1522 LOGD("JIT: Average execution count -> %d",(int)(sum / numTraces));
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],
1534 for (i=0; i < gDvmJit.jitTableSize && i < 10; i++) {
1535 /* Stip interpreter stubs */
1536 if (sortedEntries[i].codeAddress == dvmCompilerGetInterpretTemplate()) {
1539 JitTraceDescription* desc =
1540 dvmCopyTraceDescriptor(NULL, &sortedEntries[i]);
1542 dvmCompilerWorkEnqueue(sortedEntries[i].dPC,
1543 kWorkOrderTraceDebug, desc);
1547 free(sortedEntries);
1549 dvmUnlockMutex(&gDvmJit.tableLock);
1553 static void findClassPointersSingleTrace(char *base, void (*callback)(void *))
1555 unsigned int chainTypeIdx, chainIdx;
1556 ChainCellCounts *pChainCellCounts = getChainCellCountsPointer(base);
1557 int cellSize = getChainCellSize(pChainCellCounts);
1558 /* Scan the chaining cells */
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;
1566 if (chainTypeIdx != kChainingCellInvokePredicted) {
1567 /* In 32-bit words */
1568 pChainCells += (CHAIN_CELL_NORMAL_SIZE >> 2) *
1569 pChainCellCounts->u.count[chainTypeIdx];
1573 chainIdx < pChainCellCounts->u.count[chainTypeIdx];
1575 PredictedChainingCell *cell =
1576 (PredictedChainingCell *) pChainCells;
1578 * Report the cell if it contains a sane class
1581 if (cell->clazz != NULL &&
1583 (ClassObject *) PREDICTED_CHAIN_FAKE_CLAZZ) {
1584 callback(&cell->clazz);
1586 pChainCells += CHAIN_CELL_PREDICTED_SIZE >> 2;
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);
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.
1606 void dvmJitScanAllClassPointers(void (*callback)(void *))
1608 UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
1610 /* Handle the inflight compilation first */
1611 if (gDvmJit.inflightBaseAddr)
1612 findClassPointersSingleTrace((char *) gDvmJit.inflightBaseAddr,
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];
1621 !entry->u.info.isMethodEntry &&
1622 entry->codeAddress &&
1623 (entry->codeAddress != dvmCompilerGetInterpretTemplate())) {
1624 char *base = getTraceBase(entry);
1625 findClassPointersSingleTrace(base, callback);
1628 dvmUnlockMutex(&gDvmJit.tableLock);
1630 UPDATE_CODE_CACHE_PATCHES();
1632 PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
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.
1639 void dvmJitInstallClassObjectPointers(CompilationUnit *cUnit, char *codeAddress)
1641 char *base = codeAddress - cUnit->headerSize;
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;
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.
1656 dvmChangeStatus(gDvmJit.compilerThread, THREAD_RUNNING);
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).
1667 UNPROTECT_CODE_CACHE(startClassPointerP,
1668 numClassPointers * sizeof(intptr_t));
1669 #if defined(WITH_JIT_TUNING)
1670 u8 startTime = dvmGetRelativeTimeUsec();
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;
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
1686 gDvmJit.inflightBaseAddr = base;
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++;
1695 UPDATE_CODE_CACHE_PATCHES();
1697 PROTECT_CODE_CACHE(startClassPointerP, numClassPointers * sizeof(intptr_t));
1699 /* Change the thread state back to VMWAIT */
1700 dvmChangeStatus(gDvmJit.compilerThread, THREAD_VMWAIT);
1703 #if defined(WITH_SELF_VERIFICATION)
1705 * The following are used to keep compiled loads and stores from modifying
1706 * memory during self verification mode.
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
1713 * Loads check heapSpace first and return data from there if an entry exists.
1714 * Otherwise, data is loaded from memory as usual.
1717 /* Used to specify sizes of memory operations */
1728 /* Load the value of a decoded register from the stack */
1729 static int selfVerificationMemRegLoad(int* sp, int reg)
1731 assert(0); /* MIPSTODO retarg func */
1735 /* Load the value of a decoded doubleword register from the stack */
1736 static s8 selfVerificationMemRegLoadDouble(int* sp, int reg)
1738 assert(0); /* MIPSTODO retarg func */
1739 return *((s8*)(sp + reg));
1742 /* Store the value of a decoded register out to the stack */
1743 static void selfVerificationMemRegStore(int* sp, int data, int reg)
1745 assert(0); /* MIPSTODO retarg func */
1749 /* Store the value of a decoded doubleword register out to the stack */
1750 static void selfVerificationMemRegStoreDouble(int* sp, s8 data, int reg)
1752 assert(0); /* MIPSTODO retarg func */
1753 *((s8*)(sp + reg)) = data;
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.
1761 static int selfVerificationLoad(int addr, int size)
1763 assert(0); /* MIPSTODO retarg func */
1764 Thread *self = dvmThreadSelf();
1765 ShadowSpace *shadowSpace = self->shadowSpace;
1766 ShadowHeap *heapSpacePtr;
1769 int maskedAddr = addr & 0xFFFFFFFC;
1770 int alignment = addr & 0x3;
1772 for (heapSpacePtr = shadowSpace->heapSpace;
1773 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
1774 if (heapSpacePtr->addr == maskedAddr) {
1775 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
1782 data = *((u1*) addr);
1785 data = *((s1*) addr);
1788 data = *((u2*) addr);
1790 case kSVSignedHalfword:
1791 data = *((s2*) addr);
1794 data = *((u4*) addr);
1797 LOGE("*** ERROR: BAD SIZE IN selfVerificationLoad: %d", size);
1802 //LOGD("*** HEAP LOAD: Addr: %#x Data: %#x Size: %d", addr, data, size);
1806 /* Like selfVerificationLoad, but specifically for doublewords */
1807 static s8 selfVerificationLoadDoubleword(int addr)
1809 assert(0); /* MIPSTODO retarg func */
1810 Thread *self = dvmThreadSelf();
1811 ShadowSpace* shadowSpace = self->shadowSpace;
1812 ShadowHeap* heapSpacePtr;
1815 unsigned int data = *((unsigned int*) addr);
1816 unsigned int data2 = *((unsigned int*) addr2);
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;
1827 //LOGD("*** HEAP LOAD DOUBLEWORD: Addr: %#x Data: %#x Data2: %#x",
1828 // addr, data, data2);
1829 return (((s8) data2) << 32) | data;
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.
1838 static void selfVerificationStore(int addr, int data, int size)
1840 assert(0); /* MIPSTODO retarg func */
1841 Thread *self = dvmThreadSelf();
1842 ShadowSpace *shadowSpace = self->shadowSpace;
1843 ShadowHeap *heapSpacePtr;
1845 int maskedAddr = addr & 0xFFFFFFFC;
1846 int alignment = addr & 0x3;
1848 //LOGD("*** HEAP STORE: Addr: %#x Data: %#x Size: %d", addr, data, size);
1850 for (heapSpacePtr = shadowSpace->heapSpace;
1851 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
1852 if (heapSpacePtr->addr == maskedAddr) break;
1855 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
1856 heapSpacePtr->addr = maskedAddr;
1857 heapSpacePtr->data = *((unsigned int*) maskedAddr);
1858 shadowSpace->heapSpaceTail++;
1861 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
1864 *((u1*) addr) = data;
1867 *((s1*) addr) = data;
1870 *((u2*) addr) = data;
1872 case kSVSignedHalfword:
1873 *((s2*) addr) = data;
1876 *((u4*) addr) = data;
1879 LOGE("*** ERROR: BAD SIZE IN selfVerificationSave: %d", size);
1884 /* Like selfVerificationStore, but specifically for doublewords */
1885 static void selfVerificationStoreDoubleword(int addr, s8 double_data)
1887 assert(0); /* MIPSTODO retarg func */
1888 Thread *self = dvmThreadSelf();
1889 ShadowSpace *shadowSpace = self->shadowSpace;
1890 ShadowHeap *heapSpacePtr;
1893 int data = double_data;
1894 int data2 = double_data >> 32;
1895 bool store1 = false, store2 = false;
1897 //LOGD("*** HEAP STORE DOUBLEWORD: Addr: %#x Data: %#x, Data2: %#x",
1898 // addr, data, data2);
1900 for (heapSpacePtr = shadowSpace->heapSpace;
1901 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
1902 if (heapSpacePtr->addr == addr) {
1903 heapSpacePtr->data = data;
1905 } else if (heapSpacePtr->addr == addr2) {
1906 heapSpacePtr->data = data2;
1912 shadowSpace->heapSpaceTail->addr = addr;
1913 shadowSpace->heapSpaceTail->data = data;
1914 shadowSpace->heapSpaceTail++;
1917 shadowSpace->heapSpaceTail->addr = addr2;
1918 shadowSpace->heapSpaceTail->data = data2;
1919 shadowSpace->heapSpaceTail++;
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.
1930 void dvmSelfVerificationMemOpDecode(int lr, int* sp)
1932 assert(0); /* MIPSTODO retarg func */
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
1999 int addr, offset, data;
2000 long long double_data;
2003 unsigned int *lr_masked = (unsigned int *) (lr & 0xFFFFFFFE);
2004 unsigned int insn = *lr_masked;
2007 old_lr = selfVerificationMemRegLoad(sp, 13);
2009 if ((insn & kMemOp2) == kMemOp2) {
2010 insn = (insn << 16) | (insn >> 16);
2011 //LOGD("*** THUMB2 - Addr: %#x Insn: %#x", lr, insn);
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;
2025 // Update the link register
2026 selfVerificationMemRegStore(sp, old_lr+4, 13);
2028 // Determine whether the mem op is a store or load
2034 case kMemOp2StrbRRR:
2035 case kMemOp2StrhRRR:
2037 case kMemOp2StrbRRI12:
2038 case kMemOp2StrhRRI12:
2039 case kMemOp2StrRRI12:
2043 // Determine the size of the mem access
2045 case kMemOp2StrbRRR:
2046 case kMemOp2LdrbRRR:
2047 case kMemOp2StrbRRI12:
2048 case kMemOp2LdrbRRI12:
2051 case kMemOp2LdrsbRRR:
2052 case kMemOp2LdrsbRRI12:
2053 size = kSVSignedByte;
2055 case kMemOp2StrhRRR:
2056 case kMemOp2LdrhRRR:
2057 case kMemOp2StrhRRI12:
2058 case kMemOp2LdrhRRI12:
2061 case kMemOp2LdrshRRR:
2062 case kMemOp2LdrshRRI12:
2063 size = kSVSignedHalfword;
2069 if (opcode4 == kMemOp2Double) size = kSVDoubleword;
2079 // Load the value of the address
2080 addr = selfVerificationMemRegLoad(sp, rn);
2082 // Figure out the offset
2089 if (opcode4 == kMemOp2Single) {
2091 if (insn & 0x400000) rt |= 0x1;
2092 } else if (opcode4 == kMemOp2Double) {
2093 if (insn & 0x400000) rt |= 0x10;
2096 LOGE("*** ERROR: UNRECOGNIZED VECTOR MEM OP: %x", opcode4);
2101 case kMemOp2StrbRRR:
2102 case kMemOp2LdrbRRR:
2103 case kMemOp2StrhRRR:
2104 case kMemOp2LdrhRRR:
2107 case kMemOp2LdrsbRRR:
2108 case kMemOp2LdrshRRR:
2109 offset = selfVerificationMemRegLoad(sp, rm) << imm2;
2111 case kMemOp2StrbRRI12:
2112 case kMemOp2LdrbRRI12:
2113 case kMemOp2StrhRRI12:
2114 case kMemOp2LdrhRRI12:
2115 case kMemOp2StrRRI12:
2116 case kMemOp2LdrRRI12:
2117 case kMemOp2LdrsbRRI12:
2118 case kMemOp2LdrshRRI12:
2129 LOGE("*** ERROR: UNRECOGNIZED THUMB2 MEM OP: %x", opcode12);
2134 // Handle the decoded mem op accordingly
2136 if (size == kSVVariable) {
2137 LOGD("*** THUMB2 STMIA CURRENTLY UNUSED (AND UNTESTED)");
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);
2146 regList = regList >> 1;
2148 if (wBack) selfVerificationMemRegStore(sp, addr, rn);
2149 } else if (size == kSVDoubleword) {
2150 double_data = selfVerificationMemRegLoadDouble(sp, rt);
2151 selfVerificationStoreDoubleword(addr+offset, double_data);
2153 data = selfVerificationMemRegLoad(sp, rt);
2154 selfVerificationStore(addr+offset, data, size);
2157 if (size == kSVVariable) {
2158 LOGD("*** THUMB2 LDMIA CURRENTLY UNUSED (AND UNTESTED)");
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);
2167 regList = regList >> 1;
2169 if (wBack) selfVerificationMemRegStore(sp, addr, rn);
2170 } else if (size == kSVDoubleword) {
2171 double_data = selfVerificationLoadDoubleword(addr+offset);
2172 selfVerificationMemRegStoreDouble(sp, double_data, rt);
2174 data = selfVerificationLoad(addr+offset, size);
2175 selfVerificationMemRegStore(sp, data, rt);
2179 //LOGD("*** THUMB - Addr: %#x Insn: %#x", lr, insn);
2181 // Update the link register
2182 selfVerificationMemRegStore(sp, old_lr+2, 13);
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;
2192 // Determine whether the mem op is a store or load
2203 case kMemOpStrbRRI5:
2204 case kMemOpStrhRRI5:
2209 // Determine the size of the mem access
2218 case kMemOpLdrsbRRR:
2219 size = kSVSignedByte;
2225 case kMemOpLdrshRRR:
2226 size = kSVSignedHalfword;
2230 case kMemOpStrbRRI5:
2231 case kMemOpLdrbRRI5:
2234 case kMemOpStrhRRI5:
2235 case kMemOpLdrhRRI5:
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);
2250 addr = selfVerificationMemRegLoad(sp, rn);
2252 // Figure out the offset
2254 case kMemOpLdrPcRel:
2255 offset = (insn & 0xFF) << 2;
2260 offset = selfVerificationMemRegLoad(sp, rm);
2266 case kMemOpStrhRRI5:
2267 case kMemOpLdrhRRI5:
2270 case kMemOpStrbRRI5:
2271 case kMemOpLdrbRRI5:
2279 LOGE("*** ERROR: UNRECOGNIZED THUMB MEM OP: %x", opcode5);
2284 // Handle the decoded mem op accordingly
2286 if (size == kSVVariable) {
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);
2295 regList = regList >> 1;
2297 selfVerificationMemRegStore(sp, addr, rd);
2299 data = selfVerificationMemRegLoad(sp, rt);
2300 selfVerificationStore(addr+offset, data, size);
2303 if (size == kSVVariable) {
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);
2314 regList = regList >> 1;
2316 if (wBack) selfVerificationMemRegStore(sp, addr, rd);
2318 data = selfVerificationLoad(addr+offset, size);
2319 selfVerificationMemRegStore(sp, data, rt);