blob: 6c31cfe5b3f2ae54aa34c77751894f6e261d51d2 [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 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 "CompilerInternals.h"
19#include "Dataflow.h"
buzbeec143c552011-08-20 17:38:58 -070020#include "constants.h"
buzbee67bf8852011-08-17 17:51:35 -070021
22static inline bool contentIsInsn(const u2* codePtr) {
23 u2 instr = *codePtr;
24 Opcode opcode = (Opcode)(instr & 0xff);
25
26 /*
27 * Since the low 8-bit in metadata may look like OP_NOP, we need to check
28 * both the low and whole sub-word to determine whether it is code or data.
29 */
30 return (opcode != OP_NOP || instr == 0);
31}
32
33/*
34 * Parse an instruction, return the length of the instruction
35 */
36static inline int parseInsn(const u2* codePtr, DecodedInstruction* decInsn,
37 bool printMe)
38{
39 // Don't parse instruction data
40 if (!contentIsInsn(codePtr)) {
41 return 0;
42 }
43
44 u2 instr = *codePtr;
45 Opcode opcode = dexOpcodeFromCodeUnit(instr);
46
47 dexDecodeInstruction(codePtr, decInsn);
48 if (printMe) {
49 char *decodedString = oatGetDalvikDisassembly(decInsn, NULL);
50 LOG(INFO) << codePtr << ": 0x" << std::hex << (int)opcode <<
51 " " << decodedString;
52 }
53 return dexGetWidthFromOpcode(opcode);
54}
55
56#define UNKNOWN_TARGET 0xffffffff
57
58static inline bool isGoto(MIR* insn)
59{
60 switch (insn->dalvikInsn.opcode) {
61 case OP_GOTO:
62 case OP_GOTO_16:
63 case OP_GOTO_32:
64 return true;
65 default:
66 return false;
67 }
68}
69
70/*
71 * Identify unconditional branch instructions
72 */
73static inline bool isUnconditionalBranch(MIR* insn)
74{
75 switch (insn->dalvikInsn.opcode) {
76 case OP_RETURN_VOID:
77 case OP_RETURN:
78 case OP_RETURN_WIDE:
79 case OP_RETURN_OBJECT:
80 return true;
81 default:
82 return isGoto(insn);
83 }
84}
85
86/* Split an existing block from the specified code offset into two */
87static BasicBlock *splitBlock(CompilationUnit* cUnit,
88 unsigned int codeOffset,
89 BasicBlock* origBlock)
90{
91 MIR* insn = origBlock->firstMIRInsn;
92 while (insn) {
93 if (insn->offset == codeOffset) break;
94 insn = insn->next;
95 }
96 if (insn == NULL) {
97 LOG(FATAL) << "Break split failed";
98 }
99 BasicBlock *bottomBlock = oatNewBB(kDalvikByteCode,
100 cUnit->numBlocks++);
101 oatInsertGrowableList(&cUnit->blockList, (intptr_t) bottomBlock);
102
103 bottomBlock->startOffset = codeOffset;
104 bottomBlock->firstMIRInsn = insn;
105 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
106
107 /* Handle the taken path */
108 bottomBlock->taken = origBlock->taken;
109 if (bottomBlock->taken) {
110 origBlock->taken = NULL;
111 oatClearBit(bottomBlock->taken->predecessors, origBlock->id);
112 oatSetBit(bottomBlock->taken->predecessors, bottomBlock->id);
113 }
114
115 /* Handle the fallthrough path */
116 bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
117 bottomBlock->fallThrough = origBlock->fallThrough;
118 origBlock->fallThrough = bottomBlock;
119 origBlock->needFallThroughBranch = true;
120 oatSetBit(bottomBlock->predecessors, origBlock->id);
121 if (bottomBlock->fallThrough) {
122 oatClearBit(bottomBlock->fallThrough->predecessors,
123 origBlock->id);
124 oatSetBit(bottomBlock->fallThrough->predecessors,
125 bottomBlock->id);
126 }
127
128 /* Handle the successor list */
129 if (origBlock->successorBlockList.blockListType != kNotUsed) {
130 bottomBlock->successorBlockList = origBlock->successorBlockList;
131 origBlock->successorBlockList.blockListType = kNotUsed;
132 GrowableListIterator iterator;
133
134 oatGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
135 &iterator);
136 while (true) {
137 SuccessorBlockInfo *successorBlockInfo =
138 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
139 if (successorBlockInfo == NULL) break;
140 BasicBlock *bb = successorBlockInfo->block;
141 oatClearBit(bb->predecessors, origBlock->id);
142 oatSetBit(bb->predecessors, bottomBlock->id);
143 }
144 }
145
146 origBlock->lastMIRInsn = insn->prev;
147
148 insn->prev->next = NULL;
149 insn->prev = NULL;
150 return bottomBlock;
151}
152
153/*
154 * Given a code offset, find out the block that starts with it. If the offset
155 * is in the middle of an existing block, split it into two.
156 */
157static BasicBlock *findBlock(CompilationUnit* cUnit,
158 unsigned int codeOffset,
159 bool split, bool create)
160{
161 GrowableList* blockList = &cUnit->blockList;
162 BasicBlock* bb;
163 unsigned int i;
164
165 for (i = 0; i < blockList->numUsed; i++) {
166 bb = (BasicBlock *) blockList->elemList[i];
167 if (bb->blockType != kDalvikByteCode) continue;
168 if (bb->startOffset == codeOffset) return bb;
169 /* Check if a branch jumps into the middle of an existing block */
170 if ((split == true) && (codeOffset > bb->startOffset) &&
171 (bb->lastMIRInsn != NULL) &&
172 (codeOffset <= bb->lastMIRInsn->offset)) {
173 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb);
174 return newBB;
175 }
176 }
177 if (create) {
178 bb = oatNewBB(kDalvikByteCode, cUnit->numBlocks++);
179 oatInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
180 bb->startOffset = codeOffset;
181 return bb;
182 }
183 return NULL;
184}
185
186/* Dump the CFG into a DOT graph */
187void oatDumpCFG(CompilationUnit* cUnit, const char* dirPrefix)
188{
buzbee67bf8852011-08-17 17:51:35 -0700189 FILE* file;
buzbeedfd3d702011-08-28 12:56:51 -0700190 std::string name = art::PrettyMethod(cUnit->method);
buzbee67bf8852011-08-17 17:51:35 -0700191 char startOffset[80];
192 sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
193 char* fileName = (char *) oatNew(
buzbeec143c552011-08-20 17:38:58 -0700194 strlen(dirPrefix) +
195 name.length() +
196 strlen(".dot") + 1, true);
197 sprintf(fileName, "%s%s%s.dot", dirPrefix, name.c_str(), startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700198
199 /*
200 * Convert the special characters into a filesystem- and shell-friendly
201 * format.
202 */
203 int i;
204 for (i = strlen(dirPrefix); fileName[i]; i++) {
205 if (fileName[i] == '/') {
206 fileName[i] = '_';
207 } else if (fileName[i] == ';') {
208 fileName[i] = '#';
209 } else if (fileName[i] == '$') {
210 fileName[i] = '+';
211 } else if (fileName[i] == '(' || fileName[i] == ')') {
212 fileName[i] = '@';
213 } else if (fileName[i] == '<' || fileName[i] == '>') {
214 fileName[i] = '=';
215 }
216 }
217 file = fopen(fileName, "w");
218 if (file == NULL) {
219 return;
220 }
221 fprintf(file, "digraph G {\n");
222
223 fprintf(file, " rankdir=TB\n");
224
225 int numReachableBlocks = cUnit->numReachableBlocks;
226 int idx;
227 const GrowableList *blockList = &cUnit->blockList;
228
229 for (idx = 0; idx < numReachableBlocks; idx++) {
230 int blockIdx = cUnit->dfsOrder.elemList[idx];
231 BasicBlock *bb = (BasicBlock *) oatGrowableListGetElement(blockList,
232 blockIdx);
233 if (bb == NULL) break;
234 if (bb->blockType == kEntryBlock) {
235 fprintf(file, " entry [shape=Mdiamond];\n");
236 } else if (bb->blockType == kExitBlock) {
237 fprintf(file, " exit [shape=Mdiamond];\n");
238 } else if (bb->blockType == kDalvikByteCode) {
239 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
240 bb->startOffset);
241 const MIR *mir;
242 fprintf(file, " {block id %d\\l}%s\\\n", bb->id,
243 bb->firstMIRInsn ? " | " : " ");
244 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
245 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
246 mir->ssaRep ?
247 oatFullDisassembler(cUnit, mir) :
248 dexGetOpcodeName(mir->dalvikInsn.opcode),
249 mir->next ? " | " : " ");
250 }
251 fprintf(file, " }\"];\n\n");
252 } else if (bb->blockType == kExceptionHandling) {
253 char blockName[BLOCK_NAME_LEN];
254
255 oatGetBlockName(bb, blockName);
256 fprintf(file, " %s [shape=invhouse];\n", blockName);
257 }
258
259 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
260
261 if (bb->taken) {
262 oatGetBlockName(bb, blockName1);
263 oatGetBlockName(bb->taken, blockName2);
264 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
265 blockName1, blockName2);
266 }
267 if (bb->fallThrough) {
268 oatGetBlockName(bb, blockName1);
269 oatGetBlockName(bb->fallThrough, blockName2);
270 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
271 }
272
273 if (bb->successorBlockList.blockListType != kNotUsed) {
274 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
275 bb->startOffset,
276 (bb->successorBlockList.blockListType == kCatch) ?
277 "Mrecord" : "record");
278 GrowableListIterator iterator;
279 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
280 &iterator);
281 SuccessorBlockInfo *successorBlockInfo =
282 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
283
284 int succId = 0;
285 while (true) {
286 if (successorBlockInfo == NULL) break;
287
288 BasicBlock *destBlock = successorBlockInfo->block;
289 SuccessorBlockInfo *nextSuccessorBlockInfo =
290 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
291
292 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
293 succId++,
294 successorBlockInfo->key,
295 destBlock->startOffset,
296 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
297
298 successorBlockInfo = nextSuccessorBlockInfo;
299 }
300 fprintf(file, " }\"];\n\n");
301
302 oatGetBlockName(bb, blockName1);
303 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
304 blockName1, bb->startOffset);
305
306 if (bb->successorBlockList.blockListType == kPackedSwitch ||
307 bb->successorBlockList.blockListType == kSparseSwitch) {
308
309 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
310 &iterator);
311
312 succId = 0;
313 while (true) {
314 SuccessorBlockInfo *successorBlockInfo =
315 (SuccessorBlockInfo *)
316 oatGrowableListIteratorNext(&iterator);
317 if (successorBlockInfo == NULL) break;
318
319 BasicBlock *destBlock = successorBlockInfo->block;
320
321 oatGetBlockName(destBlock, blockName2);
322 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
323 bb->startOffset, succId++,
324 blockName2);
325 }
326 }
327 }
328 fprintf(file, "\n");
329
330 /*
331 * If we need to debug the dominator tree, uncomment the following code
332 */
333#if 1
334 oatGetBlockName(bb, blockName1);
335 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
336 blockName1, blockName1);
337 if (bb->iDom) {
338 oatGetBlockName(bb->iDom, blockName2);
339 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
340 blockName2, blockName1);
341 }
342#endif
343 }
344 fprintf(file, "}\n");
345 fclose(file);
346}
347
348/* Verify if all the successor is connected with all the claimed predecessors */
349static bool verifyPredInfo(CompilationUnit* cUnit, BasicBlock* bb)
350{
351 ArenaBitVectorIterator bvIterator;
352
353 oatBitVectorIteratorInit(bb->predecessors, &bvIterator);
354 while (true) {
355 int blockIdx = oatBitVectorIteratorNext(&bvIterator);
356 if (blockIdx == -1) break;
357 BasicBlock *predBB = (BasicBlock *)
358 oatGrowableListGetElement(&cUnit->blockList, blockIdx);
359 bool found = false;
360 if (predBB->taken == bb) {
361 found = true;
362 } else if (predBB->fallThrough == bb) {
363 found = true;
364 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
365 GrowableListIterator iterator;
366 oatGrowableListIteratorInit(&predBB->successorBlockList.blocks,
367 &iterator);
368 while (true) {
369 SuccessorBlockInfo *successorBlockInfo =
370 (SuccessorBlockInfo *)
371 oatGrowableListIteratorNext(&iterator);
372 if (successorBlockInfo == NULL) break;
373 BasicBlock *succBB = successorBlockInfo->block;
374 if (succBB == bb) {
375 found = true;
376 break;
377 }
378 }
379 }
380 if (found == false) {
381 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
382 oatGetBlockName(bb, blockName1);
383 oatGetBlockName(predBB, blockName2);
384 oatDumpCFG(cUnit, "/sdcard/cfg/");
385 LOG(FATAL) << "Successor " << blockName1 << "not found from "
386 << blockName2;
387 }
388 }
389 return true;
390}
391
392/* Identify code range in try blocks and set up the empty catch blocks */
393static void processTryCatchBlocks(CompilationUnit* cUnit)
394{
buzbeec143c552011-08-20 17:38:58 -0700395
396 UNIMPLEMENTED(WARNING) << "Need to finish processTryCatchBlocks()";
397#if 0
buzbee67bf8852011-08-17 17:51:35 -0700398 const Method* meth = cUnit->method;
399 const DexCode *pCode = dvmGetMethodCode(meth);
400 int triesSize = pCode->triesSize;
401 int i;
402 int offset;
403
404 if (triesSize == 0) {
405 return;
406 }
407
408 const DexTry* pTries = dexGetTries(pCode);
409 ArenaBitVector* tryBlockAddr = cUnit->tryBlockAddr;
410
411 /* Mark all the insn offsets in Try blocks */
412 for (i = 0; i < triesSize; i++) {
413 const DexTry* pTry = &pTries[i];
414 /* all in 16-bit units */
415 int startOffset = pTry->startAddr;
416 int endOffset = startOffset + pTry->insnCount;
417
418 for (offset = startOffset; offset < endOffset; offset++) {
419 oatSetBit(tryBlockAddr, offset);
420 }
421 }
422
423 /* Iterate over each of the handlers to enqueue the empty Catch blocks */
424 offset = dexGetFirstHandlerOffset(pCode);
425 int handlersSize = dexGetHandlersSize(pCode);
426
427 for (i = 0; i < handlersSize; i++) {
428 DexCatchIterator iterator;
429 dexCatchIteratorInit(&iterator, pCode, offset);
430
431 for (;;) {
432 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
433
434 if (handler == NULL) {
435 break;
436 }
437
438 /*
439 * Create dummy catch blocks first. Since these are created before
440 * other blocks are processed, "split" is specified as false.
441 */
442 findBlock(cUnit, handler->address,
443 /* split */
444 false,
445 /* create */
446 true);
447 }
448
449 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
450 }
buzbeec143c552011-08-20 17:38:58 -0700451#endif
buzbee67bf8852011-08-17 17:51:35 -0700452}
453
454/* Process instructions with the kInstrCanBranch flag */
455static void processCanBranch(CompilationUnit* cUnit, BasicBlock* curBlock,
456 MIR* insn, int curOffset, int width, int flags,
457 const u2* codePtr, const u2* codeEnd)
458{
459 int target = curOffset;
460 switch (insn->dalvikInsn.opcode) {
461 case OP_GOTO:
462 case OP_GOTO_16:
463 case OP_GOTO_32:
464 target += (int) insn->dalvikInsn.vA;
465 break;
466 case OP_IF_EQ:
467 case OP_IF_NE:
468 case OP_IF_LT:
469 case OP_IF_GE:
470 case OP_IF_GT:
471 case OP_IF_LE:
472 target += (int) insn->dalvikInsn.vC;
473 break;
474 case OP_IF_EQZ:
475 case OP_IF_NEZ:
476 case OP_IF_LTZ:
477 case OP_IF_GEZ:
478 case OP_IF_GTZ:
479 case OP_IF_LEZ:
480 target += (int) insn->dalvikInsn.vB;
481 break;
482 default:
483 LOG(FATAL) << "Unexpected opcode(" << (int)insn->dalvikInsn.opcode
484 << ") with kInstrCanBranch set";
485 }
486 BasicBlock *takenBlock = findBlock(cUnit, target,
487 /* split */
488 true,
489 /* create */
490 true);
491 curBlock->taken = takenBlock;
492 oatSetBit(takenBlock->predecessors, curBlock->id);
493
494 /* Always terminate the current block for conditional branches */
495 if (flags & kInstrCanContinue) {
496 BasicBlock *fallthroughBlock = findBlock(cUnit,
497 curOffset + width,
498 /*
499 * If the method is processed
500 * in sequential order from the
501 * beginning, we don't need to
502 * specify split for continue
503 * blocks. However, this
504 * routine can be called by
505 * compileLoop, which starts
506 * parsing the method from an
507 * arbitrary address in the
508 * method body.
509 */
510 true,
511 /* create */
512 true);
513 curBlock->fallThrough = fallthroughBlock;
514 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
515 } else if (codePtr < codeEnd) {
516 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
517 if (contentIsInsn(codePtr)) {
518 findBlock(cUnit, curOffset + width,
519 /* split */
520 false,
521 /* create */
522 true);
523 }
524 }
525}
526
527/* Process instructions with the kInstrCanSwitch flag */
528static void processCanSwitch(CompilationUnit* cUnit, BasicBlock* curBlock,
529 MIR* insn, int curOffset, int width, int flags)
530{
531 u2* switchData= (u2 *) (cUnit->insns + curOffset +
532 insn->dalvikInsn.vB);
533 int size;
534 int* keyTable;
535 int* targetTable;
536 int i;
537 int firstKey;
538
539 /*
540 * Packed switch data format:
541 * ushort ident = 0x0100 magic value
542 * ushort size number of entries in the table
543 * int first_key first (and lowest) switch case value
544 * int targets[size] branch targets, relative to switch opcode
545 *
546 * Total size is (4+size*2) 16-bit code units.
547 */
548 if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
549 assert(switchData[0] == kPackedSwitchSignature);
550 size = switchData[1];
551 firstKey = switchData[2] | (switchData[3] << 16);
552 targetTable = (int *) &switchData[4];
553 keyTable = NULL; // Make the compiler happy
554 /*
555 * Sparse switch data format:
556 * ushort ident = 0x0200 magic value
557 * ushort size number of entries in the table; > 0
558 * int keys[size] keys, sorted low-to-high; 32-bit aligned
559 * int targets[size] branch targets, relative to switch opcode
560 *
561 * Total size is (2+size*4) 16-bit code units.
562 */
563 } else {
564 assert(switchData[0] == kSparseSwitchSignature);
565 size = switchData[1];
566 keyTable = (int *) &switchData[2];
567 targetTable = (int *) &switchData[2 + size*2];
568 firstKey = 0; // To make the compiler happy
569 }
570
571 if (curBlock->successorBlockList.blockListType != kNotUsed) {
572 LOG(FATAL) << "Successor block list already in use: " <<
573 (int)curBlock->successorBlockList.blockListType;
574 }
575 curBlock->successorBlockList.blockListType =
576 (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
577 kPackedSwitch : kSparseSwitch;
578 oatInitGrowableList(&curBlock->successorBlockList.blocks, size);
579
580 for (i = 0; i < size; i++) {
581 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
582 /* split */
583 true,
584 /* create */
585 true);
586 SuccessorBlockInfo *successorBlockInfo =
587 (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
588 false);
589 successorBlockInfo->block = caseBlock;
590 successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)?
591 firstKey + i : keyTable[i];
592 oatInsertGrowableList(&curBlock->successorBlockList.blocks,
593 (intptr_t) successorBlockInfo);
594 oatSetBit(caseBlock->predecessors, curBlock->id);
595 }
596
597 /* Fall-through case */
598 BasicBlock* fallthroughBlock = findBlock(cUnit,
599 curOffset + width,
600 /* split */
601 false,
602 /* create */
603 true);
604 curBlock->fallThrough = fallthroughBlock;
605 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
606}
607
608/* Process instructions with the kInstrCanThrow flag */
609static void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock,
610 MIR* insn, int curOffset, int width, int flags,
611 ArenaBitVector* tryBlockAddr, const u2* codePtr,
612 const u2* codeEnd)
613{
buzbeec143c552011-08-20 17:38:58 -0700614 UNIMPLEMENTED(WARNING) << "Need to complete processCanThrow";
615#if 0
buzbee67bf8852011-08-17 17:51:35 -0700616 const Method* method = cUnit->method;
617 const DexCode* dexCode = dvmGetMethodCode(method);
618
619 /* In try block */
620 if (oatIsBitSet(tryBlockAddr, curOffset)) {
621 DexCatchIterator iterator;
622
623 if (!dexFindCatchHandler(&iterator, dexCode, curOffset)) {
624 LOG(FATAL) << "Catch block not found in dexfile for insn " <<
625 curOffset << " in " << method->name;
626
627 }
628 if (curBlock->successorBlockList.blockListType != kNotUsed) {
629 LOG(FATAL) << "Successor block list already in use: " <<
630 (int)curBlock->successorBlockList.blockListType;
631 }
632 curBlock->successorBlockList.blockListType = kCatch;
633 oatInitGrowableList(&curBlock->successorBlockList.blocks, 2);
634
635 for (;;) {
636 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
637
638 if (handler == NULL) {
639 break;
640 }
641
642 BasicBlock *catchBlock = findBlock(cUnit, handler->address,
643 /* split */
644 false,
645 /* create */
646 false);
647
648 SuccessorBlockInfo *successorBlockInfo =
649 (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
650 false);
651 successorBlockInfo->block = catchBlock;
652 successorBlockInfo->key = handler->typeIdx;
653 oatInsertGrowableList(&curBlock->successorBlockList.blocks,
654 (intptr_t) successorBlockInfo);
655 oatSetBit(catchBlock->predecessors, curBlock->id);
656 }
657 } else {
658 BasicBlock *ehBlock = oatNewBB(kExceptionHandling,
659 cUnit->numBlocks++);
660 curBlock->taken = ehBlock;
661 oatInsertGrowableList(&cUnit->blockList, (intptr_t) ehBlock);
662 ehBlock->startOffset = curOffset;
663 oatSetBit(ehBlock->predecessors, curBlock->id);
664 }
665
666 /*
667 * Force the current block to terminate.
668 *
669 * Data may be present before codeEnd, so we need to parse it to know
670 * whether it is code or data.
671 */
672 if (codePtr < codeEnd) {
673 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
674 if (contentIsInsn(codePtr)) {
675 BasicBlock *fallthroughBlock = findBlock(cUnit,
676 curOffset + width,
677 /* split */
678 false,
679 /* create */
680 true);
681 /*
682 * OP_THROW and OP_THROW_VERIFICATION_ERROR are unconditional
683 * branches.
684 */
685 if (insn->dalvikInsn.opcode != OP_THROW_VERIFICATION_ERROR &&
686 insn->dalvikInsn.opcode != OP_THROW) {
687 curBlock->fallThrough = fallthroughBlock;
688 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
689 }
690 }
691 }
buzbeec143c552011-08-20 17:38:58 -0700692#endif
buzbee67bf8852011-08-17 17:51:35 -0700693}
694
695/*
696 * Compile a method.
697 */
buzbeec143c552011-08-20 17:38:58 -0700698bool oatCompileMethod(Method* method, art::InstructionSet insnSet)
buzbee67bf8852011-08-17 17:51:35 -0700699{
buzbee439c4fa2011-08-27 15:59:07 -0700700 bool compiling = true;
701 if (!method->IsStatic()) {
buzbeedfd3d702011-08-28 12:56:51 -0700702 compiling = false; // assume skip
703 if (PrettyMethod(method).find("virtualCall") != std::string::npos) {
704 compiling = true;
705 }
buzbeedd3efae2011-08-28 14:39:07 -0700706 if (PrettyMethod(method).find("getFoo") != std::string::npos) {
707 compiling = true;
708 }
709 if (PrettyMethod(method).find("setFoo") != std::string::npos) {
710 compiling = true;
711 }
buzbeedfd3d702011-08-28 12:56:51 -0700712 if (PrettyMethod(method).find("IntMath.<init>") != std::string::npos) {
713 compiling = true;
714 }
715 if (PrettyMethod(method).find("java.lang.Object.<init>") != std::string::npos) {
716 compiling = true;
717 }
buzbee439c4fa2011-08-27 15:59:07 -0700718 } else if ( (method->GetName()->ToModifiedUtf8().find("foo") != std::string::npos) ||
Brian Carlstrombffb1552011-08-25 12:23:53 -0700719 (method->GetName()->ToModifiedUtf8().find("main") != std::string::npos)) {
buzbee439c4fa2011-08-27 15:59:07 -0700720 compiling = false;
721 }
722
723 if (compiling) {
buzbeedfd3d702011-08-28 12:56:51 -0700724 LOG(INFO) << "Compiling " << PrettyMethod(method);
buzbee439c4fa2011-08-27 15:59:07 -0700725 } else {
buzbeedfd3d702011-08-28 12:56:51 -0700726 LOG(INFO) << "not compiling " << PrettyMethod(method);
Brian Carlstrom94496d32011-08-22 09:22:47 -0700727 return false;
728 }
729
buzbee67bf8852011-08-17 17:51:35 -0700730 CompilationUnit cUnit;
buzbeec143c552011-08-20 17:38:58 -0700731 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
732 const art::DexFile& dex_file = class_linker->FindDexFile(
733 method->GetDeclaringClass()->GetDexCache());
734 const art::DexFile::CodeItem* code_item =
735 dex_file.GetCodeItem(method->code_off_);
736 const u2* codePtr = code_item->insns_;
737 const u2* codeEnd = code_item->insns_ + code_item->insns_size_;
buzbee67bf8852011-08-17 17:51:35 -0700738 int numBlocks = 0;
739 unsigned int curOffset = 0;
740
741#if 1
742 // FIXME - temp 'till properly integrated
743 oatInit();
744#endif
745
746 memset(&cUnit, 0, sizeof(cUnit));
747 cUnit.method = method;
buzbeec143c552011-08-20 17:38:58 -0700748 cUnit.instructionSet = (OatInstructionSetType)insnSet;
749 cUnit.insns = code_item->insns_;
750 cUnit.insnsSize = code_item->insns_size_;
buzbee67bf8852011-08-17 17:51:35 -0700751#if 1
buzbee3ea4ec52011-08-22 17:37:19 -0700752 // TODO: Use command-line argument passing mechanism
buzbee67bf8852011-08-17 17:51:35 -0700753 cUnit.printMe = true;
754 cUnit.printMeVerbose = true;
buzbee3ea4ec52011-08-22 17:37:19 -0700755 cUnit.disableOpt = 0 |
756 (1 << kLoadStoreElimination) |
757 (1 << kLoadHoisting) |
758 (1 << kTrackLiveTemps) |
759 (1 << kSuppressLoads) |
760 (1 << kPromoteRegs) |
761 0;
buzbee67bf8852011-08-17 17:51:35 -0700762#endif
763
764 /* Initialize the block list */
765 oatInitGrowableList(&cUnit.blockList, 40);
766
767 /* Initialize the switchTables list */
768 oatInitGrowableList(&cUnit.switchTables, 4);
769
770 /* Intialize the fillArrayData list */
771 oatInitGrowableList(&cUnit.fillArrayData, 4);
772
773 /* Allocate the bit-vector to track the beginning of basic blocks */
774 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit.insnsSize,
775 true /* expandable */);
776 cUnit.tryBlockAddr = tryBlockAddr;
777
778 /* Create the default entry and exit blocks and enter them to the list */
779 BasicBlock *entryBlock = oatNewBB(kEntryBlock, numBlocks++);
780 BasicBlock *exitBlock = oatNewBB(kExitBlock, numBlocks++);
781
782 cUnit.entryBlock = entryBlock;
783 cUnit.exitBlock = exitBlock;
784
785 oatInsertGrowableList(&cUnit.blockList, (intptr_t) entryBlock);
786 oatInsertGrowableList(&cUnit.blockList, (intptr_t) exitBlock);
787
788 /* Current block to record parsed instructions */
789 BasicBlock *curBlock = oatNewBB(kDalvikByteCode, numBlocks++);
790 curBlock->startOffset = 0;
791 oatInsertGrowableList(&cUnit.blockList, (intptr_t) curBlock);
792 entryBlock->fallThrough = curBlock;
793 oatSetBit(curBlock->predecessors, entryBlock->id);
794
795 /*
796 * Store back the number of blocks since new blocks may be created of
797 * accessing cUnit.
798 */
799 cUnit.numBlocks = numBlocks;
800
801 /* Identify code range in try blocks and set up the empty catch blocks */
802 processTryCatchBlocks(&cUnit);
803
804 /* Parse all instructions and put them into containing basic blocks */
805 while (codePtr < codeEnd) {
806 MIR *insn = (MIR *) oatNew(sizeof(MIR), true);
807 insn->offset = curOffset;
808 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
809 insn->width = width;
810
811 /* Terminate when the data section is seen */
812 if (width == 0)
813 break;
814
815 oatAppendMIR(curBlock, insn);
816
817 codePtr += width;
818 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
819
820 if (flags & kInstrCanBranch) {
821 processCanBranch(&cUnit, curBlock, insn, curOffset, width, flags,
822 codePtr, codeEnd);
823 } else if (flags & kInstrCanReturn) {
824 curBlock->fallThrough = exitBlock;
825 oatSetBit(exitBlock->predecessors, curBlock->id);
826 /*
827 * Terminate the current block if there are instructions
828 * afterwards.
829 */
830 if (codePtr < codeEnd) {
831 /*
832 * Create a fallthrough block for real instructions
833 * (incl. OP_NOP).
834 */
835 if (contentIsInsn(codePtr)) {
836 findBlock(&cUnit, curOffset + width,
837 /* split */
838 false,
839 /* create */
840 true);
841 }
842 }
843 } else if (flags & kInstrCanThrow) {
844 processCanThrow(&cUnit, curBlock, insn, curOffset, width, flags,
845 tryBlockAddr, codePtr, codeEnd);
846 } else if (flags & kInstrCanSwitch) {
847 processCanSwitch(&cUnit, curBlock, insn, curOffset, width, flags);
848 }
849 curOffset += width;
850 BasicBlock *nextBlock = findBlock(&cUnit, curOffset,
851 /* split */
852 false,
853 /* create */
854 false);
855 if (nextBlock) {
856 /*
857 * The next instruction could be the target of a previously parsed
858 * forward branch so a block is already created. If the current
859 * instruction is not an unconditional branch, connect them through
860 * the fall-through link.
861 */
862 assert(curBlock->fallThrough == NULL ||
863 curBlock->fallThrough == nextBlock ||
864 curBlock->fallThrough == exitBlock);
865
866 if ((curBlock->fallThrough == NULL) &&
867 (flags & kInstrCanContinue)) {
868 curBlock->fallThrough = nextBlock;
869 oatSetBit(nextBlock->predecessors, curBlock->id);
870 }
871 curBlock = nextBlock;
872 }
873 }
874
875 if (cUnit.printMe) {
876 oatDumpCompilationUnit(&cUnit);
877 }
878
879 /* Adjust this value accordingly once inlining is performed */
buzbeec143c552011-08-20 17:38:58 -0700880 cUnit.numDalvikRegisters = cUnit.method->num_registers_;
buzbee67bf8852011-08-17 17:51:35 -0700881
882
883 /* Verify if all blocks are connected as claimed */
884 oatDataFlowAnalysisDispatcher(&cUnit, verifyPredInfo,
885 kAllNodes,
886 false /* isIterative */);
887
888
889
890 /* Perform SSA transformation for the whole method */
891 oatMethodSSATransformation(&cUnit);
892
893 oatInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
894
895 /* Allocate Registers using simple local allocation scheme */
896 oatSimpleRegAlloc(&cUnit);
897
898 /* Convert MIR to LIR, etc. */
899 oatMethodMIR2LIR(&cUnit);
900
901 // Debugging only
902 //oatDumpCFG(&cUnit, "/sdcard/cfg/");
903
904 /* Method is not empty */
905 if (cUnit.firstLIRInsn) {
906
907 // mark the targets of switch statement case labels
908 oatProcessSwitchTables(&cUnit);
909
910 /* Convert LIR into machine code. */
911 oatAssembleLIR(&cUnit);
912
913 if (cUnit.printMe) {
914 oatCodegenDump(&cUnit);
915 }
916 }
917
buzbeec143c552011-08-20 17:38:58 -0700918 method->SetCode((const art::byte*)&cUnit.codeBuffer[0],
919 cUnit.codeBuffer.size() * 2, art::kThumb2);
Shih-wei Liaod11af152011-08-23 16:02:11 -0700920 method->SetFrameSizeInBytes(cUnit.frameSize);
buzbeec143c552011-08-20 17:38:58 -0700921 method->SetCoreSpillMask(cUnit.coreSpillMask);
922 method->SetFpSpillMask(cUnit.fpSpillMask);
923 // TODO: Transmit mapping table to caller
buzbee67bf8852011-08-17 17:51:35 -0700924
925#if 0
926 oatDumpCFG(&cUnit, "/sdcard/cfg/");
927#endif
928
Brian Carlstrombffb1552011-08-25 12:23:53 -0700929 return true;
buzbee67bf8852011-08-17 17:51:35 -0700930}
931
932void oatInit(void)
933{
934#if 1
935 // FIXME - temp hack 'till properly integrated
936 static bool initialized = false;
937 if (initialized)
938 return;
939 initialized = true;
940 LOG(INFO) << "Initializing compiler";
941#endif
942 if (!oatArchInit()) {
943 LOG(FATAL) << "Failed to initialize oat";
944 }
945 if (!oatHeapInit()) {
946 LOG(FATAL) << "Failed to initialize oat heap";
947 }
948}