blob: b41afc05bb75c2d0841d67489ada13c9316893a7 [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
52std::string compilerMethodMatch; // Method name match to apply above flags
53
54bool compilerFlipMatch = false; // Reverses sense of method name match
55
buzbeeed3e9302011-09-23 17:34:19 -070056STATIC inline bool contentIsInsn(const u2* codePtr) {
buzbee67bf8852011-08-17 17:51:35 -070057 u2 instr = *codePtr;
58 Opcode opcode = (Opcode)(instr & 0xff);
59
60 /*
61 * Since the low 8-bit in metadata may look like OP_NOP, we need to check
62 * both the low and whole sub-word to determine whether it is code or data.
63 */
64 return (opcode != OP_NOP || instr == 0);
65}
66
67/*
68 * Parse an instruction, return the length of the instruction
69 */
buzbeeed3e9302011-09-23 17:34:19 -070070STATIC inline int parseInsn(const u2* codePtr, DecodedInstruction* decInsn,
buzbee67bf8852011-08-17 17:51:35 -070071 bool printMe)
72{
73 // Don't parse instruction data
74 if (!contentIsInsn(codePtr)) {
75 return 0;
76 }
77
78 u2 instr = *codePtr;
79 Opcode opcode = dexOpcodeFromCodeUnit(instr);
80
81 dexDecodeInstruction(codePtr, decInsn);
82 if (printMe) {
Elliott Hughesc1f143d2011-12-01 17:31:10 -080083 char* decodedString = oatGetDalvikDisassembly(decInsn, NULL);
buzbee67bf8852011-08-17 17:51:35 -070084 LOG(INFO) << codePtr << ": 0x" << std::hex << (int)opcode <<
85 " " << decodedString;
86 }
87 return dexGetWidthFromOpcode(opcode);
88}
89
90#define UNKNOWN_TARGET 0xffffffff
91
buzbeeed3e9302011-09-23 17:34:19 -070092STATIC inline bool isGoto(MIR* insn)
buzbee67bf8852011-08-17 17:51:35 -070093{
94 switch (insn->dalvikInsn.opcode) {
95 case OP_GOTO:
96 case OP_GOTO_16:
97 case OP_GOTO_32:
98 return true;
99 default:
100 return false;
101 }
102}
103
104/*
105 * Identify unconditional branch instructions
106 */
buzbeeed3e9302011-09-23 17:34:19 -0700107STATIC inline bool isUnconditionalBranch(MIR* insn)
buzbee67bf8852011-08-17 17:51:35 -0700108{
109 switch (insn->dalvikInsn.opcode) {
110 case OP_RETURN_VOID:
111 case OP_RETURN:
112 case OP_RETURN_WIDE:
113 case OP_RETURN_OBJECT:
114 return true;
115 default:
116 return isGoto(insn);
117 }
118}
119
120/* Split an existing block from the specified code offset into two */
buzbeeed3e9302011-09-23 17:34:19 -0700121STATIC BasicBlock *splitBlock(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -0700122 unsigned int codeOffset,
buzbee9ab05de2012-01-18 15:43:48 -0800123 BasicBlock* origBlock,
124 BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700125{
126 MIR* insn = origBlock->firstMIRInsn;
127 while (insn) {
128 if (insn->offset == codeOffset) break;
129 insn = insn->next;
130 }
131 if (insn == NULL) {
132 LOG(FATAL) << "Break split failed";
133 }
buzbee5abfa3e2012-01-31 17:01:43 -0800134 BasicBlock *bottomBlock = oatNewBB(cUnit, kDalvikByteCode,
135 cUnit->numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700136 oatInsertGrowableList(&cUnit->blockList, (intptr_t) bottomBlock);
137
138 bottomBlock->startOffset = codeOffset;
139 bottomBlock->firstMIRInsn = insn;
140 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
141
buzbee5b537102012-01-17 17:33:47 -0800142 /* Add it to the quick lookup cache */
143 cUnit->blockMap.insert(std::make_pair(bottomBlock->startOffset,
144 bottomBlock));
145
buzbee67bf8852011-08-17 17:51:35 -0700146 /* Handle the taken path */
147 bottomBlock->taken = origBlock->taken;
148 if (bottomBlock->taken) {
149 origBlock->taken = NULL;
buzbee5abfa3e2012-01-31 17:01:43 -0800150 oatDeleteGrowableList(bottomBlock->taken->predecessors,
151 (intptr_t)origBlock);
152 oatInsertGrowableList(bottomBlock->taken->predecessors,
153 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700154 }
155
156 /* Handle the fallthrough path */
157 bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
158 bottomBlock->fallThrough = origBlock->fallThrough;
159 origBlock->fallThrough = bottomBlock;
160 origBlock->needFallThroughBranch = true;
buzbee5abfa3e2012-01-31 17:01:43 -0800161 oatInsertGrowableList(bottomBlock->predecessors, (intptr_t)origBlock);
buzbee67bf8852011-08-17 17:51:35 -0700162 if (bottomBlock->fallThrough) {
buzbee5abfa3e2012-01-31 17:01:43 -0800163 oatDeleteGrowableList(bottomBlock->fallThrough->predecessors,
164 (intptr_t)origBlock);
165 oatInsertGrowableList(bottomBlock->fallThrough->predecessors,
166 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700167 }
168
169 /* Handle the successor list */
170 if (origBlock->successorBlockList.blockListType != kNotUsed) {
171 bottomBlock->successorBlockList = origBlock->successorBlockList;
172 origBlock->successorBlockList.blockListType = kNotUsed;
173 GrowableListIterator iterator;
174
175 oatGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
176 &iterator);
177 while (true) {
178 SuccessorBlockInfo *successorBlockInfo =
179 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
180 if (successorBlockInfo == NULL) break;
181 BasicBlock *bb = successorBlockInfo->block;
buzbee5abfa3e2012-01-31 17:01:43 -0800182 oatDeleteGrowableList(bb->predecessors, (intptr_t)origBlock);
183 oatInsertGrowableList(bb->predecessors, (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700184 }
185 }
186
187 origBlock->lastMIRInsn = insn->prev;
188
189 insn->prev->next = NULL;
190 insn->prev = NULL;
buzbee9ab05de2012-01-18 15:43:48 -0800191 /*
192 * Update the immediate predecessor block pointer so that outgoing edges
193 * can be applied to the proper block.
194 */
195 if (immedPredBlockP) {
196 DCHECK_EQ(*immedPredBlockP, origBlock);
197 *immedPredBlockP = bottomBlock;
198 }
buzbee67bf8852011-08-17 17:51:35 -0700199 return bottomBlock;
200}
201
202/*
203 * Given a code offset, find out the block that starts with it. If the offset
buzbee9ab05de2012-01-18 15:43:48 -0800204 * is in the middle of an existing block, split it into two. If immedPredBlockP
205 * is not non-null and is the block being split, update *immedPredBlockP to
206 * point to the bottom block so that outgoing edges can be set up properly
207 * (by the caller)
buzbee5b537102012-01-17 17:33:47 -0800208 * Utilizes a map for fast lookup of the typical cases.
buzbee67bf8852011-08-17 17:51:35 -0700209 */
buzbeeed3e9302011-09-23 17:34:19 -0700210STATIC BasicBlock *findBlock(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -0700211 unsigned int codeOffset,
buzbee9ab05de2012-01-18 15:43:48 -0800212 bool split, bool create,
213 BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700214{
215 GrowableList* blockList = &cUnit->blockList;
216 BasicBlock* bb;
217 unsigned int i;
buzbee5b537102012-01-17 17:33:47 -0800218 std::map<unsigned int, BasicBlock*>::iterator it;
buzbee67bf8852011-08-17 17:51:35 -0700219
buzbee5b537102012-01-17 17:33:47 -0800220 it = cUnit->blockMap.find(codeOffset);
221 if (it != cUnit->blockMap.end()) {
222 return it->second;
223 } else if (!create) {
224 return NULL;
225 }
226
227 if (split) {
228 for (i = 0; i < blockList->numUsed; i++) {
229 bb = (BasicBlock *) blockList->elemList[i];
230 if (bb->blockType != kDalvikByteCode) continue;
231 /* Check if a branch jumps into the middle of an existing block */
232 if ((codeOffset > bb->startOffset) && (bb->lastMIRInsn != NULL) &&
233 (codeOffset <= bb->lastMIRInsn->offset)) {
234 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb,
235 bb == *immedPredBlockP ?
236 immedPredBlockP : NULL);
237 return newBB;
238 }
buzbee67bf8852011-08-17 17:51:35 -0700239 }
240 }
buzbee5b537102012-01-17 17:33:47 -0800241
242 /* Create a new one */
buzbee5abfa3e2012-01-31 17:01:43 -0800243 bb = oatNewBB(cUnit, kDalvikByteCode, cUnit->numBlocks++);
buzbee5b537102012-01-17 17:33:47 -0800244 oatInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
245 bb->startOffset = codeOffset;
246 cUnit->blockMap.insert(std::make_pair(bb->startOffset, bb));
247 return bb;
buzbee67bf8852011-08-17 17:51:35 -0700248}
249
250/* Dump the CFG into a DOT graph */
251void oatDumpCFG(CompilationUnit* cUnit, const char* dirPrefix)
252{
buzbee67bf8852011-08-17 17:51:35 -0700253 FILE* file;
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800254 std::string name(PrettyMethod(cUnit->method_idx, *cUnit->dex_file));
buzbee67bf8852011-08-17 17:51:35 -0700255 char startOffset[80];
256 sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
Elliott Hughesc1f143d2011-12-01 17:31:10 -0800257 char* fileName = (char*) oatNew(
buzbeec143c552011-08-20 17:38:58 -0700258 strlen(dirPrefix) +
259 name.length() +
buzbee5abfa3e2012-01-31 17:01:43 -0800260 strlen(".dot") + 1, true, kAllocDebugInfo);
buzbeec143c552011-08-20 17:38:58 -0700261 sprintf(fileName, "%s%s%s.dot", dirPrefix, name.c_str(), startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700262
263 /*
264 * Convert the special characters into a filesystem- and shell-friendly
265 * format.
266 */
267 int i;
268 for (i = strlen(dirPrefix); fileName[i]; i++) {
269 if (fileName[i] == '/') {
270 fileName[i] = '_';
271 } else if (fileName[i] == ';') {
272 fileName[i] = '#';
273 } else if (fileName[i] == '$') {
274 fileName[i] = '+';
275 } else if (fileName[i] == '(' || fileName[i] == ')') {
276 fileName[i] = '@';
277 } else if (fileName[i] == '<' || fileName[i] == '>') {
278 fileName[i] = '=';
279 }
280 }
281 file = fopen(fileName, "w");
282 if (file == NULL) {
283 return;
284 }
285 fprintf(file, "digraph G {\n");
286
287 fprintf(file, " rankdir=TB\n");
288
289 int numReachableBlocks = cUnit->numReachableBlocks;
290 int idx;
291 const GrowableList *blockList = &cUnit->blockList;
292
293 for (idx = 0; idx < numReachableBlocks; idx++) {
294 int blockIdx = cUnit->dfsOrder.elemList[idx];
295 BasicBlock *bb = (BasicBlock *) oatGrowableListGetElement(blockList,
296 blockIdx);
297 if (bb == NULL) break;
298 if (bb->blockType == kEntryBlock) {
299 fprintf(file, " entry [shape=Mdiamond];\n");
300 } else if (bb->blockType == kExitBlock) {
301 fprintf(file, " exit [shape=Mdiamond];\n");
302 } else if (bb->blockType == kDalvikByteCode) {
303 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
304 bb->startOffset);
305 const MIR *mir;
306 fprintf(file, " {block id %d\\l}%s\\\n", bb->id,
307 bb->firstMIRInsn ? " | " : " ");
308 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
309 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
310 mir->ssaRep ?
311 oatFullDisassembler(cUnit, mir) :
312 dexGetOpcodeName(mir->dalvikInsn.opcode),
313 mir->next ? " | " : " ");
314 }
315 fprintf(file, " }\"];\n\n");
316 } else if (bb->blockType == kExceptionHandling) {
317 char blockName[BLOCK_NAME_LEN];
318
319 oatGetBlockName(bb, blockName);
320 fprintf(file, " %s [shape=invhouse];\n", blockName);
321 }
322
323 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
324
325 if (bb->taken) {
326 oatGetBlockName(bb, blockName1);
327 oatGetBlockName(bb->taken, blockName2);
328 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
329 blockName1, blockName2);
330 }
331 if (bb->fallThrough) {
332 oatGetBlockName(bb, blockName1);
333 oatGetBlockName(bb->fallThrough, blockName2);
334 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
335 }
336
337 if (bb->successorBlockList.blockListType != kNotUsed) {
338 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
339 bb->startOffset,
340 (bb->successorBlockList.blockListType == kCatch) ?
341 "Mrecord" : "record");
342 GrowableListIterator iterator;
343 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
344 &iterator);
345 SuccessorBlockInfo *successorBlockInfo =
346 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
347
348 int succId = 0;
349 while (true) {
350 if (successorBlockInfo == NULL) break;
351
352 BasicBlock *destBlock = successorBlockInfo->block;
353 SuccessorBlockInfo *nextSuccessorBlockInfo =
354 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
355
356 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
357 succId++,
358 successorBlockInfo->key,
359 destBlock->startOffset,
360 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
361
362 successorBlockInfo = nextSuccessorBlockInfo;
363 }
364 fprintf(file, " }\"];\n\n");
365
366 oatGetBlockName(bb, blockName1);
367 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
368 blockName1, bb->startOffset);
369
370 if (bb->successorBlockList.blockListType == kPackedSwitch ||
371 bb->successorBlockList.blockListType == kSparseSwitch) {
372
373 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
374 &iterator);
375
376 succId = 0;
377 while (true) {
378 SuccessorBlockInfo *successorBlockInfo =
379 (SuccessorBlockInfo *)
380 oatGrowableListIteratorNext(&iterator);
381 if (successorBlockInfo == NULL) break;
382
383 BasicBlock *destBlock = successorBlockInfo->block;
384
385 oatGetBlockName(destBlock, blockName2);
386 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
387 bb->startOffset, succId++,
388 blockName2);
389 }
390 }
391 }
392 fprintf(file, "\n");
393
buzbeece302932011-10-04 14:32:18 -0700394 /* Display the dominator tree */
buzbee67bf8852011-08-17 17:51:35 -0700395 oatGetBlockName(bb, blockName1);
396 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
397 blockName1, blockName1);
398 if (bb->iDom) {
399 oatGetBlockName(bb->iDom, blockName2);
400 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
401 blockName2, blockName1);
402 }
buzbee67bf8852011-08-17 17:51:35 -0700403 }
404 fprintf(file, "}\n");
405 fclose(file);
406}
407
408/* Verify if all the successor is connected with all the claimed predecessors */
buzbeeed3e9302011-09-23 17:34:19 -0700409STATIC bool verifyPredInfo(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -0700410{
buzbee5abfa3e2012-01-31 17:01:43 -0800411 GrowableListIterator iter;
buzbee67bf8852011-08-17 17:51:35 -0700412
buzbee5abfa3e2012-01-31 17:01:43 -0800413 oatGrowableListIteratorInit(bb->predecessors, &iter);
buzbee67bf8852011-08-17 17:51:35 -0700414 while (true) {
buzbee5abfa3e2012-01-31 17:01:43 -0800415 BasicBlock *predBB = (BasicBlock*)oatGrowableListIteratorNext(&iter);
416 if (!predBB) break;
buzbee67bf8852011-08-17 17:51:35 -0700417 bool found = false;
418 if (predBB->taken == bb) {
419 found = true;
420 } else if (predBB->fallThrough == bb) {
421 found = true;
422 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
423 GrowableListIterator iterator;
424 oatGrowableListIteratorInit(&predBB->successorBlockList.blocks,
425 &iterator);
426 while (true) {
427 SuccessorBlockInfo *successorBlockInfo =
428 (SuccessorBlockInfo *)
429 oatGrowableListIteratorNext(&iterator);
430 if (successorBlockInfo == NULL) break;
431 BasicBlock *succBB = successorBlockInfo->block;
432 if (succBB == bb) {
433 found = true;
434 break;
435 }
436 }
437 }
438 if (found == false) {
439 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
440 oatGetBlockName(bb, blockName1);
441 oatGetBlockName(predBB, blockName2);
442 oatDumpCFG(cUnit, "/sdcard/cfg/");
443 LOG(FATAL) << "Successor " << blockName1 << "not found from "
444 << blockName2;
445 }
446 }
447 return true;
448}
449
450/* Identify code range in try blocks and set up the empty catch blocks */
buzbeeed3e9302011-09-23 17:34:19 -0700451STATIC void processTryCatchBlocks(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700452{
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800453 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbeee9a72f62011-09-04 17:59:07 -0700454 int triesSize = code_item->tries_size_;
buzbee67bf8852011-08-17 17:51:35 -0700455 int offset;
456
457 if (triesSize == 0) {
458 return;
459 }
460
buzbee67bf8852011-08-17 17:51:35 -0700461 ArenaBitVector* tryBlockAddr = cUnit->tryBlockAddr;
462
buzbeee9a72f62011-09-04 17:59:07 -0700463 for (int i = 0; i < triesSize; i++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800464 const DexFile::TryItem* pTry =
465 DexFile::GetTryItems(*code_item, i);
buzbeee9a72f62011-09-04 17:59:07 -0700466 int startOffset = pTry->start_addr_;
467 int endOffset = startOffset + pTry->insn_count_;
buzbee67bf8852011-08-17 17:51:35 -0700468 for (offset = startOffset; offset < endOffset; offset++) {
469 oatSetBit(tryBlockAddr, offset);
470 }
471 }
472
buzbeee9a72f62011-09-04 17:59:07 -0700473 // Iterate over each of the handlers to enqueue the empty Catch blocks
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800474 const byte* handlers_ptr =
475 DexFile::GetCatchHandlerData(*code_item, 0);
476 uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
buzbeee9a72f62011-09-04 17:59:07 -0700477 for (uint32_t idx = 0; idx < handlers_size; idx++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800478 CatchHandlerIterator iterator(handlers_ptr);
Ian Rogers0571d352011-11-03 19:51:38 -0700479 for (; iterator.HasNext(); iterator.Next()) {
480 uint32_t address = iterator.GetHandlerAddress();
buzbee9ab05de2012-01-18 15:43:48 -0800481 findBlock(cUnit, address, false /* split */, true /*create*/,
482 /* immedPredBlockP */ NULL);
buzbee67bf8852011-08-17 17:51:35 -0700483 }
Ian Rogers0571d352011-11-03 19:51:38 -0700484 handlers_ptr = iterator.EndDataPointer();
buzbee67bf8852011-08-17 17:51:35 -0700485 }
486}
487
488/* Process instructions with the kInstrCanBranch flag */
buzbeee941e2c2011-12-05 12:38:17 -0800489STATIC BasicBlock* processCanBranch(CompilationUnit* cUnit,
490 BasicBlock* curBlock, MIR* insn,
491 int curOffset, int width, int flags,
492 const u2* codePtr, const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700493{
494 int target = curOffset;
495 switch (insn->dalvikInsn.opcode) {
496 case OP_GOTO:
497 case OP_GOTO_16:
498 case OP_GOTO_32:
499 target += (int) insn->dalvikInsn.vA;
500 break;
501 case OP_IF_EQ:
502 case OP_IF_NE:
503 case OP_IF_LT:
504 case OP_IF_GE:
505 case OP_IF_GT:
506 case OP_IF_LE:
507 target += (int) insn->dalvikInsn.vC;
508 break;
509 case OP_IF_EQZ:
510 case OP_IF_NEZ:
511 case OP_IF_LTZ:
512 case OP_IF_GEZ:
513 case OP_IF_GTZ:
514 case OP_IF_LEZ:
515 target += (int) insn->dalvikInsn.vB;
516 break;
517 default:
518 LOG(FATAL) << "Unexpected opcode(" << (int)insn->dalvikInsn.opcode
519 << ") with kInstrCanBranch set";
520 }
521 BasicBlock *takenBlock = findBlock(cUnit, target,
522 /* split */
523 true,
524 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800525 true,
526 /* immedPredBlockP */
527 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700528 curBlock->taken = takenBlock;
buzbee5abfa3e2012-01-31 17:01:43 -0800529 oatInsertGrowableList(takenBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700530
531 /* Always terminate the current block for conditional branches */
532 if (flags & kInstrCanContinue) {
533 BasicBlock *fallthroughBlock = findBlock(cUnit,
534 curOffset + width,
535 /*
536 * If the method is processed
537 * in sequential order from the
538 * beginning, we don't need to
539 * specify split for continue
540 * blocks. However, this
541 * routine can be called by
542 * compileLoop, which starts
543 * parsing the method from an
544 * arbitrary address in the
545 * method body.
546 */
547 true,
548 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800549 true,
550 /* immedPredBlockP */
551 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700552 curBlock->fallThrough = fallthroughBlock;
buzbee5abfa3e2012-01-31 17:01:43 -0800553 oatInsertGrowableList(fallthroughBlock->predecessors,
554 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700555 } else if (codePtr < codeEnd) {
556 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
557 if (contentIsInsn(codePtr)) {
558 findBlock(cUnit, curOffset + width,
559 /* split */
560 false,
561 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800562 true,
563 /* immedPredBlockP */
564 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700565 }
566 }
buzbeee941e2c2011-12-05 12:38:17 -0800567 return curBlock;
buzbee67bf8852011-08-17 17:51:35 -0700568}
569
570/* Process instructions with the kInstrCanSwitch flag */
buzbeeed3e9302011-09-23 17:34:19 -0700571STATIC void processCanSwitch(CompilationUnit* cUnit, BasicBlock* curBlock,
buzbee67bf8852011-08-17 17:51:35 -0700572 MIR* insn, int curOffset, int width, int flags)
573{
574 u2* switchData= (u2 *) (cUnit->insns + curOffset +
575 insn->dalvikInsn.vB);
576 int size;
577 int* keyTable;
578 int* targetTable;
579 int i;
580 int firstKey;
581
582 /*
583 * Packed switch data format:
584 * ushort ident = 0x0100 magic value
585 * ushort size number of entries in the table
586 * int first_key first (and lowest) switch case value
587 * int targets[size] branch targets, relative to switch opcode
588 *
589 * Total size is (4+size*2) 16-bit code units.
590 */
591 if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
buzbeeed3e9302011-09-23 17:34:19 -0700592 DCHECK_EQ(switchData[0], kPackedSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700593 size = switchData[1];
594 firstKey = switchData[2] | (switchData[3] << 16);
595 targetTable = (int *) &switchData[4];
596 keyTable = NULL; // Make the compiler happy
597 /*
598 * Sparse switch data format:
599 * ushort ident = 0x0200 magic value
600 * ushort size number of entries in the table; > 0
601 * int keys[size] keys, sorted low-to-high; 32-bit aligned
602 * int targets[size] branch targets, relative to switch opcode
603 *
604 * Total size is (2+size*4) 16-bit code units.
605 */
606 } else {
buzbeeed3e9302011-09-23 17:34:19 -0700607 DCHECK_EQ(switchData[0], kSparseSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700608 size = switchData[1];
609 keyTable = (int *) &switchData[2];
610 targetTable = (int *) &switchData[2 + size*2];
611 firstKey = 0; // To make the compiler happy
612 }
613
614 if (curBlock->successorBlockList.blockListType != kNotUsed) {
615 LOG(FATAL) << "Successor block list already in use: " <<
616 (int)curBlock->successorBlockList.blockListType;
617 }
618 curBlock->successorBlockList.blockListType =
619 (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
620 kPackedSwitch : kSparseSwitch;
buzbee5abfa3e2012-01-31 17:01:43 -0800621 oatInitGrowableList(&curBlock->successorBlockList.blocks, size,
622 kListSuccessorBlocks);
buzbee67bf8852011-08-17 17:51:35 -0700623
624 for (i = 0; i < size; i++) {
625 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
626 /* split */
627 true,
628 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800629 true,
630 /* immedPredBlockP */
631 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700632 SuccessorBlockInfo *successorBlockInfo =
633 (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
buzbee5abfa3e2012-01-31 17:01:43 -0800634 false, kAllocSuccessor);
buzbee67bf8852011-08-17 17:51:35 -0700635 successorBlockInfo->block = caseBlock;
636 successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)?
637 firstKey + i : keyTable[i];
638 oatInsertGrowableList(&curBlock->successorBlockList.blocks,
639 (intptr_t) successorBlockInfo);
buzbee5abfa3e2012-01-31 17:01:43 -0800640 oatInsertGrowableList(caseBlock->predecessors, (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;
buzbee5abfa3e2012-01-31 17:01:43 -0800653 oatInsertGrowableList(fallthroughBlock->predecessors, (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;
buzbee5abfa3e2012-01-31 17:01:43 -0800674 oatInitGrowableList(&curBlock->successorBlockList.blocks, 2,
675 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;
buzbee67bf8852011-08-17 17:51:35 -0700683 SuccessorBlockInfo *successorBlockInfo =
buzbeee9a72f62011-09-04 17:59:07 -0700684 (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
buzbee5abfa3e2012-01-31 17:01:43 -0800685 false, kAllocSuccessor);
buzbee67bf8852011-08-17 17:51:35 -0700686 successorBlockInfo->block = catchBlock;
Ian Rogers0571d352011-11-03 19:51:38 -0700687 successorBlockInfo->key = iterator.GetHandlerTypeIndex();
buzbee67bf8852011-08-17 17:51:35 -0700688 oatInsertGrowableList(&curBlock->successorBlockList.blocks,
689 (intptr_t) successorBlockInfo);
buzbee5abfa3e2012-01-31 17:01:43 -0800690 oatInsertGrowableList(catchBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700691 }
692 } else {
buzbee5abfa3e2012-01-31 17:01:43 -0800693 BasicBlock *ehBlock = oatNewBB(cUnit, kExceptionHandling,
694 cUnit->numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700695 curBlock->taken = ehBlock;
696 oatInsertGrowableList(&cUnit->blockList, (intptr_t) ehBlock);
697 ehBlock->startOffset = curOffset;
buzbee5abfa3e2012-01-31 17:01:43 -0800698 oatInsertGrowableList(ehBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700699 }
700
701 /*
702 * Force the current block to terminate.
703 *
704 * Data may be present before codeEnd, so we need to parse it to know
705 * whether it is code or data.
706 */
707 if (codePtr < codeEnd) {
708 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
709 if (contentIsInsn(codePtr)) {
710 BasicBlock *fallthroughBlock = findBlock(cUnit,
711 curOffset + width,
712 /* split */
713 false,
714 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800715 true,
716 /* immedPredBlockP */
717 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700718 /*
buzbee510c6052011-10-27 10:47:20 -0700719 * OP_THROW is an unconditional branch. NOTE:
720 * OP_THROW_VERIFICATION_ERROR is also an unconditional
721 * branch, but we shouldn't treat it as such until we have
722 * a dead code elimination pass (which won't be important
723 * until inlining w/ constant propogation is implemented.
buzbee67bf8852011-08-17 17:51:35 -0700724 */
buzbee510c6052011-10-27 10:47:20 -0700725 if (insn->dalvikInsn.opcode != OP_THROW) {
buzbee67bf8852011-08-17 17:51:35 -0700726 curBlock->fallThrough = fallthroughBlock;
buzbee5abfa3e2012-01-31 17:01:43 -0800727 oatInsertGrowableList(fallthroughBlock->predecessors,
728 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700729 }
730 }
731 }
732}
733
734/*
735 * Compile a method.
736 */
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800737CompiledMethod* oatCompileMethod(const Compiler& compiler, const DexFile::CodeItem* code_item,
Ian Rogersa3760aa2011-11-14 14:32:37 -0800738 uint32_t access_flags, uint32_t method_idx,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800739 const ClassLoader* class_loader,
740 const DexFile& dex_file, InstructionSet insnSet)
buzbee67bf8852011-08-17 17:51:35 -0700741{
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800742 VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
buzbee2a475e72011-09-07 17:19:17 -0700743 oatArenaReset();
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
Brian Carlstrom16192862011-09-12 17:50:06 -0700750 oatInit(compiler);
buzbee67bf8852011-08-17 17:51:35 -0700751
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800752 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700753 UniquePtr<CompilationUnit> cUnit(new CompilationUnit);
754 memset(cUnit.get(), 0, sizeof(*cUnit));
755 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();
buzbeece302932011-10-04 14:32:18 -0700775 bool useMatch = compilerMethodMatch.length() != 0;
776 bool match = useMatch && (compilerFlipMatch ^
Ian Rogersa3760aa2011-11-14 14:32:37 -0800777 (PrettyMethod(method_idx, dex_file).find(compilerMethodMatch) != std::string::npos));
buzbeece302932011-10-04 14:32:18 -0700778 if (!useMatch || match) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700779 cUnit->disableOpt = compilerOptimizerDisableFlags;
780 cUnit->enableDebug = compilerDebugFlags;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800781 cUnit->printMe = VLOG_IS_ON(compiler) || (cUnit->enableDebug & (1 << kDebugVerbose));
buzbeece302932011-10-04 14:32:18 -0700782 }
buzbee67bf8852011-08-17 17:51:35 -0700783
buzbeecefd1872011-09-09 09:59:52 -0700784 /* Assume non-throwing leaf */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700785 cUnit->attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
buzbeecefd1872011-09-09 09:59:52 -0700786
buzbee5abfa3e2012-01-31 17:01:43 -0800787 /* Initialize the block list, estimate size based on insnsSize */
788 oatInitGrowableList(&cUnit->blockList, cUnit->insnsSize, kListBlockList);
buzbee67bf8852011-08-17 17:51:35 -0700789
790 /* Initialize the switchTables list */
buzbee5abfa3e2012-01-31 17:01:43 -0800791 oatInitGrowableList(&cUnit->switchTables, 4, kListSwitchTables);
buzbee67bf8852011-08-17 17:51:35 -0700792
793 /* Intialize the fillArrayData list */
buzbee5abfa3e2012-01-31 17:01:43 -0800794 oatInitGrowableList(&cUnit->fillArrayData, 4, kListFillArrayData);
buzbee67bf8852011-08-17 17:51:35 -0700795
buzbee5abfa3e2012-01-31 17:01:43 -0800796 /* Intialize the throwLaunchpads list, estimate size based on insnsSize */
797 oatInitGrowableList(&cUnit->throwLaunchpads, cUnit->insnsSize,
798 kListThrowLaunchPads);
buzbee5ade1d22011-09-09 14:44:52 -0700799
buzbeec1f45042011-09-21 16:03:19 -0700800 /* Intialize the suspendLaunchpads list */
buzbee5abfa3e2012-01-31 17:01:43 -0800801 oatInitGrowableList(&cUnit->suspendLaunchpads, 2048,
802 kListSuspendLaunchPads);
buzbeec1f45042011-09-21 16:03:19 -0700803
buzbee67bf8852011-08-17 17:51:35 -0700804 /* Allocate the bit-vector to track the beginning of basic blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700805 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit->insnsSize,
buzbee67bf8852011-08-17 17:51:35 -0700806 true /* expandable */);
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700807 cUnit->tryBlockAddr = tryBlockAddr;
buzbee67bf8852011-08-17 17:51:35 -0700808
809 /* Create the default entry and exit blocks and enter them to the list */
buzbee5abfa3e2012-01-31 17:01:43 -0800810 BasicBlock *entryBlock = oatNewBB(cUnit.get(), kEntryBlock, numBlocks++);
811 BasicBlock *exitBlock = oatNewBB(cUnit.get(), kExitBlock, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700812
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700813 cUnit->entryBlock = entryBlock;
814 cUnit->exitBlock = exitBlock;
buzbee67bf8852011-08-17 17:51:35 -0700815
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700816 oatInsertGrowableList(&cUnit->blockList, (intptr_t) entryBlock);
817 oatInsertGrowableList(&cUnit->blockList, (intptr_t) exitBlock);
buzbee67bf8852011-08-17 17:51:35 -0700818
819 /* Current block to record parsed instructions */
buzbee5abfa3e2012-01-31 17:01:43 -0800820 BasicBlock *curBlock = oatNewBB(cUnit.get(), kDalvikByteCode, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700821 curBlock->startOffset = 0;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700822 oatInsertGrowableList(&cUnit->blockList, (intptr_t) curBlock);
buzbee5b537102012-01-17 17:33:47 -0800823 /* Add first block to the fast lookup cache */
824 cUnit->blockMap.insert(std::make_pair(curBlock->startOffset, curBlock));
buzbee67bf8852011-08-17 17:51:35 -0700825 entryBlock->fallThrough = curBlock;
buzbee5abfa3e2012-01-31 17:01:43 -0800826 oatInsertGrowableList(curBlock->predecessors, (intptr_t)entryBlock);
buzbee67bf8852011-08-17 17:51:35 -0700827
828 /*
829 * Store back the number of blocks since new blocks may be created of
830 * accessing cUnit.
831 */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700832 cUnit->numBlocks = numBlocks;
buzbee67bf8852011-08-17 17:51:35 -0700833
834 /* Identify code range in try blocks and set up the empty catch blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700835 processTryCatchBlocks(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700836
837 /* Parse all instructions and put them into containing basic blocks */
838 while (codePtr < codeEnd) {
buzbee5abfa3e2012-01-31 17:01:43 -0800839 MIR *insn = (MIR *) oatNew(sizeof(MIR), true, kAllocMIR);
buzbee67bf8852011-08-17 17:51:35 -0700840 insn->offset = curOffset;
841 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
842 insn->width = width;
843
844 /* Terminate when the data section is seen */
845 if (width == 0)
846 break;
847
848 oatAppendMIR(curBlock, insn);
849
850 codePtr += width;
851 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
852
buzbee5abfa3e2012-01-31 17:01:43 -0800853 int dfFlags = oatDataFlowAttributes[insn->dalvikInsn.opcode];
854
855 if (dfFlags & DF_HAS_DEFS) {
856 cUnit->defCount += (dfFlags & DF_DA_WIDE) ? 2 : 1;
857 }
buzbee99ba9642012-01-25 14:23:14 -0800858
buzbee67bf8852011-08-17 17:51:35 -0700859 if (flags & kInstrCanBranch) {
buzbeee941e2c2011-12-05 12:38:17 -0800860 curBlock = processCanBranch(cUnit.get(), curBlock, insn, curOffset,
861 width, flags, codePtr, codeEnd);
buzbee67bf8852011-08-17 17:51:35 -0700862 } else if (flags & kInstrCanReturn) {
863 curBlock->fallThrough = exitBlock;
buzbee5abfa3e2012-01-31 17:01:43 -0800864 oatInsertGrowableList(exitBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700865 /*
866 * Terminate the current block if there are instructions
867 * afterwards.
868 */
869 if (codePtr < codeEnd) {
870 /*
871 * Create a fallthrough block for real instructions
872 * (incl. OP_NOP).
873 */
874 if (contentIsInsn(codePtr)) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700875 findBlock(cUnit.get(), curOffset + width,
buzbee67bf8852011-08-17 17:51:35 -0700876 /* split */
877 false,
878 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800879 true,
880 /* immedPredBlockP */
881 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700882 }
883 }
884 } else if (flags & kInstrCanThrow) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700885 processCanThrow(cUnit.get(), curBlock, insn, curOffset, width, flags,
buzbee67bf8852011-08-17 17:51:35 -0700886 tryBlockAddr, codePtr, codeEnd);
887 } else if (flags & kInstrCanSwitch) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700888 processCanSwitch(cUnit.get(), curBlock, insn, curOffset, width, flags);
buzbee67bf8852011-08-17 17:51:35 -0700889 }
890 curOffset += width;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700891 BasicBlock *nextBlock = findBlock(cUnit.get(), curOffset,
buzbee67bf8852011-08-17 17:51:35 -0700892 /* split */
893 false,
894 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800895 false,
896 /* immedPredBlockP */
897 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700898 if (nextBlock) {
899 /*
900 * The next instruction could be the target of a previously parsed
901 * forward branch so a block is already created. If the current
902 * instruction is not an unconditional branch, connect them through
903 * the fall-through link.
904 */
buzbeeed3e9302011-09-23 17:34:19 -0700905 DCHECK(curBlock->fallThrough == NULL ||
buzbee67bf8852011-08-17 17:51:35 -0700906 curBlock->fallThrough == nextBlock ||
907 curBlock->fallThrough == exitBlock);
908
909 if ((curBlock->fallThrough == NULL) &&
910 (flags & kInstrCanContinue)) {
911 curBlock->fallThrough = nextBlock;
buzbee5abfa3e2012-01-31 17:01:43 -0800912 oatInsertGrowableList(nextBlock->predecessors,
913 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700914 }
915 curBlock = nextBlock;
916 }
917 }
918
buzbee5abfa3e2012-01-31 17:01:43 -0800919 if (!(cUnit->disableOpt & (1 << kSkipLargeMethodOptimization))) {
buzbee99ba9642012-01-25 14:23:14 -0800920 if ((cUnit->numBlocks > MANY_BLOCKS) ||
921 ((cUnit->numBlocks > MANY_BLOCKS_INITIALIZER) &&
922 PrettyMethod(method_idx, dex_file).find("init>") !=
923 std::string::npos)) {
924 cUnit->disableDataflow = true;
925 // Disable optimization which require dataflow/ssa
926 cUnit->disableOpt |=
927 (1 << kNullCheckElimination) |
928 (1 << kPromoteRegs);
929 if (cUnit->printMe) {
930 LOG(INFO) << "Compiler: " << PrettyMethod(method_idx, dex_file)
931 << " too big: " << cUnit->numBlocks;
932 }
933 }
934 }
935
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700936 if (cUnit->printMe) {
937 oatDumpCompilationUnit(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700938 }
939
buzbee5b537102012-01-17 17:33:47 -0800940 if (cUnit->enableDebug & (1 << kDebugVerifyDataflow)) {
941 /* Verify if all blocks are connected as claimed */
buzbee5abfa3e2012-01-31 17:01:43 -0800942 oatDataFlowAnalysisDispatcher(cUnit.get(), verifyPredInfo, kAllNodes,
943 false /* isIterative */);
buzbee5b537102012-01-17 17:33:47 -0800944 }
buzbee67bf8852011-08-17 17:51:35 -0700945
946 /* Perform SSA transformation for the whole method */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700947 oatMethodSSATransformation(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700948
buzbee43a36422011-09-14 14:00:13 -0700949 /* Perform null check elimination */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700950 oatMethodNullCheckElimination(cUnit.get());
buzbee43a36422011-09-14 14:00:13 -0700951
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700952 oatInitializeRegAlloc(cUnit.get()); // Needs to happen after SSA naming
buzbee67bf8852011-08-17 17:51:35 -0700953
954 /* Allocate Registers using simple local allocation scheme */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700955 oatSimpleRegAlloc(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700956
957 /* Convert MIR to LIR, etc. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700958 oatMethodMIR2LIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700959
960 // Debugging only
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700961 if (cUnit->enableDebug & (1 << kDebugDumpCFG)) {
962 oatDumpCFG(cUnit.get(), "/sdcard/cfg/");
buzbeeec5adf32011-09-11 15:25:43 -0700963 }
buzbee67bf8852011-08-17 17:51:35 -0700964
965 /* Method is not empty */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700966 if (cUnit->firstLIRInsn) {
buzbee67bf8852011-08-17 17:51:35 -0700967
968 // mark the targets of switch statement case labels
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700969 oatProcessSwitchTables(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700970
971 /* Convert LIR into machine code. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700972 oatAssembleLIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700973
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700974 if (cUnit->printMe) {
975 oatCodegenDump(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700976 }
977 }
978
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700979 // Combine vmap tables - core regs, then fp regs - into vmapTable
980 std::vector<uint16_t> vmapTable;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700981 for (size_t i = 0 ; i < cUnit->coreVmapTable.size(); i++) {
982 vmapTable.push_back(cUnit->coreVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700983 }
buzbeec41e5b52011-09-23 12:46:19 -0700984 // Add a marker to take place of lr
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -0700985 vmapTable.push_back(INVALID_VREG);
buzbeec41e5b52011-09-23 12:46:19 -0700986 // Combine vmap tables - core regs, then fp regs
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700987 for (uint32_t i = 0; i < cUnit->fpVmapTable.size(); i++) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700988 vmapTable.push_back(cUnit->fpVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700989 }
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -0700990 DCHECK_EQ(vmapTable.size(),
991 static_cast<uint32_t>(__builtin_popcount(cUnit->coreSpillMask)
992 + __builtin_popcount(cUnit->fpSpillMask)));
993 DCHECK_GE(vmapTable.size(), 1U); // should always at least one INVALID_VREG for lr
994
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800995 CompiledMethod* result = new CompiledMethod(kThumb2, cUnit->codeBuffer,
Ian Rogers0571d352011-11-03 19:51:38 -0700996 cUnit->frameSize, cUnit->coreSpillMask,
997 cUnit->fpSpillMask, cUnit->mappingTable,
998 vmapTable);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700999
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -08001000 VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file)
buzbee5abfa3e2012-01-31 17:01:43 -08001001 << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0]))
1002 << " bytes)";
1003
1004#ifdef WITH_MEMSTATS
1005 if (cUnit->enableDebug & (1 << kDebugShowMemoryUsage)) {
1006 oatDumpMemStats(cUnit.get());
1007 }
1008#endif
buzbee67bf8852011-08-17 17:51:35 -07001009
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001010 return result;
buzbee67bf8852011-08-17 17:51:35 -07001011}
1012
Brian Carlstrom16192862011-09-12 17:50:06 -07001013void oatInit(const Compiler& compiler)
buzbee67bf8852011-08-17 17:51:35 -07001014{
buzbee67bf8852011-08-17 17:51:35 -07001015 static bool initialized = false;
1016 if (initialized)
1017 return;
1018 initialized = true;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -08001019 VLOG(compiler) << "Initializing compiler";
buzbee67bf8852011-08-17 17:51:35 -07001020 if (!oatArchInit()) {
1021 LOG(FATAL) << "Failed to initialize oat";
1022 }
1023 if (!oatHeapInit()) {
1024 LOG(FATAL) << "Failed to initialize oat heap";
1025 }
1026}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001027
1028} // namespace art