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 23 static 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 */ 34 static 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 165 void 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 */ 218 void 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 */ 318 void 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 */ 346 void dvmCompilerCacheFlush(long start, long end, long flags) 347 { 348 cacheflush(start, end, flags); 349 } 350 351 /* Target-specific cache clearing */ 352 void dvmCompilerCacheClear(char *start, size_t size) 353 { 354 /* 0x66 is an invalid opcode for mips. */ 355 memset(start, 0x66, size); 356 } 357