blob: 4271722b143558e36b4ab06aba3526cab15d5f47 [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) |
buzbeece302932011-10-04 14:32:18 -070037 0;
38
39uint32_t compilerDebugFlags = 0 | // Enable debug/testing modes
buzbeee3de7492011-10-05 13:37:17 -070040 //(1 << kDebugDisplayMissingTargets) |
buzbeece302932011-10-04 14:32:18 -070041 //(1 << kDebugVerbose) |
42 //(1 << kDebugDumpCFG) |
43 //(1 << kDebugSlowFieldPath) |
44 //(1 << kDebugSlowInvokePath) |
45 //(1 << kDebugSlowStringPath) |
46 //(1 << kDebugSlowestFieldPath) |
47 //(1 << kDebugSlowestStringPath) |
buzbee34c77ad2012-01-11 13:01:32 -080048 //(1 << kDebugExerciseResolveMethod) |
buzbee5b537102012-01-17 17:33:47 -080049 //(1 << kDebugVerifyDataflow) |
buzbee5abfa3e2012-01-31 17:01:43 -080050 //(1 << kDebugShowMemoryUsage) |
buzbee86a4bce2012-03-06 18:15:00 -080051 //(1 << kDebugShowNops) |
buzbeece302932011-10-04 14:32:18 -070052 0;
53
buzbee31a4a6f2012-02-28 15:36:15 -080054inline bool contentIsInsn(const u2* codePtr) {
buzbee67bf8852011-08-17 17:51:35 -070055 u2 instr = *codePtr;
Elliott Hughesadb8c672012-03-06 16:49:32 -080056 Instruction::Code opcode = (Instruction::Code)(instr & 0xff);
buzbee67bf8852011-08-17 17:51:35 -070057
58 /*
Elliott Hughesadb8c672012-03-06 16:49:32 -080059 * Since the low 8-bit in metadata may look like NOP, we need to check
buzbee67bf8852011-08-17 17:51:35 -070060 * both the low and whole sub-word to determine whether it is code or data.
61 */
Elliott Hughesadb8c672012-03-06 16:49:32 -080062 return (opcode != Instruction::NOP || instr == 0);
buzbee67bf8852011-08-17 17:51:35 -070063}
64
65/*
66 * Parse an instruction, return the length of the instruction
67 */
buzbee31a4a6f2012-02-28 15:36:15 -080068inline int parseInsn(CompilationUnit* cUnit, const u2* codePtr,
Elliott Hughesadb8c672012-03-06 16:49:32 -080069 DecodedInstruction* decoded_instruction, bool printMe)
buzbee67bf8852011-08-17 17:51:35 -070070{
Elliott Hughesadb8c672012-03-06 16:49:32 -080071 // Don't parse instruction data
72 if (!contentIsInsn(codePtr)) {
73 return 0;
74 }
buzbee67bf8852011-08-17 17:51:35 -070075
Elliott Hughesadb8c672012-03-06 16:49:32 -080076 const Instruction* instruction = Instruction::At(codePtr);
77 *decoded_instruction = DecodedInstruction(instruction);
buzbee67bf8852011-08-17 17:51:35 -070078
Elliott Hughesadb8c672012-03-06 16:49:32 -080079 if (printMe) {
80 char* decodedString = oatGetDalvikDisassembly(cUnit, *decoded_instruction, NULL);
81 LOG(INFO) << codePtr << ": 0x" << std::hex << static_cast<int>(decoded_instruction->opcode)
82 << " " << decodedString;
83 }
84 return instruction->SizeInCodeUnits();
buzbee67bf8852011-08-17 17:51:35 -070085}
86
87#define UNKNOWN_TARGET 0xffffffff
88
Elliott Hughesadb8c672012-03-06 16:49:32 -080089inline bool isGoto(MIR* insn) {
90 switch (insn->dalvikInsn.opcode) {
91 case Instruction::GOTO:
92 case Instruction::GOTO_16:
93 case Instruction::GOTO_32:
94 return true;
95 default:
96 return false;
buzbee67bf8852011-08-17 17:51:35 -070097 }
98}
99
100/*
101 * Identify unconditional branch instructions
102 */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800103inline bool isUnconditionalBranch(MIR* insn) {
104 switch (insn->dalvikInsn.opcode) {
105 case Instruction::RETURN_VOID:
106 case Instruction::RETURN:
107 case Instruction::RETURN_WIDE:
108 case Instruction::RETURN_OBJECT:
109 return true;
110 default:
111 return isGoto(insn);
112 }
buzbee67bf8852011-08-17 17:51:35 -0700113}
114
115/* Split an existing block from the specified code offset into two */
buzbee31a4a6f2012-02-28 15:36:15 -0800116BasicBlock *splitBlock(CompilationUnit* cUnit, unsigned int codeOffset,
117 BasicBlock* origBlock, BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700118{
119 MIR* insn = origBlock->firstMIRInsn;
120 while (insn) {
121 if (insn->offset == codeOffset) break;
122 insn = insn->next;
123 }
124 if (insn == NULL) {
125 LOG(FATAL) << "Break split failed";
126 }
buzbee5abfa3e2012-01-31 17:01:43 -0800127 BasicBlock *bottomBlock = oatNewBB(cUnit, kDalvikByteCode,
128 cUnit->numBlocks++);
buzbeeba938cb2012-02-03 14:47:55 -0800129 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700130
131 bottomBlock->startOffset = codeOffset;
132 bottomBlock->firstMIRInsn = insn;
133 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
134
buzbee5b537102012-01-17 17:33:47 -0800135 /* Add it to the quick lookup cache */
136 cUnit->blockMap.insert(std::make_pair(bottomBlock->startOffset,
137 bottomBlock));
138
buzbee67bf8852011-08-17 17:51:35 -0700139 /* Handle the taken path */
140 bottomBlock->taken = origBlock->taken;
141 if (bottomBlock->taken) {
142 origBlock->taken = NULL;
buzbee5abfa3e2012-01-31 17:01:43 -0800143 oatDeleteGrowableList(bottomBlock->taken->predecessors,
144 (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800145 oatInsertGrowableList(cUnit, bottomBlock->taken->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800146 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700147 }
148
149 /* Handle the fallthrough path */
150 bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
151 bottomBlock->fallThrough = origBlock->fallThrough;
152 origBlock->fallThrough = bottomBlock;
153 origBlock->needFallThroughBranch = true;
buzbeeba938cb2012-02-03 14:47:55 -0800154 oatInsertGrowableList(cUnit, bottomBlock->predecessors,
155 (intptr_t)origBlock);
buzbee67bf8852011-08-17 17:51:35 -0700156 if (bottomBlock->fallThrough) {
buzbee5abfa3e2012-01-31 17:01:43 -0800157 oatDeleteGrowableList(bottomBlock->fallThrough->predecessors,
158 (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800159 oatInsertGrowableList(cUnit, bottomBlock->fallThrough->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800160 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700161 }
162
163 /* Handle the successor list */
164 if (origBlock->successorBlockList.blockListType != kNotUsed) {
165 bottomBlock->successorBlockList = origBlock->successorBlockList;
166 origBlock->successorBlockList.blockListType = kNotUsed;
167 GrowableListIterator iterator;
168
169 oatGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
170 &iterator);
171 while (true) {
172 SuccessorBlockInfo *successorBlockInfo =
173 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
174 if (successorBlockInfo == NULL) break;
175 BasicBlock *bb = successorBlockInfo->block;
buzbee5abfa3e2012-01-31 17:01:43 -0800176 oatDeleteGrowableList(bb->predecessors, (intptr_t)origBlock);
buzbeeba938cb2012-02-03 14:47:55 -0800177 oatInsertGrowableList(cUnit, bb->predecessors,
178 (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700179 }
180 }
181
182 origBlock->lastMIRInsn = insn->prev;
183
184 insn->prev->next = NULL;
185 insn->prev = NULL;
buzbee9ab05de2012-01-18 15:43:48 -0800186 /*
187 * Update the immediate predecessor block pointer so that outgoing edges
188 * can be applied to the proper block.
189 */
190 if (immedPredBlockP) {
191 DCHECK_EQ(*immedPredBlockP, origBlock);
192 *immedPredBlockP = bottomBlock;
193 }
buzbee67bf8852011-08-17 17:51:35 -0700194 return bottomBlock;
195}
196
197/*
198 * Given a code offset, find out the block that starts with it. If the offset
buzbee9ab05de2012-01-18 15:43:48 -0800199 * is in the middle of an existing block, split it into two. If immedPredBlockP
200 * is not non-null and is the block being split, update *immedPredBlockP to
201 * point to the bottom block so that outgoing edges can be set up properly
202 * (by the caller)
buzbee5b537102012-01-17 17:33:47 -0800203 * Utilizes a map for fast lookup of the typical cases.
buzbee67bf8852011-08-17 17:51:35 -0700204 */
buzbee31a4a6f2012-02-28 15:36:15 -0800205BasicBlock *findBlock(CompilationUnit* cUnit, unsigned int codeOffset,
206 bool split, bool create, BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700207{
208 GrowableList* blockList = &cUnit->blockList;
209 BasicBlock* bb;
210 unsigned int i;
buzbee5b537102012-01-17 17:33:47 -0800211 std::map<unsigned int, BasicBlock*>::iterator it;
buzbee67bf8852011-08-17 17:51:35 -0700212
buzbee5b537102012-01-17 17:33:47 -0800213 it = cUnit->blockMap.find(codeOffset);
214 if (it != cUnit->blockMap.end()) {
215 return it->second;
216 } else if (!create) {
217 return NULL;
218 }
219
220 if (split) {
221 for (i = 0; i < blockList->numUsed; i++) {
222 bb = (BasicBlock *) blockList->elemList[i];
223 if (bb->blockType != kDalvikByteCode) continue;
224 /* Check if a branch jumps into the middle of an existing block */
225 if ((codeOffset > bb->startOffset) && (bb->lastMIRInsn != NULL) &&
226 (codeOffset <= bb->lastMIRInsn->offset)) {
227 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb,
228 bb == *immedPredBlockP ?
229 immedPredBlockP : NULL);
230 return newBB;
231 }
buzbee67bf8852011-08-17 17:51:35 -0700232 }
233 }
buzbee5b537102012-01-17 17:33:47 -0800234
235 /* Create a new one */
buzbee5abfa3e2012-01-31 17:01:43 -0800236 bb = oatNewBB(cUnit, kDalvikByteCode, cUnit->numBlocks++);
buzbeeba938cb2012-02-03 14:47:55 -0800237 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) bb);
buzbee5b537102012-01-17 17:33:47 -0800238 bb->startOffset = codeOffset;
239 cUnit->blockMap.insert(std::make_pair(bb->startOffset, bb));
240 return bb;
buzbee67bf8852011-08-17 17:51:35 -0700241}
242
243/* Dump the CFG into a DOT graph */
244void oatDumpCFG(CompilationUnit* cUnit, const char* dirPrefix)
245{
buzbee67bf8852011-08-17 17:51:35 -0700246 FILE* file;
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800247 std::string name(PrettyMethod(cUnit->method_idx, *cUnit->dex_file));
buzbee67bf8852011-08-17 17:51:35 -0700248 char startOffset[80];
249 sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
buzbeeba938cb2012-02-03 14:47:55 -0800250 char* fileName = (char*) oatNew(cUnit,
buzbeec143c552011-08-20 17:38:58 -0700251 strlen(dirPrefix) +
252 name.length() +
buzbee5abfa3e2012-01-31 17:01:43 -0800253 strlen(".dot") + 1, true, kAllocDebugInfo);
buzbeec143c552011-08-20 17:38:58 -0700254 sprintf(fileName, "%s%s%s.dot", dirPrefix, name.c_str(), startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700255
256 /*
257 * Convert the special characters into a filesystem- and shell-friendly
258 * format.
259 */
260 int i;
261 for (i = strlen(dirPrefix); fileName[i]; i++) {
262 if (fileName[i] == '/') {
263 fileName[i] = '_';
264 } else if (fileName[i] == ';') {
265 fileName[i] = '#';
266 } else if (fileName[i] == '$') {
267 fileName[i] = '+';
268 } else if (fileName[i] == '(' || fileName[i] == ')') {
269 fileName[i] = '@';
270 } else if (fileName[i] == '<' || fileName[i] == '>') {
271 fileName[i] = '=';
272 }
273 }
274 file = fopen(fileName, "w");
275 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,
Elliott Hughesadb8c672012-03-06 16:49:32 -0800303 mir->ssaRep ? oatFullDisassembler(cUnit, mir) : Instruction::Name(mir->dalvikInsn.opcode),
buzbee67bf8852011-08-17 17:51:35 -0700304 mir->next ? " | " : " ");
305 }
306 fprintf(file, " }\"];\n\n");
307 } else if (bb->blockType == kExceptionHandling) {
308 char blockName[BLOCK_NAME_LEN];
309
310 oatGetBlockName(bb, blockName);
311 fprintf(file, " %s [shape=invhouse];\n", blockName);
312 }
313
314 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
315
316 if (bb->taken) {
317 oatGetBlockName(bb, blockName1);
318 oatGetBlockName(bb->taken, blockName2);
319 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
320 blockName1, blockName2);
321 }
322 if (bb->fallThrough) {
323 oatGetBlockName(bb, blockName1);
324 oatGetBlockName(bb->fallThrough, blockName2);
325 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
326 }
327
328 if (bb->successorBlockList.blockListType != kNotUsed) {
329 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
330 bb->startOffset,
331 (bb->successorBlockList.blockListType == kCatch) ?
332 "Mrecord" : "record");
333 GrowableListIterator iterator;
334 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
335 &iterator);
336 SuccessorBlockInfo *successorBlockInfo =
337 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
338
339 int succId = 0;
340 while (true) {
341 if (successorBlockInfo == NULL) break;
342
343 BasicBlock *destBlock = successorBlockInfo->block;
344 SuccessorBlockInfo *nextSuccessorBlockInfo =
345 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
346
347 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
348 succId++,
349 successorBlockInfo->key,
350 destBlock->startOffset,
351 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
352
353 successorBlockInfo = nextSuccessorBlockInfo;
354 }
355 fprintf(file, " }\"];\n\n");
356
357 oatGetBlockName(bb, blockName1);
358 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
359 blockName1, bb->startOffset);
360
361 if (bb->successorBlockList.blockListType == kPackedSwitch ||
362 bb->successorBlockList.blockListType == kSparseSwitch) {
363
364 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
365 &iterator);
366
367 succId = 0;
368 while (true) {
369 SuccessorBlockInfo *successorBlockInfo =
370 (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",
378 bb->startOffset, succId++,
379 blockName2);
380 }
381 }
382 }
383 fprintf(file, "\n");
384
buzbeece302932011-10-04 14:32:18 -0700385 /* Display the dominator tree */
buzbee67bf8852011-08-17 17:51:35 -0700386 oatGetBlockName(bb, blockName1);
387 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
388 blockName1, blockName1);
389 if (bb->iDom) {
390 oatGetBlockName(bb->iDom, blockName2);
391 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
392 blockName2, blockName1);
393 }
buzbee67bf8852011-08-17 17:51:35 -0700394 }
395 fprintf(file, "}\n");
396 fclose(file);
397}
398
399/* Verify if all the successor is connected with all the claimed predecessors */
buzbee31a4a6f2012-02-28 15:36:15 -0800400bool verifyPredInfo(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -0700401{
buzbee5abfa3e2012-01-31 17:01:43 -0800402 GrowableListIterator iter;
buzbee67bf8852011-08-17 17:51:35 -0700403
buzbee5abfa3e2012-01-31 17:01:43 -0800404 oatGrowableListIteratorInit(bb->predecessors, &iter);
buzbee67bf8852011-08-17 17:51:35 -0700405 while (true) {
buzbee5abfa3e2012-01-31 17:01:43 -0800406 BasicBlock *predBB = (BasicBlock*)oatGrowableListIteratorNext(&iter);
407 if (!predBB) break;
buzbee67bf8852011-08-17 17:51:35 -0700408 bool found = false;
409 if (predBB->taken == bb) {
410 found = true;
411 } else if (predBB->fallThrough == bb) {
412 found = true;
413 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
414 GrowableListIterator iterator;
415 oatGrowableListIteratorInit(&predBB->successorBlockList.blocks,
416 &iterator);
417 while (true) {
418 SuccessorBlockInfo *successorBlockInfo =
419 (SuccessorBlockInfo *)
420 oatGrowableListIteratorNext(&iterator);
421 if (successorBlockInfo == NULL) break;
422 BasicBlock *succBB = successorBlockInfo->block;
423 if (succBB == bb) {
424 found = true;
425 break;
426 }
427 }
428 }
429 if (found == false) {
430 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
431 oatGetBlockName(bb, blockName1);
432 oatGetBlockName(predBB, blockName2);
433 oatDumpCFG(cUnit, "/sdcard/cfg/");
434 LOG(FATAL) << "Successor " << blockName1 << "not found from "
435 << blockName2;
436 }
437 }
438 return true;
439}
440
441/* Identify code range in try blocks and set up the empty catch blocks */
buzbee31a4a6f2012-02-28 15:36:15 -0800442void processTryCatchBlocks(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700443{
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800444 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbeee9a72f62011-09-04 17:59:07 -0700445 int triesSize = code_item->tries_size_;
buzbee67bf8852011-08-17 17:51:35 -0700446 int offset;
447
448 if (triesSize == 0) {
449 return;
450 }
451
buzbee67bf8852011-08-17 17:51:35 -0700452 ArenaBitVector* tryBlockAddr = cUnit->tryBlockAddr;
453
buzbeee9a72f62011-09-04 17:59:07 -0700454 for (int i = 0; i < triesSize; i++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800455 const DexFile::TryItem* pTry =
456 DexFile::GetTryItems(*code_item, i);
buzbeee9a72f62011-09-04 17:59:07 -0700457 int startOffset = pTry->start_addr_;
458 int endOffset = startOffset + pTry->insn_count_;
buzbee67bf8852011-08-17 17:51:35 -0700459 for (offset = startOffset; offset < endOffset; offset++) {
buzbeeba938cb2012-02-03 14:47:55 -0800460 oatSetBit(cUnit, tryBlockAddr, offset);
buzbee67bf8852011-08-17 17:51:35 -0700461 }
462 }
463
buzbeee9a72f62011-09-04 17:59:07 -0700464 // Iterate over each of the handlers to enqueue the empty Catch blocks
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800465 const byte* handlers_ptr =
466 DexFile::GetCatchHandlerData(*code_item, 0);
467 uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
buzbeee9a72f62011-09-04 17:59:07 -0700468 for (uint32_t idx = 0; idx < handlers_size; idx++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800469 CatchHandlerIterator iterator(handlers_ptr);
Ian Rogers0571d352011-11-03 19:51:38 -0700470 for (; iterator.HasNext(); iterator.Next()) {
471 uint32_t address = iterator.GetHandlerAddress();
buzbee9ab05de2012-01-18 15:43:48 -0800472 findBlock(cUnit, address, false /* split */, true /*create*/,
473 /* immedPredBlockP */ NULL);
buzbee67bf8852011-08-17 17:51:35 -0700474 }
Ian Rogers0571d352011-11-03 19:51:38 -0700475 handlers_ptr = iterator.EndDataPointer();
buzbee67bf8852011-08-17 17:51:35 -0700476 }
477}
478
Elliott Hughesadb8c672012-03-06 16:49:32 -0800479/* Process instructions with the kBranch flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800480BasicBlock* processCanBranch(CompilationUnit* cUnit, BasicBlock* curBlock,
481 MIR* insn, int curOffset, int width, int flags,
482 const u2* codePtr, const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700483{
484 int target = curOffset;
485 switch (insn->dalvikInsn.opcode) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800486 case Instruction::GOTO:
487 case Instruction::GOTO_16:
488 case Instruction::GOTO_32:
buzbee67bf8852011-08-17 17:51:35 -0700489 target += (int) insn->dalvikInsn.vA;
490 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800491 case Instruction::IF_EQ:
492 case Instruction::IF_NE:
493 case Instruction::IF_LT:
494 case Instruction::IF_GE:
495 case Instruction::IF_GT:
496 case Instruction::IF_LE:
buzbee67bf8852011-08-17 17:51:35 -0700497 target += (int) insn->dalvikInsn.vC;
498 break;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800499 case Instruction::IF_EQZ:
500 case Instruction::IF_NEZ:
501 case Instruction::IF_LTZ:
502 case Instruction::IF_GEZ:
503 case Instruction::IF_GTZ:
504 case Instruction::IF_LEZ:
buzbee67bf8852011-08-17 17:51:35 -0700505 target += (int) insn->dalvikInsn.vB;
506 break;
507 default:
508 LOG(FATAL) << "Unexpected opcode(" << (int)insn->dalvikInsn.opcode
Elliott Hughesadb8c672012-03-06 16:49:32 -0800509 << ") with kBranch set";
buzbee67bf8852011-08-17 17:51:35 -0700510 }
511 BasicBlock *takenBlock = findBlock(cUnit, target,
512 /* split */
513 true,
514 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800515 true,
516 /* immedPredBlockP */
517 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700518 curBlock->taken = takenBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800519 oatInsertGrowableList(cUnit, takenBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700520
521 /* Always terminate the current block for conditional branches */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800522 if (flags & Instruction::kContinue) {
buzbee67bf8852011-08-17 17:51:35 -0700523 BasicBlock *fallthroughBlock = findBlock(cUnit,
524 curOffset + width,
525 /*
526 * If the method is processed
527 * in sequential order from the
528 * beginning, we don't need to
529 * specify split for continue
530 * blocks. However, this
531 * routine can be called by
532 * compileLoop, which starts
533 * parsing the method from an
534 * arbitrary address in the
535 * method body.
536 */
537 true,
538 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800539 true,
540 /* immedPredBlockP */
541 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700542 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800543 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800544 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700545 } else if (codePtr < codeEnd) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800546 /* Create a fallthrough block for real instructions (incl. NOP) */
buzbee67bf8852011-08-17 17:51:35 -0700547 if (contentIsInsn(codePtr)) {
548 findBlock(cUnit, curOffset + width,
549 /* split */
550 false,
551 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800552 true,
553 /* immedPredBlockP */
554 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700555 }
556 }
buzbeee941e2c2011-12-05 12:38:17 -0800557 return curBlock;
buzbee67bf8852011-08-17 17:51:35 -0700558}
559
Elliott Hughesadb8c672012-03-06 16:49:32 -0800560/* Process instructions with the kSwitch flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800561void processCanSwitch(CompilationUnit* cUnit, BasicBlock* curBlock,
562 MIR* insn, int curOffset, int width, int flags)
buzbee67bf8852011-08-17 17:51:35 -0700563{
564 u2* switchData= (u2 *) (cUnit->insns + curOffset +
565 insn->dalvikInsn.vB);
566 int size;
567 int* keyTable;
568 int* targetTable;
569 int i;
570 int firstKey;
571
572 /*
573 * Packed switch data format:
574 * ushort ident = 0x0100 magic value
575 * ushort size number of entries in the table
576 * int first_key first (and lowest) switch case value
577 * int targets[size] branch targets, relative to switch opcode
578 *
579 * Total size is (4+size*2) 16-bit code units.
580 */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800581 if (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) {
582 DCHECK_EQ(static_cast<int>(switchData[0]), static_cast<int>(Instruction::kPackedSwitchSignature));
buzbee67bf8852011-08-17 17:51:35 -0700583 size = switchData[1];
584 firstKey = switchData[2] | (switchData[3] << 16);
585 targetTable = (int *) &switchData[4];
586 keyTable = NULL; // Make the compiler happy
587 /*
588 * Sparse switch data format:
589 * ushort ident = 0x0200 magic value
590 * ushort size number of entries in the table; > 0
591 * int keys[size] keys, sorted low-to-high; 32-bit aligned
592 * int targets[size] branch targets, relative to switch opcode
593 *
594 * Total size is (2+size*4) 16-bit code units.
595 */
596 } else {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800597 DCHECK_EQ(static_cast<int>(switchData[0]), static_cast<int>(Instruction::kSparseSwitchSignature));
buzbee67bf8852011-08-17 17:51:35 -0700598 size = switchData[1];
599 keyTable = (int *) &switchData[2];
600 targetTable = (int *) &switchData[2 + size*2];
601 firstKey = 0; // To make the compiler happy
602 }
603
604 if (curBlock->successorBlockList.blockListType != kNotUsed) {
605 LOG(FATAL) << "Successor block list already in use: " <<
606 (int)curBlock->successorBlockList.blockListType;
607 }
608 curBlock->successorBlockList.blockListType =
Elliott Hughesadb8c672012-03-06 16:49:32 -0800609 (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) ?
buzbee67bf8852011-08-17 17:51:35 -0700610 kPackedSwitch : kSparseSwitch;
buzbeeba938cb2012-02-03 14:47:55 -0800611 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, size,
buzbee5abfa3e2012-01-31 17:01:43 -0800612 kListSuccessorBlocks);
buzbee67bf8852011-08-17 17:51:35 -0700613
614 for (i = 0; i < size; i++) {
615 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
616 /* split */
617 true,
618 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800619 true,
620 /* immedPredBlockP */
621 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700622 SuccessorBlockInfo *successorBlockInfo =
buzbeeba938cb2012-02-03 14:47:55 -0800623 (SuccessorBlockInfo *) oatNew(cUnit, sizeof(SuccessorBlockInfo),
624 false, kAllocSuccessor);
buzbee67bf8852011-08-17 17:51:35 -0700625 successorBlockInfo->block = caseBlock;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800626 successorBlockInfo->key = (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH)?
buzbee67bf8852011-08-17 17:51:35 -0700627 firstKey + i : keyTable[i];
buzbeeba938cb2012-02-03 14:47:55 -0800628 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
buzbee67bf8852011-08-17 17:51:35 -0700629 (intptr_t) successorBlockInfo);
buzbeeba938cb2012-02-03 14:47:55 -0800630 oatInsertGrowableList(cUnit, caseBlock->predecessors,
631 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700632 }
633
634 /* Fall-through case */
635 BasicBlock* fallthroughBlock = findBlock(cUnit,
636 curOffset + width,
637 /* split */
638 false,
639 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800640 true,
641 /* immedPredBlockP */
642 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700643 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800644 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
645 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700646}
647
Elliott Hughesadb8c672012-03-06 16:49:32 -0800648/* Process instructions with the kThrow flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800649void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock, MIR* insn,
650 int curOffset, int width, int flags,
651 ArenaBitVector* tryBlockAddr, const u2* codePtr,
652 const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700653{
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800654 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbee67bf8852011-08-17 17:51:35 -0700655
656 /* In try block */
657 if (oatIsBitSet(tryBlockAddr, curOffset)) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800658 CatchHandlerIterator iterator(*code_item, curOffset);
buzbee67bf8852011-08-17 17:51:35 -0700659
buzbee67bf8852011-08-17 17:51:35 -0700660 if (curBlock->successorBlockList.blockListType != kNotUsed) {
661 LOG(FATAL) << "Successor block list already in use: " <<
662 (int)curBlock->successorBlockList.blockListType;
663 }
buzbeee9a72f62011-09-04 17:59:07 -0700664
buzbee67bf8852011-08-17 17:51:35 -0700665 curBlock->successorBlockList.blockListType = kCatch;
buzbeeba938cb2012-02-03 14:47:55 -0800666 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, 2,
buzbee5abfa3e2012-01-31 17:01:43 -0800667 kListSuccessorBlocks);
buzbee67bf8852011-08-17 17:51:35 -0700668
Ian Rogers0571d352011-11-03 19:51:38 -0700669 for (;iterator.HasNext(); iterator.Next()) {
670 BasicBlock *catchBlock = findBlock(cUnit, iterator.GetHandlerAddress(),
buzbeee9a72f62011-09-04 17:59:07 -0700671 false /* split*/,
buzbee9ab05de2012-01-18 15:43:48 -0800672 false /* creat */,
673 NULL /* immedPredBlockP */);
buzbee43a36422011-09-14 14:00:13 -0700674 catchBlock->catchEntry = true;
buzbeeba938cb2012-02-03 14:47:55 -0800675 SuccessorBlockInfo *successorBlockInfo = (SuccessorBlockInfo *)
676 oatNew(cUnit, sizeof(SuccessorBlockInfo), false,
677 kAllocSuccessor);
buzbee67bf8852011-08-17 17:51:35 -0700678 successorBlockInfo->block = catchBlock;
Ian Rogers0571d352011-11-03 19:51:38 -0700679 successorBlockInfo->key = iterator.GetHandlerTypeIndex();
buzbeeba938cb2012-02-03 14:47:55 -0800680 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
buzbee67bf8852011-08-17 17:51:35 -0700681 (intptr_t) successorBlockInfo);
buzbeeba938cb2012-02-03 14:47:55 -0800682 oatInsertGrowableList(cUnit, catchBlock->predecessors,
683 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700684 }
685 } else {
buzbee5abfa3e2012-01-31 17:01:43 -0800686 BasicBlock *ehBlock = oatNewBB(cUnit, kExceptionHandling,
687 cUnit->numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700688 curBlock->taken = ehBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800689 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) ehBlock);
buzbee67bf8852011-08-17 17:51:35 -0700690 ehBlock->startOffset = curOffset;
buzbeeba938cb2012-02-03 14:47:55 -0800691 oatInsertGrowableList(cUnit, ehBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700692 }
693
694 /*
695 * Force the current block to terminate.
696 *
697 * Data may be present before codeEnd, so we need to parse it to know
698 * whether it is code or data.
699 */
700 if (codePtr < codeEnd) {
Elliott Hughesadb8c672012-03-06 16:49:32 -0800701 /* Create a fallthrough block for real instructions (incl. NOP) */
buzbee67bf8852011-08-17 17:51:35 -0700702 if (contentIsInsn(codePtr)) {
703 BasicBlock *fallthroughBlock = findBlock(cUnit,
704 curOffset + width,
705 /* split */
706 false,
707 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800708 true,
709 /* immedPredBlockP */
710 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700711 /*
Elliott Hughesadb8c672012-03-06 16:49:32 -0800712 * THROW is an unconditional branch. NOTE:
713 * THROW_VERIFICATION_ERROR is also an unconditional
buzbee510c6052011-10-27 10:47:20 -0700714 * branch, but we shouldn't treat it as such until we have
715 * a dead code elimination pass (which won't be important
716 * until inlining w/ constant propogation is implemented.
buzbee67bf8852011-08-17 17:51:35 -0700717 */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800718 if (insn->dalvikInsn.opcode != Instruction::THROW) {
buzbee67bf8852011-08-17 17:51:35 -0700719 curBlock->fallThrough = fallthroughBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800720 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800721 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700722 }
723 }
724 }
725}
726
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800727void oatInit(CompilationUnit* cUnit, const Compiler& compiler) {
728 if (!oatArchInit()) {
729 LOG(FATAL) << "Failed to initialize oat";
730 }
731 if (!oatHeapInit(cUnit)) {
732 LOG(FATAL) << "Failed to initialize oat heap";
733 }
734}
735
736CompiledMethod* oatCompileMethodInternal(Compiler& compiler,
737 const DexFile::CodeItem* code_item,
738 uint32_t access_flags, uint32_t method_idx,
739 const ClassLoader* class_loader,
740 const DexFile& dex_file)
buzbee67bf8852011-08-17 17:51:35 -0700741{
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800742 VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
Brian Carlstrom94496d32011-08-22 09:22:47 -0700743
buzbeec143c552011-08-20 17:38:58 -0700744 const u2* codePtr = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700745 const u2* codeEnd = code_item->insns_ + code_item->insns_size_in_code_units_;
buzbee67bf8852011-08-17 17:51:35 -0700746 int numBlocks = 0;
747 unsigned int curOffset = 0;
748
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800749 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700750 UniquePtr<CompilationUnit> cUnit(new CompilationUnit);
751 memset(cUnit.get(), 0, sizeof(*cUnit));
buzbeeba938cb2012-02-03 14:47:55 -0800752
753 oatInit(cUnit.get(), compiler);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800754
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700755 cUnit->compiler = &compiler;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800756 cUnit->class_linker = class_linker;
757 cUnit->dex_file = &dex_file;
758 cUnit->dex_cache = class_linker->FindDexCache(dex_file);
759 cUnit->method_idx = method_idx;
760 cUnit->code_item = code_item;
761 cUnit->access_flags = access_flags;
762 cUnit->shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800763 cUnit->instructionSet = compiler.GetInstructionSet();
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700764 cUnit->insns = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700765 cUnit->insnsSize = code_item->insns_size_in_code_units_;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800766 cUnit->numIns = code_item->ins_size_;
767 cUnit->numRegs = code_item->registers_size_ - cUnit->numIns;
768 cUnit->numOuts = code_item->outs_size_;
769 /* Adjust this value accordingly once inlining is performed */
770 cUnit->numDalvikRegisters = code_item->registers_size_;
buzbee5b537102012-01-17 17:33:47 -0800771 cUnit->blockMap = std::map<unsigned int, BasicBlock*>();
772 cUnit->blockMap.clear();
buzbee85d8c1e2012-01-27 15:52:35 -0800773 cUnit->boundaryMap = std::map<unsigned int, LIR*>();
774 cUnit->boundaryMap.clear();
buzbeeba938cb2012-02-03 14:47:55 -0800775 // TODO: set these from command line
776 cUnit->compilerMethodMatch = new std::string("");
777 cUnit->compilerFlipMatch = false;
778 bool useMatch = cUnit->compilerMethodMatch->length() != 0;
779 bool match = useMatch && (cUnit->compilerFlipMatch ^
780 (PrettyMethod(method_idx, dex_file).find(*cUnit->compilerMethodMatch)
781 != std::string::npos));
buzbeece302932011-10-04 14:32:18 -0700782 if (!useMatch || match) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700783 cUnit->disableOpt = compilerOptimizerDisableFlags;
784 cUnit->enableDebug = compilerDebugFlags;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800785 cUnit->printMe = VLOG_IS_ON(compiler) || (cUnit->enableDebug & (1 << kDebugVerbose));
buzbeece302932011-10-04 14:32:18 -0700786 }
buzbee67bf8852011-08-17 17:51:35 -0700787
buzbee44b412b2012-02-04 08:50:53 -0800788 /* Are we generating code for the debugger? */
Elliott Hughesde6e4cf2012-02-27 14:46:06 -0800789 if (compiler.IsDebuggingSupported()) {
buzbee44b412b2012-02-04 08:50:53 -0800790 cUnit->genDebugger = true;
791 // Yes, disable most optimizations
792 cUnit->disableOpt |= (
793 (1 << kLoadStoreElimination) |
794 (1 << kLoadHoisting) |
795 (1 << kSuppressLoads) |
796 (1 << kPromoteRegs) |
797 (1 << kTrackLiveTemps));
798 }
799
buzbeecefd1872011-09-09 09:59:52 -0700800 /* Assume non-throwing leaf */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700801 cUnit->attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
buzbeecefd1872011-09-09 09:59:52 -0700802
buzbee5abfa3e2012-01-31 17:01:43 -0800803 /* Initialize the block list, estimate size based on insnsSize */
buzbeeba938cb2012-02-03 14:47:55 -0800804 oatInitGrowableList(cUnit.get(), &cUnit->blockList, cUnit->insnsSize,
805 kListBlockList);
buzbee67bf8852011-08-17 17:51:35 -0700806
807 /* Initialize the switchTables list */
buzbeeba938cb2012-02-03 14:47:55 -0800808 oatInitGrowableList(cUnit.get(), &cUnit->switchTables, 4,
809 kListSwitchTables);
buzbee67bf8852011-08-17 17:51:35 -0700810
811 /* Intialize the fillArrayData list */
buzbeeba938cb2012-02-03 14:47:55 -0800812 oatInitGrowableList(cUnit.get(), &cUnit->fillArrayData, 4,
813 kListFillArrayData);
buzbee67bf8852011-08-17 17:51:35 -0700814
buzbee5abfa3e2012-01-31 17:01:43 -0800815 /* Intialize the throwLaunchpads list, estimate size based on insnsSize */
buzbeeba938cb2012-02-03 14:47:55 -0800816 oatInitGrowableList(cUnit.get(), &cUnit->throwLaunchpads, cUnit->insnsSize,
buzbee5abfa3e2012-01-31 17:01:43 -0800817 kListThrowLaunchPads);
buzbee5ade1d22011-09-09 14:44:52 -0700818
buzbeec1f45042011-09-21 16:03:19 -0700819 /* Intialize the suspendLaunchpads list */
buzbeeba938cb2012-02-03 14:47:55 -0800820 oatInitGrowableList(cUnit.get(), &cUnit->suspendLaunchpads, 2048,
buzbee5abfa3e2012-01-31 17:01:43 -0800821 kListSuspendLaunchPads);
buzbeec1f45042011-09-21 16:03:19 -0700822
buzbee67bf8852011-08-17 17:51:35 -0700823 /* Allocate the bit-vector to track the beginning of basic blocks */
buzbeeba938cb2012-02-03 14:47:55 -0800824 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit.get(),
825 cUnit->insnsSize,
buzbee67bf8852011-08-17 17:51:35 -0700826 true /* expandable */);
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700827 cUnit->tryBlockAddr = tryBlockAddr;
buzbee67bf8852011-08-17 17:51:35 -0700828
829 /* Create the default entry and exit blocks and enter them to the list */
buzbee5abfa3e2012-01-31 17:01:43 -0800830 BasicBlock *entryBlock = oatNewBB(cUnit.get(), kEntryBlock, numBlocks++);
831 BasicBlock *exitBlock = oatNewBB(cUnit.get(), kExitBlock, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700832
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700833 cUnit->entryBlock = entryBlock;
834 cUnit->exitBlock = exitBlock;
buzbee67bf8852011-08-17 17:51:35 -0700835
buzbeeba938cb2012-02-03 14:47:55 -0800836 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) entryBlock);
837 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) exitBlock);
buzbee67bf8852011-08-17 17:51:35 -0700838
839 /* Current block to record parsed instructions */
buzbee5abfa3e2012-01-31 17:01:43 -0800840 BasicBlock *curBlock = oatNewBB(cUnit.get(), kDalvikByteCode, numBlocks++);
buzbee67bf8852011-08-17 17:51:35 -0700841 curBlock->startOffset = 0;
buzbeeba938cb2012-02-03 14:47:55 -0800842 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) curBlock);
buzbee5b537102012-01-17 17:33:47 -0800843 /* Add first block to the fast lookup cache */
844 cUnit->blockMap.insert(std::make_pair(curBlock->startOffset, curBlock));
buzbee67bf8852011-08-17 17:51:35 -0700845 entryBlock->fallThrough = curBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800846 oatInsertGrowableList(cUnit.get(), curBlock->predecessors,
847 (intptr_t)entryBlock);
buzbee67bf8852011-08-17 17:51:35 -0700848
849 /*
850 * Store back the number of blocks since new blocks may be created of
851 * accessing cUnit.
852 */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700853 cUnit->numBlocks = numBlocks;
buzbee67bf8852011-08-17 17:51:35 -0700854
855 /* Identify code range in try blocks and set up the empty catch blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700856 processTryCatchBlocks(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700857
858 /* Parse all instructions and put them into containing basic blocks */
859 while (codePtr < codeEnd) {
buzbeeba938cb2012-02-03 14:47:55 -0800860 MIR *insn = (MIR *) oatNew(cUnit.get(), sizeof(MIR), true, kAllocMIR);
buzbee67bf8852011-08-17 17:51:35 -0700861 insn->offset = curOffset;
buzbeeba938cb2012-02-03 14:47:55 -0800862 int width = parseInsn(cUnit.get(), codePtr, &insn->dalvikInsn, false);
buzbee67bf8852011-08-17 17:51:35 -0700863 insn->width = width;
864
865 /* Terminate when the data section is seen */
866 if (width == 0)
867 break;
868
869 oatAppendMIR(curBlock, insn);
870
871 codePtr += width;
Elliott Hughesadb8c672012-03-06 16:49:32 -0800872 int flags = Instruction::Flags(insn->dalvikInsn.opcode);
buzbee67bf8852011-08-17 17:51:35 -0700873
buzbee5abfa3e2012-01-31 17:01:43 -0800874 int dfFlags = oatDataFlowAttributes[insn->dalvikInsn.opcode];
875
876 if (dfFlags & DF_HAS_DEFS) {
877 cUnit->defCount += (dfFlags & DF_DA_WIDE) ? 2 : 1;
878 }
buzbee99ba9642012-01-25 14:23:14 -0800879
Elliott Hughesadb8c672012-03-06 16:49:32 -0800880 if (flags & Instruction::kBranch) {
buzbeee941e2c2011-12-05 12:38:17 -0800881 curBlock = processCanBranch(cUnit.get(), curBlock, insn, curOffset,
882 width, flags, codePtr, codeEnd);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800883 } else if (flags & Instruction::kReturn) {
buzbee67bf8852011-08-17 17:51:35 -0700884 curBlock->fallThrough = exitBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800885 oatInsertGrowableList(cUnit.get(), exitBlock->predecessors,
886 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700887 /*
888 * Terminate the current block if there are instructions
889 * afterwards.
890 */
891 if (codePtr < codeEnd) {
892 /*
893 * Create a fallthrough block for real instructions
Elliott Hughesadb8c672012-03-06 16:49:32 -0800894 * (incl. NOP).
buzbee67bf8852011-08-17 17:51:35 -0700895 */
896 if (contentIsInsn(codePtr)) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700897 findBlock(cUnit.get(), curOffset + width,
buzbee67bf8852011-08-17 17:51:35 -0700898 /* split */
899 false,
900 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800901 true,
902 /* immedPredBlockP */
903 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700904 }
905 }
Elliott Hughesadb8c672012-03-06 16:49:32 -0800906 } else if (flags & Instruction::kThrow) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700907 processCanThrow(cUnit.get(), curBlock, insn, curOffset, width, flags,
buzbee67bf8852011-08-17 17:51:35 -0700908 tryBlockAddr, codePtr, codeEnd);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800909 } else if (flags & Instruction::kSwitch) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700910 processCanSwitch(cUnit.get(), curBlock, insn, curOffset, width, flags);
buzbee67bf8852011-08-17 17:51:35 -0700911 }
912 curOffset += width;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700913 BasicBlock *nextBlock = findBlock(cUnit.get(), curOffset,
buzbee67bf8852011-08-17 17:51:35 -0700914 /* split */
915 false,
916 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800917 false,
918 /* immedPredBlockP */
919 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700920 if (nextBlock) {
921 /*
922 * The next instruction could be the target of a previously parsed
923 * forward branch so a block is already created. If the current
924 * instruction is not an unconditional branch, connect them through
925 * the fall-through link.
926 */
buzbeeed3e9302011-09-23 17:34:19 -0700927 DCHECK(curBlock->fallThrough == NULL ||
buzbee67bf8852011-08-17 17:51:35 -0700928 curBlock->fallThrough == nextBlock ||
929 curBlock->fallThrough == exitBlock);
930
Elliott Hughesadb8c672012-03-06 16:49:32 -0800931 if ((curBlock->fallThrough == NULL) && (flags & Instruction::kContinue)) {
buzbee67bf8852011-08-17 17:51:35 -0700932 curBlock->fallThrough = nextBlock;
buzbeeba938cb2012-02-03 14:47:55 -0800933 oatInsertGrowableList(cUnit.get(), nextBlock->predecessors,
buzbee5abfa3e2012-01-31 17:01:43 -0800934 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700935 }
936 curBlock = nextBlock;
937 }
938 }
939
buzbee5abfa3e2012-01-31 17:01:43 -0800940 if (!(cUnit->disableOpt & (1 << kSkipLargeMethodOptimization))) {
buzbee99ba9642012-01-25 14:23:14 -0800941 if ((cUnit->numBlocks > MANY_BLOCKS) ||
942 ((cUnit->numBlocks > MANY_BLOCKS_INITIALIZER) &&
943 PrettyMethod(method_idx, dex_file).find("init>") !=
944 std::string::npos)) {
945 cUnit->disableDataflow = true;
946 // Disable optimization which require dataflow/ssa
947 cUnit->disableOpt |=
948 (1 << kNullCheckElimination) |
949 (1 << kPromoteRegs);
950 if (cUnit->printMe) {
951 LOG(INFO) << "Compiler: " << PrettyMethod(method_idx, dex_file)
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800952 << " too big: " << cUnit->numBlocks;
buzbee99ba9642012-01-25 14:23:14 -0800953 }
954 }
955 }
956
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700957 if (cUnit->printMe) {
958 oatDumpCompilationUnit(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700959 }
960
buzbee5b537102012-01-17 17:33:47 -0800961 if (cUnit->enableDebug & (1 << kDebugVerifyDataflow)) {
962 /* Verify if all blocks are connected as claimed */
buzbee5abfa3e2012-01-31 17:01:43 -0800963 oatDataFlowAnalysisDispatcher(cUnit.get(), verifyPredInfo, kAllNodes,
964 false /* isIterative */);
buzbee5b537102012-01-17 17:33:47 -0800965 }
buzbee67bf8852011-08-17 17:51:35 -0700966
967 /* Perform SSA transformation for the whole method */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700968 oatMethodSSATransformation(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700969
buzbee43a36422011-09-14 14:00:13 -0700970 /* Perform null check elimination */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700971 oatMethodNullCheckElimination(cUnit.get());
buzbee43a36422011-09-14 14:00:13 -0700972
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700973 oatInitializeRegAlloc(cUnit.get()); // Needs to happen after SSA naming
buzbee67bf8852011-08-17 17:51:35 -0700974
975 /* Allocate Registers using simple local allocation scheme */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700976 oatSimpleRegAlloc(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700977
978 /* Convert MIR to LIR, etc. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700979 oatMethodMIR2LIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700980
981 // Debugging only
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700982 if (cUnit->enableDebug & (1 << kDebugDumpCFG)) {
983 oatDumpCFG(cUnit.get(), "/sdcard/cfg/");
buzbeeec5adf32011-09-11 15:25:43 -0700984 }
buzbee67bf8852011-08-17 17:51:35 -0700985
986 /* Method is not empty */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700987 if (cUnit->firstLIRInsn) {
buzbee67bf8852011-08-17 17:51:35 -0700988
989 // mark the targets of switch statement case labels
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700990 oatProcessSwitchTables(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700991
992 /* Convert LIR into machine code. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700993 oatAssembleLIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700994
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700995 if (cUnit->printMe) {
996 oatCodegenDump(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700997 }
998 }
999
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001000 // Combine vmap tables - core regs, then fp regs - into vmapTable
1001 std::vector<uint16_t> vmapTable;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001002 for (size_t i = 0 ; i < cUnit->coreVmapTable.size(); i++) {
1003 vmapTable.push_back(cUnit->coreVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001004 }
buzbeec41e5b52011-09-23 12:46:19 -07001005 // Add a marker to take place of lr
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -07001006 vmapTable.push_back(INVALID_VREG);
buzbeec41e5b52011-09-23 12:46:19 -07001007 // Combine vmap tables - core regs, then fp regs
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001008 for (uint32_t i = 0; i < cUnit->fpVmapTable.size(); i++) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001009 vmapTable.push_back(cUnit->fpVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001010 }
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -07001011 DCHECK_EQ(vmapTable.size(),
1012 static_cast<uint32_t>(__builtin_popcount(cUnit->coreSpillMask)
1013 + __builtin_popcount(cUnit->fpSpillMask)));
1014 DCHECK_GE(vmapTable.size(), 1U); // should always at least one INVALID_VREG for lr
1015
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001016 CompiledMethod* result = new CompiledMethod(kThumb2, cUnit->codeBuffer,
Ian Rogers0571d352011-11-03 19:51:38 -07001017 cUnit->frameSize, cUnit->coreSpillMask,
1018 cUnit->fpSpillMask, cUnit->mappingTable,
1019 vmapTable);
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001020
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -08001021 VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file)
buzbee5abfa3e2012-01-31 17:01:43 -08001022 << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0]))
1023 << " bytes)";
1024
1025#ifdef WITH_MEMSTATS
1026 if (cUnit->enableDebug & (1 << kDebugShowMemoryUsage)) {
1027 oatDumpMemStats(cUnit.get());
1028 }
1029#endif
buzbee67bf8852011-08-17 17:51:35 -07001030
buzbeeba938cb2012-02-03 14:47:55 -08001031 oatArenaReset(cUnit.get());
1032
Brian Carlstrom3320cf42011-10-04 14:58:28 -07001033 return result;
buzbee67bf8852011-08-17 17:51:35 -07001034}
1035
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001036} // namespace art
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001037
1038extern "C" art::CompiledMethod* oatCompileMethod(art::Compiler& compiler,
1039 const art::DexFile::CodeItem* code_item,
1040 uint32_t access_flags, uint32_t method_idx,
1041 const art::ClassLoader* class_loader,
1042 const art::DexFile& dex_file)
1043{
1044 CHECK_EQ(compiler.GetInstructionSet(), art::oatInstructionSet());
1045 return art::oatCompileMethodInternal(compiler, code_item, access_flags, method_idx, class_loader, dex_file);
1046}