blob: d97c20fb60f2a29b7f33e4fdb1ae75a26ed85abc [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) |
buzbee86a4bce2012-03-06 18:15:00 -080036 //(1 << kSafeOptimizations) |
buzbee239c4e72012-03-16 08:42:29 -070037 //(1 << kBBOpt) |
buzbeece302932011-10-04 14:32:18 -070038 0;
39
40uint32_t compilerDebugFlags = 0 | // Enable debug/testing modes
buzbeee3de7492011-10-05 13:37:17 -070041 //(1 << kDebugDisplayMissingTargets) |
buzbeece302932011-10-04 14:32:18 -070042 //(1 << kDebugVerbose) |
43 //(1 << kDebugDumpCFG) |
44 //(1 << kDebugSlowFieldPath) |
45 //(1 << kDebugSlowInvokePath) |
46 //(1 << kDebugSlowStringPath) |
47 //(1 << kDebugSlowestFieldPath) |
48 //(1 << kDebugSlowestStringPath) |
buzbee34c77ad2012-01-11 13:01:32 -080049 //(1 << kDebugExerciseResolveMethod) |
buzbee5b537102012-01-17 17:33:47 -080050 //(1 << kDebugVerifyDataflow) |
buzbee5abfa3e2012-01-31 17:01:43 -080051 //(1 << kDebugShowMemoryUsage) |
buzbee86a4bce2012-03-06 18:15:00 -080052 //(1 << kDebugShowNops) |
buzbeece302932011-10-04 14:32:18 -070053 0;
54
buzbee31a4a6f2012-02-28 15:36:15 -080055inline bool contentIsInsn(const u2* codePtr) {
buzbee67bf8852011-08-17 17:51:35 -070056 u2 instr = *codePtr;
Elliott Hughesadb8c672012-03-06 16:49:32 -080057 Instruction::Code opcode = (Instruction::Code)(instr & 0xff);
buzbee67bf8852011-08-17 17:51:35 -070058
59 /*
Elliott Hughesadb8c672012-03-06 16:49:32 -080060 * Since the low 8-bit in metadata may look like NOP, we need to check
buzbee67bf8852011-08-17 17:51:35 -070061 * both the low and whole sub-word to determine whether it is code or data.
62 */
Elliott Hughesadb8c672012-03-06 16:49:32 -080063 return (opcode != Instruction::NOP || instr == 0);
buzbee67bf8852011-08-17 17:51:35 -070064}
65
66/*
67 * Parse an instruction, return the length of the instruction
68 */
buzbee31a4a6f2012-02-28 15:36:15 -080069inline int parseInsn(CompilationUnit* cUnit, const u2* codePtr,
Elliott Hughesadb8c672012-03-06 16:49:32 -080070 DecodedInstruction* decoded_instruction, bool printMe)
buzbee67bf8852011-08-17 17:51:35 -070071{
Elliott Hughesadb8c672012-03-06 16:49:32 -080072 // Don't parse instruction data
73 if (!contentIsInsn(codePtr)) {
74 return 0;
75 }
buzbee67bf8852011-08-17 17:51:35 -070076
Elliott Hughesadb8c672012-03-06 16:49:32 -080077 const Instruction* instruction = Instruction::At(codePtr);
78 *decoded_instruction = DecodedInstruction(instruction);
buzbee67bf8852011-08-17 17:51:35 -070079
Elliott Hughesadb8c672012-03-06 16:49:32 -080080 if (printMe) {
81 char* decodedString = oatGetDalvikDisassembly(cUnit, *decoded_instruction, NULL);
82 LOG(INFO) << codePtr << ": 0x" << std::hex << static_cast<int>(decoded_instruction->opcode)
83 << " " << decodedString;
84 }
85 return instruction->SizeInCodeUnits();
buzbee67bf8852011-08-17 17:51:35 -070086}
87
88#define UNKNOWN_TARGET 0xffffffff
89
Elliott Hughesadb8c672012-03-06 16:49:32 -080090inline bool isGoto(MIR* insn) {
91 switch (insn->dalvikInsn.opcode) {
92 case Instruction::GOTO:
93 case Instruction::GOTO_16:
94 case Instruction::GOTO_32:
95 return true;
96 default:
97 return false;
buzbee67bf8852011-08-17 17:51:35 -070098 }
99}
100
101/*
102 * Identify unconditional branch instructions
103 */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800104inline bool isUnconditionalBranch(MIR* insn) {
105 switch (insn->dalvikInsn.opcode) {
106 case Instruction::RETURN_VOID:
107 case Instruction::RETURN:
108 case Instruction::RETURN_WIDE:
109 case Instruction::RETURN_OBJECT:
110 return true;
111 default:
112 return isGoto(insn);
113 }
buzbee67bf8852011-08-17 17:51:35 -0700114}
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,
Elliott Hughesadb8c672012-03-06 16:49:32 -0800304 mir->ssaRep ? oatFullDisassembler(cUnit, mir) : Instruction::Name(mir->dalvikInsn.opcode),
buzbee67bf8852011-08-17 17:51:35 -0700305 mir->next ? " | " : " ");
306 }
307 fprintf(file, " }\"];\n\n");
308 } else if (bb->blockType == kExceptionHandling) {
309 char blockName[BLOCK_NAME_LEN];
310
311 oatGetBlockName(bb, blockName);
312 fprintf(file, " %s [shape=invhouse];\n", blockName);
313 }
314
315 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
316
317 if (bb->taken) {
318 oatGetBlockName(bb, blockName1);
319 oatGetBlockName(bb->taken, blockName2);
320 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
321 blockName1, blockName2);
322 }
323 if (bb->fallThrough) {
324 oatGetBlockName(bb, blockName1);
325 oatGetBlockName(bb->fallThrough, blockName2);
326 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
327 }
328
329 if (bb->successorBlockList.blockListType != kNotUsed) {
330 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
331 bb->startOffset,
332 (bb->successorBlockList.blockListType == kCatch) ?
333 "Mrecord" : "record");
334 GrowableListIterator iterator;
335 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
336 &iterator);
337 SuccessorBlockInfo *successorBlockInfo =
338 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
339
340 int succId = 0;
341 while (true) {
342 if (successorBlockInfo == NULL) break;
343
344 BasicBlock *destBlock = successorBlockInfo->block;
345 SuccessorBlockInfo *nextSuccessorBlockInfo =
346 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
347
348 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
349 succId++,
350 successorBlockInfo->key,
351 destBlock->startOffset,
352 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
353
354 successorBlockInfo = nextSuccessorBlockInfo;
355 }
356 fprintf(file, " }\"];\n\n");
357
358 oatGetBlockName(bb, blockName1);
359 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
360 blockName1, bb->startOffset);
361
362 if (bb->successorBlockList.blockListType == kPackedSwitch ||
363 bb->successorBlockList.blockListType == kSparseSwitch) {
364
365 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
366 &iterator);
367
368 succId = 0;
369 while (true) {
370 SuccessorBlockInfo *successorBlockInfo =
371 (SuccessorBlockInfo *)
372 oatGrowableListIteratorNext(&iterator);
373 if (successorBlockInfo == NULL) break;
374
375 BasicBlock *destBlock = successorBlockInfo->block;
376
377 oatGetBlockName(destBlock, blockName2);
378 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
379 bb->startOffset, succId++,
380 blockName2);
381 }
382 }
383 }
384 fprintf(file, "\n");
385
buzbeece302932011-10-04 14:32:18 -0700386 /* Display the dominator tree */
buzbee67bf8852011-08-17 17:51:35 -0700387 oatGetBlockName(bb, blockName1);
388 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
389 blockName1, blockName1);
390 if (bb->iDom) {
391 oatGetBlockName(bb->iDom, blockName2);
392 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
393 blockName2, blockName1);
394 }
buzbee67bf8852011-08-17 17:51:35 -0700395 }
396 fprintf(file, "}\n");
397 fclose(file);
398}
399
400/* Verify if all the successor is connected with all the claimed predecessors */
buzbee31a4a6f2012-02-28 15:36:15 -0800401bool verifyPredInfo(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -0700402{
buzbee5abfa3e2012-01-31 17:01:43 -0800403 GrowableListIterator iter;
buzbee67bf8852011-08-17 17:51:35 -0700404
buzbee5abfa3e2012-01-31 17:01:43 -0800405 oatGrowableListIteratorInit(bb->predecessors, &iter);
buzbee67bf8852011-08-17 17:51:35 -0700406 while (true) {
buzbee5abfa3e2012-01-31 17:01:43 -0800407 BasicBlock *predBB = (BasicBlock*)oatGrowableListIteratorNext(&iter);
408 if (!predBB) break;
buzbee67bf8852011-08-17 17:51:35 -0700409 bool found = false;
410 if (predBB->taken == bb) {
411 found = true;
412 } else if (predBB->fallThrough == bb) {
413 found = true;
414 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
415 GrowableListIterator iterator;
416 oatGrowableListIteratorInit(&predBB->successorBlockList.blocks,
417 &iterator);
418 while (true) {
419 SuccessorBlockInfo *successorBlockInfo =
420 (SuccessorBlockInfo *)
421 oatGrowableListIteratorNext(&iterator);
422 if (successorBlockInfo == NULL) break;
423 BasicBlock *succBB = successorBlockInfo->block;
424 if (succBB == bb) {
425 found = true;
426 break;
427 }
428 }
429 }
430 if (found == false) {
431 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
432 oatGetBlockName(bb, blockName1);
433 oatGetBlockName(predBB, blockName2);
434 oatDumpCFG(cUnit, "/sdcard/cfg/");
435 LOG(FATAL) << "Successor " << blockName1 << "not found from "
436 << blockName2;
437 }
438 }
439 return true;
440}
441
442/* Identify code range in try blocks and set up the empty catch blocks */
buzbee31a4a6f2012-02-28 15:36:15 -0800443void processTryCatchBlocks(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700444{
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800445 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbeee9a72f62011-09-04 17:59:07 -0700446 int triesSize = code_item->tries_size_;
buzbee67bf8852011-08-17 17:51:35 -0700447 int offset;
448
449 if (triesSize == 0) {
450 return;
451 }
452
buzbee67bf8852011-08-17 17:51:35 -0700453 ArenaBitVector* tryBlockAddr = cUnit->tryBlockAddr;
454
buzbeee9a72f62011-09-04 17:59:07 -0700455 for (int i = 0; i < triesSize; i++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800456 const DexFile::TryItem* pTry =
457 DexFile::GetTryItems(*code_item, i);
buzbeee9a72f62011-09-04 17:59:07 -0700458 int startOffset = pTry->start_addr_;
459 int endOffset = startOffset + pTry->insn_count_;
buzbee67bf8852011-08-17 17:51:35 -0700460 for (offset = startOffset; offset < endOffset; offset++) {
buzbeeba938cb2012-02-03 14:47:55 -0800461 oatSetBit(cUnit, tryBlockAddr, offset);
buzbee67bf8852011-08-17 17:51:35 -0700462 }
463 }
464
buzbeee9a72f62011-09-04 17:59:07 -0700465 // Iterate over each of the handlers to enqueue the empty Catch blocks
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800466 const byte* handlers_ptr =
467 DexFile::GetCatchHandlerData(*code_item, 0);
468 uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
buzbeee9a72f62011-09-04 17:59:07 -0700469 for (uint32_t idx = 0; idx < handlers_size; idx++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800470 CatchHandlerIterator iterator(handlers_ptr);
Ian Rogers0571d352011-11-03 19:51:38 -0700471 for (; iterator.HasNext(); iterator.Next()) {
472 uint32_t address = iterator.GetHandlerAddress();
buzbee9ab05de2012-01-18 15:43:48 -0800473 findBlock(cUnit, address, false /* split */, true /*create*/,
474 /* immedPredBlockP */ NULL);
buzbee67bf8852011-08-17 17:51:35 -0700475 }
Ian Rogers0571d352011-11-03 19:51:38 -0700476 handlers_ptr = iterator.EndDataPointer();
buzbee67bf8852011-08-17 17:51:35 -0700477 }
478}
479
Elliott Hughesadb8c672012-03-06 16:49:32 -0800480/* Process instructions with the kBranch flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800481BasicBlock* processCanBranch(CompilationUnit* cUnit, BasicBlock* curBlock,
482 MIR* insn, int curOffset, int width, int flags,
483 const u2* codePtr, const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700484{
485 int target = curOffset;
486 switch (insn->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800487 case Instruction::GOTO:
488 case Instruction::GOTO_16:
489 case Instruction::GOTO_32:
buzbee67bf8852011-08-17 17:51:35 -0700490 target += (int) insn->dalvikInsn.vA;
491 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800492 case Instruction::IF_EQ:
493 case Instruction::IF_NE:
494 case Instruction::IF_LT:
495 case Instruction::IF_GE:
496 case Instruction::IF_GT:
497 case Instruction::IF_LE:
buzbee67bf8852011-08-17 17:51:35 -0700498 target += (int) insn->dalvikInsn.vC;
499 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800500 case Instruction::IF_EQZ:
501 case Instruction::IF_NEZ:
502 case Instruction::IF_LTZ:
503 case Instruction::IF_GEZ:
504 case Instruction::IF_GTZ:
505 case Instruction::IF_LEZ:
buzbee67bf8852011-08-17 17:51:35 -0700506 target += (int) insn->dalvikInsn.vB;
507 break;
508 default:
509 LOG(FATAL) << "Unexpected opcode(" << (int)insn->dalvikInsn.opcode
Elliott Hughesadb8c672012-03-06 16:49:32 -0800510 << ") with kBranch set";
buzbee67bf8852011-08-17 17:51:35 -0700511 }
512 BasicBlock *takenBlock = findBlock(cUnit, target,
513 /* split */
514 true,
515 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800516 true,
517 /* immedPredBlockP */
518 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700519 curBlock->taken = takenBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800520 oatInsertGrowableList(cUnit, takenBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700521
522 /* Always terminate the current block for conditional branches */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800523 if (flags & Instruction::kContinue) {
buzbee67bf8852011-08-17 17:51:35 -0700524 BasicBlock *fallthroughBlock = findBlock(cUnit,
525 curOffset + width,
526 /*
527 * If the method is processed
528 * in sequential order from the
529 * beginning, we don't need to
530 * specify split for continue
531 * blocks. However, this
532 * routine can be called by
533 * compileLoop, which starts
534 * parsing the method from an
535 * arbitrary address in the
536 * method body.
537 */
538 true,
539 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800540 true,
541 /* immedPredBlockP */
542 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700543 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800544 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800545 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700546 } else if (codePtr < codeEnd) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800547 /* Create a fallthrough block for real instructions (incl. NOP) */
buzbee67bf8852011-08-17 17:51:35 -0700548 if (contentIsInsn(codePtr)) {
549 findBlock(cUnit, curOffset + width,
550 /* split */
551 false,
552 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800553 true,
554 /* immedPredBlockP */
555 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700556 }
557 }
buzbeee941e2c2011-12-05 12:38:17 -0800558 return curBlock;
buzbee67bf8852011-08-17 17:51:35 -0700559}
560
Elliott Hughesadb8c672012-03-06 16:49:32 -0800561/* Process instructions with the kSwitch flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800562void processCanSwitch(CompilationUnit* cUnit, BasicBlock* curBlock,
563 MIR* insn, int curOffset, int width, int flags)
buzbee67bf8852011-08-17 17:51:35 -0700564{
565 u2* switchData= (u2 *) (cUnit->insns + curOffset +
566 insn->dalvikInsn.vB);
567 int size;
568 int* keyTable;
569 int* targetTable;
570 int i;
571 int firstKey;
572
573 /*
574 * Packed switch data format:
575 * ushort ident = 0x0100 magic value
576 * ushort size number of entries in the table
577 * int first_key first (and lowest) switch case value
578 * int targets[size] branch targets, relative to switch opcode
579 *
580 * Total size is (4+size*2) 16-bit code units.
581 */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800582 if (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) {
583 DCHECK_EQ(static_cast<int>(switchData[0]), static_cast<int>(Instruction::kPackedSwitchSignature));
buzbee67bf8852011-08-17 17:51:35 -0700584 size = switchData[1];
585 firstKey = switchData[2] | (switchData[3] << 16);
586 targetTable = (int *) &switchData[4];
587 keyTable = NULL; // Make the compiler happy
588 /*
589 * Sparse switch data format:
590 * ushort ident = 0x0200 magic value
591 * ushort size number of entries in the table; > 0
592 * int keys[size] keys, sorted low-to-high; 32-bit aligned
593 * int targets[size] branch targets, relative to switch opcode
594 *
595 * Total size is (2+size*4) 16-bit code units.
596 */
597 } else {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800598 DCHECK_EQ(static_cast<int>(switchData[0]), static_cast<int>(Instruction::kSparseSwitchSignature));
buzbee67bf8852011-08-17 17:51:35 -0700599 size = switchData[1];
600 keyTable = (int *) &switchData[2];
601 targetTable = (int *) &switchData[2 + size*2];
602 firstKey = 0; // To make the compiler happy
603 }
604
605 if (curBlock->successorBlockList.blockListType != kNotUsed) {
606 LOG(FATAL) << "Successor block list already in use: " <<
607 (int)curBlock->successorBlockList.blockListType;
608 }
609 curBlock->successorBlockList.blockListType =
Elliott Hughesadb8c672012-03-06 16:49:32 -0800610 (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) ?
buzbee67bf8852011-08-17 17:51:35 -0700611 kPackedSwitch : kSparseSwitch;
buzbeeba938cb2012-02-03 14:47:55 -0800612 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, size,
buzbee5abfa3e2012-01-31 17:01:43 -0800613 kListSuccessorBlocks);
buzbee67bf8852011-08-17 17:51:35 -0700614
615 for (i = 0; i < size; i++) {
616 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
617 /* split */
618 true,
619 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800620 true,
621 /* immedPredBlockP */
622 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700623 SuccessorBlockInfo *successorBlockInfo =
buzbeeba938cb2012-02-03 14:47:55 -0800624 (SuccessorBlockInfo *) oatNew(cUnit, sizeof(SuccessorBlockInfo),
625 false, kAllocSuccessor);
buzbee67bf8852011-08-17 17:51:35 -0700626 successorBlockInfo->block = caseBlock;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800627 successorBlockInfo->key = (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH)?
buzbee67bf8852011-08-17 17:51:35 -0700628 firstKey + i : keyTable[i];
buzbeeba938cb2012-02-03 14:47:55 -0800629 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
buzbee67bf8852011-08-17 17:51:35 -0700630 (intptr_t) successorBlockInfo);
buzbeeba938cb2012-02-03 14:47:55 -0800631 oatInsertGrowableList(cUnit, caseBlock->predecessors,
632 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700633 }
634
635 /* Fall-through case */
636 BasicBlock* fallthroughBlock = findBlock(cUnit,
637 curOffset + width,
638 /* split */
639 false,
640 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800641 true,
642 /* immedPredBlockP */
643 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700644 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800645 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
646 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700647}
648
Elliott Hughesadb8c672012-03-06 16:49:32 -0800649/* Process instructions with the kThrow flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800650void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock, MIR* insn,
651 int curOffset, int width, int flags,
652 ArenaBitVector* tryBlockAddr, const u2* codePtr,
653 const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700654{
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800655 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbee67bf8852011-08-17 17:51:35 -0700656
657 /* In try block */
658 if (oatIsBitSet(tryBlockAddr, curOffset)) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800659 CatchHandlerIterator iterator(*code_item, curOffset);
buzbee67bf8852011-08-17 17:51:35 -0700660
buzbee67bf8852011-08-17 17:51:35 -0700661 if (curBlock->successorBlockList.blockListType != kNotUsed) {
662 LOG(FATAL) << "Successor block list already in use: " <<
663 (int)curBlock->successorBlockList.blockListType;
664 }
buzbeee9a72f62011-09-04 17:59:07 -0700665
buzbee67bf8852011-08-17 17:51:35 -0700666 curBlock->successorBlockList.blockListType = kCatch;
buzbeeba938cb2012-02-03 14:47:55 -0800667 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, 2,
buzbee5abfa3e2012-01-31 17:01:43 -0800668 kListSuccessorBlocks);
buzbee67bf8852011-08-17 17:51:35 -0700669
Ian Rogers0571d352011-11-03 19:51:38 -0700670 for (;iterator.HasNext(); iterator.Next()) {
671 BasicBlock *catchBlock = findBlock(cUnit, iterator.GetHandlerAddress(),
buzbeee9a72f62011-09-04 17:59:07 -0700672 false /* split*/,
buzbee9ab05de2012-01-18 15:43:48 -0800673 false /* creat */,
674 NULL /* immedPredBlockP */);
buzbee43a36422011-09-14 14:00:13 -0700675 catchBlock->catchEntry = true;
buzbeeba938cb2012-02-03 14:47:55 -0800676 SuccessorBlockInfo *successorBlockInfo = (SuccessorBlockInfo *)
677 oatNew(cUnit, sizeof(SuccessorBlockInfo), false,
678 kAllocSuccessor);
buzbee67bf8852011-08-17 17:51:35 -0700679 successorBlockInfo->block = catchBlock;
Ian Rogers0571d352011-11-03 19:51:38 -0700680 successorBlockInfo->key = iterator.GetHandlerTypeIndex();
buzbeeba938cb2012-02-03 14:47:55 -0800681 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
buzbee67bf8852011-08-17 17:51:35 -0700682 (intptr_t) successorBlockInfo);
buzbeeba938cb2012-02-03 14:47:55 -0800683 oatInsertGrowableList(cUnit, catchBlock->predecessors,
684 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700685 }
686 } else {
buzbee5abfa3e2012-01-31 17:01:43 -0800687 BasicBlock *ehBlock = oatNewBB(cUnit, kExceptionHandling,
688 cUnit->numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700689 curBlock->taken = ehBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800690 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) ehBlock);
buzbee67bf8852011-08-17 17:51:35 -0700691 ehBlock->startOffset = curOffset;
buzbeeba938cb2012-02-03 14:47:55 -0800692 oatInsertGrowableList(cUnit, ehBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700693 }
694
695 /*
696 * Force the current block to terminate.
697 *
698 * Data may be present before codeEnd, so we need to parse it to know
699 * whether it is code or data.
700 */
701 if (codePtr < codeEnd) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800702 /* Create a fallthrough block for real instructions (incl. NOP) */
buzbee67bf8852011-08-17 17:51:35 -0700703 if (contentIsInsn(codePtr)) {
704 BasicBlock *fallthroughBlock = findBlock(cUnit,
705 curOffset + width,
706 /* split */
707 false,
708 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800709 true,
710 /* immedPredBlockP */
711 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700712 /*
Elliott Hughesadb8c672012-03-06 16:49:32 -0800713 * THROW is an unconditional branch. NOTE:
714 * THROW_VERIFICATION_ERROR is also an unconditional
buzbee510c6052011-10-27 10:47:20 -0700715 * branch, but we shouldn't treat it as such until we have
716 * a dead code elimination pass (which won't be important
717 * until inlining w/ constant propogation is implemented.
buzbee67bf8852011-08-17 17:51:35 -0700718 */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800719 if (insn->dalvikInsn.opcode != Instruction::THROW) {
buzbee67bf8852011-08-17 17:51:35 -0700720 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800721 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800722 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700723 }
724 }
725 }
726}
727
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800728void oatInit(CompilationUnit* cUnit, const Compiler& compiler) {
729 if (!oatArchInit()) {
730 LOG(FATAL) << "Failed to initialize oat";
731 }
732 if (!oatHeapInit(cUnit)) {
733 LOG(FATAL) << "Failed to initialize oat heap";
734 }
735}
736
Elliott Hughes3fa1b7e2012-03-13 17:06:22 -0700737CompiledMethod* oatCompileMethod(Compiler& compiler,
738 const DexFile::CodeItem* code_item,
739 uint32_t access_flags, uint32_t method_idx,
740 const ClassLoader* class_loader,
741 const DexFile& dex_file)
buzbee67bf8852011-08-17 17:51:35 -0700742{
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800743 VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
Brian Carlstrom94496d32011-08-22 09:22:47 -0700744
buzbeec143c552011-08-20 17:38:58 -0700745 const u2* codePtr = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700746 const u2* codeEnd = code_item->insns_ + code_item->insns_size_in_code_units_;
buzbee67bf8852011-08-17 17:51:35 -0700747 int numBlocks = 0;
748 unsigned int curOffset = 0;
749
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800750 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700751 UniquePtr<CompilationUnit> cUnit(new CompilationUnit);
752 memset(cUnit.get(), 0, sizeof(*cUnit));
buzbeeba938cb2012-02-03 14:47:55 -0800753
754 oatInit(cUnit.get(), compiler);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800755
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700756 cUnit->compiler = &compiler;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800757 cUnit->class_linker = class_linker;
758 cUnit->dex_file = &dex_file;
759 cUnit->dex_cache = class_linker->FindDexCache(dex_file);
760 cUnit->method_idx = method_idx;
761 cUnit->code_item = code_item;
762 cUnit->access_flags = access_flags;
763 cUnit->shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800764 cUnit->instructionSet = compiler.GetInstructionSet();
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700765 cUnit->insns = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700766 cUnit->insnsSize = code_item->insns_size_in_code_units_;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800767 cUnit->numIns = code_item->ins_size_;
768 cUnit->numRegs = code_item->registers_size_ - cUnit->numIns;
769 cUnit->numOuts = code_item->outs_size_;
770 /* Adjust this value accordingly once inlining is performed */
771 cUnit->numDalvikRegisters = code_item->registers_size_;
buzbee5b537102012-01-17 17:33:47 -0800772 cUnit->blockMap = std::map<unsigned int, BasicBlock*>();
773 cUnit->blockMap.clear();
buzbee85d8c1e2012-01-27 15:52:35 -0800774 cUnit->boundaryMap = std::map<unsigned int, LIR*>();
775 cUnit->boundaryMap.clear();
buzbeeba938cb2012-02-03 14:47:55 -0800776 // TODO: set these from command line
777 cUnit->compilerMethodMatch = new std::string("");
778 cUnit->compilerFlipMatch = false;
779 bool useMatch = cUnit->compilerMethodMatch->length() != 0;
780 bool match = useMatch && (cUnit->compilerFlipMatch ^
781 (PrettyMethod(method_idx, dex_file).find(*cUnit->compilerMethodMatch)
782 != std::string::npos));
buzbeece302932011-10-04 14:32:18 -0700783 if (!useMatch || match) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700784 cUnit->disableOpt = compilerOptimizerDisableFlags;
785 cUnit->enableDebug = compilerDebugFlags;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800786 cUnit->printMe = VLOG_IS_ON(compiler) || (cUnit->enableDebug & (1 << kDebugVerbose));
buzbeece302932011-10-04 14:32:18 -0700787 }
buzbee44b412b2012-02-04 08:50:53 -0800788 /* Are we generating code for the debugger? */
Elliott Hughesde6e4cf2012-02-27 14:46:06 -0800789 if (compiler.IsDebuggingSupported()) {
buzbee44b412b2012-02-04 08:50:53 -0800790 cUnit->genDebugger = true;
791 // Yes, disable most optimizations
792 cUnit->disableOpt |= (
793 (1 << kLoadStoreElimination) |
794 (1 << kLoadHoisting) |
795 (1 << kSuppressLoads) |
796 (1 << kPromoteRegs) |
797 (1 << kTrackLiveTemps));
798 }
799
buzbeecefd1872011-09-09 09:59:52 -0700800 /* Assume non-throwing leaf */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700801 cUnit->attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
buzbeecefd1872011-09-09 09:59:52 -0700802
buzbee5abfa3e2012-01-31 17:01:43 -0800803 /* Initialize the block list, estimate size based on insnsSize */
buzbeeba938cb2012-02-03 14:47:55 -0800804 oatInitGrowableList(cUnit.get(), &cUnit->blockList, cUnit->insnsSize,
805 kListBlockList);
buzbee67bf8852011-08-17 17:51:35 -0700806
807 /* Initialize the switchTables list */
buzbeeba938cb2012-02-03 14:47:55 -0800808 oatInitGrowableList(cUnit.get(), &cUnit->switchTables, 4,
809 kListSwitchTables);
buzbee67bf8852011-08-17 17:51:35 -0700810
811 /* Intialize the fillArrayData list */
buzbeeba938cb2012-02-03 14:47:55 -0800812 oatInitGrowableList(cUnit.get(), &cUnit->fillArrayData, 4,
813 kListFillArrayData);
buzbee67bf8852011-08-17 17:51:35 -0700814
buzbee5abfa3e2012-01-31 17:01:43 -0800815 /* Intialize the throwLaunchpads list, estimate size based on insnsSize */
buzbeeba938cb2012-02-03 14:47:55 -0800816 oatInitGrowableList(cUnit.get(), &cUnit->throwLaunchpads, cUnit->insnsSize,
buzbee5abfa3e2012-01-31 17:01:43 -0800817 kListThrowLaunchPads);
buzbee5ade1d22011-09-09 14:44:52 -0700818
buzbeec1f45042011-09-21 16:03:19 -0700819 /* Intialize the suspendLaunchpads list */
buzbeeba938cb2012-02-03 14:47:55 -0800820 oatInitGrowableList(cUnit.get(), &cUnit->suspendLaunchpads, 2048,
buzbee5abfa3e2012-01-31 17:01:43 -0800821 kListSuspendLaunchPads);
buzbeec1f45042011-09-21 16:03:19 -0700822
buzbee67bf8852011-08-17 17:51:35 -0700823 /* Allocate the bit-vector to track the beginning of basic blocks */
buzbeeba938cb2012-02-03 14:47:55 -0800824 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit.get(),
825 cUnit->insnsSize,
buzbee67bf8852011-08-17 17:51:35 -0700826 true /* expandable */);
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700827 cUnit->tryBlockAddr = tryBlockAddr;
buzbee67bf8852011-08-17 17:51:35 -0700828
829 /* Create the default entry and exit blocks and enter them to the list */
buzbee5abfa3e2012-01-31 17:01:43 -0800830 BasicBlock *entryBlock = oatNewBB(cUnit.get(), kEntryBlock, numBlocks++);
831 BasicBlock *exitBlock = oatNewBB(cUnit.get(), kExitBlock, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700832
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700833 cUnit->entryBlock = entryBlock;
834 cUnit->exitBlock = exitBlock;
buzbee67bf8852011-08-17 17:51:35 -0700835
buzbeeba938cb2012-02-03 14:47:55 -0800836 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) entryBlock);
837 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) exitBlock);
buzbee67bf8852011-08-17 17:51:35 -0700838
839 /* Current block to record parsed instructions */
buzbee5abfa3e2012-01-31 17:01:43 -0800840 BasicBlock *curBlock = oatNewBB(cUnit.get(), kDalvikByteCode, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700841 curBlock->startOffset = 0;
buzbeeba938cb2012-02-03 14:47:55 -0800842 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) curBlock);
buzbee5b537102012-01-17 17:33:47 -0800843 /* Add first block to the fast lookup cache */
844 cUnit->blockMap.insert(std::make_pair(curBlock->startOffset, curBlock));
buzbee67bf8852011-08-17 17:51:35 -0700845 entryBlock->fallThrough = curBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800846 oatInsertGrowableList(cUnit.get(), curBlock->predecessors,
847 (intptr_t)entryBlock);
buzbee67bf8852011-08-17 17:51:35 -0700848
849 /*
850 * Store back the number of blocks since new blocks may be created of
851 * accessing cUnit.
852 */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700853 cUnit->numBlocks = numBlocks;
buzbee67bf8852011-08-17 17:51:35 -0700854
855 /* Identify code range in try blocks and set up the empty catch blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700856 processTryCatchBlocks(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700857
858 /* Parse all instructions and put them into containing basic blocks */
859 while (codePtr < codeEnd) {
buzbeeba938cb2012-02-03 14:47:55 -0800860 MIR *insn = (MIR *) oatNew(cUnit.get(), sizeof(MIR), true, kAllocMIR);
buzbee67bf8852011-08-17 17:51:35 -0700861 insn->offset = curOffset;
buzbeeba938cb2012-02-03 14:47:55 -0800862 int width = parseInsn(cUnit.get(), codePtr, &insn->dalvikInsn, false);
buzbee67bf8852011-08-17 17:51:35 -0700863 insn->width = width;
864
865 /* Terminate when the data section is seen */
866 if (width == 0)
867 break;
868
869 oatAppendMIR(curBlock, insn);
870
871 codePtr += width;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800872 int flags = Instruction::Flags(insn->dalvikInsn.opcode);
buzbee67bf8852011-08-17 17:51:35 -0700873
buzbee5abfa3e2012-01-31 17:01:43 -0800874 int dfFlags = oatDataFlowAttributes[insn->dalvikInsn.opcode];
875
876 if (dfFlags & DF_HAS_DEFS) {
877 cUnit->defCount += (dfFlags & DF_DA_WIDE) ? 2 : 1;
878 }
buzbee99ba9642012-01-25 14:23:14 -0800879
Elliott Hughesadb8c672012-03-06 16:49:32 -0800880 if (flags & Instruction::kBranch) {
buzbeee941e2c2011-12-05 12:38:17 -0800881 curBlock = processCanBranch(cUnit.get(), curBlock, insn, curOffset,
882 width, flags, codePtr, codeEnd);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800883 } else if (flags & Instruction::kReturn) {
buzbee67bf8852011-08-17 17:51:35 -0700884 curBlock->fallThrough = exitBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800885 oatInsertGrowableList(cUnit.get(), exitBlock->predecessors,
886 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700887 /*
888 * Terminate the current block if there are instructions
889 * afterwards.
890 */
891 if (codePtr < codeEnd) {
892 /*
893 * Create a fallthrough block for real instructions
Elliott Hughesadb8c672012-03-06 16:49:32 -0800894 * (incl. NOP).
buzbee67bf8852011-08-17 17:51:35 -0700895 */
896 if (contentIsInsn(codePtr)) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700897 findBlock(cUnit.get(), curOffset + width,
buzbee67bf8852011-08-17 17:51:35 -0700898 /* split */
899 false,
900 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800901 true,
902 /* immedPredBlockP */
903 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700904 }
905 }
Elliott Hughesadb8c672012-03-06 16:49:32 -0800906 } else if (flags & Instruction::kThrow) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700907 processCanThrow(cUnit.get(), curBlock, insn, curOffset, width, flags,
buzbee67bf8852011-08-17 17:51:35 -0700908 tryBlockAddr, codePtr, codeEnd);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800909 } else if (flags & Instruction::kSwitch) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700910 processCanSwitch(cUnit.get(), curBlock, insn, curOffset, width, flags);
buzbee67bf8852011-08-17 17:51:35 -0700911 }
912 curOffset += width;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700913 BasicBlock *nextBlock = findBlock(cUnit.get(), curOffset,
buzbee67bf8852011-08-17 17:51:35 -0700914 /* split */
915 false,
916 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800917 false,
918 /* immedPredBlockP */
919 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700920 if (nextBlock) {
921 /*
922 * The next instruction could be the target of a previously parsed
923 * forward branch so a block is already created. If the current
924 * instruction is not an unconditional branch, connect them through
925 * the fall-through link.
926 */
buzbeeed3e9302011-09-23 17:34:19 -0700927 DCHECK(curBlock->fallThrough == NULL ||
buzbee67bf8852011-08-17 17:51:35 -0700928 curBlock->fallThrough == nextBlock ||
929 curBlock->fallThrough == exitBlock);
930
Elliott Hughesadb8c672012-03-06 16:49:32 -0800931 if ((curBlock->fallThrough == NULL) && (flags & Instruction::kContinue)) {
buzbee67bf8852011-08-17 17:51:35 -0700932 curBlock->fallThrough = nextBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800933 oatInsertGrowableList(cUnit.get(), nextBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800934 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700935 }
936 curBlock = nextBlock;
937 }
938 }
939
buzbee5abfa3e2012-01-31 17:01:43 -0800940 if (!(cUnit->disableOpt & (1 << kSkipLargeMethodOptimization))) {
buzbee99ba9642012-01-25 14:23:14 -0800941 if ((cUnit->numBlocks > MANY_BLOCKS) ||
942 ((cUnit->numBlocks > MANY_BLOCKS_INITIALIZER) &&
943 PrettyMethod(method_idx, dex_file).find("init>") !=
944 std::string::npos)) {
945 cUnit->disableDataflow = true;
946 // Disable optimization which require dataflow/ssa
947 cUnit->disableOpt |=
948 (1 << kNullCheckElimination) |
949 (1 << kPromoteRegs);
950 if (cUnit->printMe) {
951 LOG(INFO) << "Compiler: " << PrettyMethod(method_idx, dex_file)
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800952 << " too big: " << cUnit->numBlocks;
buzbee99ba9642012-01-25 14:23:14 -0800953 }
954 }
955 }
956
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700957 if (cUnit->printMe) {
958 oatDumpCompilationUnit(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700959 }
960
buzbee5b537102012-01-17 17:33:47 -0800961 if (cUnit->enableDebug & (1 << kDebugVerifyDataflow)) {
962 /* Verify if all blocks are connected as claimed */
buzbee5abfa3e2012-01-31 17:01:43 -0800963 oatDataFlowAnalysisDispatcher(cUnit.get(), verifyPredInfo, kAllNodes,
964 false /* isIterative */);
buzbee5b537102012-01-17 17:33:47 -0800965 }
buzbee67bf8852011-08-17 17:51:35 -0700966
967 /* Perform SSA transformation for the whole method */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700968 oatMethodSSATransformation(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700969
buzbee239c4e72012-03-16 08:42:29 -0700970 /* Detect loops */
971 oatMethodLoopDetection(cUnit.get());
972
973 /* Count uses */
974 oatMethodUseCount(cUnit.get());
975
buzbee43a36422011-09-14 14:00:13 -0700976 /* Perform null check elimination */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700977 oatMethodNullCheckElimination(cUnit.get());
buzbee43a36422011-09-14 14:00:13 -0700978
buzbeee1965672012-03-11 18:39:19 -0700979 /* Do some basic block optimizations */
980 oatMethodBasicBlockOptimization(cUnit.get());
buzbeee1965672012-03-11 18:39:19 -0700981
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700982 oatInitializeRegAlloc(cUnit.get()); // Needs to happen after SSA naming
buzbee67bf8852011-08-17 17:51:35 -0700983
984 /* Allocate Registers using simple local allocation scheme */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700985 oatSimpleRegAlloc(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700986
987 /* Convert MIR to LIR, etc. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700988 oatMethodMIR2LIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700989
990 // Debugging only
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700991 if (cUnit->enableDebug & (1 << kDebugDumpCFG)) {
992 oatDumpCFG(cUnit.get(), "/sdcard/cfg/");
buzbeeec5adf32011-09-11 15:25:43 -0700993 }
buzbee67bf8852011-08-17 17:51:35 -0700994
995 /* Method is not empty */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700996 if (cUnit->firstLIRInsn) {
buzbee67bf8852011-08-17 17:51:35 -0700997
998 // mark the targets of switch statement case labels
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700999 oatProcessSwitchTables(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001000
1001 /* Convert LIR into machine code. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001002 oatAssembleLIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001003
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001004 if (cUnit->printMe) {
1005 oatCodegenDump(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001006 }
1007 }
1008
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001009 // Combine vmap tables - core regs, then fp regs - into vmapTable
1010 std::vector<uint16_t> vmapTable;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001011 for (size_t i = 0 ; i < cUnit->coreVmapTable.size(); i++) {
1012 vmapTable.push_back(cUnit->coreVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001013 }
Ian Rogersf7d9ad32012-03-13 18:45:39 -07001014 // Add a marker to take place of lr
1015 vmapTable.push_back(INVALID_VREG);
buzbeec41e5b52011-09-23 12:46:19 -07001016 // Combine vmap tables - core regs, then fp regs
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001017 for (uint32_t i = 0; i < cUnit->fpVmapTable.size(); i++) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001018 vmapTable.push_back(cUnit->fpVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001019 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001020 CompiledMethod* result = new CompiledMethod(cUnit->instructionSet, cUnit->codeBuffer,
Ian Rogers0571d352011-11-03 19:51:38 -07001021 cUnit->frameSize, cUnit->coreSpillMask,
1022 cUnit->fpSpillMask, cUnit->mappingTable,
1023 vmapTable);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001024
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -08001025 VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file)
buzbee5abfa3e2012-01-31 17:01:43 -08001026 << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0]))
1027 << " bytes)";
1028
1029#ifdef WITH_MEMSTATS
1030 if (cUnit->enableDebug & (1 << kDebugShowMemoryUsage)) {
1031 oatDumpMemStats(cUnit.get());
1032 }
1033#endif
buzbee67bf8852011-08-17 17:51:35 -07001034
buzbeeba938cb2012-02-03 14:47:55 -08001035 oatArenaReset(cUnit.get());
1036
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001037 return result;
buzbee67bf8852011-08-17 17:51:35 -07001038}
1039
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001040} // namespace art
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001041
Elliott Hughes3fa1b7e2012-03-13 17:06:22 -07001042extern "C" art::CompiledMethod* ArtCompileMethod(art::Compiler& compiler,
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001043 const art::DexFile::CodeItem* code_item,
1044 uint32_t access_flags, uint32_t method_idx,
1045 const art::ClassLoader* class_loader,
1046 const art::DexFile& dex_file)
1047{
1048 CHECK_EQ(compiler.GetInstructionSet(), art::oatInstructionSet());
Elliott Hughes3fa1b7e2012-03-13 17:06:22 -07001049 return art::oatCompileMethod(compiler, code_item, access_flags, method_idx, class_loader, dex_file);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001050}