blob: 38d697208208cb5bfdc8b3326d26ce570ffd3c91 [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) |
buzbeece302932011-10-04 14:32:18 -070036 0;
37
38uint32_t compilerDebugFlags = 0 | // Enable debug/testing modes
buzbeee3de7492011-10-05 13:37:17 -070039 //(1 << kDebugDisplayMissingTargets) |
buzbeece302932011-10-04 14:32:18 -070040 //(1 << kDebugVerbose) |
41 //(1 << kDebugDumpCFG) |
42 //(1 << kDebugSlowFieldPath) |
43 //(1 << kDebugSlowInvokePath) |
44 //(1 << kDebugSlowStringPath) |
45 //(1 << kDebugSlowestFieldPath) |
46 //(1 << kDebugSlowestStringPath) |
buzbee34c77ad2012-01-11 13:01:32 -080047 //(1 << kDebugExerciseResolveMethod) |
buzbee5b537102012-01-17 17:33:47 -080048 //(1 << kDebugVerifyDataflow) |
buzbee5abfa3e2012-01-31 17:01:43 -080049 //(1 << kDebugShowMemoryUsage) |
buzbeece302932011-10-04 14:32:18 -070050 0;
51
buzbeeed3e9302011-09-23 17:34:19 -070052STATIC inline bool contentIsInsn(const u2* codePtr) {
buzbee67bf8852011-08-17 17:51:35 -070053 u2 instr = *codePtr;
54 Opcode opcode = (Opcode)(instr & 0xff);
55
56 /*
57 * Since the low 8-bit in metadata may look like OP_NOP, we need to check
58 * both the low and whole sub-word to determine whether it is code or data.
59 */
60 return (opcode != OP_NOP || instr == 0);
61}
62
63/*
64 * Parse an instruction, return the length of the instruction
65 */
buzbeeba938cb2012-02-03 14:47:55 -080066STATIC inline int parseInsn(CompilationUnit* cUnit, const u2* codePtr,
67 DecodedInstruction* decInsn, bool printMe)
buzbee67bf8852011-08-17 17:51:35 -070068{
69 // Don't parse instruction data
70 if (!contentIsInsn(codePtr)) {
71 return 0;
72 }
73
74 u2 instr = *codePtr;
75 Opcode opcode = dexOpcodeFromCodeUnit(instr);
76
77 dexDecodeInstruction(codePtr, decInsn);
78 if (printMe) {
buzbeeba938cb2012-02-03 14:47:55 -080079 char* decodedString = oatGetDalvikDisassembly(cUnit, decInsn, NULL);
buzbee67bf8852011-08-17 17:51:35 -070080 LOG(INFO) << codePtr << ": 0x" << std::hex << (int)opcode <<
81 " " << decodedString;
82 }
83 return dexGetWidthFromOpcode(opcode);
84}
85
86#define UNKNOWN_TARGET 0xffffffff
87
buzbeeed3e9302011-09-23 17:34:19 -070088STATIC inline bool isGoto(MIR* insn)
buzbee67bf8852011-08-17 17:51:35 -070089{
90 switch (insn->dalvikInsn.opcode) {
91 case OP_GOTO:
92 case OP_GOTO_16:
93 case OP_GOTO_32:
94 return true;
95 default:
96 return false;
97 }
98}
99
100/*
101 * Identify unconditional branch instructions
102 */
buzbeeed3e9302011-09-23 17:34:19 -0700103STATIC inline bool isUnconditionalBranch(MIR* insn)
buzbee67bf8852011-08-17 17:51:35 -0700104{
105 switch (insn->dalvikInsn.opcode) {
106 case OP_RETURN_VOID:
107 case OP_RETURN:
108 case OP_RETURN_WIDE:
109 case OP_RETURN_OBJECT:
110 return true;
111 default:
112 return isGoto(insn);
113 }
114}
115
116/* Split an existing block from the specified code offset into two */
buzbeeed3e9302011-09-23 17:34:19 -0700117STATIC BasicBlock *splitBlock(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -0700118 unsigned int codeOffset,
buzbee9ab05de2012-01-18 15:43:48 -0800119 BasicBlock* origBlock,
120 BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700121{
122 MIR* insn = origBlock->firstMIRInsn;
123 while (insn) {
124 if (insn->offset == codeOffset) break;
125 insn = insn->next;
126 }
127 if (insn == NULL) {
128 LOG(FATAL) << "Break split failed";
129 }
buzbee5abfa3e2012-01-31 17:01:43 -0800130 BasicBlock *bottomBlock = oatNewBB(cUnit, kDalvikByteCode,
131 cUnit->numBlocks++);
buzbeeba938cb2012-02-03 14:47:55 -0800132 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700133
134 bottomBlock->startOffset = codeOffset;
135 bottomBlock->firstMIRInsn = insn;
136 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
137
buzbee5b537102012-01-17 17:33:47 -0800138 /* Add it to the quick lookup cache */
139 cUnit->blockMap.insert(std::make_pair(bottomBlock->startOffset,
140 bottomBlock));
141
buzbee67bf8852011-08-17 17:51:35 -0700142 /* Handle the taken path */
143 bottomBlock->taken = origBlock->taken;
144 if (bottomBlock->taken) {
145 origBlock->taken = NULL;
buzbee5abfa3e2012-01-31 17:01:43 -0800146 oatDeleteGrowableList(bottomBlock->taken->predecessors,
147 (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800148 oatInsertGrowableList(cUnit, bottomBlock->taken->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800149 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700150 }
151
152 /* Handle the fallthrough path */
153 bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
154 bottomBlock->fallThrough = origBlock->fallThrough;
155 origBlock->fallThrough = bottomBlock;
156 origBlock->needFallThroughBranch = true;
buzbeeba938cb2012-02-03 14:47:55 -0800157 oatInsertGrowableList(cUnit, bottomBlock->predecessors,
158 (intptr_t)origBlock);
buzbee67bf8852011-08-17 17:51:35 -0700159 if (bottomBlock->fallThrough) {
buzbee5abfa3e2012-01-31 17:01:43 -0800160 oatDeleteGrowableList(bottomBlock->fallThrough->predecessors,
161 (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800162 oatInsertGrowableList(cUnit, bottomBlock->fallThrough->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800163 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700164 }
165
166 /* Handle the successor list */
167 if (origBlock->successorBlockList.blockListType != kNotUsed) {
168 bottomBlock->successorBlockList = origBlock->successorBlockList;
169 origBlock->successorBlockList.blockListType = kNotUsed;
170 GrowableListIterator iterator;
171
172 oatGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
173 &iterator);
174 while (true) {
175 SuccessorBlockInfo *successorBlockInfo =
176 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
177 if (successorBlockInfo == NULL) break;
178 BasicBlock *bb = successorBlockInfo->block;
buzbee5abfa3e2012-01-31 17:01:43 -0800179 oatDeleteGrowableList(bb->predecessors, (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800180 oatInsertGrowableList(cUnit, bb->predecessors,
181 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700182 }
183 }
184
185 origBlock->lastMIRInsn = insn->prev;
186
187 insn->prev->next = NULL;
188 insn->prev = NULL;
buzbee9ab05de2012-01-18 15:43:48 -0800189 /*
190 * Update the immediate predecessor block pointer so that outgoing edges
191 * can be applied to the proper block.
192 */
193 if (immedPredBlockP) {
194 DCHECK_EQ(*immedPredBlockP, origBlock);
195 *immedPredBlockP = bottomBlock;
196 }
buzbee67bf8852011-08-17 17:51:35 -0700197 return bottomBlock;
198}
199
200/*
201 * Given a code offset, find out the block that starts with it. If the offset
buzbee9ab05de2012-01-18 15:43:48 -0800202 * is in the middle of an existing block, split it into two. If immedPredBlockP
203 * is not non-null and is the block being split, update *immedPredBlockP to
204 * point to the bottom block so that outgoing edges can be set up properly
205 * (by the caller)
buzbee5b537102012-01-17 17:33:47 -0800206 * Utilizes a map for fast lookup of the typical cases.
buzbee67bf8852011-08-17 17:51:35 -0700207 */
buzbeeed3e9302011-09-23 17:34:19 -0700208STATIC BasicBlock *findBlock(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -0700209 unsigned int codeOffset,
buzbee9ab05de2012-01-18 15:43:48 -0800210 bool split, bool create,
211 BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700212{
213 GrowableList* blockList = &cUnit->blockList;
214 BasicBlock* bb;
215 unsigned int i;
buzbee5b537102012-01-17 17:33:47 -0800216 std::map<unsigned int, BasicBlock*>::iterator it;
buzbee67bf8852011-08-17 17:51:35 -0700217
buzbee5b537102012-01-17 17:33:47 -0800218 it = cUnit->blockMap.find(codeOffset);
219 if (it != cUnit->blockMap.end()) {
220 return it->second;
221 } else if (!create) {
222 return NULL;
223 }
224
225 if (split) {
226 for (i = 0; i < blockList->numUsed; i++) {
227 bb = (BasicBlock *) blockList->elemList[i];
228 if (bb->blockType != kDalvikByteCode) continue;
229 /* Check if a branch jumps into the middle of an existing block */
230 if ((codeOffset > bb->startOffset) && (bb->lastMIRInsn != NULL) &&
231 (codeOffset <= bb->lastMIRInsn->offset)) {
232 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb,
233 bb == *immedPredBlockP ?
234 immedPredBlockP : NULL);
235 return newBB;
236 }
buzbee67bf8852011-08-17 17:51:35 -0700237 }
238 }
buzbee5b537102012-01-17 17:33:47 -0800239
240 /* Create a new one */
buzbee5abfa3e2012-01-31 17:01:43 -0800241 bb = oatNewBB(cUnit, kDalvikByteCode, cUnit->numBlocks++);
buzbeeba938cb2012-02-03 14:47:55 -0800242 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) bb);
buzbee5b537102012-01-17 17:33:47 -0800243 bb->startOffset = codeOffset;
244 cUnit->blockMap.insert(std::make_pair(bb->startOffset, bb));
245 return bb;
buzbee67bf8852011-08-17 17:51:35 -0700246}
247
248/* Dump the CFG into a DOT graph */
249void oatDumpCFG(CompilationUnit* cUnit, const char* dirPrefix)
250{
buzbee67bf8852011-08-17 17:51:35 -0700251 FILE* file;
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800252 std::string name(PrettyMethod(cUnit->method_idx, *cUnit->dex_file));
buzbee67bf8852011-08-17 17:51:35 -0700253 char startOffset[80];
254 sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
buzbeeba938cb2012-02-03 14:47:55 -0800255 char* fileName = (char*) oatNew(cUnit,
buzbeec143c552011-08-20 17:38:58 -0700256 strlen(dirPrefix) +
257 name.length() +
buzbee5abfa3e2012-01-31 17:01:43 -0800258 strlen(".dot") + 1, true, kAllocDebugInfo);
buzbeec143c552011-08-20 17:38:58 -0700259 sprintf(fileName, "%s%s%s.dot", dirPrefix, name.c_str(), startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700260
261 /*
262 * Convert the special characters into a filesystem- and shell-friendly
263 * format.
264 */
265 int i;
266 for (i = strlen(dirPrefix); fileName[i]; i++) {
267 if (fileName[i] == '/') {
268 fileName[i] = '_';
269 } else if (fileName[i] == ';') {
270 fileName[i] = '#';
271 } else if (fileName[i] == '$') {
272 fileName[i] = '+';
273 } else if (fileName[i] == '(' || fileName[i] == ')') {
274 fileName[i] = '@';
275 } else if (fileName[i] == '<' || fileName[i] == '>') {
276 fileName[i] = '=';
277 }
278 }
279 file = fopen(fileName, "w");
280 if (file == NULL) {
281 return;
282 }
283 fprintf(file, "digraph G {\n");
284
285 fprintf(file, " rankdir=TB\n");
286
287 int numReachableBlocks = cUnit->numReachableBlocks;
288 int idx;
289 const GrowableList *blockList = &cUnit->blockList;
290
291 for (idx = 0; idx < numReachableBlocks; idx++) {
292 int blockIdx = cUnit->dfsOrder.elemList[idx];
293 BasicBlock *bb = (BasicBlock *) oatGrowableListGetElement(blockList,
294 blockIdx);
295 if (bb == NULL) break;
296 if (bb->blockType == kEntryBlock) {
297 fprintf(file, " entry [shape=Mdiamond];\n");
298 } else if (bb->blockType == kExitBlock) {
299 fprintf(file, " exit [shape=Mdiamond];\n");
300 } else if (bb->blockType == kDalvikByteCode) {
301 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
302 bb->startOffset);
303 const MIR *mir;
304 fprintf(file, " {block id %d\\l}%s\\\n", bb->id,
305 bb->firstMIRInsn ? " | " : " ");
306 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
307 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
308 mir->ssaRep ?
309 oatFullDisassembler(cUnit, mir) :
310 dexGetOpcodeName(mir->dalvikInsn.opcode),
311 mir->next ? " | " : " ");
312 }
313 fprintf(file, " }\"];\n\n");
314 } else if (bb->blockType == kExceptionHandling) {
315 char blockName[BLOCK_NAME_LEN];
316
317 oatGetBlockName(bb, blockName);
318 fprintf(file, " %s [shape=invhouse];\n", blockName);
319 }
320
321 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
322
323 if (bb->taken) {
324 oatGetBlockName(bb, blockName1);
325 oatGetBlockName(bb->taken, blockName2);
326 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
327 blockName1, blockName2);
328 }
329 if (bb->fallThrough) {
330 oatGetBlockName(bb, blockName1);
331 oatGetBlockName(bb->fallThrough, blockName2);
332 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
333 }
334
335 if (bb->successorBlockList.blockListType != kNotUsed) {
336 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
337 bb->startOffset,
338 (bb->successorBlockList.blockListType == kCatch) ?
339 "Mrecord" : "record");
340 GrowableListIterator iterator;
341 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
342 &iterator);
343 SuccessorBlockInfo *successorBlockInfo =
344 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
345
346 int succId = 0;
347 while (true) {
348 if (successorBlockInfo == NULL) break;
349
350 BasicBlock *destBlock = successorBlockInfo->block;
351 SuccessorBlockInfo *nextSuccessorBlockInfo =
352 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
353
354 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
355 succId++,
356 successorBlockInfo->key,
357 destBlock->startOffset,
358 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
359
360 successorBlockInfo = nextSuccessorBlockInfo;
361 }
362 fprintf(file, " }\"];\n\n");
363
364 oatGetBlockName(bb, blockName1);
365 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
366 blockName1, bb->startOffset);
367
368 if (bb->successorBlockList.blockListType == kPackedSwitch ||
369 bb->successorBlockList.blockListType == kSparseSwitch) {
370
371 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
372 &iterator);
373
374 succId = 0;
375 while (true) {
376 SuccessorBlockInfo *successorBlockInfo =
377 (SuccessorBlockInfo *)
378 oatGrowableListIteratorNext(&iterator);
379 if (successorBlockInfo == NULL) break;
380
381 BasicBlock *destBlock = successorBlockInfo->block;
382
383 oatGetBlockName(destBlock, blockName2);
384 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
385 bb->startOffset, succId++,
386 blockName2);
387 }
388 }
389 }
390 fprintf(file, "\n");
391
buzbeece302932011-10-04 14:32:18 -0700392 /* Display the dominator tree */
buzbee67bf8852011-08-17 17:51:35 -0700393 oatGetBlockName(bb, blockName1);
394 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
395 blockName1, blockName1);
396 if (bb->iDom) {
397 oatGetBlockName(bb->iDom, blockName2);
398 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
399 blockName2, blockName1);
400 }
buzbee67bf8852011-08-17 17:51:35 -0700401 }
402 fprintf(file, "}\n");
403 fclose(file);
404}
405
406/* Verify if all the successor is connected with all the claimed predecessors */
buzbeeed3e9302011-09-23 17:34:19 -0700407STATIC bool verifyPredInfo(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -0700408{
buzbee5abfa3e2012-01-31 17:01:43 -0800409 GrowableListIterator iter;
buzbee67bf8852011-08-17 17:51:35 -0700410
buzbee5abfa3e2012-01-31 17:01:43 -0800411 oatGrowableListIteratorInit(bb->predecessors, &iter);
buzbee67bf8852011-08-17 17:51:35 -0700412 while (true) {
buzbee5abfa3e2012-01-31 17:01:43 -0800413 BasicBlock *predBB = (BasicBlock*)oatGrowableListIteratorNext(&iter);
414 if (!predBB) break;
buzbee67bf8852011-08-17 17:51:35 -0700415 bool found = false;
416 if (predBB->taken == bb) {
417 found = true;
418 } else if (predBB->fallThrough == bb) {
419 found = true;
420 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
421 GrowableListIterator iterator;
422 oatGrowableListIteratorInit(&predBB->successorBlockList.blocks,
423 &iterator);
424 while (true) {
425 SuccessorBlockInfo *successorBlockInfo =
426 (SuccessorBlockInfo *)
427 oatGrowableListIteratorNext(&iterator);
428 if (successorBlockInfo == NULL) break;
429 BasicBlock *succBB = successorBlockInfo->block;
430 if (succBB == bb) {
431 found = true;
432 break;
433 }
434 }
435 }
436 if (found == false) {
437 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
438 oatGetBlockName(bb, blockName1);
439 oatGetBlockName(predBB, blockName2);
440 oatDumpCFG(cUnit, "/sdcard/cfg/");
441 LOG(FATAL) << "Successor " << blockName1 << "not found from "
442 << blockName2;
443 }
444 }
445 return true;
446}
447
448/* Identify code range in try blocks and set up the empty catch blocks */
buzbeeed3e9302011-09-23 17:34:19 -0700449STATIC void processTryCatchBlocks(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700450{
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800451 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbeee9a72f62011-09-04 17:59:07 -0700452 int triesSize = code_item->tries_size_;
buzbee67bf8852011-08-17 17:51:35 -0700453 int offset;
454
455 if (triesSize == 0) {
456 return;
457 }
458
buzbee67bf8852011-08-17 17:51:35 -0700459 ArenaBitVector* tryBlockAddr = cUnit->tryBlockAddr;
460
buzbeee9a72f62011-09-04 17:59:07 -0700461 for (int i = 0; i < triesSize; i++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800462 const DexFile::TryItem* pTry =
463 DexFile::GetTryItems(*code_item, i);
buzbeee9a72f62011-09-04 17:59:07 -0700464 int startOffset = pTry->start_addr_;
465 int endOffset = startOffset + pTry->insn_count_;
buzbee67bf8852011-08-17 17:51:35 -0700466 for (offset = startOffset; offset < endOffset; offset++) {
buzbeeba938cb2012-02-03 14:47:55 -0800467 oatSetBit(cUnit, tryBlockAddr, offset);
buzbee67bf8852011-08-17 17:51:35 -0700468 }
469 }
470
buzbeee9a72f62011-09-04 17:59:07 -0700471 // Iterate over each of the handlers to enqueue the empty Catch blocks
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800472 const byte* handlers_ptr =
473 DexFile::GetCatchHandlerData(*code_item, 0);
474 uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
buzbeee9a72f62011-09-04 17:59:07 -0700475 for (uint32_t idx = 0; idx < handlers_size; idx++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800476 CatchHandlerIterator iterator(handlers_ptr);
Ian Rogers0571d352011-11-03 19:51:38 -0700477 for (; iterator.HasNext(); iterator.Next()) {
478 uint32_t address = iterator.GetHandlerAddress();
buzbee9ab05de2012-01-18 15:43:48 -0800479 findBlock(cUnit, address, false /* split */, true /*create*/,
480 /* immedPredBlockP */ NULL);
buzbee67bf8852011-08-17 17:51:35 -0700481 }
Ian Rogers0571d352011-11-03 19:51:38 -0700482 handlers_ptr = iterator.EndDataPointer();
buzbee67bf8852011-08-17 17:51:35 -0700483 }
484}
485
486/* Process instructions with the kInstrCanBranch flag */
buzbeee941e2c2011-12-05 12:38:17 -0800487STATIC BasicBlock* processCanBranch(CompilationUnit* cUnit,
488 BasicBlock* curBlock, MIR* insn,
489 int curOffset, int width, int flags,
490 const u2* codePtr, const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700491{
492 int target = curOffset;
493 switch (insn->dalvikInsn.opcode) {
494 case OP_GOTO:
495 case OP_GOTO_16:
496 case OP_GOTO_32:
497 target += (int) insn->dalvikInsn.vA;
498 break;
499 case OP_IF_EQ:
500 case OP_IF_NE:
501 case OP_IF_LT:
502 case OP_IF_GE:
503 case OP_IF_GT:
504 case OP_IF_LE:
505 target += (int) insn->dalvikInsn.vC;
506 break;
507 case OP_IF_EQZ:
508 case OP_IF_NEZ:
509 case OP_IF_LTZ:
510 case OP_IF_GEZ:
511 case OP_IF_GTZ:
512 case OP_IF_LEZ:
513 target += (int) insn->dalvikInsn.vB;
514 break;
515 default:
516 LOG(FATAL) << "Unexpected opcode(" << (int)insn->dalvikInsn.opcode
517 << ") with kInstrCanBranch set";
518 }
519 BasicBlock *takenBlock = findBlock(cUnit, target,
520 /* split */
521 true,
522 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800523 true,
524 /* immedPredBlockP */
525 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700526 curBlock->taken = takenBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800527 oatInsertGrowableList(cUnit, takenBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700528
529 /* Always terminate the current block for conditional branches */
530 if (flags & kInstrCanContinue) {
531 BasicBlock *fallthroughBlock = findBlock(cUnit,
532 curOffset + width,
533 /*
534 * If the method is processed
535 * in sequential order from the
536 * beginning, we don't need to
537 * specify split for continue
538 * blocks. However, this
539 * routine can be called by
540 * compileLoop, which starts
541 * parsing the method from an
542 * arbitrary address in the
543 * method body.
544 */
545 true,
546 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800547 true,
548 /* immedPredBlockP */
549 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700550 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800551 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800552 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700553 } else if (codePtr < codeEnd) {
554 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
555 if (contentIsInsn(codePtr)) {
556 findBlock(cUnit, curOffset + width,
557 /* split */
558 false,
559 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800560 true,
561 /* immedPredBlockP */
562 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700563 }
564 }
buzbeee941e2c2011-12-05 12:38:17 -0800565 return curBlock;
buzbee67bf8852011-08-17 17:51:35 -0700566}
567
568/* Process instructions with the kInstrCanSwitch flag */
buzbeeed3e9302011-09-23 17:34:19 -0700569STATIC void processCanSwitch(CompilationUnit* cUnit, BasicBlock* curBlock,
buzbee67bf8852011-08-17 17:51:35 -0700570 MIR* insn, int curOffset, int width, int flags)
571{
572 u2* switchData= (u2 *) (cUnit->insns + curOffset +
573 insn->dalvikInsn.vB);
574 int size;
575 int* keyTable;
576 int* targetTable;
577 int i;
578 int firstKey;
579
580 /*
581 * Packed switch data format:
582 * ushort ident = 0x0100 magic value
583 * ushort size number of entries in the table
584 * int first_key first (and lowest) switch case value
585 * int targets[size] branch targets, relative to switch opcode
586 *
587 * Total size is (4+size*2) 16-bit code units.
588 */
589 if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
buzbeeed3e9302011-09-23 17:34:19 -0700590 DCHECK_EQ(switchData[0], kPackedSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700591 size = switchData[1];
592 firstKey = switchData[2] | (switchData[3] << 16);
593 targetTable = (int *) &switchData[4];
594 keyTable = NULL; // Make the compiler happy
595 /*
596 * Sparse switch data format:
597 * ushort ident = 0x0200 magic value
598 * ushort size number of entries in the table; > 0
599 * int keys[size] keys, sorted low-to-high; 32-bit aligned
600 * int targets[size] branch targets, relative to switch opcode
601 *
602 * Total size is (2+size*4) 16-bit code units.
603 */
604 } else {
buzbeeed3e9302011-09-23 17:34:19 -0700605 DCHECK_EQ(switchData[0], kSparseSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700606 size = switchData[1];
607 keyTable = (int *) &switchData[2];
608 targetTable = (int *) &switchData[2 + size*2];
609 firstKey = 0; // To make the compiler happy
610 }
611
612 if (curBlock->successorBlockList.blockListType != kNotUsed) {
613 LOG(FATAL) << "Successor block list already in use: " <<
614 (int)curBlock->successorBlockList.blockListType;
615 }
616 curBlock->successorBlockList.blockListType =
617 (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
618 kPackedSwitch : kSparseSwitch;
buzbeeba938cb2012-02-03 14:47:55 -0800619 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, size,
buzbee5abfa3e2012-01-31 17:01:43 -0800620 kListSuccessorBlocks);
buzbee67bf8852011-08-17 17:51:35 -0700621
622 for (i = 0; i < size; i++) {
623 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
624 /* split */
625 true,
626 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800627 true,
628 /* immedPredBlockP */
629 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700630 SuccessorBlockInfo *successorBlockInfo =
buzbeeba938cb2012-02-03 14:47:55 -0800631 (SuccessorBlockInfo *) oatNew(cUnit, sizeof(SuccessorBlockInfo),
632 false, kAllocSuccessor);
buzbee67bf8852011-08-17 17:51:35 -0700633 successorBlockInfo->block = caseBlock;
634 successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)?
635 firstKey + i : keyTable[i];
buzbeeba938cb2012-02-03 14:47:55 -0800636 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
buzbee67bf8852011-08-17 17:51:35 -0700637 (intptr_t) successorBlockInfo);
buzbeeba938cb2012-02-03 14:47:55 -0800638 oatInsertGrowableList(cUnit, caseBlock->predecessors,
639 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700640 }
641
642 /* Fall-through case */
643 BasicBlock* fallthroughBlock = findBlock(cUnit,
644 curOffset + width,
645 /* split */
646 false,
647 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800648 true,
649 /* immedPredBlockP */
650 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700651 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800652 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
653 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700654}
655
656/* Process instructions with the kInstrCanThrow flag */
buzbeeed3e9302011-09-23 17:34:19 -0700657STATIC void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock,
buzbee67bf8852011-08-17 17:51:35 -0700658 MIR* insn, int curOffset, int width, int flags,
659 ArenaBitVector* tryBlockAddr, const u2* codePtr,
660 const u2* codeEnd)
661{
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800662 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbee67bf8852011-08-17 17:51:35 -0700663
664 /* In try block */
665 if (oatIsBitSet(tryBlockAddr, curOffset)) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800666 CatchHandlerIterator iterator(*code_item, curOffset);
buzbee67bf8852011-08-17 17:51:35 -0700667
buzbee67bf8852011-08-17 17:51:35 -0700668 if (curBlock->successorBlockList.blockListType != kNotUsed) {
669 LOG(FATAL) << "Successor block list already in use: " <<
670 (int)curBlock->successorBlockList.blockListType;
671 }
buzbeee9a72f62011-09-04 17:59:07 -0700672
buzbee67bf8852011-08-17 17:51:35 -0700673 curBlock->successorBlockList.blockListType = kCatch;
buzbeeba938cb2012-02-03 14:47:55 -0800674 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, 2,
buzbee5abfa3e2012-01-31 17:01:43 -0800675 kListSuccessorBlocks);
buzbee67bf8852011-08-17 17:51:35 -0700676
Ian Rogers0571d352011-11-03 19:51:38 -0700677 for (;iterator.HasNext(); iterator.Next()) {
678 BasicBlock *catchBlock = findBlock(cUnit, iterator.GetHandlerAddress(),
buzbeee9a72f62011-09-04 17:59:07 -0700679 false /* split*/,
buzbee9ab05de2012-01-18 15:43:48 -0800680 false /* creat */,
681 NULL /* immedPredBlockP */);
buzbee43a36422011-09-14 14:00:13 -0700682 catchBlock->catchEntry = true;
buzbeeba938cb2012-02-03 14:47:55 -0800683 SuccessorBlockInfo *successorBlockInfo = (SuccessorBlockInfo *)
684 oatNew(cUnit, sizeof(SuccessorBlockInfo), false,
685 kAllocSuccessor);
buzbee67bf8852011-08-17 17:51:35 -0700686 successorBlockInfo->block = catchBlock;
Ian Rogers0571d352011-11-03 19:51:38 -0700687 successorBlockInfo->key = iterator.GetHandlerTypeIndex();
buzbeeba938cb2012-02-03 14:47:55 -0800688 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
buzbee67bf8852011-08-17 17:51:35 -0700689 (intptr_t) successorBlockInfo);
buzbeeba938cb2012-02-03 14:47:55 -0800690 oatInsertGrowableList(cUnit, catchBlock->predecessors,
691 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700692 }
693 } else {
buzbee5abfa3e2012-01-31 17:01:43 -0800694 BasicBlock *ehBlock = oatNewBB(cUnit, kExceptionHandling,
695 cUnit->numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700696 curBlock->taken = ehBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800697 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) ehBlock);
buzbee67bf8852011-08-17 17:51:35 -0700698 ehBlock->startOffset = curOffset;
buzbeeba938cb2012-02-03 14:47:55 -0800699 oatInsertGrowableList(cUnit, ehBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700700 }
701
702 /*
703 * Force the current block to terminate.
704 *
705 * Data may be present before codeEnd, so we need to parse it to know
706 * whether it is code or data.
707 */
708 if (codePtr < codeEnd) {
709 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
710 if (contentIsInsn(codePtr)) {
711 BasicBlock *fallthroughBlock = findBlock(cUnit,
712 curOffset + width,
713 /* split */
714 false,
715 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800716 true,
717 /* immedPredBlockP */
718 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700719 /*
buzbee510c6052011-10-27 10:47:20 -0700720 * OP_THROW is an unconditional branch. NOTE:
721 * OP_THROW_VERIFICATION_ERROR is also an unconditional
722 * branch, but we shouldn't treat it as such until we have
723 * a dead code elimination pass (which won't be important
724 * until inlining w/ constant propogation is implemented.
buzbee67bf8852011-08-17 17:51:35 -0700725 */
buzbee510c6052011-10-27 10:47:20 -0700726 if (insn->dalvikInsn.opcode != OP_THROW) {
buzbee67bf8852011-08-17 17:51:35 -0700727 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800728 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800729 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700730 }
731 }
732 }
733}
734
735/*
736 * Compile a method.
737 */
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800738CompiledMethod* oatCompileMethod(const Compiler& compiler, const DexFile::CodeItem* code_item,
Ian Rogersa3760aa2011-11-14 14:32:37 -0800739 uint32_t access_flags, uint32_t method_idx,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800740 const ClassLoader* class_loader,
741 const DexFile& dex_file, InstructionSet insnSet)
buzbee67bf8852011-08-17 17:51:35 -0700742{
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800743 VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
Brian Carlstrom94496d32011-08-22 09:22:47 -0700744
buzbeec143c552011-08-20 17:38:58 -0700745 const u2* codePtr = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700746 const u2* codeEnd = code_item->insns_ + code_item->insns_size_in_code_units_;
buzbee67bf8852011-08-17 17:51:35 -0700747 int numBlocks = 0;
748 unsigned int curOffset = 0;
749
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800750 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700751 UniquePtr<CompilationUnit> cUnit(new CompilationUnit);
752 memset(cUnit.get(), 0, sizeof(*cUnit));
buzbeeba938cb2012-02-03 14:47:55 -0800753
754 oatInit(cUnit.get(), compiler);
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700755 cUnit->compiler = &compiler;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800756 cUnit->class_linker = class_linker;
757 cUnit->dex_file = &dex_file;
758 cUnit->dex_cache = class_linker->FindDexCache(dex_file);
759 cUnit->method_idx = method_idx;
760 cUnit->code_item = code_item;
761 cUnit->access_flags = access_flags;
762 cUnit->shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700763 cUnit->instructionSet = (OatInstructionSetType)insnSet;
764 cUnit->insns = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700765 cUnit->insnsSize = code_item->insns_size_in_code_units_;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800766 cUnit->numIns = code_item->ins_size_;
767 cUnit->numRegs = code_item->registers_size_ - cUnit->numIns;
768 cUnit->numOuts = code_item->outs_size_;
769 /* Adjust this value accordingly once inlining is performed */
770 cUnit->numDalvikRegisters = code_item->registers_size_;
buzbee5b537102012-01-17 17:33:47 -0800771 cUnit->blockMap = std::map<unsigned int, BasicBlock*>();
772 cUnit->blockMap.clear();
buzbee85d8c1e2012-01-27 15:52:35 -0800773 cUnit->boundaryMap = std::map<unsigned int, LIR*>();
774 cUnit->boundaryMap.clear();
buzbeeba938cb2012-02-03 14:47:55 -0800775 // TODO: set these from command line
776 cUnit->compilerMethodMatch = new std::string("");
777 cUnit->compilerFlipMatch = false;
778 bool useMatch = cUnit->compilerMethodMatch->length() != 0;
779 bool match = useMatch && (cUnit->compilerFlipMatch ^
780 (PrettyMethod(method_idx, dex_file).find(*cUnit->compilerMethodMatch)
781 != std::string::npos));
buzbeece302932011-10-04 14:32:18 -0700782 if (!useMatch || match) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700783 cUnit->disableOpt = compilerOptimizerDisableFlags;
784 cUnit->enableDebug = compilerDebugFlags;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800785 cUnit->printMe = VLOG_IS_ON(compiler) || (cUnit->enableDebug & (1 << kDebugVerbose));
buzbeece302932011-10-04 14:32:18 -0700786 }
buzbee67bf8852011-08-17 17:51:35 -0700787
buzbeecefd1872011-09-09 09:59:52 -0700788 /* Assume non-throwing leaf */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700789 cUnit->attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
buzbeecefd1872011-09-09 09:59:52 -0700790
buzbee5abfa3e2012-01-31 17:01:43 -0800791 /* Initialize the block list, estimate size based on insnsSize */
buzbeeba938cb2012-02-03 14:47:55 -0800792 oatInitGrowableList(cUnit.get(), &cUnit->blockList, cUnit->insnsSize,
793 kListBlockList);
buzbee67bf8852011-08-17 17:51:35 -0700794
795 /* Initialize the switchTables list */
buzbeeba938cb2012-02-03 14:47:55 -0800796 oatInitGrowableList(cUnit.get(), &cUnit->switchTables, 4,
797 kListSwitchTables);
buzbee67bf8852011-08-17 17:51:35 -0700798
799 /* Intialize the fillArrayData list */
buzbeeba938cb2012-02-03 14:47:55 -0800800 oatInitGrowableList(cUnit.get(), &cUnit->fillArrayData, 4,
801 kListFillArrayData);
buzbee67bf8852011-08-17 17:51:35 -0700802
buzbee5abfa3e2012-01-31 17:01:43 -0800803 /* Intialize the throwLaunchpads list, estimate size based on insnsSize */
buzbeeba938cb2012-02-03 14:47:55 -0800804 oatInitGrowableList(cUnit.get(), &cUnit->throwLaunchpads, cUnit->insnsSize,
buzbee5abfa3e2012-01-31 17:01:43 -0800805 kListThrowLaunchPads);
buzbee5ade1d22011-09-09 14:44:52 -0700806
buzbeec1f45042011-09-21 16:03:19 -0700807 /* Intialize the suspendLaunchpads list */
buzbeeba938cb2012-02-03 14:47:55 -0800808 oatInitGrowableList(cUnit.get(), &cUnit->suspendLaunchpads, 2048,
buzbee5abfa3e2012-01-31 17:01:43 -0800809 kListSuspendLaunchPads);
buzbeec1f45042011-09-21 16:03:19 -0700810
buzbee67bf8852011-08-17 17:51:35 -0700811 /* Allocate the bit-vector to track the beginning of basic blocks */
buzbeeba938cb2012-02-03 14:47:55 -0800812 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit.get(),
813 cUnit->insnsSize,
buzbee67bf8852011-08-17 17:51:35 -0700814 true /* expandable */);
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700815 cUnit->tryBlockAddr = tryBlockAddr;
buzbee67bf8852011-08-17 17:51:35 -0700816
817 /* Create the default entry and exit blocks and enter them to the list */
buzbee5abfa3e2012-01-31 17:01:43 -0800818 BasicBlock *entryBlock = oatNewBB(cUnit.get(), kEntryBlock, numBlocks++);
819 BasicBlock *exitBlock = oatNewBB(cUnit.get(), kExitBlock, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700820
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700821 cUnit->entryBlock = entryBlock;
822 cUnit->exitBlock = exitBlock;
buzbee67bf8852011-08-17 17:51:35 -0700823
buzbeeba938cb2012-02-03 14:47:55 -0800824 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) entryBlock);
825 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) exitBlock);
buzbee67bf8852011-08-17 17:51:35 -0700826
827 /* Current block to record parsed instructions */
buzbee5abfa3e2012-01-31 17:01:43 -0800828 BasicBlock *curBlock = oatNewBB(cUnit.get(), kDalvikByteCode, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700829 curBlock->startOffset = 0;
buzbeeba938cb2012-02-03 14:47:55 -0800830 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) curBlock);
buzbee5b537102012-01-17 17:33:47 -0800831 /* Add first block to the fast lookup cache */
832 cUnit->blockMap.insert(std::make_pair(curBlock->startOffset, curBlock));
buzbee67bf8852011-08-17 17:51:35 -0700833 entryBlock->fallThrough = curBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800834 oatInsertGrowableList(cUnit.get(), curBlock->predecessors,
835 (intptr_t)entryBlock);
buzbee67bf8852011-08-17 17:51:35 -0700836
837 /*
838 * Store back the number of blocks since new blocks may be created of
839 * accessing cUnit.
840 */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700841 cUnit->numBlocks = numBlocks;
buzbee67bf8852011-08-17 17:51:35 -0700842
843 /* Identify code range in try blocks and set up the empty catch blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700844 processTryCatchBlocks(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700845
846 /* Parse all instructions and put them into containing basic blocks */
847 while (codePtr < codeEnd) {
buzbeeba938cb2012-02-03 14:47:55 -0800848 MIR *insn = (MIR *) oatNew(cUnit.get(), sizeof(MIR), true, kAllocMIR);
buzbee67bf8852011-08-17 17:51:35 -0700849 insn->offset = curOffset;
buzbeeba938cb2012-02-03 14:47:55 -0800850 int width = parseInsn(cUnit.get(), codePtr, &insn->dalvikInsn, false);
buzbee67bf8852011-08-17 17:51:35 -0700851 insn->width = width;
852
853 /* Terminate when the data section is seen */
854 if (width == 0)
855 break;
856
857 oatAppendMIR(curBlock, insn);
858
859 codePtr += width;
860 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
861
buzbee5abfa3e2012-01-31 17:01:43 -0800862 int dfFlags = oatDataFlowAttributes[insn->dalvikInsn.opcode];
863
864 if (dfFlags & DF_HAS_DEFS) {
865 cUnit->defCount += (dfFlags & DF_DA_WIDE) ? 2 : 1;
866 }
buzbee99ba9642012-01-25 14:23:14 -0800867
buzbee67bf8852011-08-17 17:51:35 -0700868 if (flags & kInstrCanBranch) {
buzbeee941e2c2011-12-05 12:38:17 -0800869 curBlock = processCanBranch(cUnit.get(), curBlock, insn, curOffset,
870 width, flags, codePtr, codeEnd);
buzbee67bf8852011-08-17 17:51:35 -0700871 } else if (flags & kInstrCanReturn) {
872 curBlock->fallThrough = exitBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800873 oatInsertGrowableList(cUnit.get(), exitBlock->predecessors,
874 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700875 /*
876 * Terminate the current block if there are instructions
877 * afterwards.
878 */
879 if (codePtr < codeEnd) {
880 /*
881 * Create a fallthrough block for real instructions
882 * (incl. OP_NOP).
883 */
884 if (contentIsInsn(codePtr)) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700885 findBlock(cUnit.get(), curOffset + width,
buzbee67bf8852011-08-17 17:51:35 -0700886 /* split */
887 false,
888 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800889 true,
890 /* immedPredBlockP */
891 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700892 }
893 }
894 } else if (flags & kInstrCanThrow) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700895 processCanThrow(cUnit.get(), curBlock, insn, curOffset, width, flags,
buzbee67bf8852011-08-17 17:51:35 -0700896 tryBlockAddr, codePtr, codeEnd);
897 } else if (flags & kInstrCanSwitch) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700898 processCanSwitch(cUnit.get(), curBlock, insn, curOffset, width, flags);
buzbee67bf8852011-08-17 17:51:35 -0700899 }
900 curOffset += width;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700901 BasicBlock *nextBlock = findBlock(cUnit.get(), curOffset,
buzbee67bf8852011-08-17 17:51:35 -0700902 /* split */
903 false,
904 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800905 false,
906 /* immedPredBlockP */
907 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700908 if (nextBlock) {
909 /*
910 * The next instruction could be the target of a previously parsed
911 * forward branch so a block is already created. If the current
912 * instruction is not an unconditional branch, connect them through
913 * the fall-through link.
914 */
buzbeeed3e9302011-09-23 17:34:19 -0700915 DCHECK(curBlock->fallThrough == NULL ||
buzbee67bf8852011-08-17 17:51:35 -0700916 curBlock->fallThrough == nextBlock ||
917 curBlock->fallThrough == exitBlock);
918
919 if ((curBlock->fallThrough == NULL) &&
920 (flags & kInstrCanContinue)) {
921 curBlock->fallThrough = nextBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800922 oatInsertGrowableList(cUnit.get(), nextBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800923 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700924 }
925 curBlock = nextBlock;
926 }
927 }
928
buzbee5abfa3e2012-01-31 17:01:43 -0800929 if (!(cUnit->disableOpt & (1 << kSkipLargeMethodOptimization))) {
buzbee99ba9642012-01-25 14:23:14 -0800930 if ((cUnit->numBlocks > MANY_BLOCKS) ||
931 ((cUnit->numBlocks > MANY_BLOCKS_INITIALIZER) &&
932 PrettyMethod(method_idx, dex_file).find("init>") !=
933 std::string::npos)) {
934 cUnit->disableDataflow = true;
935 // Disable optimization which require dataflow/ssa
936 cUnit->disableOpt |=
937 (1 << kNullCheckElimination) |
938 (1 << kPromoteRegs);
939 if (cUnit->printMe) {
940 LOG(INFO) << "Compiler: " << PrettyMethod(method_idx, dex_file)
941 << " too big: " << cUnit->numBlocks;
942 }
943 }
944 }
945
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700946 if (cUnit->printMe) {
947 oatDumpCompilationUnit(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700948 }
949
buzbee5b537102012-01-17 17:33:47 -0800950 if (cUnit->enableDebug & (1 << kDebugVerifyDataflow)) {
951 /* Verify if all blocks are connected as claimed */
buzbee5abfa3e2012-01-31 17:01:43 -0800952 oatDataFlowAnalysisDispatcher(cUnit.get(), verifyPredInfo, kAllNodes,
953 false /* isIterative */);
buzbee5b537102012-01-17 17:33:47 -0800954 }
buzbee67bf8852011-08-17 17:51:35 -0700955
956 /* Perform SSA transformation for the whole method */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700957 oatMethodSSATransformation(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700958
buzbee43a36422011-09-14 14:00:13 -0700959 /* Perform null check elimination */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700960 oatMethodNullCheckElimination(cUnit.get());
buzbee43a36422011-09-14 14:00:13 -0700961
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700962 oatInitializeRegAlloc(cUnit.get()); // Needs to happen after SSA naming
buzbee67bf8852011-08-17 17:51:35 -0700963
964 /* Allocate Registers using simple local allocation scheme */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700965 oatSimpleRegAlloc(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700966
967 /* Convert MIR to LIR, etc. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700968 oatMethodMIR2LIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700969
970 // Debugging only
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700971 if (cUnit->enableDebug & (1 << kDebugDumpCFG)) {
972 oatDumpCFG(cUnit.get(), "/sdcard/cfg/");
buzbeeec5adf32011-09-11 15:25:43 -0700973 }
buzbee67bf8852011-08-17 17:51:35 -0700974
975 /* Method is not empty */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700976 if (cUnit->firstLIRInsn) {
buzbee67bf8852011-08-17 17:51:35 -0700977
978 // mark the targets of switch statement case labels
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700979 oatProcessSwitchTables(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700980
981 /* Convert LIR into machine code. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700982 oatAssembleLIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700983
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700984 if (cUnit->printMe) {
985 oatCodegenDump(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700986 }
987 }
988
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700989 // Combine vmap tables - core regs, then fp regs - into vmapTable
990 std::vector<uint16_t> vmapTable;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700991 for (size_t i = 0 ; i < cUnit->coreVmapTable.size(); i++) {
992 vmapTable.push_back(cUnit->coreVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700993 }
buzbeec41e5b52011-09-23 12:46:19 -0700994 // Add a marker to take place of lr
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -0700995 vmapTable.push_back(INVALID_VREG);
buzbeec41e5b52011-09-23 12:46:19 -0700996 // Combine vmap tables - core regs, then fp regs
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700997 for (uint32_t i = 0; i < cUnit->fpVmapTable.size(); i++) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700998 vmapTable.push_back(cUnit->fpVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700999 }
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -07001000 DCHECK_EQ(vmapTable.size(),
1001 static_cast<uint32_t>(__builtin_popcount(cUnit->coreSpillMask)
1002 + __builtin_popcount(cUnit->fpSpillMask)));
1003 DCHECK_GE(vmapTable.size(), 1U); // should always at least one INVALID_VREG for lr
1004
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001005 CompiledMethod* result = new CompiledMethod(kThumb2, cUnit->codeBuffer,
Ian Rogers0571d352011-11-03 19:51:38 -07001006 cUnit->frameSize, cUnit->coreSpillMask,
1007 cUnit->fpSpillMask, cUnit->mappingTable,
1008 vmapTable);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001009
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -08001010 VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file)
buzbee5abfa3e2012-01-31 17:01:43 -08001011 << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0]))
1012 << " bytes)";
1013
1014#ifdef WITH_MEMSTATS
1015 if (cUnit->enableDebug & (1 << kDebugShowMemoryUsage)) {
1016 oatDumpMemStats(cUnit.get());
1017 }
1018#endif
buzbee67bf8852011-08-17 17:51:35 -07001019
buzbeeba938cb2012-02-03 14:47:55 -08001020 oatArenaReset(cUnit.get());
1021
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001022 return result;
buzbee67bf8852011-08-17 17:51:35 -07001023}
1024
buzbeeba938cb2012-02-03 14:47:55 -08001025void oatInit(CompilationUnit* cUnit, const Compiler& compiler)
buzbee67bf8852011-08-17 17:51:35 -07001026{
buzbee67bf8852011-08-17 17:51:35 -07001027 if (!oatArchInit()) {
1028 LOG(FATAL) << "Failed to initialize oat";
1029 }
buzbeeba938cb2012-02-03 14:47:55 -08001030 if (!oatHeapInit(cUnit)) {
buzbee67bf8852011-08-17 17:51:35 -07001031 LOG(FATAL) << "Failed to initialize oat heap";
1032 }
1033}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001034
1035} // namespace art