1 /*
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 "../../CompilerInternals.h"
18 #include "libdex/DexOpcodes.h"
19 #include "ArmLIR.h"
20
21 static const char *shiftNames[4] = {
22 "lsl",
23 "lsr",
24 "asr",
25 "ror"};
26
27 /* Decode and print a ARM register name */
decodeRegList(ArmOpcode opcode,int vector,char * buf)28 static char * decodeRegList(ArmOpcode opcode, int vector, char *buf)
29 {
30 int i;
31 bool printed = false;
32 buf[0] = 0;
33 for (i = 0; i < 16; i++, vector >>= 1) {
34 if (vector & 0x1) {
35 int regId = i;
36 if (opcode == kThumbPush && i == 8) {
37 regId = r14lr;
38 } else if (opcode == kThumbPop && i == 8) {
39 regId = r15pc;
40 }
41 if (printed) {
42 sprintf(buf + strlen(buf), ", r%d", regId);
43 } else {
44 printed = true;
45 sprintf(buf, "r%d", regId);
46 }
47 }
48 }
49 return buf;
50 }
51
expandImmediate(int value)52 static int expandImmediate(int value)
53 {
54 int mode = (value & 0xf00) >> 8;
55 u4 bits = value & 0xff;
56 switch(mode) {
57 case 0:
58 return bits;
59 case 1:
60 return (bits << 16) | bits;
61 case 2:
62 return (bits << 24) | (bits << 8);
63 case 3:
64 return (bits << 24) | (bits << 16) | (bits << 8) | bits;
65 default:
66 break;
67 }
68 bits = (bits | 0x80) << 24;
69 return bits >> (((value & 0xf80) >> 7) - 8);
70 }
71
72 /*
73 * Interpret a format string and build a string no longer than size
74 * See format key in Assemble.c.
75 */
buildInsnString(const char * fmt,ArmLIR * lir,char * buf,unsigned char * baseAddr,int size)76 static void buildInsnString(const char *fmt, ArmLIR *lir, char* buf,
77 unsigned char *baseAddr, int size)
78 {
79 int i;
80 char *bufEnd = &buf[size-1];
81 const char *fmtEnd = &fmt[strlen(fmt)];
82 char tbuf[256];
83 const char *name;
84 char nc;
85 while (fmt < fmtEnd) {
86 int operand;
87 if (*fmt == '!') {
88 fmt++;
89 assert(fmt < fmtEnd);
90 nc = *fmt++;
91 if (nc=='!') {
92 strcpy(tbuf, "!");
93 } else {
94 assert(fmt < fmtEnd);
95 assert((unsigned)(nc-'0') < 4);
96 operand = lir->operands[nc-'0'];
97 switch(*fmt++) {
98 case 'H':
99 if (operand != 0) {
100 sprintf(tbuf, ", %s %d",shiftNames[operand & 0x3],
101 operand >> 2);
102 } else {
103 strcpy(tbuf,"");
104 }
105 break;
106 case 'B':
107 switch (operand) {
108 case kSY:
109 name = "sy";
110 break;
111 case kST:
112 name = "st";
113 break;
114 case kISH:
115 name = "ish";
116 break;
117 case kISHST:
118 name = "ishst";
119 break;
120 case kNSH:
121 name = "nsh";
122 break;
123 case kNSHST:
124 name = "shst";
125 break;
126 default:
127 name = "DecodeError";
128 break;
129 }
130 strcpy(tbuf, name);
131 break;
132 case 'b':
133 strcpy(tbuf,"0000");
134 for (i=3; i>= 0; i--) {
135 tbuf[i] += operand & 1;
136 operand >>= 1;
137 }
138 break;
139 case 'n':
140 operand = ~expandImmediate(operand);
141 sprintf(tbuf,"%d [%#x]", operand, operand);
142 break;
143 case 'm':
144 operand = expandImmediate(operand);
145 sprintf(tbuf,"%d [%#x]", operand, operand);
146 break;
147 case 's':
148 sprintf(tbuf,"s%d",operand & FP_REG_MASK);
149 break;
150 case 'S':
151 sprintf(tbuf,"d%d",(operand & FP_REG_MASK) >> 1);
152 break;
153 case 'h':
154 sprintf(tbuf,"%04x", operand);
155 break;
156 case 'M':
157 case 'd':
158 sprintf(tbuf,"%d", operand);
159 break;
160 case 'E':
161 sprintf(tbuf,"%d", operand*4);
162 break;
163 case 'F':
164 sprintf(tbuf,"%d", operand*2);
165 break;
166 case 'c':
167 switch (operand) {
168 case kArmCondEq:
169 strcpy(tbuf, "eq");
170 break;
171 case kArmCondNe:
172 strcpy(tbuf, "ne");
173 break;
174 case kArmCondLt:
175 strcpy(tbuf, "lt");
176 break;
177 case kArmCondGe:
178 strcpy(tbuf, "ge");
179 break;
180 case kArmCondGt:
181 strcpy(tbuf, "gt");
182 break;
183 case kArmCondLe:
184 strcpy(tbuf, "le");
185 break;
186 case kArmCondCs:
187 strcpy(tbuf, "cs");
188 break;
189 case kArmCondMi:
190 strcpy(tbuf, "mi");
191 break;
192 default:
193 strcpy(tbuf, "");
194 break;
195 }
196 break;
197 case 't':
198 sprintf(tbuf,"0x%08x (L%p)",
199 (int) baseAddr + lir->generic.offset + 4 +
200 (operand << 1),
201 lir->generic.target);
202 break;
203 case 'u': {
204 int offset_1 = lir->operands[0];
205 int offset_2 = NEXT_LIR(lir)->operands[0];
206 intptr_t target =
207 ((((intptr_t) baseAddr + lir->generic.offset + 4) &
208 ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
209 0xfffffffc;
210 sprintf(tbuf, "%p", (void *) target);
211 break;
212 }
213
214 /* Nothing to print for BLX_2 */
215 case 'v':
216 strcpy(tbuf, "see above");
217 break;
218 case 'R':
219 decodeRegList(lir->opcode, operand, tbuf);
220 break;
221 default:
222 strcpy(tbuf,"DecodeError");
223 break;
224 }
225 if (buf+strlen(tbuf) <= bufEnd) {
226 strcpy(buf, tbuf);
227 buf += strlen(tbuf);
228 } else {
229 break;
230 }
231 }
232 } else {
233 *buf++ = *fmt++;
234 }
235 if (buf == bufEnd)
236 break;
237 }
238 *buf = 0;
239 }
240
dvmDumpResourceMask(LIR * lir,u8 mask,const char * prefix)241 void dvmDumpResourceMask(LIR *lir, u8 mask, const char *prefix)
242 {
243 char buf[256];
244 buf[0] = 0;
245 ArmLIR *armLIR = (ArmLIR *) lir;
246
247 if (mask == ENCODE_ALL) {
248 strcpy(buf, "all");
249 } else {
250 char num[8];
251 int i;
252
253 for (i = 0; i < kRegEnd; i++) {
254 if (mask & (1ULL << i)) {
255 sprintf(num, "%d ", i);
256 strcat(buf, num);
257 }
258 }
259
260 if (mask & ENCODE_CCODE) {
261 strcat(buf, "cc ");
262 }
263 if (mask & ENCODE_FP_STATUS) {
264 strcat(buf, "fpcc ");
265 }
266
267 /* Memory bits */
268 if (armLIR && (mask & ENCODE_DALVIK_REG)) {
269 sprintf(buf + strlen(buf), "dr%d%s", armLIR->aliasInfo & 0xffff,
270 (armLIR->aliasInfo & 0x80000000) ? "(+1)" : "");
271 }
272 if (mask & ENCODE_LITERAL) {
273 strcat(buf, "lit ");
274 }
275
276 if (mask & ENCODE_HEAP_REF) {
277 strcat(buf, "heap ");
278 }
279 if (mask & ENCODE_MUST_NOT_ALIAS) {
280 strcat(buf, "noalias ");
281 }
282 }
283 if (buf[0]) {
284 ALOGD("%s: %s", prefix, buf);
285 }
286 }
287
288 /*
289 * Debugging macros
290 */
291 #define DUMP_RESOURCE_MASK(X)
292 #define DUMP_SSA_REP(X)
293
294 /* Pretty-print a LIR instruction */
dvmDumpLIRInsn(LIR * arg,unsigned char * baseAddr)295 void dvmDumpLIRInsn(LIR *arg, unsigned char *baseAddr)
296 {
297 ArmLIR *lir = (ArmLIR *) arg;
298 char buf[256];
299 char opName[256];
300 int offset = lir->generic.offset;
301 int dest = lir->operands[0];
302 const bool dumpNop = false;
303
304 /* Handle pseudo-ops individually, and all regular insns as a group */
305 switch(lir->opcode) {
306 case kArmChainingCellBottom:
307 ALOGD("-------- end of chaining cells (0x%04x)", offset);
308 break;
309 case kArmPseudoBarrier:
310 ALOGD("-------- BARRIER");
311 break;
312 case kArmPseudoExtended:
313 ALOGD("-------- %s", (char *) dest);
314 break;
315 case kArmPseudoSSARep:
316 DUMP_SSA_REP(LOGD("-------- %s", (char *) dest));
317 break;
318 case kArmPseudoChainingCellBackwardBranch:
319 ALOGD("L%p:", lir);
320 ALOGD("-------- chaining cell (backward branch): 0x%04x", dest);
321 break;
322 case kArmPseudoChainingCellNormal:
323 ALOGD("L%p:", lir);
324 ALOGD("-------- chaining cell (normal): 0x%04x", dest);
325 break;
326 case kArmPseudoChainingCellHot:
327 ALOGD("L%p:", lir);
328 ALOGD("-------- chaining cell (hot): 0x%04x", dest);
329 break;
330 case kArmPseudoChainingCellInvokePredicted:
331 ALOGD("L%p:", lir);
332 ALOGD("-------- chaining cell (predicted): %s%s",
333 dest ? ((Method *) dest)->clazz->descriptor : "",
334 dest ? ((Method *) dest)->name : "N/A");
335 break;
336 case kArmPseudoChainingCellInvokeSingleton:
337 ALOGD("L%p:", lir);
338 ALOGD("-------- chaining cell (invoke singleton): %s%s/%p",
339 ((Method *)dest)->clazz->descriptor,
340 ((Method *)dest)->name,
341 ((Method *)dest)->insns);
342 break;
343 case kArmPseudoEntryBlock:
344 ALOGD("-------- entry offset: 0x%04x", dest);
345 break;
346 case kArmPseudoDalvikByteCodeBoundary:
347 ALOGD("-------- dalvik offset: 0x%04x @ %s", dest,
348 (char *) lir->operands[1]);
349 break;
350 case kArmPseudoExitBlock:
351 ALOGD("-------- exit offset: 0x%04x", dest);
352 break;
353 case kArmPseudoPseudoAlign4:
354 ALOGD("%p (%04x): .align4", baseAddr + offset, offset);
355 break;
356 case kArmPseudoPCReconstructionCell:
357 ALOGD("L%p:", lir);
358 ALOGD("-------- reconstruct dalvik PC : 0x%04x @ +0x%04x", dest,
359 lir->operands[1]);
360 break;
361 case kArmPseudoPCReconstructionBlockLabel:
362 /* Do nothing */
363 break;
364 case kArmPseudoEHBlockLabel:
365 ALOGD("Exception_Handling:");
366 break;
367 case kArmPseudoTargetLabel:
368 case kArmPseudoNormalBlockLabel:
369 ALOGD("L%p:", lir);
370 break;
371 default:
372 if (lir->flags.isNop && !dumpNop) {
373 break;
374 }
375 buildInsnString(EncodingMap[lir->opcode].name, lir, opName,
376 baseAddr, 256);
377 buildInsnString(EncodingMap[lir->opcode].fmt, lir, buf, baseAddr,
378 256);
379 ALOGD("%p (%04x): %-8s%s%s",
380 baseAddr + offset, offset, opName, buf,
381 lir->flags.isNop ? "(nop)" : "");
382 break;
383 }
384
385 if (lir->useMask && (!lir->flags.isNop || dumpNop)) {
386 DUMP_RESOURCE_MASK(dvmDumpResourceMask((LIR *) lir,
387 lir->useMask, "use"));
388 }
389 if (lir->defMask && (!lir->flags.isNop || dumpNop)) {
390 DUMP_RESOURCE_MASK(dvmDumpResourceMask((LIR *) lir,
391 lir->defMask, "def"));
392 }
393 }
394
395 /* Dump instructions and constant pool contents */
dvmCompilerCodegenDump(CompilationUnit * cUnit)396 void dvmCompilerCodegenDump(CompilationUnit *cUnit)
397 {
398 ALOGD("Dumping LIR insns");
399 LIR *lirInsn;
400 ArmLIR *armLIR;
401
402 ALOGD("installed code is at %p", cUnit->baseAddr);
403 ALOGD("total size is %d bytes", cUnit->totalSize);
404 for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) {
405 dvmDumpLIRInsn(lirInsn, (unsigned char *) cUnit->baseAddr);
406 }
407 for (lirInsn = cUnit->classPointerList; lirInsn; lirInsn = lirInsn->next) {
408 armLIR = (ArmLIR *) lirInsn;
409 ALOGD("%p (%04x): .class (%s)",
410 (char*)cUnit->baseAddr + armLIR->generic.offset,
411 armLIR->generic.offset,
412 ((CallsiteInfo *) armLIR->operands[0])->classDescriptor);
413 }
414 for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) {
415 armLIR = (ArmLIR *) lirInsn;
416 ALOGD("%p (%04x): .word (%#x)",
417 (char*)cUnit->baseAddr + armLIR->generic.offset,
418 armLIR->generic.offset,
419 armLIR->operands[0]);
420 }
421 }
422
423 /* Target-specific cache flushing */
dvmCompilerCacheFlush(long start,long end,long flags)424 void dvmCompilerCacheFlush(long start, long end, long flags)
425 {
426 cacheflush(start, end, flags);
427 }
428
429 /* Target-specific cache clearing */
dvmCompilerCacheClear(char * start,size_t size)430 void dvmCompilerCacheClear(char *start, size_t size)
431 {
432 /*
433 * de is an invalid opcode for arm.
434 * From gdb disassembly: <UNDEFINED> instruction: 0xdede
435 */
436
437 memset(start, 0xde, size);
438 }
439