ArchUtility.cpp revision 60497bbcee68d98b2bdcb3fb64682b00d61b942d
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
21static const char *shiftNames[4] = {
22    "lsl",
23    "lsr",
24    "asr",
25    "ror"};
26
27/* Decode and print a ARM register name */
28static 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
52static 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 */
76static 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
241void 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 */
295void 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 */
396void 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 */
424void dvmCompilerCacheFlush(long start, long end, long flags)
425{
426    cacheflush(start, end, flags);
427}
428
429/* Target-specific cache clearing */
430void 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