blob: ba5bd3d5e17803528a3a4288bc354be911913b7c [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
buzbeece302932011-10-04 14:32:18 -070025/* Default optimizer/debug setting for the compiler. */
26uint32_t compilerOptimizerDisableFlags = 0 | // Disable specific optimizations
buzbee67bc2362011-10-11 18:08:40 -070027 //(1 << kLoadStoreElimination) |
28 //(1 << kLoadHoisting) |
29 //(1 << kSuppressLoads) |
30 //(1 << kNullCheckElimination) |
buzbeeb7990c72011-10-31 15:29:33 -070031 (1 << kPromoteRegs) |
32 (1 << kTrackLiveTemps) |
buzbeece302932011-10-04 14:32:18 -070033 0;
34
35uint32_t compilerDebugFlags = 0 | // Enable debug/testing modes
buzbeee3de7492011-10-05 13:37:17 -070036 //(1 << kDebugDisplayMissingTargets) |
buzbeece302932011-10-04 14:32:18 -070037 //(1 << kDebugVerbose) |
38 //(1 << kDebugDumpCFG) |
39 //(1 << kDebugSlowFieldPath) |
40 //(1 << kDebugSlowInvokePath) |
41 //(1 << kDebugSlowStringPath) |
42 //(1 << kDebugSlowestFieldPath) |
43 //(1 << kDebugSlowestStringPath) |
44 0;
45
46std::string compilerMethodMatch; // Method name match to apply above flags
47
48bool compilerFlipMatch = false; // Reverses sense of method name match
49
buzbeeed3e9302011-09-23 17:34:19 -070050STATIC inline bool contentIsInsn(const u2* codePtr) {
buzbee67bf8852011-08-17 17:51:35 -070051 u2 instr = *codePtr;
52 Opcode opcode = (Opcode)(instr & 0xff);
53
54 /*
55 * Since the low 8-bit in metadata may look like OP_NOP, we need to check
56 * both the low and whole sub-word to determine whether it is code or data.
57 */
58 return (opcode != OP_NOP || instr == 0);
59}
60
61/*
62 * Parse an instruction, return the length of the instruction
63 */
buzbeeed3e9302011-09-23 17:34:19 -070064STATIC inline int parseInsn(const u2* codePtr, DecodedInstruction* decInsn,
buzbee67bf8852011-08-17 17:51:35 -070065 bool printMe)
66{
67 // Don't parse instruction data
68 if (!contentIsInsn(codePtr)) {
69 return 0;
70 }
71
72 u2 instr = *codePtr;
73 Opcode opcode = dexOpcodeFromCodeUnit(instr);
74
75 dexDecodeInstruction(codePtr, decInsn);
76 if (printMe) {
Elliott Hughesc1f143d2011-12-01 17:31:10 -080077 char* decodedString = oatGetDalvikDisassembly(decInsn, NULL);
buzbee67bf8852011-08-17 17:51:35 -070078 LOG(INFO) << codePtr << ": 0x" << std::hex << (int)opcode <<
79 " " << decodedString;
80 }
81 return dexGetWidthFromOpcode(opcode);
82}
83
84#define UNKNOWN_TARGET 0xffffffff
85
buzbeeed3e9302011-09-23 17:34:19 -070086STATIC inline bool isGoto(MIR* insn)
buzbee67bf8852011-08-17 17:51:35 -070087{
88 switch (insn->dalvikInsn.opcode) {
89 case OP_GOTO:
90 case OP_GOTO_16:
91 case OP_GOTO_32:
92 return true;
93 default:
94 return false;
95 }
96}
97
98/*
99 * Identify unconditional branch instructions
100 */
buzbeeed3e9302011-09-23 17:34:19 -0700101STATIC inline bool isUnconditionalBranch(MIR* insn)
buzbee67bf8852011-08-17 17:51:35 -0700102{
103 switch (insn->dalvikInsn.opcode) {
104 case OP_RETURN_VOID:
105 case OP_RETURN:
106 case OP_RETURN_WIDE:
107 case OP_RETURN_OBJECT:
108 return true;
109 default:
110 return isGoto(insn);
111 }
112}
113
114/* Split an existing block from the specified code offset into two */
buzbeeed3e9302011-09-23 17:34:19 -0700115STATIC BasicBlock *splitBlock(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -0700116 unsigned int codeOffset,
117 BasicBlock* origBlock)
118{
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 }
127 BasicBlock *bottomBlock = oatNewBB(kDalvikByteCode,
128 cUnit->numBlocks++);
129 oatInsertGrowableList(&cUnit->blockList, (intptr_t) bottomBlock);
130
131 bottomBlock->startOffset = codeOffset;
132 bottomBlock->firstMIRInsn = insn;
133 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
134
135 /* Handle the taken path */
136 bottomBlock->taken = origBlock->taken;
137 if (bottomBlock->taken) {
138 origBlock->taken = NULL;
139 oatClearBit(bottomBlock->taken->predecessors, origBlock->id);
140 oatSetBit(bottomBlock->taken->predecessors, bottomBlock->id);
141 }
142
143 /* Handle the fallthrough path */
144 bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
145 bottomBlock->fallThrough = origBlock->fallThrough;
146 origBlock->fallThrough = bottomBlock;
147 origBlock->needFallThroughBranch = true;
148 oatSetBit(bottomBlock->predecessors, origBlock->id);
149 if (bottomBlock->fallThrough) {
150 oatClearBit(bottomBlock->fallThrough->predecessors,
151 origBlock->id);
152 oatSetBit(bottomBlock->fallThrough->predecessors,
153 bottomBlock->id);
154 }
155
156 /* Handle the successor list */
157 if (origBlock->successorBlockList.blockListType != kNotUsed) {
158 bottomBlock->successorBlockList = origBlock->successorBlockList;
159 origBlock->successorBlockList.blockListType = kNotUsed;
160 GrowableListIterator iterator;
161
162 oatGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
163 &iterator);
164 while (true) {
165 SuccessorBlockInfo *successorBlockInfo =
166 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
167 if (successorBlockInfo == NULL) break;
168 BasicBlock *bb = successorBlockInfo->block;
169 oatClearBit(bb->predecessors, origBlock->id);
170 oatSetBit(bb->predecessors, bottomBlock->id);
171 }
172 }
173
174 origBlock->lastMIRInsn = insn->prev;
175
176 insn->prev->next = NULL;
177 insn->prev = NULL;
178 return bottomBlock;
179}
180
181/*
182 * Given a code offset, find out the block that starts with it. If the offset
183 * is in the middle of an existing block, split it into two.
184 */
buzbeeed3e9302011-09-23 17:34:19 -0700185STATIC BasicBlock *findBlock(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -0700186 unsigned int codeOffset,
187 bool split, bool create)
188{
189 GrowableList* blockList = &cUnit->blockList;
190 BasicBlock* bb;
191 unsigned int i;
192
193 for (i = 0; i < blockList->numUsed; i++) {
194 bb = (BasicBlock *) blockList->elemList[i];
195 if (bb->blockType != kDalvikByteCode) continue;
196 if (bb->startOffset == codeOffset) return bb;
197 /* Check if a branch jumps into the middle of an existing block */
198 if ((split == true) && (codeOffset > bb->startOffset) &&
199 (bb->lastMIRInsn != NULL) &&
200 (codeOffset <= bb->lastMIRInsn->offset)) {
201 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb);
202 return newBB;
203 }
204 }
205 if (create) {
206 bb = oatNewBB(kDalvikByteCode, cUnit->numBlocks++);
207 oatInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
208 bb->startOffset = codeOffset;
209 return bb;
210 }
211 return NULL;
212}
213
214/* Dump the CFG into a DOT graph */
215void oatDumpCFG(CompilationUnit* cUnit, const char* dirPrefix)
216{
buzbee67bf8852011-08-17 17:51:35 -0700217 FILE* file;
Elliott Hughes95572412011-12-13 18:14:20 -0800218 std::string name(art::PrettyMethod(cUnit->method_idx, *cUnit->dex_file));
buzbee67bf8852011-08-17 17:51:35 -0700219 char startOffset[80];
220 sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
Elliott Hughesc1f143d2011-12-01 17:31:10 -0800221 char* fileName = (char*) oatNew(
buzbeec143c552011-08-20 17:38:58 -0700222 strlen(dirPrefix) +
223 name.length() +
224 strlen(".dot") + 1, true);
225 sprintf(fileName, "%s%s%s.dot", dirPrefix, name.c_str(), startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700226
227 /*
228 * Convert the special characters into a filesystem- and shell-friendly
229 * format.
230 */
231 int i;
232 for (i = strlen(dirPrefix); fileName[i]; i++) {
233 if (fileName[i] == '/') {
234 fileName[i] = '_';
235 } else if (fileName[i] == ';') {
236 fileName[i] = '#';
237 } else if (fileName[i] == '$') {
238 fileName[i] = '+';
239 } else if (fileName[i] == '(' || fileName[i] == ')') {
240 fileName[i] = '@';
241 } else if (fileName[i] == '<' || fileName[i] == '>') {
242 fileName[i] = '=';
243 }
244 }
245 file = fopen(fileName, "w");
246 if (file == NULL) {
247 return;
248 }
249 fprintf(file, "digraph G {\n");
250
251 fprintf(file, " rankdir=TB\n");
252
253 int numReachableBlocks = cUnit->numReachableBlocks;
254 int idx;
255 const GrowableList *blockList = &cUnit->blockList;
256
257 for (idx = 0; idx < numReachableBlocks; idx++) {
258 int blockIdx = cUnit->dfsOrder.elemList[idx];
259 BasicBlock *bb = (BasicBlock *) oatGrowableListGetElement(blockList,
260 blockIdx);
261 if (bb == NULL) break;
262 if (bb->blockType == kEntryBlock) {
263 fprintf(file, " entry [shape=Mdiamond];\n");
264 } else if (bb->blockType == kExitBlock) {
265 fprintf(file, " exit [shape=Mdiamond];\n");
266 } else if (bb->blockType == kDalvikByteCode) {
267 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
268 bb->startOffset);
269 const MIR *mir;
270 fprintf(file, " {block id %d\\l}%s\\\n", bb->id,
271 bb->firstMIRInsn ? " | " : " ");
272 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
273 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
274 mir->ssaRep ?
275 oatFullDisassembler(cUnit, mir) :
276 dexGetOpcodeName(mir->dalvikInsn.opcode),
277 mir->next ? " | " : " ");
278 }
279 fprintf(file, " }\"];\n\n");
280 } else if (bb->blockType == kExceptionHandling) {
281 char blockName[BLOCK_NAME_LEN];
282
283 oatGetBlockName(bb, blockName);
284 fprintf(file, " %s [shape=invhouse];\n", blockName);
285 }
286
287 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
288
289 if (bb->taken) {
290 oatGetBlockName(bb, blockName1);
291 oatGetBlockName(bb->taken, blockName2);
292 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
293 blockName1, blockName2);
294 }
295 if (bb->fallThrough) {
296 oatGetBlockName(bb, blockName1);
297 oatGetBlockName(bb->fallThrough, blockName2);
298 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
299 }
300
301 if (bb->successorBlockList.blockListType != kNotUsed) {
302 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
303 bb->startOffset,
304 (bb->successorBlockList.blockListType == kCatch) ?
305 "Mrecord" : "record");
306 GrowableListIterator iterator;
307 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
308 &iterator);
309 SuccessorBlockInfo *successorBlockInfo =
310 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
311
312 int succId = 0;
313 while (true) {
314 if (successorBlockInfo == NULL) break;
315
316 BasicBlock *destBlock = successorBlockInfo->block;
317 SuccessorBlockInfo *nextSuccessorBlockInfo =
318 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
319
320 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
321 succId++,
322 successorBlockInfo->key,
323 destBlock->startOffset,
324 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
325
326 successorBlockInfo = nextSuccessorBlockInfo;
327 }
328 fprintf(file, " }\"];\n\n");
329
330 oatGetBlockName(bb, blockName1);
331 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
332 blockName1, bb->startOffset);
333
334 if (bb->successorBlockList.blockListType == kPackedSwitch ||
335 bb->successorBlockList.blockListType == kSparseSwitch) {
336
337 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
338 &iterator);
339
340 succId = 0;
341 while (true) {
342 SuccessorBlockInfo *successorBlockInfo =
343 (SuccessorBlockInfo *)
344 oatGrowableListIteratorNext(&iterator);
345 if (successorBlockInfo == NULL) break;
346
347 BasicBlock *destBlock = successorBlockInfo->block;
348
349 oatGetBlockName(destBlock, blockName2);
350 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
351 bb->startOffset, succId++,
352 blockName2);
353 }
354 }
355 }
356 fprintf(file, "\n");
357
buzbeece302932011-10-04 14:32:18 -0700358 /* Display the dominator tree */
buzbee67bf8852011-08-17 17:51:35 -0700359 oatGetBlockName(bb, blockName1);
360 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
361 blockName1, blockName1);
362 if (bb->iDom) {
363 oatGetBlockName(bb->iDom, blockName2);
364 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
365 blockName2, blockName1);
366 }
buzbee67bf8852011-08-17 17:51:35 -0700367 }
368 fprintf(file, "}\n");
369 fclose(file);
370}
371
372/* Verify if all the successor is connected with all the claimed predecessors */
buzbeeed3e9302011-09-23 17:34:19 -0700373STATIC bool verifyPredInfo(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -0700374{
375 ArenaBitVectorIterator bvIterator;
376
377 oatBitVectorIteratorInit(bb->predecessors, &bvIterator);
378 while (true) {
379 int blockIdx = oatBitVectorIteratorNext(&bvIterator);
380 if (blockIdx == -1) break;
381 BasicBlock *predBB = (BasicBlock *)
382 oatGrowableListGetElement(&cUnit->blockList, blockIdx);
383 bool found = false;
384 if (predBB->taken == bb) {
385 found = true;
386 } else if (predBB->fallThrough == bb) {
387 found = true;
388 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
389 GrowableListIterator iterator;
390 oatGrowableListIteratorInit(&predBB->successorBlockList.blocks,
391 &iterator);
392 while (true) {
393 SuccessorBlockInfo *successorBlockInfo =
394 (SuccessorBlockInfo *)
395 oatGrowableListIteratorNext(&iterator);
396 if (successorBlockInfo == NULL) break;
397 BasicBlock *succBB = successorBlockInfo->block;
398 if (succBB == bb) {
399 found = true;
400 break;
401 }
402 }
403 }
404 if (found == false) {
405 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
406 oatGetBlockName(bb, blockName1);
407 oatGetBlockName(predBB, blockName2);
408 oatDumpCFG(cUnit, "/sdcard/cfg/");
409 LOG(FATAL) << "Successor " << blockName1 << "not found from "
410 << blockName2;
411 }
412 }
413 return true;
414}
415
416/* Identify code range in try blocks and set up the empty catch blocks */
buzbeeed3e9302011-09-23 17:34:19 -0700417STATIC void processTryCatchBlocks(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700418{
Ian Rogersa3760aa2011-11-14 14:32:37 -0800419 const art::DexFile::CodeItem* code_item = cUnit->code_item;
buzbeee9a72f62011-09-04 17:59:07 -0700420 int triesSize = code_item->tries_size_;
buzbee67bf8852011-08-17 17:51:35 -0700421 int offset;
422
423 if (triesSize == 0) {
424 return;
425 }
426
buzbee67bf8852011-08-17 17:51:35 -0700427 ArenaBitVector* tryBlockAddr = cUnit->tryBlockAddr;
428
buzbeee9a72f62011-09-04 17:59:07 -0700429 for (int i = 0; i < triesSize; i++) {
430 const art::DexFile::TryItem* pTry =
Ian Rogers0571d352011-11-03 19:51:38 -0700431 art::DexFile::GetTryItems(*code_item, i);
buzbeee9a72f62011-09-04 17:59:07 -0700432 int startOffset = pTry->start_addr_;
433 int endOffset = startOffset + pTry->insn_count_;
buzbee67bf8852011-08-17 17:51:35 -0700434 for (offset = startOffset; offset < endOffset; offset++) {
435 oatSetBit(tryBlockAddr, offset);
436 }
437 }
438
buzbeee9a72f62011-09-04 17:59:07 -0700439 // Iterate over each of the handlers to enqueue the empty Catch blocks
440 const art::byte* handlers_ptr =
Ian Rogers0571d352011-11-03 19:51:38 -0700441 art::DexFile::GetCatchHandlerData(*code_item, 0);
buzbeee9a72f62011-09-04 17:59:07 -0700442 uint32_t handlers_size = art::DecodeUnsignedLeb128(&handlers_ptr);
443 for (uint32_t idx = 0; idx < handlers_size; idx++) {
Ian Rogers0571d352011-11-03 19:51:38 -0700444 art::CatchHandlerIterator iterator(handlers_ptr);
445 for (; iterator.HasNext(); iterator.Next()) {
446 uint32_t address = iterator.GetHandlerAddress();
buzbeee9a72f62011-09-04 17:59:07 -0700447 findBlock(cUnit, address, false /* split */, true /*create*/);
buzbee67bf8852011-08-17 17:51:35 -0700448 }
Ian Rogers0571d352011-11-03 19:51:38 -0700449 handlers_ptr = iterator.EndDataPointer();
buzbee67bf8852011-08-17 17:51:35 -0700450 }
451}
452
453/* Process instructions with the kInstrCanBranch flag */
buzbeee941e2c2011-12-05 12:38:17 -0800454STATIC BasicBlock* processCanBranch(CompilationUnit* cUnit,
455 BasicBlock* curBlock, MIR* insn,
456 int curOffset, int width, int flags,
457 const u2* codePtr, const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700458{
459 int target = curOffset;
460 switch (insn->dalvikInsn.opcode) {
461 case OP_GOTO:
462 case OP_GOTO_16:
463 case OP_GOTO_32:
464 target += (int) insn->dalvikInsn.vA;
465 break;
466 case OP_IF_EQ:
467 case OP_IF_NE:
468 case OP_IF_LT:
469 case OP_IF_GE:
470 case OP_IF_GT:
471 case OP_IF_LE:
472 target += (int) insn->dalvikInsn.vC;
473 break;
474 case OP_IF_EQZ:
475 case OP_IF_NEZ:
476 case OP_IF_LTZ:
477 case OP_IF_GEZ:
478 case OP_IF_GTZ:
479 case OP_IF_LEZ:
480 target += (int) insn->dalvikInsn.vB;
481 break;
482 default:
483 LOG(FATAL) << "Unexpected opcode(" << (int)insn->dalvikInsn.opcode
484 << ") with kInstrCanBranch set";
485 }
buzbeee941e2c2011-12-05 12:38:17 -0800486 /*
487 * Some ugliness here. It is possible that findBlock will
488 * split the current block. In that case, we need to operate
489 * on the 2nd half on the split pair. It isn't directly obvious
490 * when this happens, so we infer.
491 */
492 DCHECK(curBlock->lastMIRInsn == insn);
buzbee67bf8852011-08-17 17:51:35 -0700493 BasicBlock *takenBlock = findBlock(cUnit, target,
494 /* split */
495 true,
496 /* create */
497 true);
buzbeee941e2c2011-12-05 12:38:17 -0800498 if (curBlock->lastMIRInsn != insn) {
499 DCHECK(takenBlock->lastMIRInsn == insn);
500 curBlock = curBlock->fallThrough;
501 }
buzbee67bf8852011-08-17 17:51:35 -0700502 curBlock->taken = takenBlock;
503 oatSetBit(takenBlock->predecessors, curBlock->id);
504
505 /* Always terminate the current block for conditional branches */
506 if (flags & kInstrCanContinue) {
507 BasicBlock *fallthroughBlock = findBlock(cUnit,
508 curOffset + width,
509 /*
510 * If the method is processed
511 * in sequential order from the
512 * beginning, we don't need to
513 * specify split for continue
514 * blocks. However, this
515 * routine can be called by
516 * compileLoop, which starts
517 * parsing the method from an
518 * arbitrary address in the
519 * method body.
520 */
521 true,
522 /* create */
523 true);
524 curBlock->fallThrough = fallthroughBlock;
525 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
526 } else if (codePtr < codeEnd) {
527 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
528 if (contentIsInsn(codePtr)) {
529 findBlock(cUnit, curOffset + width,
530 /* split */
531 false,
532 /* create */
533 true);
534 }
535 }
buzbeee941e2c2011-12-05 12:38:17 -0800536 return curBlock;
buzbee67bf8852011-08-17 17:51:35 -0700537}
538
539/* Process instructions with the kInstrCanSwitch flag */
buzbeeed3e9302011-09-23 17:34:19 -0700540STATIC void processCanSwitch(CompilationUnit* cUnit, BasicBlock* curBlock,
buzbee67bf8852011-08-17 17:51:35 -0700541 MIR* insn, int curOffset, int width, int flags)
542{
543 u2* switchData= (u2 *) (cUnit->insns + curOffset +
544 insn->dalvikInsn.vB);
545 int size;
546 int* keyTable;
547 int* targetTable;
548 int i;
549 int firstKey;
550
551 /*
552 * Packed switch data format:
553 * ushort ident = 0x0100 magic value
554 * ushort size number of entries in the table
555 * int first_key first (and lowest) switch case value
556 * int targets[size] branch targets, relative to switch opcode
557 *
558 * Total size is (4+size*2) 16-bit code units.
559 */
560 if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
buzbeeed3e9302011-09-23 17:34:19 -0700561 DCHECK_EQ(switchData[0], kPackedSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700562 size = switchData[1];
563 firstKey = switchData[2] | (switchData[3] << 16);
564 targetTable = (int *) &switchData[4];
565 keyTable = NULL; // Make the compiler happy
566 /*
567 * Sparse switch data format:
568 * ushort ident = 0x0200 magic value
569 * ushort size number of entries in the table; > 0
570 * int keys[size] keys, sorted low-to-high; 32-bit aligned
571 * int targets[size] branch targets, relative to switch opcode
572 *
573 * Total size is (2+size*4) 16-bit code units.
574 */
575 } else {
buzbeeed3e9302011-09-23 17:34:19 -0700576 DCHECK_EQ(switchData[0], kSparseSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700577 size = switchData[1];
578 keyTable = (int *) &switchData[2];
579 targetTable = (int *) &switchData[2 + size*2];
580 firstKey = 0; // To make the compiler happy
581 }
582
583 if (curBlock->successorBlockList.blockListType != kNotUsed) {
584 LOG(FATAL) << "Successor block list already in use: " <<
585 (int)curBlock->successorBlockList.blockListType;
586 }
587 curBlock->successorBlockList.blockListType =
588 (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
589 kPackedSwitch : kSparseSwitch;
590 oatInitGrowableList(&curBlock->successorBlockList.blocks, size);
591
592 for (i = 0; i < size; i++) {
593 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
594 /* split */
595 true,
596 /* create */
597 true);
598 SuccessorBlockInfo *successorBlockInfo =
599 (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
600 false);
601 successorBlockInfo->block = caseBlock;
602 successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)?
603 firstKey + i : keyTable[i];
604 oatInsertGrowableList(&curBlock->successorBlockList.blocks,
605 (intptr_t) successorBlockInfo);
606 oatSetBit(caseBlock->predecessors, curBlock->id);
607 }
608
609 /* Fall-through case */
610 BasicBlock* fallthroughBlock = findBlock(cUnit,
611 curOffset + width,
612 /* split */
613 false,
614 /* create */
615 true);
616 curBlock->fallThrough = fallthroughBlock;
617 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
618}
619
620/* Process instructions with the kInstrCanThrow flag */
buzbeeed3e9302011-09-23 17:34:19 -0700621STATIC void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock,
buzbee67bf8852011-08-17 17:51:35 -0700622 MIR* insn, int curOffset, int width, int flags,
623 ArenaBitVector* tryBlockAddr, const u2* codePtr,
624 const u2* codeEnd)
625{
Ian Rogersa3760aa2011-11-14 14:32:37 -0800626 const art::DexFile::CodeItem* code_item = cUnit->code_item;
buzbee67bf8852011-08-17 17:51:35 -0700627
628 /* In try block */
629 if (oatIsBitSet(tryBlockAddr, curOffset)) {
Ian Rogers0571d352011-11-03 19:51:38 -0700630 art::CatchHandlerIterator iterator(*code_item, curOffset);
buzbee67bf8852011-08-17 17:51:35 -0700631
buzbee67bf8852011-08-17 17:51:35 -0700632 if (curBlock->successorBlockList.blockListType != kNotUsed) {
633 LOG(FATAL) << "Successor block list already in use: " <<
634 (int)curBlock->successorBlockList.blockListType;
635 }
buzbeee9a72f62011-09-04 17:59:07 -0700636
buzbee67bf8852011-08-17 17:51:35 -0700637 curBlock->successorBlockList.blockListType = kCatch;
638 oatInitGrowableList(&curBlock->successorBlockList.blocks, 2);
639
Ian Rogers0571d352011-11-03 19:51:38 -0700640 for (;iterator.HasNext(); iterator.Next()) {
641 BasicBlock *catchBlock = findBlock(cUnit, iterator.GetHandlerAddress(),
buzbeee9a72f62011-09-04 17:59:07 -0700642 false /* split*/,
643 false /* creat */);
buzbee43a36422011-09-14 14:00:13 -0700644 catchBlock->catchEntry = true;
buzbee67bf8852011-08-17 17:51:35 -0700645 SuccessorBlockInfo *successorBlockInfo =
buzbeee9a72f62011-09-04 17:59:07 -0700646 (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
647 false);
buzbee67bf8852011-08-17 17:51:35 -0700648 successorBlockInfo->block = catchBlock;
Ian Rogers0571d352011-11-03 19:51:38 -0700649 successorBlockInfo->key = iterator.GetHandlerTypeIndex();
buzbee67bf8852011-08-17 17:51:35 -0700650 oatInsertGrowableList(&curBlock->successorBlockList.blocks,
651 (intptr_t) successorBlockInfo);
652 oatSetBit(catchBlock->predecessors, curBlock->id);
653 }
654 } else {
655 BasicBlock *ehBlock = oatNewBB(kExceptionHandling,
656 cUnit->numBlocks++);
657 curBlock->taken = ehBlock;
658 oatInsertGrowableList(&cUnit->blockList, (intptr_t) ehBlock);
659 ehBlock->startOffset = curOffset;
660 oatSetBit(ehBlock->predecessors, curBlock->id);
661 }
662
663 /*
664 * Force the current block to terminate.
665 *
666 * Data may be present before codeEnd, so we need to parse it to know
667 * whether it is code or data.
668 */
669 if (codePtr < codeEnd) {
670 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
671 if (contentIsInsn(codePtr)) {
672 BasicBlock *fallthroughBlock = findBlock(cUnit,
673 curOffset + width,
674 /* split */
675 false,
676 /* create */
677 true);
678 /*
buzbee510c6052011-10-27 10:47:20 -0700679 * OP_THROW is an unconditional branch. NOTE:
680 * OP_THROW_VERIFICATION_ERROR is also an unconditional
681 * branch, but we shouldn't treat it as such until we have
682 * a dead code elimination pass (which won't be important
683 * until inlining w/ constant propogation is implemented.
buzbee67bf8852011-08-17 17:51:35 -0700684 */
buzbee510c6052011-10-27 10:47:20 -0700685 if (insn->dalvikInsn.opcode != OP_THROW) {
buzbee67bf8852011-08-17 17:51:35 -0700686 curBlock->fallThrough = fallthroughBlock;
687 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
688 }
689 }
690 }
691}
692
693/*
694 * Compile a method.
695 */
Ian Rogersa3760aa2011-11-14 14:32:37 -0800696CompiledMethod* oatCompileMethod(const Compiler& compiler, const art::DexFile::CodeItem* code_item,
697 uint32_t access_flags, uint32_t method_idx,
698 const art::ClassLoader* class_loader,
699 const art::DexFile& dex_file, art::InstructionSet insnSet)
buzbee67bf8852011-08-17 17:51:35 -0700700{
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800701 VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
buzbee2a475e72011-09-07 17:19:17 -0700702 oatArenaReset();
Brian Carlstrom94496d32011-08-22 09:22:47 -0700703
buzbeec143c552011-08-20 17:38:58 -0700704 const u2* codePtr = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700705 const u2* codeEnd = code_item->insns_ + code_item->insns_size_in_code_units_;
buzbee67bf8852011-08-17 17:51:35 -0700706 int numBlocks = 0;
707 unsigned int curOffset = 0;
708
Brian Carlstrom16192862011-09-12 17:50:06 -0700709 oatInit(compiler);
buzbee67bf8852011-08-17 17:51:35 -0700710
Ian Rogersa3760aa2011-11-14 14:32:37 -0800711 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700712 UniquePtr<CompilationUnit> cUnit(new CompilationUnit);
713 memset(cUnit.get(), 0, sizeof(*cUnit));
714 cUnit->compiler = &compiler;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800715 cUnit->class_linker = class_linker;
716 cUnit->dex_file = &dex_file;
717 cUnit->dex_cache = class_linker->FindDexCache(dex_file);
718 cUnit->method_idx = method_idx;
719 cUnit->code_item = code_item;
720 cUnit->access_flags = access_flags;
721 cUnit->shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700722 cUnit->instructionSet = (OatInstructionSetType)insnSet;
723 cUnit->insns = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700724 cUnit->insnsSize = code_item->insns_size_in_code_units_;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800725 cUnit->numIns = code_item->ins_size_;
726 cUnit->numRegs = code_item->registers_size_ - cUnit->numIns;
727 cUnit->numOuts = code_item->outs_size_;
728 /* Adjust this value accordingly once inlining is performed */
729 cUnit->numDalvikRegisters = code_item->registers_size_;
buzbeece302932011-10-04 14:32:18 -0700730 bool useMatch = compilerMethodMatch.length() != 0;
731 bool match = useMatch && (compilerFlipMatch ^
Ian Rogersa3760aa2011-11-14 14:32:37 -0800732 (PrettyMethod(method_idx, dex_file).find(compilerMethodMatch) != std::string::npos));
buzbeece302932011-10-04 14:32:18 -0700733 if (!useMatch || match) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700734 cUnit->disableOpt = compilerOptimizerDisableFlags;
735 cUnit->enableDebug = compilerDebugFlags;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800736 cUnit->printMe = VLOG_IS_ON(compiler) || (cUnit->enableDebug & (1 << kDebugVerbose));
buzbeece302932011-10-04 14:32:18 -0700737 }
buzbee67bf8852011-08-17 17:51:35 -0700738
buzbeecefd1872011-09-09 09:59:52 -0700739 /* Assume non-throwing leaf */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700740 cUnit->attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
buzbeecefd1872011-09-09 09:59:52 -0700741
buzbee67bf8852011-08-17 17:51:35 -0700742 /* Initialize the block list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700743 oatInitGrowableList(&cUnit->blockList, 40);
buzbee67bf8852011-08-17 17:51:35 -0700744
745 /* Initialize the switchTables list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700746 oatInitGrowableList(&cUnit->switchTables, 4);
buzbee67bf8852011-08-17 17:51:35 -0700747
748 /* Intialize the fillArrayData list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700749 oatInitGrowableList(&cUnit->fillArrayData, 4);
buzbee67bf8852011-08-17 17:51:35 -0700750
buzbee5ade1d22011-09-09 14:44:52 -0700751 /* Intialize the throwLaunchpads list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700752 oatInitGrowableList(&cUnit->throwLaunchpads, 4);
buzbee5ade1d22011-09-09 14:44:52 -0700753
buzbeec1f45042011-09-21 16:03:19 -0700754 /* Intialize the suspendLaunchpads list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700755 oatInitGrowableList(&cUnit->suspendLaunchpads, 4);
buzbeec1f45042011-09-21 16:03:19 -0700756
buzbee67bf8852011-08-17 17:51:35 -0700757 /* Allocate the bit-vector to track the beginning of basic blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700758 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit->insnsSize,
buzbee67bf8852011-08-17 17:51:35 -0700759 true /* expandable */);
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700760 cUnit->tryBlockAddr = tryBlockAddr;
buzbee67bf8852011-08-17 17:51:35 -0700761
762 /* Create the default entry and exit blocks and enter them to the list */
763 BasicBlock *entryBlock = oatNewBB(kEntryBlock, numBlocks++);
764 BasicBlock *exitBlock = oatNewBB(kExitBlock, numBlocks++);
765
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700766 cUnit->entryBlock = entryBlock;
767 cUnit->exitBlock = exitBlock;
buzbee67bf8852011-08-17 17:51:35 -0700768
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700769 oatInsertGrowableList(&cUnit->blockList, (intptr_t) entryBlock);
770 oatInsertGrowableList(&cUnit->blockList, (intptr_t) exitBlock);
buzbee67bf8852011-08-17 17:51:35 -0700771
772 /* Current block to record parsed instructions */
773 BasicBlock *curBlock = oatNewBB(kDalvikByteCode, numBlocks++);
774 curBlock->startOffset = 0;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700775 oatInsertGrowableList(&cUnit->blockList, (intptr_t) curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700776 entryBlock->fallThrough = curBlock;
777 oatSetBit(curBlock->predecessors, entryBlock->id);
778
779 /*
780 * Store back the number of blocks since new blocks may be created of
781 * accessing cUnit.
782 */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700783 cUnit->numBlocks = numBlocks;
buzbee67bf8852011-08-17 17:51:35 -0700784
785 /* Identify code range in try blocks and set up the empty catch blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700786 processTryCatchBlocks(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700787
788 /* Parse all instructions and put them into containing basic blocks */
789 while (codePtr < codeEnd) {
790 MIR *insn = (MIR *) oatNew(sizeof(MIR), true);
791 insn->offset = curOffset;
792 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
793 insn->width = width;
794
795 /* Terminate when the data section is seen */
796 if (width == 0)
797 break;
798
799 oatAppendMIR(curBlock, insn);
800
801 codePtr += width;
802 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
803
804 if (flags & kInstrCanBranch) {
buzbeee941e2c2011-12-05 12:38:17 -0800805 curBlock = processCanBranch(cUnit.get(), curBlock, insn, curOffset,
806 width, flags, codePtr, codeEnd);
buzbee67bf8852011-08-17 17:51:35 -0700807 } else if (flags & kInstrCanReturn) {
808 curBlock->fallThrough = exitBlock;
809 oatSetBit(exitBlock->predecessors, curBlock->id);
810 /*
811 * Terminate the current block if there are instructions
812 * afterwards.
813 */
814 if (codePtr < codeEnd) {
815 /*
816 * Create a fallthrough block for real instructions
817 * (incl. OP_NOP).
818 */
819 if (contentIsInsn(codePtr)) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700820 findBlock(cUnit.get(), curOffset + width,
buzbee67bf8852011-08-17 17:51:35 -0700821 /* split */
822 false,
823 /* create */
824 true);
825 }
826 }
827 } else if (flags & kInstrCanThrow) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700828 processCanThrow(cUnit.get(), curBlock, insn, curOffset, width, flags,
buzbee67bf8852011-08-17 17:51:35 -0700829 tryBlockAddr, codePtr, codeEnd);
830 } else if (flags & kInstrCanSwitch) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700831 processCanSwitch(cUnit.get(), curBlock, insn, curOffset, width, flags);
buzbee67bf8852011-08-17 17:51:35 -0700832 }
833 curOffset += width;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700834 BasicBlock *nextBlock = findBlock(cUnit.get(), curOffset,
buzbee67bf8852011-08-17 17:51:35 -0700835 /* split */
836 false,
837 /* create */
838 false);
839 if (nextBlock) {
840 /*
841 * The next instruction could be the target of a previously parsed
842 * forward branch so a block is already created. If the current
843 * instruction is not an unconditional branch, connect them through
844 * the fall-through link.
845 */
buzbeeed3e9302011-09-23 17:34:19 -0700846 DCHECK(curBlock->fallThrough == NULL ||
buzbee67bf8852011-08-17 17:51:35 -0700847 curBlock->fallThrough == nextBlock ||
848 curBlock->fallThrough == exitBlock);
849
850 if ((curBlock->fallThrough == NULL) &&
851 (flags & kInstrCanContinue)) {
852 curBlock->fallThrough = nextBlock;
853 oatSetBit(nextBlock->predecessors, curBlock->id);
854 }
855 curBlock = nextBlock;
856 }
857 }
858
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700859 if (cUnit->printMe) {
860 oatDumpCompilationUnit(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700861 }
862
buzbee67bf8852011-08-17 17:51:35 -0700863 /* Verify if all blocks are connected as claimed */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700864 oatDataFlowAnalysisDispatcher(cUnit.get(), verifyPredInfo, kAllNodes, false /* isIterative */);
buzbee67bf8852011-08-17 17:51:35 -0700865
866 /* Perform SSA transformation for the whole method */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700867 oatMethodSSATransformation(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700868
buzbee43a36422011-09-14 14:00:13 -0700869 /* Perform null check elimination */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700870 oatMethodNullCheckElimination(cUnit.get());
buzbee43a36422011-09-14 14:00:13 -0700871
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700872 oatInitializeRegAlloc(cUnit.get()); // Needs to happen after SSA naming
buzbee67bf8852011-08-17 17:51:35 -0700873
874 /* Allocate Registers using simple local allocation scheme */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700875 oatSimpleRegAlloc(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700876
877 /* Convert MIR to LIR, etc. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700878 oatMethodMIR2LIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700879
880 // Debugging only
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700881 if (cUnit->enableDebug & (1 << kDebugDumpCFG)) {
882 oatDumpCFG(cUnit.get(), "/sdcard/cfg/");
buzbeeec5adf32011-09-11 15:25:43 -0700883 }
buzbee67bf8852011-08-17 17:51:35 -0700884
885 /* Method is not empty */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700886 if (cUnit->firstLIRInsn) {
buzbee67bf8852011-08-17 17:51:35 -0700887
888 // mark the targets of switch statement case labels
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700889 oatProcessSwitchTables(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700890
891 /* Convert LIR into machine code. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700892 oatAssembleLIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700893
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700894 if (cUnit->printMe) {
895 oatCodegenDump(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700896 }
897 }
898
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700899 // Combine vmap tables - core regs, then fp regs - into vmapTable
900 std::vector<uint16_t> vmapTable;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700901 for (size_t i = 0 ; i < cUnit->coreVmapTable.size(); i++) {
902 vmapTable.push_back(cUnit->coreVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700903 }
buzbeec41e5b52011-09-23 12:46:19 -0700904 // Add a marker to take place of lr
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -0700905 vmapTable.push_back(INVALID_VREG);
buzbeec41e5b52011-09-23 12:46:19 -0700906 // Combine vmap tables - core regs, then fp regs
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700907 for (uint32_t i = 0; i < cUnit->fpVmapTable.size(); i++) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700908 vmapTable.push_back(cUnit->fpVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700909 }
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -0700910 DCHECK_EQ(vmapTable.size(),
911 static_cast<uint32_t>(__builtin_popcount(cUnit->coreSpillMask)
912 + __builtin_popcount(cUnit->fpSpillMask)));
913 DCHECK_GE(vmapTable.size(), 1U); // should always at least one INVALID_VREG for lr
914
Ian Rogers0571d352011-11-03 19:51:38 -0700915 CompiledMethod* result = new CompiledMethod(art::kThumb2, cUnit->codeBuffer,
916 cUnit->frameSize, cUnit->coreSpillMask,
917 cUnit->fpSpillMask, cUnit->mappingTable,
918 vmapTable);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700919
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800920 VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file)
921 << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0])) << " bytes)";
buzbee67bf8852011-08-17 17:51:35 -0700922
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700923 return result;
buzbee67bf8852011-08-17 17:51:35 -0700924}
925
Brian Carlstrom16192862011-09-12 17:50:06 -0700926void oatInit(const Compiler& compiler)
buzbee67bf8852011-08-17 17:51:35 -0700927{
buzbee67bf8852011-08-17 17:51:35 -0700928 static bool initialized = false;
929 if (initialized)
930 return;
931 initialized = true;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800932 VLOG(compiler) << "Initializing compiler";
buzbee67bf8852011-08-17 17:51:35 -0700933 if (!oatArchInit()) {
934 LOG(FATAL) << "Failed to initialize oat";
935 }
936 if (!oatHeapInit()) {
937 LOG(FATAL) << "Failed to initialize oat heap";
938 }
939}