blob: 92ffefcb36800e5b039e674959d6d819ab4b486d [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
buzbee31a4a6f2012-02-28 15:36:15 -080052inline 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 */
buzbee31a4a6f2012-02-28 15:36:15 -080066inline int parseInsn(CompilationUnit* cUnit, const u2* codePtr,
buzbeeba938cb2012-02-03 14:47:55 -080067 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
buzbee31a4a6f2012-02-28 15:36:15 -080088inline 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 */
buzbee31a4a6f2012-02-28 15:36:15 -0800103inline 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 */
buzbee31a4a6f2012-02-28 15:36:15 -0800117BasicBlock *splitBlock(CompilationUnit* cUnit, unsigned int codeOffset,
118 BasicBlock* origBlock, BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700119{
120 MIR* insn = origBlock->firstMIRInsn;
121 while (insn) {
122 if (insn->offset == codeOffset) break;
123 insn = insn->next;
124 }
125 if (insn == NULL) {
126 LOG(FATAL) << "Break split failed";
127 }
buzbee5abfa3e2012-01-31 17:01:43 -0800128 BasicBlock *bottomBlock = oatNewBB(cUnit, kDalvikByteCode,
129 cUnit->numBlocks++);
buzbeeba938cb2012-02-03 14:47:55 -0800130 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700131
132 bottomBlock->startOffset = codeOffset;
133 bottomBlock->firstMIRInsn = insn;
134 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
135
buzbee5b537102012-01-17 17:33:47 -0800136 /* Add it to the quick lookup cache */
137 cUnit->blockMap.insert(std::make_pair(bottomBlock->startOffset,
138 bottomBlock));
139
buzbee67bf8852011-08-17 17:51:35 -0700140 /* Handle the taken path */
141 bottomBlock->taken = origBlock->taken;
142 if (bottomBlock->taken) {
143 origBlock->taken = NULL;
buzbee5abfa3e2012-01-31 17:01:43 -0800144 oatDeleteGrowableList(bottomBlock->taken->predecessors,
145 (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800146 oatInsertGrowableList(cUnit, bottomBlock->taken->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800147 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700148 }
149
150 /* Handle the fallthrough path */
151 bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
152 bottomBlock->fallThrough = origBlock->fallThrough;
153 origBlock->fallThrough = bottomBlock;
154 origBlock->needFallThroughBranch = true;
buzbeeba938cb2012-02-03 14:47:55 -0800155 oatInsertGrowableList(cUnit, bottomBlock->predecessors,
156 (intptr_t)origBlock);
buzbee67bf8852011-08-17 17:51:35 -0700157 if (bottomBlock->fallThrough) {
buzbee5abfa3e2012-01-31 17:01:43 -0800158 oatDeleteGrowableList(bottomBlock->fallThrough->predecessors,
159 (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800160 oatInsertGrowableList(cUnit, bottomBlock->fallThrough->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800161 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700162 }
163
164 /* Handle the successor list */
165 if (origBlock->successorBlockList.blockListType != kNotUsed) {
166 bottomBlock->successorBlockList = origBlock->successorBlockList;
167 origBlock->successorBlockList.blockListType = kNotUsed;
168 GrowableListIterator iterator;
169
170 oatGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
171 &iterator);
172 while (true) {
173 SuccessorBlockInfo *successorBlockInfo =
174 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
175 if (successorBlockInfo == NULL) break;
176 BasicBlock *bb = successorBlockInfo->block;
buzbee5abfa3e2012-01-31 17:01:43 -0800177 oatDeleteGrowableList(bb->predecessors, (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800178 oatInsertGrowableList(cUnit, bb->predecessors,
179 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700180 }
181 }
182
183 origBlock->lastMIRInsn = insn->prev;
184
185 insn->prev->next = NULL;
186 insn->prev = NULL;
buzbee9ab05de2012-01-18 15:43:48 -0800187 /*
188 * Update the immediate predecessor block pointer so that outgoing edges
189 * can be applied to the proper block.
190 */
191 if (immedPredBlockP) {
192 DCHECK_EQ(*immedPredBlockP, origBlock);
193 *immedPredBlockP = bottomBlock;
194 }
buzbee67bf8852011-08-17 17:51:35 -0700195 return bottomBlock;
196}
197
198/*
199 * Given a code offset, find out the block that starts with it. If the offset
buzbee9ab05de2012-01-18 15:43:48 -0800200 * is in the middle of an existing block, split it into two. If immedPredBlockP
201 * is not non-null and is the block being split, update *immedPredBlockP to
202 * point to the bottom block so that outgoing edges can be set up properly
203 * (by the caller)
buzbee5b537102012-01-17 17:33:47 -0800204 * Utilizes a map for fast lookup of the typical cases.
buzbee67bf8852011-08-17 17:51:35 -0700205 */
buzbee31a4a6f2012-02-28 15:36:15 -0800206BasicBlock *findBlock(CompilationUnit* cUnit, unsigned int codeOffset,
207 bool split, bool create, BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700208{
209 GrowableList* blockList = &cUnit->blockList;
210 BasicBlock* bb;
211 unsigned int i;
buzbee5b537102012-01-17 17:33:47 -0800212 std::map<unsigned int, BasicBlock*>::iterator it;
buzbee67bf8852011-08-17 17:51:35 -0700213
buzbee5b537102012-01-17 17:33:47 -0800214 it = cUnit->blockMap.find(codeOffset);
215 if (it != cUnit->blockMap.end()) {
216 return it->second;
217 } else if (!create) {
218 return NULL;
219 }
220
221 if (split) {
222 for (i = 0; i < blockList->numUsed; i++) {
223 bb = (BasicBlock *) blockList->elemList[i];
224 if (bb->blockType != kDalvikByteCode) continue;
225 /* Check if a branch jumps into the middle of an existing block */
226 if ((codeOffset > bb->startOffset) && (bb->lastMIRInsn != NULL) &&
227 (codeOffset <= bb->lastMIRInsn->offset)) {
228 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb,
229 bb == *immedPredBlockP ?
230 immedPredBlockP : NULL);
231 return newBB;
232 }
buzbee67bf8852011-08-17 17:51:35 -0700233 }
234 }
buzbee5b537102012-01-17 17:33:47 -0800235
236 /* Create a new one */
buzbee5abfa3e2012-01-31 17:01:43 -0800237 bb = oatNewBB(cUnit, kDalvikByteCode, cUnit->numBlocks++);
buzbeeba938cb2012-02-03 14:47:55 -0800238 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) bb);
buzbee5b537102012-01-17 17:33:47 -0800239 bb->startOffset = codeOffset;
240 cUnit->blockMap.insert(std::make_pair(bb->startOffset, bb));
241 return bb;
buzbee67bf8852011-08-17 17:51:35 -0700242}
243
244/* Dump the CFG into a DOT graph */
245void oatDumpCFG(CompilationUnit* cUnit, const char* dirPrefix)
246{
buzbee67bf8852011-08-17 17:51:35 -0700247 FILE* file;
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800248 std::string name(PrettyMethod(cUnit->method_idx, *cUnit->dex_file));
buzbee67bf8852011-08-17 17:51:35 -0700249 char startOffset[80];
250 sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
buzbeeba938cb2012-02-03 14:47:55 -0800251 char* fileName = (char*) oatNew(cUnit,
buzbeec143c552011-08-20 17:38:58 -0700252 strlen(dirPrefix) +
253 name.length() +
buzbee5abfa3e2012-01-31 17:01:43 -0800254 strlen(".dot") + 1, true, kAllocDebugInfo);
buzbeec143c552011-08-20 17:38:58 -0700255 sprintf(fileName, "%s%s%s.dot", dirPrefix, name.c_str(), startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700256
257 /*
258 * Convert the special characters into a filesystem- and shell-friendly
259 * format.
260 */
261 int i;
262 for (i = strlen(dirPrefix); fileName[i]; i++) {
263 if (fileName[i] == '/') {
264 fileName[i] = '_';
265 } else if (fileName[i] == ';') {
266 fileName[i] = '#';
267 } else if (fileName[i] == '$') {
268 fileName[i] = '+';
269 } else if (fileName[i] == '(' || fileName[i] == ')') {
270 fileName[i] = '@';
271 } else if (fileName[i] == '<' || fileName[i] == '>') {
272 fileName[i] = '=';
273 }
274 }
275 file = fopen(fileName, "w");
276 if (file == NULL) {
277 return;
278 }
279 fprintf(file, "digraph G {\n");
280
281 fprintf(file, " rankdir=TB\n");
282
283 int numReachableBlocks = cUnit->numReachableBlocks;
284 int idx;
285 const GrowableList *blockList = &cUnit->blockList;
286
287 for (idx = 0; idx < numReachableBlocks; idx++) {
288 int blockIdx = cUnit->dfsOrder.elemList[idx];
289 BasicBlock *bb = (BasicBlock *) oatGrowableListGetElement(blockList,
290 blockIdx);
291 if (bb == NULL) break;
292 if (bb->blockType == kEntryBlock) {
293 fprintf(file, " entry [shape=Mdiamond];\n");
294 } else if (bb->blockType == kExitBlock) {
295 fprintf(file, " exit [shape=Mdiamond];\n");
296 } else if (bb->blockType == kDalvikByteCode) {
297 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
298 bb->startOffset);
299 const MIR *mir;
300 fprintf(file, " {block id %d\\l}%s\\\n", bb->id,
301 bb->firstMIRInsn ? " | " : " ");
302 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
303 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
304 mir->ssaRep ?
305 oatFullDisassembler(cUnit, mir) :
306 dexGetOpcodeName(mir->dalvikInsn.opcode),
307 mir->next ? " | " : " ");
308 }
309 fprintf(file, " }\"];\n\n");
310 } else if (bb->blockType == kExceptionHandling) {
311 char blockName[BLOCK_NAME_LEN];
312
313 oatGetBlockName(bb, blockName);
314 fprintf(file, " %s [shape=invhouse];\n", blockName);
315 }
316
317 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
318
319 if (bb->taken) {
320 oatGetBlockName(bb, blockName1);
321 oatGetBlockName(bb->taken, blockName2);
322 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
323 blockName1, blockName2);
324 }
325 if (bb->fallThrough) {
326 oatGetBlockName(bb, blockName1);
327 oatGetBlockName(bb->fallThrough, blockName2);
328 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
329 }
330
331 if (bb->successorBlockList.blockListType != kNotUsed) {
332 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
333 bb->startOffset,
334 (bb->successorBlockList.blockListType == kCatch) ?
335 "Mrecord" : "record");
336 GrowableListIterator iterator;
337 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
338 &iterator);
339 SuccessorBlockInfo *successorBlockInfo =
340 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
341
342 int succId = 0;
343 while (true) {
344 if (successorBlockInfo == NULL) break;
345
346 BasicBlock *destBlock = successorBlockInfo->block;
347 SuccessorBlockInfo *nextSuccessorBlockInfo =
348 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
349
350 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
351 succId++,
352 successorBlockInfo->key,
353 destBlock->startOffset,
354 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
355
356 successorBlockInfo = nextSuccessorBlockInfo;
357 }
358 fprintf(file, " }\"];\n\n");
359
360 oatGetBlockName(bb, blockName1);
361 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
362 blockName1, bb->startOffset);
363
364 if (bb->successorBlockList.blockListType == kPackedSwitch ||
365 bb->successorBlockList.blockListType == kSparseSwitch) {
366
367 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
368 &iterator);
369
370 succId = 0;
371 while (true) {
372 SuccessorBlockInfo *successorBlockInfo =
373 (SuccessorBlockInfo *)
374 oatGrowableListIteratorNext(&iterator);
375 if (successorBlockInfo == NULL) break;
376
377 BasicBlock *destBlock = successorBlockInfo->block;
378
379 oatGetBlockName(destBlock, blockName2);
380 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
381 bb->startOffset, succId++,
382 blockName2);
383 }
384 }
385 }
386 fprintf(file, "\n");
387
buzbeece302932011-10-04 14:32:18 -0700388 /* Display the dominator tree */
buzbee67bf8852011-08-17 17:51:35 -0700389 oatGetBlockName(bb, blockName1);
390 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
391 blockName1, blockName1);
392 if (bb->iDom) {
393 oatGetBlockName(bb->iDom, blockName2);
394 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
395 blockName2, blockName1);
396 }
buzbee67bf8852011-08-17 17:51:35 -0700397 }
398 fprintf(file, "}\n");
399 fclose(file);
400}
401
402/* Verify if all the successor is connected with all the claimed predecessors */
buzbee31a4a6f2012-02-28 15:36:15 -0800403bool verifyPredInfo(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -0700404{
buzbee5abfa3e2012-01-31 17:01:43 -0800405 GrowableListIterator iter;
buzbee67bf8852011-08-17 17:51:35 -0700406
buzbee5abfa3e2012-01-31 17:01:43 -0800407 oatGrowableListIteratorInit(bb->predecessors, &iter);
buzbee67bf8852011-08-17 17:51:35 -0700408 while (true) {
buzbee5abfa3e2012-01-31 17:01:43 -0800409 BasicBlock *predBB = (BasicBlock*)oatGrowableListIteratorNext(&iter);
410 if (!predBB) break;
buzbee67bf8852011-08-17 17:51:35 -0700411 bool found = false;
412 if (predBB->taken == bb) {
413 found = true;
414 } else if (predBB->fallThrough == bb) {
415 found = true;
416 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
417 GrowableListIterator iterator;
418 oatGrowableListIteratorInit(&predBB->successorBlockList.blocks,
419 &iterator);
420 while (true) {
421 SuccessorBlockInfo *successorBlockInfo =
422 (SuccessorBlockInfo *)
423 oatGrowableListIteratorNext(&iterator);
424 if (successorBlockInfo == NULL) break;
425 BasicBlock *succBB = successorBlockInfo->block;
426 if (succBB == bb) {
427 found = true;
428 break;
429 }
430 }
431 }
432 if (found == false) {
433 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
434 oatGetBlockName(bb, blockName1);
435 oatGetBlockName(predBB, blockName2);
436 oatDumpCFG(cUnit, "/sdcard/cfg/");
437 LOG(FATAL) << "Successor " << blockName1 << "not found from "
438 << blockName2;
439 }
440 }
441 return true;
442}
443
444/* Identify code range in try blocks and set up the empty catch blocks */
buzbee31a4a6f2012-02-28 15:36:15 -0800445void processTryCatchBlocks(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700446{
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800447 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbeee9a72f62011-09-04 17:59:07 -0700448 int triesSize = code_item->tries_size_;
buzbee67bf8852011-08-17 17:51:35 -0700449 int offset;
450
451 if (triesSize == 0) {
452 return;
453 }
454
buzbee67bf8852011-08-17 17:51:35 -0700455 ArenaBitVector* tryBlockAddr = cUnit->tryBlockAddr;
456
buzbeee9a72f62011-09-04 17:59:07 -0700457 for (int i = 0; i < triesSize; i++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800458 const DexFile::TryItem* pTry =
459 DexFile::GetTryItems(*code_item, i);
buzbeee9a72f62011-09-04 17:59:07 -0700460 int startOffset = pTry->start_addr_;
461 int endOffset = startOffset + pTry->insn_count_;
buzbee67bf8852011-08-17 17:51:35 -0700462 for (offset = startOffset; offset < endOffset; offset++) {
buzbeeba938cb2012-02-03 14:47:55 -0800463 oatSetBit(cUnit, tryBlockAddr, offset);
buzbee67bf8852011-08-17 17:51:35 -0700464 }
465 }
466
buzbeee9a72f62011-09-04 17:59:07 -0700467 // Iterate over each of the handlers to enqueue the empty Catch blocks
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800468 const byte* handlers_ptr =
469 DexFile::GetCatchHandlerData(*code_item, 0);
470 uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
buzbeee9a72f62011-09-04 17:59:07 -0700471 for (uint32_t idx = 0; idx < handlers_size; idx++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800472 CatchHandlerIterator iterator(handlers_ptr);
Ian Rogers0571d352011-11-03 19:51:38 -0700473 for (; iterator.HasNext(); iterator.Next()) {
474 uint32_t address = iterator.GetHandlerAddress();
buzbee9ab05de2012-01-18 15:43:48 -0800475 findBlock(cUnit, address, false /* split */, true /*create*/,
476 /* immedPredBlockP */ NULL);
buzbee67bf8852011-08-17 17:51:35 -0700477 }
Ian Rogers0571d352011-11-03 19:51:38 -0700478 handlers_ptr = iterator.EndDataPointer();
buzbee67bf8852011-08-17 17:51:35 -0700479 }
480}
481
482/* Process instructions with the kInstrCanBranch flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800483BasicBlock* processCanBranch(CompilationUnit* cUnit, BasicBlock* curBlock,
484 MIR* insn, int curOffset, int width, int flags,
485 const u2* codePtr, const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700486{
487 int target = curOffset;
488 switch (insn->dalvikInsn.opcode) {
489 case OP_GOTO:
490 case OP_GOTO_16:
491 case OP_GOTO_32:
492 target += (int) insn->dalvikInsn.vA;
493 break;
494 case OP_IF_EQ:
495 case OP_IF_NE:
496 case OP_IF_LT:
497 case OP_IF_GE:
498 case OP_IF_GT:
499 case OP_IF_LE:
500 target += (int) insn->dalvikInsn.vC;
501 break;
502 case OP_IF_EQZ:
503 case OP_IF_NEZ:
504 case OP_IF_LTZ:
505 case OP_IF_GEZ:
506 case OP_IF_GTZ:
507 case OP_IF_LEZ:
508 target += (int) insn->dalvikInsn.vB;
509 break;
510 default:
511 LOG(FATAL) << "Unexpected opcode(" << (int)insn->dalvikInsn.opcode
512 << ") with kInstrCanBranch set";
513 }
514 BasicBlock *takenBlock = findBlock(cUnit, target,
515 /* split */
516 true,
517 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800518 true,
519 /* immedPredBlockP */
520 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700521 curBlock->taken = takenBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800522 oatInsertGrowableList(cUnit, takenBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700523
524 /* Always terminate the current block for conditional branches */
525 if (flags & kInstrCanContinue) {
526 BasicBlock *fallthroughBlock = findBlock(cUnit,
527 curOffset + width,
528 /*
529 * If the method is processed
530 * in sequential order from the
531 * beginning, we don't need to
532 * specify split for continue
533 * blocks. However, this
534 * routine can be called by
535 * compileLoop, which starts
536 * parsing the method from an
537 * arbitrary address in the
538 * method body.
539 */
540 true,
541 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800542 true,
543 /* immedPredBlockP */
544 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700545 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800546 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800547 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700548 } else if (codePtr < codeEnd) {
549 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
550 if (contentIsInsn(codePtr)) {
551 findBlock(cUnit, curOffset + width,
552 /* split */
553 false,
554 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800555 true,
556 /* immedPredBlockP */
557 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700558 }
559 }
buzbeee941e2c2011-12-05 12:38:17 -0800560 return curBlock;
buzbee67bf8852011-08-17 17:51:35 -0700561}
562
563/* Process instructions with the kInstrCanSwitch flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800564void processCanSwitch(CompilationUnit* cUnit, BasicBlock* curBlock,
565 MIR* insn, int curOffset, int width, int flags)
buzbee67bf8852011-08-17 17:51:35 -0700566{
567 u2* switchData= (u2 *) (cUnit->insns + curOffset +
568 insn->dalvikInsn.vB);
569 int size;
570 int* keyTable;
571 int* targetTable;
572 int i;
573 int firstKey;
574
575 /*
576 * Packed switch data format:
577 * ushort ident = 0x0100 magic value
578 * ushort size number of entries in the table
579 * int first_key first (and lowest) switch case value
580 * int targets[size] branch targets, relative to switch opcode
581 *
582 * Total size is (4+size*2) 16-bit code units.
583 */
584 if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
buzbeeed3e9302011-09-23 17:34:19 -0700585 DCHECK_EQ(switchData[0], kPackedSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700586 size = switchData[1];
587 firstKey = switchData[2] | (switchData[3] << 16);
588 targetTable = (int *) &switchData[4];
589 keyTable = NULL; // Make the compiler happy
590 /*
591 * Sparse switch data format:
592 * ushort ident = 0x0200 magic value
593 * ushort size number of entries in the table; > 0
594 * int keys[size] keys, sorted low-to-high; 32-bit aligned
595 * int targets[size] branch targets, relative to switch opcode
596 *
597 * Total size is (2+size*4) 16-bit code units.
598 */
599 } else {
buzbeeed3e9302011-09-23 17:34:19 -0700600 DCHECK_EQ(switchData[0], kSparseSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700601 size = switchData[1];
602 keyTable = (int *) &switchData[2];
603 targetTable = (int *) &switchData[2 + size*2];
604 firstKey = 0; // To make the compiler happy
605 }
606
607 if (curBlock->successorBlockList.blockListType != kNotUsed) {
608 LOG(FATAL) << "Successor block list already in use: " <<
609 (int)curBlock->successorBlockList.blockListType;
610 }
611 curBlock->successorBlockList.blockListType =
612 (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
613 kPackedSwitch : kSparseSwitch;
buzbeeba938cb2012-02-03 14:47:55 -0800614 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, size,
buzbee5abfa3e2012-01-31 17:01:43 -0800615 kListSuccessorBlocks);
buzbee67bf8852011-08-17 17:51:35 -0700616
617 for (i = 0; i < size; i++) {
618 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
619 /* split */
620 true,
621 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800622 true,
623 /* immedPredBlockP */
624 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700625 SuccessorBlockInfo *successorBlockInfo =
buzbeeba938cb2012-02-03 14:47:55 -0800626 (SuccessorBlockInfo *) oatNew(cUnit, sizeof(SuccessorBlockInfo),
627 false, kAllocSuccessor);
buzbee67bf8852011-08-17 17:51:35 -0700628 successorBlockInfo->block = caseBlock;
629 successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)?
630 firstKey + i : keyTable[i];
buzbeeba938cb2012-02-03 14:47:55 -0800631 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
buzbee67bf8852011-08-17 17:51:35 -0700632 (intptr_t) successorBlockInfo);
buzbeeba938cb2012-02-03 14:47:55 -0800633 oatInsertGrowableList(cUnit, caseBlock->predecessors,
634 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700635 }
636
637 /* Fall-through case */
638 BasicBlock* fallthroughBlock = findBlock(cUnit,
639 curOffset + width,
640 /* split */
641 false,
642 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800643 true,
644 /* immedPredBlockP */
645 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700646 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800647 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
648 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700649}
650
651/* Process instructions with the kInstrCanThrow flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800652void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock, MIR* insn,
653 int curOffset, int width, int flags,
654 ArenaBitVector* tryBlockAddr, const u2* codePtr,
655 const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700656{
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800657 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbee67bf8852011-08-17 17:51:35 -0700658
659 /* In try block */
660 if (oatIsBitSet(tryBlockAddr, curOffset)) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800661 CatchHandlerIterator iterator(*code_item, curOffset);
buzbee67bf8852011-08-17 17:51:35 -0700662
buzbee67bf8852011-08-17 17:51:35 -0700663 if (curBlock->successorBlockList.blockListType != kNotUsed) {
664 LOG(FATAL) << "Successor block list already in use: " <<
665 (int)curBlock->successorBlockList.blockListType;
666 }
buzbeee9a72f62011-09-04 17:59:07 -0700667
buzbee67bf8852011-08-17 17:51:35 -0700668 curBlock->successorBlockList.blockListType = kCatch;
buzbeeba938cb2012-02-03 14:47:55 -0800669 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, 2,
buzbee5abfa3e2012-01-31 17:01:43 -0800670 kListSuccessorBlocks);
buzbee67bf8852011-08-17 17:51:35 -0700671
Ian Rogers0571d352011-11-03 19:51:38 -0700672 for (;iterator.HasNext(); iterator.Next()) {
673 BasicBlock *catchBlock = findBlock(cUnit, iterator.GetHandlerAddress(),
buzbeee9a72f62011-09-04 17:59:07 -0700674 false /* split*/,
buzbee9ab05de2012-01-18 15:43:48 -0800675 false /* creat */,
676 NULL /* immedPredBlockP */);
buzbee43a36422011-09-14 14:00:13 -0700677 catchBlock->catchEntry = true;
buzbeeba938cb2012-02-03 14:47:55 -0800678 SuccessorBlockInfo *successorBlockInfo = (SuccessorBlockInfo *)
679 oatNew(cUnit, sizeof(SuccessorBlockInfo), false,
680 kAllocSuccessor);
buzbee67bf8852011-08-17 17:51:35 -0700681 successorBlockInfo->block = catchBlock;
Ian Rogers0571d352011-11-03 19:51:38 -0700682 successorBlockInfo->key = iterator.GetHandlerTypeIndex();
buzbeeba938cb2012-02-03 14:47:55 -0800683 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
buzbee67bf8852011-08-17 17:51:35 -0700684 (intptr_t) successorBlockInfo);
buzbeeba938cb2012-02-03 14:47:55 -0800685 oatInsertGrowableList(cUnit, catchBlock->predecessors,
686 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700687 }
688 } else {
buzbee5abfa3e2012-01-31 17:01:43 -0800689 BasicBlock *ehBlock = oatNewBB(cUnit, kExceptionHandling,
690 cUnit->numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700691 curBlock->taken = ehBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800692 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) ehBlock);
buzbee67bf8852011-08-17 17:51:35 -0700693 ehBlock->startOffset = curOffset;
buzbeeba938cb2012-02-03 14:47:55 -0800694 oatInsertGrowableList(cUnit, ehBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700695 }
696
697 /*
698 * Force the current block to terminate.
699 *
700 * Data may be present before codeEnd, so we need to parse it to know
701 * whether it is code or data.
702 */
703 if (codePtr < codeEnd) {
704 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
705 if (contentIsInsn(codePtr)) {
706 BasicBlock *fallthroughBlock = findBlock(cUnit,
707 curOffset + width,
708 /* split */
709 false,
710 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800711 true,
712 /* immedPredBlockP */
713 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700714 /*
buzbee510c6052011-10-27 10:47:20 -0700715 * OP_THROW is an unconditional branch. NOTE:
716 * OP_THROW_VERIFICATION_ERROR is also an unconditional
717 * branch, but we shouldn't treat it as such until we have
718 * a dead code elimination pass (which won't be important
719 * until inlining w/ constant propogation is implemented.
buzbee67bf8852011-08-17 17:51:35 -0700720 */
buzbee510c6052011-10-27 10:47:20 -0700721 if (insn->dalvikInsn.opcode != OP_THROW) {
buzbee67bf8852011-08-17 17:51:35 -0700722 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800723 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800724 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700725 }
726 }
727 }
728}
729
730/*
731 * Compile a method.
732 */
buzbee31a4a6f2012-02-28 15:36:15 -0800733CompiledMethod* oatCompileMethod(Compiler& compiler,
734 const DexFile::CodeItem* code_item,
Ian Rogersa3760aa2011-11-14 14:32:37 -0800735 uint32_t access_flags, uint32_t method_idx,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800736 const ClassLoader* class_loader,
buzbee31a4a6f2012-02-28 15:36:15 -0800737 const DexFile& dex_file,
738 InstructionSet insnSet)
buzbee67bf8852011-08-17 17:51:35 -0700739{
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800740 VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
Brian Carlstrom94496d32011-08-22 09:22:47 -0700741
buzbeec143c552011-08-20 17:38:58 -0700742 const u2* codePtr = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700743 const u2* codeEnd = code_item->insns_ + code_item->insns_size_in_code_units_;
buzbee67bf8852011-08-17 17:51:35 -0700744 int numBlocks = 0;
745 unsigned int curOffset = 0;
746
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800747 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700748 UniquePtr<CompilationUnit> cUnit(new CompilationUnit);
749 memset(cUnit.get(), 0, sizeof(*cUnit));
buzbeeba938cb2012-02-03 14:47:55 -0800750
751 oatInit(cUnit.get(), compiler);
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700752 cUnit->compiler = &compiler;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800753 cUnit->class_linker = class_linker;
754 cUnit->dex_file = &dex_file;
755 cUnit->dex_cache = class_linker->FindDexCache(dex_file);
756 cUnit->method_idx = method_idx;
757 cUnit->code_item = code_item;
758 cUnit->access_flags = access_flags;
759 cUnit->shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700760 cUnit->instructionSet = (OatInstructionSetType)insnSet;
761 cUnit->insns = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700762 cUnit->insnsSize = code_item->insns_size_in_code_units_;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800763 cUnit->numIns = code_item->ins_size_;
764 cUnit->numRegs = code_item->registers_size_ - cUnit->numIns;
765 cUnit->numOuts = code_item->outs_size_;
766 /* Adjust this value accordingly once inlining is performed */
767 cUnit->numDalvikRegisters = code_item->registers_size_;
buzbee5b537102012-01-17 17:33:47 -0800768 cUnit->blockMap = std::map<unsigned int, BasicBlock*>();
769 cUnit->blockMap.clear();
buzbee85d8c1e2012-01-27 15:52:35 -0800770 cUnit->boundaryMap = std::map<unsigned int, LIR*>();
771 cUnit->boundaryMap.clear();
buzbeeba938cb2012-02-03 14:47:55 -0800772 // TODO: set these from command line
773 cUnit->compilerMethodMatch = new std::string("");
774 cUnit->compilerFlipMatch = false;
775 bool useMatch = cUnit->compilerMethodMatch->length() != 0;
776 bool match = useMatch && (cUnit->compilerFlipMatch ^
777 (PrettyMethod(method_idx, dex_file).find(*cUnit->compilerMethodMatch)
778 != std::string::npos));
buzbeece302932011-10-04 14:32:18 -0700779 if (!useMatch || match) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700780 cUnit->disableOpt = compilerOptimizerDisableFlags;
781 cUnit->enableDebug = compilerDebugFlags;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800782 cUnit->printMe = VLOG_IS_ON(compiler) || (cUnit->enableDebug & (1 << kDebugVerbose));
buzbeece302932011-10-04 14:32:18 -0700783 }
buzbee67bf8852011-08-17 17:51:35 -0700784
buzbee44b412b2012-02-04 08:50:53 -0800785 /* Are we generating code for the debugger? */
Elliott Hughesde6e4cf2012-02-27 14:46:06 -0800786 if (compiler.IsDebuggingSupported()) {
buzbee44b412b2012-02-04 08:50:53 -0800787 cUnit->genDebugger = true;
788 // Yes, disable most optimizations
789 cUnit->disableOpt |= (
790 (1 << kLoadStoreElimination) |
791 (1 << kLoadHoisting) |
792 (1 << kSuppressLoads) |
793 (1 << kPromoteRegs) |
794 (1 << kTrackLiveTemps));
795 }
796
buzbeecefd1872011-09-09 09:59:52 -0700797 /* Assume non-throwing leaf */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700798 cUnit->attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
buzbeecefd1872011-09-09 09:59:52 -0700799
buzbee5abfa3e2012-01-31 17:01:43 -0800800 /* Initialize the block list, estimate size based on insnsSize */
buzbeeba938cb2012-02-03 14:47:55 -0800801 oatInitGrowableList(cUnit.get(), &cUnit->blockList, cUnit->insnsSize,
802 kListBlockList);
buzbee67bf8852011-08-17 17:51:35 -0700803
804 /* Initialize the switchTables list */
buzbeeba938cb2012-02-03 14:47:55 -0800805 oatInitGrowableList(cUnit.get(), &cUnit->switchTables, 4,
806 kListSwitchTables);
buzbee67bf8852011-08-17 17:51:35 -0700807
808 /* Intialize the fillArrayData list */
buzbeeba938cb2012-02-03 14:47:55 -0800809 oatInitGrowableList(cUnit.get(), &cUnit->fillArrayData, 4,
810 kListFillArrayData);
buzbee67bf8852011-08-17 17:51:35 -0700811
buzbee5abfa3e2012-01-31 17:01:43 -0800812 /* Intialize the throwLaunchpads list, estimate size based on insnsSize */
buzbeeba938cb2012-02-03 14:47:55 -0800813 oatInitGrowableList(cUnit.get(), &cUnit->throwLaunchpads, cUnit->insnsSize,
buzbee5abfa3e2012-01-31 17:01:43 -0800814 kListThrowLaunchPads);
buzbee5ade1d22011-09-09 14:44:52 -0700815
buzbeec1f45042011-09-21 16:03:19 -0700816 /* Intialize the suspendLaunchpads list */
buzbeeba938cb2012-02-03 14:47:55 -0800817 oatInitGrowableList(cUnit.get(), &cUnit->suspendLaunchpads, 2048,
buzbee5abfa3e2012-01-31 17:01:43 -0800818 kListSuspendLaunchPads);
buzbeec1f45042011-09-21 16:03:19 -0700819
buzbee67bf8852011-08-17 17:51:35 -0700820 /* Allocate the bit-vector to track the beginning of basic blocks */
buzbeeba938cb2012-02-03 14:47:55 -0800821 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit.get(),
822 cUnit->insnsSize,
buzbee67bf8852011-08-17 17:51:35 -0700823 true /* expandable */);
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700824 cUnit->tryBlockAddr = tryBlockAddr;
buzbee67bf8852011-08-17 17:51:35 -0700825
826 /* Create the default entry and exit blocks and enter them to the list */
buzbee5abfa3e2012-01-31 17:01:43 -0800827 BasicBlock *entryBlock = oatNewBB(cUnit.get(), kEntryBlock, numBlocks++);
828 BasicBlock *exitBlock = oatNewBB(cUnit.get(), kExitBlock, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700829
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700830 cUnit->entryBlock = entryBlock;
831 cUnit->exitBlock = exitBlock;
buzbee67bf8852011-08-17 17:51:35 -0700832
buzbeeba938cb2012-02-03 14:47:55 -0800833 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) entryBlock);
834 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) exitBlock);
buzbee67bf8852011-08-17 17:51:35 -0700835
836 /* Current block to record parsed instructions */
buzbee5abfa3e2012-01-31 17:01:43 -0800837 BasicBlock *curBlock = oatNewBB(cUnit.get(), kDalvikByteCode, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700838 curBlock->startOffset = 0;
buzbeeba938cb2012-02-03 14:47:55 -0800839 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) curBlock);
buzbee5b537102012-01-17 17:33:47 -0800840 /* Add first block to the fast lookup cache */
841 cUnit->blockMap.insert(std::make_pair(curBlock->startOffset, curBlock));
buzbee67bf8852011-08-17 17:51:35 -0700842 entryBlock->fallThrough = curBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800843 oatInsertGrowableList(cUnit.get(), curBlock->predecessors,
844 (intptr_t)entryBlock);
buzbee67bf8852011-08-17 17:51:35 -0700845
846 /*
847 * Store back the number of blocks since new blocks may be created of
848 * accessing cUnit.
849 */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700850 cUnit->numBlocks = numBlocks;
buzbee67bf8852011-08-17 17:51:35 -0700851
852 /* Identify code range in try blocks and set up the empty catch blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700853 processTryCatchBlocks(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700854
855 /* Parse all instructions and put them into containing basic blocks */
856 while (codePtr < codeEnd) {
buzbeeba938cb2012-02-03 14:47:55 -0800857 MIR *insn = (MIR *) oatNew(cUnit.get(), sizeof(MIR), true, kAllocMIR);
buzbee67bf8852011-08-17 17:51:35 -0700858 insn->offset = curOffset;
buzbeeba938cb2012-02-03 14:47:55 -0800859 int width = parseInsn(cUnit.get(), codePtr, &insn->dalvikInsn, false);
buzbee67bf8852011-08-17 17:51:35 -0700860 insn->width = width;
861
862 /* Terminate when the data section is seen */
863 if (width == 0)
864 break;
865
866 oatAppendMIR(curBlock, insn);
867
868 codePtr += width;
869 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
870
buzbee5abfa3e2012-01-31 17:01:43 -0800871 int dfFlags = oatDataFlowAttributes[insn->dalvikInsn.opcode];
872
873 if (dfFlags & DF_HAS_DEFS) {
874 cUnit->defCount += (dfFlags & DF_DA_WIDE) ? 2 : 1;
875 }
buzbee99ba9642012-01-25 14:23:14 -0800876
buzbee67bf8852011-08-17 17:51:35 -0700877 if (flags & kInstrCanBranch) {
buzbeee941e2c2011-12-05 12:38:17 -0800878 curBlock = processCanBranch(cUnit.get(), curBlock, insn, curOffset,
879 width, flags, codePtr, codeEnd);
buzbee67bf8852011-08-17 17:51:35 -0700880 } else if (flags & kInstrCanReturn) {
881 curBlock->fallThrough = exitBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800882 oatInsertGrowableList(cUnit.get(), exitBlock->predecessors,
883 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700884 /*
885 * Terminate the current block if there are instructions
886 * afterwards.
887 */
888 if (codePtr < codeEnd) {
889 /*
890 * Create a fallthrough block for real instructions
891 * (incl. OP_NOP).
892 */
893 if (contentIsInsn(codePtr)) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700894 findBlock(cUnit.get(), curOffset + width,
buzbee67bf8852011-08-17 17:51:35 -0700895 /* split */
896 false,
897 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800898 true,
899 /* immedPredBlockP */
900 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700901 }
902 }
903 } else if (flags & kInstrCanThrow) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700904 processCanThrow(cUnit.get(), curBlock, insn, curOffset, width, flags,
buzbee67bf8852011-08-17 17:51:35 -0700905 tryBlockAddr, codePtr, codeEnd);
906 } else if (flags & kInstrCanSwitch) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700907 processCanSwitch(cUnit.get(), curBlock, insn, curOffset, width, flags);
buzbee67bf8852011-08-17 17:51:35 -0700908 }
909 curOffset += width;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700910 BasicBlock *nextBlock = findBlock(cUnit.get(), curOffset,
buzbee67bf8852011-08-17 17:51:35 -0700911 /* split */
912 false,
913 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800914 false,
915 /* immedPredBlockP */
916 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700917 if (nextBlock) {
918 /*
919 * The next instruction could be the target of a previously parsed
920 * forward branch so a block is already created. If the current
921 * instruction is not an unconditional branch, connect them through
922 * the fall-through link.
923 */
buzbeeed3e9302011-09-23 17:34:19 -0700924 DCHECK(curBlock->fallThrough == NULL ||
buzbee67bf8852011-08-17 17:51:35 -0700925 curBlock->fallThrough == nextBlock ||
926 curBlock->fallThrough == exitBlock);
927
928 if ((curBlock->fallThrough == NULL) &&
929 (flags & kInstrCanContinue)) {
930 curBlock->fallThrough = nextBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800931 oatInsertGrowableList(cUnit.get(), nextBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800932 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700933 }
934 curBlock = nextBlock;
935 }
936 }
937
buzbee5abfa3e2012-01-31 17:01:43 -0800938 if (!(cUnit->disableOpt & (1 << kSkipLargeMethodOptimization))) {
buzbee99ba9642012-01-25 14:23:14 -0800939 if ((cUnit->numBlocks > MANY_BLOCKS) ||
940 ((cUnit->numBlocks > MANY_BLOCKS_INITIALIZER) &&
941 PrettyMethod(method_idx, dex_file).find("init>") !=
942 std::string::npos)) {
943 cUnit->disableDataflow = true;
944 // Disable optimization which require dataflow/ssa
945 cUnit->disableOpt |=
946 (1 << kNullCheckElimination) |
947 (1 << kPromoteRegs);
948 if (cUnit->printMe) {
949 LOG(INFO) << "Compiler: " << PrettyMethod(method_idx, dex_file)
950 << " too big: " << cUnit->numBlocks;
951 }
952 }
953 }
954
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700955 if (cUnit->printMe) {
956 oatDumpCompilationUnit(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700957 }
958
buzbee5b537102012-01-17 17:33:47 -0800959 if (cUnit->enableDebug & (1 << kDebugVerifyDataflow)) {
960 /* Verify if all blocks are connected as claimed */
buzbee5abfa3e2012-01-31 17:01:43 -0800961 oatDataFlowAnalysisDispatcher(cUnit.get(), verifyPredInfo, kAllNodes,
962 false /* isIterative */);
buzbee5b537102012-01-17 17:33:47 -0800963 }
buzbee67bf8852011-08-17 17:51:35 -0700964
965 /* Perform SSA transformation for the whole method */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700966 oatMethodSSATransformation(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700967
buzbee43a36422011-09-14 14:00:13 -0700968 /* Perform null check elimination */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700969 oatMethodNullCheckElimination(cUnit.get());
buzbee43a36422011-09-14 14:00:13 -0700970
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700971 oatInitializeRegAlloc(cUnit.get()); // Needs to happen after SSA naming
buzbee67bf8852011-08-17 17:51:35 -0700972
973 /* Allocate Registers using simple local allocation scheme */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700974 oatSimpleRegAlloc(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700975
976 /* Convert MIR to LIR, etc. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700977 oatMethodMIR2LIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700978
979 // Debugging only
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700980 if (cUnit->enableDebug & (1 << kDebugDumpCFG)) {
981 oatDumpCFG(cUnit.get(), "/sdcard/cfg/");
buzbeeec5adf32011-09-11 15:25:43 -0700982 }
buzbee67bf8852011-08-17 17:51:35 -0700983
984 /* Method is not empty */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700985 if (cUnit->firstLIRInsn) {
buzbee67bf8852011-08-17 17:51:35 -0700986
987 // mark the targets of switch statement case labels
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700988 oatProcessSwitchTables(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700989
990 /* Convert LIR into machine code. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700991 oatAssembleLIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700992
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700993 if (cUnit->printMe) {
994 oatCodegenDump(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700995 }
996 }
997
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700998 // Combine vmap tables - core regs, then fp regs - into vmapTable
999 std::vector<uint16_t> vmapTable;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001000 for (size_t i = 0 ; i < cUnit->coreVmapTable.size(); i++) {
1001 vmapTable.push_back(cUnit->coreVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001002 }
buzbeec41e5b52011-09-23 12:46:19 -07001003 // Add a marker to take place of lr
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -07001004 vmapTable.push_back(INVALID_VREG);
buzbeec41e5b52011-09-23 12:46:19 -07001005 // Combine vmap tables - core regs, then fp regs
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001006 for (uint32_t i = 0; i < cUnit->fpVmapTable.size(); i++) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001007 vmapTable.push_back(cUnit->fpVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001008 }
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -07001009 DCHECK_EQ(vmapTable.size(),
1010 static_cast<uint32_t>(__builtin_popcount(cUnit->coreSpillMask)
1011 + __builtin_popcount(cUnit->fpSpillMask)));
1012 DCHECK_GE(vmapTable.size(), 1U); // should always at least one INVALID_VREG for lr
1013
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001014 CompiledMethod* result = new CompiledMethod(kThumb2, cUnit->codeBuffer,
Ian Rogers0571d352011-11-03 19:51:38 -07001015 cUnit->frameSize, cUnit->coreSpillMask,
1016 cUnit->fpSpillMask, cUnit->mappingTable,
1017 vmapTable);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001018
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -08001019 VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file)
buzbee5abfa3e2012-01-31 17:01:43 -08001020 << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0]))
1021 << " bytes)";
1022
1023#ifdef WITH_MEMSTATS
1024 if (cUnit->enableDebug & (1 << kDebugShowMemoryUsage)) {
1025 oatDumpMemStats(cUnit.get());
1026 }
1027#endif
buzbee67bf8852011-08-17 17:51:35 -07001028
buzbeeba938cb2012-02-03 14:47:55 -08001029 oatArenaReset(cUnit.get());
1030
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001031 return result;
buzbee67bf8852011-08-17 17:51:35 -07001032}
1033
buzbeeba938cb2012-02-03 14:47:55 -08001034void oatInit(CompilationUnit* cUnit, const Compiler& compiler)
buzbee67bf8852011-08-17 17:51:35 -07001035{
buzbee67bf8852011-08-17 17:51:35 -07001036 if (!oatArchInit()) {
1037 LOG(FATAL) << "Failed to initialize oat";
1038 }
buzbeeba938cb2012-02-03 14:47:55 -08001039 if (!oatHeapInit(cUnit)) {
buzbee67bf8852011-08-17 17:51:35 -07001040 LOG(FATAL) << "Failed to initialize oat heap";
1041 }
1042}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001043
1044} // namespace art