blob: 8ffcc72590c9e32725abf2d162005bbbf53f8281 [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) |
buzbeee1965672012-03-11 18:39:19 -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 }
buzbee67bf8852011-08-17 17:51:35 -0700788
buzbee44b412b2012-02-04 08:50:53 -0800789 /* Are we generating code for the debugger? */
Elliott Hughesde6e4cf2012-02-27 14:46:06 -0800790 if (compiler.IsDebuggingSupported()) {
buzbee44b412b2012-02-04 08:50:53 -0800791 cUnit->genDebugger = true;
792 // Yes, disable most optimizations
793 cUnit->disableOpt |= (
794 (1 << kLoadStoreElimination) |
795 (1 << kLoadHoisting) |
796 (1 << kSuppressLoads) |
797 (1 << kPromoteRegs) |
798 (1 << kTrackLiveTemps));
799 }
800
buzbeecefd1872011-09-09 09:59:52 -0700801 /* Assume non-throwing leaf */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700802 cUnit->attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
buzbeecefd1872011-09-09 09:59:52 -0700803
buzbee5abfa3e2012-01-31 17:01:43 -0800804 /* Initialize the block list, estimate size based on insnsSize */
buzbeeba938cb2012-02-03 14:47:55 -0800805 oatInitGrowableList(cUnit.get(), &cUnit->blockList, cUnit->insnsSize,
806 kListBlockList);
buzbee67bf8852011-08-17 17:51:35 -0700807
808 /* Initialize the switchTables list */
buzbeeba938cb2012-02-03 14:47:55 -0800809 oatInitGrowableList(cUnit.get(), &cUnit->switchTables, 4,
810 kListSwitchTables);
buzbee67bf8852011-08-17 17:51:35 -0700811
812 /* Intialize the fillArrayData list */
buzbeeba938cb2012-02-03 14:47:55 -0800813 oatInitGrowableList(cUnit.get(), &cUnit->fillArrayData, 4,
814 kListFillArrayData);
buzbee67bf8852011-08-17 17:51:35 -0700815
buzbee5abfa3e2012-01-31 17:01:43 -0800816 /* Intialize the throwLaunchpads list, estimate size based on insnsSize */
buzbeeba938cb2012-02-03 14:47:55 -0800817 oatInitGrowableList(cUnit.get(), &cUnit->throwLaunchpads, cUnit->insnsSize,
buzbee5abfa3e2012-01-31 17:01:43 -0800818 kListThrowLaunchPads);
buzbee5ade1d22011-09-09 14:44:52 -0700819
buzbeec1f45042011-09-21 16:03:19 -0700820 /* Intialize the suspendLaunchpads list */
buzbeeba938cb2012-02-03 14:47:55 -0800821 oatInitGrowableList(cUnit.get(), &cUnit->suspendLaunchpads, 2048,
buzbee5abfa3e2012-01-31 17:01:43 -0800822 kListSuspendLaunchPads);
buzbeec1f45042011-09-21 16:03:19 -0700823
buzbee67bf8852011-08-17 17:51:35 -0700824 /* Allocate the bit-vector to track the beginning of basic blocks */
buzbeeba938cb2012-02-03 14:47:55 -0800825 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit.get(),
826 cUnit->insnsSize,
buzbee67bf8852011-08-17 17:51:35 -0700827 true /* expandable */);
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700828 cUnit->tryBlockAddr = tryBlockAddr;
buzbee67bf8852011-08-17 17:51:35 -0700829
830 /* Create the default entry and exit blocks and enter them to the list */
buzbee5abfa3e2012-01-31 17:01:43 -0800831 BasicBlock *entryBlock = oatNewBB(cUnit.get(), kEntryBlock, numBlocks++);
832 BasicBlock *exitBlock = oatNewBB(cUnit.get(), kExitBlock, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700833
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700834 cUnit->entryBlock = entryBlock;
835 cUnit->exitBlock = exitBlock;
buzbee67bf8852011-08-17 17:51:35 -0700836
buzbeeba938cb2012-02-03 14:47:55 -0800837 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) entryBlock);
838 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) exitBlock);
buzbee67bf8852011-08-17 17:51:35 -0700839
840 /* Current block to record parsed instructions */
buzbee5abfa3e2012-01-31 17:01:43 -0800841 BasicBlock *curBlock = oatNewBB(cUnit.get(), kDalvikByteCode, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700842 curBlock->startOffset = 0;
buzbeeba938cb2012-02-03 14:47:55 -0800843 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) curBlock);
buzbee5b537102012-01-17 17:33:47 -0800844 /* Add first block to the fast lookup cache */
845 cUnit->blockMap.insert(std::make_pair(curBlock->startOffset, curBlock));
buzbee67bf8852011-08-17 17:51:35 -0700846 entryBlock->fallThrough = curBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800847 oatInsertGrowableList(cUnit.get(), curBlock->predecessors,
848 (intptr_t)entryBlock);
buzbee67bf8852011-08-17 17:51:35 -0700849
850 /*
851 * Store back the number of blocks since new blocks may be created of
852 * accessing cUnit.
853 */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700854 cUnit->numBlocks = numBlocks;
buzbee67bf8852011-08-17 17:51:35 -0700855
856 /* Identify code range in try blocks and set up the empty catch blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700857 processTryCatchBlocks(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700858
859 /* Parse all instructions and put them into containing basic blocks */
860 while (codePtr < codeEnd) {
buzbeeba938cb2012-02-03 14:47:55 -0800861 MIR *insn = (MIR *) oatNew(cUnit.get(), sizeof(MIR), true, kAllocMIR);
buzbee67bf8852011-08-17 17:51:35 -0700862 insn->offset = curOffset;
buzbeeba938cb2012-02-03 14:47:55 -0800863 int width = parseInsn(cUnit.get(), codePtr, &insn->dalvikInsn, false);
buzbee67bf8852011-08-17 17:51:35 -0700864 insn->width = width;
865
866 /* Terminate when the data section is seen */
867 if (width == 0)
868 break;
869
870 oatAppendMIR(curBlock, insn);
871
872 codePtr += width;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800873 int flags = Instruction::Flags(insn->dalvikInsn.opcode);
buzbee67bf8852011-08-17 17:51:35 -0700874
buzbee5abfa3e2012-01-31 17:01:43 -0800875 int dfFlags = oatDataFlowAttributes[insn->dalvikInsn.opcode];
876
877 if (dfFlags & DF_HAS_DEFS) {
878 cUnit->defCount += (dfFlags & DF_DA_WIDE) ? 2 : 1;
879 }
buzbee99ba9642012-01-25 14:23:14 -0800880
Elliott Hughesadb8c672012-03-06 16:49:32 -0800881 if (flags & Instruction::kBranch) {
buzbeee941e2c2011-12-05 12:38:17 -0800882 curBlock = processCanBranch(cUnit.get(), curBlock, insn, curOffset,
883 width, flags, codePtr, codeEnd);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800884 } else if (flags & Instruction::kReturn) {
buzbee67bf8852011-08-17 17:51:35 -0700885 curBlock->fallThrough = exitBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800886 oatInsertGrowableList(cUnit.get(), exitBlock->predecessors,
887 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700888 /*
889 * Terminate the current block if there are instructions
890 * afterwards.
891 */
892 if (codePtr < codeEnd) {
893 /*
894 * Create a fallthrough block for real instructions
Elliott Hughesadb8c672012-03-06 16:49:32 -0800895 * (incl. NOP).
buzbee67bf8852011-08-17 17:51:35 -0700896 */
897 if (contentIsInsn(codePtr)) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700898 findBlock(cUnit.get(), curOffset + width,
buzbee67bf8852011-08-17 17:51:35 -0700899 /* split */
900 false,
901 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800902 true,
903 /* immedPredBlockP */
904 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700905 }
906 }
Elliott Hughesadb8c672012-03-06 16:49:32 -0800907 } else if (flags & Instruction::kThrow) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700908 processCanThrow(cUnit.get(), curBlock, insn, curOffset, width, flags,
buzbee67bf8852011-08-17 17:51:35 -0700909 tryBlockAddr, codePtr, codeEnd);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800910 } else if (flags & Instruction::kSwitch) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700911 processCanSwitch(cUnit.get(), curBlock, insn, curOffset, width, flags);
buzbee67bf8852011-08-17 17:51:35 -0700912 }
913 curOffset += width;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700914 BasicBlock *nextBlock = findBlock(cUnit.get(), curOffset,
buzbee67bf8852011-08-17 17:51:35 -0700915 /* split */
916 false,
917 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800918 false,
919 /* immedPredBlockP */
920 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700921 if (nextBlock) {
922 /*
923 * The next instruction could be the target of a previously parsed
924 * forward branch so a block is already created. If the current
925 * instruction is not an unconditional branch, connect them through
926 * the fall-through link.
927 */
buzbeeed3e9302011-09-23 17:34:19 -0700928 DCHECK(curBlock->fallThrough == NULL ||
buzbee67bf8852011-08-17 17:51:35 -0700929 curBlock->fallThrough == nextBlock ||
930 curBlock->fallThrough == exitBlock);
931
Elliott Hughesadb8c672012-03-06 16:49:32 -0800932 if ((curBlock->fallThrough == NULL) && (flags & Instruction::kContinue)) {
buzbee67bf8852011-08-17 17:51:35 -0700933 curBlock->fallThrough = nextBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800934 oatInsertGrowableList(cUnit.get(), nextBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800935 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700936 }
937 curBlock = nextBlock;
938 }
939 }
940
buzbee5abfa3e2012-01-31 17:01:43 -0800941 if (!(cUnit->disableOpt & (1 << kSkipLargeMethodOptimization))) {
buzbee99ba9642012-01-25 14:23:14 -0800942 if ((cUnit->numBlocks > MANY_BLOCKS) ||
943 ((cUnit->numBlocks > MANY_BLOCKS_INITIALIZER) &&
944 PrettyMethod(method_idx, dex_file).find("init>") !=
945 std::string::npos)) {
946 cUnit->disableDataflow = true;
947 // Disable optimization which require dataflow/ssa
948 cUnit->disableOpt |=
949 (1 << kNullCheckElimination) |
950 (1 << kPromoteRegs);
951 if (cUnit->printMe) {
952 LOG(INFO) << "Compiler: " << PrettyMethod(method_idx, dex_file)
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800953 << " too big: " << cUnit->numBlocks;
buzbee99ba9642012-01-25 14:23:14 -0800954 }
955 }
956 }
957
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700958 if (cUnit->printMe) {
959 oatDumpCompilationUnit(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700960 }
961
buzbee5b537102012-01-17 17:33:47 -0800962 if (cUnit->enableDebug & (1 << kDebugVerifyDataflow)) {
963 /* Verify if all blocks are connected as claimed */
buzbee5abfa3e2012-01-31 17:01:43 -0800964 oatDataFlowAnalysisDispatcher(cUnit.get(), verifyPredInfo, kAllNodes,
965 false /* isIterative */);
buzbee5b537102012-01-17 17:33:47 -0800966 }
buzbee67bf8852011-08-17 17:51:35 -0700967
968 /* Perform SSA transformation for the whole method */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700969 oatMethodSSATransformation(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700970
buzbee43a36422011-09-14 14:00:13 -0700971 /* Perform null check elimination */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700972 oatMethodNullCheckElimination(cUnit.get());
buzbee43a36422011-09-14 14:00:13 -0700973
buzbeee1965672012-03-11 18:39:19 -0700974#if 0
975 /* Do some basic block optimizations */
976 oatMethodBasicBlockOptimization(cUnit.get());
977#endif
978
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700979 oatInitializeRegAlloc(cUnit.get()); // Needs to happen after SSA naming
buzbee67bf8852011-08-17 17:51:35 -0700980
981 /* Allocate Registers using simple local allocation scheme */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700982 oatSimpleRegAlloc(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700983
984 /* Convert MIR to LIR, etc. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700985 oatMethodMIR2LIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700986
987 // Debugging only
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700988 if (cUnit->enableDebug & (1 << kDebugDumpCFG)) {
989 oatDumpCFG(cUnit.get(), "/sdcard/cfg/");
buzbeeec5adf32011-09-11 15:25:43 -0700990 }
buzbee67bf8852011-08-17 17:51:35 -0700991
992 /* Method is not empty */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700993 if (cUnit->firstLIRInsn) {
buzbee67bf8852011-08-17 17:51:35 -0700994
995 // mark the targets of switch statement case labels
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700996 oatProcessSwitchTables(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700997
998 /* Convert LIR into machine code. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700999 oatAssembleLIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001000
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001001 if (cUnit->printMe) {
1002 oatCodegenDump(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001003 }
1004 }
1005
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001006 // Combine vmap tables - core regs, then fp regs - into vmapTable
1007 std::vector<uint16_t> vmapTable;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001008 for (size_t i = 0 ; i < cUnit->coreVmapTable.size(); i++) {
1009 vmapTable.push_back(cUnit->coreVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001010 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001011 if (cUnit->instructionSet != kX86) {
1012 // Add a marker to take place of lr
1013 vmapTable.push_back(INVALID_VREG);
1014 }
buzbeec41e5b52011-09-23 12:46:19 -07001015 // Combine vmap tables - core regs, then fp regs
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001016 for (uint32_t i = 0; i < cUnit->fpVmapTable.size(); i++) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001017 vmapTable.push_back(cUnit->fpVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001018 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001019 CompiledMethod* result = new CompiledMethod(cUnit->instructionSet, cUnit->codeBuffer,
Ian Rogers0571d352011-11-03 19:51:38 -07001020 cUnit->frameSize, cUnit->coreSpillMask,
1021 cUnit->fpSpillMask, cUnit->mappingTable,
1022 vmapTable);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001023
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -08001024 VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file)
buzbee5abfa3e2012-01-31 17:01:43 -08001025 << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0]))
1026 << " bytes)";
1027
1028#ifdef WITH_MEMSTATS
1029 if (cUnit->enableDebug & (1 << kDebugShowMemoryUsage)) {
1030 oatDumpMemStats(cUnit.get());
1031 }
1032#endif
buzbee67bf8852011-08-17 17:51:35 -07001033
buzbeeba938cb2012-02-03 14:47:55 -08001034 oatArenaReset(cUnit.get());
1035
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001036 return result;
buzbee67bf8852011-08-17 17:51:35 -07001037}
1038
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001039} // namespace art
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001040
Elliott Hughes3fa1b7e2012-03-13 17:06:22 -07001041extern "C" art::CompiledMethod* ArtCompileMethod(art::Compiler& compiler,
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001042 const art::DexFile::CodeItem* code_item,
1043 uint32_t access_flags, uint32_t method_idx,
1044 const art::ClassLoader* class_loader,
1045 const art::DexFile& dex_file)
1046{
1047 CHECK_EQ(compiler.GetInstructionSet(), art::oatInstructionSet());
Elliott Hughes3fa1b7e2012-03-13 17:06:22 -07001048 return art::oatCompileMethod(compiler, code_item, access_flags, method_idx, class_loader, dex_file);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001049}