ArchUtility.cpp revision fc3b0c4ba9e0ecabb0f6df1ceb6a3eb69da07c7b
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 "MipsLIR.h"
20
21/* For dumping instructions */
22#define MIPS_REG_COUNT 32
23static const char *mipsRegName[MIPS_REG_COUNT] = {
24    "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
25    "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
26    "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
27    "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
28};
29
30/*
31 * Interpret a format string and build a string no longer than size
32 * See format key in Assemble.c.
33 */
34static void buildInsnString(const char *fmt, MipsLIR *lir, char* buf,
35                            unsigned char *baseAddr, int size)
36{
37    int i;
38    char *bufEnd = &buf[size-1];
39    const char *fmtEnd = &fmt[strlen(fmt)];
40    char tbuf[256];
41    char nc;
42    while (fmt < fmtEnd) {
43        int operand;
44        if (*fmt == '!') {
45            fmt++;
46            assert(fmt < fmtEnd);
47            nc = *fmt++;
48            if (nc=='!') {
49                strcpy(tbuf, "!");
50            } else {
51               assert(fmt < fmtEnd);
52               assert((unsigned)(nc-'0') < 4);
53               operand = lir->operands[nc-'0'];
54               switch(*fmt++) {
55                   case 'b':
56                       strcpy(tbuf,"0000");
57                       for (i=3; i>= 0; i--) {
58                           tbuf[i] += operand & 1;
59                           operand >>= 1;
60                       }
61                       break;
62                   case 's':
63                       sprintf(tbuf,"$f%d",operand & FP_REG_MASK);
64                       break;
65                   case 'S':
66		       assert(((operand & FP_REG_MASK) & 1) == 0);
67                       sprintf(tbuf,"$f%d",operand & FP_REG_MASK);
68                       break;
69                   case 'h':
70                       sprintf(tbuf,"%04x", operand);
71                       break;
72                   case 'M':
73                   case 'd':
74                       sprintf(tbuf,"%d", operand);
75                       break;
76                   case 'D':
77                       sprintf(tbuf,"%d", operand+1);
78                       break;
79                   case 'E':
80                       sprintf(tbuf,"%d", operand*4);
81                       break;
82                   case 'F':
83                       sprintf(tbuf,"%d", operand*2);
84                       break;
85                   case 'c':
86                       switch (operand) {
87                           case kMipsCondEq:
88                               strcpy(tbuf, "eq");
89                               break;
90                           case kMipsCondNe:
91                               strcpy(tbuf, "ne");
92                               break;
93                           case kMipsCondLt:
94                               strcpy(tbuf, "lt");
95                               break;
96                           case kMipsCondGe:
97                               strcpy(tbuf, "ge");
98                               break;
99                           case kMipsCondGt:
100                               strcpy(tbuf, "gt");
101                               break;
102                           case kMipsCondLe:
103                               strcpy(tbuf, "le");
104                               break;
105                           case kMipsCondCs:
106                               strcpy(tbuf, "cs");
107                               break;
108                           case kMipsCondMi:
109                               strcpy(tbuf, "mi");
110                               break;
111                           default:
112                               strcpy(tbuf, "");
113                               break;
114                       }
115                       break;
116                   case 't':
117                       sprintf(tbuf,"0x%08x (L%p)",
118                               (int) baseAddr + lir->generic.offset + 4 +
119                               (operand << 2),
120                               lir->generic.target);
121                       break;
122                   case 'T':
123                       sprintf(tbuf,"0x%08x",
124                               (int) (operand << 2));
125                       break;
126                   case 'u': {
127                       int offset_1 = lir->operands[0];
128                       int offset_2 = NEXT_LIR(lir)->operands[0];
129                       intptr_t target =
130                           ((((intptr_t) baseAddr + lir->generic.offset + 4) &
131                            ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
132                           0xfffffffc;
133                       sprintf(tbuf, "%p", (void *) target);
134                       break;
135                    }
136
137                   /* Nothing to print for BLX_2 */
138                   case 'v':
139                       strcpy(tbuf, "see above");
140                       break;
141                   case 'r':
142                       assert(operand >= 0 && operand < MIPS_REG_COUNT);
143                       strcpy(tbuf, mipsRegName[operand]);
144                       break;
145                   default:
146                       strcpy(tbuf,"DecodeError");
147                       break;
148               }
149               if (buf+strlen(tbuf) <= bufEnd) {
150                   strcpy(buf, tbuf);
151                   buf += strlen(tbuf);
152               } else {
153                   break;
154               }
155            }
156        } else {
157           *buf++ = *fmt++;
158        }
159        if (buf == bufEnd)
160            break;
161    }
162    *buf = 0;
163}
164
165void dvmDumpResourceMask(LIR *lir, u8 mask, const char *prefix)
166{
167    char buf[256];
168    buf[0] = 0;
169    MipsLIR *mipsLIR = (MipsLIR *) lir;
170
171    if (mask == ENCODE_ALL) {
172        strcpy(buf, "all");
173    } else {
174        char num[8];
175        int i;
176
177        for (i = 0; i < kRegEnd; i++) {
178            if (mask & (1ULL << i)) {
179                sprintf(num, "%d ", i);
180                strcat(buf, num);
181            }
182        }
183
184        if (mask & ENCODE_CCODE) {
185            strcat(buf, "cc ");
186        }
187        if (mask & ENCODE_FP_STATUS) {
188            strcat(buf, "fpcc ");
189        }
190        /* Memory bits */
191        if (mipsLIR && (mask & ENCODE_DALVIK_REG)) {
192            sprintf(buf + strlen(buf), "dr%d%s", mipsLIR->aliasInfo & 0xffff,
193                    (mipsLIR->aliasInfo & 0x80000000) ? "(+1)" : "");
194        }
195        if (mask & ENCODE_LITERAL) {
196            strcat(buf, "lit ");
197        }
198
199        if (mask & ENCODE_HEAP_REF) {
200            strcat(buf, "heap ");
201        }
202        if (mask & ENCODE_MUST_NOT_ALIAS) {
203            strcat(buf, "noalias ");
204        }
205    }
206    if (buf[0]) {
207        ALOGD("%s: %s", prefix, buf);
208    }
209}
210
211/*
212 * Debugging macros
213 */
214#define DUMP_RESOURCE_MASK(X)
215#define DUMP_SSA_REP(X)
216
217/* Pretty-print a LIR instruction */
218void dvmDumpLIRInsn(LIR *arg, unsigned char *baseAddr)
219{
220    MipsLIR *lir = (MipsLIR *) arg;
221    char buf[256];
222    char opName[256];
223    int offset = lir->generic.offset;
224    int dest = lir->operands[0];
225    const bool dumpNop = false;
226
227    /* Handle pseudo-ops individually, and all regular insns as a group */
228    switch(lir->opcode) {
229        case kMipsChainingCellBottom:
230            ALOGD("-------- end of chaining cells (0x%04x)", offset);
231            break;
232        case kMipsPseudoBarrier:
233            ALOGD("-------- BARRIER");
234            break;
235        case kMipsPseudoExtended:
236            /* intentional fallthrough */
237        case kMipsPseudoSSARep:
238            DUMP_SSA_REP(ALOGD("-------- %s", (char *) dest));
239            break;
240        case kMipsPseudoChainingCellBackwardBranch:
241            ALOGD("L%p:", lir);
242            ALOGD("-------- chaining cell (backward branch): 0x%04x", dest);
243            break;
244        case kMipsPseudoChainingCellNormal:
245            ALOGD("L%p:", lir);
246            ALOGD("-------- chaining cell (normal): 0x%04x", dest);
247            break;
248        case kMipsPseudoChainingCellHot:
249            ALOGD("L%p:", lir);
250            ALOGD("-------- chaining cell (hot): 0x%04x", dest);
251            break;
252        case kMipsPseudoChainingCellInvokePredicted:
253            ALOGD("L%p:", lir);
254            ALOGD("-------- chaining cell (predicted): %s%s",
255                 dest ? ((Method *) dest)->clazz->descriptor : "",
256                 dest ? ((Method *) dest)->name : "N/A");
257            break;
258        case kMipsPseudoChainingCellInvokeSingleton:
259            ALOGD("L%p:", lir);
260            ALOGD("-------- chaining cell (invoke singleton): %s%s/%p",
261                 ((Method *)dest)->clazz->descriptor,
262                 ((Method *)dest)->name,
263                 ((Method *)dest)->insns);
264            break;
265        case kMipsPseudoEntryBlock:
266            ALOGD("-------- entry offset: 0x%04x", dest);
267            break;
268        case kMipsPseudoDalvikByteCodeBoundary:
269            ALOGD("-------- dalvik offset: 0x%04x @ %s", dest,
270                 (char *) lir->operands[1]);
271            break;
272        case kMipsPseudoExitBlock:
273            ALOGD("-------- exit offset: 0x%04x", dest);
274            break;
275        case kMipsPseudoPseudoAlign4:
276            ALOGD("%p (%04x): .align4", baseAddr + offset, offset);
277            break;
278        case kMipsPseudoPCReconstructionCell:
279            ALOGD("L%p:", lir);
280            ALOGD("-------- reconstruct dalvik PC : 0x%04x @ +0x%04x", dest,
281                 lir->operands[1]);
282            break;
283        case kMipsPseudoPCReconstructionBlockLabel:
284            /* Do nothing */
285            break;
286        case kMipsPseudoEHBlockLabel:
287            ALOGD("Exception_Handling:");
288            break;
289        case kMipsPseudoTargetLabel:
290        case kMipsPseudoNormalBlockLabel:
291            ALOGD("L%p:", lir);
292            break;
293        default:
294            if (lir->flags.isNop && !dumpNop) {
295                break;
296            }
297            buildInsnString(EncodingMap[lir->opcode].name, lir, opName,
298                            baseAddr, 256);
299            buildInsnString(EncodingMap[lir->opcode].fmt, lir, buf, baseAddr,
300                            256);
301            ALOGD("%p (%04x): %08x %-9s%s%s",
302                 baseAddr + offset, offset, *(u4 *)(baseAddr + offset), opName, buf,
303                 lir->flags.isNop ? "(nop)" : "");
304            break;
305    }
306
307    if (lir->useMask && (!lir->flags.isNop || dumpNop)) {
308        DUMP_RESOURCE_MASK(dvmDumpResourceMask((LIR *) lir,
309                                               lir->useMask, "use"));
310    }
311    if (lir->defMask && (!lir->flags.isNop || dumpNop)) {
312        DUMP_RESOURCE_MASK(dvmDumpResourceMask((LIR *) lir,
313                                               lir->defMask, "def"));
314    }
315}
316
317/* Dump instructions and constant pool contents */
318void dvmCompilerCodegenDump(CompilationUnit *cUnit)
319{
320    ALOGD("Dumping LIR insns");
321    LIR *lirInsn;
322    MipsLIR *mipsLIR;
323
324    ALOGD("installed code is at %p", cUnit->baseAddr);
325    ALOGD("total size is %d bytes", cUnit->totalSize);
326    for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) {
327        dvmDumpLIRInsn(lirInsn, (unsigned char *) cUnit->baseAddr);
328    }
329    for (lirInsn = cUnit->classPointerList; lirInsn; lirInsn = lirInsn->next) {
330        mipsLIR = (MipsLIR *) lirInsn;
331        ALOGD("%p (%04x): .class (%s)",
332             (char*)cUnit->baseAddr + mipsLIR->generic.offset,
333             mipsLIR->generic.offset,
334             ((CallsiteInfo *) mipsLIR->operands[0])->classDescriptor);
335    }
336    for (lirInsn = cUnit->literalList; lirInsn; lirInsn = lirInsn->next) {
337        mipsLIR = (MipsLIR *) lirInsn;
338        ALOGD("%p (%04x): .word (%#x)",
339             (char*)cUnit->baseAddr + mipsLIR->generic.offset,
340             mipsLIR->generic.offset,
341             mipsLIR->operands[0]);
342    }
343}
344
345/* Target-specific cache flushing */
346void dvmCompilerCacheFlush(long start, long end, long flags)
347{
348    cacheflush(start, end, flags);
349}
350
351/* Target-specific cache clearing */
352void dvmCompilerCacheClear(char *start, size_t size)
353{
354    /* 0x66 is an invalid opcode for mips. */
355    memset(start, 0x66, size);
356}
357