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