blob: 309bcf82d88e375244fe88e4ed243dae9bee0043 [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"
Ian Rogers0571d352011-11-03 19:51:38 -070020#include "leb128.h"
Brian Carlstrom9baa4ae2011-09-01 21:14:14 -070021#include "object.h"
Brian Carlstrom1f870082011-08-23 16:02:11 -070022#include "runtime.h"
buzbee67bf8852011-08-17 17:51:35 -070023
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080024namespace art {
25
buzbeece302932011-10-04 14:32:18 -070026/* Default optimizer/debug setting for the compiler. */
Elliott Hughese52e49b2012-04-02 16:05:44 -070027static uint32_t kCompilerOptimizerDisableFlags = 0 | // Disable specific optimizations
buzbee67bc2362011-10-11 18:08:40 -070028 //(1 << kLoadStoreElimination) |
29 //(1 << kLoadHoisting) |
30 //(1 << kSuppressLoads) |
31 //(1 << kNullCheckElimination) |
buzbee769fde12012-01-05 17:35:23 -080032 //(1 << kPromoteRegs) |
33 //(1 << kTrackLiveTemps) |
buzbee99ba9642012-01-25 14:23:14 -080034 //(1 << kSkipLargeMethodOptimization) |
buzbee86a4bce2012-03-06 18:15:00 -080035 //(1 << kSafeOptimizations) |
buzbee239c4e72012-03-16 08:42:29 -070036 //(1 << kBBOpt) |
buzbee16da88c2012-03-20 10:38:17 -070037 //(1 << kMatch) |
buzbee9c044ce2012-03-18 13:24:07 -070038 //(1 << kPromoteCompilerTemps) |
buzbeece302932011-10-04 14:32:18 -070039 0;
40
Elliott Hughese52e49b2012-04-02 16:05:44 -070041static uint32_t kCompilerDebugFlags = 0 | // Enable debug/testing modes
buzbeee3de7492011-10-05 13:37:17 -070042 //(1 << kDebugDisplayMissingTargets) |
buzbeece302932011-10-04 14:32:18 -070043 //(1 << kDebugVerbose) |
44 //(1 << kDebugDumpCFG) |
45 //(1 << kDebugSlowFieldPath) |
46 //(1 << kDebugSlowInvokePath) |
47 //(1 << kDebugSlowStringPath) |
48 //(1 << kDebugSlowestFieldPath) |
49 //(1 << kDebugSlowestStringPath) |
buzbee34c77ad2012-01-11 13:01:32 -080050 //(1 << kDebugExerciseResolveMethod) |
buzbee5b537102012-01-17 17:33:47 -080051 //(1 << kDebugVerifyDataflow) |
buzbee5abfa3e2012-01-31 17:01:43 -080052 //(1 << kDebugShowMemoryUsage) |
buzbee86a4bce2012-03-06 18:15:00 -080053 //(1 << kDebugShowNops) |
buzbeea7c12682012-03-19 13:13:53 -070054 //(1 << kDebugCountOpcodes) |
buzbeece302932011-10-04 14:32:18 -070055 0;
56
buzbee31a4a6f2012-02-28 15:36:15 -080057inline bool contentIsInsn(const u2* codePtr) {
buzbee67bf8852011-08-17 17:51:35 -070058 u2 instr = *codePtr;
Elliott Hughesadb8c672012-03-06 16:49:32 -080059 Instruction::Code opcode = (Instruction::Code)(instr & 0xff);
buzbee67bf8852011-08-17 17:51:35 -070060
61 /*
Elliott Hughesadb8c672012-03-06 16:49:32 -080062 * Since the low 8-bit in metadata may look like NOP, we need to check
buzbee67bf8852011-08-17 17:51:35 -070063 * both the low and whole sub-word to determine whether it is code or data.
64 */
Elliott Hughesadb8c672012-03-06 16:49:32 -080065 return (opcode != Instruction::NOP || instr == 0);
buzbee67bf8852011-08-17 17:51:35 -070066}
67
68/*
69 * Parse an instruction, return the length of the instruction
70 */
buzbee31a4a6f2012-02-28 15:36:15 -080071inline int parseInsn(CompilationUnit* cUnit, const u2* codePtr,
Elliott Hughesadb8c672012-03-06 16:49:32 -080072 DecodedInstruction* decoded_instruction, bool printMe)
buzbee67bf8852011-08-17 17:51:35 -070073{
Elliott Hughesadb8c672012-03-06 16:49:32 -080074 // Don't parse instruction data
75 if (!contentIsInsn(codePtr)) {
76 return 0;
77 }
buzbee67bf8852011-08-17 17:51:35 -070078
Elliott Hughesadb8c672012-03-06 16:49:32 -080079 const Instruction* instruction = Instruction::At(codePtr);
80 *decoded_instruction = DecodedInstruction(instruction);
buzbee67bf8852011-08-17 17:51:35 -070081
Elliott Hughesadb8c672012-03-06 16:49:32 -080082 if (printMe) {
83 char* decodedString = oatGetDalvikDisassembly(cUnit, *decoded_instruction, NULL);
84 LOG(INFO) << codePtr << ": 0x" << std::hex << static_cast<int>(decoded_instruction->opcode)
85 << " " << decodedString;
86 }
87 return instruction->SizeInCodeUnits();
buzbee67bf8852011-08-17 17:51:35 -070088}
89
90#define UNKNOWN_TARGET 0xffffffff
91
Elliott Hughesadb8c672012-03-06 16:49:32 -080092inline bool isGoto(MIR* insn) {
93 switch (insn->dalvikInsn.opcode) {
94 case Instruction::GOTO:
95 case Instruction::GOTO_16:
96 case Instruction::GOTO_32:
97 return true;
98 default:
99 return false;
buzbee67bf8852011-08-17 17:51:35 -0700100 }
101}
102
103/*
104 * Identify unconditional branch instructions
105 */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800106inline bool isUnconditionalBranch(MIR* insn) {
107 switch (insn->dalvikInsn.opcode) {
108 case Instruction::RETURN_VOID:
109 case Instruction::RETURN:
110 case Instruction::RETURN_WIDE:
111 case Instruction::RETURN_OBJECT:
112 return true;
113 default:
114 return isGoto(insn);
115 }
buzbee67bf8852011-08-17 17:51:35 -0700116}
117
118/* Split an existing block from the specified code offset into two */
buzbee31a4a6f2012-02-28 15:36:15 -0800119BasicBlock *splitBlock(CompilationUnit* cUnit, unsigned int codeOffset,
120 BasicBlock* origBlock, BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700121{
122 MIR* insn = origBlock->firstMIRInsn;
123 while (insn) {
124 if (insn->offset == codeOffset) break;
125 insn = insn->next;
126 }
127 if (insn == NULL) {
128 LOG(FATAL) << "Break split failed";
129 }
buzbee5abfa3e2012-01-31 17:01:43 -0800130 BasicBlock *bottomBlock = oatNewBB(cUnit, kDalvikByteCode,
131 cUnit->numBlocks++);
buzbeeba938cb2012-02-03 14:47:55 -0800132 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700133
134 bottomBlock->startOffset = codeOffset;
135 bottomBlock->firstMIRInsn = insn;
136 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
137
buzbee5b537102012-01-17 17:33:47 -0800138 /* Add it to the quick lookup cache */
139 cUnit->blockMap.insert(std::make_pair(bottomBlock->startOffset,
140 bottomBlock));
141
buzbee67bf8852011-08-17 17:51:35 -0700142 /* Handle the taken path */
143 bottomBlock->taken = origBlock->taken;
144 if (bottomBlock->taken) {
145 origBlock->taken = NULL;
buzbee5abfa3e2012-01-31 17:01:43 -0800146 oatDeleteGrowableList(bottomBlock->taken->predecessors,
147 (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800148 oatInsertGrowableList(cUnit, bottomBlock->taken->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800149 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700150 }
151
152 /* Handle the fallthrough path */
153 bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
154 bottomBlock->fallThrough = origBlock->fallThrough;
155 origBlock->fallThrough = bottomBlock;
156 origBlock->needFallThroughBranch = true;
buzbeeba938cb2012-02-03 14:47:55 -0800157 oatInsertGrowableList(cUnit, bottomBlock->predecessors,
158 (intptr_t)origBlock);
buzbee67bf8852011-08-17 17:51:35 -0700159 if (bottomBlock->fallThrough) {
buzbee5abfa3e2012-01-31 17:01:43 -0800160 oatDeleteGrowableList(bottomBlock->fallThrough->predecessors,
161 (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800162 oatInsertGrowableList(cUnit, bottomBlock->fallThrough->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800163 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700164 }
165
166 /* Handle the successor list */
167 if (origBlock->successorBlockList.blockListType != kNotUsed) {
168 bottomBlock->successorBlockList = origBlock->successorBlockList;
169 origBlock->successorBlockList.blockListType = kNotUsed;
170 GrowableListIterator iterator;
171
172 oatGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
173 &iterator);
174 while (true) {
175 SuccessorBlockInfo *successorBlockInfo =
176 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
177 if (successorBlockInfo == NULL) break;
178 BasicBlock *bb = successorBlockInfo->block;
buzbee5abfa3e2012-01-31 17:01:43 -0800179 oatDeleteGrowableList(bb->predecessors, (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800180 oatInsertGrowableList(cUnit, bb->predecessors,
181 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700182 }
183 }
184
185 origBlock->lastMIRInsn = insn->prev;
186
187 insn->prev->next = NULL;
188 insn->prev = NULL;
buzbee9ab05de2012-01-18 15:43:48 -0800189 /*
190 * Update the immediate predecessor block pointer so that outgoing edges
191 * can be applied to the proper block.
192 */
193 if (immedPredBlockP) {
194 DCHECK_EQ(*immedPredBlockP, origBlock);
195 *immedPredBlockP = bottomBlock;
196 }
buzbee67bf8852011-08-17 17:51:35 -0700197 return bottomBlock;
198}
199
200/*
201 * Given a code offset, find out the block that starts with it. If the offset
buzbee9ab05de2012-01-18 15:43:48 -0800202 * is in the middle of an existing block, split it into two. If immedPredBlockP
203 * is not non-null and is the block being split, update *immedPredBlockP to
204 * point to the bottom block so that outgoing edges can be set up properly
205 * (by the caller)
buzbee5b537102012-01-17 17:33:47 -0800206 * Utilizes a map for fast lookup of the typical cases.
buzbee67bf8852011-08-17 17:51:35 -0700207 */
buzbee31a4a6f2012-02-28 15:36:15 -0800208BasicBlock *findBlock(CompilationUnit* cUnit, unsigned int codeOffset,
209 bool split, bool create, BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700210{
211 GrowableList* blockList = &cUnit->blockList;
212 BasicBlock* bb;
213 unsigned int i;
buzbee5b537102012-01-17 17:33:47 -0800214 std::map<unsigned int, BasicBlock*>::iterator it;
buzbee67bf8852011-08-17 17:51:35 -0700215
buzbee5b537102012-01-17 17:33:47 -0800216 it = cUnit->blockMap.find(codeOffset);
217 if (it != cUnit->blockMap.end()) {
218 return it->second;
219 } else if (!create) {
220 return NULL;
221 }
222
223 if (split) {
224 for (i = 0; i < blockList->numUsed; i++) {
225 bb = (BasicBlock *) blockList->elemList[i];
226 if (bb->blockType != kDalvikByteCode) continue;
227 /* Check if a branch jumps into the middle of an existing block */
228 if ((codeOffset > bb->startOffset) && (bb->lastMIRInsn != NULL) &&
229 (codeOffset <= bb->lastMIRInsn->offset)) {
230 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb,
231 bb == *immedPredBlockP ?
232 immedPredBlockP : NULL);
233 return newBB;
234 }
buzbee67bf8852011-08-17 17:51:35 -0700235 }
236 }
buzbee5b537102012-01-17 17:33:47 -0800237
238 /* Create a new one */
buzbee5abfa3e2012-01-31 17:01:43 -0800239 bb = oatNewBB(cUnit, kDalvikByteCode, cUnit->numBlocks++);
buzbeeba938cb2012-02-03 14:47:55 -0800240 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) bb);
buzbee5b537102012-01-17 17:33:47 -0800241 bb->startOffset = codeOffset;
242 cUnit->blockMap.insert(std::make_pair(bb->startOffset, bb));
243 return bb;
buzbee67bf8852011-08-17 17:51:35 -0700244}
245
246/* Dump the CFG into a DOT graph */
247void oatDumpCFG(CompilationUnit* cUnit, const char* dirPrefix)
248{
buzbee67bf8852011-08-17 17:51:35 -0700249 FILE* file;
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800250 std::string name(PrettyMethod(cUnit->method_idx, *cUnit->dex_file));
buzbee67bf8852011-08-17 17:51:35 -0700251 char startOffset[80];
252 sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
buzbeeba938cb2012-02-03 14:47:55 -0800253 char* fileName = (char*) oatNew(cUnit,
buzbeec143c552011-08-20 17:38:58 -0700254 strlen(dirPrefix) +
255 name.length() +
buzbee5abfa3e2012-01-31 17:01:43 -0800256 strlen(".dot") + 1, true, kAllocDebugInfo);
buzbeec143c552011-08-20 17:38:58 -0700257 sprintf(fileName, "%s%s%s.dot", dirPrefix, name.c_str(), startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700258
259 /*
260 * Convert the special characters into a filesystem- and shell-friendly
261 * format.
262 */
263 int i;
264 for (i = strlen(dirPrefix); fileName[i]; i++) {
265 if (fileName[i] == '/') {
266 fileName[i] = '_';
267 } else if (fileName[i] == ';') {
268 fileName[i] = '#';
269 } else if (fileName[i] == '$') {
270 fileName[i] = '+';
271 } else if (fileName[i] == '(' || fileName[i] == ')') {
272 fileName[i] = '@';
273 } else if (fileName[i] == '<' || fileName[i] == '>') {
274 fileName[i] = '=';
275 }
276 }
277 file = fopen(fileName, "w");
278 if (file == NULL) {
279 return;
280 }
281 fprintf(file, "digraph G {\n");
282
283 fprintf(file, " rankdir=TB\n");
284
285 int numReachableBlocks = cUnit->numReachableBlocks;
286 int idx;
287 const GrowableList *blockList = &cUnit->blockList;
288
289 for (idx = 0; idx < numReachableBlocks; idx++) {
290 int blockIdx = cUnit->dfsOrder.elemList[idx];
291 BasicBlock *bb = (BasicBlock *) oatGrowableListGetElement(blockList,
292 blockIdx);
293 if (bb == NULL) break;
294 if (bb->blockType == kEntryBlock) {
295 fprintf(file, " entry [shape=Mdiamond];\n");
296 } else if (bb->blockType == kExitBlock) {
297 fprintf(file, " exit [shape=Mdiamond];\n");
298 } else if (bb->blockType == kDalvikByteCode) {
299 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
300 bb->startOffset);
301 const MIR *mir;
302 fprintf(file, " {block id %d\\l}%s\\\n", bb->id,
303 bb->firstMIRInsn ? " | " : " ");
304 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
305 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
Elliott Hughesadb8c672012-03-06 16:49:32 -0800306 mir->ssaRep ? oatFullDisassembler(cUnit, mir) : Instruction::Name(mir->dalvikInsn.opcode),
buzbee67bf8852011-08-17 17:51:35 -0700307 mir->next ? " | " : " ");
308 }
309 fprintf(file, " }\"];\n\n");
310 } else if (bb->blockType == kExceptionHandling) {
311 char blockName[BLOCK_NAME_LEN];
312
313 oatGetBlockName(bb, blockName);
314 fprintf(file, " %s [shape=invhouse];\n", blockName);
315 }
316
317 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
318
319 if (bb->taken) {
320 oatGetBlockName(bb, blockName1);
321 oatGetBlockName(bb->taken, blockName2);
322 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
323 blockName1, blockName2);
324 }
325 if (bb->fallThrough) {
326 oatGetBlockName(bb, blockName1);
327 oatGetBlockName(bb->fallThrough, blockName2);
328 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
329 }
330
331 if (bb->successorBlockList.blockListType != kNotUsed) {
332 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
333 bb->startOffset,
334 (bb->successorBlockList.blockListType == kCatch) ?
335 "Mrecord" : "record");
336 GrowableListIterator iterator;
337 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
338 &iterator);
339 SuccessorBlockInfo *successorBlockInfo =
340 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
341
342 int succId = 0;
343 while (true) {
344 if (successorBlockInfo == NULL) break;
345
346 BasicBlock *destBlock = successorBlockInfo->block;
347 SuccessorBlockInfo *nextSuccessorBlockInfo =
348 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
349
350 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
351 succId++,
352 successorBlockInfo->key,
353 destBlock->startOffset,
354 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
355
356 successorBlockInfo = nextSuccessorBlockInfo;
357 }
358 fprintf(file, " }\"];\n\n");
359
360 oatGetBlockName(bb, blockName1);
361 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
362 blockName1, bb->startOffset);
363
364 if (bb->successorBlockList.blockListType == kPackedSwitch ||
365 bb->successorBlockList.blockListType == kSparseSwitch) {
366
367 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
368 &iterator);
369
370 succId = 0;
371 while (true) {
372 SuccessorBlockInfo *successorBlockInfo =
373 (SuccessorBlockInfo *)
374 oatGrowableListIteratorNext(&iterator);
375 if (successorBlockInfo == NULL) break;
376
377 BasicBlock *destBlock = successorBlockInfo->block;
378
379 oatGetBlockName(destBlock, blockName2);
380 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
381 bb->startOffset, succId++,
382 blockName2);
383 }
384 }
385 }
386 fprintf(file, "\n");
387
buzbeece302932011-10-04 14:32:18 -0700388 /* Display the dominator tree */
buzbee67bf8852011-08-17 17:51:35 -0700389 oatGetBlockName(bb, blockName1);
390 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
391 blockName1, blockName1);
392 if (bb->iDom) {
393 oatGetBlockName(bb->iDom, blockName2);
394 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
395 blockName2, blockName1);
396 }
buzbee67bf8852011-08-17 17:51:35 -0700397 }
398 fprintf(file, "}\n");
399 fclose(file);
400}
401
402/* Verify if all the successor is connected with all the claimed predecessors */
buzbee31a4a6f2012-02-28 15:36:15 -0800403bool verifyPredInfo(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -0700404{
buzbee5abfa3e2012-01-31 17:01:43 -0800405 GrowableListIterator iter;
buzbee67bf8852011-08-17 17:51:35 -0700406
buzbee5abfa3e2012-01-31 17:01:43 -0800407 oatGrowableListIteratorInit(bb->predecessors, &iter);
buzbee67bf8852011-08-17 17:51:35 -0700408 while (true) {
buzbee5abfa3e2012-01-31 17:01:43 -0800409 BasicBlock *predBB = (BasicBlock*)oatGrowableListIteratorNext(&iter);
410 if (!predBB) break;
buzbee67bf8852011-08-17 17:51:35 -0700411 bool found = false;
412 if (predBB->taken == bb) {
413 found = true;
414 } else if (predBB->fallThrough == bb) {
415 found = true;
416 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
417 GrowableListIterator iterator;
418 oatGrowableListIteratorInit(&predBB->successorBlockList.blocks,
419 &iterator);
420 while (true) {
421 SuccessorBlockInfo *successorBlockInfo =
422 (SuccessorBlockInfo *)
423 oatGrowableListIteratorNext(&iterator);
424 if (successorBlockInfo == NULL) break;
425 BasicBlock *succBB = successorBlockInfo->block;
426 if (succBB == bb) {
427 found = true;
428 break;
429 }
430 }
431 }
432 if (found == false) {
433 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
434 oatGetBlockName(bb, blockName1);
435 oatGetBlockName(predBB, blockName2);
436 oatDumpCFG(cUnit, "/sdcard/cfg/");
437 LOG(FATAL) << "Successor " << blockName1 << "not found from "
438 << blockName2;
439 }
440 }
441 return true;
442}
443
444/* Identify code range in try blocks and set up the empty catch blocks */
buzbee31a4a6f2012-02-28 15:36:15 -0800445void processTryCatchBlocks(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700446{
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800447 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbeee9a72f62011-09-04 17:59:07 -0700448 int triesSize = code_item->tries_size_;
buzbee67bf8852011-08-17 17:51:35 -0700449 int offset;
450
451 if (triesSize == 0) {
452 return;
453 }
454
buzbee67bf8852011-08-17 17:51:35 -0700455 ArenaBitVector* tryBlockAddr = cUnit->tryBlockAddr;
456
buzbeee9a72f62011-09-04 17:59:07 -0700457 for (int i = 0; i < triesSize; i++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800458 const DexFile::TryItem* pTry =
459 DexFile::GetTryItems(*code_item, i);
buzbeee9a72f62011-09-04 17:59:07 -0700460 int startOffset = pTry->start_addr_;
461 int endOffset = startOffset + pTry->insn_count_;
buzbee67bf8852011-08-17 17:51:35 -0700462 for (offset = startOffset; offset < endOffset; offset++) {
buzbeeba938cb2012-02-03 14:47:55 -0800463 oatSetBit(cUnit, tryBlockAddr, offset);
buzbee67bf8852011-08-17 17:51:35 -0700464 }
465 }
466
buzbeee9a72f62011-09-04 17:59:07 -0700467 // Iterate over each of the handlers to enqueue the empty Catch blocks
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800468 const byte* handlers_ptr =
469 DexFile::GetCatchHandlerData(*code_item, 0);
470 uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
buzbeee9a72f62011-09-04 17:59:07 -0700471 for (uint32_t idx = 0; idx < handlers_size; idx++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800472 CatchHandlerIterator iterator(handlers_ptr);
Ian Rogers0571d352011-11-03 19:51:38 -0700473 for (; iterator.HasNext(); iterator.Next()) {
474 uint32_t address = iterator.GetHandlerAddress();
buzbee9ab05de2012-01-18 15:43:48 -0800475 findBlock(cUnit, address, false /* split */, true /*create*/,
476 /* immedPredBlockP */ NULL);
buzbee67bf8852011-08-17 17:51:35 -0700477 }
Ian Rogers0571d352011-11-03 19:51:38 -0700478 handlers_ptr = iterator.EndDataPointer();
buzbee67bf8852011-08-17 17:51:35 -0700479 }
480}
481
Elliott Hughesadb8c672012-03-06 16:49:32 -0800482/* Process instructions with the kBranch flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800483BasicBlock* processCanBranch(CompilationUnit* cUnit, BasicBlock* curBlock,
484 MIR* insn, int curOffset, int width, int flags,
485 const u2* codePtr, const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700486{
487 int target = curOffset;
488 switch (insn->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800489 case Instruction::GOTO:
490 case Instruction::GOTO_16:
491 case Instruction::GOTO_32:
buzbee67bf8852011-08-17 17:51:35 -0700492 target += (int) insn->dalvikInsn.vA;
493 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800494 case Instruction::IF_EQ:
495 case Instruction::IF_NE:
496 case Instruction::IF_LT:
497 case Instruction::IF_GE:
498 case Instruction::IF_GT:
499 case Instruction::IF_LE:
buzbee67bf8852011-08-17 17:51:35 -0700500 target += (int) insn->dalvikInsn.vC;
501 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800502 case Instruction::IF_EQZ:
503 case Instruction::IF_NEZ:
504 case Instruction::IF_LTZ:
505 case Instruction::IF_GEZ:
506 case Instruction::IF_GTZ:
507 case Instruction::IF_LEZ:
buzbee67bf8852011-08-17 17:51:35 -0700508 target += (int) insn->dalvikInsn.vB;
509 break;
510 default:
511 LOG(FATAL) << "Unexpected opcode(" << (int)insn->dalvikInsn.opcode
Elliott Hughesadb8c672012-03-06 16:49:32 -0800512 << ") with kBranch set";
buzbee67bf8852011-08-17 17:51:35 -0700513 }
514 BasicBlock *takenBlock = findBlock(cUnit, target,
515 /* split */
516 true,
517 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800518 true,
519 /* immedPredBlockP */
520 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700521 curBlock->taken = takenBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800522 oatInsertGrowableList(cUnit, takenBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700523
524 /* Always terminate the current block for conditional branches */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800525 if (flags & Instruction::kContinue) {
buzbee67bf8852011-08-17 17:51:35 -0700526 BasicBlock *fallthroughBlock = findBlock(cUnit,
527 curOffset + width,
528 /*
529 * If the method is processed
530 * in sequential order from the
531 * beginning, we don't need to
532 * specify split for continue
533 * blocks. However, this
534 * routine can be called by
535 * compileLoop, which starts
536 * parsing the method from an
537 * arbitrary address in the
538 * method body.
539 */
540 true,
541 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800542 true,
543 /* immedPredBlockP */
544 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700545 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800546 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800547 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700548 } else if (codePtr < codeEnd) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800549 /* Create a fallthrough block for real instructions (incl. NOP) */
buzbee67bf8852011-08-17 17:51:35 -0700550 if (contentIsInsn(codePtr)) {
551 findBlock(cUnit, curOffset + width,
552 /* split */
553 false,
554 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800555 true,
556 /* immedPredBlockP */
557 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700558 }
559 }
buzbeee941e2c2011-12-05 12:38:17 -0800560 return curBlock;
buzbee67bf8852011-08-17 17:51:35 -0700561}
562
Elliott Hughesadb8c672012-03-06 16:49:32 -0800563/* Process instructions with the kSwitch flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800564void processCanSwitch(CompilationUnit* cUnit, BasicBlock* curBlock,
565 MIR* insn, int curOffset, int width, int flags)
buzbee67bf8852011-08-17 17:51:35 -0700566{
567 u2* switchData= (u2 *) (cUnit->insns + curOffset +
568 insn->dalvikInsn.vB);
569 int size;
570 int* keyTable;
571 int* targetTable;
572 int i;
573 int firstKey;
574
575 /*
576 * Packed switch data format:
577 * ushort ident = 0x0100 magic value
578 * ushort size number of entries in the table
579 * int first_key first (and lowest) switch case value
580 * int targets[size] branch targets, relative to switch opcode
581 *
582 * Total size is (4+size*2) 16-bit code units.
583 */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800584 if (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) {
585 DCHECK_EQ(static_cast<int>(switchData[0]), static_cast<int>(Instruction::kPackedSwitchSignature));
buzbee67bf8852011-08-17 17:51:35 -0700586 size = switchData[1];
587 firstKey = switchData[2] | (switchData[3] << 16);
588 targetTable = (int *) &switchData[4];
589 keyTable = NULL; // Make the compiler happy
590 /*
591 * Sparse switch data format:
592 * ushort ident = 0x0200 magic value
593 * ushort size number of entries in the table; > 0
594 * int keys[size] keys, sorted low-to-high; 32-bit aligned
595 * int targets[size] branch targets, relative to switch opcode
596 *
597 * Total size is (2+size*4) 16-bit code units.
598 */
599 } else {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800600 DCHECK_EQ(static_cast<int>(switchData[0]), static_cast<int>(Instruction::kSparseSwitchSignature));
buzbee67bf8852011-08-17 17:51:35 -0700601 size = switchData[1];
602 keyTable = (int *) &switchData[2];
603 targetTable = (int *) &switchData[2 + size*2];
604 firstKey = 0; // To make the compiler happy
605 }
606
607 if (curBlock->successorBlockList.blockListType != kNotUsed) {
608 LOG(FATAL) << "Successor block list already in use: " <<
609 (int)curBlock->successorBlockList.blockListType;
610 }
611 curBlock->successorBlockList.blockListType =
Elliott Hughesadb8c672012-03-06 16:49:32 -0800612 (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) ?
buzbee67bf8852011-08-17 17:51:35 -0700613 kPackedSwitch : kSparseSwitch;
buzbeeba938cb2012-02-03 14:47:55 -0800614 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, size,
buzbee5abfa3e2012-01-31 17:01:43 -0800615 kListSuccessorBlocks);
buzbee67bf8852011-08-17 17:51:35 -0700616
617 for (i = 0; i < size; i++) {
618 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
619 /* split */
620 true,
621 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800622 true,
623 /* immedPredBlockP */
624 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700625 SuccessorBlockInfo *successorBlockInfo =
buzbeeba938cb2012-02-03 14:47:55 -0800626 (SuccessorBlockInfo *) oatNew(cUnit, sizeof(SuccessorBlockInfo),
627 false, kAllocSuccessor);
buzbee67bf8852011-08-17 17:51:35 -0700628 successorBlockInfo->block = caseBlock;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800629 successorBlockInfo->key = (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH)?
buzbee67bf8852011-08-17 17:51:35 -0700630 firstKey + i : keyTable[i];
buzbeeba938cb2012-02-03 14:47:55 -0800631 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
buzbee67bf8852011-08-17 17:51:35 -0700632 (intptr_t) successorBlockInfo);
buzbeeba938cb2012-02-03 14:47:55 -0800633 oatInsertGrowableList(cUnit, caseBlock->predecessors,
634 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700635 }
636
637 /* Fall-through case */
638 BasicBlock* fallthroughBlock = findBlock(cUnit,
639 curOffset + width,
640 /* split */
641 false,
642 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800643 true,
644 /* immedPredBlockP */
645 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700646 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800647 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
648 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700649}
650
Elliott Hughesadb8c672012-03-06 16:49:32 -0800651/* Process instructions with the kThrow flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800652void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock, MIR* insn,
653 int curOffset, int width, int flags,
654 ArenaBitVector* tryBlockAddr, const u2* codePtr,
655 const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700656{
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800657 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbee67bf8852011-08-17 17:51:35 -0700658
659 /* In try block */
660 if (oatIsBitSet(tryBlockAddr, curOffset)) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800661 CatchHandlerIterator iterator(*code_item, curOffset);
buzbee67bf8852011-08-17 17:51:35 -0700662
buzbee67bf8852011-08-17 17:51:35 -0700663 if (curBlock->successorBlockList.blockListType != kNotUsed) {
664 LOG(FATAL) << "Successor block list already in use: " <<
665 (int)curBlock->successorBlockList.blockListType;
666 }
buzbeee9a72f62011-09-04 17:59:07 -0700667
buzbee67bf8852011-08-17 17:51:35 -0700668 curBlock->successorBlockList.blockListType = kCatch;
buzbeeba938cb2012-02-03 14:47:55 -0800669 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, 2,
buzbee5abfa3e2012-01-31 17:01:43 -0800670 kListSuccessorBlocks);
buzbee67bf8852011-08-17 17:51:35 -0700671
Ian Rogers0571d352011-11-03 19:51:38 -0700672 for (;iterator.HasNext(); iterator.Next()) {
673 BasicBlock *catchBlock = findBlock(cUnit, iterator.GetHandlerAddress(),
buzbeee9a72f62011-09-04 17:59:07 -0700674 false /* split*/,
buzbee9ab05de2012-01-18 15:43:48 -0800675 false /* creat */,
676 NULL /* immedPredBlockP */);
buzbee43a36422011-09-14 14:00:13 -0700677 catchBlock->catchEntry = true;
buzbeeba938cb2012-02-03 14:47:55 -0800678 SuccessorBlockInfo *successorBlockInfo = (SuccessorBlockInfo *)
679 oatNew(cUnit, sizeof(SuccessorBlockInfo), false,
680 kAllocSuccessor);
buzbee67bf8852011-08-17 17:51:35 -0700681 successorBlockInfo->block = catchBlock;
Ian Rogers0571d352011-11-03 19:51:38 -0700682 successorBlockInfo->key = iterator.GetHandlerTypeIndex();
buzbeeba938cb2012-02-03 14:47:55 -0800683 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
buzbee67bf8852011-08-17 17:51:35 -0700684 (intptr_t) successorBlockInfo);
buzbeeba938cb2012-02-03 14:47:55 -0800685 oatInsertGrowableList(cUnit, catchBlock->predecessors,
686 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700687 }
688 } else {
buzbee5abfa3e2012-01-31 17:01:43 -0800689 BasicBlock *ehBlock = oatNewBB(cUnit, kExceptionHandling,
690 cUnit->numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700691 curBlock->taken = ehBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800692 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) ehBlock);
buzbee67bf8852011-08-17 17:51:35 -0700693 ehBlock->startOffset = curOffset;
buzbeeba938cb2012-02-03 14:47:55 -0800694 oatInsertGrowableList(cUnit, ehBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700695 }
696
697 /*
698 * Force the current block to terminate.
699 *
700 * Data may be present before codeEnd, so we need to parse it to know
701 * whether it is code or data.
702 */
703 if (codePtr < codeEnd) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800704 /* Create a fallthrough block for real instructions (incl. NOP) */
buzbee67bf8852011-08-17 17:51:35 -0700705 if (contentIsInsn(codePtr)) {
706 BasicBlock *fallthroughBlock = findBlock(cUnit,
707 curOffset + width,
708 /* split */
709 false,
710 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800711 true,
712 /* immedPredBlockP */
713 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700714 /*
Elliott Hughesadb8c672012-03-06 16:49:32 -0800715 * THROW is an unconditional branch. NOTE:
716 * THROW_VERIFICATION_ERROR is also an unconditional
buzbee510c6052011-10-27 10:47:20 -0700717 * branch, but we shouldn't treat it as such until we have
718 * a dead code elimination pass (which won't be important
719 * until inlining w/ constant propogation is implemented.
buzbee67bf8852011-08-17 17:51:35 -0700720 */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800721 if (insn->dalvikInsn.opcode != Instruction::THROW) {
buzbee67bf8852011-08-17 17:51:35 -0700722 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800723 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800724 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700725 }
726 }
727 }
728}
729
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800730void oatInit(CompilationUnit* cUnit, const Compiler& compiler) {
731 if (!oatArchInit()) {
732 LOG(FATAL) << "Failed to initialize oat";
733 }
734 if (!oatHeapInit(cUnit)) {
735 LOG(FATAL) << "Failed to initialize oat heap";
736 }
737}
738
Elliott Hughes3fa1b7e2012-03-13 17:06:22 -0700739CompiledMethod* oatCompileMethod(Compiler& compiler,
740 const DexFile::CodeItem* code_item,
741 uint32_t access_flags, uint32_t method_idx,
742 const ClassLoader* class_loader,
743 const DexFile& dex_file)
buzbee67bf8852011-08-17 17:51:35 -0700744{
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800745 VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
Brian Carlstrom94496d32011-08-22 09:22:47 -0700746
buzbeec143c552011-08-20 17:38:58 -0700747 const u2* codePtr = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700748 const u2* codeEnd = code_item->insns_ + code_item->insns_size_in_code_units_;
buzbee67bf8852011-08-17 17:51:35 -0700749 int numBlocks = 0;
750 unsigned int curOffset = 0;
751
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800752 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700753 UniquePtr<CompilationUnit> cUnit(new CompilationUnit);
buzbeeba938cb2012-02-03 14:47:55 -0800754
755 oatInit(cUnit.get(), compiler);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800756
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700757 cUnit->compiler = &compiler;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800758 cUnit->class_linker = class_linker;
759 cUnit->dex_file = &dex_file;
760 cUnit->dex_cache = class_linker->FindDexCache(dex_file);
761 cUnit->method_idx = method_idx;
762 cUnit->code_item = code_item;
763 cUnit->access_flags = access_flags;
764 cUnit->shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800765 cUnit->instructionSet = compiler.GetInstructionSet();
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700766 cUnit->insns = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700767 cUnit->insnsSize = code_item->insns_size_in_code_units_;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800768 cUnit->numIns = code_item->ins_size_;
769 cUnit->numRegs = code_item->registers_size_ - cUnit->numIns;
770 cUnit->numOuts = code_item->outs_size_;
771 /* Adjust this value accordingly once inlining is performed */
772 cUnit->numDalvikRegisters = code_item->registers_size_;
Elliott Hughese52e49b2012-04-02 16:05:44 -0700773 // TODO: set this from command line
buzbeeba938cb2012-02-03 14:47:55 -0800774 cUnit->compilerFlipMatch = false;
Elliott Hughese52e49b2012-04-02 16:05:44 -0700775 bool useMatch = !cUnit->compilerMethodMatch.empty();
buzbeeba938cb2012-02-03 14:47:55 -0800776 bool match = useMatch && (cUnit->compilerFlipMatch ^
Elliott Hughese52e49b2012-04-02 16:05:44 -0700777 (PrettyMethod(method_idx, dex_file).find(cUnit->compilerMethodMatch) != std::string::npos));
buzbeece302932011-10-04 14:32:18 -0700778 if (!useMatch || match) {
Elliott Hughese52e49b2012-04-02 16:05:44 -0700779 cUnit->disableOpt = kCompilerOptimizerDisableFlags;
780 cUnit->enableDebug = kCompilerDebugFlags;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800781 cUnit->printMe = VLOG_IS_ON(compiler) || (cUnit->enableDebug & (1 << kDebugVerbose));
buzbeece302932011-10-04 14:32:18 -0700782 }
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700783 if (cUnit->instructionSet == kX86) {
784 // Disable optimizations on X86 for now
785 cUnit->disableOpt = -1;
786 }
buzbee44b412b2012-02-04 08:50:53 -0800787 /* Are we generating code for the debugger? */
Elliott Hughesde6e4cf2012-02-27 14:46:06 -0800788 if (compiler.IsDebuggingSupported()) {
buzbee44b412b2012-02-04 08:50:53 -0800789 cUnit->genDebugger = true;
790 // Yes, disable most optimizations
791 cUnit->disableOpt |= (
792 (1 << kLoadStoreElimination) |
793 (1 << kLoadHoisting) |
794 (1 << kSuppressLoads) |
795 (1 << kPromoteRegs) |
buzbeeb37c9992012-03-18 21:28:43 -0700796 (1 << kBBOpt) |
buzbee16da88c2012-03-20 10:38:17 -0700797 (1 << kMatch) |
buzbee44b412b2012-02-04 08:50:53 -0800798 (1 << kTrackLiveTemps));
799 }
800
buzbeea7c12682012-03-19 13:13:53 -0700801 /* Gathering opcode stats? */
Elliott Hughese52e49b2012-04-02 16:05:44 -0700802 if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) {
buzbeea7c12682012-03-19 13:13:53 -0700803 cUnit->opcodeCount = (int*)oatNew(cUnit.get(),
804 kNumPackedOpcodes * sizeof(int), true, kAllocMisc);
805 }
806
buzbeecefd1872011-09-09 09:59:52 -0700807 /* Assume non-throwing leaf */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700808 cUnit->attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
buzbeecefd1872011-09-09 09:59:52 -0700809
buzbee5abfa3e2012-01-31 17:01:43 -0800810 /* Initialize the block list, estimate size based on insnsSize */
buzbeeba938cb2012-02-03 14:47:55 -0800811 oatInitGrowableList(cUnit.get(), &cUnit->blockList, cUnit->insnsSize,
812 kListBlockList);
buzbee67bf8852011-08-17 17:51:35 -0700813
814 /* Initialize the switchTables list */
buzbeeba938cb2012-02-03 14:47:55 -0800815 oatInitGrowableList(cUnit.get(), &cUnit->switchTables, 4,
816 kListSwitchTables);
buzbee67bf8852011-08-17 17:51:35 -0700817
818 /* Intialize the fillArrayData list */
buzbeeba938cb2012-02-03 14:47:55 -0800819 oatInitGrowableList(cUnit.get(), &cUnit->fillArrayData, 4,
820 kListFillArrayData);
buzbee67bf8852011-08-17 17:51:35 -0700821
buzbee5abfa3e2012-01-31 17:01:43 -0800822 /* Intialize the throwLaunchpads list, estimate size based on insnsSize */
buzbeeba938cb2012-02-03 14:47:55 -0800823 oatInitGrowableList(cUnit.get(), &cUnit->throwLaunchpads, cUnit->insnsSize,
buzbee5abfa3e2012-01-31 17:01:43 -0800824 kListThrowLaunchPads);
buzbee5ade1d22011-09-09 14:44:52 -0700825
buzbeefc9e6fa2012-03-23 15:14:29 -0700826 /* Intialize the instrinsicLaunchpads list */
827 oatInitGrowableList(cUnit.get(), &cUnit->intrinsicLaunchpads, 4,
828 kListMisc);
829
830
buzbeec1f45042011-09-21 16:03:19 -0700831 /* Intialize the suspendLaunchpads list */
buzbeeba938cb2012-02-03 14:47:55 -0800832 oatInitGrowableList(cUnit.get(), &cUnit->suspendLaunchpads, 2048,
buzbee5abfa3e2012-01-31 17:01:43 -0800833 kListSuspendLaunchPads);
buzbeec1f45042011-09-21 16:03:19 -0700834
buzbee67bf8852011-08-17 17:51:35 -0700835 /* Allocate the bit-vector to track the beginning of basic blocks */
buzbeeba938cb2012-02-03 14:47:55 -0800836 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit.get(),
837 cUnit->insnsSize,
buzbee67bf8852011-08-17 17:51:35 -0700838 true /* expandable */);
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700839 cUnit->tryBlockAddr = tryBlockAddr;
buzbee67bf8852011-08-17 17:51:35 -0700840
841 /* Create the default entry and exit blocks and enter them to the list */
buzbee5abfa3e2012-01-31 17:01:43 -0800842 BasicBlock *entryBlock = oatNewBB(cUnit.get(), kEntryBlock, numBlocks++);
843 BasicBlock *exitBlock = oatNewBB(cUnit.get(), kExitBlock, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700844
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700845 cUnit->entryBlock = entryBlock;
846 cUnit->exitBlock = exitBlock;
buzbee67bf8852011-08-17 17:51:35 -0700847
buzbeeba938cb2012-02-03 14:47:55 -0800848 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) entryBlock);
849 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) exitBlock);
buzbee67bf8852011-08-17 17:51:35 -0700850
851 /* Current block to record parsed instructions */
buzbee5abfa3e2012-01-31 17:01:43 -0800852 BasicBlock *curBlock = oatNewBB(cUnit.get(), kDalvikByteCode, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700853 curBlock->startOffset = 0;
buzbeeba938cb2012-02-03 14:47:55 -0800854 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) curBlock);
buzbee5b537102012-01-17 17:33:47 -0800855 /* Add first block to the fast lookup cache */
856 cUnit->blockMap.insert(std::make_pair(curBlock->startOffset, curBlock));
buzbee67bf8852011-08-17 17:51:35 -0700857 entryBlock->fallThrough = curBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800858 oatInsertGrowableList(cUnit.get(), curBlock->predecessors,
859 (intptr_t)entryBlock);
buzbee67bf8852011-08-17 17:51:35 -0700860
861 /*
862 * Store back the number of blocks since new blocks may be created of
863 * accessing cUnit.
864 */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700865 cUnit->numBlocks = numBlocks;
buzbee67bf8852011-08-17 17:51:35 -0700866
867 /* Identify code range in try blocks and set up the empty catch blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700868 processTryCatchBlocks(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700869
buzbee16da88c2012-03-20 10:38:17 -0700870 /* Set up for simple method detection */
871 int numPatterns = sizeof(specialPatterns)/sizeof(specialPatterns[0]);
872 bool livePattern = (numPatterns > 0) && !(cUnit->disableOpt & (1 << kMatch));
873 bool* deadPattern = (bool*)oatNew(cUnit.get(), sizeof(bool) * numPatterns,
874 kAllocMisc);
875 SpecialCaseHandler specialCase = kNoHandler;
876 int patternPos = 0;
877
buzbee67bf8852011-08-17 17:51:35 -0700878 /* Parse all instructions and put them into containing basic blocks */
879 while (codePtr < codeEnd) {
buzbeeba938cb2012-02-03 14:47:55 -0800880 MIR *insn = (MIR *) oatNew(cUnit.get(), sizeof(MIR), true, kAllocMIR);
buzbee67bf8852011-08-17 17:51:35 -0700881 insn->offset = curOffset;
buzbeeba938cb2012-02-03 14:47:55 -0800882 int width = parseInsn(cUnit.get(), codePtr, &insn->dalvikInsn, false);
buzbee67bf8852011-08-17 17:51:35 -0700883 insn->width = width;
buzbee16da88c2012-03-20 10:38:17 -0700884 Instruction::Code opcode = insn->dalvikInsn.opcode;
buzbeea7c12682012-03-19 13:13:53 -0700885 if (cUnit->opcodeCount != NULL) {
buzbee16da88c2012-03-20 10:38:17 -0700886 cUnit->opcodeCount[static_cast<int>(opcode)]++;
buzbeea7c12682012-03-19 13:13:53 -0700887 }
buzbee67bf8852011-08-17 17:51:35 -0700888
889 /* Terminate when the data section is seen */
890 if (width == 0)
891 break;
892
buzbee16da88c2012-03-20 10:38:17 -0700893 /* Possible simple method? */
894 if (livePattern) {
895 livePattern = false;
896 specialCase = kNoHandler;
897 for (int i = 0; i < numPatterns; i++) {
898 if (!deadPattern[i]) {
899 if (specialPatterns[i].opcodes[patternPos] == opcode) {
900 livePattern = true;
901 specialCase = specialPatterns[i].handlerCode;
902 } else {
903 deadPattern[i] = true;
904 }
905 }
906 }
907 patternPos++;
908 }
909
buzbee67bf8852011-08-17 17:51:35 -0700910 oatAppendMIR(curBlock, insn);
911
912 codePtr += width;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800913 int flags = Instruction::Flags(insn->dalvikInsn.opcode);
buzbee67bf8852011-08-17 17:51:35 -0700914
buzbee5abfa3e2012-01-31 17:01:43 -0800915 int dfFlags = oatDataFlowAttributes[insn->dalvikInsn.opcode];
916
917 if (dfFlags & DF_HAS_DEFS) {
918 cUnit->defCount += (dfFlags & DF_DA_WIDE) ? 2 : 1;
919 }
buzbee99ba9642012-01-25 14:23:14 -0800920
Elliott Hughesadb8c672012-03-06 16:49:32 -0800921 if (flags & Instruction::kBranch) {
buzbeee941e2c2011-12-05 12:38:17 -0800922 curBlock = processCanBranch(cUnit.get(), curBlock, insn, curOffset,
923 width, flags, codePtr, codeEnd);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800924 } else if (flags & Instruction::kReturn) {
buzbee67bf8852011-08-17 17:51:35 -0700925 curBlock->fallThrough = exitBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800926 oatInsertGrowableList(cUnit.get(), exitBlock->predecessors,
927 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700928 /*
929 * Terminate the current block if there are instructions
930 * afterwards.
931 */
932 if (codePtr < codeEnd) {
933 /*
934 * Create a fallthrough block for real instructions
Elliott Hughesadb8c672012-03-06 16:49:32 -0800935 * (incl. NOP).
buzbee67bf8852011-08-17 17:51:35 -0700936 */
937 if (contentIsInsn(codePtr)) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700938 findBlock(cUnit.get(), curOffset + width,
buzbee67bf8852011-08-17 17:51:35 -0700939 /* split */
940 false,
941 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800942 true,
943 /* immedPredBlockP */
944 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700945 }
946 }
Elliott Hughesadb8c672012-03-06 16:49:32 -0800947 } else if (flags & Instruction::kThrow) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700948 processCanThrow(cUnit.get(), curBlock, insn, curOffset, width, flags,
buzbee67bf8852011-08-17 17:51:35 -0700949 tryBlockAddr, codePtr, codeEnd);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800950 } else if (flags & Instruction::kSwitch) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700951 processCanSwitch(cUnit.get(), curBlock, insn, curOffset, width, flags);
buzbee67bf8852011-08-17 17:51:35 -0700952 }
953 curOffset += width;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700954 BasicBlock *nextBlock = findBlock(cUnit.get(), curOffset,
buzbee67bf8852011-08-17 17:51:35 -0700955 /* split */
956 false,
957 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800958 false,
959 /* immedPredBlockP */
960 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700961 if (nextBlock) {
962 /*
963 * The next instruction could be the target of a previously parsed
964 * forward branch so a block is already created. If the current
965 * instruction is not an unconditional branch, connect them through
966 * the fall-through link.
967 */
buzbeeed3e9302011-09-23 17:34:19 -0700968 DCHECK(curBlock->fallThrough == NULL ||
buzbee67bf8852011-08-17 17:51:35 -0700969 curBlock->fallThrough == nextBlock ||
970 curBlock->fallThrough == exitBlock);
971
Elliott Hughesadb8c672012-03-06 16:49:32 -0800972 if ((curBlock->fallThrough == NULL) && (flags & Instruction::kContinue)) {
buzbee67bf8852011-08-17 17:51:35 -0700973 curBlock->fallThrough = nextBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800974 oatInsertGrowableList(cUnit.get(), nextBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800975 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700976 }
977 curBlock = nextBlock;
978 }
979 }
980
buzbee5abfa3e2012-01-31 17:01:43 -0800981 if (!(cUnit->disableOpt & (1 << kSkipLargeMethodOptimization))) {
buzbee99ba9642012-01-25 14:23:14 -0800982 if ((cUnit->numBlocks > MANY_BLOCKS) ||
983 ((cUnit->numBlocks > MANY_BLOCKS_INITIALIZER) &&
buzbeefc9e6fa2012-03-23 15:14:29 -0700984 PrettyMethod(method_idx, dex_file, false).find("init>") !=
buzbee99ba9642012-01-25 14:23:14 -0800985 std::string::npos)) {
buzbeea7c12682012-03-19 13:13:53 -0700986 cUnit->qdMode = true;
987 }
988 }
989
990 if (cUnit->qdMode) {
991 cUnit->disableDataflow = true;
992 // Disable optimization which require dataflow/ssa
993 cUnit->disableOpt |=
994 (1 << kNullCheckElimination) |
995 (1 << kBBOpt) |
996 (1 << kPromoteRegs);
997 if (cUnit->printMe) {
998 LOG(INFO) << "QD mode enabled: "
999 << PrettyMethod(method_idx, dex_file)
1000 << " too big: " << cUnit->numBlocks;
buzbee99ba9642012-01-25 14:23:14 -08001001 }
1002 }
1003
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001004 if (cUnit->printMe) {
1005 oatDumpCompilationUnit(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001006 }
1007
buzbee5b537102012-01-17 17:33:47 -08001008 if (cUnit->enableDebug & (1 << kDebugVerifyDataflow)) {
1009 /* Verify if all blocks are connected as claimed */
buzbee5abfa3e2012-01-31 17:01:43 -08001010 oatDataFlowAnalysisDispatcher(cUnit.get(), verifyPredInfo, kAllNodes,
1011 false /* isIterative */);
buzbee5b537102012-01-17 17:33:47 -08001012 }
buzbee67bf8852011-08-17 17:51:35 -07001013
1014 /* Perform SSA transformation for the whole method */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001015 oatMethodSSATransformation(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001016
buzbee239c4e72012-03-16 08:42:29 -07001017 /* Detect loops */
1018 oatMethodLoopDetection(cUnit.get());
1019
1020 /* Count uses */
1021 oatMethodUseCount(cUnit.get());
1022
buzbee43a36422011-09-14 14:00:13 -07001023 /* Perform null check elimination */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001024 oatMethodNullCheckElimination(cUnit.get());
buzbee43a36422011-09-14 14:00:13 -07001025
buzbeee1965672012-03-11 18:39:19 -07001026 /* Do some basic block optimizations */
1027 oatMethodBasicBlockOptimization(cUnit.get());
buzbeee1965672012-03-11 18:39:19 -07001028
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001029 oatInitializeRegAlloc(cUnit.get()); // Needs to happen after SSA naming
buzbee67bf8852011-08-17 17:51:35 -07001030
1031 /* Allocate Registers using simple local allocation scheme */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001032 oatSimpleRegAlloc(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001033
buzbee16da88c2012-03-20 10:38:17 -07001034 if (specialCase != kNoHandler) {
1035 /*
1036 * Custom codegen for special cases. If for any reason the
1037 * special codegen doesn't success, cUnit->firstLIRInsn will
1038 * set to NULL;
1039 */
1040 oatSpecialMIR2LIR(cUnit.get(), specialCase);
1041 }
1042
buzbee67bf8852011-08-17 17:51:35 -07001043 /* Convert MIR to LIR, etc. */
buzbee16da88c2012-03-20 10:38:17 -07001044 if (cUnit->firstLIRInsn == NULL) {
1045 oatMethodMIR2LIR(cUnit.get());
1046 }
buzbee67bf8852011-08-17 17:51:35 -07001047
1048 // Debugging only
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001049 if (cUnit->enableDebug & (1 << kDebugDumpCFG)) {
1050 oatDumpCFG(cUnit.get(), "/sdcard/cfg/");
buzbeeec5adf32011-09-11 15:25:43 -07001051 }
buzbee67bf8852011-08-17 17:51:35 -07001052
1053 /* Method is not empty */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001054 if (cUnit->firstLIRInsn) {
buzbee67bf8852011-08-17 17:51:35 -07001055
1056 // mark the targets of switch statement case labels
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001057 oatProcessSwitchTables(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001058
1059 /* Convert LIR into machine code. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001060 oatAssembleLIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001061
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001062 if (cUnit->printMe) {
1063 oatCodegenDump(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001064 }
buzbeea7c12682012-03-19 13:13:53 -07001065
1066 if (cUnit->opcodeCount != NULL) {
1067 LOG(INFO) << "Opcode Count";
1068 for (int i = 0; i < kNumPackedOpcodes; i++) {
1069 if (cUnit->opcodeCount[i] != 0) {
1070 LOG(INFO) << "-C- "
1071 <<Instruction::Name(static_cast<Instruction::Code>(i))
1072 << " " << cUnit->opcodeCount[i];
1073 }
1074 }
1075 }
buzbee67bf8852011-08-17 17:51:35 -07001076 }
1077
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001078 // Combine vmap tables - core regs, then fp regs - into vmapTable
1079 std::vector<uint16_t> vmapTable;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001080 for (size_t i = 0 ; i < cUnit->coreVmapTable.size(); i++) {
1081 vmapTable.push_back(cUnit->coreVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001082 }
buzbee16da88c2012-03-20 10:38:17 -07001083 // If we have a frame, push a marker to take place of lr
1084 if (cUnit->frameSize > 0) {
1085 vmapTable.push_back(INVALID_VREG);
1086 } else {
1087 DCHECK_EQ(__builtin_popcount(cUnit->coreSpillMask), 0);
1088 DCHECK_EQ(__builtin_popcount(cUnit->fpSpillMask), 0);
1089 }
buzbeec41e5b52011-09-23 12:46:19 -07001090 // Combine vmap tables - core regs, then fp regs
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001091 for (uint32_t i = 0; i < cUnit->fpVmapTable.size(); i++) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001092 vmapTable.push_back(cUnit->fpVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001093 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001094 CompiledMethod* result = new CompiledMethod(cUnit->instructionSet, cUnit->codeBuffer,
Ian Rogers0571d352011-11-03 19:51:38 -07001095 cUnit->frameSize, cUnit->coreSpillMask,
1096 cUnit->fpSpillMask, cUnit->mappingTable,
1097 vmapTable);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001098
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -08001099 VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file)
buzbee5abfa3e2012-01-31 17:01:43 -08001100 << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0]))
1101 << " bytes)";
1102
1103#ifdef WITH_MEMSTATS
1104 if (cUnit->enableDebug & (1 << kDebugShowMemoryUsage)) {
1105 oatDumpMemStats(cUnit.get());
1106 }
1107#endif
buzbee67bf8852011-08-17 17:51:35 -07001108
buzbeeba938cb2012-02-03 14:47:55 -08001109 oatArenaReset(cUnit.get());
1110
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001111 return result;
buzbee67bf8852011-08-17 17:51:35 -07001112}
1113
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001114} // namespace art
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001115
Elliott Hughes3fa1b7e2012-03-13 17:06:22 -07001116extern "C" art::CompiledMethod* ArtCompileMethod(art::Compiler& compiler,
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001117 const art::DexFile::CodeItem* code_item,
1118 uint32_t access_flags, uint32_t method_idx,
1119 const art::ClassLoader* class_loader,
1120 const art::DexFile& dex_file)
1121{
1122 CHECK_EQ(compiler.GetInstructionSet(), art::oatInstructionSet());
Elliott Hughes3fa1b7e2012-03-13 17:06:22 -07001123 return art::oatCompileMethod(compiler, code_item, access_flags, method_idx, class_loader, dex_file);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001124}