blob: 9ef2b4fe5160d7b5f45bedc5133e84783651e2b8 [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"
Brian Carlstrom1f870082011-08-23 16:02:11 -070021#include "runtime.h"
buzbee67bf8852011-08-17 17:51:35 -070022
23static inline bool contentIsInsn(const u2* codePtr) {
24 u2 instr = *codePtr;
25 Opcode opcode = (Opcode)(instr & 0xff);
26
27 /*
28 * Since the low 8-bit in metadata may look like OP_NOP, we need to check
29 * both the low and whole sub-word to determine whether it is code or data.
30 */
31 return (opcode != OP_NOP || instr == 0);
32}
33
34/*
35 * Parse an instruction, return the length of the instruction
36 */
37static inline int parseInsn(const u2* codePtr, DecodedInstruction* decInsn,
38 bool printMe)
39{
40 // Don't parse instruction data
41 if (!contentIsInsn(codePtr)) {
42 return 0;
43 }
44
45 u2 instr = *codePtr;
46 Opcode opcode = dexOpcodeFromCodeUnit(instr);
47
48 dexDecodeInstruction(codePtr, decInsn);
49 if (printMe) {
50 char *decodedString = oatGetDalvikDisassembly(decInsn, NULL);
51 LOG(INFO) << codePtr << ": 0x" << std::hex << (int)opcode <<
52 " " << decodedString;
53 }
54 return dexGetWidthFromOpcode(opcode);
55}
56
57#define UNKNOWN_TARGET 0xffffffff
58
59static inline bool isGoto(MIR* insn)
60{
61 switch (insn->dalvikInsn.opcode) {
62 case OP_GOTO:
63 case OP_GOTO_16:
64 case OP_GOTO_32:
65 return true;
66 default:
67 return false;
68 }
69}
70
71/*
72 * Identify unconditional branch instructions
73 */
74static inline bool isUnconditionalBranch(MIR* insn)
75{
76 switch (insn->dalvikInsn.opcode) {
77 case OP_RETURN_VOID:
78 case OP_RETURN:
79 case OP_RETURN_WIDE:
80 case OP_RETURN_OBJECT:
81 return true;
82 default:
83 return isGoto(insn);
84 }
85}
86
87/* Split an existing block from the specified code offset into two */
88static BasicBlock *splitBlock(CompilationUnit* cUnit,
89 unsigned int codeOffset,
90 BasicBlock* origBlock)
91{
92 MIR* insn = origBlock->firstMIRInsn;
93 while (insn) {
94 if (insn->offset == codeOffset) break;
95 insn = insn->next;
96 }
97 if (insn == NULL) {
98 LOG(FATAL) << "Break split failed";
99 }
100 BasicBlock *bottomBlock = oatNewBB(kDalvikByteCode,
101 cUnit->numBlocks++);
102 oatInsertGrowableList(&cUnit->blockList, (intptr_t) bottomBlock);
103
104 bottomBlock->startOffset = codeOffset;
105 bottomBlock->firstMIRInsn = insn;
106 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
107
108 /* Handle the taken path */
109 bottomBlock->taken = origBlock->taken;
110 if (bottomBlock->taken) {
111 origBlock->taken = NULL;
112 oatClearBit(bottomBlock->taken->predecessors, origBlock->id);
113 oatSetBit(bottomBlock->taken->predecessors, bottomBlock->id);
114 }
115
116 /* Handle the fallthrough path */
117 bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
118 bottomBlock->fallThrough = origBlock->fallThrough;
119 origBlock->fallThrough = bottomBlock;
120 origBlock->needFallThroughBranch = true;
121 oatSetBit(bottomBlock->predecessors, origBlock->id);
122 if (bottomBlock->fallThrough) {
123 oatClearBit(bottomBlock->fallThrough->predecessors,
124 origBlock->id);
125 oatSetBit(bottomBlock->fallThrough->predecessors,
126 bottomBlock->id);
127 }
128
129 /* Handle the successor list */
130 if (origBlock->successorBlockList.blockListType != kNotUsed) {
131 bottomBlock->successorBlockList = origBlock->successorBlockList;
132 origBlock->successorBlockList.blockListType = kNotUsed;
133 GrowableListIterator iterator;
134
135 oatGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
136 &iterator);
137 while (true) {
138 SuccessorBlockInfo *successorBlockInfo =
139 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
140 if (successorBlockInfo == NULL) break;
141 BasicBlock *bb = successorBlockInfo->block;
142 oatClearBit(bb->predecessors, origBlock->id);
143 oatSetBit(bb->predecessors, bottomBlock->id);
144 }
145 }
146
147 origBlock->lastMIRInsn = insn->prev;
148
149 insn->prev->next = NULL;
150 insn->prev = NULL;
151 return bottomBlock;
152}
153
154/*
155 * Given a code offset, find out the block that starts with it. If the offset
156 * is in the middle of an existing block, split it into two.
157 */
158static BasicBlock *findBlock(CompilationUnit* cUnit,
159 unsigned int codeOffset,
160 bool split, bool create)
161{
162 GrowableList* blockList = &cUnit->blockList;
163 BasicBlock* bb;
164 unsigned int i;
165
166 for (i = 0; i < blockList->numUsed; i++) {
167 bb = (BasicBlock *) blockList->elemList[i];
168 if (bb->blockType != kDalvikByteCode) continue;
169 if (bb->startOffset == codeOffset) return bb;
170 /* Check if a branch jumps into the middle of an existing block */
171 if ((split == true) && (codeOffset > bb->startOffset) &&
172 (bb->lastMIRInsn != NULL) &&
173 (codeOffset <= bb->lastMIRInsn->offset)) {
174 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb);
175 return newBB;
176 }
177 }
178 if (create) {
179 bb = oatNewBB(kDalvikByteCode, cUnit->numBlocks++);
180 oatInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
181 bb->startOffset = codeOffset;
182 return bb;
183 }
184 return NULL;
185}
186
187/* Dump the CFG into a DOT graph */
188void oatDumpCFG(CompilationUnit* cUnit, const char* dirPrefix)
189{
buzbee67bf8852011-08-17 17:51:35 -0700190 FILE* file;
buzbeedfd3d702011-08-28 12:56:51 -0700191 std::string name = art::PrettyMethod(cUnit->method);
buzbee67bf8852011-08-17 17:51:35 -0700192 char startOffset[80];
193 sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
194 char* fileName = (char *) oatNew(
buzbeec143c552011-08-20 17:38:58 -0700195 strlen(dirPrefix) +
196 name.length() +
197 strlen(".dot") + 1, true);
198 sprintf(fileName, "%s%s%s.dot", dirPrefix, name.c_str(), startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700199
200 /*
201 * Convert the special characters into a filesystem- and shell-friendly
202 * format.
203 */
204 int i;
205 for (i = strlen(dirPrefix); fileName[i]; i++) {
206 if (fileName[i] == '/') {
207 fileName[i] = '_';
208 } else if (fileName[i] == ';') {
209 fileName[i] = '#';
210 } else if (fileName[i] == '$') {
211 fileName[i] = '+';
212 } else if (fileName[i] == '(' || fileName[i] == ')') {
213 fileName[i] = '@';
214 } else if (fileName[i] == '<' || fileName[i] == '>') {
215 fileName[i] = '=';
216 }
217 }
218 file = fopen(fileName, "w");
219 if (file == NULL) {
220 return;
221 }
222 fprintf(file, "digraph G {\n");
223
224 fprintf(file, " rankdir=TB\n");
225
226 int numReachableBlocks = cUnit->numReachableBlocks;
227 int idx;
228 const GrowableList *blockList = &cUnit->blockList;
229
230 for (idx = 0; idx < numReachableBlocks; idx++) {
231 int blockIdx = cUnit->dfsOrder.elemList[idx];
232 BasicBlock *bb = (BasicBlock *) oatGrowableListGetElement(blockList,
233 blockIdx);
234 if (bb == NULL) break;
235 if (bb->blockType == kEntryBlock) {
236 fprintf(file, " entry [shape=Mdiamond];\n");
237 } else if (bb->blockType == kExitBlock) {
238 fprintf(file, " exit [shape=Mdiamond];\n");
239 } else if (bb->blockType == kDalvikByteCode) {
240 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
241 bb->startOffset);
242 const MIR *mir;
243 fprintf(file, " {block id %d\\l}%s\\\n", bb->id,
244 bb->firstMIRInsn ? " | " : " ");
245 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
246 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
247 mir->ssaRep ?
248 oatFullDisassembler(cUnit, mir) :
249 dexGetOpcodeName(mir->dalvikInsn.opcode),
250 mir->next ? " | " : " ");
251 }
252 fprintf(file, " }\"];\n\n");
253 } else if (bb->blockType == kExceptionHandling) {
254 char blockName[BLOCK_NAME_LEN];
255
256 oatGetBlockName(bb, blockName);
257 fprintf(file, " %s [shape=invhouse];\n", blockName);
258 }
259
260 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
261
262 if (bb->taken) {
263 oatGetBlockName(bb, blockName1);
264 oatGetBlockName(bb->taken, blockName2);
265 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
266 blockName1, blockName2);
267 }
268 if (bb->fallThrough) {
269 oatGetBlockName(bb, blockName1);
270 oatGetBlockName(bb->fallThrough, blockName2);
271 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
272 }
273
274 if (bb->successorBlockList.blockListType != kNotUsed) {
275 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
276 bb->startOffset,
277 (bb->successorBlockList.blockListType == kCatch) ?
278 "Mrecord" : "record");
279 GrowableListIterator iterator;
280 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
281 &iterator);
282 SuccessorBlockInfo *successorBlockInfo =
283 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
284
285 int succId = 0;
286 while (true) {
287 if (successorBlockInfo == NULL) break;
288
289 BasicBlock *destBlock = successorBlockInfo->block;
290 SuccessorBlockInfo *nextSuccessorBlockInfo =
291 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
292
293 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
294 succId++,
295 successorBlockInfo->key,
296 destBlock->startOffset,
297 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
298
299 successorBlockInfo = nextSuccessorBlockInfo;
300 }
301 fprintf(file, " }\"];\n\n");
302
303 oatGetBlockName(bb, blockName1);
304 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
305 blockName1, bb->startOffset);
306
307 if (bb->successorBlockList.blockListType == kPackedSwitch ||
308 bb->successorBlockList.blockListType == kSparseSwitch) {
309
310 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
311 &iterator);
312
313 succId = 0;
314 while (true) {
315 SuccessorBlockInfo *successorBlockInfo =
316 (SuccessorBlockInfo *)
317 oatGrowableListIteratorNext(&iterator);
318 if (successorBlockInfo == NULL) break;
319
320 BasicBlock *destBlock = successorBlockInfo->block;
321
322 oatGetBlockName(destBlock, blockName2);
323 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
324 bb->startOffset, succId++,
325 blockName2);
326 }
327 }
328 }
329 fprintf(file, "\n");
330
331 /*
332 * If we need to debug the dominator tree, uncomment the following code
333 */
334#if 1
335 oatGetBlockName(bb, blockName1);
336 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
337 blockName1, blockName1);
338 if (bb->iDom) {
339 oatGetBlockName(bb->iDom, blockName2);
340 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
341 blockName2, blockName1);
342 }
343#endif
344 }
345 fprintf(file, "}\n");
346 fclose(file);
347}
348
349/* Verify if all the successor is connected with all the claimed predecessors */
350static bool verifyPredInfo(CompilationUnit* cUnit, BasicBlock* bb)
351{
352 ArenaBitVectorIterator bvIterator;
353
354 oatBitVectorIteratorInit(bb->predecessors, &bvIterator);
355 while (true) {
356 int blockIdx = oatBitVectorIteratorNext(&bvIterator);
357 if (blockIdx == -1) break;
358 BasicBlock *predBB = (BasicBlock *)
359 oatGrowableListGetElement(&cUnit->blockList, blockIdx);
360 bool found = false;
361 if (predBB->taken == bb) {
362 found = true;
363 } else if (predBB->fallThrough == bb) {
364 found = true;
365 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
366 GrowableListIterator iterator;
367 oatGrowableListIteratorInit(&predBB->successorBlockList.blocks,
368 &iterator);
369 while (true) {
370 SuccessorBlockInfo *successorBlockInfo =
371 (SuccessorBlockInfo *)
372 oatGrowableListIteratorNext(&iterator);
373 if (successorBlockInfo == NULL) break;
374 BasicBlock *succBB = successorBlockInfo->block;
375 if (succBB == bb) {
376 found = true;
377 break;
378 }
379 }
380 }
381 if (found == false) {
382 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
383 oatGetBlockName(bb, blockName1);
384 oatGetBlockName(predBB, blockName2);
385 oatDumpCFG(cUnit, "/sdcard/cfg/");
386 LOG(FATAL) << "Successor " << blockName1 << "not found from "
387 << blockName2;
388 }
389 }
390 return true;
391}
392
393/* Identify code range in try blocks and set up the empty catch blocks */
394static void processTryCatchBlocks(CompilationUnit* cUnit)
395{
buzbeec143c552011-08-20 17:38:58 -0700396
397 UNIMPLEMENTED(WARNING) << "Need to finish processTryCatchBlocks()";
398#if 0
buzbee67bf8852011-08-17 17:51:35 -0700399 const Method* meth = cUnit->method;
400 const DexCode *pCode = dvmGetMethodCode(meth);
401 int triesSize = pCode->triesSize;
402 int i;
403 int offset;
404
405 if (triesSize == 0) {
406 return;
407 }
408
409 const DexTry* pTries = dexGetTries(pCode);
410 ArenaBitVector* tryBlockAddr = cUnit->tryBlockAddr;
411
412 /* Mark all the insn offsets in Try blocks */
413 for (i = 0; i < triesSize; i++) {
414 const DexTry* pTry = &pTries[i];
415 /* all in 16-bit units */
416 int startOffset = pTry->startAddr;
417 int endOffset = startOffset + pTry->insnCount;
418
419 for (offset = startOffset; offset < endOffset; offset++) {
420 oatSetBit(tryBlockAddr, offset);
421 }
422 }
423
424 /* Iterate over each of the handlers to enqueue the empty Catch blocks */
425 offset = dexGetFirstHandlerOffset(pCode);
426 int handlersSize = dexGetHandlersSize(pCode);
427
428 for (i = 0; i < handlersSize; i++) {
429 DexCatchIterator iterator;
430 dexCatchIteratorInit(&iterator, pCode, offset);
431
432 for (;;) {
433 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
434
435 if (handler == NULL) {
436 break;
437 }
438
439 /*
440 * Create dummy catch blocks first. Since these are created before
441 * other blocks are processed, "split" is specified as false.
442 */
443 findBlock(cUnit, handler->address,
444 /* split */
445 false,
446 /* create */
447 true);
448 }
449
450 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
451 }
buzbeec143c552011-08-20 17:38:58 -0700452#endif
buzbee67bf8852011-08-17 17:51:35 -0700453}
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{
buzbeec143c552011-08-20 17:38:58 -0700615 UNIMPLEMENTED(WARNING) << "Need to complete processCanThrow";
616#if 0
buzbee67bf8852011-08-17 17:51:35 -0700617 const Method* method = cUnit->method;
618 const DexCode* dexCode = dvmGetMethodCode(method);
619
620 /* In try block */
621 if (oatIsBitSet(tryBlockAddr, curOffset)) {
622 DexCatchIterator iterator;
623
624 if (!dexFindCatchHandler(&iterator, dexCode, curOffset)) {
625 LOG(FATAL) << "Catch block not found in dexfile for insn " <<
626 curOffset << " in " << method->name;
627
628 }
629 if (curBlock->successorBlockList.blockListType != kNotUsed) {
630 LOG(FATAL) << "Successor block list already in use: " <<
631 (int)curBlock->successorBlockList.blockListType;
632 }
633 curBlock->successorBlockList.blockListType = kCatch;
634 oatInitGrowableList(&curBlock->successorBlockList.blocks, 2);
635
636 for (;;) {
637 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
638
639 if (handler == NULL) {
640 break;
641 }
642
643 BasicBlock *catchBlock = findBlock(cUnit, handler->address,
644 /* split */
645 false,
646 /* create */
647 false);
648
649 SuccessorBlockInfo *successorBlockInfo =
650 (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
651 false);
652 successorBlockInfo->block = catchBlock;
653 successorBlockInfo->key = handler->typeIdx;
654 oatInsertGrowableList(&curBlock->successorBlockList.blocks,
655 (intptr_t) successorBlockInfo);
656 oatSetBit(catchBlock->predecessors, curBlock->id);
657 }
658 } else {
659 BasicBlock *ehBlock = oatNewBB(kExceptionHandling,
660 cUnit->numBlocks++);
661 curBlock->taken = ehBlock;
662 oatInsertGrowableList(&cUnit->blockList, (intptr_t) ehBlock);
663 ehBlock->startOffset = curOffset;
664 oatSetBit(ehBlock->predecessors, curBlock->id);
665 }
666
667 /*
668 * Force the current block to terminate.
669 *
670 * Data may be present before codeEnd, so we need to parse it to know
671 * whether it is code or data.
672 */
673 if (codePtr < codeEnd) {
674 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
675 if (contentIsInsn(codePtr)) {
676 BasicBlock *fallthroughBlock = findBlock(cUnit,
677 curOffset + width,
678 /* split */
679 false,
680 /* create */
681 true);
682 /*
683 * OP_THROW and OP_THROW_VERIFICATION_ERROR are unconditional
684 * branches.
685 */
686 if (insn->dalvikInsn.opcode != OP_THROW_VERIFICATION_ERROR &&
687 insn->dalvikInsn.opcode != OP_THROW) {
688 curBlock->fallThrough = fallthroughBlock;
689 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
690 }
691 }
692 }
buzbeec143c552011-08-20 17:38:58 -0700693#endif
buzbee67bf8852011-08-17 17:51:35 -0700694}
695
696/*
697 * Compile a method.
698 */
buzbeec143c552011-08-20 17:38:58 -0700699bool oatCompileMethod(Method* method, art::InstructionSet insnSet)
buzbee67bf8852011-08-17 17:51:35 -0700700{
buzbee439c4fa2011-08-27 15:59:07 -0700701 bool compiling = true;
702 if (!method->IsStatic()) {
buzbeedfd3d702011-08-28 12:56:51 -0700703 compiling = false; // assume skip
704 if (PrettyMethod(method).find("virtualCall") != std::string::npos) {
705 compiling = true;
706 }
buzbeedd3efae2011-08-28 14:39:07 -0700707 if (PrettyMethod(method).find("getFoo") != std::string::npos) {
708 compiling = true;
709 }
710 if (PrettyMethod(method).find("setFoo") != std::string::npos) {
711 compiling = true;
712 }
buzbeedfd3d702011-08-28 12:56:51 -0700713 if (PrettyMethod(method).find("IntMath.<init>") != std::string::npos) {
714 compiling = true;
715 }
716 if (PrettyMethod(method).find("java.lang.Object.<init>") != std::string::npos) {
717 compiling = true;
718 }
buzbee439c4fa2011-08-27 15:59:07 -0700719 } else if ( (method->GetName()->ToModifiedUtf8().find("foo") != std::string::npos) ||
Brian Carlstrombffb1552011-08-25 12:23:53 -0700720 (method->GetName()->ToModifiedUtf8().find("main") != std::string::npos)) {
buzbee439c4fa2011-08-27 15:59:07 -0700721 compiling = false;
722 }
723
724 if (compiling) {
buzbeedfd3d702011-08-28 12:56:51 -0700725 LOG(INFO) << "Compiling " << PrettyMethod(method);
buzbee439c4fa2011-08-27 15:59:07 -0700726 } else {
buzbeedfd3d702011-08-28 12:56:51 -0700727 LOG(INFO) << "not compiling " << PrettyMethod(method);
Brian Carlstrom94496d32011-08-22 09:22:47 -0700728 return false;
729 }
730
buzbee67bf8852011-08-17 17:51:35 -0700731 CompilationUnit cUnit;
buzbeec143c552011-08-20 17:38:58 -0700732 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
733 const art::DexFile& dex_file = class_linker->FindDexFile(
734 method->GetDeclaringClass()->GetDexCache());
735 const art::DexFile::CodeItem* code_item =
736 dex_file.GetCodeItem(method->code_off_);
737 const u2* codePtr = code_item->insns_;
738 const u2* codeEnd = code_item->insns_ + code_item->insns_size_;
buzbee67bf8852011-08-17 17:51:35 -0700739 int numBlocks = 0;
740 unsigned int curOffset = 0;
741
742#if 1
743 // FIXME - temp 'till properly integrated
744 oatInit();
745#endif
746
747 memset(&cUnit, 0, sizeof(cUnit));
748 cUnit.method = method;
buzbeec143c552011-08-20 17:38:58 -0700749 cUnit.instructionSet = (OatInstructionSetType)insnSet;
750 cUnit.insns = code_item->insns_;
751 cUnit.insnsSize = code_item->insns_size_;
buzbee67bf8852011-08-17 17:51:35 -0700752#if 1
buzbee3ea4ec52011-08-22 17:37:19 -0700753 // TODO: Use command-line argument passing mechanism
buzbee67bf8852011-08-17 17:51:35 -0700754 cUnit.printMe = true;
755 cUnit.printMeVerbose = true;
buzbee3ea4ec52011-08-22 17:37:19 -0700756 cUnit.disableOpt = 0 |
757 (1 << kLoadStoreElimination) |
758 (1 << kLoadHoisting) |
759 (1 << kTrackLiveTemps) |
760 (1 << kSuppressLoads) |
761 (1 << kPromoteRegs) |
762 0;
buzbee67bf8852011-08-17 17:51:35 -0700763#endif
764
765 /* Initialize the block list */
766 oatInitGrowableList(&cUnit.blockList, 40);
767
768 /* Initialize the switchTables list */
769 oatInitGrowableList(&cUnit.switchTables, 4);
770
771 /* Intialize the fillArrayData list */
772 oatInitGrowableList(&cUnit.fillArrayData, 4);
773
774 /* Allocate the bit-vector to track the beginning of basic blocks */
775 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit.insnsSize,
776 true /* expandable */);
777 cUnit.tryBlockAddr = tryBlockAddr;
778
779 /* Create the default entry and exit blocks and enter them to the list */
780 BasicBlock *entryBlock = oatNewBB(kEntryBlock, numBlocks++);
781 BasicBlock *exitBlock = oatNewBB(kExitBlock, numBlocks++);
782
783 cUnit.entryBlock = entryBlock;
784 cUnit.exitBlock = exitBlock;
785
786 oatInsertGrowableList(&cUnit.blockList, (intptr_t) entryBlock);
787 oatInsertGrowableList(&cUnit.blockList, (intptr_t) exitBlock);
788
789 /* Current block to record parsed instructions */
790 BasicBlock *curBlock = oatNewBB(kDalvikByteCode, numBlocks++);
791 curBlock->startOffset = 0;
792 oatInsertGrowableList(&cUnit.blockList, (intptr_t) curBlock);
793 entryBlock->fallThrough = curBlock;
794 oatSetBit(curBlock->predecessors, entryBlock->id);
795
796 /*
797 * Store back the number of blocks since new blocks may be created of
798 * accessing cUnit.
799 */
800 cUnit.numBlocks = numBlocks;
801
802 /* Identify code range in try blocks and set up the empty catch blocks */
803 processTryCatchBlocks(&cUnit);
804
805 /* Parse all instructions and put them into containing basic blocks */
806 while (codePtr < codeEnd) {
807 MIR *insn = (MIR *) oatNew(sizeof(MIR), true);
808 insn->offset = curOffset;
809 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
810 insn->width = width;
811
812 /* Terminate when the data section is seen */
813 if (width == 0)
814 break;
815
816 oatAppendMIR(curBlock, insn);
817
818 codePtr += width;
819 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
820
821 if (flags & kInstrCanBranch) {
822 processCanBranch(&cUnit, curBlock, insn, curOffset, width, flags,
823 codePtr, codeEnd);
824 } else if (flags & kInstrCanReturn) {
825 curBlock->fallThrough = exitBlock;
826 oatSetBit(exitBlock->predecessors, curBlock->id);
827 /*
828 * Terminate the current block if there are instructions
829 * afterwards.
830 */
831 if (codePtr < codeEnd) {
832 /*
833 * Create a fallthrough block for real instructions
834 * (incl. OP_NOP).
835 */
836 if (contentIsInsn(codePtr)) {
837 findBlock(&cUnit, curOffset + width,
838 /* split */
839 false,
840 /* create */
841 true);
842 }
843 }
844 } else if (flags & kInstrCanThrow) {
845 processCanThrow(&cUnit, curBlock, insn, curOffset, width, flags,
846 tryBlockAddr, codePtr, codeEnd);
847 } else if (flags & kInstrCanSwitch) {
848 processCanSwitch(&cUnit, curBlock, insn, curOffset, width, flags);
849 }
850 curOffset += width;
851 BasicBlock *nextBlock = findBlock(&cUnit, curOffset,
852 /* split */
853 false,
854 /* create */
855 false);
856 if (nextBlock) {
857 /*
858 * The next instruction could be the target of a previously parsed
859 * forward branch so a block is already created. If the current
860 * instruction is not an unconditional branch, connect them through
861 * the fall-through link.
862 */
863 assert(curBlock->fallThrough == NULL ||
864 curBlock->fallThrough == nextBlock ||
865 curBlock->fallThrough == exitBlock);
866
867 if ((curBlock->fallThrough == NULL) &&
868 (flags & kInstrCanContinue)) {
869 curBlock->fallThrough = nextBlock;
870 oatSetBit(nextBlock->predecessors, curBlock->id);
871 }
872 curBlock = nextBlock;
873 }
874 }
875
876 if (cUnit.printMe) {
877 oatDumpCompilationUnit(&cUnit);
878 }
879
880 /* Adjust this value accordingly once inlining is performed */
buzbeec143c552011-08-20 17:38:58 -0700881 cUnit.numDalvikRegisters = cUnit.method->num_registers_;
buzbee67bf8852011-08-17 17:51:35 -0700882
883
884 /* Verify if all blocks are connected as claimed */
885 oatDataFlowAnalysisDispatcher(&cUnit, verifyPredInfo,
886 kAllNodes,
887 false /* isIterative */);
888
889
890
891 /* Perform SSA transformation for the whole method */
892 oatMethodSSATransformation(&cUnit);
893
894 oatInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
895
896 /* Allocate Registers using simple local allocation scheme */
897 oatSimpleRegAlloc(&cUnit);
898
899 /* Convert MIR to LIR, etc. */
900 oatMethodMIR2LIR(&cUnit);
901
902 // Debugging only
903 //oatDumpCFG(&cUnit, "/sdcard/cfg/");
904
905 /* Method is not empty */
906 if (cUnit.firstLIRInsn) {
907
908 // mark the targets of switch statement case labels
909 oatProcessSwitchTables(&cUnit);
910
911 /* Convert LIR into machine code. */
912 oatAssembleLIR(&cUnit);
913
914 if (cUnit.printMe) {
915 oatCodegenDump(&cUnit);
916 }
917 }
918
buzbeec143c552011-08-20 17:38:58 -0700919 method->SetCode((const art::byte*)&cUnit.codeBuffer[0],
920 cUnit.codeBuffer.size() * 2, art::kThumb2);
Shih-wei Liaod11af152011-08-23 16:02:11 -0700921 method->SetFrameSizeInBytes(cUnit.frameSize);
buzbeec143c552011-08-20 17:38:58 -0700922 method->SetCoreSpillMask(cUnit.coreSpillMask);
923 method->SetFpSpillMask(cUnit.fpSpillMask);
924 // TODO: Transmit mapping table to caller
buzbee67bf8852011-08-17 17:51:35 -0700925
926#if 0
927 oatDumpCFG(&cUnit, "/sdcard/cfg/");
928#endif
929
Brian Carlstrombffb1552011-08-25 12:23:53 -0700930 return true;
buzbee67bf8852011-08-17 17:51:35 -0700931}
932
933void oatInit(void)
934{
935#if 1
936 // FIXME - temp hack 'till properly integrated
937 static bool initialized = false;
938 if (initialized)
939 return;
940 initialized = true;
941 LOG(INFO) << "Initializing compiler";
942#endif
943 if (!oatArchInit()) {
944 LOG(FATAL) << "Failed to initialize oat";
945 }
946 if (!oatHeapInit()) {
947 LOG(FATAL) << "Failed to initialize oat heap";
948 }
949}