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