blob: 9fa69115a16a7cf7d2c7fa3e3561a66938b7498f [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
Bill Buzbeea114add2012-05-03 15:00:40 -070028 //(1 << kLoadStoreElimination) |
29 //(1 << kLoadHoisting) |
30 //(1 << kSuppressLoads) |
31 //(1 << kNullCheckElimination) |
32 //(1 << kPromoteRegs) |
33 //(1 << kTrackLiveTemps) |
34 //(1 << kSkipLargeMethodOptimization) |
35 //(1 << kSafeOptimizations) |
36 //(1 << kBBOpt) |
37 //(1 << kMatch) |
38 //(1 << kPromoteCompilerTemps) |
39 0;
buzbeece302932011-10-04 14:32:18 -070040
Elliott Hughese52e49b2012-04-02 16:05:44 -070041static uint32_t kCompilerDebugFlags = 0 | // Enable debug/testing modes
Bill Buzbeea114add2012-05-03 15:00:40 -070042 //(1 << kDebugDisplayMissingTargets) |
43 //(1 << kDebugVerbose) |
44 //(1 << kDebugDumpCFG) |
45 //(1 << kDebugSlowFieldPath) |
46 //(1 << kDebugSlowInvokePath) |
47 //(1 << kDebugSlowStringPath) |
48 //(1 << kDebugSlowestFieldPath) |
49 //(1 << kDebugSlowestStringPath) |
50 //(1 << kDebugExerciseResolveMethod) |
51 //(1 << kDebugVerifyDataflow) |
52 //(1 << kDebugShowMemoryUsage) |
53 //(1 << kDebugShowNops) |
54 //(1 << kDebugCountOpcodes) |
buzbeead8f15e2012-06-18 14:49:45 -070055#if defined(ART_USE_QUICK_COMPILER)
56 //(1 << kDebugDumpBitcodeFile) |
57#endif
Bill Buzbeea114add2012-05-03 15:00:40 -070058 0;
buzbeece302932011-10-04 14:32:18 -070059
buzbee31a4a6f2012-02-28 15:36:15 -080060inline bool contentIsInsn(const u2* codePtr) {
Bill Buzbeea114add2012-05-03 15:00:40 -070061 u2 instr = *codePtr;
62 Instruction::Code opcode = (Instruction::Code)(instr & 0xff);
buzbee67bf8852011-08-17 17:51:35 -070063
Bill Buzbeea114add2012-05-03 15:00:40 -070064 /*
65 * Since the low 8-bit in metadata may look like NOP, we need to check
66 * both the low and whole sub-word to determine whether it is code or data.
67 */
68 return (opcode != Instruction::NOP || instr == 0);
buzbee67bf8852011-08-17 17:51:35 -070069}
70
71/*
72 * Parse an instruction, return the length of the instruction
73 */
buzbee31a4a6f2012-02-28 15:36:15 -080074inline int parseInsn(CompilationUnit* cUnit, const u2* codePtr,
Bill Buzbeea114add2012-05-03 15:00:40 -070075 DecodedInstruction* decoded_instruction, bool printMe)
buzbee67bf8852011-08-17 17:51:35 -070076{
Elliott Hughesadb8c672012-03-06 16:49:32 -080077 // Don't parse instruction data
78 if (!contentIsInsn(codePtr)) {
79 return 0;
80 }
buzbee67bf8852011-08-17 17:51:35 -070081
Elliott Hughesadb8c672012-03-06 16:49:32 -080082 const Instruction* instruction = Instruction::At(codePtr);
83 *decoded_instruction = DecodedInstruction(instruction);
buzbee67bf8852011-08-17 17:51:35 -070084
Elliott Hughesadb8c672012-03-06 16:49:32 -080085 if (printMe) {
Bill Buzbeea114add2012-05-03 15:00:40 -070086 char* decodedString = oatGetDalvikDisassembly(cUnit, *decoded_instruction,
87 NULL);
88 LOG(INFO) << codePtr << ": 0x"
89 << std::hex << static_cast<int>(decoded_instruction->opcode)
Elliott Hughesadb8c672012-03-06 16:49:32 -080090 << " " << decodedString;
91 }
92 return instruction->SizeInCodeUnits();
buzbee67bf8852011-08-17 17:51:35 -070093}
94
95#define UNKNOWN_TARGET 0xffffffff
96
Elliott Hughesadb8c672012-03-06 16:49:32 -080097inline bool isGoto(MIR* insn) {
98 switch (insn->dalvikInsn.opcode) {
99 case Instruction::GOTO:
100 case Instruction::GOTO_16:
101 case Instruction::GOTO_32:
102 return true;
103 default:
104 return false;
Bill Buzbeea114add2012-05-03 15:00:40 -0700105 }
buzbee67bf8852011-08-17 17:51:35 -0700106}
107
108/*
109 * Identify unconditional branch instructions
110 */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800111inline bool isUnconditionalBranch(MIR* insn) {
112 switch (insn->dalvikInsn.opcode) {
113 case Instruction::RETURN_VOID:
114 case Instruction::RETURN:
115 case Instruction::RETURN_WIDE:
116 case Instruction::RETURN_OBJECT:
117 return true;
Bill Buzbeea114add2012-05-03 15:00:40 -0700118 default:
119 return isGoto(insn);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800120 }
buzbee67bf8852011-08-17 17:51:35 -0700121}
122
123/* Split an existing block from the specified code offset into two */
buzbee31a4a6f2012-02-28 15:36:15 -0800124BasicBlock *splitBlock(CompilationUnit* cUnit, unsigned int codeOffset,
Bill Buzbeea114add2012-05-03 15:00:40 -0700125 BasicBlock* origBlock, BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700126{
Bill Buzbeea114add2012-05-03 15:00:40 -0700127 MIR* insn = origBlock->firstMIRInsn;
128 while (insn) {
129 if (insn->offset == codeOffset) break;
130 insn = insn->next;
131 }
132 if (insn == NULL) {
133 LOG(FATAL) << "Break split failed";
134 }
135 BasicBlock *bottomBlock = oatNewBB(cUnit, kDalvikByteCode,
136 cUnit->numBlocks++);
137 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700138
Bill Buzbeea114add2012-05-03 15:00:40 -0700139 bottomBlock->startOffset = codeOffset;
140 bottomBlock->firstMIRInsn = insn;
141 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
buzbee67bf8852011-08-17 17:51:35 -0700142
Bill Buzbeea114add2012-05-03 15:00:40 -0700143 /* Add it to the quick lookup cache */
144 cUnit->blockMap.Put(bottomBlock->startOffset, bottomBlock);
buzbee5b537102012-01-17 17:33:47 -0800145
Bill Buzbeea114add2012-05-03 15:00:40 -0700146 /* Handle the taken path */
147 bottomBlock->taken = origBlock->taken;
148 if (bottomBlock->taken) {
149 origBlock->taken = NULL;
150 oatDeleteGrowableList(bottomBlock->taken->predecessors,
buzbeeba938cb2012-02-03 14:47:55 -0800151 (intptr_t)origBlock);
Bill Buzbeea114add2012-05-03 15:00:40 -0700152 oatInsertGrowableList(cUnit, bottomBlock->taken->predecessors,
153 (intptr_t)bottomBlock);
154 }
155
156 /* Handle the fallthrough path */
157 bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
158 bottomBlock->fallThrough = origBlock->fallThrough;
159 origBlock->fallThrough = bottomBlock;
160 origBlock->needFallThroughBranch = true;
161 oatInsertGrowableList(cUnit, bottomBlock->predecessors,
162 (intptr_t)origBlock);
163 if (bottomBlock->fallThrough) {
164 oatDeleteGrowableList(bottomBlock->fallThrough->predecessors,
165 (intptr_t)origBlock);
166 oatInsertGrowableList(cUnit, bottomBlock->fallThrough->predecessors,
167 (intptr_t)bottomBlock);
168 }
169
170 /* Handle the successor list */
171 if (origBlock->successorBlockList.blockListType != kNotUsed) {
172 bottomBlock->successorBlockList = origBlock->successorBlockList;
173 origBlock->successorBlockList.blockListType = kNotUsed;
174 GrowableListIterator iterator;
175
176 oatGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
177 &iterator);
178 while (true) {
179 SuccessorBlockInfo *successorBlockInfo =
180 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
181 if (successorBlockInfo == NULL) break;
182 BasicBlock *bb = successorBlockInfo->block;
183 oatDeleteGrowableList(bb->predecessors, (intptr_t)origBlock);
184 oatInsertGrowableList(cUnit, bb->predecessors, (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700185 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700186 }
buzbee67bf8852011-08-17 17:51:35 -0700187
Bill Buzbeea114add2012-05-03 15:00:40 -0700188 origBlock->lastMIRInsn = insn->prev;
buzbee67bf8852011-08-17 17:51:35 -0700189
Bill Buzbeea114add2012-05-03 15:00:40 -0700190 insn->prev->next = NULL;
191 insn->prev = NULL;
192 /*
193 * Update the immediate predecessor block pointer so that outgoing edges
194 * can be applied to the proper block.
195 */
196 if (immedPredBlockP) {
197 DCHECK_EQ(*immedPredBlockP, origBlock);
198 *immedPredBlockP = bottomBlock;
199 }
200 return bottomBlock;
buzbee67bf8852011-08-17 17:51:35 -0700201}
202
203/*
204 * Given a code offset, find out the block that starts with it. If the offset
buzbee9ab05de2012-01-18 15:43:48 -0800205 * is in the middle of an existing block, split it into two. If immedPredBlockP
206 * is not non-null and is the block being split, update *immedPredBlockP to
207 * point to the bottom block so that outgoing edges can be set up properly
208 * (by the caller)
buzbee5b537102012-01-17 17:33:47 -0800209 * Utilizes a map for fast lookup of the typical cases.
buzbee67bf8852011-08-17 17:51:35 -0700210 */
buzbee31a4a6f2012-02-28 15:36:15 -0800211BasicBlock *findBlock(CompilationUnit* cUnit, unsigned int codeOffset,
212 bool split, bool create, BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700213{
Bill Buzbeea114add2012-05-03 15:00:40 -0700214 GrowableList* blockList = &cUnit->blockList;
215 BasicBlock* bb;
216 unsigned int i;
217 SafeMap<unsigned int, BasicBlock*>::iterator it;
buzbee67bf8852011-08-17 17:51:35 -0700218
Bill Buzbeea114add2012-05-03 15:00:40 -0700219 it = cUnit->blockMap.find(codeOffset);
220 if (it != cUnit->blockMap.end()) {
221 return it->second;
222 } else if (!create) {
223 return NULL;
224 }
225
226 if (split) {
227 for (i = 0; i < blockList->numUsed; i++) {
228 bb = (BasicBlock *) blockList->elemList[i];
229 if (bb->blockType != kDalvikByteCode) continue;
230 /* Check if a branch jumps into the middle of an existing block */
231 if ((codeOffset > bb->startOffset) && (bb->lastMIRInsn != NULL) &&
232 (codeOffset <= bb->lastMIRInsn->offset)) {
233 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb,
234 bb == *immedPredBlockP ?
235 immedPredBlockP : NULL);
236 return newBB;
237 }
buzbee5b537102012-01-17 17:33:47 -0800238 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700239 }
buzbee5b537102012-01-17 17:33:47 -0800240
Bill Buzbeea114add2012-05-03 15:00:40 -0700241 /* Create a new one */
242 bb = oatNewBB(cUnit, kDalvikByteCode, cUnit->numBlocks++);
243 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) bb);
244 bb->startOffset = codeOffset;
245 cUnit->blockMap.Put(bb->startOffset, bb);
246 return bb;
buzbee67bf8852011-08-17 17:51:35 -0700247}
248
buzbeef58c12c2012-07-03 15:06:29 -0700249/* Find existing block */
250BasicBlock* oatFindBlock(CompilationUnit* cUnit, unsigned int codeOffset)
251{
252 return findBlock(cUnit, codeOffset, false, false, NULL);
253}
254
buzbeead8f15e2012-06-18 14:49:45 -0700255/* Turn method name into a legal Linux file name */
256void oatReplaceSpecialChars(std::string& str)
257{
258 static const struct { const char before; const char after; } match[] =
259 {{'/','-'}, {';','#'}, {' ','#'}, {'$','+'},
260 {'(','@'}, {')','@'}, {'<','='}, {'>','='}};
261 for (unsigned int i = 0; i < sizeof(match)/sizeof(match[0]); i++) {
262 std::replace(str.begin(), str.end(), match[i].before, match[i].after);
263 }
264}
265
buzbee67bf8852011-08-17 17:51:35 -0700266/* Dump the CFG into a DOT graph */
267void oatDumpCFG(CompilationUnit* cUnit, const char* dirPrefix)
268{
Bill Buzbeea114add2012-05-03 15:00:40 -0700269 FILE* file;
buzbeead8f15e2012-06-18 14:49:45 -0700270 std::string fname(PrettyMethod(cUnit->method_idx, *cUnit->dex_file));
271 oatReplaceSpecialChars(fname);
272 fname = StringPrintf("%s%s%x.dot", dirPrefix, fname.c_str(),
273 cUnit->entryBlock->fallThrough->startOffset);
274 file = fopen(fname.c_str(), "w");
Bill Buzbeea114add2012-05-03 15:00:40 -0700275 if (file == NULL) {
276 return;
277 }
278 fprintf(file, "digraph G {\n");
279
280 fprintf(file, " rankdir=TB\n");
281
282 int numReachableBlocks = cUnit->numReachableBlocks;
283 int idx;
284 const GrowableList *blockList = &cUnit->blockList;
285
286 for (idx = 0; idx < numReachableBlocks; idx++) {
287 int blockIdx = cUnit->dfsOrder.elemList[idx];
288 BasicBlock *bb = (BasicBlock *) oatGrowableListGetElement(blockList,
289 blockIdx);
290 if (bb == NULL) break;
291 if (bb->blockType == kEntryBlock) {
292 fprintf(file, " entry [shape=Mdiamond];\n");
293 } else if (bb->blockType == kExitBlock) {
294 fprintf(file, " exit [shape=Mdiamond];\n");
295 } else if (bb->blockType == kDalvikByteCode) {
296 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
297 bb->startOffset);
298 const MIR *mir;
299 fprintf(file, " {block id %d\\l}%s\\\n", bb->id,
300 bb->firstMIRInsn ? " | " : " ");
301 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
302 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
303 mir->ssaRep ? oatFullDisassembler(cUnit, mir) :
304 Instruction::Name(mir->dalvikInsn.opcode),
305 mir->next ? " | " : " ");
306 }
307 fprintf(file, " }\"];\n\n");
308 } else if (bb->blockType == kExceptionHandling) {
309 char blockName[BLOCK_NAME_LEN];
310
311 oatGetBlockName(bb, blockName);
312 fprintf(file, " %s [shape=invhouse];\n", blockName);
buzbee67bf8852011-08-17 17:51:35 -0700313 }
buzbee67bf8852011-08-17 17:51:35 -0700314
Bill Buzbeea114add2012-05-03 15:00:40 -0700315 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
buzbee67bf8852011-08-17 17:51:35 -0700316
Bill Buzbeea114add2012-05-03 15:00:40 -0700317 if (bb->taken) {
318 oatGetBlockName(bb, blockName1);
319 oatGetBlockName(bb->taken, blockName2);
320 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
321 blockName1, blockName2);
buzbee67bf8852011-08-17 17:51:35 -0700322 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700323 if (bb->fallThrough) {
324 oatGetBlockName(bb, blockName1);
325 oatGetBlockName(bb->fallThrough, blockName2);
326 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
327 }
328
329 if (bb->successorBlockList.blockListType != kNotUsed) {
330 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
331 bb->startOffset,
332 (bb->successorBlockList.blockListType == kCatch) ?
333 "Mrecord" : "record");
334 GrowableListIterator iterator;
335 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
336 &iterator);
337 SuccessorBlockInfo *successorBlockInfo =
338 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
339
340 int succId = 0;
341 while (true) {
342 if (successorBlockInfo == NULL) break;
343
344 BasicBlock *destBlock = successorBlockInfo->block;
345 SuccessorBlockInfo *nextSuccessorBlockInfo =
346 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
347
348 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
349 succId++,
350 successorBlockInfo->key,
351 destBlock->startOffset,
352 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
353
354 successorBlockInfo = nextSuccessorBlockInfo;
355 }
356 fprintf(file, " }\"];\n\n");
357
358 oatGetBlockName(bb, blockName1);
359 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
360 blockName1, bb->startOffset);
361
362 if (bb->successorBlockList.blockListType == kPackedSwitch ||
363 bb->successorBlockList.blockListType == kSparseSwitch) {
364
365 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
366 &iterator);
367
368 succId = 0;
369 while (true) {
370 SuccessorBlockInfo *successorBlockInfo = (SuccessorBlockInfo *)
371 oatGrowableListIteratorNext(&iterator);
372 if (successorBlockInfo == NULL) break;
373
374 BasicBlock *destBlock = successorBlockInfo->block;
375
376 oatGetBlockName(destBlock, blockName2);
377 fprintf(file, " succ%04x:f%d:e -> %s:n\n", bb->startOffset,
378 succId++, blockName2);
379 }
380 }
381 }
382 fprintf(file, "\n");
383
384 /* Display the dominator tree */
385 oatGetBlockName(bb, blockName1);
386 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
387 blockName1, blockName1);
388 if (bb->iDom) {
389 oatGetBlockName(bb->iDom, blockName2);
390 fprintf(file, " cfg%s:s -> cfg%s:n\n\n", blockName2, blockName1);
391 }
392 }
393 fprintf(file, "}\n");
394 fclose(file);
buzbee67bf8852011-08-17 17:51:35 -0700395}
396
397/* Verify if all the successor is connected with all the claimed predecessors */
buzbee31a4a6f2012-02-28 15:36:15 -0800398bool verifyPredInfo(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -0700399{
Bill Buzbeea114add2012-05-03 15:00:40 -0700400 GrowableListIterator iter;
buzbee67bf8852011-08-17 17:51:35 -0700401
Bill Buzbeea114add2012-05-03 15:00:40 -0700402 oatGrowableListIteratorInit(bb->predecessors, &iter);
403 while (true) {
404 BasicBlock *predBB = (BasicBlock*)oatGrowableListIteratorNext(&iter);
405 if (!predBB) break;
406 bool found = false;
407 if (predBB->taken == bb) {
408 found = true;
409 } else if (predBB->fallThrough == bb) {
410 found = true;
411 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
412 GrowableListIterator iterator;
413 oatGrowableListIteratorInit(&predBB->successorBlockList.blocks,
414 &iterator);
415 while (true) {
416 SuccessorBlockInfo *successorBlockInfo = (SuccessorBlockInfo *)
417 oatGrowableListIteratorNext(&iterator);
418 if (successorBlockInfo == NULL) break;
419 BasicBlock *succBB = successorBlockInfo->block;
420 if (succBB == bb) {
buzbee67bf8852011-08-17 17:51:35 -0700421 found = true;
Bill Buzbeea114add2012-05-03 15:00:40 -0700422 break;
buzbee67bf8852011-08-17 17:51:35 -0700423 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700424 }
buzbee67bf8852011-08-17 17:51:35 -0700425 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700426 if (found == false) {
427 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
428 oatGetBlockName(bb, blockName1);
429 oatGetBlockName(predBB, blockName2);
430 oatDumpCFG(cUnit, "/sdcard/cfg/");
431 LOG(FATAL) << "Successor " << blockName1 << "not found from "
432 << blockName2;
433 }
434 }
435 return true;
buzbee67bf8852011-08-17 17:51:35 -0700436}
437
438/* Identify code range in try blocks and set up the empty catch blocks */
buzbee31a4a6f2012-02-28 15:36:15 -0800439void processTryCatchBlocks(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700440{
Bill Buzbeea114add2012-05-03 15:00:40 -0700441 const DexFile::CodeItem* code_item = cUnit->code_item;
442 int triesSize = code_item->tries_size_;
443 int offset;
buzbee67bf8852011-08-17 17:51:35 -0700444
Bill Buzbeea114add2012-05-03 15:00:40 -0700445 if (triesSize == 0) {
446 return;
447 }
448
449 ArenaBitVector* tryBlockAddr = cUnit->tryBlockAddr;
450
451 for (int i = 0; i < triesSize; i++) {
452 const DexFile::TryItem* pTry =
453 DexFile::GetTryItems(*code_item, i);
454 int startOffset = pTry->start_addr_;
455 int endOffset = startOffset + pTry->insn_count_;
456 for (offset = startOffset; offset < endOffset; offset++) {
457 oatSetBit(cUnit, tryBlockAddr, offset);
buzbee67bf8852011-08-17 17:51:35 -0700458 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700459 }
buzbee67bf8852011-08-17 17:51:35 -0700460
Bill Buzbeea114add2012-05-03 15:00:40 -0700461 // Iterate over each of the handlers to enqueue the empty Catch blocks
462 const byte* handlers_ptr = DexFile::GetCatchHandlerData(*code_item, 0);
463 uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
464 for (uint32_t idx = 0; idx < handlers_size; idx++) {
465 CatchHandlerIterator iterator(handlers_ptr);
466 for (; iterator.HasNext(); iterator.Next()) {
467 uint32_t address = iterator.GetHandlerAddress();
468 findBlock(cUnit, address, false /* split */, true /*create*/,
469 /* immedPredBlockP */ NULL);
buzbee67bf8852011-08-17 17:51:35 -0700470 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700471 handlers_ptr = iterator.EndDataPointer();
472 }
buzbee67bf8852011-08-17 17:51:35 -0700473}
474
Elliott Hughesadb8c672012-03-06 16:49:32 -0800475/* Process instructions with the kBranch flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800476BasicBlock* processCanBranch(CompilationUnit* cUnit, BasicBlock* curBlock,
Bill Buzbeea114add2012-05-03 15:00:40 -0700477 MIR* insn, int curOffset, int width, int flags,
478 const u2* codePtr, const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700479{
Bill Buzbeea114add2012-05-03 15:00:40 -0700480 int target = curOffset;
481 switch (insn->dalvikInsn.opcode) {
482 case Instruction::GOTO:
483 case Instruction::GOTO_16:
484 case Instruction::GOTO_32:
485 target += (int) insn->dalvikInsn.vA;
486 break;
487 case Instruction::IF_EQ:
488 case Instruction::IF_NE:
489 case Instruction::IF_LT:
490 case Instruction::IF_GE:
491 case Instruction::IF_GT:
492 case Instruction::IF_LE:
493 target += (int) insn->dalvikInsn.vC;
494 break;
495 case Instruction::IF_EQZ:
496 case Instruction::IF_NEZ:
497 case Instruction::IF_LTZ:
498 case Instruction::IF_GEZ:
499 case Instruction::IF_GTZ:
500 case Instruction::IF_LEZ:
501 target += (int) insn->dalvikInsn.vB;
502 break;
503 default:
504 LOG(FATAL) << "Unexpected opcode(" << (int)insn->dalvikInsn.opcode
505 << ") with kBranch set";
506 }
507 BasicBlock *takenBlock = findBlock(cUnit, target,
508 /* split */
509 true,
510 /* create */
511 true,
512 /* immedPredBlockP */
513 &curBlock);
514 curBlock->taken = takenBlock;
515 oatInsertGrowableList(cUnit, takenBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700516
Bill Buzbeea114add2012-05-03 15:00:40 -0700517 /* Always terminate the current block for conditional branches */
518 if (flags & Instruction::kContinue) {
519 BasicBlock *fallthroughBlock = findBlock(cUnit,
520 curOffset + width,
521 /*
522 * If the method is processed
523 * in sequential order from the
524 * beginning, we don't need to
525 * specify split for continue
526 * blocks. However, this
527 * routine can be called by
528 * compileLoop, which starts
529 * parsing the method from an
530 * arbitrary address in the
531 * method body.
532 */
533 true,
534 /* create */
535 true,
536 /* immedPredBlockP */
537 &curBlock);
538 curBlock->fallThrough = fallthroughBlock;
539 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
540 (intptr_t)curBlock);
541 } else if (codePtr < codeEnd) {
542 /* Create a fallthrough block for real instructions (incl. NOP) */
543 if (contentIsInsn(codePtr)) {
544 findBlock(cUnit, curOffset + width,
545 /* split */
546 false,
547 /* create */
548 true,
549 /* immedPredBlockP */
550 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700551 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700552 }
553 return curBlock;
buzbee67bf8852011-08-17 17:51:35 -0700554}
555
Elliott Hughesadb8c672012-03-06 16:49:32 -0800556/* Process instructions with the kSwitch flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800557void processCanSwitch(CompilationUnit* cUnit, BasicBlock* curBlock,
558 MIR* insn, int curOffset, int width, int flags)
buzbee67bf8852011-08-17 17:51:35 -0700559{
Bill Buzbeea114add2012-05-03 15:00:40 -0700560 u2* switchData= (u2 *) (cUnit->insns + curOffset + insn->dalvikInsn.vB);
561 int size;
562 int* keyTable;
563 int* targetTable;
564 int i;
565 int firstKey;
buzbee67bf8852011-08-17 17:51:35 -0700566
Bill Buzbeea114add2012-05-03 15:00:40 -0700567 /*
568 * Packed switch data format:
569 * ushort ident = 0x0100 magic value
570 * ushort size number of entries in the table
571 * int first_key first (and lowest) switch case value
572 * int targets[size] branch targets, relative to switch opcode
573 *
574 * Total size is (4+size*2) 16-bit code units.
575 */
576 if (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) {
577 DCHECK_EQ(static_cast<int>(switchData[0]),
578 static_cast<int>(Instruction::kPackedSwitchSignature));
579 size = switchData[1];
580 firstKey = switchData[2] | (switchData[3] << 16);
581 targetTable = (int *) &switchData[4];
582 keyTable = NULL; // Make the compiler happy
583 /*
584 * Sparse switch data format:
585 * ushort ident = 0x0200 magic value
586 * ushort size number of entries in the table; > 0
587 * int keys[size] keys, sorted low-to-high; 32-bit aligned
588 * int targets[size] branch targets, relative to switch opcode
589 *
590 * Total size is (2+size*4) 16-bit code units.
591 */
592 } else {
593 DCHECK_EQ(static_cast<int>(switchData[0]),
594 static_cast<int>(Instruction::kSparseSwitchSignature));
595 size = switchData[1];
596 keyTable = (int *) &switchData[2];
597 targetTable = (int *) &switchData[2 + size*2];
598 firstKey = 0; // To make the compiler happy
599 }
buzbee67bf8852011-08-17 17:51:35 -0700600
Bill Buzbeea114add2012-05-03 15:00:40 -0700601 if (curBlock->successorBlockList.blockListType != kNotUsed) {
602 LOG(FATAL) << "Successor block list already in use: "
603 << (int)curBlock->successorBlockList.blockListType;
604 }
605 curBlock->successorBlockList.blockListType =
606 (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) ?
607 kPackedSwitch : kSparseSwitch;
608 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, size,
609 kListSuccessorBlocks);
610
611 for (i = 0; i < size; i++) {
612 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
613 /* split */
614 true,
615 /* create */
616 true,
617 /* immedPredBlockP */
618 &curBlock);
619 SuccessorBlockInfo *successorBlockInfo =
620 (SuccessorBlockInfo *) oatNew(cUnit, sizeof(SuccessorBlockInfo),
621 false, kAllocSuccessor);
622 successorBlockInfo->block = caseBlock;
623 successorBlockInfo->key =
Elliott Hughesadb8c672012-03-06 16:49:32 -0800624 (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) ?
Bill Buzbeea114add2012-05-03 15:00:40 -0700625 firstKey + i : keyTable[i];
626 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
627 (intptr_t) successorBlockInfo);
628 oatInsertGrowableList(cUnit, caseBlock->predecessors,
buzbeeba938cb2012-02-03 14:47:55 -0800629 (intptr_t)curBlock);
Bill Buzbeea114add2012-05-03 15:00:40 -0700630 }
631
632 /* Fall-through case */
633 BasicBlock* fallthroughBlock = findBlock(cUnit,
634 curOffset + width,
635 /* split */
636 false,
637 /* create */
638 true,
639 /* immedPredBlockP */
640 NULL);
641 curBlock->fallThrough = fallthroughBlock;
642 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
643 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700644}
645
Elliott Hughesadb8c672012-03-06 16:49:32 -0800646/* Process instructions with the kThrow flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800647void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock, MIR* insn,
648 int curOffset, int width, int flags,
649 ArenaBitVector* tryBlockAddr, const u2* codePtr,
650 const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700651{
Bill Buzbeea114add2012-05-03 15:00:40 -0700652 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbee67bf8852011-08-17 17:51:35 -0700653
Bill Buzbeea114add2012-05-03 15:00:40 -0700654 /* In try block */
655 if (oatIsBitSet(tryBlockAddr, curOffset)) {
656 CatchHandlerIterator iterator(*code_item, curOffset);
buzbee67bf8852011-08-17 17:51:35 -0700657
Bill Buzbeea114add2012-05-03 15:00:40 -0700658 if (curBlock->successorBlockList.blockListType != kNotUsed) {
659 LOG(FATAL) << "Successor block list already in use: "
660 << (int)curBlock->successorBlockList.blockListType;
buzbee67bf8852011-08-17 17:51:35 -0700661 }
662
Bill Buzbeea114add2012-05-03 15:00:40 -0700663 curBlock->successorBlockList.blockListType = kCatch;
664 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, 2,
665 kListSuccessorBlocks);
666
667 for (;iterator.HasNext(); iterator.Next()) {
668 BasicBlock *catchBlock = findBlock(cUnit, iterator.GetHandlerAddress(),
669 false /* split*/,
670 false /* creat */,
671 NULL /* immedPredBlockP */);
672 catchBlock->catchEntry = true;
673 SuccessorBlockInfo *successorBlockInfo = (SuccessorBlockInfo *)
674 oatNew(cUnit, sizeof(SuccessorBlockInfo), false, kAllocSuccessor);
675 successorBlockInfo->block = catchBlock;
676 successorBlockInfo->key = iterator.GetHandlerTypeIndex();
677 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
678 (intptr_t) successorBlockInfo);
679 oatInsertGrowableList(cUnit, catchBlock->predecessors,
680 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700681 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700682 } else {
683 BasicBlock *ehBlock = oatNewBB(cUnit, kExceptionHandling,
684 cUnit->numBlocks++);
685 curBlock->taken = ehBlock;
686 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) ehBlock);
687 ehBlock->startOffset = curOffset;
688 oatInsertGrowableList(cUnit, ehBlock->predecessors, (intptr_t)curBlock);
689 }
690
691 /*
692 * Force the current block to terminate.
693 *
694 * Data may be present before codeEnd, so we need to parse it to know
695 * whether it is code or data.
696 */
697 if (codePtr < codeEnd) {
698 /* Create a fallthrough block for real instructions (incl. NOP) */
699 if (contentIsInsn(codePtr)) {
700 BasicBlock *fallthroughBlock = findBlock(cUnit,
701 curOffset + width,
702 /* split */
703 false,
704 /* create */
705 true,
706 /* immedPredBlockP */
707 NULL);
708 /*
709 * THROW is an unconditional branch. NOTE:
710 * THROW_VERIFICATION_ERROR is also an unconditional
711 * branch, but we shouldn't treat it as such until we have
712 * a dead code elimination pass (which won't be important
buzbee2cfc6392012-05-07 14:51:40 -0700713 * until inlining w/ constant propagation is implemented.
Bill Buzbeea114add2012-05-03 15:00:40 -0700714 */
715 if (insn->dalvikInsn.opcode != Instruction::THROW) {
716 curBlock->fallThrough = fallthroughBlock;
717 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
718 (intptr_t)curBlock);
719 }
720 }
721 }
buzbee67bf8852011-08-17 17:51:35 -0700722}
723
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800724void oatInit(CompilationUnit* cUnit, const Compiler& compiler) {
725 if (!oatArchInit()) {
726 LOG(FATAL) << "Failed to initialize oat";
727 }
728 if (!oatHeapInit(cUnit)) {
729 LOG(FATAL) << "Failed to initialize oat heap";
730 }
731}
732
Elliott Hughes3fa1b7e2012-03-13 17:06:22 -0700733CompiledMethod* oatCompileMethod(Compiler& compiler,
734 const DexFile::CodeItem* code_item,
735 uint32_t access_flags, uint32_t method_idx,
736 const ClassLoader* class_loader,
737 const DexFile& dex_file)
buzbee67bf8852011-08-17 17:51:35 -0700738{
Bill Buzbeea114add2012-05-03 15:00:40 -0700739 VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
Brian Carlstrom94496d32011-08-22 09:22:47 -0700740
Bill Buzbeea114add2012-05-03 15:00:40 -0700741 const u2* codePtr = code_item->insns_;
742 const u2* codeEnd = code_item->insns_ + code_item->insns_size_in_code_units_;
743 int numBlocks = 0;
744 unsigned int curOffset = 0;
buzbee67bf8852011-08-17 17:51:35 -0700745
Bill Buzbeea114add2012-05-03 15:00:40 -0700746 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
747 UniquePtr<CompilationUnit> cUnit(new CompilationUnit);
buzbeeba938cb2012-02-03 14:47:55 -0800748
Bill Buzbeea114add2012-05-03 15:00:40 -0700749 oatInit(cUnit.get(), compiler);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800750
Bill Buzbeea114add2012-05-03 15:00:40 -0700751 cUnit->compiler = &compiler;
752 cUnit->class_linker = class_linker;
753 cUnit->dex_file = &dex_file;
754 cUnit->dex_cache = class_linker->FindDexCache(dex_file);
755 cUnit->method_idx = method_idx;
756 cUnit->code_item = code_item;
757 cUnit->access_flags = access_flags;
758 cUnit->shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
759 cUnit->instructionSet = compiler.GetInstructionSet();
760 cUnit->insns = code_item->insns_;
761 cUnit->insnsSize = code_item->insns_size_in_code_units_;
762 cUnit->numIns = code_item->ins_size_;
763 cUnit->numRegs = code_item->registers_size_ - cUnit->numIns;
764 cUnit->numOuts = code_item->outs_size_;
buzbee2cfc6392012-05-07 14:51:40 -0700765#if defined(ART_USE_QUICK_COMPILER)
buzbee4f1181f2012-06-22 13:52:12 -0700766 // TODO: remove - temp for Quick compiler bring-up
buzbee6969d502012-06-15 16:40:31 -0700767 if ((PrettyMethod(method_idx, dex_file).find("fibonacci") != std::string::npos)
768 || (PrettyMethod(method_idx, dex_file).find("HelloWorld") != std::string::npos)
buzbee4f1181f2012-06-22 13:52:12 -0700769 || (PrettyMethod(method_idx, dex_file).find("count10_006") != std::string::npos)
buzbee32412962012-06-26 16:27:56 -0700770 || (PrettyMethod(method_idx, dex_file).find("exceptions_007") != std::string::npos)
771 || (PrettyMethod(method_idx, dex_file).find("catchAndRethrow") != std::string::npos)
buzbee4f1181f2012-06-22 13:52:12 -0700772 || (PrettyMethod(method_idx, dex_file).find("math_012") != std::string::npos)
773 || (PrettyMethod(method_idx, dex_file).find("math_013") != std::string::npos)
buzbee32412962012-06-26 16:27:56 -0700774 || (PrettyMethod(method_idx, dex_file).find("math_014") != std::string::npos)
buzbee4f1181f2012-06-22 13:52:12 -0700775 || (PrettyMethod(method_idx, dex_file).find("float_017") != std::string::npos)
buzbee8fa0fda2012-06-27 15:44:52 -0700776 || (PrettyMethod(method_idx, dex_file).find("array_028") != std::string::npos)
777 || (PrettyMethod(method_idx, dex_file).find("writeArray") != std::string::npos)
778 || (PrettyMethod(method_idx, dex_file).find("writeTest") != std::string::npos)
779 || (PrettyMethod(method_idx, dex_file).find("copyTest") != std::string::npos)
buzbee101305f2012-06-28 18:00:56 -0700780 || (PrettyMethod(method_idx, dex_file).find("shiftTest1") != std::string::npos)
781 || (PrettyMethod(method_idx, dex_file).find("shiftTest2") != std::string::npos)
782 || (PrettyMethod(method_idx, dex_file).find("unsignedShiftTest") != std::string::npos)
buzbee76592632012-06-29 15:18:35 -0700783 || (PrettyMethod(method_idx, dex_file).find("convTest") != std::string::npos)
buzbee4f4dfc72012-07-02 14:54:44 -0700784 || (PrettyMethod(method_idx, dex_file).find("Array") != std::string::npos)
785 || (PrettyMethod(method_idx, dex_file).find("Classes") != std::string::npos)
786 || (PrettyMethod(method_idx, dex_file).find("Compare") != std::string::npos)
787 || (PrettyMethod(method_idx, dex_file).find("FloatMath") != std::string::npos)
788 || (PrettyMethod(method_idx, dex_file).find("Goto") != std::string::npos)
789 || (PrettyMethod(method_idx, dex_file).find("InternedString") != std::string::npos)
buzbeef58c12c2012-07-03 15:06:29 -0700790 || (PrettyMethod(method_idx, dex_file).find("IntMath") != std::string::npos)
buzbee4f4dfc72012-07-02 14:54:44 -0700791 || (PrettyMethod(method_idx, dex_file).find("InstField") != std::string::npos)
792 || (PrettyMethod(method_idx, dex_file).find("MethodCall") != std::string::npos)
793 || (PrettyMethod(method_idx, dex_file).find("Monitor") != std::string::npos)
794 || (PrettyMethod(method_idx, dex_file).find("StaticField") != std::string::npos)
795 // || (PrettyMethod(method_idx, dex_file).find("Switch") != std::string::npos)
796 // || (PrettyMethod(method_idx, dex_file).find("Throw.rethrow") != std::string::npos)
797 || (PrettyMethod(method_idx, dex_file).find("UnresClass") != std::string::npos)
798 || (PrettyMethod(method_idx, dex_file).find("UsresClassSubclass") != std::string::npos)
799 || (PrettyMethod(method_idx, dex_file).find("UsresStuff") != std::string::npos)
800 || (PrettyMethod(method_idx, dex_file).find("UsresTest1") != std::string::npos)
801 || (PrettyMethod(method_idx, dex_file).find("UsresTest2") != std::string::npos)
buzbee6969d502012-06-15 16:40:31 -0700802 ) {
803 cUnit->genBitcode = true;
804 }
buzbee2cfc6392012-05-07 14:51:40 -0700805#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700806 /* Adjust this value accordingly once inlining is performed */
807 cUnit->numDalvikRegisters = code_item->registers_size_;
808 // TODO: set this from command line
809 cUnit->compilerFlipMatch = false;
810 bool useMatch = !cUnit->compilerMethodMatch.empty();
811 bool match = useMatch && (cUnit->compilerFlipMatch ^
812 (PrettyMethod(method_idx, dex_file).find(cUnit->compilerMethodMatch) !=
813 std::string::npos));
814 if (!useMatch || match) {
815 cUnit->disableOpt = kCompilerOptimizerDisableFlags;
816 cUnit->enableDebug = kCompilerDebugFlags;
817 cUnit->printMe = VLOG_IS_ON(compiler) ||
818 (cUnit->enableDebug & (1 << kDebugVerbose));
819 }
buzbee2cfc6392012-05-07 14:51:40 -0700820#if defined(ART_USE_QUICK_COMPILER)
buzbee6969d502012-06-15 16:40:31 -0700821 if (cUnit->genBitcode) {
822 cUnit->printMe = true;
buzbeead8f15e2012-06-18 14:49:45 -0700823 cUnit->enableDebug |= (1 << kDebugDumpBitcodeFile);
buzbee4f1181f2012-06-22 13:52:12 -0700824 // Disable non-safe optimizations for now
825 cUnit->disableOpt |= ~(1 << kSafeOptimizations);
buzbee6969d502012-06-15 16:40:31 -0700826 }
buzbee2cfc6392012-05-07 14:51:40 -0700827#endif
Bill Buzbeea114add2012-05-03 15:00:40 -0700828 if (cUnit->instructionSet == kX86) {
jeffhaoe2962482012-06-28 11:29:57 -0700829 // Disable some optimizations on X86 for now
830 cUnit->disableOpt |= (
831 (1 << kLoadStoreElimination) |
832 (1 << kPromoteRegs) |
833 (1 << kTrackLiveTemps));
Bill Buzbeea114add2012-05-03 15:00:40 -0700834 }
835 /* Are we generating code for the debugger? */
836 if (compiler.IsDebuggingSupported()) {
837 cUnit->genDebugger = true;
838 // Yes, disable most optimizations
839 cUnit->disableOpt |= (
840 (1 << kLoadStoreElimination) |
841 (1 << kLoadHoisting) |
842 (1 << kSuppressLoads) |
843 (1 << kPromoteRegs) |
844 (1 << kBBOpt) |
845 (1 << kMatch) |
846 (1 << kTrackLiveTemps));
847 }
848
849 /* Gathering opcode stats? */
850 if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) {
851 cUnit->opcodeCount = (int*)oatNew(cUnit.get(),
852 kNumPackedOpcodes * sizeof(int), true, kAllocMisc);
853 }
854
855 /* Assume non-throwing leaf */
856 cUnit->attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
857
858 /* Initialize the block list, estimate size based on insnsSize */
859 oatInitGrowableList(cUnit.get(), &cUnit->blockList, cUnit->insnsSize,
860 kListBlockList);
861
862 /* Initialize the switchTables list */
863 oatInitGrowableList(cUnit.get(), &cUnit->switchTables, 4,
864 kListSwitchTables);
865
866 /* Intialize the fillArrayData list */
867 oatInitGrowableList(cUnit.get(), &cUnit->fillArrayData, 4,
868 kListFillArrayData);
869
870 /* Intialize the throwLaunchpads list, estimate size based on insnsSize */
871 oatInitGrowableList(cUnit.get(), &cUnit->throwLaunchpads, cUnit->insnsSize,
872 kListThrowLaunchPads);
873
874 /* Intialize the instrinsicLaunchpads list */
875 oatInitGrowableList(cUnit.get(), &cUnit->intrinsicLaunchpads, 4,
876 kListMisc);
877
878
879 /* Intialize the suspendLaunchpads list */
880 oatInitGrowableList(cUnit.get(), &cUnit->suspendLaunchpads, 2048,
881 kListSuspendLaunchPads);
882
883 /* Allocate the bit-vector to track the beginning of basic blocks */
884 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit.get(),
885 cUnit->insnsSize,
886 true /* expandable */);
887 cUnit->tryBlockAddr = tryBlockAddr;
888
889 /* Create the default entry and exit blocks and enter them to the list */
890 BasicBlock *entryBlock = oatNewBB(cUnit.get(), kEntryBlock, numBlocks++);
891 BasicBlock *exitBlock = oatNewBB(cUnit.get(), kExitBlock, numBlocks++);
892
893 cUnit->entryBlock = entryBlock;
894 cUnit->exitBlock = exitBlock;
895
896 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) entryBlock);
897 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) exitBlock);
898
899 /* Current block to record parsed instructions */
900 BasicBlock *curBlock = oatNewBB(cUnit.get(), kDalvikByteCode, numBlocks++);
901 curBlock->startOffset = 0;
902 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) curBlock);
903 /* Add first block to the fast lookup cache */
904 cUnit->blockMap.Put(curBlock->startOffset, curBlock);
905 entryBlock->fallThrough = curBlock;
906 oatInsertGrowableList(cUnit.get(), curBlock->predecessors,
907 (intptr_t)entryBlock);
908
909 /*
910 * Store back the number of blocks since new blocks may be created of
911 * accessing cUnit.
912 */
913 cUnit->numBlocks = numBlocks;
914
915 /* Identify code range in try blocks and set up the empty catch blocks */
916 processTryCatchBlocks(cUnit.get());
917
918 /* Set up for simple method detection */
919 int numPatterns = sizeof(specialPatterns)/sizeof(specialPatterns[0]);
920 bool livePattern = (numPatterns > 0) && !(cUnit->disableOpt & (1 << kMatch));
Elliott Hughesabe64aa2012-05-30 17:34:45 -0700921 bool* deadPattern = (bool*)oatNew(cUnit.get(), sizeof(bool) * numPatterns, true,
Bill Buzbeea114add2012-05-03 15:00:40 -0700922 kAllocMisc);
923 SpecialCaseHandler specialCase = kNoHandler;
924 int patternPos = 0;
925
926 /* Parse all instructions and put them into containing basic blocks */
927 while (codePtr < codeEnd) {
928 MIR *insn = (MIR *) oatNew(cUnit.get(), sizeof(MIR), true, kAllocMIR);
929 insn->offset = curOffset;
930 int width = parseInsn(cUnit.get(), codePtr, &insn->dalvikInsn, false);
931 insn->width = width;
932 Instruction::Code opcode = insn->dalvikInsn.opcode;
933 if (cUnit->opcodeCount != NULL) {
934 cUnit->opcodeCount[static_cast<int>(opcode)]++;
buzbee44b412b2012-02-04 08:50:53 -0800935 }
936
Bill Buzbeea114add2012-05-03 15:00:40 -0700937 /* Terminate when the data section is seen */
938 if (width == 0)
939 break;
940
941 /* Possible simple method? */
942 if (livePattern) {
943 livePattern = false;
944 specialCase = kNoHandler;
945 for (int i = 0; i < numPatterns; i++) {
946 if (!deadPattern[i]) {
947 if (specialPatterns[i].opcodes[patternPos] == opcode) {
948 livePattern = true;
949 specialCase = specialPatterns[i].handlerCode;
950 } else {
951 deadPattern[i] = true;
952 }
953 }
954 }
955 patternPos++;
buzbeea7c12682012-03-19 13:13:53 -0700956 }
957
Bill Buzbeea114add2012-05-03 15:00:40 -0700958 oatAppendMIR(curBlock, insn);
buzbeecefd1872011-09-09 09:59:52 -0700959
Bill Buzbeea114add2012-05-03 15:00:40 -0700960 codePtr += width;
961 int flags = Instruction::Flags(insn->dalvikInsn.opcode);
buzbee67bf8852011-08-17 17:51:35 -0700962
Bill Buzbeea114add2012-05-03 15:00:40 -0700963 int dfFlags = oatDataFlowAttributes[insn->dalvikInsn.opcode];
buzbee67bf8852011-08-17 17:51:35 -0700964
Bill Buzbeea114add2012-05-03 15:00:40 -0700965 if (dfFlags & DF_HAS_DEFS) {
buzbeebff24652012-05-06 16:22:05 -0700966 cUnit->defCount += (dfFlags & DF_A_WIDE) ? 2 : 1;
Bill Buzbeea114add2012-05-03 15:00:40 -0700967 }
buzbee67bf8852011-08-17 17:51:35 -0700968
Bill Buzbeea114add2012-05-03 15:00:40 -0700969 if (flags & Instruction::kBranch) {
970 curBlock = processCanBranch(cUnit.get(), curBlock, insn, curOffset,
971 width, flags, codePtr, codeEnd);
972 } else if (flags & Instruction::kReturn) {
973 curBlock->fallThrough = exitBlock;
974 oatInsertGrowableList(cUnit.get(), exitBlock->predecessors,
975 (intptr_t)curBlock);
976 /*
977 * Terminate the current block if there are instructions
978 * afterwards.
979 */
980 if (codePtr < codeEnd) {
981 /*
982 * Create a fallthrough block for real instructions
983 * (incl. NOP).
984 */
985 if (contentIsInsn(codePtr)) {
986 findBlock(cUnit.get(), curOffset + width,
987 /* split */
988 false,
989 /* create */
990 true,
991 /* immedPredBlockP */
992 NULL);
993 }
994 }
995 } else if (flags & Instruction::kThrow) {
996 processCanThrow(cUnit.get(), curBlock, insn, curOffset, width, flags,
997 tryBlockAddr, codePtr, codeEnd);
998 } else if (flags & Instruction::kSwitch) {
999 processCanSwitch(cUnit.get(), curBlock, insn, curOffset, width, flags);
1000 }
1001 curOffset += width;
1002 BasicBlock *nextBlock = findBlock(cUnit.get(), curOffset,
1003 /* split */
1004 false,
1005 /* create */
1006 false,
1007 /* immedPredBlockP */
1008 NULL);
1009 if (nextBlock) {
1010 /*
1011 * The next instruction could be the target of a previously parsed
1012 * forward branch so a block is already created. If the current
1013 * instruction is not an unconditional branch, connect them through
1014 * the fall-through link.
1015 */
1016 DCHECK(curBlock->fallThrough == NULL ||
1017 curBlock->fallThrough == nextBlock ||
1018 curBlock->fallThrough == exitBlock);
buzbee5ade1d22011-09-09 14:44:52 -07001019
Bill Buzbeea114add2012-05-03 15:00:40 -07001020 if ((curBlock->fallThrough == NULL) && (flags & Instruction::kContinue)) {
1021 curBlock->fallThrough = nextBlock;
1022 oatInsertGrowableList(cUnit.get(), nextBlock->predecessors,
1023 (intptr_t)curBlock);
1024 }
1025 curBlock = nextBlock;
1026 }
1027 }
buzbeefc9e6fa2012-03-23 15:14:29 -07001028
Bill Buzbeea114add2012-05-03 15:00:40 -07001029 if (!(cUnit->disableOpt & (1 << kSkipLargeMethodOptimization))) {
1030 if ((cUnit->numBlocks > MANY_BLOCKS) ||
1031 ((cUnit->numBlocks > MANY_BLOCKS_INITIALIZER) &&
1032 PrettyMethod(method_idx, dex_file, false).find("init>") !=
1033 std::string::npos)) {
1034 cUnit->qdMode = true;
1035 }
1036 }
buzbeefc9e6fa2012-03-23 15:14:29 -07001037
buzbee2cfc6392012-05-07 14:51:40 -07001038#if defined(ART_USE_QUICK_COMPILER)
1039 if (cUnit->genBitcode) {
1040 // Bitcode generation requires full dataflow analysis, no qdMode
1041 cUnit->qdMode = false;
1042 }
1043#endif
1044
Bill Buzbeea114add2012-05-03 15:00:40 -07001045 if (cUnit->qdMode) {
1046 cUnit->disableDataflow = true;
1047 // Disable optimization which require dataflow/ssa
1048 cUnit->disableOpt |=
1049 (1 << kNullCheckElimination) |
1050 (1 << kBBOpt) |
1051 (1 << kPromoteRegs);
1052 if (cUnit->printMe) {
1053 LOG(INFO) << "QD mode enabled: "
1054 << PrettyMethod(method_idx, dex_file)
1055 << " too big: " << cUnit->numBlocks;
1056 }
1057 }
buzbeec1f45042011-09-21 16:03:19 -07001058
Bill Buzbeea114add2012-05-03 15:00:40 -07001059 if (cUnit->printMe) {
1060 oatDumpCompilationUnit(cUnit.get());
1061 }
buzbee67bf8852011-08-17 17:51:35 -07001062
Bill Buzbeea114add2012-05-03 15:00:40 -07001063 if (cUnit->enableDebug & (1 << kDebugVerifyDataflow)) {
1064 /* Verify if all blocks are connected as claimed */
1065 oatDataFlowAnalysisDispatcher(cUnit.get(), verifyPredInfo, kAllNodes,
1066 false /* isIterative */);
1067 }
buzbee67bf8852011-08-17 17:51:35 -07001068
Bill Buzbeea114add2012-05-03 15:00:40 -07001069 /* Perform SSA transformation for the whole method */
1070 oatMethodSSATransformation(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001071
buzbee2cfc6392012-05-07 14:51:40 -07001072 /* Do constant propagation */
1073 // TODO: Probably need to make these expandable to support new ssa names
1074 // introducted during MIR optimization passes
1075 cUnit->isConstantV = oatAllocBitVector(cUnit.get(), cUnit->numSSARegs,
1076 false /* not expandable */);
1077 cUnit->constantValues =
1078 (int*)oatNew(cUnit.get(), sizeof(int) * cUnit->numSSARegs, true,
1079 kAllocDFInfo);
1080 oatDataFlowAnalysisDispatcher(cUnit.get(), oatDoConstantPropagation,
1081 kAllNodes,
1082 false /* isIterative */);
1083
Bill Buzbeea114add2012-05-03 15:00:40 -07001084 /* Detect loops */
1085 oatMethodLoopDetection(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001086
Bill Buzbeea114add2012-05-03 15:00:40 -07001087 /* Count uses */
1088 oatMethodUseCount(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001089
Bill Buzbeea114add2012-05-03 15:00:40 -07001090 /* Perform null check elimination */
1091 oatMethodNullCheckElimination(cUnit.get());
1092
1093 /* Do some basic block optimizations */
1094 oatMethodBasicBlockOptimization(cUnit.get());
1095
1096 oatInitializeRegAlloc(cUnit.get()); // Needs to happen after SSA naming
1097
1098 /* Allocate Registers using simple local allocation scheme */
1099 oatSimpleRegAlloc(cUnit.get());
1100
buzbee2cfc6392012-05-07 14:51:40 -07001101#if defined(ART_USE_QUICK_COMPILER)
1102 /* Go the LLVM path? */
1103 if (cUnit->genBitcode) {
1104 // MIR->Bitcode
1105 oatMethodMIR2Bitcode(cUnit.get());
1106 // Bitcode->LIR
1107 oatMethodBitcode2LIR(cUnit.get());
1108 } else {
1109#endif
1110 if (specialCase != kNoHandler) {
1111 /*
1112 * Custom codegen for special cases. If for any reason the
1113 * special codegen doesn't succeed, cUnit->firstLIRInsn will
1114 * set to NULL;
1115 */
1116 oatSpecialMIR2LIR(cUnit.get(), specialCase);
1117 }
buzbee67bf8852011-08-17 17:51:35 -07001118
buzbee2cfc6392012-05-07 14:51:40 -07001119 /* Convert MIR to LIR, etc. */
1120 if (cUnit->firstLIRInsn == NULL) {
1121 oatMethodMIR2LIR(cUnit.get());
1122 }
1123#if defined(ART_USE_QUICK_COMPILER)
Bill Buzbeea114add2012-05-03 15:00:40 -07001124 }
buzbee2cfc6392012-05-07 14:51:40 -07001125#endif
buzbee67bf8852011-08-17 17:51:35 -07001126
Bill Buzbeea114add2012-05-03 15:00:40 -07001127 // Debugging only
1128 if (cUnit->enableDebug & (1 << kDebugDumpCFG)) {
1129 oatDumpCFG(cUnit.get(), "/sdcard/cfg/");
1130 }
buzbee16da88c2012-03-20 10:38:17 -07001131
Bill Buzbeea114add2012-05-03 15:00:40 -07001132 /* Method is not empty */
1133 if (cUnit->firstLIRInsn) {
buzbee67bf8852011-08-17 17:51:35 -07001134
Bill Buzbeea114add2012-05-03 15:00:40 -07001135 // mark the targets of switch statement case labels
1136 oatProcessSwitchTables(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001137
Bill Buzbeea114add2012-05-03 15:00:40 -07001138 /* Convert LIR into machine code. */
1139 oatAssembleLIR(cUnit.get());
buzbee99ba9642012-01-25 14:23:14 -08001140
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001141 if (cUnit->printMe) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001142 oatCodegenDump(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001143 }
1144
Bill Buzbeea114add2012-05-03 15:00:40 -07001145 if (cUnit->opcodeCount != NULL) {
1146 LOG(INFO) << "Opcode Count";
1147 for (int i = 0; i < kNumPackedOpcodes; i++) {
1148 if (cUnit->opcodeCount[i] != 0) {
1149 LOG(INFO) << "-C- "
1150 << Instruction::Name(static_cast<Instruction::Code>(i))
1151 << " " << cUnit->opcodeCount[i];
buzbee67bf8852011-08-17 17:51:35 -07001152 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001153 }
1154 }
1155 }
buzbeea7c12682012-03-19 13:13:53 -07001156
Bill Buzbeea114add2012-05-03 15:00:40 -07001157 // Combine vmap tables - core regs, then fp regs - into vmapTable
1158 std::vector<uint16_t> vmapTable;
1159 for (size_t i = 0 ; i < cUnit->coreVmapTable.size(); i++) {
1160 vmapTable.push_back(cUnit->coreVmapTable[i]);
1161 }
1162 // If we have a frame, push a marker to take place of lr
1163 if (cUnit->frameSize > 0) {
1164 vmapTable.push_back(INVALID_VREG);
1165 } else {
1166 DCHECK_EQ(__builtin_popcount(cUnit->coreSpillMask), 0);
1167 DCHECK_EQ(__builtin_popcount(cUnit->fpSpillMask), 0);
1168 }
1169 // Combine vmap tables - core regs, then fp regs
1170 for (uint32_t i = 0; i < cUnit->fpVmapTable.size(); i++) {
1171 vmapTable.push_back(cUnit->fpVmapTable[i]);
1172 }
1173 CompiledMethod* result =
1174 new CompiledMethod(cUnit->instructionSet, cUnit->codeBuffer,
1175 cUnit->frameSize, cUnit->coreSpillMask,
1176 cUnit->fpSpillMask, cUnit->mappingTable, vmapTable);
buzbee67bf8852011-08-17 17:51:35 -07001177
Bill Buzbeea114add2012-05-03 15:00:40 -07001178 VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file)
1179 << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0]))
1180 << " bytes)";
buzbee5abfa3e2012-01-31 17:01:43 -08001181
1182#ifdef WITH_MEMSTATS
Bill Buzbeea114add2012-05-03 15:00:40 -07001183 if (cUnit->enableDebug & (1 << kDebugShowMemoryUsage)) {
1184 oatDumpMemStats(cUnit.get());
1185 }
buzbee5abfa3e2012-01-31 17:01:43 -08001186#endif
buzbee67bf8852011-08-17 17:51:35 -07001187
Bill Buzbeea114add2012-05-03 15:00:40 -07001188 oatArenaReset(cUnit.get());
buzbeeba938cb2012-02-03 14:47:55 -08001189
Bill Buzbeea114add2012-05-03 15:00:40 -07001190 return result;
buzbee67bf8852011-08-17 17:51:35 -07001191}
1192
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001193} // namespace art
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001194
Bill Buzbeea114add2012-05-03 15:00:40 -07001195extern "C" art::CompiledMethod*
1196 ArtCompileMethod(art::Compiler& compiler,
1197 const art::DexFile::CodeItem* code_item,
1198 uint32_t access_flags, uint32_t method_idx,
1199 const art::ClassLoader* class_loader,
1200 const art::DexFile& dex_file)
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001201{
1202 CHECK_EQ(compiler.GetInstructionSet(), art::oatInstructionSet());
Bill Buzbeea114add2012-05-03 15:00:40 -07001203 return art::oatCompileMethod(compiler, code_item, access_flags, method_idx,
1204 class_loader, dex_file);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001205}