blob: 692fccfc5e4792730ded1f01703ed7458cf47ced [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) {
458 LOGE("PC-rel distance is not multiple of 4: %d", delta);
459 dvmAbort();
460 }
461 if (delta > 131068 || delta < -131069) {
462 LOGE("Unconditional branch distance out of range: %d", delta);
463 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) {
472 LOGE("PC-rel distance is not multiple of 4: %d", delta);
473 dvmAbort();
474 }
475 if (delta > 131068 || delta < -131069) {
476 LOGE("Conditional branch distance out of range: %d", delta);
477 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) {
486 LOGE("PC-rel distance is not multiple of 4: %d", delta);
487 dvmAbort();
488 }
489 if (delta > 131068 || delta < -131069) {
490 LOGE("Conditional branch distance out of range: %d", delta);
491 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) {
500 LOGE("Jump target is not multiple of 4: %d", target);
501 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) {
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);
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) {
819 LOGE("Code buffer allocation failure");
820 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:
849 LOGE("Unexpected assembler status: %d", cUnit->assemblerStatus);
850 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(
964 LOGD("Jit Runtime: chaining 0x%x to 0x%x",
965 (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(
1128 LOGD("Jit Runtime: predicted chain %p to distant target %s ignored",
1129 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(
1140 LOGD("Jit Runtime: predicted chain %p to method %s%s delayed",
1141 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
1190 //LOGD("Number of IC patch work orders: %d", gDvmJit.compilerICPatchIndex);
1191
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(
1210 LOGD("Jit Runtime: predicted chain %p from %s to %s (%s) "
1211 "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
1300 LOGE("Unexpected chaining type: %d", i);
1301 dvmAbort(); // dvmAbort OK here - can't safely recover
1302 }
1303 COMPILER_TRACE_CHAINING(
1304 LOGD("Jit Runtime: unchaining %#x", (int)pChainCells));
1305 /*
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) {
1329 COMPILER_TRACE_CHAINING(LOGD("Jit Runtime: unchaining all"));
1330 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
Dong-Yuan Chen0c2dc522012-07-03 13:13:07 -07001350 if (lowAddress && highAddress) {
1351 dvmCompilerCacheFlush((long)lowAddress, (long)highAddress, 0);
1352 }
Raghu Gandhama8b91c52012-05-02 14:27:16 -07001353
1354 UPDATE_CODE_CACHE_PATCHES();
1355
1356 PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
1357
1358 dvmUnlockMutex(&gDvmJit.tableLock);
1359 gDvmJit.translationChains = 0;
1360 }
1361 gDvmJit.hasNewChain = false;
1362}
1363
1364typedef struct jitProfileAddrToLine {
1365 u4 lineNum;
1366 u4 bytecodeOffset;
1367} jitProfileAddrToLine;
1368
1369
1370/* Callback function to track the bytecode offset/line number relationiship */
1371static int addrToLineCb (void *cnxt, u4 bytecodeOffset, u4 lineNum)
1372{
1373 jitProfileAddrToLine *addrToLine = (jitProfileAddrToLine *) cnxt;
1374
1375 /* Best match so far for this offset */
1376 if (addrToLine->bytecodeOffset >= bytecodeOffset) {
1377 addrToLine->lineNum = lineNum;
1378 }
1379 return 0;
1380}
1381
1382/* Dumps profile info for a single trace */
1383static int dumpTraceProfile(JitEntry *p, bool silent, bool reset,
1384 unsigned long sum)
1385{
1386 int idx;
1387
1388 if (p->codeAddress == NULL) {
1389 if (!silent)
1390 LOGD("TRACEPROFILE NULL");
1391 return 0;
1392 }
1393 if (p->codeAddress == dvmCompilerGetInterpretTemplate()) {
1394 if (!silent)
1395 LOGD("TRACEPROFILE INTERPRET_ONLY");
1396 return 0;
1397 }
1398
1399 JitTraceCounter_t count = getProfileCount(p);
1400 if (reset) {
1401 resetProfileCount(p);
1402 }
1403 if (silent) {
1404 return count;
1405 }
1406 JitTraceDescription *desc = getTraceDescriptionPointer(getTraceBase(p));
1407 const Method *method = desc->method;
1408 char *methodDesc = dexProtoCopyMethodDescriptor(&method->prototype);
1409 jitProfileAddrToLine addrToLine = {0, desc->trace[0].info.frag.startOffset};
1410
1411 /*
1412 * We may end up decoding the debug information for the same method
1413 * multiple times, but the tradeoff is we don't need to allocate extra
1414 * space to store the addr/line mapping. Since this is a debugging feature
1415 * and done infrequently so the slower but simpler mechanism should work
1416 * just fine.
1417 */
1418 dexDecodeDebugInfo(method->clazz->pDvmDex->pDexFile,
1419 dvmGetMethodCode(method),
1420 method->clazz->descriptor,
1421 method->prototype.protoIdx,
1422 method->accessFlags,
1423 addrToLineCb, NULL, &addrToLine);
1424
1425 LOGD("TRACEPROFILE 0x%08x % 10d %5.2f%% [%#x(+%d), %d] %s%s;%s",
1426 (int) getTraceBase(p),
1427 count,
1428 ((float ) count) / sum * 100.0,
1429 desc->trace[0].info.frag.startOffset,
1430 desc->trace[0].info.frag.numInsts,
1431 addrToLine.lineNum,
1432 method->clazz->descriptor, method->name, methodDesc);
1433 free(methodDesc);
1434
1435 /* Find the last fragment (ie runEnd is set) */
1436 for (idx = 0;
1437 desc->trace[idx].isCode && !desc->trace[idx].info.frag.runEnd;
1438 idx++) {
1439 }
1440
1441 /*
1442 * runEnd must comes with a JitCodeDesc frag. If isCode is false it must
1443 * be a meta info field (only used by callsite info for now).
1444 */
1445 if (!desc->trace[idx].isCode) {
1446 const Method *method = (const Method *)
1447 desc->trace[idx+JIT_TRACE_CUR_METHOD-1].info.meta;
1448 char *methodDesc = dexProtoCopyMethodDescriptor(&method->prototype);
1449 /* Print the callee info in the trace */
1450 LOGD(" -> %s%s;%s", method->clazz->descriptor, method->name,
1451 methodDesc);
1452 }
1453
1454 return count;
1455}
1456
1457/* Create a copy of the trace descriptor of an existing compilation */
1458JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc,
1459 const JitEntry *knownEntry)
1460{
1461 const JitEntry *jitEntry = knownEntry ? knownEntry
1462 : dvmJitFindEntry(pc, false);
1463 if ((jitEntry == NULL) || (jitEntry->codeAddress == 0))
1464 return NULL;
1465
1466 JitTraceDescription *desc =
1467 getTraceDescriptionPointer(getTraceBase(jitEntry));
1468
1469 /* Now make a copy and return */
1470 int descSize = getTraceDescriptionSize(desc);
1471 JitTraceDescription *newCopy = (JitTraceDescription *) malloc(descSize);
1472 memcpy(newCopy, desc, descSize);
1473 return newCopy;
1474}
1475
1476/* qsort callback function */
1477static int sortTraceProfileCount(const void *entry1, const void *entry2)
1478{
1479 const JitEntry *jitEntry1 = (const JitEntry *)entry1;
1480 const JitEntry *jitEntry2 = (const JitEntry *)entry2;
1481
1482 JitTraceCounter_t count1 = getProfileCount(jitEntry1);
1483 JitTraceCounter_t count2 = getProfileCount(jitEntry2);
1484 return (count1 == count2) ? 0 : ((count1 > count2) ? -1 : 1);
1485}
1486
1487/* Sort the trace profile counts and dump them */
1488void dvmCompilerSortAndPrintTraceProfiles()
1489{
1490 JitEntry *sortedEntries;
1491 int numTraces = 0;
1492 unsigned long sum = 0;
1493 unsigned int i;
1494
1495 /* Make sure that the table is not changing */
1496 dvmLockMutex(&gDvmJit.tableLock);
1497
1498 /* Sort the entries by descending order */
1499 sortedEntries = (JitEntry *)malloc(sizeof(JitEntry) * gDvmJit.jitTableSize);
1500 if (sortedEntries == NULL)
1501 goto done;
1502 memcpy(sortedEntries, gDvmJit.pJitEntryTable,
1503 sizeof(JitEntry) * gDvmJit.jitTableSize);
1504 qsort(sortedEntries, gDvmJit.jitTableSize, sizeof(JitEntry),
1505 sortTraceProfileCount);
1506
1507 /* Analyze the sorted entries */
1508 for (i=0; i < gDvmJit.jitTableSize; i++) {
1509 if (sortedEntries[i].dPC != 0) {
1510 sum += dumpTraceProfile(&sortedEntries[i],
1511 true /* silent */,
1512 false /* reset */,
1513 0);
1514 numTraces++;
1515 }
1516 }
1517 if (numTraces == 0)
1518 numTraces = 1;
1519 if (sum == 0) {
1520 sum = 1;
1521 }
1522
1523 LOGD("JIT: Average execution count -> %d",(int)(sum / numTraces));
1524
1525 /* Dump the sorted entries. The count of each trace will be reset to 0. */
1526 for (i=0; i < gDvmJit.jitTableSize; i++) {
1527 if (sortedEntries[i].dPC != 0) {
1528 dumpTraceProfile(&sortedEntries[i],
1529 false /* silent */,
1530 true /* reset */,
1531 sum);
1532 }
1533 }
1534
1535 for (i=0; i < gDvmJit.jitTableSize && i < 10; i++) {
1536 /* Stip interpreter stubs */
1537 if (sortedEntries[i].codeAddress == dvmCompilerGetInterpretTemplate()) {
1538 continue;
1539 }
1540 JitTraceDescription* desc =
1541 dvmCopyTraceDescriptor(NULL, &sortedEntries[i]);
1542 if (desc) {
1543 dvmCompilerWorkEnqueue(sortedEntries[i].dPC,
1544 kWorkOrderTraceDebug, desc);
1545 }
1546 }
1547
1548 free(sortedEntries);
1549done:
1550 dvmUnlockMutex(&gDvmJit.tableLock);
1551 return;
1552}
1553
1554static void findClassPointersSingleTrace(char *base, void (*callback)(void *))
1555{
1556 unsigned int chainTypeIdx, chainIdx;
1557 ChainCellCounts *pChainCellCounts = getChainCellCountsPointer(base);
1558 int cellSize = getChainCellSize(pChainCellCounts);
1559 /* Scan the chaining cells */
1560 if (cellSize) {
1561 /* Locate the beginning of the chain cell region */
1562 u4 *pChainCells = ((u4 *) pChainCellCounts) - cellSize -
1563 pChainCellCounts->u.count[kChainingCellGap];
1564 /* The cells are sorted in order - walk through them */
1565 for (chainTypeIdx = 0; chainTypeIdx < kChainingCellGap;
1566 chainTypeIdx++) {
1567 if (chainTypeIdx != kChainingCellInvokePredicted) {
1568 /* In 32-bit words */
1569 pChainCells += (CHAIN_CELL_NORMAL_SIZE >> 2) *
1570 pChainCellCounts->u.count[chainTypeIdx];
1571 continue;
1572 }
1573 for (chainIdx = 0;
1574 chainIdx < pChainCellCounts->u.count[chainTypeIdx];
1575 chainIdx++) {
1576 PredictedChainingCell *cell =
1577 (PredictedChainingCell *) pChainCells;
1578 /*
1579 * Report the cell if it contains a sane class
1580 * pointer.
1581 */
1582 if (cell->clazz != NULL &&
1583 cell->clazz !=
1584 (ClassObject *) PREDICTED_CHAIN_FAKE_CLAZZ) {
1585 callback(&cell->clazz);
1586 }
1587 pChainCells += CHAIN_CELL_PREDICTED_SIZE >> 2;
1588 }
1589 }
1590 }
1591
1592 /* Scan the class pointer pool */
1593 JitTraceDescription *desc = getTraceDescriptionPointer(base);
1594 int descSize = getTraceDescriptionSize(desc);
1595 int *classPointerP = (int *) ((char *) desc + descSize);
1596 int numClassPointers = *classPointerP++;
1597 for (; numClassPointers; numClassPointers--, classPointerP++) {
1598 callback(classPointerP);
1599 }
1600}
1601
1602/*
1603 * Scan class pointers in each translation and pass its address to the callback
1604 * function. Currently such a pointers can be found in the pointer pool and the
1605 * clazz field in the predicted chaining cells.
1606 */
1607void dvmJitScanAllClassPointers(void (*callback)(void *))
1608{
1609 UNPROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
1610
1611 /* Handle the inflight compilation first */
1612 if (gDvmJit.inflightBaseAddr)
1613 findClassPointersSingleTrace((char *) gDvmJit.inflightBaseAddr,
1614 callback);
1615
1616 if (gDvmJit.pJitEntryTable != NULL) {
1617 unsigned int traceIdx;
1618 dvmLockMutex(&gDvmJit.tableLock);
1619 for (traceIdx = 0; traceIdx < gDvmJit.jitTableSize; traceIdx++) {
1620 const JitEntry *entry = &gDvmJit.pJitEntryTable[traceIdx];
1621 if (entry->dPC &&
1622 !entry->u.info.isMethodEntry &&
1623 entry->codeAddress &&
1624 (entry->codeAddress != dvmCompilerGetInterpretTemplate())) {
1625 char *base = getTraceBase(entry);
1626 findClassPointersSingleTrace(base, callback);
1627 }
1628 }
1629 dvmUnlockMutex(&gDvmJit.tableLock);
1630 }
1631 UPDATE_CODE_CACHE_PATCHES();
1632
1633 PROTECT_CODE_CACHE(gDvmJit.codeCache, gDvmJit.codeCacheByteUsed);
1634}
1635
1636/*
1637 * Provide the final touch on the class object pointer pool to install the
1638 * actual pointers. The thread has to be in the running state.
1639 */
1640void dvmJitInstallClassObjectPointers(CompilationUnit *cUnit, char *codeAddress)
1641{
1642 char *base = codeAddress - cUnit->headerSize;
1643
1644 /* Scan the class pointer pool */
1645 JitTraceDescription *desc = getTraceDescriptionPointer(base);
1646 int descSize = getTraceDescriptionSize(desc);
1647 intptr_t *classPointerP = (int *) ((char *) desc + descSize);
1648 int numClassPointers = *(int *)classPointerP++;
1649 intptr_t *startClassPointerP = classPointerP;
1650
1651 /*
1652 * Change the thread state to VM_RUNNING so that GC won't be happening
1653 * when the assembler looks up the class pointers. May suspend the current
1654 * thread if there is a pending request before the state is actually
1655 * changed to RUNNING.
1656 */
1657 dvmChangeStatus(gDvmJit.compilerThread, THREAD_RUNNING);
1658
1659 /*
1660 * Unprotecting the code cache will need to acquire the code cache
1661 * protection lock first. Doing so after the state change may increase the
1662 * time spent in the RUNNING state (which may delay the next GC request
1663 * should there be contention on codeCacheProtectionLock). In practice
1664 * this is probably not going to happen often since a GC is just served.
1665 * More importantly, acquiring the lock before the state change will
1666 * cause deadlock (b/4192964).
1667 */
1668 UNPROTECT_CODE_CACHE(startClassPointerP,
1669 numClassPointers * sizeof(intptr_t));
1670#if defined(WITH_JIT_TUNING)
1671 u8 startTime = dvmGetRelativeTimeUsec();
1672#endif
1673 for (;numClassPointers; numClassPointers--) {
1674 CallsiteInfo *callsiteInfo = (CallsiteInfo *) *classPointerP;
1675 ClassObject *clazz = dvmFindClassNoInit(
1676 callsiteInfo->classDescriptor, callsiteInfo->classLoader);
1677 assert(!strcmp(clazz->descriptor, callsiteInfo->classDescriptor));
1678 *classPointerP++ = (intptr_t) clazz;
1679 }
1680
1681 /*
1682 * Register the base address so that if GC kicks in after the thread state
1683 * has been changed to VMWAIT and before the compiled code is registered
1684 * in the JIT table, its content can be patched if class objects are
1685 * moved.
1686 */
1687 gDvmJit.inflightBaseAddr = base;
1688
1689#if defined(WITH_JIT_TUNING)
1690 u8 blockTime = dvmGetRelativeTimeUsec() - startTime;
1691 gDvmJit.compilerThreadBlockGCTime += blockTime;
1692 if (blockTime > gDvmJit.maxCompilerThreadBlockGCTime)
1693 gDvmJit.maxCompilerThreadBlockGCTime = blockTime;
1694 gDvmJit.numCompilerThreadBlockGC++;
1695#endif
1696 UPDATE_CODE_CACHE_PATCHES();
1697
1698 PROTECT_CODE_CACHE(startClassPointerP, numClassPointers * sizeof(intptr_t));
1699
1700 /* Change the thread state back to VMWAIT */
1701 dvmChangeStatus(gDvmJit.compilerThread, THREAD_VMWAIT);
1702}
1703
1704#if defined(WITH_SELF_VERIFICATION)
1705/*
1706 * The following are used to keep compiled loads and stores from modifying
1707 * memory during self verification mode.
1708 *
1709 * Stores do not modify memory. Instead, the address and value pair are stored
1710 * into heapSpace. Addresses within heapSpace are unique. For accesses smaller
1711 * than a word, the word containing the address is loaded first before being
1712 * updated.
1713 *
1714 * Loads check heapSpace first and return data from there if an entry exists.
1715 * Otherwise, data is loaded from memory as usual.
1716 */
1717
1718/* Used to specify sizes of memory operations */
1719enum {
1720 kSVByte,
1721 kSVSignedByte,
1722 kSVHalfword,
1723 kSVSignedHalfword,
1724 kSVWord,
1725 kSVDoubleword,
1726 kSVVariable,
1727};
1728
1729/* Load the value of a decoded register from the stack */
1730static int selfVerificationMemRegLoad(int* sp, int reg)
1731{
1732assert(0); /* MIPSTODO retarg func */
1733 return *(sp + reg);
1734}
1735
1736/* Load the value of a decoded doubleword register from the stack */
1737static s8 selfVerificationMemRegLoadDouble(int* sp, int reg)
1738{
1739assert(0); /* MIPSTODO retarg func */
1740 return *((s8*)(sp + reg));
1741}
1742
1743/* Store the value of a decoded register out to the stack */
1744static void selfVerificationMemRegStore(int* sp, int data, int reg)
1745{
1746assert(0); /* MIPSTODO retarg func */
1747 *(sp + reg) = data;
1748}
1749
1750/* Store the value of a decoded doubleword register out to the stack */
1751static void selfVerificationMemRegStoreDouble(int* sp, s8 data, int reg)
1752{
1753assert(0); /* MIPSTODO retarg func */
1754 *((s8*)(sp + reg)) = data;
1755}
1756
1757/*
1758 * Load the specified size of data from the specified address, checking
1759 * heapSpace first if Self Verification mode wrote to it previously, and
1760 * falling back to actual memory otherwise.
1761 */
1762static int selfVerificationLoad(int addr, int size)
1763{
1764assert(0); /* MIPSTODO retarg func */
1765 Thread *self = dvmThreadSelf();
1766 ShadowSpace *shadowSpace = self->shadowSpace;
1767 ShadowHeap *heapSpacePtr;
1768
1769 int data;
1770 int maskedAddr = addr & 0xFFFFFFFC;
1771 int alignment = addr & 0x3;
1772
1773 for (heapSpacePtr = shadowSpace->heapSpace;
1774 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
1775 if (heapSpacePtr->addr == maskedAddr) {
1776 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
1777 break;
1778 }
1779 }
1780
1781 switch (size) {
1782 case kSVByte:
1783 data = *((u1*) addr);
1784 break;
1785 case kSVSignedByte:
1786 data = *((s1*) addr);
1787 break;
1788 case kSVHalfword:
1789 data = *((u2*) addr);
1790 break;
1791 case kSVSignedHalfword:
1792 data = *((s2*) addr);
1793 break;
1794 case kSVWord:
1795 data = *((u4*) addr);
1796 break;
1797 default:
1798 LOGE("*** ERROR: BAD SIZE IN selfVerificationLoad: %d", size);
1799 data = 0;
1800 dvmAbort();
1801 }
1802
1803 //LOGD("*** HEAP LOAD: Addr: %#x Data: %#x Size: %d", addr, data, size);
1804 return data;
1805}
1806
1807/* Like selfVerificationLoad, but specifically for doublewords */
1808static s8 selfVerificationLoadDoubleword(int addr)
1809{
1810assert(0); /* MIPSTODO retarg func */
1811 Thread *self = dvmThreadSelf();
1812 ShadowSpace* shadowSpace = self->shadowSpace;
1813 ShadowHeap* heapSpacePtr;
1814
1815 int addr2 = addr+4;
1816 unsigned int data = *((unsigned int*) addr);
1817 unsigned int data2 = *((unsigned int*) addr2);
1818
1819 for (heapSpacePtr = shadowSpace->heapSpace;
1820 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
1821 if (heapSpacePtr->addr == addr) {
1822 data = heapSpacePtr->data;
1823 } else if (heapSpacePtr->addr == addr2) {
1824 data2 = heapSpacePtr->data;
1825 }
1826 }
1827
1828 //LOGD("*** HEAP LOAD DOUBLEWORD: Addr: %#x Data: %#x Data2: %#x",
1829 // addr, data, data2);
1830 return (((s8) data2) << 32) | data;
1831}
1832
1833/*
1834 * Handles a store of a specified size of data to a specified address.
1835 * This gets logged as an addr/data pair in heapSpace instead of modifying
1836 * memory. Addresses in heapSpace are unique, and accesses smaller than a
1837 * word pull the entire word from memory first before updating.
1838 */
1839static void selfVerificationStore(int addr, int data, int size)
1840{
1841assert(0); /* MIPSTODO retarg func */
1842 Thread *self = dvmThreadSelf();
1843 ShadowSpace *shadowSpace = self->shadowSpace;
1844 ShadowHeap *heapSpacePtr;
1845
1846 int maskedAddr = addr & 0xFFFFFFFC;
1847 int alignment = addr & 0x3;
1848
1849 //LOGD("*** HEAP STORE: Addr: %#x Data: %#x Size: %d", addr, data, size);
1850
1851 for (heapSpacePtr = shadowSpace->heapSpace;
1852 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
1853 if (heapSpacePtr->addr == maskedAddr) break;
1854 }
1855
1856 if (heapSpacePtr == shadowSpace->heapSpaceTail) {
1857 heapSpacePtr->addr = maskedAddr;
1858 heapSpacePtr->data = *((unsigned int*) maskedAddr);
1859 shadowSpace->heapSpaceTail++;
1860 }
1861
1862 addr = ((unsigned int) &(heapSpacePtr->data)) | alignment;
1863 switch (size) {
1864 case kSVByte:
1865 *((u1*) addr) = data;
1866 break;
1867 case kSVSignedByte:
1868 *((s1*) addr) = data;
1869 break;
1870 case kSVHalfword:
1871 *((u2*) addr) = data;
1872 break;
1873 case kSVSignedHalfword:
1874 *((s2*) addr) = data;
1875 break;
1876 case kSVWord:
1877 *((u4*) addr) = data;
1878 break;
1879 default:
1880 LOGE("*** ERROR: BAD SIZE IN selfVerificationSave: %d", size);
1881 dvmAbort();
1882 }
1883}
1884
1885/* Like selfVerificationStore, but specifically for doublewords */
1886static void selfVerificationStoreDoubleword(int addr, s8 double_data)
1887{
1888assert(0); /* MIPSTODO retarg func */
1889 Thread *self = dvmThreadSelf();
1890 ShadowSpace *shadowSpace = self->shadowSpace;
1891 ShadowHeap *heapSpacePtr;
1892
1893 int addr2 = addr+4;
1894 int data = double_data;
1895 int data2 = double_data >> 32;
1896 bool store1 = false, store2 = false;
1897
1898 //LOGD("*** HEAP STORE DOUBLEWORD: Addr: %#x Data: %#x, Data2: %#x",
1899 // addr, data, data2);
1900
1901 for (heapSpacePtr = shadowSpace->heapSpace;
1902 heapSpacePtr != shadowSpace->heapSpaceTail; heapSpacePtr++) {
1903 if (heapSpacePtr->addr == addr) {
1904 heapSpacePtr->data = data;
1905 store1 = true;
1906 } else if (heapSpacePtr->addr == addr2) {
1907 heapSpacePtr->data = data2;
1908 store2 = true;
1909 }
1910 }
1911
1912 if (!store1) {
1913 shadowSpace->heapSpaceTail->addr = addr;
1914 shadowSpace->heapSpaceTail->data = data;
1915 shadowSpace->heapSpaceTail++;
1916 }
1917 if (!store2) {
1918 shadowSpace->heapSpaceTail->addr = addr2;
1919 shadowSpace->heapSpaceTail->data = data2;
1920 shadowSpace->heapSpaceTail++;
1921 }
1922}
1923
1924/*
1925 * Decodes the memory instruction at the address specified in the link
1926 * register. All registers (r0-r12,lr) and fp registers (d0-d15) are stored
1927 * consecutively on the stack beginning at the specified stack pointer.
1928 * Calls the proper Self Verification handler for the memory instruction and
1929 * updates the link register to point past the decoded memory instruction.
1930 */
1931void dvmSelfVerificationMemOpDecode(int lr, int* sp)
1932{
1933assert(0); /* MIPSTODO retarg func */
1934 enum {
1935 kMemOpLdrPcRel = 0x09, // ldr(3) [01001] rd[10..8] imm_8[7..0]
1936 kMemOpRRR = 0x0A, // Full opcode is 7 bits
1937 kMemOp2Single = 0x0A, // Used for Vstrs and Vldrs
1938 kMemOpRRR2 = 0x0B, // Full opcode is 7 bits
1939 kMemOp2Double = 0x0B, // Used for Vstrd and Vldrd
1940 kMemOpStrRRI5 = 0x0C, // str(1) [01100] imm_5[10..6] rn[5..3] rd[2..0]
1941 kMemOpLdrRRI5 = 0x0D, // ldr(1) [01101] imm_5[10..6] rn[5..3] rd[2..0]
1942 kMemOpStrbRRI5 = 0x0E, // strb(1) [01110] imm_5[10..6] rn[5..3] rd[2..0]
1943 kMemOpLdrbRRI5 = 0x0F, // ldrb(1) [01111] imm_5[10..6] rn[5..3] rd[2..0]
1944 kMemOpStrhRRI5 = 0x10, // strh(1) [10000] imm_5[10..6] rn[5..3] rd[2..0]
1945 kMemOpLdrhRRI5 = 0x11, // ldrh(1) [10001] imm_5[10..6] rn[5..3] rd[2..0]
1946 kMemOpLdrSpRel = 0x13, // ldr(4) [10011] rd[10..8] imm_8[7..0]
1947 kMemOpStmia = 0x18, // stmia [11000] rn[10..8] reglist [7..0]
1948 kMemOpLdmia = 0x19, // ldmia [11001] rn[10..8] reglist [7..0]
1949 kMemOpStrRRR = 0x28, // str(2) [0101000] rm[8..6] rn[5..3] rd[2..0]
1950 kMemOpStrhRRR = 0x29, // strh(2) [0101001] rm[8..6] rn[5..3] rd[2..0]
1951 kMemOpStrbRRR = 0x2A, // strb(2) [0101010] rm[8..6] rn[5..3] rd[2..0]
1952 kMemOpLdrsbRRR = 0x2B, // ldrsb [0101011] rm[8..6] rn[5..3] rd[2..0]
1953 kMemOpLdrRRR = 0x2C, // ldr(2) [0101100] rm[8..6] rn[5..3] rd[2..0]
1954 kMemOpLdrhRRR = 0x2D, // ldrh(2) [0101101] rm[8..6] rn[5..3] rd[2..0]
1955 kMemOpLdrbRRR = 0x2E, // ldrb(2) [0101110] rm[8..6] rn[5..3] rd[2..0]
1956 kMemOpLdrshRRR = 0x2F, // ldrsh [0101111] rm[8..6] rn[5..3] rd[2..0]
1957 kMemOp2Stmia = 0xE88, // stmia [111010001000[ rn[19..16] mask[15..0]
1958 kMemOp2Ldmia = 0xE89, // ldmia [111010001001[ rn[19..16] mask[15..0]
1959 kMemOp2Stmia2 = 0xE8A, // stmia [111010001010[ rn[19..16] mask[15..0]
1960 kMemOp2Ldmia2 = 0xE8B, // ldmia [111010001011[ rn[19..16] mask[15..0]
1961 kMemOp2Vstr = 0xED8, // Used for Vstrs and Vstrd
1962 kMemOp2Vldr = 0xED9, // Used for Vldrs and Vldrd
1963 kMemOp2Vstr2 = 0xEDC, // Used for Vstrs and Vstrd
1964 kMemOp2Vldr2 = 0xEDD, // Used for Vstrs and Vstrd
1965 kMemOp2StrbRRR = 0xF80, /* str rt,[rn,rm,LSL #imm] [111110000000]
1966 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
1967 kMemOp2LdrbRRR = 0xF81, /* ldrb rt,[rn,rm,LSL #imm] [111110000001]
1968 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
1969 kMemOp2StrhRRR = 0xF82, /* str rt,[rn,rm,LSL #imm] [111110000010]
1970 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
1971 kMemOp2LdrhRRR = 0xF83, /* ldrh rt,[rn,rm,LSL #imm] [111110000011]
1972 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
1973 kMemOp2StrRRR = 0xF84, /* str rt,[rn,rm,LSL #imm] [111110000100]
1974 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
1975 kMemOp2LdrRRR = 0xF85, /* ldr rt,[rn,rm,LSL #imm] [111110000101]
1976 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
1977 kMemOp2StrbRRI12 = 0xF88, /* strb rt,[rn,#imm12] [111110001000]
1978 rt[15..12] rn[19..16] imm12[11..0] */
1979 kMemOp2LdrbRRI12 = 0xF89, /* ldrb rt,[rn,#imm12] [111110001001]
1980 rt[15..12] rn[19..16] imm12[11..0] */
1981 kMemOp2StrhRRI12 = 0xF8A, /* strh rt,[rn,#imm12] [111110001010]
1982 rt[15..12] rn[19..16] imm12[11..0] */
1983 kMemOp2LdrhRRI12 = 0xF8B, /* ldrh rt,[rn,#imm12] [111110001011]
1984 rt[15..12] rn[19..16] imm12[11..0] */
1985 kMemOp2StrRRI12 = 0xF8C, /* str(Imm,T3) rd,[rn,#imm12] [111110001100]
1986 rn[19..16] rt[15..12] imm12[11..0] */
1987 kMemOp2LdrRRI12 = 0xF8D, /* ldr(Imm,T3) rd,[rn,#imm12] [111110001101]
1988 rn[19..16] rt[15..12] imm12[11..0] */
1989 kMemOp2LdrsbRRR = 0xF91, /* ldrsb rt,[rn,rm,LSL #imm] [111110010001]
1990 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
1991 kMemOp2LdrshRRR = 0xF93, /* ldrsh rt,[rn,rm,LSL #imm] [111110010011]
1992 rn[19-16] rt[15-12] [000000] imm[5-4] rm[3-0] */
1993 kMemOp2LdrsbRRI12 = 0xF99, /* ldrsb rt,[rn,#imm12] [111110011001]
1994 rt[15..12] rn[19..16] imm12[11..0] */
1995 kMemOp2LdrshRRI12 = 0xF9B, /* ldrsh rt,[rn,#imm12] [111110011011]
1996 rt[15..12] rn[19..16] imm12[11..0] */
1997 kMemOp2 = 0xE000, // top 3 bits set indicates Thumb2
1998 };
1999
2000 int addr, offset, data;
2001 long long double_data;
2002 int size = kSVWord;
2003 bool store = false;
2004 unsigned int *lr_masked = (unsigned int *) (lr & 0xFFFFFFFE);
2005 unsigned int insn = *lr_masked;
2006
2007 int old_lr;
2008 old_lr = selfVerificationMemRegLoad(sp, 13);
2009
2010 if ((insn & kMemOp2) == kMemOp2) {
2011 insn = (insn << 16) | (insn >> 16);
2012 //LOGD("*** THUMB2 - Addr: %#x Insn: %#x", lr, insn);
2013
2014 int opcode12 = (insn >> 20) & 0xFFF;
2015 int opcode6 = (insn >> 6) & 0x3F;
2016 int opcode4 = (insn >> 8) & 0xF;
2017 int imm2 = (insn >> 4) & 0x3;
2018 int imm8 = insn & 0xFF;
2019 int imm12 = insn & 0xFFF;
2020 int rd = (insn >> 12) & 0xF;
2021 int rm = insn & 0xF;
2022 int rn = (insn >> 16) & 0xF;
2023 int rt = (insn >> 12) & 0xF;
2024 bool wBack = true;
2025
2026 // Update the link register
2027 selfVerificationMemRegStore(sp, old_lr+4, 13);
2028
2029 // Determine whether the mem op is a store or load
2030 switch (opcode12) {
2031 case kMemOp2Stmia:
2032 case kMemOp2Stmia2:
2033 case kMemOp2Vstr:
2034 case kMemOp2Vstr2:
2035 case kMemOp2StrbRRR:
2036 case kMemOp2StrhRRR:
2037 case kMemOp2StrRRR:
2038 case kMemOp2StrbRRI12:
2039 case kMemOp2StrhRRI12:
2040 case kMemOp2StrRRI12:
2041 store = true;
2042 }
2043
2044 // Determine the size of the mem access
2045 switch (opcode12) {
2046 case kMemOp2StrbRRR:
2047 case kMemOp2LdrbRRR:
2048 case kMemOp2StrbRRI12:
2049 case kMemOp2LdrbRRI12:
2050 size = kSVByte;
2051 break;
2052 case kMemOp2LdrsbRRR:
2053 case kMemOp2LdrsbRRI12:
2054 size = kSVSignedByte;
2055 break;
2056 case kMemOp2StrhRRR:
2057 case kMemOp2LdrhRRR:
2058 case kMemOp2StrhRRI12:
2059 case kMemOp2LdrhRRI12:
2060 size = kSVHalfword;
2061 break;
2062 case kMemOp2LdrshRRR:
2063 case kMemOp2LdrshRRI12:
2064 size = kSVSignedHalfword;
2065 break;
2066 case kMemOp2Vstr:
2067 case kMemOp2Vstr2:
2068 case kMemOp2Vldr:
2069 case kMemOp2Vldr2:
2070 if (opcode4 == kMemOp2Double) size = kSVDoubleword;
2071 break;
2072 case kMemOp2Stmia:
2073 case kMemOp2Ldmia:
2074 case kMemOp2Stmia2:
2075 case kMemOp2Ldmia2:
2076 size = kSVVariable;
2077 break;
2078 }
2079
2080 // Load the value of the address
2081 addr = selfVerificationMemRegLoad(sp, rn);
2082
2083 // Figure out the offset
2084 switch (opcode12) {
2085 case kMemOp2Vstr:
2086 case kMemOp2Vstr2:
2087 case kMemOp2Vldr:
2088 case kMemOp2Vldr2:
2089 offset = imm8 << 2;
2090 if (opcode4 == kMemOp2Single) {
2091 rt = rd << 1;
2092 if (insn & 0x400000) rt |= 0x1;
2093 } else if (opcode4 == kMemOp2Double) {
2094 if (insn & 0x400000) rt |= 0x10;
2095 rt = rt << 1;
2096 } else {
2097 LOGE("*** ERROR: UNRECOGNIZED VECTOR MEM OP: %x", opcode4);
2098 dvmAbort();
2099 }
2100 rt += 14;
2101 break;
2102 case kMemOp2StrbRRR:
2103 case kMemOp2LdrbRRR:
2104 case kMemOp2StrhRRR:
2105 case kMemOp2LdrhRRR:
2106 case kMemOp2StrRRR:
2107 case kMemOp2LdrRRR:
2108 case kMemOp2LdrsbRRR:
2109 case kMemOp2LdrshRRR:
2110 offset = selfVerificationMemRegLoad(sp, rm) << imm2;
2111 break;
2112 case kMemOp2StrbRRI12:
2113 case kMemOp2LdrbRRI12:
2114 case kMemOp2StrhRRI12:
2115 case kMemOp2LdrhRRI12:
2116 case kMemOp2StrRRI12:
2117 case kMemOp2LdrRRI12:
2118 case kMemOp2LdrsbRRI12:
2119 case kMemOp2LdrshRRI12:
2120 offset = imm12;
2121 break;
2122 case kMemOp2Stmia:
2123 case kMemOp2Ldmia:
2124 wBack = false;
2125 case kMemOp2Stmia2:
2126 case kMemOp2Ldmia2:
2127 offset = 0;
2128 break;
2129 default:
2130 LOGE("*** ERROR: UNRECOGNIZED THUMB2 MEM OP: %x", opcode12);
2131 offset = 0;
2132 dvmAbort();
2133 }
2134
2135 // Handle the decoded mem op accordingly
2136 if (store) {
2137 if (size == kSVVariable) {
2138 LOGD("*** THUMB2 STMIA CURRENTLY UNUSED (AND UNTESTED)");
2139 int i;
2140 int regList = insn & 0xFFFF;
2141 for (i = 0; i < 16; i++) {
2142 if (regList & 0x1) {
2143 data = selfVerificationMemRegLoad(sp, i);
2144 selfVerificationStore(addr, data, kSVWord);
2145 addr += 4;
2146 }
2147 regList = regList >> 1;
2148 }
2149 if (wBack) selfVerificationMemRegStore(sp, addr, rn);
2150 } else if (size == kSVDoubleword) {
2151 double_data = selfVerificationMemRegLoadDouble(sp, rt);
2152 selfVerificationStoreDoubleword(addr+offset, double_data);
2153 } else {
2154 data = selfVerificationMemRegLoad(sp, rt);
2155 selfVerificationStore(addr+offset, data, size);
2156 }
2157 } else {
2158 if (size == kSVVariable) {
2159 LOGD("*** THUMB2 LDMIA CURRENTLY UNUSED (AND UNTESTED)");
2160 int i;
2161 int regList = insn & 0xFFFF;
2162 for (i = 0; i < 16; i++) {
2163 if (regList & 0x1) {
2164 data = selfVerificationLoad(addr, kSVWord);
2165 selfVerificationMemRegStore(sp, data, i);
2166 addr += 4;
2167 }
2168 regList = regList >> 1;
2169 }
2170 if (wBack) selfVerificationMemRegStore(sp, addr, rn);
2171 } else if (size == kSVDoubleword) {
2172 double_data = selfVerificationLoadDoubleword(addr+offset);
2173 selfVerificationMemRegStoreDouble(sp, double_data, rt);
2174 } else {
2175 data = selfVerificationLoad(addr+offset, size);
2176 selfVerificationMemRegStore(sp, data, rt);
2177 }
2178 }
2179 } else {
2180 //LOGD("*** THUMB - Addr: %#x Insn: %#x", lr, insn);
2181
2182 // Update the link register
2183 selfVerificationMemRegStore(sp, old_lr+2, 13);
2184
2185 int opcode5 = (insn >> 11) & 0x1F;
2186 int opcode7 = (insn >> 9) & 0x7F;
2187 int imm = (insn >> 6) & 0x1F;
2188 int rd = (insn >> 8) & 0x7;
2189 int rm = (insn >> 6) & 0x7;
2190 int rn = (insn >> 3) & 0x7;
2191 int rt = insn & 0x7;
2192
2193 // Determine whether the mem op is a store or load
2194 switch (opcode5) {
2195 case kMemOpRRR:
2196 switch (opcode7) {
2197 case kMemOpStrRRR:
2198 case kMemOpStrhRRR:
2199 case kMemOpStrbRRR:
2200 store = true;
2201 }
2202 break;
2203 case kMemOpStrRRI5:
2204 case kMemOpStrbRRI5:
2205 case kMemOpStrhRRI5:
2206 case kMemOpStmia:
2207 store = true;
2208 }
2209
2210 // Determine the size of the mem access
2211 switch (opcode5) {
2212 case kMemOpRRR:
2213 case kMemOpRRR2:
2214 switch (opcode7) {
2215 case kMemOpStrbRRR:
2216 case kMemOpLdrbRRR:
2217 size = kSVByte;
2218 break;
2219 case kMemOpLdrsbRRR:
2220 size = kSVSignedByte;
2221 break;
2222 case kMemOpStrhRRR:
2223 case kMemOpLdrhRRR:
2224 size = kSVHalfword;
2225 break;
2226 case kMemOpLdrshRRR:
2227 size = kSVSignedHalfword;
2228 break;
2229 }
2230 break;
2231 case kMemOpStrbRRI5:
2232 case kMemOpLdrbRRI5:
2233 size = kSVByte;
2234 break;
2235 case kMemOpStrhRRI5:
2236 case kMemOpLdrhRRI5:
2237 size = kSVHalfword;
2238 break;
2239 case kMemOpStmia:
2240 case kMemOpLdmia:
2241 size = kSVVariable;
2242 break;
2243 }
2244
2245 // Load the value of the address
2246 if (opcode5 == kMemOpLdrPcRel)
2247 addr = selfVerificationMemRegLoad(sp, 4);
2248 else if (opcode5 == kMemOpStmia || opcode5 == kMemOpLdmia)
2249 addr = selfVerificationMemRegLoad(sp, rd);
2250 else
2251 addr = selfVerificationMemRegLoad(sp, rn);
2252
2253 // Figure out the offset
2254 switch (opcode5) {
2255 case kMemOpLdrPcRel:
2256 offset = (insn & 0xFF) << 2;
2257 rt = rd;
2258 break;
2259 case kMemOpRRR:
2260 case kMemOpRRR2:
2261 offset = selfVerificationMemRegLoad(sp, rm);
2262 break;
2263 case kMemOpStrRRI5:
2264 case kMemOpLdrRRI5:
2265 offset = imm << 2;
2266 break;
2267 case kMemOpStrhRRI5:
2268 case kMemOpLdrhRRI5:
2269 offset = imm << 1;
2270 break;
2271 case kMemOpStrbRRI5:
2272 case kMemOpLdrbRRI5:
2273 offset = imm;
2274 break;
2275 case kMemOpStmia:
2276 case kMemOpLdmia:
2277 offset = 0;
2278 break;
2279 default:
2280 LOGE("*** ERROR: UNRECOGNIZED THUMB MEM OP: %x", opcode5);
2281 offset = 0;
2282 dvmAbort();
2283 }
2284
2285 // Handle the decoded mem op accordingly
2286 if (store) {
2287 if (size == kSVVariable) {
2288 int i;
2289 int regList = insn & 0xFF;
2290 for (i = 0; i < 8; i++) {
2291 if (regList & 0x1) {
2292 data = selfVerificationMemRegLoad(sp, i);
2293 selfVerificationStore(addr, data, kSVWord);
2294 addr += 4;
2295 }
2296 regList = regList >> 1;
2297 }
2298 selfVerificationMemRegStore(sp, addr, rd);
2299 } else {
2300 data = selfVerificationMemRegLoad(sp, rt);
2301 selfVerificationStore(addr+offset, data, size);
2302 }
2303 } else {
2304 if (size == kSVVariable) {
2305 bool wBack = true;
2306 int i;
2307 int regList = insn & 0xFF;
2308 for (i = 0; i < 8; i++) {
2309 if (regList & 0x1) {
2310 if (i == rd) wBack = false;
2311 data = selfVerificationLoad(addr, kSVWord);
2312 selfVerificationMemRegStore(sp, data, i);
2313 addr += 4;
2314 }
2315 regList = regList >> 1;
2316 }
2317 if (wBack) selfVerificationMemRegStore(sp, addr, rd);
2318 } else {
2319 data = selfVerificationLoad(addr+offset, size);
2320 selfVerificationMemRegStore(sp, data, rt);
2321 }
2322 }
2323 }
2324}
2325#endif