blob: 651087ff1cf12b39d5a06a88cfe30c4686b1255a [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Dalvik.h"
18#include "CompilerInternals.h"
19#include "Dataflow.h"
buzbeec143c552011-08-20 17:38:58 -070020#include "constants.h"
Ian Rogers0571d352011-11-03 19:51:38 -070021#include "leb128.h"
Brian Carlstrom9baa4ae2011-09-01 21:14:14 -070022#include "object.h"
Brian Carlstrom1f870082011-08-23 16:02:11 -070023#include "runtime.h"
buzbee67bf8852011-08-17 17:51:35 -070024
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080025namespace art {
26
buzbeece302932011-10-04 14:32:18 -070027/* Default optimizer/debug setting for the compiler. */
28uint32_t compilerOptimizerDisableFlags = 0 | // Disable specific optimizations
buzbee67bc2362011-10-11 18:08:40 -070029 //(1 << kLoadStoreElimination) |
30 //(1 << kLoadHoisting) |
31 //(1 << kSuppressLoads) |
32 //(1 << kNullCheckElimination) |
buzbee769fde12012-01-05 17:35:23 -080033 //(1 << kPromoteRegs) |
34 //(1 << kTrackLiveTemps) |
buzbee99ba9642012-01-25 14:23:14 -080035 //(1 << kSkipLargeMethodOptimization) |
buzbee86a4bce2012-03-06 18:15:00 -080036 //(1 << kSafeOptimizations) |
buzbee239c4e72012-03-16 08:42:29 -070037 //(1 << kBBOpt) |
buzbee16da88c2012-03-20 10:38:17 -070038 //(1 << kMatch) |
buzbee9c044ce2012-03-18 13:24:07 -070039 //(1 << kPromoteCompilerTemps) |
buzbeece302932011-10-04 14:32:18 -070040 0;
41
42uint32_t compilerDebugFlags = 0 | // Enable debug/testing modes
buzbeee3de7492011-10-05 13:37:17 -070043 //(1 << kDebugDisplayMissingTargets) |
buzbeece302932011-10-04 14:32:18 -070044 //(1 << kDebugVerbose) |
45 //(1 << kDebugDumpCFG) |
46 //(1 << kDebugSlowFieldPath) |
47 //(1 << kDebugSlowInvokePath) |
48 //(1 << kDebugSlowStringPath) |
49 //(1 << kDebugSlowestFieldPath) |
50 //(1 << kDebugSlowestStringPath) |
buzbee34c77ad2012-01-11 13:01:32 -080051 //(1 << kDebugExerciseResolveMethod) |
buzbee5b537102012-01-17 17:33:47 -080052 //(1 << kDebugVerifyDataflow) |
buzbee5abfa3e2012-01-31 17:01:43 -080053 //(1 << kDebugShowMemoryUsage) |
buzbee86a4bce2012-03-06 18:15:00 -080054 //(1 << kDebugShowNops) |
buzbeea7c12682012-03-19 13:13:53 -070055 //(1 << kDebugCountOpcodes) |
buzbeece302932011-10-04 14:32:18 -070056 0;
57
buzbee31a4a6f2012-02-28 15:36:15 -080058inline bool contentIsInsn(const u2* codePtr) {
buzbee67bf8852011-08-17 17:51:35 -070059 u2 instr = *codePtr;
Elliott Hughesadb8c672012-03-06 16:49:32 -080060 Instruction::Code opcode = (Instruction::Code)(instr & 0xff);
buzbee67bf8852011-08-17 17:51:35 -070061
62 /*
Elliott Hughesadb8c672012-03-06 16:49:32 -080063 * Since the low 8-bit in metadata may look like NOP, we need to check
buzbee67bf8852011-08-17 17:51:35 -070064 * both the low and whole sub-word to determine whether it is code or data.
65 */
Elliott Hughesadb8c672012-03-06 16:49:32 -080066 return (opcode != Instruction::NOP || instr == 0);
buzbee67bf8852011-08-17 17:51:35 -070067}
68
69/*
70 * Parse an instruction, return the length of the instruction
71 */
buzbee31a4a6f2012-02-28 15:36:15 -080072inline int parseInsn(CompilationUnit* cUnit, const u2* codePtr,
Elliott Hughesadb8c672012-03-06 16:49:32 -080073 DecodedInstruction* decoded_instruction, bool printMe)
buzbee67bf8852011-08-17 17:51:35 -070074{
Elliott Hughesadb8c672012-03-06 16:49:32 -080075 // Don't parse instruction data
76 if (!contentIsInsn(codePtr)) {
77 return 0;
78 }
buzbee67bf8852011-08-17 17:51:35 -070079
Elliott Hughesadb8c672012-03-06 16:49:32 -080080 const Instruction* instruction = Instruction::At(codePtr);
81 *decoded_instruction = DecodedInstruction(instruction);
buzbee67bf8852011-08-17 17:51:35 -070082
Elliott Hughesadb8c672012-03-06 16:49:32 -080083 if (printMe) {
84 char* decodedString = oatGetDalvikDisassembly(cUnit, *decoded_instruction, NULL);
85 LOG(INFO) << codePtr << ": 0x" << std::hex << static_cast<int>(decoded_instruction->opcode)
86 << " " << decodedString;
87 }
88 return instruction->SizeInCodeUnits();
buzbee67bf8852011-08-17 17:51:35 -070089}
90
91#define UNKNOWN_TARGET 0xffffffff
92
Elliott Hughesadb8c672012-03-06 16:49:32 -080093inline bool isGoto(MIR* insn) {
94 switch (insn->dalvikInsn.opcode) {
95 case Instruction::GOTO:
96 case Instruction::GOTO_16:
97 case Instruction::GOTO_32:
98 return true;
99 default:
100 return false;
buzbee67bf8852011-08-17 17:51:35 -0700101 }
102}
103
104/*
105 * Identify unconditional branch instructions
106 */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800107inline bool isUnconditionalBranch(MIR* insn) {
108 switch (insn->dalvikInsn.opcode) {
109 case Instruction::RETURN_VOID:
110 case Instruction::RETURN:
111 case Instruction::RETURN_WIDE:
112 case Instruction::RETURN_OBJECT:
113 return true;
114 default:
115 return isGoto(insn);
116 }
buzbee67bf8852011-08-17 17:51:35 -0700117}
118
119/* Split an existing block from the specified code offset into two */
buzbee31a4a6f2012-02-28 15:36:15 -0800120BasicBlock *splitBlock(CompilationUnit* cUnit, unsigned int codeOffset,
121 BasicBlock* origBlock, BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700122{
123 MIR* insn = origBlock->firstMIRInsn;
124 while (insn) {
125 if (insn->offset == codeOffset) break;
126 insn = insn->next;
127 }
128 if (insn == NULL) {
129 LOG(FATAL) << "Break split failed";
130 }
buzbee5abfa3e2012-01-31 17:01:43 -0800131 BasicBlock *bottomBlock = oatNewBB(cUnit, kDalvikByteCode,
132 cUnit->numBlocks++);
buzbeeba938cb2012-02-03 14:47:55 -0800133 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700134
135 bottomBlock->startOffset = codeOffset;
136 bottomBlock->firstMIRInsn = insn;
137 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
138
buzbee5b537102012-01-17 17:33:47 -0800139 /* Add it to the quick lookup cache */
140 cUnit->blockMap.insert(std::make_pair(bottomBlock->startOffset,
141 bottomBlock));
142
buzbee67bf8852011-08-17 17:51:35 -0700143 /* Handle the taken path */
144 bottomBlock->taken = origBlock->taken;
145 if (bottomBlock->taken) {
146 origBlock->taken = NULL;
buzbee5abfa3e2012-01-31 17:01:43 -0800147 oatDeleteGrowableList(bottomBlock->taken->predecessors,
148 (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800149 oatInsertGrowableList(cUnit, bottomBlock->taken->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800150 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700151 }
152
153 /* Handle the fallthrough path */
154 bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
155 bottomBlock->fallThrough = origBlock->fallThrough;
156 origBlock->fallThrough = bottomBlock;
157 origBlock->needFallThroughBranch = true;
buzbeeba938cb2012-02-03 14:47:55 -0800158 oatInsertGrowableList(cUnit, bottomBlock->predecessors,
159 (intptr_t)origBlock);
buzbee67bf8852011-08-17 17:51:35 -0700160 if (bottomBlock->fallThrough) {
buzbee5abfa3e2012-01-31 17:01:43 -0800161 oatDeleteGrowableList(bottomBlock->fallThrough->predecessors,
162 (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800163 oatInsertGrowableList(cUnit, bottomBlock->fallThrough->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800164 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700165 }
166
167 /* Handle the successor list */
168 if (origBlock->successorBlockList.blockListType != kNotUsed) {
169 bottomBlock->successorBlockList = origBlock->successorBlockList;
170 origBlock->successorBlockList.blockListType = kNotUsed;
171 GrowableListIterator iterator;
172
173 oatGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
174 &iterator);
175 while (true) {
176 SuccessorBlockInfo *successorBlockInfo =
177 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
178 if (successorBlockInfo == NULL) break;
179 BasicBlock *bb = successorBlockInfo->block;
buzbee5abfa3e2012-01-31 17:01:43 -0800180 oatDeleteGrowableList(bb->predecessors, (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800181 oatInsertGrowableList(cUnit, bb->predecessors,
182 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700183 }
184 }
185
186 origBlock->lastMIRInsn = insn->prev;
187
188 insn->prev->next = NULL;
189 insn->prev = NULL;
buzbee9ab05de2012-01-18 15:43:48 -0800190 /*
191 * Update the immediate predecessor block pointer so that outgoing edges
192 * can be applied to the proper block.
193 */
194 if (immedPredBlockP) {
195 DCHECK_EQ(*immedPredBlockP, origBlock);
196 *immedPredBlockP = bottomBlock;
197 }
buzbee67bf8852011-08-17 17:51:35 -0700198 return bottomBlock;
199}
200
201/*
202 * Given a code offset, find out the block that starts with it. If the offset
buzbee9ab05de2012-01-18 15:43:48 -0800203 * is in the middle of an existing block, split it into two. If immedPredBlockP
204 * is not non-null and is the block being split, update *immedPredBlockP to
205 * point to the bottom block so that outgoing edges can be set up properly
206 * (by the caller)
buzbee5b537102012-01-17 17:33:47 -0800207 * Utilizes a map for fast lookup of the typical cases.
buzbee67bf8852011-08-17 17:51:35 -0700208 */
buzbee31a4a6f2012-02-28 15:36:15 -0800209BasicBlock *findBlock(CompilationUnit* cUnit, unsigned int codeOffset,
210 bool split, bool create, BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700211{
212 GrowableList* blockList = &cUnit->blockList;
213 BasicBlock* bb;
214 unsigned int i;
buzbee5b537102012-01-17 17:33:47 -0800215 std::map<unsigned int, BasicBlock*>::iterator it;
buzbee67bf8852011-08-17 17:51:35 -0700216
buzbee5b537102012-01-17 17:33:47 -0800217 it = cUnit->blockMap.find(codeOffset);
218 if (it != cUnit->blockMap.end()) {
219 return it->second;
220 } else if (!create) {
221 return NULL;
222 }
223
224 if (split) {
225 for (i = 0; i < blockList->numUsed; i++) {
226 bb = (BasicBlock *) blockList->elemList[i];
227 if (bb->blockType != kDalvikByteCode) continue;
228 /* Check if a branch jumps into the middle of an existing block */
229 if ((codeOffset > bb->startOffset) && (bb->lastMIRInsn != NULL) &&
230 (codeOffset <= bb->lastMIRInsn->offset)) {
231 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb,
232 bb == *immedPredBlockP ?
233 immedPredBlockP : NULL);
234 return newBB;
235 }
buzbee67bf8852011-08-17 17:51:35 -0700236 }
237 }
buzbee5b537102012-01-17 17:33:47 -0800238
239 /* Create a new one */
buzbee5abfa3e2012-01-31 17:01:43 -0800240 bb = oatNewBB(cUnit, kDalvikByteCode, cUnit->numBlocks++);
buzbeeba938cb2012-02-03 14:47:55 -0800241 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) bb);
buzbee5b537102012-01-17 17:33:47 -0800242 bb->startOffset = codeOffset;
243 cUnit->blockMap.insert(std::make_pair(bb->startOffset, bb));
244 return bb;
buzbee67bf8852011-08-17 17:51:35 -0700245}
246
247/* Dump the CFG into a DOT graph */
248void oatDumpCFG(CompilationUnit* cUnit, const char* dirPrefix)
249{
buzbee67bf8852011-08-17 17:51:35 -0700250 FILE* file;
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800251 std::string name(PrettyMethod(cUnit->method_idx, *cUnit->dex_file));
buzbee67bf8852011-08-17 17:51:35 -0700252 char startOffset[80];
253 sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
buzbeeba938cb2012-02-03 14:47:55 -0800254 char* fileName = (char*) oatNew(cUnit,
buzbeec143c552011-08-20 17:38:58 -0700255 strlen(dirPrefix) +
256 name.length() +
buzbee5abfa3e2012-01-31 17:01:43 -0800257 strlen(".dot") + 1, true, kAllocDebugInfo);
buzbeec143c552011-08-20 17:38:58 -0700258 sprintf(fileName, "%s%s%s.dot", dirPrefix, name.c_str(), startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700259
260 /*
261 * Convert the special characters into a filesystem- and shell-friendly
262 * format.
263 */
264 int i;
265 for (i = strlen(dirPrefix); fileName[i]; i++) {
266 if (fileName[i] == '/') {
267 fileName[i] = '_';
268 } else if (fileName[i] == ';') {
269 fileName[i] = '#';
270 } else if (fileName[i] == '$') {
271 fileName[i] = '+';
272 } else if (fileName[i] == '(' || fileName[i] == ')') {
273 fileName[i] = '@';
274 } else if (fileName[i] == '<' || fileName[i] == '>') {
275 fileName[i] = '=';
276 }
277 }
278 file = fopen(fileName, "w");
279 if (file == NULL) {
280 return;
281 }
282 fprintf(file, "digraph G {\n");
283
284 fprintf(file, " rankdir=TB\n");
285
286 int numReachableBlocks = cUnit->numReachableBlocks;
287 int idx;
288 const GrowableList *blockList = &cUnit->blockList;
289
290 for (idx = 0; idx < numReachableBlocks; idx++) {
291 int blockIdx = cUnit->dfsOrder.elemList[idx];
292 BasicBlock *bb = (BasicBlock *) oatGrowableListGetElement(blockList,
293 blockIdx);
294 if (bb == NULL) break;
295 if (bb->blockType == kEntryBlock) {
296 fprintf(file, " entry [shape=Mdiamond];\n");
297 } else if (bb->blockType == kExitBlock) {
298 fprintf(file, " exit [shape=Mdiamond];\n");
299 } else if (bb->blockType == kDalvikByteCode) {
300 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
301 bb->startOffset);
302 const MIR *mir;
303 fprintf(file, " {block id %d\\l}%s\\\n", bb->id,
304 bb->firstMIRInsn ? " | " : " ");
305 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
306 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
Elliott Hughesadb8c672012-03-06 16:49:32 -0800307 mir->ssaRep ? oatFullDisassembler(cUnit, mir) : Instruction::Name(mir->dalvikInsn.opcode),
buzbee67bf8852011-08-17 17:51:35 -0700308 mir->next ? " | " : " ");
309 }
310 fprintf(file, " }\"];\n\n");
311 } else if (bb->blockType == kExceptionHandling) {
312 char blockName[BLOCK_NAME_LEN];
313
314 oatGetBlockName(bb, blockName);
315 fprintf(file, " %s [shape=invhouse];\n", blockName);
316 }
317
318 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
319
320 if (bb->taken) {
321 oatGetBlockName(bb, blockName1);
322 oatGetBlockName(bb->taken, blockName2);
323 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
324 blockName1, blockName2);
325 }
326 if (bb->fallThrough) {
327 oatGetBlockName(bb, blockName1);
328 oatGetBlockName(bb->fallThrough, blockName2);
329 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
330 }
331
332 if (bb->successorBlockList.blockListType != kNotUsed) {
333 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
334 bb->startOffset,
335 (bb->successorBlockList.blockListType == kCatch) ?
336 "Mrecord" : "record");
337 GrowableListIterator iterator;
338 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
339 &iterator);
340 SuccessorBlockInfo *successorBlockInfo =
341 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
342
343 int succId = 0;
344 while (true) {
345 if (successorBlockInfo == NULL) break;
346
347 BasicBlock *destBlock = successorBlockInfo->block;
348 SuccessorBlockInfo *nextSuccessorBlockInfo =
349 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
350
351 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
352 succId++,
353 successorBlockInfo->key,
354 destBlock->startOffset,
355 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
356
357 successorBlockInfo = nextSuccessorBlockInfo;
358 }
359 fprintf(file, " }\"];\n\n");
360
361 oatGetBlockName(bb, blockName1);
362 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
363 blockName1, bb->startOffset);
364
365 if (bb->successorBlockList.blockListType == kPackedSwitch ||
366 bb->successorBlockList.blockListType == kSparseSwitch) {
367
368 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
369 &iterator);
370
371 succId = 0;
372 while (true) {
373 SuccessorBlockInfo *successorBlockInfo =
374 (SuccessorBlockInfo *)
375 oatGrowableListIteratorNext(&iterator);
376 if (successorBlockInfo == NULL) break;
377
378 BasicBlock *destBlock = successorBlockInfo->block;
379
380 oatGetBlockName(destBlock, blockName2);
381 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
382 bb->startOffset, succId++,
383 blockName2);
384 }
385 }
386 }
387 fprintf(file, "\n");
388
buzbeece302932011-10-04 14:32:18 -0700389 /* Display the dominator tree */
buzbee67bf8852011-08-17 17:51:35 -0700390 oatGetBlockName(bb, blockName1);
391 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
392 blockName1, blockName1);
393 if (bb->iDom) {
394 oatGetBlockName(bb->iDom, blockName2);
395 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
396 blockName2, blockName1);
397 }
buzbee67bf8852011-08-17 17:51:35 -0700398 }
399 fprintf(file, "}\n");
400 fclose(file);
401}
402
403/* Verify if all the successor is connected with all the claimed predecessors */
buzbee31a4a6f2012-02-28 15:36:15 -0800404bool verifyPredInfo(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -0700405{
buzbee5abfa3e2012-01-31 17:01:43 -0800406 GrowableListIterator iter;
buzbee67bf8852011-08-17 17:51:35 -0700407
buzbee5abfa3e2012-01-31 17:01:43 -0800408 oatGrowableListIteratorInit(bb->predecessors, &iter);
buzbee67bf8852011-08-17 17:51:35 -0700409 while (true) {
buzbee5abfa3e2012-01-31 17:01:43 -0800410 BasicBlock *predBB = (BasicBlock*)oatGrowableListIteratorNext(&iter);
411 if (!predBB) break;
buzbee67bf8852011-08-17 17:51:35 -0700412 bool found = false;
413 if (predBB->taken == bb) {
414 found = true;
415 } else if (predBB->fallThrough == bb) {
416 found = true;
417 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
418 GrowableListIterator iterator;
419 oatGrowableListIteratorInit(&predBB->successorBlockList.blocks,
420 &iterator);
421 while (true) {
422 SuccessorBlockInfo *successorBlockInfo =
423 (SuccessorBlockInfo *)
424 oatGrowableListIteratorNext(&iterator);
425 if (successorBlockInfo == NULL) break;
426 BasicBlock *succBB = successorBlockInfo->block;
427 if (succBB == bb) {
428 found = true;
429 break;
430 }
431 }
432 }
433 if (found == false) {
434 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
435 oatGetBlockName(bb, blockName1);
436 oatGetBlockName(predBB, blockName2);
437 oatDumpCFG(cUnit, "/sdcard/cfg/");
438 LOG(FATAL) << "Successor " << blockName1 << "not found from "
439 << blockName2;
440 }
441 }
442 return true;
443}
444
445/* Identify code range in try blocks and set up the empty catch blocks */
buzbee31a4a6f2012-02-28 15:36:15 -0800446void processTryCatchBlocks(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700447{
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800448 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbeee9a72f62011-09-04 17:59:07 -0700449 int triesSize = code_item->tries_size_;
buzbee67bf8852011-08-17 17:51:35 -0700450 int offset;
451
452 if (triesSize == 0) {
453 return;
454 }
455
buzbee67bf8852011-08-17 17:51:35 -0700456 ArenaBitVector* tryBlockAddr = cUnit->tryBlockAddr;
457
buzbeee9a72f62011-09-04 17:59:07 -0700458 for (int i = 0; i < triesSize; i++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800459 const DexFile::TryItem* pTry =
460 DexFile::GetTryItems(*code_item, i);
buzbeee9a72f62011-09-04 17:59:07 -0700461 int startOffset = pTry->start_addr_;
462 int endOffset = startOffset + pTry->insn_count_;
buzbee67bf8852011-08-17 17:51:35 -0700463 for (offset = startOffset; offset < endOffset; offset++) {
buzbeeba938cb2012-02-03 14:47:55 -0800464 oatSetBit(cUnit, tryBlockAddr, offset);
buzbee67bf8852011-08-17 17:51:35 -0700465 }
466 }
467
buzbeee9a72f62011-09-04 17:59:07 -0700468 // Iterate over each of the handlers to enqueue the empty Catch blocks
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800469 const byte* handlers_ptr =
470 DexFile::GetCatchHandlerData(*code_item, 0);
471 uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
buzbeee9a72f62011-09-04 17:59:07 -0700472 for (uint32_t idx = 0; idx < handlers_size; idx++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800473 CatchHandlerIterator iterator(handlers_ptr);
Ian Rogers0571d352011-11-03 19:51:38 -0700474 for (; iterator.HasNext(); iterator.Next()) {
475 uint32_t address = iterator.GetHandlerAddress();
buzbee9ab05de2012-01-18 15:43:48 -0800476 findBlock(cUnit, address, false /* split */, true /*create*/,
477 /* immedPredBlockP */ NULL);
buzbee67bf8852011-08-17 17:51:35 -0700478 }
Ian Rogers0571d352011-11-03 19:51:38 -0700479 handlers_ptr = iterator.EndDataPointer();
buzbee67bf8852011-08-17 17:51:35 -0700480 }
481}
482
Elliott Hughesadb8c672012-03-06 16:49:32 -0800483/* Process instructions with the kBranch flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800484BasicBlock* processCanBranch(CompilationUnit* cUnit, BasicBlock* curBlock,
485 MIR* insn, int curOffset, int width, int flags,
486 const u2* codePtr, const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700487{
488 int target = curOffset;
489 switch (insn->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800490 case Instruction::GOTO:
491 case Instruction::GOTO_16:
492 case Instruction::GOTO_32:
buzbee67bf8852011-08-17 17:51:35 -0700493 target += (int) insn->dalvikInsn.vA;
494 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800495 case Instruction::IF_EQ:
496 case Instruction::IF_NE:
497 case Instruction::IF_LT:
498 case Instruction::IF_GE:
499 case Instruction::IF_GT:
500 case Instruction::IF_LE:
buzbee67bf8852011-08-17 17:51:35 -0700501 target += (int) insn->dalvikInsn.vC;
502 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800503 case Instruction::IF_EQZ:
504 case Instruction::IF_NEZ:
505 case Instruction::IF_LTZ:
506 case Instruction::IF_GEZ:
507 case Instruction::IF_GTZ:
508 case Instruction::IF_LEZ:
buzbee67bf8852011-08-17 17:51:35 -0700509 target += (int) insn->dalvikInsn.vB;
510 break;
511 default:
512 LOG(FATAL) << "Unexpected opcode(" << (int)insn->dalvikInsn.opcode
Elliott Hughesadb8c672012-03-06 16:49:32 -0800513 << ") with kBranch set";
buzbee67bf8852011-08-17 17:51:35 -0700514 }
515 BasicBlock *takenBlock = findBlock(cUnit, target,
516 /* split */
517 true,
518 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800519 true,
520 /* immedPredBlockP */
521 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700522 curBlock->taken = takenBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800523 oatInsertGrowableList(cUnit, takenBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700524
525 /* Always terminate the current block for conditional branches */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800526 if (flags & Instruction::kContinue) {
buzbee67bf8852011-08-17 17:51:35 -0700527 BasicBlock *fallthroughBlock = findBlock(cUnit,
528 curOffset + width,
529 /*
530 * If the method is processed
531 * in sequential order from the
532 * beginning, we don't need to
533 * specify split for continue
534 * blocks. However, this
535 * routine can be called by
536 * compileLoop, which starts
537 * parsing the method from an
538 * arbitrary address in the
539 * method body.
540 */
541 true,
542 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800543 true,
544 /* immedPredBlockP */
545 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700546 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800547 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800548 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700549 } else if (codePtr < codeEnd) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800550 /* Create a fallthrough block for real instructions (incl. NOP) */
buzbee67bf8852011-08-17 17:51:35 -0700551 if (contentIsInsn(codePtr)) {
552 findBlock(cUnit, curOffset + width,
553 /* split */
554 false,
555 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800556 true,
557 /* immedPredBlockP */
558 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700559 }
560 }
buzbeee941e2c2011-12-05 12:38:17 -0800561 return curBlock;
buzbee67bf8852011-08-17 17:51:35 -0700562}
563
Elliott Hughesadb8c672012-03-06 16:49:32 -0800564/* Process instructions with the kSwitch flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800565void processCanSwitch(CompilationUnit* cUnit, BasicBlock* curBlock,
566 MIR* insn, int curOffset, int width, int flags)
buzbee67bf8852011-08-17 17:51:35 -0700567{
568 u2* switchData= (u2 *) (cUnit->insns + curOffset +
569 insn->dalvikInsn.vB);
570 int size;
571 int* keyTable;
572 int* targetTable;
573 int i;
574 int firstKey;
575
576 /*
577 * Packed switch data format:
578 * ushort ident = 0x0100 magic value
579 * ushort size number of entries in the table
580 * int first_key first (and lowest) switch case value
581 * int targets[size] branch targets, relative to switch opcode
582 *
583 * Total size is (4+size*2) 16-bit code units.
584 */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800585 if (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) {
586 DCHECK_EQ(static_cast<int>(switchData[0]), static_cast<int>(Instruction::kPackedSwitchSignature));
buzbee67bf8852011-08-17 17:51:35 -0700587 size = switchData[1];
588 firstKey = switchData[2] | (switchData[3] << 16);
589 targetTable = (int *) &switchData[4];
590 keyTable = NULL; // Make the compiler happy
591 /*
592 * Sparse switch data format:
593 * ushort ident = 0x0200 magic value
594 * ushort size number of entries in the table; > 0
595 * int keys[size] keys, sorted low-to-high; 32-bit aligned
596 * int targets[size] branch targets, relative to switch opcode
597 *
598 * Total size is (2+size*4) 16-bit code units.
599 */
600 } else {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800601 DCHECK_EQ(static_cast<int>(switchData[0]), static_cast<int>(Instruction::kSparseSwitchSignature));
buzbee67bf8852011-08-17 17:51:35 -0700602 size = switchData[1];
603 keyTable = (int *) &switchData[2];
604 targetTable = (int *) &switchData[2 + size*2];
605 firstKey = 0; // To make the compiler happy
606 }
607
608 if (curBlock->successorBlockList.blockListType != kNotUsed) {
609 LOG(FATAL) << "Successor block list already in use: " <<
610 (int)curBlock->successorBlockList.blockListType;
611 }
612 curBlock->successorBlockList.blockListType =
Elliott Hughesadb8c672012-03-06 16:49:32 -0800613 (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) ?
buzbee67bf8852011-08-17 17:51:35 -0700614 kPackedSwitch : kSparseSwitch;
buzbeeba938cb2012-02-03 14:47:55 -0800615 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, size,
buzbee5abfa3e2012-01-31 17:01:43 -0800616 kListSuccessorBlocks);
buzbee67bf8852011-08-17 17:51:35 -0700617
618 for (i = 0; i < size; i++) {
619 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
620 /* split */
621 true,
622 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800623 true,
624 /* immedPredBlockP */
625 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700626 SuccessorBlockInfo *successorBlockInfo =
buzbeeba938cb2012-02-03 14:47:55 -0800627 (SuccessorBlockInfo *) oatNew(cUnit, sizeof(SuccessorBlockInfo),
628 false, kAllocSuccessor);
buzbee67bf8852011-08-17 17:51:35 -0700629 successorBlockInfo->block = caseBlock;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800630 successorBlockInfo->key = (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH)?
buzbee67bf8852011-08-17 17:51:35 -0700631 firstKey + i : keyTable[i];
buzbeeba938cb2012-02-03 14:47:55 -0800632 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
buzbee67bf8852011-08-17 17:51:35 -0700633 (intptr_t) successorBlockInfo);
buzbeeba938cb2012-02-03 14:47:55 -0800634 oatInsertGrowableList(cUnit, caseBlock->predecessors,
635 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700636 }
637
638 /* Fall-through case */
639 BasicBlock* fallthroughBlock = findBlock(cUnit,
640 curOffset + width,
641 /* split */
642 false,
643 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800644 true,
645 /* immedPredBlockP */
646 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700647 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800648 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
649 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700650}
651
Elliott Hughesadb8c672012-03-06 16:49:32 -0800652/* Process instructions with the kThrow flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800653void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock, MIR* insn,
654 int curOffset, int width, int flags,
655 ArenaBitVector* tryBlockAddr, const u2* codePtr,
656 const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700657{
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800658 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbee67bf8852011-08-17 17:51:35 -0700659
660 /* In try block */
661 if (oatIsBitSet(tryBlockAddr, curOffset)) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800662 CatchHandlerIterator iterator(*code_item, curOffset);
buzbee67bf8852011-08-17 17:51:35 -0700663
buzbee67bf8852011-08-17 17:51:35 -0700664 if (curBlock->successorBlockList.blockListType != kNotUsed) {
665 LOG(FATAL) << "Successor block list already in use: " <<
666 (int)curBlock->successorBlockList.blockListType;
667 }
buzbeee9a72f62011-09-04 17:59:07 -0700668
buzbee67bf8852011-08-17 17:51:35 -0700669 curBlock->successorBlockList.blockListType = kCatch;
buzbeeba938cb2012-02-03 14:47:55 -0800670 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, 2,
buzbee5abfa3e2012-01-31 17:01:43 -0800671 kListSuccessorBlocks);
buzbee67bf8852011-08-17 17:51:35 -0700672
Ian Rogers0571d352011-11-03 19:51:38 -0700673 for (;iterator.HasNext(); iterator.Next()) {
674 BasicBlock *catchBlock = findBlock(cUnit, iterator.GetHandlerAddress(),
buzbeee9a72f62011-09-04 17:59:07 -0700675 false /* split*/,
buzbee9ab05de2012-01-18 15:43:48 -0800676 false /* creat */,
677 NULL /* immedPredBlockP */);
buzbee43a36422011-09-14 14:00:13 -0700678 catchBlock->catchEntry = true;
buzbeeba938cb2012-02-03 14:47:55 -0800679 SuccessorBlockInfo *successorBlockInfo = (SuccessorBlockInfo *)
680 oatNew(cUnit, sizeof(SuccessorBlockInfo), false,
681 kAllocSuccessor);
buzbee67bf8852011-08-17 17:51:35 -0700682 successorBlockInfo->block = catchBlock;
Ian Rogers0571d352011-11-03 19:51:38 -0700683 successorBlockInfo->key = iterator.GetHandlerTypeIndex();
buzbeeba938cb2012-02-03 14:47:55 -0800684 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
buzbee67bf8852011-08-17 17:51:35 -0700685 (intptr_t) successorBlockInfo);
buzbeeba938cb2012-02-03 14:47:55 -0800686 oatInsertGrowableList(cUnit, catchBlock->predecessors,
687 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700688 }
689 } else {
buzbee5abfa3e2012-01-31 17:01:43 -0800690 BasicBlock *ehBlock = oatNewBB(cUnit, kExceptionHandling,
691 cUnit->numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700692 curBlock->taken = ehBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800693 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) ehBlock);
buzbee67bf8852011-08-17 17:51:35 -0700694 ehBlock->startOffset = curOffset;
buzbeeba938cb2012-02-03 14:47:55 -0800695 oatInsertGrowableList(cUnit, ehBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700696 }
697
698 /*
699 * Force the current block to terminate.
700 *
701 * Data may be present before codeEnd, so we need to parse it to know
702 * whether it is code or data.
703 */
704 if (codePtr < codeEnd) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800705 /* Create a fallthrough block for real instructions (incl. NOP) */
buzbee67bf8852011-08-17 17:51:35 -0700706 if (contentIsInsn(codePtr)) {
707 BasicBlock *fallthroughBlock = findBlock(cUnit,
708 curOffset + width,
709 /* split */
710 false,
711 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800712 true,
713 /* immedPredBlockP */
714 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700715 /*
Elliott Hughesadb8c672012-03-06 16:49:32 -0800716 * THROW is an unconditional branch. NOTE:
717 * THROW_VERIFICATION_ERROR is also an unconditional
buzbee510c6052011-10-27 10:47:20 -0700718 * branch, but we shouldn't treat it as such until we have
719 * a dead code elimination pass (which won't be important
720 * until inlining w/ constant propogation is implemented.
buzbee67bf8852011-08-17 17:51:35 -0700721 */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800722 if (insn->dalvikInsn.opcode != Instruction::THROW) {
buzbee67bf8852011-08-17 17:51:35 -0700723 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800724 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800725 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700726 }
727 }
728 }
729}
730
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800731void oatInit(CompilationUnit* cUnit, const Compiler& compiler) {
732 if (!oatArchInit()) {
733 LOG(FATAL) << "Failed to initialize oat";
734 }
735 if (!oatHeapInit(cUnit)) {
736 LOG(FATAL) << "Failed to initialize oat heap";
737 }
738}
739
Elliott Hughes3fa1b7e2012-03-13 17:06:22 -0700740CompiledMethod* oatCompileMethod(Compiler& compiler,
741 const DexFile::CodeItem* code_item,
742 uint32_t access_flags, uint32_t method_idx,
743 const ClassLoader* class_loader,
744 const DexFile& dex_file)
buzbee67bf8852011-08-17 17:51:35 -0700745{
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800746 VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
Brian Carlstrom94496d32011-08-22 09:22:47 -0700747
buzbeec143c552011-08-20 17:38:58 -0700748 const u2* codePtr = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700749 const u2* codeEnd = code_item->insns_ + code_item->insns_size_in_code_units_;
buzbee67bf8852011-08-17 17:51:35 -0700750 int numBlocks = 0;
751 unsigned int curOffset = 0;
752
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800753 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700754 UniquePtr<CompilationUnit> cUnit(new CompilationUnit);
755 memset(cUnit.get(), 0, sizeof(*cUnit));
buzbeeba938cb2012-02-03 14:47:55 -0800756
757 oatInit(cUnit.get(), compiler);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800758
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700759 cUnit->compiler = &compiler;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800760 cUnit->class_linker = class_linker;
761 cUnit->dex_file = &dex_file;
762 cUnit->dex_cache = class_linker->FindDexCache(dex_file);
763 cUnit->method_idx = method_idx;
764 cUnit->code_item = code_item;
765 cUnit->access_flags = access_flags;
766 cUnit->shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800767 cUnit->instructionSet = compiler.GetInstructionSet();
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700768 cUnit->insns = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700769 cUnit->insnsSize = code_item->insns_size_in_code_units_;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800770 cUnit->numIns = code_item->ins_size_;
771 cUnit->numRegs = code_item->registers_size_ - cUnit->numIns;
772 cUnit->numOuts = code_item->outs_size_;
773 /* Adjust this value accordingly once inlining is performed */
774 cUnit->numDalvikRegisters = code_item->registers_size_;
buzbee5b537102012-01-17 17:33:47 -0800775 cUnit->blockMap = std::map<unsigned int, BasicBlock*>();
776 cUnit->blockMap.clear();
buzbee85d8c1e2012-01-27 15:52:35 -0800777 cUnit->boundaryMap = std::map<unsigned int, LIR*>();
778 cUnit->boundaryMap.clear();
buzbeeba938cb2012-02-03 14:47:55 -0800779 // TODO: set these from command line
780 cUnit->compilerMethodMatch = new std::string("");
781 cUnit->compilerFlipMatch = false;
782 bool useMatch = cUnit->compilerMethodMatch->length() != 0;
783 bool match = useMatch && (cUnit->compilerFlipMatch ^
784 (PrettyMethod(method_idx, dex_file).find(*cUnit->compilerMethodMatch)
785 != std::string::npos));
buzbeece302932011-10-04 14:32:18 -0700786 if (!useMatch || match) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700787 cUnit->disableOpt = compilerOptimizerDisableFlags;
788 cUnit->enableDebug = compilerDebugFlags;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800789 cUnit->printMe = VLOG_IS_ON(compiler) || (cUnit->enableDebug & (1 << kDebugVerbose));
buzbeece302932011-10-04 14:32:18 -0700790 }
Ian Rogersb3ab25b2012-03-19 01:12:01 -0700791 if (cUnit->instructionSet == kX86) {
792 // Disable optimizations on X86 for now
793 cUnit->disableOpt = -1;
794 }
buzbee44b412b2012-02-04 08:50:53 -0800795 /* Are we generating code for the debugger? */
Elliott Hughesde6e4cf2012-02-27 14:46:06 -0800796 if (compiler.IsDebuggingSupported()) {
buzbee44b412b2012-02-04 08:50:53 -0800797 cUnit->genDebugger = true;
798 // Yes, disable most optimizations
799 cUnit->disableOpt |= (
800 (1 << kLoadStoreElimination) |
801 (1 << kLoadHoisting) |
802 (1 << kSuppressLoads) |
803 (1 << kPromoteRegs) |
buzbeeb37c9992012-03-18 21:28:43 -0700804 (1 << kBBOpt) |
buzbee16da88c2012-03-20 10:38:17 -0700805 (1 << kMatch) |
buzbee44b412b2012-02-04 08:50:53 -0800806 (1 << kTrackLiveTemps));
807 }
808
buzbeea7c12682012-03-19 13:13:53 -0700809 /* Gathering opcode stats? */
810 if (compilerDebugFlags & (1 << kDebugCountOpcodes)) {
811 cUnit->opcodeCount = (int*)oatNew(cUnit.get(),
812 kNumPackedOpcodes * sizeof(int), true, kAllocMisc);
813 }
814
buzbeecefd1872011-09-09 09:59:52 -0700815 /* Assume non-throwing leaf */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700816 cUnit->attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
buzbeecefd1872011-09-09 09:59:52 -0700817
buzbee5abfa3e2012-01-31 17:01:43 -0800818 /* Initialize the block list, estimate size based on insnsSize */
buzbeeba938cb2012-02-03 14:47:55 -0800819 oatInitGrowableList(cUnit.get(), &cUnit->blockList, cUnit->insnsSize,
820 kListBlockList);
buzbee67bf8852011-08-17 17:51:35 -0700821
822 /* Initialize the switchTables list */
buzbeeba938cb2012-02-03 14:47:55 -0800823 oatInitGrowableList(cUnit.get(), &cUnit->switchTables, 4,
824 kListSwitchTables);
buzbee67bf8852011-08-17 17:51:35 -0700825
826 /* Intialize the fillArrayData list */
buzbeeba938cb2012-02-03 14:47:55 -0800827 oatInitGrowableList(cUnit.get(), &cUnit->fillArrayData, 4,
828 kListFillArrayData);
buzbee67bf8852011-08-17 17:51:35 -0700829
buzbee5abfa3e2012-01-31 17:01:43 -0800830 /* Intialize the throwLaunchpads list, estimate size based on insnsSize */
buzbeeba938cb2012-02-03 14:47:55 -0800831 oatInitGrowableList(cUnit.get(), &cUnit->throwLaunchpads, cUnit->insnsSize,
buzbee5abfa3e2012-01-31 17:01:43 -0800832 kListThrowLaunchPads);
buzbee5ade1d22011-09-09 14:44:52 -0700833
buzbeefc9e6fa2012-03-23 15:14:29 -0700834 /* Intialize the instrinsicLaunchpads list */
835 oatInitGrowableList(cUnit.get(), &cUnit->intrinsicLaunchpads, 4,
836 kListMisc);
837
838
buzbeec1f45042011-09-21 16:03:19 -0700839 /* Intialize the suspendLaunchpads list */
buzbeeba938cb2012-02-03 14:47:55 -0800840 oatInitGrowableList(cUnit.get(), &cUnit->suspendLaunchpads, 2048,
buzbee5abfa3e2012-01-31 17:01:43 -0800841 kListSuspendLaunchPads);
buzbeec1f45042011-09-21 16:03:19 -0700842
buzbee67bf8852011-08-17 17:51:35 -0700843 /* Allocate the bit-vector to track the beginning of basic blocks */
buzbeeba938cb2012-02-03 14:47:55 -0800844 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit.get(),
845 cUnit->insnsSize,
buzbee67bf8852011-08-17 17:51:35 -0700846 true /* expandable */);
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700847 cUnit->tryBlockAddr = tryBlockAddr;
buzbee67bf8852011-08-17 17:51:35 -0700848
849 /* Create the default entry and exit blocks and enter them to the list */
buzbee5abfa3e2012-01-31 17:01:43 -0800850 BasicBlock *entryBlock = oatNewBB(cUnit.get(), kEntryBlock, numBlocks++);
851 BasicBlock *exitBlock = oatNewBB(cUnit.get(), kExitBlock, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700852
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700853 cUnit->entryBlock = entryBlock;
854 cUnit->exitBlock = exitBlock;
buzbee67bf8852011-08-17 17:51:35 -0700855
buzbeeba938cb2012-02-03 14:47:55 -0800856 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) entryBlock);
857 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) exitBlock);
buzbee67bf8852011-08-17 17:51:35 -0700858
859 /* Current block to record parsed instructions */
buzbee5abfa3e2012-01-31 17:01:43 -0800860 BasicBlock *curBlock = oatNewBB(cUnit.get(), kDalvikByteCode, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700861 curBlock->startOffset = 0;
buzbeeba938cb2012-02-03 14:47:55 -0800862 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) curBlock);
buzbee5b537102012-01-17 17:33:47 -0800863 /* Add first block to the fast lookup cache */
864 cUnit->blockMap.insert(std::make_pair(curBlock->startOffset, curBlock));
buzbee67bf8852011-08-17 17:51:35 -0700865 entryBlock->fallThrough = curBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800866 oatInsertGrowableList(cUnit.get(), curBlock->predecessors,
867 (intptr_t)entryBlock);
buzbee67bf8852011-08-17 17:51:35 -0700868
869 /*
870 * Store back the number of blocks since new blocks may be created of
871 * accessing cUnit.
872 */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700873 cUnit->numBlocks = numBlocks;
buzbee67bf8852011-08-17 17:51:35 -0700874
875 /* Identify code range in try blocks and set up the empty catch blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700876 processTryCatchBlocks(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700877
buzbee16da88c2012-03-20 10:38:17 -0700878 /* Set up for simple method detection */
879 int numPatterns = sizeof(specialPatterns)/sizeof(specialPatterns[0]);
880 bool livePattern = (numPatterns > 0) && !(cUnit->disableOpt & (1 << kMatch));
881 bool* deadPattern = (bool*)oatNew(cUnit.get(), sizeof(bool) * numPatterns,
882 kAllocMisc);
883 SpecialCaseHandler specialCase = kNoHandler;
884 int patternPos = 0;
885
buzbee67bf8852011-08-17 17:51:35 -0700886 /* Parse all instructions and put them into containing basic blocks */
887 while (codePtr < codeEnd) {
buzbeeba938cb2012-02-03 14:47:55 -0800888 MIR *insn = (MIR *) oatNew(cUnit.get(), sizeof(MIR), true, kAllocMIR);
buzbee67bf8852011-08-17 17:51:35 -0700889 insn->offset = curOffset;
buzbeeba938cb2012-02-03 14:47:55 -0800890 int width = parseInsn(cUnit.get(), codePtr, &insn->dalvikInsn, false);
buzbee67bf8852011-08-17 17:51:35 -0700891 insn->width = width;
buzbee16da88c2012-03-20 10:38:17 -0700892 Instruction::Code opcode = insn->dalvikInsn.opcode;
buzbeea7c12682012-03-19 13:13:53 -0700893 if (cUnit->opcodeCount != NULL) {
buzbee16da88c2012-03-20 10:38:17 -0700894 cUnit->opcodeCount[static_cast<int>(opcode)]++;
buzbeea7c12682012-03-19 13:13:53 -0700895 }
buzbee67bf8852011-08-17 17:51:35 -0700896
897 /* Terminate when the data section is seen */
898 if (width == 0)
899 break;
900
buzbee16da88c2012-03-20 10:38:17 -0700901 /* Possible simple method? */
902 if (livePattern) {
903 livePattern = false;
904 specialCase = kNoHandler;
905 for (int i = 0; i < numPatterns; i++) {
906 if (!deadPattern[i]) {
907 if (specialPatterns[i].opcodes[patternPos] == opcode) {
908 livePattern = true;
909 specialCase = specialPatterns[i].handlerCode;
910 } else {
911 deadPattern[i] = true;
912 }
913 }
914 }
915 patternPos++;
916 }
917
buzbee67bf8852011-08-17 17:51:35 -0700918 oatAppendMIR(curBlock, insn);
919
920 codePtr += width;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800921 int flags = Instruction::Flags(insn->dalvikInsn.opcode);
buzbee67bf8852011-08-17 17:51:35 -0700922
buzbee5abfa3e2012-01-31 17:01:43 -0800923 int dfFlags = oatDataFlowAttributes[insn->dalvikInsn.opcode];
924
925 if (dfFlags & DF_HAS_DEFS) {
926 cUnit->defCount += (dfFlags & DF_DA_WIDE) ? 2 : 1;
927 }
buzbee99ba9642012-01-25 14:23:14 -0800928
Elliott Hughesadb8c672012-03-06 16:49:32 -0800929 if (flags & Instruction::kBranch) {
buzbeee941e2c2011-12-05 12:38:17 -0800930 curBlock = processCanBranch(cUnit.get(), curBlock, insn, curOffset,
931 width, flags, codePtr, codeEnd);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800932 } else if (flags & Instruction::kReturn) {
buzbee67bf8852011-08-17 17:51:35 -0700933 curBlock->fallThrough = exitBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800934 oatInsertGrowableList(cUnit.get(), exitBlock->predecessors,
935 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700936 /*
937 * Terminate the current block if there are instructions
938 * afterwards.
939 */
940 if (codePtr < codeEnd) {
941 /*
942 * Create a fallthrough block for real instructions
Elliott Hughesadb8c672012-03-06 16:49:32 -0800943 * (incl. NOP).
buzbee67bf8852011-08-17 17:51:35 -0700944 */
945 if (contentIsInsn(codePtr)) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700946 findBlock(cUnit.get(), curOffset + width,
buzbee67bf8852011-08-17 17:51:35 -0700947 /* split */
948 false,
949 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800950 true,
951 /* immedPredBlockP */
952 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700953 }
954 }
Elliott Hughesadb8c672012-03-06 16:49:32 -0800955 } else if (flags & Instruction::kThrow) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700956 processCanThrow(cUnit.get(), curBlock, insn, curOffset, width, flags,
buzbee67bf8852011-08-17 17:51:35 -0700957 tryBlockAddr, codePtr, codeEnd);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800958 } else if (flags & Instruction::kSwitch) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700959 processCanSwitch(cUnit.get(), curBlock, insn, curOffset, width, flags);
buzbee67bf8852011-08-17 17:51:35 -0700960 }
961 curOffset += width;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700962 BasicBlock *nextBlock = findBlock(cUnit.get(), curOffset,
buzbee67bf8852011-08-17 17:51:35 -0700963 /* split */
964 false,
965 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800966 false,
967 /* immedPredBlockP */
968 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700969 if (nextBlock) {
970 /*
971 * The next instruction could be the target of a previously parsed
972 * forward branch so a block is already created. If the current
973 * instruction is not an unconditional branch, connect them through
974 * the fall-through link.
975 */
buzbeeed3e9302011-09-23 17:34:19 -0700976 DCHECK(curBlock->fallThrough == NULL ||
buzbee67bf8852011-08-17 17:51:35 -0700977 curBlock->fallThrough == nextBlock ||
978 curBlock->fallThrough == exitBlock);
979
Elliott Hughesadb8c672012-03-06 16:49:32 -0800980 if ((curBlock->fallThrough == NULL) && (flags & Instruction::kContinue)) {
buzbee67bf8852011-08-17 17:51:35 -0700981 curBlock->fallThrough = nextBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800982 oatInsertGrowableList(cUnit.get(), nextBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800983 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700984 }
985 curBlock = nextBlock;
986 }
987 }
988
buzbee5abfa3e2012-01-31 17:01:43 -0800989 if (!(cUnit->disableOpt & (1 << kSkipLargeMethodOptimization))) {
buzbee99ba9642012-01-25 14:23:14 -0800990 if ((cUnit->numBlocks > MANY_BLOCKS) ||
991 ((cUnit->numBlocks > MANY_BLOCKS_INITIALIZER) &&
buzbeefc9e6fa2012-03-23 15:14:29 -0700992 PrettyMethod(method_idx, dex_file, false).find("init>") !=
buzbee99ba9642012-01-25 14:23:14 -0800993 std::string::npos)) {
buzbeea7c12682012-03-19 13:13:53 -0700994 cUnit->qdMode = true;
995 }
996 }
997
998 if (cUnit->qdMode) {
999 cUnit->disableDataflow = true;
1000 // Disable optimization which require dataflow/ssa
1001 cUnit->disableOpt |=
1002 (1 << kNullCheckElimination) |
1003 (1 << kBBOpt) |
1004 (1 << kPromoteRegs);
1005 if (cUnit->printMe) {
1006 LOG(INFO) << "QD mode enabled: "
1007 << PrettyMethod(method_idx, dex_file)
1008 << " too big: " << cUnit->numBlocks;
buzbee99ba9642012-01-25 14:23:14 -08001009 }
1010 }
1011
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001012 if (cUnit->printMe) {
1013 oatDumpCompilationUnit(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001014 }
1015
buzbee5b537102012-01-17 17:33:47 -08001016 if (cUnit->enableDebug & (1 << kDebugVerifyDataflow)) {
1017 /* Verify if all blocks are connected as claimed */
buzbee5abfa3e2012-01-31 17:01:43 -08001018 oatDataFlowAnalysisDispatcher(cUnit.get(), verifyPredInfo, kAllNodes,
1019 false /* isIterative */);
buzbee5b537102012-01-17 17:33:47 -08001020 }
buzbee67bf8852011-08-17 17:51:35 -07001021
1022 /* Perform SSA transformation for the whole method */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001023 oatMethodSSATransformation(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001024
buzbee239c4e72012-03-16 08:42:29 -07001025 /* Detect loops */
1026 oatMethodLoopDetection(cUnit.get());
1027
1028 /* Count uses */
1029 oatMethodUseCount(cUnit.get());
1030
buzbee43a36422011-09-14 14:00:13 -07001031 /* Perform null check elimination */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001032 oatMethodNullCheckElimination(cUnit.get());
buzbee43a36422011-09-14 14:00:13 -07001033
buzbeee1965672012-03-11 18:39:19 -07001034 /* Do some basic block optimizations */
1035 oatMethodBasicBlockOptimization(cUnit.get());
buzbeee1965672012-03-11 18:39:19 -07001036
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001037 oatInitializeRegAlloc(cUnit.get()); // Needs to happen after SSA naming
buzbee67bf8852011-08-17 17:51:35 -07001038
1039 /* Allocate Registers using simple local allocation scheme */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001040 oatSimpleRegAlloc(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001041
buzbee16da88c2012-03-20 10:38:17 -07001042 if (specialCase != kNoHandler) {
1043 /*
1044 * Custom codegen for special cases. If for any reason the
1045 * special codegen doesn't success, cUnit->firstLIRInsn will
1046 * set to NULL;
1047 */
1048 oatSpecialMIR2LIR(cUnit.get(), specialCase);
1049 }
1050
buzbee67bf8852011-08-17 17:51:35 -07001051 /* Convert MIR to LIR, etc. */
buzbee16da88c2012-03-20 10:38:17 -07001052 if (cUnit->firstLIRInsn == NULL) {
1053 oatMethodMIR2LIR(cUnit.get());
1054 }
buzbee67bf8852011-08-17 17:51:35 -07001055
1056 // Debugging only
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001057 if (cUnit->enableDebug & (1 << kDebugDumpCFG)) {
1058 oatDumpCFG(cUnit.get(), "/sdcard/cfg/");
buzbeeec5adf32011-09-11 15:25:43 -07001059 }
buzbee67bf8852011-08-17 17:51:35 -07001060
1061 /* Method is not empty */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001062 if (cUnit->firstLIRInsn) {
buzbee67bf8852011-08-17 17:51:35 -07001063
1064 // mark the targets of switch statement case labels
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001065 oatProcessSwitchTables(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001066
1067 /* Convert LIR into machine code. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001068 oatAssembleLIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001069
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001070 if (cUnit->printMe) {
1071 oatCodegenDump(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001072 }
buzbeea7c12682012-03-19 13:13:53 -07001073
1074 if (cUnit->opcodeCount != NULL) {
1075 LOG(INFO) << "Opcode Count";
1076 for (int i = 0; i < kNumPackedOpcodes; i++) {
1077 if (cUnit->opcodeCount[i] != 0) {
1078 LOG(INFO) << "-C- "
1079 <<Instruction::Name(static_cast<Instruction::Code>(i))
1080 << " " << cUnit->opcodeCount[i];
1081 }
1082 }
1083 }
buzbee67bf8852011-08-17 17:51:35 -07001084 }
1085
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001086 // Combine vmap tables - core regs, then fp regs - into vmapTable
1087 std::vector<uint16_t> vmapTable;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001088 for (size_t i = 0 ; i < cUnit->coreVmapTable.size(); i++) {
1089 vmapTable.push_back(cUnit->coreVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001090 }
buzbee16da88c2012-03-20 10:38:17 -07001091 // If we have a frame, push a marker to take place of lr
1092 if (cUnit->frameSize > 0) {
1093 vmapTable.push_back(INVALID_VREG);
1094 } else {
1095 DCHECK_EQ(__builtin_popcount(cUnit->coreSpillMask), 0);
1096 DCHECK_EQ(__builtin_popcount(cUnit->fpSpillMask), 0);
1097 }
buzbeec41e5b52011-09-23 12:46:19 -07001098 // Combine vmap tables - core regs, then fp regs
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001099 for (uint32_t i = 0; i < cUnit->fpVmapTable.size(); i++) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001100 vmapTable.push_back(cUnit->fpVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001101 }
Ian Rogersb5d09b22012-03-06 22:14:17 -08001102 CompiledMethod* result = new CompiledMethod(cUnit->instructionSet, cUnit->codeBuffer,
Ian Rogers0571d352011-11-03 19:51:38 -07001103 cUnit->frameSize, cUnit->coreSpillMask,
1104 cUnit->fpSpillMask, cUnit->mappingTable,
1105 vmapTable);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001106
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -08001107 VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file)
buzbee5abfa3e2012-01-31 17:01:43 -08001108 << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0]))
1109 << " bytes)";
1110
1111#ifdef WITH_MEMSTATS
1112 if (cUnit->enableDebug & (1 << kDebugShowMemoryUsage)) {
1113 oatDumpMemStats(cUnit.get());
1114 }
1115#endif
buzbee67bf8852011-08-17 17:51:35 -07001116
buzbeeba938cb2012-02-03 14:47:55 -08001117 oatArenaReset(cUnit.get());
1118
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001119 return result;
buzbee67bf8852011-08-17 17:51:35 -07001120}
1121
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001122} // namespace art
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001123
Elliott Hughes3fa1b7e2012-03-13 17:06:22 -07001124extern "C" art::CompiledMethod* ArtCompileMethod(art::Compiler& compiler,
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001125 const art::DexFile::CodeItem* code_item,
1126 uint32_t access_flags, uint32_t method_idx,
1127 const art::ClassLoader* class_loader,
1128 const art::DexFile& dex_file)
1129{
1130 CHECK_EQ(compiler.GetInstructionSet(), art::oatInstructionSet());
Elliott Hughes3fa1b7e2012-03-13 17:06:22 -07001131 return art::oatCompileMethod(compiler, code_item, access_flags, method_idx, class_loader, dex_file);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001132}