blob: a829f1300e41829f2cf44df7daea67f73711def0 [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 Carlstrom9baa4ae2011-09-01 21:14:14 -070021#include "object.h"
Brian Carlstrom1f870082011-08-23 16:02:11 -070022#include "runtime.h"
buzbee67bf8852011-08-17 17:51:35 -070023
buzbeeed3e9302011-09-23 17:34:19 -070024STATIC inline bool contentIsInsn(const u2* codePtr) {
buzbee67bf8852011-08-17 17:51:35 -070025 u2 instr = *codePtr;
26 Opcode opcode = (Opcode)(instr & 0xff);
27
28 /*
29 * Since the low 8-bit in metadata may look like OP_NOP, we need to check
30 * both the low and whole sub-word to determine whether it is code or data.
31 */
32 return (opcode != OP_NOP || instr == 0);
33}
34
35/*
36 * Parse an instruction, return the length of the instruction
37 */
buzbeeed3e9302011-09-23 17:34:19 -070038STATIC inline int parseInsn(const u2* codePtr, DecodedInstruction* decInsn,
buzbee67bf8852011-08-17 17:51:35 -070039 bool printMe)
40{
41 // Don't parse instruction data
42 if (!contentIsInsn(codePtr)) {
43 return 0;
44 }
45
46 u2 instr = *codePtr;
47 Opcode opcode = dexOpcodeFromCodeUnit(instr);
48
49 dexDecodeInstruction(codePtr, decInsn);
50 if (printMe) {
51 char *decodedString = oatGetDalvikDisassembly(decInsn, NULL);
52 LOG(INFO) << codePtr << ": 0x" << std::hex << (int)opcode <<
53 " " << decodedString;
54 }
55 return dexGetWidthFromOpcode(opcode);
56}
57
58#define UNKNOWN_TARGET 0xffffffff
59
buzbeeed3e9302011-09-23 17:34:19 -070060STATIC inline bool isGoto(MIR* insn)
buzbee67bf8852011-08-17 17:51:35 -070061{
62 switch (insn->dalvikInsn.opcode) {
63 case OP_GOTO:
64 case OP_GOTO_16:
65 case OP_GOTO_32:
66 return true;
67 default:
68 return false;
69 }
70}
71
72/*
73 * Identify unconditional branch instructions
74 */
buzbeeed3e9302011-09-23 17:34:19 -070075STATIC inline bool isUnconditionalBranch(MIR* insn)
buzbee67bf8852011-08-17 17:51:35 -070076{
77 switch (insn->dalvikInsn.opcode) {
78 case OP_RETURN_VOID:
79 case OP_RETURN:
80 case OP_RETURN_WIDE:
81 case OP_RETURN_OBJECT:
82 return true;
83 default:
84 return isGoto(insn);
85 }
86}
87
88/* Split an existing block from the specified code offset into two */
buzbeeed3e9302011-09-23 17:34:19 -070089STATIC BasicBlock *splitBlock(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -070090 unsigned int codeOffset,
91 BasicBlock* origBlock)
92{
93 MIR* insn = origBlock->firstMIRInsn;
94 while (insn) {
95 if (insn->offset == codeOffset) break;
96 insn = insn->next;
97 }
98 if (insn == NULL) {
99 LOG(FATAL) << "Break split failed";
100 }
101 BasicBlock *bottomBlock = oatNewBB(kDalvikByteCode,
102 cUnit->numBlocks++);
103 oatInsertGrowableList(&cUnit->blockList, (intptr_t) bottomBlock);
104
105 bottomBlock->startOffset = codeOffset;
106 bottomBlock->firstMIRInsn = insn;
107 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
108
109 /* Handle the taken path */
110 bottomBlock->taken = origBlock->taken;
111 if (bottomBlock->taken) {
112 origBlock->taken = NULL;
113 oatClearBit(bottomBlock->taken->predecessors, origBlock->id);
114 oatSetBit(bottomBlock->taken->predecessors, bottomBlock->id);
115 }
116
117 /* Handle the fallthrough path */
118 bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
119 bottomBlock->fallThrough = origBlock->fallThrough;
120 origBlock->fallThrough = bottomBlock;
121 origBlock->needFallThroughBranch = true;
122 oatSetBit(bottomBlock->predecessors, origBlock->id);
123 if (bottomBlock->fallThrough) {
124 oatClearBit(bottomBlock->fallThrough->predecessors,
125 origBlock->id);
126 oatSetBit(bottomBlock->fallThrough->predecessors,
127 bottomBlock->id);
128 }
129
130 /* Handle the successor list */
131 if (origBlock->successorBlockList.blockListType != kNotUsed) {
132 bottomBlock->successorBlockList = origBlock->successorBlockList;
133 origBlock->successorBlockList.blockListType = kNotUsed;
134 GrowableListIterator iterator;
135
136 oatGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
137 &iterator);
138 while (true) {
139 SuccessorBlockInfo *successorBlockInfo =
140 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
141 if (successorBlockInfo == NULL) break;
142 BasicBlock *bb = successorBlockInfo->block;
143 oatClearBit(bb->predecessors, origBlock->id);
144 oatSetBit(bb->predecessors, bottomBlock->id);
145 }
146 }
147
148 origBlock->lastMIRInsn = insn->prev;
149
150 insn->prev->next = NULL;
151 insn->prev = NULL;
152 return bottomBlock;
153}
154
155/*
156 * Given a code offset, find out the block that starts with it. If the offset
157 * is in the middle of an existing block, split it into two.
158 */
buzbeeed3e9302011-09-23 17:34:19 -0700159STATIC BasicBlock *findBlock(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -0700160 unsigned int codeOffset,
161 bool split, bool create)
162{
163 GrowableList* blockList = &cUnit->blockList;
164 BasicBlock* bb;
165 unsigned int i;
166
167 for (i = 0; i < blockList->numUsed; i++) {
168 bb = (BasicBlock *) blockList->elemList[i];
169 if (bb->blockType != kDalvikByteCode) continue;
170 if (bb->startOffset == codeOffset) return bb;
171 /* Check if a branch jumps into the middle of an existing block */
172 if ((split == true) && (codeOffset > bb->startOffset) &&
173 (bb->lastMIRInsn != NULL) &&
174 (codeOffset <= bb->lastMIRInsn->offset)) {
175 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb);
176 return newBB;
177 }
178 }
179 if (create) {
180 bb = oatNewBB(kDalvikByteCode, cUnit->numBlocks++);
181 oatInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
182 bb->startOffset = codeOffset;
183 return bb;
184 }
185 return NULL;
186}
187
188/* Dump the CFG into a DOT graph */
189void oatDumpCFG(CompilationUnit* cUnit, const char* dirPrefix)
190{
buzbee67bf8852011-08-17 17:51:35 -0700191 FILE* file;
buzbeedfd3d702011-08-28 12:56:51 -0700192 std::string name = art::PrettyMethod(cUnit->method);
buzbee67bf8852011-08-17 17:51:35 -0700193 char startOffset[80];
194 sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
195 char* fileName = (char *) oatNew(
buzbeec143c552011-08-20 17:38:58 -0700196 strlen(dirPrefix) +
197 name.length() +
198 strlen(".dot") + 1, true);
199 sprintf(fileName, "%s%s%s.dot", dirPrefix, name.c_str(), startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700200
201 /*
202 * Convert the special characters into a filesystem- and shell-friendly
203 * format.
204 */
205 int i;
206 for (i = strlen(dirPrefix); fileName[i]; i++) {
207 if (fileName[i] == '/') {
208 fileName[i] = '_';
209 } else if (fileName[i] == ';') {
210 fileName[i] = '#';
211 } else if (fileName[i] == '$') {
212 fileName[i] = '+';
213 } else if (fileName[i] == '(' || fileName[i] == ')') {
214 fileName[i] = '@';
215 } else if (fileName[i] == '<' || fileName[i] == '>') {
216 fileName[i] = '=';
217 }
218 }
219 file = fopen(fileName, "w");
220 if (file == NULL) {
221 return;
222 }
223 fprintf(file, "digraph G {\n");
224
225 fprintf(file, " rankdir=TB\n");
226
227 int numReachableBlocks = cUnit->numReachableBlocks;
228 int idx;
229 const GrowableList *blockList = &cUnit->blockList;
230
231 for (idx = 0; idx < numReachableBlocks; idx++) {
232 int blockIdx = cUnit->dfsOrder.elemList[idx];
233 BasicBlock *bb = (BasicBlock *) oatGrowableListGetElement(blockList,
234 blockIdx);
235 if (bb == NULL) break;
236 if (bb->blockType == kEntryBlock) {
237 fprintf(file, " entry [shape=Mdiamond];\n");
238 } else if (bb->blockType == kExitBlock) {
239 fprintf(file, " exit [shape=Mdiamond];\n");
240 } else if (bb->blockType == kDalvikByteCode) {
241 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
242 bb->startOffset);
243 const MIR *mir;
244 fprintf(file, " {block id %d\\l}%s\\\n", bb->id,
245 bb->firstMIRInsn ? " | " : " ");
246 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
247 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
248 mir->ssaRep ?
249 oatFullDisassembler(cUnit, mir) :
250 dexGetOpcodeName(mir->dalvikInsn.opcode),
251 mir->next ? " | " : " ");
252 }
253 fprintf(file, " }\"];\n\n");
254 } else if (bb->blockType == kExceptionHandling) {
255 char blockName[BLOCK_NAME_LEN];
256
257 oatGetBlockName(bb, blockName);
258 fprintf(file, " %s [shape=invhouse];\n", blockName);
259 }
260
261 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
262
263 if (bb->taken) {
264 oatGetBlockName(bb, blockName1);
265 oatGetBlockName(bb->taken, blockName2);
266 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
267 blockName1, blockName2);
268 }
269 if (bb->fallThrough) {
270 oatGetBlockName(bb, blockName1);
271 oatGetBlockName(bb->fallThrough, blockName2);
272 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
273 }
274
275 if (bb->successorBlockList.blockListType != kNotUsed) {
276 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
277 bb->startOffset,
278 (bb->successorBlockList.blockListType == kCatch) ?
279 "Mrecord" : "record");
280 GrowableListIterator iterator;
281 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
282 &iterator);
283 SuccessorBlockInfo *successorBlockInfo =
284 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
285
286 int succId = 0;
287 while (true) {
288 if (successorBlockInfo == NULL) break;
289
290 BasicBlock *destBlock = successorBlockInfo->block;
291 SuccessorBlockInfo *nextSuccessorBlockInfo =
292 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
293
294 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
295 succId++,
296 successorBlockInfo->key,
297 destBlock->startOffset,
298 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
299
300 successorBlockInfo = nextSuccessorBlockInfo;
301 }
302 fprintf(file, " }\"];\n\n");
303
304 oatGetBlockName(bb, blockName1);
305 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
306 blockName1, bb->startOffset);
307
308 if (bb->successorBlockList.blockListType == kPackedSwitch ||
309 bb->successorBlockList.blockListType == kSparseSwitch) {
310
311 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
312 &iterator);
313
314 succId = 0;
315 while (true) {
316 SuccessorBlockInfo *successorBlockInfo =
317 (SuccessorBlockInfo *)
318 oatGrowableListIteratorNext(&iterator);
319 if (successorBlockInfo == NULL) break;
320
321 BasicBlock *destBlock = successorBlockInfo->block;
322
323 oatGetBlockName(destBlock, blockName2);
324 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
325 bb->startOffset, succId++,
326 blockName2);
327 }
328 }
329 }
330 fprintf(file, "\n");
331
332 /*
333 * If we need to debug the dominator tree, uncomment the following code
334 */
335#if 1
336 oatGetBlockName(bb, blockName1);
337 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
338 blockName1, blockName1);
339 if (bb->iDom) {
340 oatGetBlockName(bb->iDom, blockName2);
341 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
342 blockName2, blockName1);
343 }
344#endif
345 }
346 fprintf(file, "}\n");
347 fclose(file);
348}
349
350/* Verify if all the successor is connected with all the claimed predecessors */
buzbeeed3e9302011-09-23 17:34:19 -0700351STATIC bool verifyPredInfo(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -0700352{
353 ArenaBitVectorIterator bvIterator;
354
355 oatBitVectorIteratorInit(bb->predecessors, &bvIterator);
356 while (true) {
357 int blockIdx = oatBitVectorIteratorNext(&bvIterator);
358 if (blockIdx == -1) break;
359 BasicBlock *predBB = (BasicBlock *)
360 oatGrowableListGetElement(&cUnit->blockList, blockIdx);
361 bool found = false;
362 if (predBB->taken == bb) {
363 found = true;
364 } else if (predBB->fallThrough == bb) {
365 found = true;
366 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
367 GrowableListIterator iterator;
368 oatGrowableListIteratorInit(&predBB->successorBlockList.blocks,
369 &iterator);
370 while (true) {
371 SuccessorBlockInfo *successorBlockInfo =
372 (SuccessorBlockInfo *)
373 oatGrowableListIteratorNext(&iterator);
374 if (successorBlockInfo == NULL) break;
375 BasicBlock *succBB = successorBlockInfo->block;
376 if (succBB == bb) {
377 found = true;
378 break;
379 }
380 }
381 }
382 if (found == false) {
383 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
384 oatGetBlockName(bb, blockName1);
385 oatGetBlockName(predBB, blockName2);
386 oatDumpCFG(cUnit, "/sdcard/cfg/");
387 LOG(FATAL) << "Successor " << blockName1 << "not found from "
388 << blockName2;
389 }
390 }
391 return true;
392}
393
394/* Identify code range in try blocks and set up the empty catch blocks */
buzbeeed3e9302011-09-23 17:34:19 -0700395STATIC void processTryCatchBlocks(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700396{
buzbeee9a72f62011-09-04 17:59:07 -0700397 const Method* method = cUnit->method;
398 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
399 const art::DexFile& dex_file = class_linker->FindDexFile(
400 method->GetDeclaringClass()->GetDexCache());
401 const art::DexFile::CodeItem* code_item =
402 dex_file.GetCodeItem(method->GetCodeItemOffset());
403 int triesSize = code_item->tries_size_;
buzbee67bf8852011-08-17 17:51:35 -0700404 int offset;
405
406 if (triesSize == 0) {
407 return;
408 }
409
buzbee67bf8852011-08-17 17:51:35 -0700410 ArenaBitVector* tryBlockAddr = cUnit->tryBlockAddr;
411
buzbeee9a72f62011-09-04 17:59:07 -0700412 for (int i = 0; i < triesSize; i++) {
413 const art::DexFile::TryItem* pTry =
414 art::DexFile::dexGetTryItems(*code_item, i);
415 int startOffset = pTry->start_addr_;
416 int endOffset = startOffset + pTry->insn_count_;
buzbee67bf8852011-08-17 17:51:35 -0700417 for (offset = startOffset; offset < endOffset; offset++) {
418 oatSetBit(tryBlockAddr, offset);
419 }
420 }
421
buzbeee9a72f62011-09-04 17:59:07 -0700422 // Iterate over each of the handlers to enqueue the empty Catch blocks
423 const art::byte* handlers_ptr =
424 art::DexFile::dexGetCatchHandlerData(*code_item, 0);
425 uint32_t handlers_size = art::DecodeUnsignedLeb128(&handlers_ptr);
426 for (uint32_t idx = 0; idx < handlers_size; idx++) {
427 art::DexFile::CatchHandlerIterator iterator(handlers_ptr);
buzbee67bf8852011-08-17 17:51:35 -0700428
buzbeee9a72f62011-09-04 17:59:07 -0700429 for (; !iterator.HasNext(); iterator.Next()) {
430 uint32_t address = iterator.Get().address_;
431 findBlock(cUnit, address, false /* split */, true /*create*/);
buzbee67bf8852011-08-17 17:51:35 -0700432 }
buzbeee9a72f62011-09-04 17:59:07 -0700433 handlers_ptr = iterator.GetData();
buzbee67bf8852011-08-17 17:51:35 -0700434 }
435}
436
437/* Process instructions with the kInstrCanBranch flag */
buzbeeed3e9302011-09-23 17:34:19 -0700438STATIC void processCanBranch(CompilationUnit* cUnit, BasicBlock* curBlock,
buzbee67bf8852011-08-17 17:51:35 -0700439 MIR* insn, int curOffset, int width, int flags,
440 const u2* codePtr, const u2* codeEnd)
441{
442 int target = curOffset;
443 switch (insn->dalvikInsn.opcode) {
444 case OP_GOTO:
445 case OP_GOTO_16:
446 case OP_GOTO_32:
447 target += (int) insn->dalvikInsn.vA;
448 break;
449 case OP_IF_EQ:
450 case OP_IF_NE:
451 case OP_IF_LT:
452 case OP_IF_GE:
453 case OP_IF_GT:
454 case OP_IF_LE:
455 target += (int) insn->dalvikInsn.vC;
456 break;
457 case OP_IF_EQZ:
458 case OP_IF_NEZ:
459 case OP_IF_LTZ:
460 case OP_IF_GEZ:
461 case OP_IF_GTZ:
462 case OP_IF_LEZ:
463 target += (int) insn->dalvikInsn.vB;
464 break;
465 default:
466 LOG(FATAL) << "Unexpected opcode(" << (int)insn->dalvikInsn.opcode
467 << ") with kInstrCanBranch set";
468 }
469 BasicBlock *takenBlock = findBlock(cUnit, target,
470 /* split */
471 true,
472 /* create */
473 true);
474 curBlock->taken = takenBlock;
475 oatSetBit(takenBlock->predecessors, curBlock->id);
476
477 /* Always terminate the current block for conditional branches */
478 if (flags & kInstrCanContinue) {
479 BasicBlock *fallthroughBlock = findBlock(cUnit,
480 curOffset + width,
481 /*
482 * If the method is processed
483 * in sequential order from the
484 * beginning, we don't need to
485 * specify split for continue
486 * blocks. However, this
487 * routine can be called by
488 * compileLoop, which starts
489 * parsing the method from an
490 * arbitrary address in the
491 * method body.
492 */
493 true,
494 /* create */
495 true);
496 curBlock->fallThrough = fallthroughBlock;
497 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
498 } else if (codePtr < codeEnd) {
499 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
500 if (contentIsInsn(codePtr)) {
501 findBlock(cUnit, curOffset + width,
502 /* split */
503 false,
504 /* create */
505 true);
506 }
507 }
508}
509
510/* Process instructions with the kInstrCanSwitch flag */
buzbeeed3e9302011-09-23 17:34:19 -0700511STATIC void processCanSwitch(CompilationUnit* cUnit, BasicBlock* curBlock,
buzbee67bf8852011-08-17 17:51:35 -0700512 MIR* insn, int curOffset, int width, int flags)
513{
514 u2* switchData= (u2 *) (cUnit->insns + curOffset +
515 insn->dalvikInsn.vB);
516 int size;
517 int* keyTable;
518 int* targetTable;
519 int i;
520 int firstKey;
521
522 /*
523 * Packed switch data format:
524 * ushort ident = 0x0100 magic value
525 * ushort size number of entries in the table
526 * int first_key first (and lowest) switch case value
527 * int targets[size] branch targets, relative to switch opcode
528 *
529 * Total size is (4+size*2) 16-bit code units.
530 */
531 if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
buzbeeed3e9302011-09-23 17:34:19 -0700532 DCHECK_EQ(switchData[0], kPackedSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700533 size = switchData[1];
534 firstKey = switchData[2] | (switchData[3] << 16);
535 targetTable = (int *) &switchData[4];
536 keyTable = NULL; // Make the compiler happy
537 /*
538 * Sparse switch data format:
539 * ushort ident = 0x0200 magic value
540 * ushort size number of entries in the table; > 0
541 * int keys[size] keys, sorted low-to-high; 32-bit aligned
542 * int targets[size] branch targets, relative to switch opcode
543 *
544 * Total size is (2+size*4) 16-bit code units.
545 */
546 } else {
buzbeeed3e9302011-09-23 17:34:19 -0700547 DCHECK_EQ(switchData[0], kSparseSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700548 size = switchData[1];
549 keyTable = (int *) &switchData[2];
550 targetTable = (int *) &switchData[2 + size*2];
551 firstKey = 0; // To make the compiler happy
552 }
553
554 if (curBlock->successorBlockList.blockListType != kNotUsed) {
555 LOG(FATAL) << "Successor block list already in use: " <<
556 (int)curBlock->successorBlockList.blockListType;
557 }
558 curBlock->successorBlockList.blockListType =
559 (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
560 kPackedSwitch : kSparseSwitch;
561 oatInitGrowableList(&curBlock->successorBlockList.blocks, size);
562
563 for (i = 0; i < size; i++) {
564 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
565 /* split */
566 true,
567 /* create */
568 true);
569 SuccessorBlockInfo *successorBlockInfo =
570 (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
571 false);
572 successorBlockInfo->block = caseBlock;
573 successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)?
574 firstKey + i : keyTable[i];
575 oatInsertGrowableList(&curBlock->successorBlockList.blocks,
576 (intptr_t) successorBlockInfo);
577 oatSetBit(caseBlock->predecessors, curBlock->id);
578 }
579
580 /* Fall-through case */
581 BasicBlock* fallthroughBlock = findBlock(cUnit,
582 curOffset + width,
583 /* split */
584 false,
585 /* create */
586 true);
587 curBlock->fallThrough = fallthroughBlock;
588 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
589}
590
591/* Process instructions with the kInstrCanThrow flag */
buzbeeed3e9302011-09-23 17:34:19 -0700592STATIC void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock,
buzbee67bf8852011-08-17 17:51:35 -0700593 MIR* insn, int curOffset, int width, int flags,
594 ArenaBitVector* tryBlockAddr, const u2* codePtr,
595 const u2* codeEnd)
596{
buzbeee9a72f62011-09-04 17:59:07 -0700597
buzbee67bf8852011-08-17 17:51:35 -0700598 const Method* method = cUnit->method;
buzbeee9a72f62011-09-04 17:59:07 -0700599 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
600 const art::DexFile& dex_file = class_linker->FindDexFile(
601 method->GetDeclaringClass()->GetDexCache());
602 const art::DexFile::CodeItem* code_item =
603 dex_file.GetCodeItem(method->GetCodeItemOffset());
buzbee67bf8852011-08-17 17:51:35 -0700604
605 /* In try block */
606 if (oatIsBitSet(tryBlockAddr, curOffset)) {
buzbeee9a72f62011-09-04 17:59:07 -0700607 art::DexFile::CatchHandlerIterator iterator =
608 art::DexFile::dexFindCatchHandler(*code_item, curOffset);
buzbee67bf8852011-08-17 17:51:35 -0700609
buzbee67bf8852011-08-17 17:51:35 -0700610 if (curBlock->successorBlockList.blockListType != kNotUsed) {
611 LOG(FATAL) << "Successor block list already in use: " <<
612 (int)curBlock->successorBlockList.blockListType;
613 }
buzbeee9a72f62011-09-04 17:59:07 -0700614
buzbee67bf8852011-08-17 17:51:35 -0700615 curBlock->successorBlockList.blockListType = kCatch;
616 oatInitGrowableList(&curBlock->successorBlockList.blocks, 2);
617
buzbeee9a72f62011-09-04 17:59:07 -0700618 for (;!iterator.HasNext(); iterator.Next()) {
619 BasicBlock *catchBlock = findBlock(cUnit, iterator.Get().address_,
620 false /* split*/,
621 false /* creat */);
buzbee43a36422011-09-14 14:00:13 -0700622 catchBlock->catchEntry = true;
buzbee67bf8852011-08-17 17:51:35 -0700623 SuccessorBlockInfo *successorBlockInfo =
buzbeee9a72f62011-09-04 17:59:07 -0700624 (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
625 false);
buzbee67bf8852011-08-17 17:51:35 -0700626 successorBlockInfo->block = catchBlock;
buzbeee9a72f62011-09-04 17:59:07 -0700627 successorBlockInfo->key = iterator.Get().type_idx_;
buzbee67bf8852011-08-17 17:51:35 -0700628 oatInsertGrowableList(&curBlock->successorBlockList.blocks,
629 (intptr_t) successorBlockInfo);
630 oatSetBit(catchBlock->predecessors, curBlock->id);
631 }
632 } else {
633 BasicBlock *ehBlock = oatNewBB(kExceptionHandling,
634 cUnit->numBlocks++);
635 curBlock->taken = ehBlock;
636 oatInsertGrowableList(&cUnit->blockList, (intptr_t) ehBlock);
637 ehBlock->startOffset = curOffset;
638 oatSetBit(ehBlock->predecessors, curBlock->id);
639 }
640
641 /*
642 * Force the current block to terminate.
643 *
644 * Data may be present before codeEnd, so we need to parse it to know
645 * whether it is code or data.
646 */
647 if (codePtr < codeEnd) {
648 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
649 if (contentIsInsn(codePtr)) {
650 BasicBlock *fallthroughBlock = findBlock(cUnit,
651 curOffset + width,
652 /* split */
653 false,
654 /* create */
655 true);
656 /*
657 * OP_THROW and OP_THROW_VERIFICATION_ERROR are unconditional
658 * branches.
659 */
660 if (insn->dalvikInsn.opcode != OP_THROW_VERIFICATION_ERROR &&
661 insn->dalvikInsn.opcode != OP_THROW) {
662 curBlock->fallThrough = fallthroughBlock;
663 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
664 }
665 }
666 }
667}
668
669/*
670 * Compile a method.
671 */
Brian Carlstrom16192862011-09-12 17:50:06 -0700672bool oatCompileMethod(const Compiler& compiler, Method* method, art::InstructionSet insnSet)
buzbee67bf8852011-08-17 17:51:35 -0700673{
Brian Carlstrom16192862011-09-12 17:50:06 -0700674 if (compiler.IsVerbose()) {
675 LOG(INFO) << "Compiling " << PrettyMethod(method) << "...";
676 }
buzbee2a475e72011-09-07 17:19:17 -0700677 oatArenaReset();
Brian Carlstrom94496d32011-08-22 09:22:47 -0700678
buzbee67bf8852011-08-17 17:51:35 -0700679 CompilationUnit cUnit;
buzbeec143c552011-08-20 17:38:58 -0700680 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
681 const art::DexFile& dex_file = class_linker->FindDexFile(
682 method->GetDeclaringClass()->GetDexCache());
683 const art::DexFile::CodeItem* code_item =
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700684 dex_file.GetCodeItem(method->GetCodeItemOffset());
buzbeec143c552011-08-20 17:38:58 -0700685 const u2* codePtr = code_item->insns_;
686 const u2* codeEnd = code_item->insns_ + code_item->insns_size_;
buzbee67bf8852011-08-17 17:51:35 -0700687 int numBlocks = 0;
688 unsigned int curOffset = 0;
689
690#if 1
691 // FIXME - temp 'till properly integrated
Brian Carlstrom16192862011-09-12 17:50:06 -0700692 oatInit(compiler);
buzbee67bf8852011-08-17 17:51:35 -0700693#endif
694
695 memset(&cUnit, 0, sizeof(cUnit));
696 cUnit.method = method;
buzbeec143c552011-08-20 17:38:58 -0700697 cUnit.instructionSet = (OatInstructionSetType)insnSet;
698 cUnit.insns = code_item->insns_;
699 cUnit.insnsSize = code_item->insns_size_;
buzbee67bf8852011-08-17 17:51:35 -0700700#if 1
buzbee3ea4ec52011-08-22 17:37:19 -0700701 // TODO: Use command-line argument passing mechanism
Brian Carlstrom16192862011-09-12 17:50:06 -0700702 cUnit.printMe = compiler.IsVerbose();
703 cUnit.printMeVerbose = compiler.IsVerbose();
buzbee3ea4ec52011-08-22 17:37:19 -0700704 cUnit.disableOpt = 0 |
705 (1 << kLoadStoreElimination) |
706 (1 << kLoadHoisting) |
buzbee3ea4ec52011-08-22 17:37:19 -0700707 (1 << kSuppressLoads) |
buzbee43a36422011-09-14 14:00:13 -0700708 (1 << kNullCheckElimination) |
buzbee3ea4ec52011-08-22 17:37:19 -0700709 (1 << kPromoteRegs) |
710 0;
buzbee67bf8852011-08-17 17:51:35 -0700711#endif
712
buzbeecefd1872011-09-09 09:59:52 -0700713 /* Assume non-throwing leaf */
714 cUnit.attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
715
buzbee67bf8852011-08-17 17:51:35 -0700716 /* Initialize the block list */
717 oatInitGrowableList(&cUnit.blockList, 40);
718
719 /* Initialize the switchTables list */
720 oatInitGrowableList(&cUnit.switchTables, 4);
721
722 /* Intialize the fillArrayData list */
723 oatInitGrowableList(&cUnit.fillArrayData, 4);
724
buzbee5ade1d22011-09-09 14:44:52 -0700725 /* Intialize the throwLaunchpads list */
726 oatInitGrowableList(&cUnit.throwLaunchpads, 4);
727
buzbeec1f45042011-09-21 16:03:19 -0700728 /* Intialize the suspendLaunchpads list */
729 oatInitGrowableList(&cUnit.suspendLaunchpads, 4);
730
buzbee67bf8852011-08-17 17:51:35 -0700731 /* Allocate the bit-vector to track the beginning of basic blocks */
732 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit.insnsSize,
733 true /* expandable */);
734 cUnit.tryBlockAddr = tryBlockAddr;
735
736 /* Create the default entry and exit blocks and enter them to the list */
737 BasicBlock *entryBlock = oatNewBB(kEntryBlock, numBlocks++);
738 BasicBlock *exitBlock = oatNewBB(kExitBlock, numBlocks++);
739
740 cUnit.entryBlock = entryBlock;
741 cUnit.exitBlock = exitBlock;
742
743 oatInsertGrowableList(&cUnit.blockList, (intptr_t) entryBlock);
744 oatInsertGrowableList(&cUnit.blockList, (intptr_t) exitBlock);
745
746 /* Current block to record parsed instructions */
747 BasicBlock *curBlock = oatNewBB(kDalvikByteCode, numBlocks++);
748 curBlock->startOffset = 0;
749 oatInsertGrowableList(&cUnit.blockList, (intptr_t) curBlock);
750 entryBlock->fallThrough = curBlock;
751 oatSetBit(curBlock->predecessors, entryBlock->id);
752
753 /*
754 * Store back the number of blocks since new blocks may be created of
755 * accessing cUnit.
756 */
757 cUnit.numBlocks = numBlocks;
758
759 /* Identify code range in try blocks and set up the empty catch blocks */
760 processTryCatchBlocks(&cUnit);
761
762 /* Parse all instructions and put them into containing basic blocks */
763 while (codePtr < codeEnd) {
764 MIR *insn = (MIR *) oatNew(sizeof(MIR), true);
765 insn->offset = curOffset;
766 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
767 insn->width = width;
768
769 /* Terminate when the data section is seen */
770 if (width == 0)
771 break;
772
773 oatAppendMIR(curBlock, insn);
774
775 codePtr += width;
776 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
777
778 if (flags & kInstrCanBranch) {
779 processCanBranch(&cUnit, curBlock, insn, curOffset, width, flags,
780 codePtr, codeEnd);
781 } else if (flags & kInstrCanReturn) {
782 curBlock->fallThrough = exitBlock;
783 oatSetBit(exitBlock->predecessors, curBlock->id);
784 /*
785 * Terminate the current block if there are instructions
786 * afterwards.
787 */
788 if (codePtr < codeEnd) {
789 /*
790 * Create a fallthrough block for real instructions
791 * (incl. OP_NOP).
792 */
793 if (contentIsInsn(codePtr)) {
794 findBlock(&cUnit, curOffset + width,
795 /* split */
796 false,
797 /* create */
798 true);
799 }
800 }
801 } else if (flags & kInstrCanThrow) {
802 processCanThrow(&cUnit, curBlock, insn, curOffset, width, flags,
803 tryBlockAddr, codePtr, codeEnd);
804 } else if (flags & kInstrCanSwitch) {
805 processCanSwitch(&cUnit, curBlock, insn, curOffset, width, flags);
806 }
807 curOffset += width;
808 BasicBlock *nextBlock = findBlock(&cUnit, curOffset,
809 /* split */
810 false,
811 /* create */
812 false);
813 if (nextBlock) {
814 /*
815 * The next instruction could be the target of a previously parsed
816 * forward branch so a block is already created. If the current
817 * instruction is not an unconditional branch, connect them through
818 * the fall-through link.
819 */
buzbeeed3e9302011-09-23 17:34:19 -0700820 DCHECK(curBlock->fallThrough == NULL ||
buzbee67bf8852011-08-17 17:51:35 -0700821 curBlock->fallThrough == nextBlock ||
822 curBlock->fallThrough == exitBlock);
823
824 if ((curBlock->fallThrough == NULL) &&
825 (flags & kInstrCanContinue)) {
826 curBlock->fallThrough = nextBlock;
827 oatSetBit(nextBlock->predecessors, curBlock->id);
828 }
829 curBlock = nextBlock;
830 }
831 }
832
833 if (cUnit.printMe) {
834 oatDumpCompilationUnit(&cUnit);
835 }
836
837 /* Adjust this value accordingly once inlining is performed */
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700838 cUnit.numDalvikRegisters = cUnit.method->NumRegisters();
buzbee67bf8852011-08-17 17:51:35 -0700839
840
841 /* Verify if all blocks are connected as claimed */
842 oatDataFlowAnalysisDispatcher(&cUnit, verifyPredInfo,
843 kAllNodes,
844 false /* isIterative */);
845
846
847
848 /* Perform SSA transformation for the whole method */
849 oatMethodSSATransformation(&cUnit);
850
buzbee43a36422011-09-14 14:00:13 -0700851 /* Perform null check elimination */
852 oatMethodNullCheckElimination(&cUnit);
853
buzbee67bf8852011-08-17 17:51:35 -0700854 oatInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
855
856 /* Allocate Registers using simple local allocation scheme */
857 oatSimpleRegAlloc(&cUnit);
858
859 /* Convert MIR to LIR, etc. */
860 oatMethodMIR2LIR(&cUnit);
861
862 // Debugging only
buzbeeec5adf32011-09-11 15:25:43 -0700863 if (cUnit.dumpCFG) {
864 oatDumpCFG(&cUnit, "/sdcard/cfg/");
865 }
buzbee67bf8852011-08-17 17:51:35 -0700866
867 /* Method is not empty */
868 if (cUnit.firstLIRInsn) {
869
870 // mark the targets of switch statement case labels
871 oatProcessSwitchTables(&cUnit);
872
873 /* Convert LIR into machine code. */
874 oatAssembleLIR(&cUnit);
875
876 if (cUnit.printMe) {
877 oatCodegenDump(&cUnit);
878 }
879 }
880
buzbee4ef76522011-09-08 10:00:32 -0700881 art::ByteArray* managed_code =
Ian Rogersbdb03912011-09-14 00:55:44 -0700882 art::ByteArray::Alloc(cUnit.codeBuffer.size() * sizeof(cUnit.codeBuffer[0]));
Brian Carlstrom9baa4ae2011-09-01 21:14:14 -0700883 memcpy(managed_code->GetData(),
884 reinterpret_cast<const int8_t*>(&cUnit.codeBuffer[0]),
885 managed_code->GetLength());
Ian Rogersbdb03912011-09-14 00:55:44 -0700886 art::IntArray* mapping_table =
887 art::IntArray::Alloc(cUnit.mappingTable.size());
888 DCHECK_EQ(mapping_table->GetClass()->GetComponentSize(), sizeof(cUnit.mappingTable[0]));
buzbee4ef76522011-09-08 10:00:32 -0700889 memcpy(mapping_table->GetData(),
Ian Rogersbdb03912011-09-14 00:55:44 -0700890 reinterpret_cast<const int32_t*>(&cUnit.mappingTable[0]),
891 mapping_table->GetLength() * sizeof(cUnit.mappingTable[0]));
buzbeec41e5b52011-09-23 12:46:19 -0700892 // Add a marker to take place of lr
893 cUnit.coreVmapTable.push_back(-1);
894 // Combine vmap tables - core regs, then fp regs
895 for (uint32_t i = 0; i < cUnit.fpVmapTable.size(); i++) {
896 cUnit.coreVmapTable.push_back(cUnit.fpVmapTable[i]);
897 }
898 DCHECK(cUnit.coreVmapTable.size() == (uint32_t)
899 (__builtin_popcount(cUnit.coreSpillMask) +
900 __builtin_popcount(cUnit.fpSpillMask)));
901 art::ShortArray* vmap_table =
902 art::ShortArray::Alloc(cUnit.coreVmapTable.size());
903 memcpy(vmap_table->GetData(),
904 reinterpret_cast<const int16_t*>(&cUnit.coreVmapTable[0]),
905 vmap_table->GetLength() * sizeof(cUnit.coreVmapTable[0]));
906 method->SetCode(managed_code, art::kThumb2, mapping_table, vmap_table);
Shih-wei Liaod11af152011-08-23 16:02:11 -0700907 method->SetFrameSizeInBytes(cUnit.frameSize);
Ian Rogersbdb03912011-09-14 00:55:44 -0700908 method->SetReturnPcOffsetInBytes(cUnit.frameSize - sizeof(intptr_t));
buzbeec143c552011-08-20 17:38:58 -0700909 method->SetCoreSpillMask(cUnit.coreSpillMask);
910 method->SetFpSpillMask(cUnit.fpSpillMask);
Brian Carlstrom16192862011-09-12 17:50:06 -0700911 if (compiler.IsVerbose()) {
912 LOG(INFO) << "Compiled " << PrettyMethod(method)
913 << " code at " << reinterpret_cast<void*>(managed_code->GetData())
914 << " (" << managed_code->GetLength() << " bytes)";
915 }
buzbee67bf8852011-08-17 17:51:35 -0700916#if 0
917 oatDumpCFG(&cUnit, "/sdcard/cfg/");
918#endif
919
Brian Carlstrombffb1552011-08-25 12:23:53 -0700920 return true;
buzbee67bf8852011-08-17 17:51:35 -0700921}
922
Brian Carlstrom16192862011-09-12 17:50:06 -0700923void oatInit(const Compiler& compiler)
buzbee67bf8852011-08-17 17:51:35 -0700924{
925#if 1
926 // FIXME - temp hack 'till properly integrated
927 static bool initialized = false;
928 if (initialized)
929 return;
930 initialized = true;
Brian Carlstrom16192862011-09-12 17:50:06 -0700931 if (compiler.IsVerbose()) {
932 LOG(INFO) << "Initializing compiler";
933 }
buzbee67bf8852011-08-17 17:51:35 -0700934#endif
935 if (!oatArchInit()) {
936 LOG(FATAL) << "Failed to initialize oat";
937 }
938 if (!oatHeapInit()) {
939 LOG(FATAL) << "Failed to initialize oat heap";
940 }
941}