blob: a0e771385d706a3270196a77f27d518a255e837e [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
buzbeece302932011-10-04 14:32:18 -070024/* Default optimizer/debug setting for the compiler. */
25uint32_t compilerOptimizerDisableFlags = 0 | // Disable specific optimizations
buzbee67bc2362011-10-11 18:08:40 -070026 //(1 << kLoadStoreElimination) |
27 //(1 << kLoadHoisting) |
28 //(1 << kSuppressLoads) |
29 //(1 << kNullCheckElimination) |
30 //(1 << kPromoteRegs) |
31 //(1 << kTrackLiveTemps) |
buzbeece302932011-10-04 14:32:18 -070032 0;
33
34uint32_t compilerDebugFlags = 0 | // Enable debug/testing modes
buzbeee3de7492011-10-05 13:37:17 -070035 //(1 << kDebugDisplayMissingTargets) |
buzbeece302932011-10-04 14:32:18 -070036 //(1 << kDebugVerbose) |
37 //(1 << kDebugDumpCFG) |
38 //(1 << kDebugSlowFieldPath) |
39 //(1 << kDebugSlowInvokePath) |
40 //(1 << kDebugSlowStringPath) |
41 //(1 << kDebugSlowestFieldPath) |
42 //(1 << kDebugSlowestStringPath) |
43 0;
44
45std::string compilerMethodMatch; // Method name match to apply above flags
46
47bool compilerFlipMatch = false; // Reverses sense of method name match
48
buzbeeed3e9302011-09-23 17:34:19 -070049STATIC inline bool contentIsInsn(const u2* codePtr) {
buzbee67bf8852011-08-17 17:51:35 -070050 u2 instr = *codePtr;
51 Opcode opcode = (Opcode)(instr & 0xff);
52
53 /*
54 * Since the low 8-bit in metadata may look like OP_NOP, we need to check
55 * both the low and whole sub-word to determine whether it is code or data.
56 */
57 return (opcode != OP_NOP || instr == 0);
58}
59
60/*
61 * Parse an instruction, return the length of the instruction
62 */
buzbeeed3e9302011-09-23 17:34:19 -070063STATIC inline int parseInsn(const u2* codePtr, DecodedInstruction* decInsn,
buzbee67bf8852011-08-17 17:51:35 -070064 bool printMe)
65{
66 // Don't parse instruction data
67 if (!contentIsInsn(codePtr)) {
68 return 0;
69 }
70
71 u2 instr = *codePtr;
72 Opcode opcode = dexOpcodeFromCodeUnit(instr);
73
74 dexDecodeInstruction(codePtr, decInsn);
75 if (printMe) {
76 char *decodedString = oatGetDalvikDisassembly(decInsn, NULL);
77 LOG(INFO) << codePtr << ": 0x" << std::hex << (int)opcode <<
78 " " << decodedString;
79 }
80 return dexGetWidthFromOpcode(opcode);
81}
82
83#define UNKNOWN_TARGET 0xffffffff
84
buzbeeed3e9302011-09-23 17:34:19 -070085STATIC inline bool isGoto(MIR* insn)
buzbee67bf8852011-08-17 17:51:35 -070086{
87 switch (insn->dalvikInsn.opcode) {
88 case OP_GOTO:
89 case OP_GOTO_16:
90 case OP_GOTO_32:
91 return true;
92 default:
93 return false;
94 }
95}
96
97/*
98 * Identify unconditional branch instructions
99 */
buzbeeed3e9302011-09-23 17:34:19 -0700100STATIC inline bool isUnconditionalBranch(MIR* insn)
buzbee67bf8852011-08-17 17:51:35 -0700101{
102 switch (insn->dalvikInsn.opcode) {
103 case OP_RETURN_VOID:
104 case OP_RETURN:
105 case OP_RETURN_WIDE:
106 case OP_RETURN_OBJECT:
107 return true;
108 default:
109 return isGoto(insn);
110 }
111}
112
113/* Split an existing block from the specified code offset into two */
buzbeeed3e9302011-09-23 17:34:19 -0700114STATIC BasicBlock *splitBlock(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -0700115 unsigned int codeOffset,
116 BasicBlock* origBlock)
117{
118 MIR* insn = origBlock->firstMIRInsn;
119 while (insn) {
120 if (insn->offset == codeOffset) break;
121 insn = insn->next;
122 }
123 if (insn == NULL) {
124 LOG(FATAL) << "Break split failed";
125 }
126 BasicBlock *bottomBlock = oatNewBB(kDalvikByteCode,
127 cUnit->numBlocks++);
128 oatInsertGrowableList(&cUnit->blockList, (intptr_t) bottomBlock);
129
130 bottomBlock->startOffset = codeOffset;
131 bottomBlock->firstMIRInsn = insn;
132 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
133
134 /* Handle the taken path */
135 bottomBlock->taken = origBlock->taken;
136 if (bottomBlock->taken) {
137 origBlock->taken = NULL;
138 oatClearBit(bottomBlock->taken->predecessors, origBlock->id);
139 oatSetBit(bottomBlock->taken->predecessors, bottomBlock->id);
140 }
141
142 /* Handle the fallthrough path */
143 bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
144 bottomBlock->fallThrough = origBlock->fallThrough;
145 origBlock->fallThrough = bottomBlock;
146 origBlock->needFallThroughBranch = true;
147 oatSetBit(bottomBlock->predecessors, origBlock->id);
148 if (bottomBlock->fallThrough) {
149 oatClearBit(bottomBlock->fallThrough->predecessors,
150 origBlock->id);
151 oatSetBit(bottomBlock->fallThrough->predecessors,
152 bottomBlock->id);
153 }
154
155 /* Handle the successor list */
156 if (origBlock->successorBlockList.blockListType != kNotUsed) {
157 bottomBlock->successorBlockList = origBlock->successorBlockList;
158 origBlock->successorBlockList.blockListType = kNotUsed;
159 GrowableListIterator iterator;
160
161 oatGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
162 &iterator);
163 while (true) {
164 SuccessorBlockInfo *successorBlockInfo =
165 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
166 if (successorBlockInfo == NULL) break;
167 BasicBlock *bb = successorBlockInfo->block;
168 oatClearBit(bb->predecessors, origBlock->id);
169 oatSetBit(bb->predecessors, bottomBlock->id);
170 }
171 }
172
173 origBlock->lastMIRInsn = insn->prev;
174
175 insn->prev->next = NULL;
176 insn->prev = NULL;
177 return bottomBlock;
178}
179
180/*
181 * Given a code offset, find out the block that starts with it. If the offset
182 * is in the middle of an existing block, split it into two.
183 */
buzbeeed3e9302011-09-23 17:34:19 -0700184STATIC BasicBlock *findBlock(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -0700185 unsigned int codeOffset,
186 bool split, bool create)
187{
188 GrowableList* blockList = &cUnit->blockList;
189 BasicBlock* bb;
190 unsigned int i;
191
192 for (i = 0; i < blockList->numUsed; i++) {
193 bb = (BasicBlock *) blockList->elemList[i];
194 if (bb->blockType != kDalvikByteCode) continue;
195 if (bb->startOffset == codeOffset) return bb;
196 /* Check if a branch jumps into the middle of an existing block */
197 if ((split == true) && (codeOffset > bb->startOffset) &&
198 (bb->lastMIRInsn != NULL) &&
199 (codeOffset <= bb->lastMIRInsn->offset)) {
200 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb);
201 return newBB;
202 }
203 }
204 if (create) {
205 bb = oatNewBB(kDalvikByteCode, cUnit->numBlocks++);
206 oatInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
207 bb->startOffset = codeOffset;
208 return bb;
209 }
210 return NULL;
211}
212
213/* Dump the CFG into a DOT graph */
214void oatDumpCFG(CompilationUnit* cUnit, const char* dirPrefix)
215{
buzbee67bf8852011-08-17 17:51:35 -0700216 FILE* file;
buzbeedfd3d702011-08-28 12:56:51 -0700217 std::string name = art::PrettyMethod(cUnit->method);
buzbee67bf8852011-08-17 17:51:35 -0700218 char startOffset[80];
219 sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
220 char* fileName = (char *) oatNew(
buzbeec143c552011-08-20 17:38:58 -0700221 strlen(dirPrefix) +
222 name.length() +
223 strlen(".dot") + 1, true);
224 sprintf(fileName, "%s%s%s.dot", dirPrefix, name.c_str(), startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700225
226 /*
227 * Convert the special characters into a filesystem- and shell-friendly
228 * format.
229 */
230 int i;
231 for (i = strlen(dirPrefix); fileName[i]; i++) {
232 if (fileName[i] == '/') {
233 fileName[i] = '_';
234 } else if (fileName[i] == ';') {
235 fileName[i] = '#';
236 } else if (fileName[i] == '$') {
237 fileName[i] = '+';
238 } else if (fileName[i] == '(' || fileName[i] == ')') {
239 fileName[i] = '@';
240 } else if (fileName[i] == '<' || fileName[i] == '>') {
241 fileName[i] = '=';
242 }
243 }
244 file = fopen(fileName, "w");
245 if (file == NULL) {
246 return;
247 }
248 fprintf(file, "digraph G {\n");
249
250 fprintf(file, " rankdir=TB\n");
251
252 int numReachableBlocks = cUnit->numReachableBlocks;
253 int idx;
254 const GrowableList *blockList = &cUnit->blockList;
255
256 for (idx = 0; idx < numReachableBlocks; idx++) {
257 int blockIdx = cUnit->dfsOrder.elemList[idx];
258 BasicBlock *bb = (BasicBlock *) oatGrowableListGetElement(blockList,
259 blockIdx);
260 if (bb == NULL) break;
261 if (bb->blockType == kEntryBlock) {
262 fprintf(file, " entry [shape=Mdiamond];\n");
263 } else if (bb->blockType == kExitBlock) {
264 fprintf(file, " exit [shape=Mdiamond];\n");
265 } else if (bb->blockType == kDalvikByteCode) {
266 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
267 bb->startOffset);
268 const MIR *mir;
269 fprintf(file, " {block id %d\\l}%s\\\n", bb->id,
270 bb->firstMIRInsn ? " | " : " ");
271 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
272 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
273 mir->ssaRep ?
274 oatFullDisassembler(cUnit, mir) :
275 dexGetOpcodeName(mir->dalvikInsn.opcode),
276 mir->next ? " | " : " ");
277 }
278 fprintf(file, " }\"];\n\n");
279 } else if (bb->blockType == kExceptionHandling) {
280 char blockName[BLOCK_NAME_LEN];
281
282 oatGetBlockName(bb, blockName);
283 fprintf(file, " %s [shape=invhouse];\n", blockName);
284 }
285
286 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
287
288 if (bb->taken) {
289 oatGetBlockName(bb, blockName1);
290 oatGetBlockName(bb->taken, blockName2);
291 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
292 blockName1, blockName2);
293 }
294 if (bb->fallThrough) {
295 oatGetBlockName(bb, blockName1);
296 oatGetBlockName(bb->fallThrough, blockName2);
297 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
298 }
299
300 if (bb->successorBlockList.blockListType != kNotUsed) {
301 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
302 bb->startOffset,
303 (bb->successorBlockList.blockListType == kCatch) ?
304 "Mrecord" : "record");
305 GrowableListIterator iterator;
306 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
307 &iterator);
308 SuccessorBlockInfo *successorBlockInfo =
309 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
310
311 int succId = 0;
312 while (true) {
313 if (successorBlockInfo == NULL) break;
314
315 BasicBlock *destBlock = successorBlockInfo->block;
316 SuccessorBlockInfo *nextSuccessorBlockInfo =
317 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
318
319 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
320 succId++,
321 successorBlockInfo->key,
322 destBlock->startOffset,
323 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
324
325 successorBlockInfo = nextSuccessorBlockInfo;
326 }
327 fprintf(file, " }\"];\n\n");
328
329 oatGetBlockName(bb, blockName1);
330 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
331 blockName1, bb->startOffset);
332
333 if (bb->successorBlockList.blockListType == kPackedSwitch ||
334 bb->successorBlockList.blockListType == kSparseSwitch) {
335
336 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
337 &iterator);
338
339 succId = 0;
340 while (true) {
341 SuccessorBlockInfo *successorBlockInfo =
342 (SuccessorBlockInfo *)
343 oatGrowableListIteratorNext(&iterator);
344 if (successorBlockInfo == NULL) break;
345
346 BasicBlock *destBlock = successorBlockInfo->block;
347
348 oatGetBlockName(destBlock, blockName2);
349 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
350 bb->startOffset, succId++,
351 blockName2);
352 }
353 }
354 }
355 fprintf(file, "\n");
356
buzbeece302932011-10-04 14:32:18 -0700357 /* Display the dominator tree */
buzbee67bf8852011-08-17 17:51:35 -0700358 oatGetBlockName(bb, blockName1);
359 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
360 blockName1, blockName1);
361 if (bb->iDom) {
362 oatGetBlockName(bb->iDom, blockName2);
363 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
364 blockName2, blockName1);
365 }
buzbee67bf8852011-08-17 17:51:35 -0700366 }
367 fprintf(file, "}\n");
368 fclose(file);
369}
370
371/* Verify if all the successor is connected with all the claimed predecessors */
buzbeeed3e9302011-09-23 17:34:19 -0700372STATIC bool verifyPredInfo(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -0700373{
374 ArenaBitVectorIterator bvIterator;
375
376 oatBitVectorIteratorInit(bb->predecessors, &bvIterator);
377 while (true) {
378 int blockIdx = oatBitVectorIteratorNext(&bvIterator);
379 if (blockIdx == -1) break;
380 BasicBlock *predBB = (BasicBlock *)
381 oatGrowableListGetElement(&cUnit->blockList, blockIdx);
382 bool found = false;
383 if (predBB->taken == bb) {
384 found = true;
385 } else if (predBB->fallThrough == bb) {
386 found = true;
387 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
388 GrowableListIterator iterator;
389 oatGrowableListIteratorInit(&predBB->successorBlockList.blocks,
390 &iterator);
391 while (true) {
392 SuccessorBlockInfo *successorBlockInfo =
393 (SuccessorBlockInfo *)
394 oatGrowableListIteratorNext(&iterator);
395 if (successorBlockInfo == NULL) break;
396 BasicBlock *succBB = successorBlockInfo->block;
397 if (succBB == bb) {
398 found = true;
399 break;
400 }
401 }
402 }
403 if (found == false) {
404 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
405 oatGetBlockName(bb, blockName1);
406 oatGetBlockName(predBB, blockName2);
407 oatDumpCFG(cUnit, "/sdcard/cfg/");
408 LOG(FATAL) << "Successor " << blockName1 << "not found from "
409 << blockName2;
410 }
411 }
412 return true;
413}
414
415/* Identify code range in try blocks and set up the empty catch blocks */
buzbeeed3e9302011-09-23 17:34:19 -0700416STATIC void processTryCatchBlocks(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700417{
buzbeee9a72f62011-09-04 17:59:07 -0700418 const Method* method = cUnit->method;
419 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
420 const art::DexFile& dex_file = class_linker->FindDexFile(
421 method->GetDeclaringClass()->GetDexCache());
422 const art::DexFile::CodeItem* code_item =
423 dex_file.GetCodeItem(method->GetCodeItemOffset());
424 int triesSize = code_item->tries_size_;
buzbee67bf8852011-08-17 17:51:35 -0700425 int offset;
426
427 if (triesSize == 0) {
428 return;
429 }
430
buzbee67bf8852011-08-17 17:51:35 -0700431 ArenaBitVector* tryBlockAddr = cUnit->tryBlockAddr;
432
buzbeee9a72f62011-09-04 17:59:07 -0700433 for (int i = 0; i < triesSize; i++) {
434 const art::DexFile::TryItem* pTry =
435 art::DexFile::dexGetTryItems(*code_item, i);
436 int startOffset = pTry->start_addr_;
437 int endOffset = startOffset + pTry->insn_count_;
buzbee67bf8852011-08-17 17:51:35 -0700438 for (offset = startOffset; offset < endOffset; offset++) {
439 oatSetBit(tryBlockAddr, offset);
440 }
441 }
442
buzbeee9a72f62011-09-04 17:59:07 -0700443 // Iterate over each of the handlers to enqueue the empty Catch blocks
444 const art::byte* handlers_ptr =
445 art::DexFile::dexGetCatchHandlerData(*code_item, 0);
446 uint32_t handlers_size = art::DecodeUnsignedLeb128(&handlers_ptr);
447 for (uint32_t idx = 0; idx < handlers_size; idx++) {
448 art::DexFile::CatchHandlerIterator iterator(handlers_ptr);
buzbee67bf8852011-08-17 17:51:35 -0700449
buzbeee9a72f62011-09-04 17:59:07 -0700450 for (; !iterator.HasNext(); iterator.Next()) {
451 uint32_t address = iterator.Get().address_;
452 findBlock(cUnit, address, false /* split */, true /*create*/);
buzbee67bf8852011-08-17 17:51:35 -0700453 }
buzbeee9a72f62011-09-04 17:59:07 -0700454 handlers_ptr = iterator.GetData();
buzbee67bf8852011-08-17 17:51:35 -0700455 }
456}
457
458/* Process instructions with the kInstrCanBranch flag */
buzbeeed3e9302011-09-23 17:34:19 -0700459STATIC void processCanBranch(CompilationUnit* cUnit, BasicBlock* curBlock,
buzbee67bf8852011-08-17 17:51:35 -0700460 MIR* insn, int curOffset, int width, int flags,
461 const u2* codePtr, const u2* codeEnd)
462{
463 int target = curOffset;
464 switch (insn->dalvikInsn.opcode) {
465 case OP_GOTO:
466 case OP_GOTO_16:
467 case OP_GOTO_32:
468 target += (int) insn->dalvikInsn.vA;
469 break;
470 case OP_IF_EQ:
471 case OP_IF_NE:
472 case OP_IF_LT:
473 case OP_IF_GE:
474 case OP_IF_GT:
475 case OP_IF_LE:
476 target += (int) insn->dalvikInsn.vC;
477 break;
478 case OP_IF_EQZ:
479 case OP_IF_NEZ:
480 case OP_IF_LTZ:
481 case OP_IF_GEZ:
482 case OP_IF_GTZ:
483 case OP_IF_LEZ:
484 target += (int) insn->dalvikInsn.vB;
485 break;
486 default:
487 LOG(FATAL) << "Unexpected opcode(" << (int)insn->dalvikInsn.opcode
488 << ") with kInstrCanBranch set";
489 }
490 BasicBlock *takenBlock = findBlock(cUnit, target,
491 /* split */
492 true,
493 /* create */
494 true);
495 curBlock->taken = takenBlock;
496 oatSetBit(takenBlock->predecessors, curBlock->id);
497
498 /* Always terminate the current block for conditional branches */
499 if (flags & kInstrCanContinue) {
500 BasicBlock *fallthroughBlock = findBlock(cUnit,
501 curOffset + width,
502 /*
503 * If the method is processed
504 * in sequential order from the
505 * beginning, we don't need to
506 * specify split for continue
507 * blocks. However, this
508 * routine can be called by
509 * compileLoop, which starts
510 * parsing the method from an
511 * arbitrary address in the
512 * method body.
513 */
514 true,
515 /* create */
516 true);
517 curBlock->fallThrough = fallthroughBlock;
518 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
519 } else if (codePtr < codeEnd) {
520 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
521 if (contentIsInsn(codePtr)) {
522 findBlock(cUnit, curOffset + width,
523 /* split */
524 false,
525 /* create */
526 true);
527 }
528 }
529}
530
531/* Process instructions with the kInstrCanSwitch flag */
buzbeeed3e9302011-09-23 17:34:19 -0700532STATIC void processCanSwitch(CompilationUnit* cUnit, BasicBlock* curBlock,
buzbee67bf8852011-08-17 17:51:35 -0700533 MIR* insn, int curOffset, int width, int flags)
534{
535 u2* switchData= (u2 *) (cUnit->insns + curOffset +
536 insn->dalvikInsn.vB);
537 int size;
538 int* keyTable;
539 int* targetTable;
540 int i;
541 int firstKey;
542
543 /*
544 * Packed switch data format:
545 * ushort ident = 0x0100 magic value
546 * ushort size number of entries in the table
547 * int first_key first (and lowest) switch case value
548 * int targets[size] branch targets, relative to switch opcode
549 *
550 * Total size is (4+size*2) 16-bit code units.
551 */
552 if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
buzbeeed3e9302011-09-23 17:34:19 -0700553 DCHECK_EQ(switchData[0], kPackedSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700554 size = switchData[1];
555 firstKey = switchData[2] | (switchData[3] << 16);
556 targetTable = (int *) &switchData[4];
557 keyTable = NULL; // Make the compiler happy
558 /*
559 * Sparse switch data format:
560 * ushort ident = 0x0200 magic value
561 * ushort size number of entries in the table; > 0
562 * int keys[size] keys, sorted low-to-high; 32-bit aligned
563 * int targets[size] branch targets, relative to switch opcode
564 *
565 * Total size is (2+size*4) 16-bit code units.
566 */
567 } else {
buzbeeed3e9302011-09-23 17:34:19 -0700568 DCHECK_EQ(switchData[0], kSparseSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700569 size = switchData[1];
570 keyTable = (int *) &switchData[2];
571 targetTable = (int *) &switchData[2 + size*2];
572 firstKey = 0; // To make the compiler happy
573 }
574
575 if (curBlock->successorBlockList.blockListType != kNotUsed) {
576 LOG(FATAL) << "Successor block list already in use: " <<
577 (int)curBlock->successorBlockList.blockListType;
578 }
579 curBlock->successorBlockList.blockListType =
580 (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
581 kPackedSwitch : kSparseSwitch;
582 oatInitGrowableList(&curBlock->successorBlockList.blocks, size);
583
584 for (i = 0; i < size; i++) {
585 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
586 /* split */
587 true,
588 /* create */
589 true);
590 SuccessorBlockInfo *successorBlockInfo =
591 (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
592 false);
593 successorBlockInfo->block = caseBlock;
594 successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)?
595 firstKey + i : keyTable[i];
596 oatInsertGrowableList(&curBlock->successorBlockList.blocks,
597 (intptr_t) successorBlockInfo);
598 oatSetBit(caseBlock->predecessors, curBlock->id);
599 }
600
601 /* Fall-through case */
602 BasicBlock* fallthroughBlock = findBlock(cUnit,
603 curOffset + width,
604 /* split */
605 false,
606 /* create */
607 true);
608 curBlock->fallThrough = fallthroughBlock;
609 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
610}
611
612/* Process instructions with the kInstrCanThrow flag */
buzbeeed3e9302011-09-23 17:34:19 -0700613STATIC void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock,
buzbee67bf8852011-08-17 17:51:35 -0700614 MIR* insn, int curOffset, int width, int flags,
615 ArenaBitVector* tryBlockAddr, const u2* codePtr,
616 const u2* codeEnd)
617{
buzbeee9a72f62011-09-04 17:59:07 -0700618
buzbee67bf8852011-08-17 17:51:35 -0700619 const Method* method = cUnit->method;
buzbeee9a72f62011-09-04 17:59:07 -0700620 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
621 const art::DexFile& dex_file = class_linker->FindDexFile(
622 method->GetDeclaringClass()->GetDexCache());
623 const art::DexFile::CodeItem* code_item =
624 dex_file.GetCodeItem(method->GetCodeItemOffset());
buzbee67bf8852011-08-17 17:51:35 -0700625
626 /* In try block */
627 if (oatIsBitSet(tryBlockAddr, curOffset)) {
buzbeee9a72f62011-09-04 17:59:07 -0700628 art::DexFile::CatchHandlerIterator iterator =
629 art::DexFile::dexFindCatchHandler(*code_item, curOffset);
buzbee67bf8852011-08-17 17:51:35 -0700630
buzbee67bf8852011-08-17 17:51:35 -0700631 if (curBlock->successorBlockList.blockListType != kNotUsed) {
632 LOG(FATAL) << "Successor block list already in use: " <<
633 (int)curBlock->successorBlockList.blockListType;
634 }
buzbeee9a72f62011-09-04 17:59:07 -0700635
buzbee67bf8852011-08-17 17:51:35 -0700636 curBlock->successorBlockList.blockListType = kCatch;
637 oatInitGrowableList(&curBlock->successorBlockList.blocks, 2);
638
buzbeee9a72f62011-09-04 17:59:07 -0700639 for (;!iterator.HasNext(); iterator.Next()) {
640 BasicBlock *catchBlock = findBlock(cUnit, iterator.Get().address_,
641 false /* split*/,
642 false /* creat */);
buzbee43a36422011-09-14 14:00:13 -0700643 catchBlock->catchEntry = true;
buzbee67bf8852011-08-17 17:51:35 -0700644 SuccessorBlockInfo *successorBlockInfo =
buzbeee9a72f62011-09-04 17:59:07 -0700645 (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
646 false);
buzbee67bf8852011-08-17 17:51:35 -0700647 successorBlockInfo->block = catchBlock;
buzbeee9a72f62011-09-04 17:59:07 -0700648 successorBlockInfo->key = iterator.Get().type_idx_;
buzbee67bf8852011-08-17 17:51:35 -0700649 oatInsertGrowableList(&curBlock->successorBlockList.blocks,
650 (intptr_t) successorBlockInfo);
651 oatSetBit(catchBlock->predecessors, curBlock->id);
652 }
653 } else {
654 BasicBlock *ehBlock = oatNewBB(kExceptionHandling,
655 cUnit->numBlocks++);
656 curBlock->taken = ehBlock;
657 oatInsertGrowableList(&cUnit->blockList, (intptr_t) ehBlock);
658 ehBlock->startOffset = curOffset;
659 oatSetBit(ehBlock->predecessors, curBlock->id);
660 }
661
662 /*
663 * Force the current block to terminate.
664 *
665 * Data may be present before codeEnd, so we need to parse it to know
666 * whether it is code or data.
667 */
668 if (codePtr < codeEnd) {
669 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
670 if (contentIsInsn(codePtr)) {
671 BasicBlock *fallthroughBlock = findBlock(cUnit,
672 curOffset + width,
673 /* split */
674 false,
675 /* create */
676 true);
677 /*
678 * OP_THROW and OP_THROW_VERIFICATION_ERROR are unconditional
679 * branches.
680 */
681 if (insn->dalvikInsn.opcode != OP_THROW_VERIFICATION_ERROR &&
682 insn->dalvikInsn.opcode != OP_THROW) {
683 curBlock->fallThrough = fallthroughBlock;
684 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
685 }
686 }
687 }
688}
689
690/*
691 * Compile a method.
692 */
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700693CompiledMethod* oatCompileMethod(const Compiler& compiler, const Method* method, art::InstructionSet insnSet)
buzbee67bf8852011-08-17 17:51:35 -0700694{
Brian Carlstrom16192862011-09-12 17:50:06 -0700695 if (compiler.IsVerbose()) {
696 LOG(INFO) << "Compiling " << PrettyMethod(method) << "...";
697 }
buzbee2a475e72011-09-07 17:19:17 -0700698 oatArenaReset();
Brian Carlstrom94496d32011-08-22 09:22:47 -0700699
buzbeec143c552011-08-20 17:38:58 -0700700 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
701 const art::DexFile& dex_file = class_linker->FindDexFile(
702 method->GetDeclaringClass()->GetDexCache());
703 const art::DexFile::CodeItem* code_item =
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700704 dex_file.GetCodeItem(method->GetCodeItemOffset());
buzbeec143c552011-08-20 17:38:58 -0700705 const u2* codePtr = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700706 const u2* codeEnd = code_item->insns_ + code_item->insns_size_in_code_units_;
buzbee67bf8852011-08-17 17:51:35 -0700707 int numBlocks = 0;
708 unsigned int curOffset = 0;
709
Brian Carlstrom16192862011-09-12 17:50:06 -0700710 oatInit(compiler);
buzbee67bf8852011-08-17 17:51:35 -0700711
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700712 UniquePtr<CompilationUnit> cUnit(new CompilationUnit);
713 memset(cUnit.get(), 0, sizeof(*cUnit));
714 cUnit->compiler = &compiler;
715 cUnit->method = method;
716 cUnit->instructionSet = (OatInstructionSetType)insnSet;
717 cUnit->insns = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700718 cUnit->insnsSize = code_item->insns_size_in_code_units_;
buzbeece302932011-10-04 14:32:18 -0700719 bool useMatch = compilerMethodMatch.length() != 0;
720 bool match = useMatch && (compilerFlipMatch ^
721 (PrettyMethod(method).find(compilerMethodMatch) != std::string::npos));
722 if (!useMatch || match) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700723 cUnit->disableOpt = compilerOptimizerDisableFlags;
724 cUnit->enableDebug = compilerDebugFlags;
725 cUnit->printMe = compiler.IsVerbose() || (cUnit->enableDebug & (1 << kDebugVerbose));
buzbeece302932011-10-04 14:32:18 -0700726 }
buzbee67bf8852011-08-17 17:51:35 -0700727
buzbeecefd1872011-09-09 09:59:52 -0700728 /* Assume non-throwing leaf */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700729 cUnit->attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
buzbeecefd1872011-09-09 09:59:52 -0700730
buzbee67bf8852011-08-17 17:51:35 -0700731 /* Initialize the block list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700732 oatInitGrowableList(&cUnit->blockList, 40);
buzbee67bf8852011-08-17 17:51:35 -0700733
734 /* Initialize the switchTables list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700735 oatInitGrowableList(&cUnit->switchTables, 4);
buzbee67bf8852011-08-17 17:51:35 -0700736
737 /* Intialize the fillArrayData list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700738 oatInitGrowableList(&cUnit->fillArrayData, 4);
buzbee67bf8852011-08-17 17:51:35 -0700739
buzbee5ade1d22011-09-09 14:44:52 -0700740 /* Intialize the throwLaunchpads list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700741 oatInitGrowableList(&cUnit->throwLaunchpads, 4);
buzbee5ade1d22011-09-09 14:44:52 -0700742
buzbeec1f45042011-09-21 16:03:19 -0700743 /* Intialize the suspendLaunchpads list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700744 oatInitGrowableList(&cUnit->suspendLaunchpads, 4);
buzbeec1f45042011-09-21 16:03:19 -0700745
buzbee67bf8852011-08-17 17:51:35 -0700746 /* Allocate the bit-vector to track the beginning of basic blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700747 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit->insnsSize,
buzbee67bf8852011-08-17 17:51:35 -0700748 true /* expandable */);
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700749 cUnit->tryBlockAddr = tryBlockAddr;
buzbee67bf8852011-08-17 17:51:35 -0700750
751 /* Create the default entry and exit blocks and enter them to the list */
752 BasicBlock *entryBlock = oatNewBB(kEntryBlock, numBlocks++);
753 BasicBlock *exitBlock = oatNewBB(kExitBlock, numBlocks++);
754
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700755 cUnit->entryBlock = entryBlock;
756 cUnit->exitBlock = exitBlock;
buzbee67bf8852011-08-17 17:51:35 -0700757
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700758 oatInsertGrowableList(&cUnit->blockList, (intptr_t) entryBlock);
759 oatInsertGrowableList(&cUnit->blockList, (intptr_t) exitBlock);
buzbee67bf8852011-08-17 17:51:35 -0700760
761 /* Current block to record parsed instructions */
762 BasicBlock *curBlock = oatNewBB(kDalvikByteCode, numBlocks++);
763 curBlock->startOffset = 0;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700764 oatInsertGrowableList(&cUnit->blockList, (intptr_t) curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700765 entryBlock->fallThrough = curBlock;
766 oatSetBit(curBlock->predecessors, entryBlock->id);
767
768 /*
769 * Store back the number of blocks since new blocks may be created of
770 * accessing cUnit.
771 */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700772 cUnit->numBlocks = numBlocks;
buzbee67bf8852011-08-17 17:51:35 -0700773
774 /* Identify code range in try blocks and set up the empty catch blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700775 processTryCatchBlocks(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700776
777 /* Parse all instructions and put them into containing basic blocks */
778 while (codePtr < codeEnd) {
779 MIR *insn = (MIR *) oatNew(sizeof(MIR), true);
780 insn->offset = curOffset;
781 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
782 insn->width = width;
783
784 /* Terminate when the data section is seen */
785 if (width == 0)
786 break;
787
788 oatAppendMIR(curBlock, insn);
789
790 codePtr += width;
791 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
792
793 if (flags & kInstrCanBranch) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700794 processCanBranch(cUnit.get(), curBlock, insn, curOffset, width, flags,
buzbee67bf8852011-08-17 17:51:35 -0700795 codePtr, codeEnd);
796 } else if (flags & kInstrCanReturn) {
797 curBlock->fallThrough = exitBlock;
798 oatSetBit(exitBlock->predecessors, curBlock->id);
799 /*
800 * Terminate the current block if there are instructions
801 * afterwards.
802 */
803 if (codePtr < codeEnd) {
804 /*
805 * Create a fallthrough block for real instructions
806 * (incl. OP_NOP).
807 */
808 if (contentIsInsn(codePtr)) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700809 findBlock(cUnit.get(), curOffset + width,
buzbee67bf8852011-08-17 17:51:35 -0700810 /* split */
811 false,
812 /* create */
813 true);
814 }
815 }
816 } else if (flags & kInstrCanThrow) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700817 processCanThrow(cUnit.get(), curBlock, insn, curOffset, width, flags,
buzbee67bf8852011-08-17 17:51:35 -0700818 tryBlockAddr, codePtr, codeEnd);
819 } else if (flags & kInstrCanSwitch) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700820 processCanSwitch(cUnit.get(), curBlock, insn, curOffset, width, flags);
buzbee67bf8852011-08-17 17:51:35 -0700821 }
822 curOffset += width;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700823 BasicBlock *nextBlock = findBlock(cUnit.get(), curOffset,
buzbee67bf8852011-08-17 17:51:35 -0700824 /* split */
825 false,
826 /* create */
827 false);
828 if (nextBlock) {
829 /*
830 * The next instruction could be the target of a previously parsed
831 * forward branch so a block is already created. If the current
832 * instruction is not an unconditional branch, connect them through
833 * the fall-through link.
834 */
buzbeeed3e9302011-09-23 17:34:19 -0700835 DCHECK(curBlock->fallThrough == NULL ||
buzbee67bf8852011-08-17 17:51:35 -0700836 curBlock->fallThrough == nextBlock ||
837 curBlock->fallThrough == exitBlock);
838
839 if ((curBlock->fallThrough == NULL) &&
840 (flags & kInstrCanContinue)) {
841 curBlock->fallThrough = nextBlock;
842 oatSetBit(nextBlock->predecessors, curBlock->id);
843 }
844 curBlock = nextBlock;
845 }
846 }
847
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700848 if (cUnit->printMe) {
849 oatDumpCompilationUnit(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700850 }
851
852 /* Adjust this value accordingly once inlining is performed */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700853 cUnit->numDalvikRegisters = cUnit->method->NumRegisters();
buzbee67bf8852011-08-17 17:51:35 -0700854
855
856 /* Verify if all blocks are connected as claimed */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700857 oatDataFlowAnalysisDispatcher(cUnit.get(), verifyPredInfo, kAllNodes, false /* isIterative */);
buzbee67bf8852011-08-17 17:51:35 -0700858
859 /* Perform SSA transformation for the whole method */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700860 oatMethodSSATransformation(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700861
buzbee43a36422011-09-14 14:00:13 -0700862 /* Perform null check elimination */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700863 oatMethodNullCheckElimination(cUnit.get());
buzbee43a36422011-09-14 14:00:13 -0700864
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700865 oatInitializeRegAlloc(cUnit.get()); // Needs to happen after SSA naming
buzbee67bf8852011-08-17 17:51:35 -0700866
867 /* Allocate Registers using simple local allocation scheme */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700868 oatSimpleRegAlloc(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700869
870 /* Convert MIR to LIR, etc. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700871 oatMethodMIR2LIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700872
873 // Debugging only
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700874 if (cUnit->enableDebug & (1 << kDebugDumpCFG)) {
875 oatDumpCFG(cUnit.get(), "/sdcard/cfg/");
buzbeeec5adf32011-09-11 15:25:43 -0700876 }
buzbee67bf8852011-08-17 17:51:35 -0700877
878 /* Method is not empty */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700879 if (cUnit->firstLIRInsn) {
buzbee67bf8852011-08-17 17:51:35 -0700880
881 // mark the targets of switch statement case labels
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700882 oatProcessSwitchTables(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700883
884 /* Convert LIR into machine code. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700885 oatAssembleLIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700886
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700887 if (cUnit->printMe) {
888 oatCodegenDump(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700889 }
890 }
891
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700892 // Combine vmap tables - core regs, then fp regs - into vmapTable
893 std::vector<uint16_t> vmapTable;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700894 for (size_t i = 0 ; i < cUnit->coreVmapTable.size(); i++) {
895 vmapTable.push_back(cUnit->coreVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700896 }
buzbeec41e5b52011-09-23 12:46:19 -0700897 // Add a marker to take place of lr
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -0700898 vmapTable.push_back(INVALID_VREG);
buzbeec41e5b52011-09-23 12:46:19 -0700899 // Combine vmap tables - core regs, then fp regs
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700900 for (uint32_t i = 0; i < cUnit->fpVmapTable.size(); i++) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700901 vmapTable.push_back(cUnit->fpVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700902 }
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -0700903 DCHECK_EQ(vmapTable.size(),
904 static_cast<uint32_t>(__builtin_popcount(cUnit->coreSpillMask)
905 + __builtin_popcount(cUnit->fpSpillMask)));
906 DCHECK_GE(vmapTable.size(), 1U); // should always at least one INVALID_VREG for lr
907
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700908 CompiledMethod* result = new CompiledMethod(art::kThumb2,
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700909 cUnit->codeBuffer, cUnit->frameSize, cUnit->frameSize - sizeof(intptr_t),
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -0700910 cUnit->coreSpillMask, cUnit->fpSpillMask, cUnit->mappingTable, vmapTable);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700911
Brian Carlstrom16192862011-09-12 17:50:06 -0700912 if (compiler.IsVerbose()) {
913 LOG(INFO) << "Compiled " << PrettyMethod(method)
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700914 << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0])) << " bytes)";
Brian Carlstrom16192862011-09-12 17:50:06 -0700915 }
buzbee67bf8852011-08-17 17:51:35 -0700916
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700917 return result;
buzbee67bf8852011-08-17 17:51:35 -0700918}
919
Brian Carlstrom16192862011-09-12 17:50:06 -0700920void oatInit(const Compiler& compiler)
buzbee67bf8852011-08-17 17:51:35 -0700921{
buzbee67bf8852011-08-17 17:51:35 -0700922 static bool initialized = false;
923 if (initialized)
924 return;
925 initialized = true;
Brian Carlstrom16192862011-09-12 17:50:06 -0700926 if (compiler.IsVerbose()) {
927 LOG(INFO) << "Initializing compiler";
928 }
buzbee67bf8852011-08-17 17:51:35 -0700929 if (!oatArchInit()) {
930 LOG(FATAL) << "Failed to initialize oat";
931 }
932 if (!oatHeapInit()) {
933 LOG(FATAL) << "Failed to initialize oat heap";
934 }
935}