blob: 3b03a35f006d7c0fa01bf8f81693a15c68b63518 [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"
Ian Rogers0571d352011-11-03 19:51:38 -070021#include "leb128.h"
Brian Carlstrom9baa4ae2011-09-01 21:14:14 -070022#include "object.h"
Brian Carlstrom1f870082011-08-23 16:02:11 -070023#include "runtime.h"
buzbee67bf8852011-08-17 17:51:35 -070024
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080025namespace art {
26
buzbeece302932011-10-04 14:32:18 -070027/* Default optimizer/debug setting for the compiler. */
28uint32_t compilerOptimizerDisableFlags = 0 | // Disable specific optimizations
buzbee67bc2362011-10-11 18:08:40 -070029 //(1 << kLoadStoreElimination) |
30 //(1 << kLoadHoisting) |
31 //(1 << kSuppressLoads) |
32 //(1 << kNullCheckElimination) |
buzbee769fde12012-01-05 17:35:23 -080033 //(1 << kPromoteRegs) |
34 //(1 << kTrackLiveTemps) |
buzbee99ba9642012-01-25 14:23:14 -080035 //(1 << kSkipLargeMethodOptimization) |
buzbee44b412b2012-02-04 08:50:53 -080036 //(1 << kGenCodeForDebugger) |
buzbeece302932011-10-04 14:32:18 -070037 0;
38
39uint32_t compilerDebugFlags = 0 | // Enable debug/testing modes
buzbeee3de7492011-10-05 13:37:17 -070040 //(1 << kDebugDisplayMissingTargets) |
buzbeece302932011-10-04 14:32:18 -070041 //(1 << kDebugVerbose) |
42 //(1 << kDebugDumpCFG) |
43 //(1 << kDebugSlowFieldPath) |
44 //(1 << kDebugSlowInvokePath) |
45 //(1 << kDebugSlowStringPath) |
46 //(1 << kDebugSlowestFieldPath) |
47 //(1 << kDebugSlowestStringPath) |
buzbee34c77ad2012-01-11 13:01:32 -080048 //(1 << kDebugExerciseResolveMethod) |
buzbee5b537102012-01-17 17:33:47 -080049 //(1 << kDebugVerifyDataflow) |
buzbee5abfa3e2012-01-31 17:01:43 -080050 //(1 << kDebugShowMemoryUsage) |
buzbeece302932011-10-04 14:32:18 -070051 0;
52
buzbeeed3e9302011-09-23 17:34:19 -070053STATIC inline bool contentIsInsn(const u2* codePtr) {
buzbee67bf8852011-08-17 17:51:35 -070054 u2 instr = *codePtr;
55 Opcode opcode = (Opcode)(instr & 0xff);
56
57 /*
58 * Since the low 8-bit in metadata may look like OP_NOP, we need to check
59 * both the low and whole sub-word to determine whether it is code or data.
60 */
61 return (opcode != OP_NOP || instr == 0);
62}
63
64/*
65 * Parse an instruction, return the length of the instruction
66 */
buzbeeba938cb2012-02-03 14:47:55 -080067STATIC inline int parseInsn(CompilationUnit* cUnit, const u2* codePtr,
68 DecodedInstruction* decInsn, bool printMe)
buzbee67bf8852011-08-17 17:51:35 -070069{
70 // Don't parse instruction data
71 if (!contentIsInsn(codePtr)) {
72 return 0;
73 }
74
75 u2 instr = *codePtr;
76 Opcode opcode = dexOpcodeFromCodeUnit(instr);
77
78 dexDecodeInstruction(codePtr, decInsn);
79 if (printMe) {
buzbeeba938cb2012-02-03 14:47:55 -080080 char* decodedString = oatGetDalvikDisassembly(cUnit, decInsn, NULL);
buzbee67bf8852011-08-17 17:51:35 -070081 LOG(INFO) << codePtr << ": 0x" << std::hex << (int)opcode <<
82 " " << decodedString;
83 }
84 return dexGetWidthFromOpcode(opcode);
85}
86
87#define UNKNOWN_TARGET 0xffffffff
88
buzbeeed3e9302011-09-23 17:34:19 -070089STATIC inline bool isGoto(MIR* insn)
buzbee67bf8852011-08-17 17:51:35 -070090{
91 switch (insn->dalvikInsn.opcode) {
92 case OP_GOTO:
93 case OP_GOTO_16:
94 case OP_GOTO_32:
95 return true;
96 default:
97 return false;
98 }
99}
100
101/*
102 * Identify unconditional branch instructions
103 */
buzbeeed3e9302011-09-23 17:34:19 -0700104STATIC inline bool isUnconditionalBranch(MIR* insn)
buzbee67bf8852011-08-17 17:51:35 -0700105{
106 switch (insn->dalvikInsn.opcode) {
107 case OP_RETURN_VOID:
108 case OP_RETURN:
109 case OP_RETURN_WIDE:
110 case OP_RETURN_OBJECT:
111 return true;
112 default:
113 return isGoto(insn);
114 }
115}
116
117/* Split an existing block from the specified code offset into two */
buzbeeed3e9302011-09-23 17:34:19 -0700118STATIC BasicBlock *splitBlock(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -0700119 unsigned int codeOffset,
buzbee9ab05de2012-01-18 15:43:48 -0800120 BasicBlock* origBlock,
121 BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700122{
123 MIR* insn = origBlock->firstMIRInsn;
124 while (insn) {
125 if (insn->offset == codeOffset) break;
126 insn = insn->next;
127 }
128 if (insn == NULL) {
129 LOG(FATAL) << "Break split failed";
130 }
buzbee5abfa3e2012-01-31 17:01:43 -0800131 BasicBlock *bottomBlock = oatNewBB(cUnit, kDalvikByteCode,
132 cUnit->numBlocks++);
buzbeeba938cb2012-02-03 14:47:55 -0800133 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700134
135 bottomBlock->startOffset = codeOffset;
136 bottomBlock->firstMIRInsn = insn;
137 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
138
buzbee5b537102012-01-17 17:33:47 -0800139 /* Add it to the quick lookup cache */
140 cUnit->blockMap.insert(std::make_pair(bottomBlock->startOffset,
141 bottomBlock));
142
buzbee67bf8852011-08-17 17:51:35 -0700143 /* Handle the taken path */
144 bottomBlock->taken = origBlock->taken;
145 if (bottomBlock->taken) {
146 origBlock->taken = NULL;
buzbee5abfa3e2012-01-31 17:01:43 -0800147 oatDeleteGrowableList(bottomBlock->taken->predecessors,
148 (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800149 oatInsertGrowableList(cUnit, bottomBlock->taken->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800150 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700151 }
152
153 /* Handle the fallthrough path */
154 bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
155 bottomBlock->fallThrough = origBlock->fallThrough;
156 origBlock->fallThrough = bottomBlock;
157 origBlock->needFallThroughBranch = true;
buzbeeba938cb2012-02-03 14:47:55 -0800158 oatInsertGrowableList(cUnit, bottomBlock->predecessors,
159 (intptr_t)origBlock);
buzbee67bf8852011-08-17 17:51:35 -0700160 if (bottomBlock->fallThrough) {
buzbee5abfa3e2012-01-31 17:01:43 -0800161 oatDeleteGrowableList(bottomBlock->fallThrough->predecessors,
162 (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800163 oatInsertGrowableList(cUnit, bottomBlock->fallThrough->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800164 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700165 }
166
167 /* Handle the successor list */
168 if (origBlock->successorBlockList.blockListType != kNotUsed) {
169 bottomBlock->successorBlockList = origBlock->successorBlockList;
170 origBlock->successorBlockList.blockListType = kNotUsed;
171 GrowableListIterator iterator;
172
173 oatGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
174 &iterator);
175 while (true) {
176 SuccessorBlockInfo *successorBlockInfo =
177 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
178 if (successorBlockInfo == NULL) break;
179 BasicBlock *bb = successorBlockInfo->block;
buzbee5abfa3e2012-01-31 17:01:43 -0800180 oatDeleteGrowableList(bb->predecessors, (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800181 oatInsertGrowableList(cUnit, bb->predecessors,
182 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700183 }
184 }
185
186 origBlock->lastMIRInsn = insn->prev;
187
188 insn->prev->next = NULL;
189 insn->prev = NULL;
buzbee9ab05de2012-01-18 15:43:48 -0800190 /*
191 * Update the immediate predecessor block pointer so that outgoing edges
192 * can be applied to the proper block.
193 */
194 if (immedPredBlockP) {
195 DCHECK_EQ(*immedPredBlockP, origBlock);
196 *immedPredBlockP = bottomBlock;
197 }
buzbee67bf8852011-08-17 17:51:35 -0700198 return bottomBlock;
199}
200
201/*
202 * Given a code offset, find out the block that starts with it. If the offset
buzbee9ab05de2012-01-18 15:43:48 -0800203 * is in the middle of an existing block, split it into two. If immedPredBlockP
204 * is not non-null and is the block being split, update *immedPredBlockP to
205 * point to the bottom block so that outgoing edges can be set up properly
206 * (by the caller)
buzbee5b537102012-01-17 17:33:47 -0800207 * Utilizes a map for fast lookup of the typical cases.
buzbee67bf8852011-08-17 17:51:35 -0700208 */
buzbeeed3e9302011-09-23 17:34:19 -0700209STATIC BasicBlock *findBlock(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -0700210 unsigned int codeOffset,
buzbee9ab05de2012-01-18 15:43:48 -0800211 bool split, bool create,
212 BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700213{
214 GrowableList* blockList = &cUnit->blockList;
215 BasicBlock* bb;
216 unsigned int i;
buzbee5b537102012-01-17 17:33:47 -0800217 std::map<unsigned int, BasicBlock*>::iterator it;
buzbee67bf8852011-08-17 17:51:35 -0700218
buzbee5b537102012-01-17 17:33:47 -0800219 it = cUnit->blockMap.find(codeOffset);
220 if (it != cUnit->blockMap.end()) {
221 return it->second;
222 } else if (!create) {
223 return NULL;
224 }
225
226 if (split) {
227 for (i = 0; i < blockList->numUsed; i++) {
228 bb = (BasicBlock *) blockList->elemList[i];
229 if (bb->blockType != kDalvikByteCode) continue;
230 /* Check if a branch jumps into the middle of an existing block */
231 if ((codeOffset > bb->startOffset) && (bb->lastMIRInsn != NULL) &&
232 (codeOffset <= bb->lastMIRInsn->offset)) {
233 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb,
234 bb == *immedPredBlockP ?
235 immedPredBlockP : NULL);
236 return newBB;
237 }
buzbee67bf8852011-08-17 17:51:35 -0700238 }
239 }
buzbee5b537102012-01-17 17:33:47 -0800240
241 /* Create a new one */
buzbee5abfa3e2012-01-31 17:01:43 -0800242 bb = oatNewBB(cUnit, kDalvikByteCode, cUnit->numBlocks++);
buzbeeba938cb2012-02-03 14:47:55 -0800243 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) bb);
buzbee5b537102012-01-17 17:33:47 -0800244 bb->startOffset = codeOffset;
245 cUnit->blockMap.insert(std::make_pair(bb->startOffset, bb));
246 return bb;
buzbee67bf8852011-08-17 17:51:35 -0700247}
248
249/* Dump the CFG into a DOT graph */
250void oatDumpCFG(CompilationUnit* cUnit, const char* dirPrefix)
251{
buzbee67bf8852011-08-17 17:51:35 -0700252 FILE* file;
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800253 std::string name(PrettyMethod(cUnit->method_idx, *cUnit->dex_file));
buzbee67bf8852011-08-17 17:51:35 -0700254 char startOffset[80];
255 sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
buzbeeba938cb2012-02-03 14:47:55 -0800256 char* fileName = (char*) oatNew(cUnit,
buzbeec143c552011-08-20 17:38:58 -0700257 strlen(dirPrefix) +
258 name.length() +
buzbee5abfa3e2012-01-31 17:01:43 -0800259 strlen(".dot") + 1, true, kAllocDebugInfo);
buzbeec143c552011-08-20 17:38:58 -0700260 sprintf(fileName, "%s%s%s.dot", dirPrefix, name.c_str(), startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700261
262 /*
263 * Convert the special characters into a filesystem- and shell-friendly
264 * format.
265 */
266 int i;
267 for (i = strlen(dirPrefix); fileName[i]; i++) {
268 if (fileName[i] == '/') {
269 fileName[i] = '_';
270 } else if (fileName[i] == ';') {
271 fileName[i] = '#';
272 } else if (fileName[i] == '$') {
273 fileName[i] = '+';
274 } else if (fileName[i] == '(' || fileName[i] == ')') {
275 fileName[i] = '@';
276 } else if (fileName[i] == '<' || fileName[i] == '>') {
277 fileName[i] = '=';
278 }
279 }
280 file = fopen(fileName, "w");
281 if (file == NULL) {
282 return;
283 }
284 fprintf(file, "digraph G {\n");
285
286 fprintf(file, " rankdir=TB\n");
287
288 int numReachableBlocks = cUnit->numReachableBlocks;
289 int idx;
290 const GrowableList *blockList = &cUnit->blockList;
291
292 for (idx = 0; idx < numReachableBlocks; idx++) {
293 int blockIdx = cUnit->dfsOrder.elemList[idx];
294 BasicBlock *bb = (BasicBlock *) oatGrowableListGetElement(blockList,
295 blockIdx);
296 if (bb == NULL) break;
297 if (bb->blockType == kEntryBlock) {
298 fprintf(file, " entry [shape=Mdiamond];\n");
299 } else if (bb->blockType == kExitBlock) {
300 fprintf(file, " exit [shape=Mdiamond];\n");
301 } else if (bb->blockType == kDalvikByteCode) {
302 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
303 bb->startOffset);
304 const MIR *mir;
305 fprintf(file, " {block id %d\\l}%s\\\n", bb->id,
306 bb->firstMIRInsn ? " | " : " ");
307 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
308 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
309 mir->ssaRep ?
310 oatFullDisassembler(cUnit, mir) :
311 dexGetOpcodeName(mir->dalvikInsn.opcode),
312 mir->next ? " | " : " ");
313 }
314 fprintf(file, " }\"];\n\n");
315 } else if (bb->blockType == kExceptionHandling) {
316 char blockName[BLOCK_NAME_LEN];
317
318 oatGetBlockName(bb, blockName);
319 fprintf(file, " %s [shape=invhouse];\n", blockName);
320 }
321
322 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
323
324 if (bb->taken) {
325 oatGetBlockName(bb, blockName1);
326 oatGetBlockName(bb->taken, blockName2);
327 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
328 blockName1, blockName2);
329 }
330 if (bb->fallThrough) {
331 oatGetBlockName(bb, blockName1);
332 oatGetBlockName(bb->fallThrough, blockName2);
333 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
334 }
335
336 if (bb->successorBlockList.blockListType != kNotUsed) {
337 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
338 bb->startOffset,
339 (bb->successorBlockList.blockListType == kCatch) ?
340 "Mrecord" : "record");
341 GrowableListIterator iterator;
342 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
343 &iterator);
344 SuccessorBlockInfo *successorBlockInfo =
345 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
346
347 int succId = 0;
348 while (true) {
349 if (successorBlockInfo == NULL) break;
350
351 BasicBlock *destBlock = successorBlockInfo->block;
352 SuccessorBlockInfo *nextSuccessorBlockInfo =
353 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
354
355 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
356 succId++,
357 successorBlockInfo->key,
358 destBlock->startOffset,
359 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
360
361 successorBlockInfo = nextSuccessorBlockInfo;
362 }
363 fprintf(file, " }\"];\n\n");
364
365 oatGetBlockName(bb, blockName1);
366 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
367 blockName1, bb->startOffset);
368
369 if (bb->successorBlockList.blockListType == kPackedSwitch ||
370 bb->successorBlockList.blockListType == kSparseSwitch) {
371
372 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
373 &iterator);
374
375 succId = 0;
376 while (true) {
377 SuccessorBlockInfo *successorBlockInfo =
378 (SuccessorBlockInfo *)
379 oatGrowableListIteratorNext(&iterator);
380 if (successorBlockInfo == NULL) break;
381
382 BasicBlock *destBlock = successorBlockInfo->block;
383
384 oatGetBlockName(destBlock, blockName2);
385 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
386 bb->startOffset, succId++,
387 blockName2);
388 }
389 }
390 }
391 fprintf(file, "\n");
392
buzbeece302932011-10-04 14:32:18 -0700393 /* Display the dominator tree */
buzbee67bf8852011-08-17 17:51:35 -0700394 oatGetBlockName(bb, blockName1);
395 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
396 blockName1, blockName1);
397 if (bb->iDom) {
398 oatGetBlockName(bb->iDom, blockName2);
399 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
400 blockName2, blockName1);
401 }
buzbee67bf8852011-08-17 17:51:35 -0700402 }
403 fprintf(file, "}\n");
404 fclose(file);
405}
406
407/* Verify if all the successor is connected with all the claimed predecessors */
buzbeeed3e9302011-09-23 17:34:19 -0700408STATIC bool verifyPredInfo(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -0700409{
buzbee5abfa3e2012-01-31 17:01:43 -0800410 GrowableListIterator iter;
buzbee67bf8852011-08-17 17:51:35 -0700411
buzbee5abfa3e2012-01-31 17:01:43 -0800412 oatGrowableListIteratorInit(bb->predecessors, &iter);
buzbee67bf8852011-08-17 17:51:35 -0700413 while (true) {
buzbee5abfa3e2012-01-31 17:01:43 -0800414 BasicBlock *predBB = (BasicBlock*)oatGrowableListIteratorNext(&iter);
415 if (!predBB) break;
buzbee67bf8852011-08-17 17:51:35 -0700416 bool found = false;
417 if (predBB->taken == bb) {
418 found = true;
419 } else if (predBB->fallThrough == bb) {
420 found = true;
421 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
422 GrowableListIterator iterator;
423 oatGrowableListIteratorInit(&predBB->successorBlockList.blocks,
424 &iterator);
425 while (true) {
426 SuccessorBlockInfo *successorBlockInfo =
427 (SuccessorBlockInfo *)
428 oatGrowableListIteratorNext(&iterator);
429 if (successorBlockInfo == NULL) break;
430 BasicBlock *succBB = successorBlockInfo->block;
431 if (succBB == bb) {
432 found = true;
433 break;
434 }
435 }
436 }
437 if (found == false) {
438 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
439 oatGetBlockName(bb, blockName1);
440 oatGetBlockName(predBB, blockName2);
441 oatDumpCFG(cUnit, "/sdcard/cfg/");
442 LOG(FATAL) << "Successor " << blockName1 << "not found from "
443 << blockName2;
444 }
445 }
446 return true;
447}
448
449/* Identify code range in try blocks and set up the empty catch blocks */
buzbeeed3e9302011-09-23 17:34:19 -0700450STATIC void processTryCatchBlocks(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700451{
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800452 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbeee9a72f62011-09-04 17:59:07 -0700453 int triesSize = code_item->tries_size_;
buzbee67bf8852011-08-17 17:51:35 -0700454 int offset;
455
456 if (triesSize == 0) {
457 return;
458 }
459
buzbee67bf8852011-08-17 17:51:35 -0700460 ArenaBitVector* tryBlockAddr = cUnit->tryBlockAddr;
461
buzbeee9a72f62011-09-04 17:59:07 -0700462 for (int i = 0; i < triesSize; i++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800463 const DexFile::TryItem* pTry =
464 DexFile::GetTryItems(*code_item, i);
buzbeee9a72f62011-09-04 17:59:07 -0700465 int startOffset = pTry->start_addr_;
466 int endOffset = startOffset + pTry->insn_count_;
buzbee67bf8852011-08-17 17:51:35 -0700467 for (offset = startOffset; offset < endOffset; offset++) {
buzbeeba938cb2012-02-03 14:47:55 -0800468 oatSetBit(cUnit, tryBlockAddr, offset);
buzbee67bf8852011-08-17 17:51:35 -0700469 }
470 }
471
buzbeee9a72f62011-09-04 17:59:07 -0700472 // Iterate over each of the handlers to enqueue the empty Catch blocks
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800473 const byte* handlers_ptr =
474 DexFile::GetCatchHandlerData(*code_item, 0);
475 uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
buzbeee9a72f62011-09-04 17:59:07 -0700476 for (uint32_t idx = 0; idx < handlers_size; idx++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800477 CatchHandlerIterator iterator(handlers_ptr);
Ian Rogers0571d352011-11-03 19:51:38 -0700478 for (; iterator.HasNext(); iterator.Next()) {
479 uint32_t address = iterator.GetHandlerAddress();
buzbee9ab05de2012-01-18 15:43:48 -0800480 findBlock(cUnit, address, false /* split */, true /*create*/,
481 /* immedPredBlockP */ NULL);
buzbee67bf8852011-08-17 17:51:35 -0700482 }
Ian Rogers0571d352011-11-03 19:51:38 -0700483 handlers_ptr = iterator.EndDataPointer();
buzbee67bf8852011-08-17 17:51:35 -0700484 }
485}
486
487/* Process instructions with the kInstrCanBranch flag */
buzbeee941e2c2011-12-05 12:38:17 -0800488STATIC BasicBlock* processCanBranch(CompilationUnit* cUnit,
489 BasicBlock* curBlock, MIR* insn,
490 int curOffset, int width, int flags,
491 const u2* codePtr, const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700492{
493 int target = curOffset;
494 switch (insn->dalvikInsn.opcode) {
495 case OP_GOTO:
496 case OP_GOTO_16:
497 case OP_GOTO_32:
498 target += (int) insn->dalvikInsn.vA;
499 break;
500 case OP_IF_EQ:
501 case OP_IF_NE:
502 case OP_IF_LT:
503 case OP_IF_GE:
504 case OP_IF_GT:
505 case OP_IF_LE:
506 target += (int) insn->dalvikInsn.vC;
507 break;
508 case OP_IF_EQZ:
509 case OP_IF_NEZ:
510 case OP_IF_LTZ:
511 case OP_IF_GEZ:
512 case OP_IF_GTZ:
513 case OP_IF_LEZ:
514 target += (int) insn->dalvikInsn.vB;
515 break;
516 default:
517 LOG(FATAL) << "Unexpected opcode(" << (int)insn->dalvikInsn.opcode
518 << ") with kInstrCanBranch set";
519 }
520 BasicBlock *takenBlock = findBlock(cUnit, target,
521 /* split */
522 true,
523 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800524 true,
525 /* immedPredBlockP */
526 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700527 curBlock->taken = takenBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800528 oatInsertGrowableList(cUnit, takenBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700529
530 /* Always terminate the current block for conditional branches */
531 if (flags & kInstrCanContinue) {
532 BasicBlock *fallthroughBlock = findBlock(cUnit,
533 curOffset + width,
534 /*
535 * If the method is processed
536 * in sequential order from the
537 * beginning, we don't need to
538 * specify split for continue
539 * blocks. However, this
540 * routine can be called by
541 * compileLoop, which starts
542 * parsing the method from an
543 * arbitrary address in the
544 * method body.
545 */
546 true,
547 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800548 true,
549 /* immedPredBlockP */
550 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700551 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800552 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800553 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700554 } else if (codePtr < codeEnd) {
555 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
556 if (contentIsInsn(codePtr)) {
557 findBlock(cUnit, curOffset + width,
558 /* split */
559 false,
560 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800561 true,
562 /* immedPredBlockP */
563 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700564 }
565 }
buzbeee941e2c2011-12-05 12:38:17 -0800566 return curBlock;
buzbee67bf8852011-08-17 17:51:35 -0700567}
568
569/* Process instructions with the kInstrCanSwitch flag */
buzbeeed3e9302011-09-23 17:34:19 -0700570STATIC void processCanSwitch(CompilationUnit* cUnit, BasicBlock* curBlock,
buzbee67bf8852011-08-17 17:51:35 -0700571 MIR* insn, int curOffset, int width, int flags)
572{
573 u2* switchData= (u2 *) (cUnit->insns + curOffset +
574 insn->dalvikInsn.vB);
575 int size;
576 int* keyTable;
577 int* targetTable;
578 int i;
579 int firstKey;
580
581 /*
582 * Packed switch data format:
583 * ushort ident = 0x0100 magic value
584 * ushort size number of entries in the table
585 * int first_key first (and lowest) switch case value
586 * int targets[size] branch targets, relative to switch opcode
587 *
588 * Total size is (4+size*2) 16-bit code units.
589 */
590 if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
buzbeeed3e9302011-09-23 17:34:19 -0700591 DCHECK_EQ(switchData[0], kPackedSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700592 size = switchData[1];
593 firstKey = switchData[2] | (switchData[3] << 16);
594 targetTable = (int *) &switchData[4];
595 keyTable = NULL; // Make the compiler happy
596 /*
597 * Sparse switch data format:
598 * ushort ident = 0x0200 magic value
599 * ushort size number of entries in the table; > 0
600 * int keys[size] keys, sorted low-to-high; 32-bit aligned
601 * int targets[size] branch targets, relative to switch opcode
602 *
603 * Total size is (2+size*4) 16-bit code units.
604 */
605 } else {
buzbeeed3e9302011-09-23 17:34:19 -0700606 DCHECK_EQ(switchData[0], kSparseSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700607 size = switchData[1];
608 keyTable = (int *) &switchData[2];
609 targetTable = (int *) &switchData[2 + size*2];
610 firstKey = 0; // To make the compiler happy
611 }
612
613 if (curBlock->successorBlockList.blockListType != kNotUsed) {
614 LOG(FATAL) << "Successor block list already in use: " <<
615 (int)curBlock->successorBlockList.blockListType;
616 }
617 curBlock->successorBlockList.blockListType =
618 (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
619 kPackedSwitch : kSparseSwitch;
buzbeeba938cb2012-02-03 14:47:55 -0800620 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, size,
buzbee5abfa3e2012-01-31 17:01:43 -0800621 kListSuccessorBlocks);
buzbee67bf8852011-08-17 17:51:35 -0700622
623 for (i = 0; i < size; i++) {
624 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
625 /* split */
626 true,
627 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800628 true,
629 /* immedPredBlockP */
630 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700631 SuccessorBlockInfo *successorBlockInfo =
buzbeeba938cb2012-02-03 14:47:55 -0800632 (SuccessorBlockInfo *) oatNew(cUnit, sizeof(SuccessorBlockInfo),
633 false, kAllocSuccessor);
buzbee67bf8852011-08-17 17:51:35 -0700634 successorBlockInfo->block = caseBlock;
635 successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)?
636 firstKey + i : keyTable[i];
buzbeeba938cb2012-02-03 14:47:55 -0800637 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
buzbee67bf8852011-08-17 17:51:35 -0700638 (intptr_t) successorBlockInfo);
buzbeeba938cb2012-02-03 14:47:55 -0800639 oatInsertGrowableList(cUnit, caseBlock->predecessors,
640 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700641 }
642
643 /* Fall-through case */
644 BasicBlock* fallthroughBlock = findBlock(cUnit,
645 curOffset + width,
646 /* split */
647 false,
648 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800649 true,
650 /* immedPredBlockP */
651 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700652 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800653 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
654 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700655}
656
657/* Process instructions with the kInstrCanThrow flag */
buzbeeed3e9302011-09-23 17:34:19 -0700658STATIC void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock,
buzbee67bf8852011-08-17 17:51:35 -0700659 MIR* insn, int curOffset, int width, int flags,
660 ArenaBitVector* tryBlockAddr, const u2* codePtr,
661 const u2* codeEnd)
662{
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800663 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbee67bf8852011-08-17 17:51:35 -0700664
665 /* In try block */
666 if (oatIsBitSet(tryBlockAddr, curOffset)) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800667 CatchHandlerIterator iterator(*code_item, curOffset);
buzbee67bf8852011-08-17 17:51:35 -0700668
buzbee67bf8852011-08-17 17:51:35 -0700669 if (curBlock->successorBlockList.blockListType != kNotUsed) {
670 LOG(FATAL) << "Successor block list already in use: " <<
671 (int)curBlock->successorBlockList.blockListType;
672 }
buzbeee9a72f62011-09-04 17:59:07 -0700673
buzbee67bf8852011-08-17 17:51:35 -0700674 curBlock->successorBlockList.blockListType = kCatch;
buzbeeba938cb2012-02-03 14:47:55 -0800675 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, 2,
buzbee5abfa3e2012-01-31 17:01:43 -0800676 kListSuccessorBlocks);
buzbee67bf8852011-08-17 17:51:35 -0700677
Ian Rogers0571d352011-11-03 19:51:38 -0700678 for (;iterator.HasNext(); iterator.Next()) {
679 BasicBlock *catchBlock = findBlock(cUnit, iterator.GetHandlerAddress(),
buzbeee9a72f62011-09-04 17:59:07 -0700680 false /* split*/,
buzbee9ab05de2012-01-18 15:43:48 -0800681 false /* creat */,
682 NULL /* immedPredBlockP */);
buzbee43a36422011-09-14 14:00:13 -0700683 catchBlock->catchEntry = true;
buzbeeba938cb2012-02-03 14:47:55 -0800684 SuccessorBlockInfo *successorBlockInfo = (SuccessorBlockInfo *)
685 oatNew(cUnit, sizeof(SuccessorBlockInfo), false,
686 kAllocSuccessor);
buzbee67bf8852011-08-17 17:51:35 -0700687 successorBlockInfo->block = catchBlock;
Ian Rogers0571d352011-11-03 19:51:38 -0700688 successorBlockInfo->key = iterator.GetHandlerTypeIndex();
buzbeeba938cb2012-02-03 14:47:55 -0800689 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
buzbee67bf8852011-08-17 17:51:35 -0700690 (intptr_t) successorBlockInfo);
buzbeeba938cb2012-02-03 14:47:55 -0800691 oatInsertGrowableList(cUnit, catchBlock->predecessors,
692 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700693 }
694 } else {
buzbee5abfa3e2012-01-31 17:01:43 -0800695 BasicBlock *ehBlock = oatNewBB(cUnit, kExceptionHandling,
696 cUnit->numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700697 curBlock->taken = ehBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800698 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) ehBlock);
buzbee67bf8852011-08-17 17:51:35 -0700699 ehBlock->startOffset = curOffset;
buzbeeba938cb2012-02-03 14:47:55 -0800700 oatInsertGrowableList(cUnit, ehBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700701 }
702
703 /*
704 * Force the current block to terminate.
705 *
706 * Data may be present before codeEnd, so we need to parse it to know
707 * whether it is code or data.
708 */
709 if (codePtr < codeEnd) {
710 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
711 if (contentIsInsn(codePtr)) {
712 BasicBlock *fallthroughBlock = findBlock(cUnit,
713 curOffset + width,
714 /* split */
715 false,
716 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800717 true,
718 /* immedPredBlockP */
719 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700720 /*
buzbee510c6052011-10-27 10:47:20 -0700721 * OP_THROW is an unconditional branch. NOTE:
722 * OP_THROW_VERIFICATION_ERROR is also an unconditional
723 * branch, but we shouldn't treat it as such until we have
724 * a dead code elimination pass (which won't be important
725 * until inlining w/ constant propogation is implemented.
buzbee67bf8852011-08-17 17:51:35 -0700726 */
buzbee510c6052011-10-27 10:47:20 -0700727 if (insn->dalvikInsn.opcode != OP_THROW) {
buzbee67bf8852011-08-17 17:51:35 -0700728 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800729 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800730 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700731 }
732 }
733 }
734}
735
736/*
737 * Compile a method.
738 */
Ian Rogers996cc582012-02-14 22:23:29 -0800739CompiledMethod* oatCompileMethod(Compiler& compiler, const DexFile::CodeItem* code_item,
Ian Rogersa3760aa2011-11-14 14:32:37 -0800740 uint32_t access_flags, uint32_t method_idx,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800741 const ClassLoader* class_loader,
742 const DexFile& dex_file, InstructionSet insnSet)
buzbee67bf8852011-08-17 17:51:35 -0700743{
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800744 VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
Brian Carlstrom94496d32011-08-22 09:22:47 -0700745
buzbeec143c552011-08-20 17:38:58 -0700746 const u2* codePtr = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700747 const u2* codeEnd = code_item->insns_ + code_item->insns_size_in_code_units_;
buzbee67bf8852011-08-17 17:51:35 -0700748 int numBlocks = 0;
749 unsigned int curOffset = 0;
750
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800751 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700752 UniquePtr<CompilationUnit> cUnit(new CompilationUnit);
753 memset(cUnit.get(), 0, sizeof(*cUnit));
buzbeeba938cb2012-02-03 14:47:55 -0800754
755 oatInit(cUnit.get(), compiler);
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700756 cUnit->compiler = &compiler;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800757 cUnit->class_linker = class_linker;
758 cUnit->dex_file = &dex_file;
759 cUnit->dex_cache = class_linker->FindDexCache(dex_file);
760 cUnit->method_idx = method_idx;
761 cUnit->code_item = code_item;
762 cUnit->access_flags = access_flags;
763 cUnit->shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700764 cUnit->instructionSet = (OatInstructionSetType)insnSet;
765 cUnit->insns = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700766 cUnit->insnsSize = code_item->insns_size_in_code_units_;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800767 cUnit->numIns = code_item->ins_size_;
768 cUnit->numRegs = code_item->registers_size_ - cUnit->numIns;
769 cUnit->numOuts = code_item->outs_size_;
770 /* Adjust this value accordingly once inlining is performed */
771 cUnit->numDalvikRegisters = code_item->registers_size_;
buzbee5b537102012-01-17 17:33:47 -0800772 cUnit->blockMap = std::map<unsigned int, BasicBlock*>();
773 cUnit->blockMap.clear();
buzbee85d8c1e2012-01-27 15:52:35 -0800774 cUnit->boundaryMap = std::map<unsigned int, LIR*>();
775 cUnit->boundaryMap.clear();
buzbeeba938cb2012-02-03 14:47:55 -0800776 // TODO: set these from command line
777 cUnit->compilerMethodMatch = new std::string("");
778 cUnit->compilerFlipMatch = false;
779 bool useMatch = cUnit->compilerMethodMatch->length() != 0;
780 bool match = useMatch && (cUnit->compilerFlipMatch ^
781 (PrettyMethod(method_idx, dex_file).find(*cUnit->compilerMethodMatch)
782 != std::string::npos));
buzbeece302932011-10-04 14:32:18 -0700783 if (!useMatch || match) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700784 cUnit->disableOpt = compilerOptimizerDisableFlags;
785 cUnit->enableDebug = compilerDebugFlags;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800786 cUnit->printMe = VLOG_IS_ON(compiler) || (cUnit->enableDebug & (1 << kDebugVerbose));
buzbeece302932011-10-04 14:32:18 -0700787 }
buzbee67bf8852011-08-17 17:51:35 -0700788
buzbee44b412b2012-02-04 08:50:53 -0800789 /* Are we generating code for the debugger? */
790 if (cUnit->disableOpt & (1 << kGenCodeForDebugger)) {
791 cUnit->genDebugger = true;
792 // Yes, disable most optimizations
793 cUnit->disableOpt |= (
794 (1 << kLoadStoreElimination) |
795 (1 << kLoadHoisting) |
796 (1 << kSuppressLoads) |
797 (1 << kPromoteRegs) |
798 (1 << kTrackLiveTemps));
799 }
800
buzbeecefd1872011-09-09 09:59:52 -0700801 /* Assume non-throwing leaf */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700802 cUnit->attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
buzbeecefd1872011-09-09 09:59:52 -0700803
buzbee5abfa3e2012-01-31 17:01:43 -0800804 /* Initialize the block list, estimate size based on insnsSize */
buzbeeba938cb2012-02-03 14:47:55 -0800805 oatInitGrowableList(cUnit.get(), &cUnit->blockList, cUnit->insnsSize,
806 kListBlockList);
buzbee67bf8852011-08-17 17:51:35 -0700807
808 /* Initialize the switchTables list */
buzbeeba938cb2012-02-03 14:47:55 -0800809 oatInitGrowableList(cUnit.get(), &cUnit->switchTables, 4,
810 kListSwitchTables);
buzbee67bf8852011-08-17 17:51:35 -0700811
812 /* Intialize the fillArrayData list */
buzbeeba938cb2012-02-03 14:47:55 -0800813 oatInitGrowableList(cUnit.get(), &cUnit->fillArrayData, 4,
814 kListFillArrayData);
buzbee67bf8852011-08-17 17:51:35 -0700815
buzbee5abfa3e2012-01-31 17:01:43 -0800816 /* Intialize the throwLaunchpads list, estimate size based on insnsSize */
buzbeeba938cb2012-02-03 14:47:55 -0800817 oatInitGrowableList(cUnit.get(), &cUnit->throwLaunchpads, cUnit->insnsSize,
buzbee5abfa3e2012-01-31 17:01:43 -0800818 kListThrowLaunchPads);
buzbee5ade1d22011-09-09 14:44:52 -0700819
buzbeec1f45042011-09-21 16:03:19 -0700820 /* Intialize the suspendLaunchpads list */
buzbeeba938cb2012-02-03 14:47:55 -0800821 oatInitGrowableList(cUnit.get(), &cUnit->suspendLaunchpads, 2048,
buzbee5abfa3e2012-01-31 17:01:43 -0800822 kListSuspendLaunchPads);
buzbeec1f45042011-09-21 16:03:19 -0700823
buzbee67bf8852011-08-17 17:51:35 -0700824 /* Allocate the bit-vector to track the beginning of basic blocks */
buzbeeba938cb2012-02-03 14:47:55 -0800825 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit.get(),
826 cUnit->insnsSize,
buzbee67bf8852011-08-17 17:51:35 -0700827 true /* expandable */);
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700828 cUnit->tryBlockAddr = tryBlockAddr;
buzbee67bf8852011-08-17 17:51:35 -0700829
830 /* Create the default entry and exit blocks and enter them to the list */
buzbee5abfa3e2012-01-31 17:01:43 -0800831 BasicBlock *entryBlock = oatNewBB(cUnit.get(), kEntryBlock, numBlocks++);
832 BasicBlock *exitBlock = oatNewBB(cUnit.get(), kExitBlock, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700833
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700834 cUnit->entryBlock = entryBlock;
835 cUnit->exitBlock = exitBlock;
buzbee67bf8852011-08-17 17:51:35 -0700836
buzbeeba938cb2012-02-03 14:47:55 -0800837 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) entryBlock);
838 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) exitBlock);
buzbee67bf8852011-08-17 17:51:35 -0700839
840 /* Current block to record parsed instructions */
buzbee5abfa3e2012-01-31 17:01:43 -0800841 BasicBlock *curBlock = oatNewBB(cUnit.get(), kDalvikByteCode, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700842 curBlock->startOffset = 0;
buzbeeba938cb2012-02-03 14:47:55 -0800843 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) curBlock);
buzbee5b537102012-01-17 17:33:47 -0800844 /* Add first block to the fast lookup cache */
845 cUnit->blockMap.insert(std::make_pair(curBlock->startOffset, curBlock));
buzbee67bf8852011-08-17 17:51:35 -0700846 entryBlock->fallThrough = curBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800847 oatInsertGrowableList(cUnit.get(), curBlock->predecessors,
848 (intptr_t)entryBlock);
buzbee67bf8852011-08-17 17:51:35 -0700849
850 /*
851 * Store back the number of blocks since new blocks may be created of
852 * accessing cUnit.
853 */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700854 cUnit->numBlocks = numBlocks;
buzbee67bf8852011-08-17 17:51:35 -0700855
856 /* Identify code range in try blocks and set up the empty catch blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700857 processTryCatchBlocks(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700858
859 /* Parse all instructions and put them into containing basic blocks */
860 while (codePtr < codeEnd) {
buzbeeba938cb2012-02-03 14:47:55 -0800861 MIR *insn = (MIR *) oatNew(cUnit.get(), sizeof(MIR), true, kAllocMIR);
buzbee67bf8852011-08-17 17:51:35 -0700862 insn->offset = curOffset;
buzbeeba938cb2012-02-03 14:47:55 -0800863 int width = parseInsn(cUnit.get(), codePtr, &insn->dalvikInsn, false);
buzbee67bf8852011-08-17 17:51:35 -0700864 insn->width = width;
865
866 /* Terminate when the data section is seen */
867 if (width == 0)
868 break;
869
870 oatAppendMIR(curBlock, insn);
871
872 codePtr += width;
873 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
874
buzbee5abfa3e2012-01-31 17:01:43 -0800875 int dfFlags = oatDataFlowAttributes[insn->dalvikInsn.opcode];
876
877 if (dfFlags & DF_HAS_DEFS) {
878 cUnit->defCount += (dfFlags & DF_DA_WIDE) ? 2 : 1;
879 }
buzbee99ba9642012-01-25 14:23:14 -0800880
buzbee67bf8852011-08-17 17:51:35 -0700881 if (flags & kInstrCanBranch) {
buzbeee941e2c2011-12-05 12:38:17 -0800882 curBlock = processCanBranch(cUnit.get(), curBlock, insn, curOffset,
883 width, flags, codePtr, codeEnd);
buzbee67bf8852011-08-17 17:51:35 -0700884 } else if (flags & kInstrCanReturn) {
885 curBlock->fallThrough = exitBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800886 oatInsertGrowableList(cUnit.get(), exitBlock->predecessors,
887 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700888 /*
889 * Terminate the current block if there are instructions
890 * afterwards.
891 */
892 if (codePtr < codeEnd) {
893 /*
894 * Create a fallthrough block for real instructions
895 * (incl. OP_NOP).
896 */
897 if (contentIsInsn(codePtr)) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700898 findBlock(cUnit.get(), curOffset + width,
buzbee67bf8852011-08-17 17:51:35 -0700899 /* split */
900 false,
901 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800902 true,
903 /* immedPredBlockP */
904 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700905 }
906 }
907 } else if (flags & kInstrCanThrow) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700908 processCanThrow(cUnit.get(), curBlock, insn, curOffset, width, flags,
buzbee67bf8852011-08-17 17:51:35 -0700909 tryBlockAddr, codePtr, codeEnd);
910 } else if (flags & kInstrCanSwitch) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700911 processCanSwitch(cUnit.get(), curBlock, insn, curOffset, width, flags);
buzbee67bf8852011-08-17 17:51:35 -0700912 }
913 curOffset += width;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700914 BasicBlock *nextBlock = findBlock(cUnit.get(), curOffset,
buzbee67bf8852011-08-17 17:51:35 -0700915 /* split */
916 false,
917 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800918 false,
919 /* immedPredBlockP */
920 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700921 if (nextBlock) {
922 /*
923 * The next instruction could be the target of a previously parsed
924 * forward branch so a block is already created. If the current
925 * instruction is not an unconditional branch, connect them through
926 * the fall-through link.
927 */
buzbeeed3e9302011-09-23 17:34:19 -0700928 DCHECK(curBlock->fallThrough == NULL ||
buzbee67bf8852011-08-17 17:51:35 -0700929 curBlock->fallThrough == nextBlock ||
930 curBlock->fallThrough == exitBlock);
931
932 if ((curBlock->fallThrough == NULL) &&
933 (flags & kInstrCanContinue)) {
934 curBlock->fallThrough = nextBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800935 oatInsertGrowableList(cUnit.get(), nextBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800936 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700937 }
938 curBlock = nextBlock;
939 }
940 }
941
buzbee5abfa3e2012-01-31 17:01:43 -0800942 if (!(cUnit->disableOpt & (1 << kSkipLargeMethodOptimization))) {
buzbee99ba9642012-01-25 14:23:14 -0800943 if ((cUnit->numBlocks > MANY_BLOCKS) ||
944 ((cUnit->numBlocks > MANY_BLOCKS_INITIALIZER) &&
945 PrettyMethod(method_idx, dex_file).find("init>") !=
946 std::string::npos)) {
947 cUnit->disableDataflow = true;
948 // Disable optimization which require dataflow/ssa
949 cUnit->disableOpt |=
950 (1 << kNullCheckElimination) |
951 (1 << kPromoteRegs);
952 if (cUnit->printMe) {
953 LOG(INFO) << "Compiler: " << PrettyMethod(method_idx, dex_file)
954 << " too big: " << cUnit->numBlocks;
955 }
956 }
957 }
958
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700959 if (cUnit->printMe) {
960 oatDumpCompilationUnit(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700961 }
962
buzbee5b537102012-01-17 17:33:47 -0800963 if (cUnit->enableDebug & (1 << kDebugVerifyDataflow)) {
964 /* Verify if all blocks are connected as claimed */
buzbee5abfa3e2012-01-31 17:01:43 -0800965 oatDataFlowAnalysisDispatcher(cUnit.get(), verifyPredInfo, kAllNodes,
966 false /* isIterative */);
buzbee5b537102012-01-17 17:33:47 -0800967 }
buzbee67bf8852011-08-17 17:51:35 -0700968
969 /* Perform SSA transformation for the whole method */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700970 oatMethodSSATransformation(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700971
buzbee43a36422011-09-14 14:00:13 -0700972 /* Perform null check elimination */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700973 oatMethodNullCheckElimination(cUnit.get());
buzbee43a36422011-09-14 14:00:13 -0700974
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700975 oatInitializeRegAlloc(cUnit.get()); // Needs to happen after SSA naming
buzbee67bf8852011-08-17 17:51:35 -0700976
977 /* Allocate Registers using simple local allocation scheme */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700978 oatSimpleRegAlloc(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700979
980 /* Convert MIR to LIR, etc. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700981 oatMethodMIR2LIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700982
983 // Debugging only
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700984 if (cUnit->enableDebug & (1 << kDebugDumpCFG)) {
985 oatDumpCFG(cUnit.get(), "/sdcard/cfg/");
buzbeeec5adf32011-09-11 15:25:43 -0700986 }
buzbee67bf8852011-08-17 17:51:35 -0700987
988 /* Method is not empty */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700989 if (cUnit->firstLIRInsn) {
buzbee67bf8852011-08-17 17:51:35 -0700990
991 // mark the targets of switch statement case labels
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700992 oatProcessSwitchTables(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700993
994 /* Convert LIR into machine code. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700995 oatAssembleLIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700996
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700997 if (cUnit->printMe) {
998 oatCodegenDump(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700999 }
1000 }
1001
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001002 // Combine vmap tables - core regs, then fp regs - into vmapTable
1003 std::vector<uint16_t> vmapTable;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001004 for (size_t i = 0 ; i < cUnit->coreVmapTable.size(); i++) {
1005 vmapTable.push_back(cUnit->coreVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001006 }
buzbeec41e5b52011-09-23 12:46:19 -07001007 // Add a marker to take place of lr
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -07001008 vmapTable.push_back(INVALID_VREG);
buzbeec41e5b52011-09-23 12:46:19 -07001009 // Combine vmap tables - core regs, then fp regs
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001010 for (uint32_t i = 0; i < cUnit->fpVmapTable.size(); i++) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001011 vmapTable.push_back(cUnit->fpVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001012 }
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -07001013 DCHECK_EQ(vmapTable.size(),
1014 static_cast<uint32_t>(__builtin_popcount(cUnit->coreSpillMask)
1015 + __builtin_popcount(cUnit->fpSpillMask)));
1016 DCHECK_GE(vmapTable.size(), 1U); // should always at least one INVALID_VREG for lr
1017
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001018 CompiledMethod* result = new CompiledMethod(kThumb2, cUnit->codeBuffer,
Ian Rogers0571d352011-11-03 19:51:38 -07001019 cUnit->frameSize, cUnit->coreSpillMask,
1020 cUnit->fpSpillMask, cUnit->mappingTable,
1021 vmapTable);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001022
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -08001023 VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file)
buzbee5abfa3e2012-01-31 17:01:43 -08001024 << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0]))
1025 << " bytes)";
1026
1027#ifdef WITH_MEMSTATS
1028 if (cUnit->enableDebug & (1 << kDebugShowMemoryUsage)) {
1029 oatDumpMemStats(cUnit.get());
1030 }
1031#endif
buzbee67bf8852011-08-17 17:51:35 -07001032
buzbeeba938cb2012-02-03 14:47:55 -08001033 oatArenaReset(cUnit.get());
1034
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001035 return result;
buzbee67bf8852011-08-17 17:51:35 -07001036}
1037
buzbeeba938cb2012-02-03 14:47:55 -08001038void oatInit(CompilationUnit* cUnit, const Compiler& compiler)
buzbee67bf8852011-08-17 17:51:35 -07001039{
buzbee67bf8852011-08-17 17:51:35 -07001040 if (!oatArchInit()) {
1041 LOG(FATAL) << "Failed to initialize oat";
1042 }
buzbeeba938cb2012-02-03 14:47:55 -08001043 if (!oatHeapInit(cUnit)) {
buzbee67bf8852011-08-17 17:51:35 -07001044 LOG(FATAL) << "Failed to initialize oat heap";
1045 }
1046}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001047
1048} // namespace art