blob: c5692bc10d2d3e810f1266f8c63f8d8e80d9a26f [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) |
buzbeece302932011-10-04 14:32:18 -070036 0;
37
38uint32_t compilerDebugFlags = 0 | // Enable debug/testing modes
buzbeee3de7492011-10-05 13:37:17 -070039 //(1 << kDebugDisplayMissingTargets) |
buzbeece302932011-10-04 14:32:18 -070040 //(1 << kDebugVerbose) |
41 //(1 << kDebugDumpCFG) |
42 //(1 << kDebugSlowFieldPath) |
43 //(1 << kDebugSlowInvokePath) |
44 //(1 << kDebugSlowStringPath) |
45 //(1 << kDebugSlowestFieldPath) |
46 //(1 << kDebugSlowestStringPath) |
buzbee34c77ad2012-01-11 13:01:32 -080047 //(1 << kDebugExerciseResolveMethod) |
buzbee5b537102012-01-17 17:33:47 -080048 //(1 << kDebugVerifyDataflow) |
buzbeece302932011-10-04 14:32:18 -070049 0;
50
51std::string compilerMethodMatch; // Method name match to apply above flags
52
53bool compilerFlipMatch = false; // Reverses sense of method name match
54
buzbeeed3e9302011-09-23 17:34:19 -070055STATIC inline bool contentIsInsn(const u2* codePtr) {
buzbee67bf8852011-08-17 17:51:35 -070056 u2 instr = *codePtr;
57 Opcode opcode = (Opcode)(instr & 0xff);
58
59 /*
60 * Since the low 8-bit in metadata may look like OP_NOP, we need to check
61 * both the low and whole sub-word to determine whether it is code or data.
62 */
63 return (opcode != OP_NOP || instr == 0);
64}
65
66/*
67 * Parse an instruction, return the length of the instruction
68 */
buzbeeed3e9302011-09-23 17:34:19 -070069STATIC inline int parseInsn(const u2* codePtr, DecodedInstruction* decInsn,
buzbee67bf8852011-08-17 17:51:35 -070070 bool printMe)
71{
72 // Don't parse instruction data
73 if (!contentIsInsn(codePtr)) {
74 return 0;
75 }
76
77 u2 instr = *codePtr;
78 Opcode opcode = dexOpcodeFromCodeUnit(instr);
79
80 dexDecodeInstruction(codePtr, decInsn);
81 if (printMe) {
Elliott Hughesc1f143d2011-12-01 17:31:10 -080082 char* decodedString = oatGetDalvikDisassembly(decInsn, NULL);
buzbee67bf8852011-08-17 17:51:35 -070083 LOG(INFO) << codePtr << ": 0x" << std::hex << (int)opcode <<
84 " " << decodedString;
85 }
86 return dexGetWidthFromOpcode(opcode);
87}
88
89#define UNKNOWN_TARGET 0xffffffff
90
buzbeeed3e9302011-09-23 17:34:19 -070091STATIC inline bool isGoto(MIR* insn)
buzbee67bf8852011-08-17 17:51:35 -070092{
93 switch (insn->dalvikInsn.opcode) {
94 case OP_GOTO:
95 case OP_GOTO_16:
96 case OP_GOTO_32:
97 return true;
98 default:
99 return false;
100 }
101}
102
103/*
104 * Identify unconditional branch instructions
105 */
buzbeeed3e9302011-09-23 17:34:19 -0700106STATIC inline bool isUnconditionalBranch(MIR* insn)
buzbee67bf8852011-08-17 17:51:35 -0700107{
108 switch (insn->dalvikInsn.opcode) {
109 case OP_RETURN_VOID:
110 case OP_RETURN:
111 case OP_RETURN_WIDE:
112 case OP_RETURN_OBJECT:
113 return true;
114 default:
115 return isGoto(insn);
116 }
117}
118
119/* Split an existing block from the specified code offset into two */
buzbeeed3e9302011-09-23 17:34:19 -0700120STATIC BasicBlock *splitBlock(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -0700121 unsigned int codeOffset,
buzbee9ab05de2012-01-18 15:43:48 -0800122 BasicBlock* origBlock,
123 BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700124{
125 MIR* insn = origBlock->firstMIRInsn;
126 while (insn) {
127 if (insn->offset == codeOffset) break;
128 insn = insn->next;
129 }
130 if (insn == NULL) {
131 LOG(FATAL) << "Break split failed";
132 }
133 BasicBlock *bottomBlock = oatNewBB(kDalvikByteCode,
134 cUnit->numBlocks++);
135 oatInsertGrowableList(&cUnit->blockList, (intptr_t) bottomBlock);
136
137 bottomBlock->startOffset = codeOffset;
138 bottomBlock->firstMIRInsn = insn;
139 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
140
buzbee5b537102012-01-17 17:33:47 -0800141 /* Add it to the quick lookup cache */
142 cUnit->blockMap.insert(std::make_pair(bottomBlock->startOffset,
143 bottomBlock));
144
buzbee67bf8852011-08-17 17:51:35 -0700145 /* Handle the taken path */
146 bottomBlock->taken = origBlock->taken;
147 if (bottomBlock->taken) {
148 origBlock->taken = NULL;
149 oatClearBit(bottomBlock->taken->predecessors, origBlock->id);
150 oatSetBit(bottomBlock->taken->predecessors, bottomBlock->id);
151 }
152
153 /* Handle the fallthrough path */
154 bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
155 bottomBlock->fallThrough = origBlock->fallThrough;
156 origBlock->fallThrough = bottomBlock;
157 origBlock->needFallThroughBranch = true;
158 oatSetBit(bottomBlock->predecessors, origBlock->id);
159 if (bottomBlock->fallThrough) {
160 oatClearBit(bottomBlock->fallThrough->predecessors,
161 origBlock->id);
162 oatSetBit(bottomBlock->fallThrough->predecessors,
163 bottomBlock->id);
164 }
165
166 /* Handle the successor list */
167 if (origBlock->successorBlockList.blockListType != kNotUsed) {
168 bottomBlock->successorBlockList = origBlock->successorBlockList;
169 origBlock->successorBlockList.blockListType = kNotUsed;
170 GrowableListIterator iterator;
171
172 oatGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
173 &iterator);
174 while (true) {
175 SuccessorBlockInfo *successorBlockInfo =
176 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
177 if (successorBlockInfo == NULL) break;
178 BasicBlock *bb = successorBlockInfo->block;
179 oatClearBit(bb->predecessors, origBlock->id);
180 oatSetBit(bb->predecessors, bottomBlock->id);
181 }
182 }
183
184 origBlock->lastMIRInsn = insn->prev;
185
186 insn->prev->next = NULL;
187 insn->prev = NULL;
buzbee9ab05de2012-01-18 15:43:48 -0800188 /*
189 * Update the immediate predecessor block pointer so that outgoing edges
190 * can be applied to the proper block.
191 */
192 if (immedPredBlockP) {
193 DCHECK_EQ(*immedPredBlockP, origBlock);
194 *immedPredBlockP = bottomBlock;
195 }
buzbee67bf8852011-08-17 17:51:35 -0700196 return bottomBlock;
197}
198
199/*
200 * Given a code offset, find out the block that starts with it. If the offset
buzbee9ab05de2012-01-18 15:43:48 -0800201 * is in the middle of an existing block, split it into two. If immedPredBlockP
202 * is not non-null and is the block being split, update *immedPredBlockP to
203 * point to the bottom block so that outgoing edges can be set up properly
204 * (by the caller)
buzbee5b537102012-01-17 17:33:47 -0800205 * Utilizes a map for fast lookup of the typical cases.
buzbee67bf8852011-08-17 17:51:35 -0700206 */
buzbeeed3e9302011-09-23 17:34:19 -0700207STATIC BasicBlock *findBlock(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -0700208 unsigned int codeOffset,
buzbee9ab05de2012-01-18 15:43:48 -0800209 bool split, bool create,
210 BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700211{
212 GrowableList* blockList = &cUnit->blockList;
213 BasicBlock* bb;
214 unsigned int i;
buzbee5b537102012-01-17 17:33:47 -0800215 std::map<unsigned int, BasicBlock*>::iterator it;
buzbee67bf8852011-08-17 17:51:35 -0700216
buzbee5b537102012-01-17 17:33:47 -0800217 it = cUnit->blockMap.find(codeOffset);
218 if (it != cUnit->blockMap.end()) {
219 return it->second;
220 } else if (!create) {
221 return NULL;
222 }
223
224 if (split) {
225 for (i = 0; i < blockList->numUsed; i++) {
226 bb = (BasicBlock *) blockList->elemList[i];
227 if (bb->blockType != kDalvikByteCode) continue;
228 /* Check if a branch jumps into the middle of an existing block */
229 if ((codeOffset > bb->startOffset) && (bb->lastMIRInsn != NULL) &&
230 (codeOffset <= bb->lastMIRInsn->offset)) {
231 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb,
232 bb == *immedPredBlockP ?
233 immedPredBlockP : NULL);
234 return newBB;
235 }
buzbee67bf8852011-08-17 17:51:35 -0700236 }
237 }
buzbee5b537102012-01-17 17:33:47 -0800238
239 /* Create a new one */
240 bb = oatNewBB(kDalvikByteCode, cUnit->numBlocks++);
241 oatInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
242 bb->startOffset = codeOffset;
243 cUnit->blockMap.insert(std::make_pair(bb->startOffset, bb));
244 return bb;
buzbee67bf8852011-08-17 17:51:35 -0700245}
246
247/* Dump the CFG into a DOT graph */
248void oatDumpCFG(CompilationUnit* cUnit, const char* dirPrefix)
249{
buzbee67bf8852011-08-17 17:51:35 -0700250 FILE* file;
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800251 std::string name(PrettyMethod(cUnit->method_idx, *cUnit->dex_file));
buzbee67bf8852011-08-17 17:51:35 -0700252 char startOffset[80];
253 sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
Elliott Hughesc1f143d2011-12-01 17:31:10 -0800254 char* fileName = (char*) oatNew(
buzbeec143c552011-08-20 17:38:58 -0700255 strlen(dirPrefix) +
256 name.length() +
257 strlen(".dot") + 1, true);
258 sprintf(fileName, "%s%s%s.dot", dirPrefix, name.c_str(), startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700259
260 /*
261 * Convert the special characters into a filesystem- and shell-friendly
262 * format.
263 */
264 int i;
265 for (i = strlen(dirPrefix); fileName[i]; i++) {
266 if (fileName[i] == '/') {
267 fileName[i] = '_';
268 } else if (fileName[i] == ';') {
269 fileName[i] = '#';
270 } else if (fileName[i] == '$') {
271 fileName[i] = '+';
272 } else if (fileName[i] == '(' || fileName[i] == ')') {
273 fileName[i] = '@';
274 } else if (fileName[i] == '<' || fileName[i] == '>') {
275 fileName[i] = '=';
276 }
277 }
278 file = fopen(fileName, "w");
279 if (file == NULL) {
280 return;
281 }
282 fprintf(file, "digraph G {\n");
283
284 fprintf(file, " rankdir=TB\n");
285
286 int numReachableBlocks = cUnit->numReachableBlocks;
287 int idx;
288 const GrowableList *blockList = &cUnit->blockList;
289
290 for (idx = 0; idx < numReachableBlocks; idx++) {
291 int blockIdx = cUnit->dfsOrder.elemList[idx];
292 BasicBlock *bb = (BasicBlock *) oatGrowableListGetElement(blockList,
293 blockIdx);
294 if (bb == NULL) break;
295 if (bb->blockType == kEntryBlock) {
296 fprintf(file, " entry [shape=Mdiamond];\n");
297 } else if (bb->blockType == kExitBlock) {
298 fprintf(file, " exit [shape=Mdiamond];\n");
299 } else if (bb->blockType == kDalvikByteCode) {
300 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
301 bb->startOffset);
302 const MIR *mir;
303 fprintf(file, " {block id %d\\l}%s\\\n", bb->id,
304 bb->firstMIRInsn ? " | " : " ");
305 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
306 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
307 mir->ssaRep ?
308 oatFullDisassembler(cUnit, mir) :
309 dexGetOpcodeName(mir->dalvikInsn.opcode),
310 mir->next ? " | " : " ");
311 }
312 fprintf(file, " }\"];\n\n");
313 } else if (bb->blockType == kExceptionHandling) {
314 char blockName[BLOCK_NAME_LEN];
315
316 oatGetBlockName(bb, blockName);
317 fprintf(file, " %s [shape=invhouse];\n", blockName);
318 }
319
320 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
321
322 if (bb->taken) {
323 oatGetBlockName(bb, blockName1);
324 oatGetBlockName(bb->taken, blockName2);
325 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
326 blockName1, blockName2);
327 }
328 if (bb->fallThrough) {
329 oatGetBlockName(bb, blockName1);
330 oatGetBlockName(bb->fallThrough, blockName2);
331 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
332 }
333
334 if (bb->successorBlockList.blockListType != kNotUsed) {
335 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
336 bb->startOffset,
337 (bb->successorBlockList.blockListType == kCatch) ?
338 "Mrecord" : "record");
339 GrowableListIterator iterator;
340 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
341 &iterator);
342 SuccessorBlockInfo *successorBlockInfo =
343 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
344
345 int succId = 0;
346 while (true) {
347 if (successorBlockInfo == NULL) break;
348
349 BasicBlock *destBlock = successorBlockInfo->block;
350 SuccessorBlockInfo *nextSuccessorBlockInfo =
351 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
352
353 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
354 succId++,
355 successorBlockInfo->key,
356 destBlock->startOffset,
357 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
358
359 successorBlockInfo = nextSuccessorBlockInfo;
360 }
361 fprintf(file, " }\"];\n\n");
362
363 oatGetBlockName(bb, blockName1);
364 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
365 blockName1, bb->startOffset);
366
367 if (bb->successorBlockList.blockListType == kPackedSwitch ||
368 bb->successorBlockList.blockListType == kSparseSwitch) {
369
370 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
371 &iterator);
372
373 succId = 0;
374 while (true) {
375 SuccessorBlockInfo *successorBlockInfo =
376 (SuccessorBlockInfo *)
377 oatGrowableListIteratorNext(&iterator);
378 if (successorBlockInfo == NULL) break;
379
380 BasicBlock *destBlock = successorBlockInfo->block;
381
382 oatGetBlockName(destBlock, blockName2);
383 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
384 bb->startOffset, succId++,
385 blockName2);
386 }
387 }
388 }
389 fprintf(file, "\n");
390
buzbeece302932011-10-04 14:32:18 -0700391 /* Display the dominator tree */
buzbee67bf8852011-08-17 17:51:35 -0700392 oatGetBlockName(bb, blockName1);
393 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
394 blockName1, blockName1);
395 if (bb->iDom) {
396 oatGetBlockName(bb->iDom, blockName2);
397 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
398 blockName2, blockName1);
399 }
buzbee67bf8852011-08-17 17:51:35 -0700400 }
401 fprintf(file, "}\n");
402 fclose(file);
403}
404
405/* Verify if all the successor is connected with all the claimed predecessors */
buzbeeed3e9302011-09-23 17:34:19 -0700406STATIC bool verifyPredInfo(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -0700407{
408 ArenaBitVectorIterator bvIterator;
409
410 oatBitVectorIteratorInit(bb->predecessors, &bvIterator);
411 while (true) {
412 int blockIdx = oatBitVectorIteratorNext(&bvIterator);
413 if (blockIdx == -1) break;
414 BasicBlock *predBB = (BasicBlock *)
415 oatGrowableListGetElement(&cUnit->blockList, blockIdx);
416 bool found = false;
417 if (predBB->taken == bb) {
418 found = true;
419 } else if (predBB->fallThrough == bb) {
420 found = true;
421 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
422 GrowableListIterator iterator;
423 oatGrowableListIteratorInit(&predBB->successorBlockList.blocks,
424 &iterator);
425 while (true) {
426 SuccessorBlockInfo *successorBlockInfo =
427 (SuccessorBlockInfo *)
428 oatGrowableListIteratorNext(&iterator);
429 if (successorBlockInfo == NULL) break;
430 BasicBlock *succBB = successorBlockInfo->block;
431 if (succBB == bb) {
432 found = true;
433 break;
434 }
435 }
436 }
437 if (found == false) {
438 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
439 oatGetBlockName(bb, blockName1);
440 oatGetBlockName(predBB, blockName2);
441 oatDumpCFG(cUnit, "/sdcard/cfg/");
442 LOG(FATAL) << "Successor " << blockName1 << "not found from "
443 << blockName2;
444 }
445 }
446 return true;
447}
448
449/* Identify code range in try blocks and set up the empty catch blocks */
buzbeeed3e9302011-09-23 17:34:19 -0700450STATIC void processTryCatchBlocks(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700451{
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800452 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbeee9a72f62011-09-04 17:59:07 -0700453 int triesSize = code_item->tries_size_;
buzbee67bf8852011-08-17 17:51:35 -0700454 int offset;
455
456 if (triesSize == 0) {
457 return;
458 }
459
buzbee67bf8852011-08-17 17:51:35 -0700460 ArenaBitVector* tryBlockAddr = cUnit->tryBlockAddr;
461
buzbeee9a72f62011-09-04 17:59:07 -0700462 for (int i = 0; i < triesSize; i++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800463 const DexFile::TryItem* pTry =
464 DexFile::GetTryItems(*code_item, i);
buzbeee9a72f62011-09-04 17:59:07 -0700465 int startOffset = pTry->start_addr_;
466 int endOffset = startOffset + pTry->insn_count_;
buzbee67bf8852011-08-17 17:51:35 -0700467 for (offset = startOffset; offset < endOffset; offset++) {
468 oatSetBit(tryBlockAddr, offset);
469 }
470 }
471
buzbeee9a72f62011-09-04 17:59:07 -0700472 // Iterate over each of the handlers to enqueue the empty Catch blocks
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800473 const byte* handlers_ptr =
474 DexFile::GetCatchHandlerData(*code_item, 0);
475 uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
buzbeee9a72f62011-09-04 17:59:07 -0700476 for (uint32_t idx = 0; idx < handlers_size; idx++) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800477 CatchHandlerIterator iterator(handlers_ptr);
Ian Rogers0571d352011-11-03 19:51:38 -0700478 for (; iterator.HasNext(); iterator.Next()) {
479 uint32_t address = iterator.GetHandlerAddress();
buzbee9ab05de2012-01-18 15:43:48 -0800480 findBlock(cUnit, address, false /* split */, true /*create*/,
481 /* immedPredBlockP */ NULL);
buzbee67bf8852011-08-17 17:51:35 -0700482 }
Ian Rogers0571d352011-11-03 19:51:38 -0700483 handlers_ptr = iterator.EndDataPointer();
buzbee67bf8852011-08-17 17:51:35 -0700484 }
485}
486
487/* Process instructions with the kInstrCanBranch flag */
buzbeee941e2c2011-12-05 12:38:17 -0800488STATIC BasicBlock* processCanBranch(CompilationUnit* cUnit,
489 BasicBlock* curBlock, MIR* insn,
490 int curOffset, int width, int flags,
491 const u2* codePtr, const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700492{
493 int target = curOffset;
494 switch (insn->dalvikInsn.opcode) {
495 case OP_GOTO:
496 case OP_GOTO_16:
497 case OP_GOTO_32:
498 target += (int) insn->dalvikInsn.vA;
499 break;
500 case OP_IF_EQ:
501 case OP_IF_NE:
502 case OP_IF_LT:
503 case OP_IF_GE:
504 case OP_IF_GT:
505 case OP_IF_LE:
506 target += (int) insn->dalvikInsn.vC;
507 break;
508 case OP_IF_EQZ:
509 case OP_IF_NEZ:
510 case OP_IF_LTZ:
511 case OP_IF_GEZ:
512 case OP_IF_GTZ:
513 case OP_IF_LEZ:
514 target += (int) insn->dalvikInsn.vB;
515 break;
516 default:
517 LOG(FATAL) << "Unexpected opcode(" << (int)insn->dalvikInsn.opcode
518 << ") with kInstrCanBranch set";
519 }
520 BasicBlock *takenBlock = findBlock(cUnit, target,
521 /* split */
522 true,
523 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800524 true,
525 /* immedPredBlockP */
526 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700527 curBlock->taken = takenBlock;
528 oatSetBit(takenBlock->predecessors, curBlock->id);
529
530 /* Always terminate the current block for conditional branches */
531 if (flags & kInstrCanContinue) {
532 BasicBlock *fallthroughBlock = findBlock(cUnit,
533 curOffset + width,
534 /*
535 * If the method is processed
536 * in sequential order from the
537 * beginning, we don't need to
538 * specify split for continue
539 * blocks. However, this
540 * routine can be called by
541 * compileLoop, which starts
542 * parsing the method from an
543 * arbitrary address in the
544 * method body.
545 */
546 true,
547 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800548 true,
549 /* immedPredBlockP */
550 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700551 curBlock->fallThrough = fallthroughBlock;
552 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
553 } else if (codePtr < codeEnd) {
554 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
555 if (contentIsInsn(codePtr)) {
556 findBlock(cUnit, curOffset + width,
557 /* split */
558 false,
559 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800560 true,
561 /* immedPredBlockP */
562 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700563 }
564 }
buzbeee941e2c2011-12-05 12:38:17 -0800565 return curBlock;
buzbee67bf8852011-08-17 17:51:35 -0700566}
567
568/* Process instructions with the kInstrCanSwitch flag */
buzbeeed3e9302011-09-23 17:34:19 -0700569STATIC void processCanSwitch(CompilationUnit* cUnit, BasicBlock* curBlock,
buzbee67bf8852011-08-17 17:51:35 -0700570 MIR* insn, int curOffset, int width, int flags)
571{
572 u2* switchData= (u2 *) (cUnit->insns + curOffset +
573 insn->dalvikInsn.vB);
574 int size;
575 int* keyTable;
576 int* targetTable;
577 int i;
578 int firstKey;
579
580 /*
581 * Packed switch data format:
582 * ushort ident = 0x0100 magic value
583 * ushort size number of entries in the table
584 * int first_key first (and lowest) switch case value
585 * int targets[size] branch targets, relative to switch opcode
586 *
587 * Total size is (4+size*2) 16-bit code units.
588 */
589 if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
buzbeeed3e9302011-09-23 17:34:19 -0700590 DCHECK_EQ(switchData[0], kPackedSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700591 size = switchData[1];
592 firstKey = switchData[2] | (switchData[3] << 16);
593 targetTable = (int *) &switchData[4];
594 keyTable = NULL; // Make the compiler happy
595 /*
596 * Sparse switch data format:
597 * ushort ident = 0x0200 magic value
598 * ushort size number of entries in the table; > 0
599 * int keys[size] keys, sorted low-to-high; 32-bit aligned
600 * int targets[size] branch targets, relative to switch opcode
601 *
602 * Total size is (2+size*4) 16-bit code units.
603 */
604 } else {
buzbeeed3e9302011-09-23 17:34:19 -0700605 DCHECK_EQ(switchData[0], kSparseSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700606 size = switchData[1];
607 keyTable = (int *) &switchData[2];
608 targetTable = (int *) &switchData[2 + size*2];
609 firstKey = 0; // To make the compiler happy
610 }
611
612 if (curBlock->successorBlockList.blockListType != kNotUsed) {
613 LOG(FATAL) << "Successor block list already in use: " <<
614 (int)curBlock->successorBlockList.blockListType;
615 }
616 curBlock->successorBlockList.blockListType =
617 (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
618 kPackedSwitch : kSparseSwitch;
619 oatInitGrowableList(&curBlock->successorBlockList.blocks, size);
620
621 for (i = 0; i < size; i++) {
622 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
623 /* split */
624 true,
625 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800626 true,
627 /* immedPredBlockP */
628 &curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700629 SuccessorBlockInfo *successorBlockInfo =
630 (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
631 false);
632 successorBlockInfo->block = caseBlock;
633 successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)?
634 firstKey + i : keyTable[i];
635 oatInsertGrowableList(&curBlock->successorBlockList.blocks,
636 (intptr_t) successorBlockInfo);
637 oatSetBit(caseBlock->predecessors, curBlock->id);
638 }
639
640 /* Fall-through case */
641 BasicBlock* fallthroughBlock = findBlock(cUnit,
642 curOffset + width,
643 /* split */
644 false,
645 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800646 true,
647 /* immedPredBlockP */
648 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700649 curBlock->fallThrough = fallthroughBlock;
650 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
651}
652
653/* Process instructions with the kInstrCanThrow flag */
buzbeeed3e9302011-09-23 17:34:19 -0700654STATIC void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock,
buzbee67bf8852011-08-17 17:51:35 -0700655 MIR* insn, int curOffset, int width, int flags,
656 ArenaBitVector* tryBlockAddr, const u2* codePtr,
657 const u2* codeEnd)
658{
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800659 const DexFile::CodeItem* code_item = cUnit->code_item;
buzbee67bf8852011-08-17 17:51:35 -0700660
661 /* In try block */
662 if (oatIsBitSet(tryBlockAddr, curOffset)) {
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800663 CatchHandlerIterator iterator(*code_item, curOffset);
buzbee67bf8852011-08-17 17:51:35 -0700664
buzbee67bf8852011-08-17 17:51:35 -0700665 if (curBlock->successorBlockList.blockListType != kNotUsed) {
666 LOG(FATAL) << "Successor block list already in use: " <<
667 (int)curBlock->successorBlockList.blockListType;
668 }
buzbeee9a72f62011-09-04 17:59:07 -0700669
buzbee67bf8852011-08-17 17:51:35 -0700670 curBlock->successorBlockList.blockListType = kCatch;
671 oatInitGrowableList(&curBlock->successorBlockList.blocks, 2);
672
Ian Rogers0571d352011-11-03 19:51:38 -0700673 for (;iterator.HasNext(); iterator.Next()) {
674 BasicBlock *catchBlock = findBlock(cUnit, iterator.GetHandlerAddress(),
buzbeee9a72f62011-09-04 17:59:07 -0700675 false /* split*/,
buzbee9ab05de2012-01-18 15:43:48 -0800676 false /* creat */,
677 NULL /* immedPredBlockP */);
buzbee43a36422011-09-14 14:00:13 -0700678 catchBlock->catchEntry = true;
buzbee67bf8852011-08-17 17:51:35 -0700679 SuccessorBlockInfo *successorBlockInfo =
buzbeee9a72f62011-09-04 17:59:07 -0700680 (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
681 false);
buzbee67bf8852011-08-17 17:51:35 -0700682 successorBlockInfo->block = catchBlock;
Ian Rogers0571d352011-11-03 19:51:38 -0700683 successorBlockInfo->key = iterator.GetHandlerTypeIndex();
buzbee67bf8852011-08-17 17:51:35 -0700684 oatInsertGrowableList(&curBlock->successorBlockList.blocks,
685 (intptr_t) successorBlockInfo);
686 oatSetBit(catchBlock->predecessors, curBlock->id);
687 }
688 } else {
689 BasicBlock *ehBlock = oatNewBB(kExceptionHandling,
690 cUnit->numBlocks++);
691 curBlock->taken = ehBlock;
692 oatInsertGrowableList(&cUnit->blockList, (intptr_t) ehBlock);
693 ehBlock->startOffset = curOffset;
694 oatSetBit(ehBlock->predecessors, curBlock->id);
695 }
696
697 /*
698 * Force the current block to terminate.
699 *
700 * Data may be present before codeEnd, so we need to parse it to know
701 * whether it is code or data.
702 */
703 if (codePtr < codeEnd) {
704 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
705 if (contentIsInsn(codePtr)) {
706 BasicBlock *fallthroughBlock = findBlock(cUnit,
707 curOffset + width,
708 /* split */
709 false,
710 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800711 true,
712 /* immedPredBlockP */
713 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700714 /*
buzbee510c6052011-10-27 10:47:20 -0700715 * OP_THROW is an unconditional branch. NOTE:
716 * OP_THROW_VERIFICATION_ERROR is also an unconditional
717 * branch, but we shouldn't treat it as such until we have
718 * a dead code elimination pass (which won't be important
719 * until inlining w/ constant propogation is implemented.
buzbee67bf8852011-08-17 17:51:35 -0700720 */
buzbee510c6052011-10-27 10:47:20 -0700721 if (insn->dalvikInsn.opcode != OP_THROW) {
buzbee67bf8852011-08-17 17:51:35 -0700722 curBlock->fallThrough = fallthroughBlock;
723 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
724 }
725 }
726 }
727}
728
729/*
730 * Compile a method.
731 */
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800732CompiledMethod* oatCompileMethod(const Compiler& compiler, const DexFile::CodeItem* code_item,
Ian Rogersa3760aa2011-11-14 14:32:37 -0800733 uint32_t access_flags, uint32_t method_idx,
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800734 const ClassLoader* class_loader,
735 const DexFile& dex_file, InstructionSet insnSet)
buzbee67bf8852011-08-17 17:51:35 -0700736{
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800737 VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
buzbee2a475e72011-09-07 17:19:17 -0700738 oatArenaReset();
Brian Carlstrom94496d32011-08-22 09:22:47 -0700739
buzbeec143c552011-08-20 17:38:58 -0700740 const u2* codePtr = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700741 const u2* codeEnd = code_item->insns_ + code_item->insns_size_in_code_units_;
buzbee67bf8852011-08-17 17:51:35 -0700742 int numBlocks = 0;
743 unsigned int curOffset = 0;
744
Brian Carlstrom16192862011-09-12 17:50:06 -0700745 oatInit(compiler);
buzbee67bf8852011-08-17 17:51:35 -0700746
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800747 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700748 UniquePtr<CompilationUnit> cUnit(new CompilationUnit);
749 memset(cUnit.get(), 0, sizeof(*cUnit));
750 cUnit->compiler = &compiler;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800751 cUnit->class_linker = class_linker;
752 cUnit->dex_file = &dex_file;
753 cUnit->dex_cache = class_linker->FindDexCache(dex_file);
754 cUnit->method_idx = method_idx;
755 cUnit->code_item = code_item;
756 cUnit->access_flags = access_flags;
757 cUnit->shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700758 cUnit->instructionSet = (OatInstructionSetType)insnSet;
759 cUnit->insns = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700760 cUnit->insnsSize = code_item->insns_size_in_code_units_;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800761 cUnit->numIns = code_item->ins_size_;
762 cUnit->numRegs = code_item->registers_size_ - cUnit->numIns;
763 cUnit->numOuts = code_item->outs_size_;
764 /* Adjust this value accordingly once inlining is performed */
765 cUnit->numDalvikRegisters = code_item->registers_size_;
buzbee5b537102012-01-17 17:33:47 -0800766 cUnit->blockMap = std::map<unsigned int, BasicBlock*>();
767 cUnit->blockMap.clear();
buzbeece302932011-10-04 14:32:18 -0700768 bool useMatch = compilerMethodMatch.length() != 0;
769 bool match = useMatch && (compilerFlipMatch ^
Ian Rogersa3760aa2011-11-14 14:32:37 -0800770 (PrettyMethod(method_idx, dex_file).find(compilerMethodMatch) != std::string::npos));
buzbeece302932011-10-04 14:32:18 -0700771 if (!useMatch || match) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700772 cUnit->disableOpt = compilerOptimizerDisableFlags;
773 cUnit->enableDebug = compilerDebugFlags;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800774 cUnit->printMe = VLOG_IS_ON(compiler) || (cUnit->enableDebug & (1 << kDebugVerbose));
buzbeece302932011-10-04 14:32:18 -0700775 }
buzbee67bf8852011-08-17 17:51:35 -0700776
buzbeecefd1872011-09-09 09:59:52 -0700777 /* Assume non-throwing leaf */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700778 cUnit->attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
buzbeecefd1872011-09-09 09:59:52 -0700779
buzbee67bf8852011-08-17 17:51:35 -0700780 /* Initialize the block list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700781 oatInitGrowableList(&cUnit->blockList, 40);
buzbee67bf8852011-08-17 17:51:35 -0700782
783 /* Initialize the switchTables list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700784 oatInitGrowableList(&cUnit->switchTables, 4);
buzbee67bf8852011-08-17 17:51:35 -0700785
786 /* Intialize the fillArrayData list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700787 oatInitGrowableList(&cUnit->fillArrayData, 4);
buzbee67bf8852011-08-17 17:51:35 -0700788
buzbee5ade1d22011-09-09 14:44:52 -0700789 /* Intialize the throwLaunchpads list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700790 oatInitGrowableList(&cUnit->throwLaunchpads, 4);
buzbee5ade1d22011-09-09 14:44:52 -0700791
buzbeec1f45042011-09-21 16:03:19 -0700792 /* Intialize the suspendLaunchpads list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700793 oatInitGrowableList(&cUnit->suspendLaunchpads, 4);
buzbeec1f45042011-09-21 16:03:19 -0700794
buzbee67bf8852011-08-17 17:51:35 -0700795 /* Allocate the bit-vector to track the beginning of basic blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700796 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit->insnsSize,
buzbee67bf8852011-08-17 17:51:35 -0700797 true /* expandable */);
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700798 cUnit->tryBlockAddr = tryBlockAddr;
buzbee67bf8852011-08-17 17:51:35 -0700799
800 /* Create the default entry and exit blocks and enter them to the list */
801 BasicBlock *entryBlock = oatNewBB(kEntryBlock, numBlocks++);
802 BasicBlock *exitBlock = oatNewBB(kExitBlock, numBlocks++);
803
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700804 cUnit->entryBlock = entryBlock;
805 cUnit->exitBlock = exitBlock;
buzbee67bf8852011-08-17 17:51:35 -0700806
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700807 oatInsertGrowableList(&cUnit->blockList, (intptr_t) entryBlock);
808 oatInsertGrowableList(&cUnit->blockList, (intptr_t) exitBlock);
buzbee67bf8852011-08-17 17:51:35 -0700809
810 /* Current block to record parsed instructions */
811 BasicBlock *curBlock = oatNewBB(kDalvikByteCode, numBlocks++);
812 curBlock->startOffset = 0;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700813 oatInsertGrowableList(&cUnit->blockList, (intptr_t) curBlock);
buzbee5b537102012-01-17 17:33:47 -0800814 /* Add first block to the fast lookup cache */
815 cUnit->blockMap.insert(std::make_pair(curBlock->startOffset, curBlock));
buzbee67bf8852011-08-17 17:51:35 -0700816 entryBlock->fallThrough = curBlock;
817 oatSetBit(curBlock->predecessors, entryBlock->id);
818
819 /*
820 * Store back the number of blocks since new blocks may be created of
821 * accessing cUnit.
822 */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700823 cUnit->numBlocks = numBlocks;
buzbee67bf8852011-08-17 17:51:35 -0700824
825 /* Identify code range in try blocks and set up the empty catch blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700826 processTryCatchBlocks(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700827
828 /* Parse all instructions and put them into containing basic blocks */
829 while (codePtr < codeEnd) {
830 MIR *insn = (MIR *) oatNew(sizeof(MIR), true);
831 insn->offset = curOffset;
832 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
833 insn->width = width;
834
835 /* Terminate when the data section is seen */
836 if (width == 0)
837 break;
838
839 oatAppendMIR(curBlock, insn);
840
841 codePtr += width;
842 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
843
buzbee99ba9642012-01-25 14:23:14 -0800844 cUnit->usesFP |= (oatDataFlowAttributes[insn->dalvikInsn.opcode] &
845 DF_USES_FP);
846
buzbee67bf8852011-08-17 17:51:35 -0700847 if (flags & kInstrCanBranch) {
buzbeee941e2c2011-12-05 12:38:17 -0800848 curBlock = processCanBranch(cUnit.get(), curBlock, insn, curOffset,
849 width, flags, codePtr, codeEnd);
buzbee67bf8852011-08-17 17:51:35 -0700850 } else if (flags & kInstrCanReturn) {
851 curBlock->fallThrough = exitBlock;
852 oatSetBit(exitBlock->predecessors, curBlock->id);
853 /*
854 * Terminate the current block if there are instructions
855 * afterwards.
856 */
857 if (codePtr < codeEnd) {
858 /*
859 * Create a fallthrough block for real instructions
860 * (incl. OP_NOP).
861 */
862 if (contentIsInsn(codePtr)) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700863 findBlock(cUnit.get(), curOffset + width,
buzbee67bf8852011-08-17 17:51:35 -0700864 /* split */
865 false,
866 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800867 true,
868 /* immedPredBlockP */
869 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700870 }
871 }
872 } else if (flags & kInstrCanThrow) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700873 processCanThrow(cUnit.get(), curBlock, insn, curOffset, width, flags,
buzbee67bf8852011-08-17 17:51:35 -0700874 tryBlockAddr, codePtr, codeEnd);
875 } else if (flags & kInstrCanSwitch) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700876 processCanSwitch(cUnit.get(), curBlock, insn, curOffset, width, flags);
buzbee67bf8852011-08-17 17:51:35 -0700877 }
878 curOffset += width;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700879 BasicBlock *nextBlock = findBlock(cUnit.get(), curOffset,
buzbee67bf8852011-08-17 17:51:35 -0700880 /* split */
881 false,
882 /* create */
buzbee9ab05de2012-01-18 15:43:48 -0800883 false,
884 /* immedPredBlockP */
885 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700886 if (nextBlock) {
887 /*
888 * The next instruction could be the target of a previously parsed
889 * forward branch so a block is already created. If the current
890 * instruction is not an unconditional branch, connect them through
891 * the fall-through link.
892 */
buzbeeed3e9302011-09-23 17:34:19 -0700893 DCHECK(curBlock->fallThrough == NULL ||
buzbee67bf8852011-08-17 17:51:35 -0700894 curBlock->fallThrough == nextBlock ||
895 curBlock->fallThrough == exitBlock);
896
897 if ((curBlock->fallThrough == NULL) &&
898 (flags & kInstrCanContinue)) {
899 curBlock->fallThrough = nextBlock;
900 oatSetBit(nextBlock->predecessors, curBlock->id);
901 }
902 curBlock = nextBlock;
903 }
904 }
905
buzbee99ba9642012-01-25 14:23:14 -0800906 if (!cUnit->usesFP &&
907 !(cUnit->disableOpt & (1 << kSkipLargeMethodOptimization))) {
908 if ((cUnit->numBlocks > MANY_BLOCKS) ||
909 ((cUnit->numBlocks > MANY_BLOCKS_INITIALIZER) &&
910 PrettyMethod(method_idx, dex_file).find("init>") !=
911 std::string::npos)) {
912 cUnit->disableDataflow = true;
913 // Disable optimization which require dataflow/ssa
914 cUnit->disableOpt |=
915 (1 << kNullCheckElimination) |
916 (1 << kPromoteRegs);
917 if (cUnit->printMe) {
918 LOG(INFO) << "Compiler: " << PrettyMethod(method_idx, dex_file)
919 << " too big: " << cUnit->numBlocks;
920 }
921 }
922 }
923
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700924 if (cUnit->printMe) {
925 oatDumpCompilationUnit(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700926 }
927
buzbee5b537102012-01-17 17:33:47 -0800928 if (cUnit->enableDebug & (1 << kDebugVerifyDataflow)) {
929 /* Verify if all blocks are connected as claimed */
930 oatDataFlowAnalysisDispatcher(cUnit.get(), verifyPredInfo, kAllNodes, false /* isIterative */);
931 }
buzbee67bf8852011-08-17 17:51:35 -0700932
933 /* Perform SSA transformation for the whole method */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700934 oatMethodSSATransformation(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700935
buzbee43a36422011-09-14 14:00:13 -0700936 /* Perform null check elimination */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700937 oatMethodNullCheckElimination(cUnit.get());
buzbee43a36422011-09-14 14:00:13 -0700938
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700939 oatInitializeRegAlloc(cUnit.get()); // Needs to happen after SSA naming
buzbee67bf8852011-08-17 17:51:35 -0700940
941 /* Allocate Registers using simple local allocation scheme */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700942 oatSimpleRegAlloc(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700943
944 /* Convert MIR to LIR, etc. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700945 oatMethodMIR2LIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700946
947 // Debugging only
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700948 if (cUnit->enableDebug & (1 << kDebugDumpCFG)) {
949 oatDumpCFG(cUnit.get(), "/sdcard/cfg/");
buzbeeec5adf32011-09-11 15:25:43 -0700950 }
buzbee67bf8852011-08-17 17:51:35 -0700951
952 /* Method is not empty */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700953 if (cUnit->firstLIRInsn) {
buzbee67bf8852011-08-17 17:51:35 -0700954
955 // mark the targets of switch statement case labels
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700956 oatProcessSwitchTables(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700957
958 /* Convert LIR into machine code. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700959 oatAssembleLIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700960
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700961 if (cUnit->printMe) {
962 oatCodegenDump(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700963 }
964 }
965
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700966 // Combine vmap tables - core regs, then fp regs - into vmapTable
967 std::vector<uint16_t> vmapTable;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700968 for (size_t i = 0 ; i < cUnit->coreVmapTable.size(); i++) {
969 vmapTable.push_back(cUnit->coreVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700970 }
buzbeec41e5b52011-09-23 12:46:19 -0700971 // Add a marker to take place of lr
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -0700972 vmapTable.push_back(INVALID_VREG);
buzbeec41e5b52011-09-23 12:46:19 -0700973 // Combine vmap tables - core regs, then fp regs
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700974 for (uint32_t i = 0; i < cUnit->fpVmapTable.size(); i++) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700975 vmapTable.push_back(cUnit->fpVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700976 }
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -0700977 DCHECK_EQ(vmapTable.size(),
978 static_cast<uint32_t>(__builtin_popcount(cUnit->coreSpillMask)
979 + __builtin_popcount(cUnit->fpSpillMask)));
980 DCHECK_GE(vmapTable.size(), 1U); // should always at least one INVALID_VREG for lr
981
Elliott Hughes11d1b0c2012-01-23 16:57:47 -0800982 CompiledMethod* result = new CompiledMethod(kThumb2, cUnit->codeBuffer,
Ian Rogers0571d352011-11-03 19:51:38 -0700983 cUnit->frameSize, cUnit->coreSpillMask,
984 cUnit->fpSpillMask, cUnit->mappingTable,
985 vmapTable);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700986
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800987 VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file)
988 << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0])) << " bytes)";
buzbee67bf8852011-08-17 17:51:35 -0700989
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700990 return result;
buzbee67bf8852011-08-17 17:51:35 -0700991}
992
Brian Carlstrom16192862011-09-12 17:50:06 -0700993void oatInit(const Compiler& compiler)
buzbee67bf8852011-08-17 17:51:35 -0700994{
buzbee67bf8852011-08-17 17:51:35 -0700995 static bool initialized = false;
996 if (initialized)
997 return;
998 initialized = true;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800999 VLOG(compiler) << "Initializing compiler";
buzbee67bf8852011-08-17 17:51:35 -07001000 if (!oatArchInit()) {
1001 LOG(FATAL) << "Failed to initialize oat";
1002 }
1003 if (!oatHeapInit()) {
1004 LOG(FATAL) << "Failed to initialize oat heap";
1005 }
1006}
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001007
1008} // namespace art