blob: 2eba586a22331a93850939ae4fc932550530abe7 [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) |
buzbee769fde12012-01-05 17:35:23 -080031 //(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) |
buzbee34c77ad2012-01-11 13:01:32 -080044 //(1 << kDebugExerciseResolveMethod) |
buzbeece302932011-10-04 14:32:18 -070045 0;
46
47std::string compilerMethodMatch; // Method name match to apply above flags
48
49bool compilerFlipMatch = false; // Reverses sense of method name match
50
buzbeeed3e9302011-09-23 17:34:19 -070051STATIC inline bool contentIsInsn(const u2* codePtr) {
buzbee67bf8852011-08-17 17:51:35 -070052 u2 instr = *codePtr;
53 Opcode opcode = (Opcode)(instr & 0xff);
54
55 /*
56 * Since the low 8-bit in metadata may look like OP_NOP, we need to check
57 * both the low and whole sub-word to determine whether it is code or data.
58 */
59 return (opcode != OP_NOP || instr == 0);
60}
61
62/*
63 * Parse an instruction, return the length of the instruction
64 */
buzbeeed3e9302011-09-23 17:34:19 -070065STATIC inline int parseInsn(const u2* codePtr, DecodedInstruction* decInsn,
buzbee67bf8852011-08-17 17:51:35 -070066 bool printMe)
67{
68 // Don't parse instruction data
69 if (!contentIsInsn(codePtr)) {
70 return 0;
71 }
72
73 u2 instr = *codePtr;
74 Opcode opcode = dexOpcodeFromCodeUnit(instr);
75
76 dexDecodeInstruction(codePtr, decInsn);
77 if (printMe) {
Elliott Hughesc1f143d2011-12-01 17:31:10 -080078 char* decodedString = oatGetDalvikDisassembly(decInsn, NULL);
buzbee67bf8852011-08-17 17:51:35 -070079 LOG(INFO) << codePtr << ": 0x" << std::hex << (int)opcode <<
80 " " << decodedString;
81 }
82 return dexGetWidthFromOpcode(opcode);
83}
84
85#define UNKNOWN_TARGET 0xffffffff
86
buzbeeed3e9302011-09-23 17:34:19 -070087STATIC inline bool isGoto(MIR* insn)
buzbee67bf8852011-08-17 17:51:35 -070088{
89 switch (insn->dalvikInsn.opcode) {
90 case OP_GOTO:
91 case OP_GOTO_16:
92 case OP_GOTO_32:
93 return true;
94 default:
95 return false;
96 }
97}
98
99/*
100 * Identify unconditional branch instructions
101 */
buzbeeed3e9302011-09-23 17:34:19 -0700102STATIC inline bool isUnconditionalBranch(MIR* insn)
buzbee67bf8852011-08-17 17:51:35 -0700103{
104 switch (insn->dalvikInsn.opcode) {
105 case OP_RETURN_VOID:
106 case OP_RETURN:
107 case OP_RETURN_WIDE:
108 case OP_RETURN_OBJECT:
109 return true;
110 default:
111 return isGoto(insn);
112 }
113}
114
115/* Split an existing block from the specified code offset into two */
buzbeeed3e9302011-09-23 17:34:19 -0700116STATIC BasicBlock *splitBlock(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -0700117 unsigned int codeOffset,
118 BasicBlock* origBlock)
119{
120 MIR* insn = origBlock->firstMIRInsn;
121 while (insn) {
122 if (insn->offset == codeOffset) break;
123 insn = insn->next;
124 }
125 if (insn == NULL) {
126 LOG(FATAL) << "Break split failed";
127 }
128 BasicBlock *bottomBlock = oatNewBB(kDalvikByteCode,
129 cUnit->numBlocks++);
130 oatInsertGrowableList(&cUnit->blockList, (intptr_t) bottomBlock);
131
132 bottomBlock->startOffset = codeOffset;
133 bottomBlock->firstMIRInsn = insn;
134 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
135
136 /* Handle the taken path */
137 bottomBlock->taken = origBlock->taken;
138 if (bottomBlock->taken) {
139 origBlock->taken = NULL;
140 oatClearBit(bottomBlock->taken->predecessors, origBlock->id);
141 oatSetBit(bottomBlock->taken->predecessors, bottomBlock->id);
142 }
143
144 /* Handle the fallthrough path */
145 bottomBlock->needFallThroughBranch = origBlock->needFallThroughBranch;
146 bottomBlock->fallThrough = origBlock->fallThrough;
147 origBlock->fallThrough = bottomBlock;
148 origBlock->needFallThroughBranch = true;
149 oatSetBit(bottomBlock->predecessors, origBlock->id);
150 if (bottomBlock->fallThrough) {
151 oatClearBit(bottomBlock->fallThrough->predecessors,
152 origBlock->id);
153 oatSetBit(bottomBlock->fallThrough->predecessors,
154 bottomBlock->id);
155 }
156
157 /* Handle the successor list */
158 if (origBlock->successorBlockList.blockListType != kNotUsed) {
159 bottomBlock->successorBlockList = origBlock->successorBlockList;
160 origBlock->successorBlockList.blockListType = kNotUsed;
161 GrowableListIterator iterator;
162
163 oatGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
164 &iterator);
165 while (true) {
166 SuccessorBlockInfo *successorBlockInfo =
167 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
168 if (successorBlockInfo == NULL) break;
169 BasicBlock *bb = successorBlockInfo->block;
170 oatClearBit(bb->predecessors, origBlock->id);
171 oatSetBit(bb->predecessors, bottomBlock->id);
172 }
173 }
174
175 origBlock->lastMIRInsn = insn->prev;
176
177 insn->prev->next = NULL;
178 insn->prev = NULL;
179 return bottomBlock;
180}
181
182/*
183 * Given a code offset, find out the block that starts with it. If the offset
184 * is in the middle of an existing block, split it into two.
185 */
buzbeeed3e9302011-09-23 17:34:19 -0700186STATIC BasicBlock *findBlock(CompilationUnit* cUnit,
buzbee67bf8852011-08-17 17:51:35 -0700187 unsigned int codeOffset,
188 bool split, bool create)
189{
190 GrowableList* blockList = &cUnit->blockList;
191 BasicBlock* bb;
192 unsigned int i;
193
194 for (i = 0; i < blockList->numUsed; i++) {
195 bb = (BasicBlock *) blockList->elemList[i];
196 if (bb->blockType != kDalvikByteCode) continue;
197 if (bb->startOffset == codeOffset) return bb;
198 /* Check if a branch jumps into the middle of an existing block */
199 if ((split == true) && (codeOffset > bb->startOffset) &&
200 (bb->lastMIRInsn != NULL) &&
201 (codeOffset <= bb->lastMIRInsn->offset)) {
202 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb);
203 return newBB;
204 }
205 }
206 if (create) {
207 bb = oatNewBB(kDalvikByteCode, cUnit->numBlocks++);
208 oatInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
209 bb->startOffset = codeOffset;
210 return bb;
211 }
212 return NULL;
213}
214
215/* Dump the CFG into a DOT graph */
216void oatDumpCFG(CompilationUnit* cUnit, const char* dirPrefix)
217{
buzbee67bf8852011-08-17 17:51:35 -0700218 FILE* file;
Elliott Hughes95572412011-12-13 18:14:20 -0800219 std::string name(art::PrettyMethod(cUnit->method_idx, *cUnit->dex_file));
buzbee67bf8852011-08-17 17:51:35 -0700220 char startOffset[80];
221 sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
Elliott Hughesc1f143d2011-12-01 17:31:10 -0800222 char* fileName = (char*) oatNew(
buzbeec143c552011-08-20 17:38:58 -0700223 strlen(dirPrefix) +
224 name.length() +
225 strlen(".dot") + 1, true);
226 sprintf(fileName, "%s%s%s.dot", dirPrefix, name.c_str(), startOffset);
buzbee67bf8852011-08-17 17:51:35 -0700227
228 /*
229 * Convert the special characters into a filesystem- and shell-friendly
230 * format.
231 */
232 int i;
233 for (i = strlen(dirPrefix); fileName[i]; i++) {
234 if (fileName[i] == '/') {
235 fileName[i] = '_';
236 } else if (fileName[i] == ';') {
237 fileName[i] = '#';
238 } else if (fileName[i] == '$') {
239 fileName[i] = '+';
240 } else if (fileName[i] == '(' || fileName[i] == ')') {
241 fileName[i] = '@';
242 } else if (fileName[i] == '<' || fileName[i] == '>') {
243 fileName[i] = '=';
244 }
245 }
246 file = fopen(fileName, "w");
247 if (file == NULL) {
248 return;
249 }
250 fprintf(file, "digraph G {\n");
251
252 fprintf(file, " rankdir=TB\n");
253
254 int numReachableBlocks = cUnit->numReachableBlocks;
255 int idx;
256 const GrowableList *blockList = &cUnit->blockList;
257
258 for (idx = 0; idx < numReachableBlocks; idx++) {
259 int blockIdx = cUnit->dfsOrder.elemList[idx];
260 BasicBlock *bb = (BasicBlock *) oatGrowableListGetElement(blockList,
261 blockIdx);
262 if (bb == NULL) break;
263 if (bb->blockType == kEntryBlock) {
264 fprintf(file, " entry [shape=Mdiamond];\n");
265 } else if (bb->blockType == kExitBlock) {
266 fprintf(file, " exit [shape=Mdiamond];\n");
267 } else if (bb->blockType == kDalvikByteCode) {
268 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
269 bb->startOffset);
270 const MIR *mir;
271 fprintf(file, " {block id %d\\l}%s\\\n", bb->id,
272 bb->firstMIRInsn ? " | " : " ");
273 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
274 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
275 mir->ssaRep ?
276 oatFullDisassembler(cUnit, mir) :
277 dexGetOpcodeName(mir->dalvikInsn.opcode),
278 mir->next ? " | " : " ");
279 }
280 fprintf(file, " }\"];\n\n");
281 } else if (bb->blockType == kExceptionHandling) {
282 char blockName[BLOCK_NAME_LEN];
283
284 oatGetBlockName(bb, blockName);
285 fprintf(file, " %s [shape=invhouse];\n", blockName);
286 }
287
288 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
289
290 if (bb->taken) {
291 oatGetBlockName(bb, blockName1);
292 oatGetBlockName(bb->taken, blockName2);
293 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
294 blockName1, blockName2);
295 }
296 if (bb->fallThrough) {
297 oatGetBlockName(bb, blockName1);
298 oatGetBlockName(bb->fallThrough, blockName2);
299 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
300 }
301
302 if (bb->successorBlockList.blockListType != kNotUsed) {
303 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
304 bb->startOffset,
305 (bb->successorBlockList.blockListType == kCatch) ?
306 "Mrecord" : "record");
307 GrowableListIterator iterator;
308 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
309 &iterator);
310 SuccessorBlockInfo *successorBlockInfo =
311 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
312
313 int succId = 0;
314 while (true) {
315 if (successorBlockInfo == NULL) break;
316
317 BasicBlock *destBlock = successorBlockInfo->block;
318 SuccessorBlockInfo *nextSuccessorBlockInfo =
319 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
320
321 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
322 succId++,
323 successorBlockInfo->key,
324 destBlock->startOffset,
325 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
326
327 successorBlockInfo = nextSuccessorBlockInfo;
328 }
329 fprintf(file, " }\"];\n\n");
330
331 oatGetBlockName(bb, blockName1);
332 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
333 blockName1, bb->startOffset);
334
335 if (bb->successorBlockList.blockListType == kPackedSwitch ||
336 bb->successorBlockList.blockListType == kSparseSwitch) {
337
338 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
339 &iterator);
340
341 succId = 0;
342 while (true) {
343 SuccessorBlockInfo *successorBlockInfo =
344 (SuccessorBlockInfo *)
345 oatGrowableListIteratorNext(&iterator);
346 if (successorBlockInfo == NULL) break;
347
348 BasicBlock *destBlock = successorBlockInfo->block;
349
350 oatGetBlockName(destBlock, blockName2);
351 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
352 bb->startOffset, succId++,
353 blockName2);
354 }
355 }
356 }
357 fprintf(file, "\n");
358
buzbeece302932011-10-04 14:32:18 -0700359 /* Display the dominator tree */
buzbee67bf8852011-08-17 17:51:35 -0700360 oatGetBlockName(bb, blockName1);
361 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
362 blockName1, blockName1);
363 if (bb->iDom) {
364 oatGetBlockName(bb->iDom, blockName2);
365 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
366 blockName2, blockName1);
367 }
buzbee67bf8852011-08-17 17:51:35 -0700368 }
369 fprintf(file, "}\n");
370 fclose(file);
371}
372
373/* Verify if all the successor is connected with all the claimed predecessors */
buzbeeed3e9302011-09-23 17:34:19 -0700374STATIC bool verifyPredInfo(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -0700375{
376 ArenaBitVectorIterator bvIterator;
377
378 oatBitVectorIteratorInit(bb->predecessors, &bvIterator);
379 while (true) {
380 int blockIdx = oatBitVectorIteratorNext(&bvIterator);
381 if (blockIdx == -1) break;
382 BasicBlock *predBB = (BasicBlock *)
383 oatGrowableListGetElement(&cUnit->blockList, blockIdx);
384 bool found = false;
385 if (predBB->taken == bb) {
386 found = true;
387 } else if (predBB->fallThrough == bb) {
388 found = true;
389 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
390 GrowableListIterator iterator;
391 oatGrowableListIteratorInit(&predBB->successorBlockList.blocks,
392 &iterator);
393 while (true) {
394 SuccessorBlockInfo *successorBlockInfo =
395 (SuccessorBlockInfo *)
396 oatGrowableListIteratorNext(&iterator);
397 if (successorBlockInfo == NULL) break;
398 BasicBlock *succBB = successorBlockInfo->block;
399 if (succBB == bb) {
400 found = true;
401 break;
402 }
403 }
404 }
405 if (found == false) {
406 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
407 oatGetBlockName(bb, blockName1);
408 oatGetBlockName(predBB, blockName2);
409 oatDumpCFG(cUnit, "/sdcard/cfg/");
410 LOG(FATAL) << "Successor " << blockName1 << "not found from "
411 << blockName2;
412 }
413 }
414 return true;
415}
416
417/* Identify code range in try blocks and set up the empty catch blocks */
buzbeeed3e9302011-09-23 17:34:19 -0700418STATIC void processTryCatchBlocks(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700419{
Ian Rogersa3760aa2011-11-14 14:32:37 -0800420 const art::DexFile::CodeItem* code_item = cUnit->code_item;
buzbeee9a72f62011-09-04 17:59:07 -0700421 int triesSize = code_item->tries_size_;
buzbee67bf8852011-08-17 17:51:35 -0700422 int offset;
423
424 if (triesSize == 0) {
425 return;
426 }
427
buzbee67bf8852011-08-17 17:51:35 -0700428 ArenaBitVector* tryBlockAddr = cUnit->tryBlockAddr;
429
buzbeee9a72f62011-09-04 17:59:07 -0700430 for (int i = 0; i < triesSize; i++) {
431 const art::DexFile::TryItem* pTry =
Ian Rogers0571d352011-11-03 19:51:38 -0700432 art::DexFile::GetTryItems(*code_item, i);
buzbeee9a72f62011-09-04 17:59:07 -0700433 int startOffset = pTry->start_addr_;
434 int endOffset = startOffset + pTry->insn_count_;
buzbee67bf8852011-08-17 17:51:35 -0700435 for (offset = startOffset; offset < endOffset; offset++) {
436 oatSetBit(tryBlockAddr, offset);
437 }
438 }
439
buzbeee9a72f62011-09-04 17:59:07 -0700440 // Iterate over each of the handlers to enqueue the empty Catch blocks
441 const art::byte* handlers_ptr =
Ian Rogers0571d352011-11-03 19:51:38 -0700442 art::DexFile::GetCatchHandlerData(*code_item, 0);
buzbeee9a72f62011-09-04 17:59:07 -0700443 uint32_t handlers_size = art::DecodeUnsignedLeb128(&handlers_ptr);
444 for (uint32_t idx = 0; idx < handlers_size; idx++) {
Ian Rogers0571d352011-11-03 19:51:38 -0700445 art::CatchHandlerIterator iterator(handlers_ptr);
446 for (; iterator.HasNext(); iterator.Next()) {
447 uint32_t address = iterator.GetHandlerAddress();
buzbeee9a72f62011-09-04 17:59:07 -0700448 findBlock(cUnit, address, false /* split */, true /*create*/);
buzbee67bf8852011-08-17 17:51:35 -0700449 }
Ian Rogers0571d352011-11-03 19:51:38 -0700450 handlers_ptr = iterator.EndDataPointer();
buzbee67bf8852011-08-17 17:51:35 -0700451 }
452}
453
454/* Process instructions with the kInstrCanBranch flag */
buzbeee941e2c2011-12-05 12:38:17 -0800455STATIC BasicBlock* processCanBranch(CompilationUnit* cUnit,
456 BasicBlock* curBlock, MIR* insn,
457 int curOffset, int width, int flags,
458 const u2* codePtr, const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700459{
460 int target = curOffset;
461 switch (insn->dalvikInsn.opcode) {
462 case OP_GOTO:
463 case OP_GOTO_16:
464 case OP_GOTO_32:
465 target += (int) insn->dalvikInsn.vA;
466 break;
467 case OP_IF_EQ:
468 case OP_IF_NE:
469 case OP_IF_LT:
470 case OP_IF_GE:
471 case OP_IF_GT:
472 case OP_IF_LE:
473 target += (int) insn->dalvikInsn.vC;
474 break;
475 case OP_IF_EQZ:
476 case OP_IF_NEZ:
477 case OP_IF_LTZ:
478 case OP_IF_GEZ:
479 case OP_IF_GTZ:
480 case OP_IF_LEZ:
481 target += (int) insn->dalvikInsn.vB;
482 break;
483 default:
484 LOG(FATAL) << "Unexpected opcode(" << (int)insn->dalvikInsn.opcode
485 << ") with kInstrCanBranch set";
486 }
buzbeee941e2c2011-12-05 12:38:17 -0800487 /*
488 * Some ugliness here. It is possible that findBlock will
489 * split the current block. In that case, we need to operate
490 * on the 2nd half on the split pair. It isn't directly obvious
491 * when this happens, so we infer.
492 */
493 DCHECK(curBlock->lastMIRInsn == insn);
buzbee67bf8852011-08-17 17:51:35 -0700494 BasicBlock *takenBlock = findBlock(cUnit, target,
495 /* split */
496 true,
497 /* create */
498 true);
buzbeee941e2c2011-12-05 12:38:17 -0800499 if (curBlock->lastMIRInsn != insn) {
500 DCHECK(takenBlock->lastMIRInsn == insn);
501 curBlock = curBlock->fallThrough;
502 }
buzbee67bf8852011-08-17 17:51:35 -0700503 curBlock->taken = takenBlock;
504 oatSetBit(takenBlock->predecessors, curBlock->id);
505
506 /* Always terminate the current block for conditional branches */
507 if (flags & kInstrCanContinue) {
508 BasicBlock *fallthroughBlock = findBlock(cUnit,
509 curOffset + width,
510 /*
511 * If the method is processed
512 * in sequential order from the
513 * beginning, we don't need to
514 * specify split for continue
515 * blocks. However, this
516 * routine can be called by
517 * compileLoop, which starts
518 * parsing the method from an
519 * arbitrary address in the
520 * method body.
521 */
522 true,
523 /* create */
524 true);
525 curBlock->fallThrough = fallthroughBlock;
526 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
527 } else if (codePtr < codeEnd) {
528 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
529 if (contentIsInsn(codePtr)) {
530 findBlock(cUnit, curOffset + width,
531 /* split */
532 false,
533 /* create */
534 true);
535 }
536 }
buzbeee941e2c2011-12-05 12:38:17 -0800537 return curBlock;
buzbee67bf8852011-08-17 17:51:35 -0700538}
539
540/* Process instructions with the kInstrCanSwitch flag */
buzbeeed3e9302011-09-23 17:34:19 -0700541STATIC void processCanSwitch(CompilationUnit* cUnit, BasicBlock* curBlock,
buzbee67bf8852011-08-17 17:51:35 -0700542 MIR* insn, int curOffset, int width, int flags)
543{
544 u2* switchData= (u2 *) (cUnit->insns + curOffset +
545 insn->dalvikInsn.vB);
546 int size;
547 int* keyTable;
548 int* targetTable;
549 int i;
550 int firstKey;
551
552 /*
553 * Packed switch data format:
554 * ushort ident = 0x0100 magic value
555 * ushort size number of entries in the table
556 * int first_key first (and lowest) switch case value
557 * int targets[size] branch targets, relative to switch opcode
558 *
559 * Total size is (4+size*2) 16-bit code units.
560 */
561 if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
buzbeeed3e9302011-09-23 17:34:19 -0700562 DCHECK_EQ(switchData[0], kPackedSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700563 size = switchData[1];
564 firstKey = switchData[2] | (switchData[3] << 16);
565 targetTable = (int *) &switchData[4];
566 keyTable = NULL; // Make the compiler happy
567 /*
568 * Sparse switch data format:
569 * ushort ident = 0x0200 magic value
570 * ushort size number of entries in the table; > 0
571 * int keys[size] keys, sorted low-to-high; 32-bit aligned
572 * int targets[size] branch targets, relative to switch opcode
573 *
574 * Total size is (2+size*4) 16-bit code units.
575 */
576 } else {
buzbeeed3e9302011-09-23 17:34:19 -0700577 DCHECK_EQ(switchData[0], kSparseSwitchSignature);
buzbee67bf8852011-08-17 17:51:35 -0700578 size = switchData[1];
579 keyTable = (int *) &switchData[2];
580 targetTable = (int *) &switchData[2 + size*2];
581 firstKey = 0; // To make the compiler happy
582 }
583
584 if (curBlock->successorBlockList.blockListType != kNotUsed) {
585 LOG(FATAL) << "Successor block list already in use: " <<
586 (int)curBlock->successorBlockList.blockListType;
587 }
588 curBlock->successorBlockList.blockListType =
589 (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
590 kPackedSwitch : kSparseSwitch;
591 oatInitGrowableList(&curBlock->successorBlockList.blocks, size);
592
593 for (i = 0; i < size; i++) {
594 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
595 /* split */
596 true,
597 /* create */
598 true);
599 SuccessorBlockInfo *successorBlockInfo =
600 (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
601 false);
602 successorBlockInfo->block = caseBlock;
603 successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)?
604 firstKey + i : keyTable[i];
605 oatInsertGrowableList(&curBlock->successorBlockList.blocks,
606 (intptr_t) successorBlockInfo);
607 oatSetBit(caseBlock->predecessors, curBlock->id);
608 }
609
610 /* Fall-through case */
611 BasicBlock* fallthroughBlock = findBlock(cUnit,
612 curOffset + width,
613 /* split */
614 false,
615 /* create */
616 true);
617 curBlock->fallThrough = fallthroughBlock;
618 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
619}
620
621/* Process instructions with the kInstrCanThrow flag */
buzbeeed3e9302011-09-23 17:34:19 -0700622STATIC void processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock,
buzbee67bf8852011-08-17 17:51:35 -0700623 MIR* insn, int curOffset, int width, int flags,
624 ArenaBitVector* tryBlockAddr, const u2* codePtr,
625 const u2* codeEnd)
626{
Ian Rogersa3760aa2011-11-14 14:32:37 -0800627 const art::DexFile::CodeItem* code_item = cUnit->code_item;
buzbee67bf8852011-08-17 17:51:35 -0700628
629 /* In try block */
630 if (oatIsBitSet(tryBlockAddr, curOffset)) {
Ian Rogers0571d352011-11-03 19:51:38 -0700631 art::CatchHandlerIterator iterator(*code_item, curOffset);
buzbee67bf8852011-08-17 17:51:35 -0700632
buzbee67bf8852011-08-17 17:51:35 -0700633 if (curBlock->successorBlockList.blockListType != kNotUsed) {
634 LOG(FATAL) << "Successor block list already in use: " <<
635 (int)curBlock->successorBlockList.blockListType;
636 }
buzbeee9a72f62011-09-04 17:59:07 -0700637
buzbee67bf8852011-08-17 17:51:35 -0700638 curBlock->successorBlockList.blockListType = kCatch;
639 oatInitGrowableList(&curBlock->successorBlockList.blocks, 2);
640
Ian Rogers0571d352011-11-03 19:51:38 -0700641 for (;iterator.HasNext(); iterator.Next()) {
642 BasicBlock *catchBlock = findBlock(cUnit, iterator.GetHandlerAddress(),
buzbeee9a72f62011-09-04 17:59:07 -0700643 false /* split*/,
644 false /* creat */);
buzbee43a36422011-09-14 14:00:13 -0700645 catchBlock->catchEntry = true;
buzbee67bf8852011-08-17 17:51:35 -0700646 SuccessorBlockInfo *successorBlockInfo =
buzbeee9a72f62011-09-04 17:59:07 -0700647 (SuccessorBlockInfo *) oatNew(sizeof(SuccessorBlockInfo),
648 false);
buzbee67bf8852011-08-17 17:51:35 -0700649 successorBlockInfo->block = catchBlock;
Ian Rogers0571d352011-11-03 19:51:38 -0700650 successorBlockInfo->key = iterator.GetHandlerTypeIndex();
buzbee67bf8852011-08-17 17:51:35 -0700651 oatInsertGrowableList(&curBlock->successorBlockList.blocks,
652 (intptr_t) successorBlockInfo);
653 oatSetBit(catchBlock->predecessors, curBlock->id);
654 }
655 } else {
656 BasicBlock *ehBlock = oatNewBB(kExceptionHandling,
657 cUnit->numBlocks++);
658 curBlock->taken = ehBlock;
659 oatInsertGrowableList(&cUnit->blockList, (intptr_t) ehBlock);
660 ehBlock->startOffset = curOffset;
661 oatSetBit(ehBlock->predecessors, curBlock->id);
662 }
663
664 /*
665 * Force the current block to terminate.
666 *
667 * Data may be present before codeEnd, so we need to parse it to know
668 * whether it is code or data.
669 */
670 if (codePtr < codeEnd) {
671 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
672 if (contentIsInsn(codePtr)) {
673 BasicBlock *fallthroughBlock = findBlock(cUnit,
674 curOffset + width,
675 /* split */
676 false,
677 /* create */
678 true);
679 /*
buzbee510c6052011-10-27 10:47:20 -0700680 * OP_THROW is an unconditional branch. NOTE:
681 * OP_THROW_VERIFICATION_ERROR is also an unconditional
682 * branch, but we shouldn't treat it as such until we have
683 * a dead code elimination pass (which won't be important
684 * until inlining w/ constant propogation is implemented.
buzbee67bf8852011-08-17 17:51:35 -0700685 */
buzbee510c6052011-10-27 10:47:20 -0700686 if (insn->dalvikInsn.opcode != OP_THROW) {
buzbee67bf8852011-08-17 17:51:35 -0700687 curBlock->fallThrough = fallthroughBlock;
688 oatSetBit(fallthroughBlock->predecessors, curBlock->id);
689 }
690 }
691 }
692}
693
694/*
695 * Compile a method.
696 */
Ian Rogersa3760aa2011-11-14 14:32:37 -0800697CompiledMethod* oatCompileMethod(const Compiler& compiler, const art::DexFile::CodeItem* code_item,
698 uint32_t access_flags, uint32_t method_idx,
699 const art::ClassLoader* class_loader,
700 const art::DexFile& dex_file, art::InstructionSet insnSet)
buzbee67bf8852011-08-17 17:51:35 -0700701{
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800702 VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
buzbee2a475e72011-09-07 17:19:17 -0700703 oatArenaReset();
Brian Carlstrom94496d32011-08-22 09:22:47 -0700704
buzbeec143c552011-08-20 17:38:58 -0700705 const u2* codePtr = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700706 const u2* codeEnd = code_item->insns_ + code_item->insns_size_in_code_units_;
buzbee67bf8852011-08-17 17:51:35 -0700707 int numBlocks = 0;
708 unsigned int curOffset = 0;
709
Brian Carlstrom16192862011-09-12 17:50:06 -0700710 oatInit(compiler);
buzbee67bf8852011-08-17 17:51:35 -0700711
Ian Rogersa3760aa2011-11-14 14:32:37 -0800712 art::ClassLinker* class_linker = art::Runtime::Current()->GetClassLinker();
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700713 UniquePtr<CompilationUnit> cUnit(new CompilationUnit);
714 memset(cUnit.get(), 0, sizeof(*cUnit));
715 cUnit->compiler = &compiler;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800716 cUnit->class_linker = class_linker;
717 cUnit->dex_file = &dex_file;
718 cUnit->dex_cache = class_linker->FindDexCache(dex_file);
719 cUnit->method_idx = method_idx;
720 cUnit->code_item = code_item;
721 cUnit->access_flags = access_flags;
722 cUnit->shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700723 cUnit->instructionSet = (OatInstructionSetType)insnSet;
724 cUnit->insns = code_item->insns_;
Ian Rogersd81871c2011-10-03 13:57:23 -0700725 cUnit->insnsSize = code_item->insns_size_in_code_units_;
Ian Rogersa3760aa2011-11-14 14:32:37 -0800726 cUnit->numIns = code_item->ins_size_;
727 cUnit->numRegs = code_item->registers_size_ - cUnit->numIns;
728 cUnit->numOuts = code_item->outs_size_;
729 /* Adjust this value accordingly once inlining is performed */
730 cUnit->numDalvikRegisters = code_item->registers_size_;
buzbeece302932011-10-04 14:32:18 -0700731 bool useMatch = compilerMethodMatch.length() != 0;
732 bool match = useMatch && (compilerFlipMatch ^
Ian Rogersa3760aa2011-11-14 14:32:37 -0800733 (PrettyMethod(method_idx, dex_file).find(compilerMethodMatch) != std::string::npos));
buzbeece302932011-10-04 14:32:18 -0700734 if (!useMatch || match) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700735 cUnit->disableOpt = compilerOptimizerDisableFlags;
736 cUnit->enableDebug = compilerDebugFlags;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800737 cUnit->printMe = VLOG_IS_ON(compiler) || (cUnit->enableDebug & (1 << kDebugVerbose));
buzbeece302932011-10-04 14:32:18 -0700738 }
buzbee67bf8852011-08-17 17:51:35 -0700739
buzbeecefd1872011-09-09 09:59:52 -0700740 /* Assume non-throwing leaf */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700741 cUnit->attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
buzbeecefd1872011-09-09 09:59:52 -0700742
buzbee67bf8852011-08-17 17:51:35 -0700743 /* Initialize the block list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700744 oatInitGrowableList(&cUnit->blockList, 40);
buzbee67bf8852011-08-17 17:51:35 -0700745
746 /* Initialize the switchTables list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700747 oatInitGrowableList(&cUnit->switchTables, 4);
buzbee67bf8852011-08-17 17:51:35 -0700748
749 /* Intialize the fillArrayData list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700750 oatInitGrowableList(&cUnit->fillArrayData, 4);
buzbee67bf8852011-08-17 17:51:35 -0700751
buzbee5ade1d22011-09-09 14:44:52 -0700752 /* Intialize the throwLaunchpads list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700753 oatInitGrowableList(&cUnit->throwLaunchpads, 4);
buzbee5ade1d22011-09-09 14:44:52 -0700754
buzbeec1f45042011-09-21 16:03:19 -0700755 /* Intialize the suspendLaunchpads list */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700756 oatInitGrowableList(&cUnit->suspendLaunchpads, 4);
buzbeec1f45042011-09-21 16:03:19 -0700757
buzbee67bf8852011-08-17 17:51:35 -0700758 /* Allocate the bit-vector to track the beginning of basic blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700759 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit->insnsSize,
buzbee67bf8852011-08-17 17:51:35 -0700760 true /* expandable */);
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700761 cUnit->tryBlockAddr = tryBlockAddr;
buzbee67bf8852011-08-17 17:51:35 -0700762
763 /* Create the default entry and exit blocks and enter them to the list */
764 BasicBlock *entryBlock = oatNewBB(kEntryBlock, numBlocks++);
765 BasicBlock *exitBlock = oatNewBB(kExitBlock, numBlocks++);
766
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700767 cUnit->entryBlock = entryBlock;
768 cUnit->exitBlock = exitBlock;
buzbee67bf8852011-08-17 17:51:35 -0700769
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700770 oatInsertGrowableList(&cUnit->blockList, (intptr_t) entryBlock);
771 oatInsertGrowableList(&cUnit->blockList, (intptr_t) exitBlock);
buzbee67bf8852011-08-17 17:51:35 -0700772
773 /* Current block to record parsed instructions */
774 BasicBlock *curBlock = oatNewBB(kDalvikByteCode, numBlocks++);
775 curBlock->startOffset = 0;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700776 oatInsertGrowableList(&cUnit->blockList, (intptr_t) curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700777 entryBlock->fallThrough = curBlock;
778 oatSetBit(curBlock->predecessors, entryBlock->id);
779
780 /*
781 * Store back the number of blocks since new blocks may be created of
782 * accessing cUnit.
783 */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700784 cUnit->numBlocks = numBlocks;
buzbee67bf8852011-08-17 17:51:35 -0700785
786 /* Identify code range in try blocks and set up the empty catch blocks */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700787 processTryCatchBlocks(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700788
789 /* Parse all instructions and put them into containing basic blocks */
790 while (codePtr < codeEnd) {
791 MIR *insn = (MIR *) oatNew(sizeof(MIR), true);
792 insn->offset = curOffset;
793 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
794 insn->width = width;
795
796 /* Terminate when the data section is seen */
797 if (width == 0)
798 break;
799
800 oatAppendMIR(curBlock, insn);
801
802 codePtr += width;
803 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
804
805 if (flags & kInstrCanBranch) {
buzbeee941e2c2011-12-05 12:38:17 -0800806 curBlock = processCanBranch(cUnit.get(), curBlock, insn, curOffset,
807 width, flags, codePtr, codeEnd);
buzbee67bf8852011-08-17 17:51:35 -0700808 } else if (flags & kInstrCanReturn) {
809 curBlock->fallThrough = exitBlock;
810 oatSetBit(exitBlock->predecessors, curBlock->id);
811 /*
812 * Terminate the current block if there are instructions
813 * afterwards.
814 */
815 if (codePtr < codeEnd) {
816 /*
817 * Create a fallthrough block for real instructions
818 * (incl. OP_NOP).
819 */
820 if (contentIsInsn(codePtr)) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700821 findBlock(cUnit.get(), curOffset + width,
buzbee67bf8852011-08-17 17:51:35 -0700822 /* split */
823 false,
824 /* create */
825 true);
826 }
827 }
828 } else if (flags & kInstrCanThrow) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700829 processCanThrow(cUnit.get(), curBlock, insn, curOffset, width, flags,
buzbee67bf8852011-08-17 17:51:35 -0700830 tryBlockAddr, codePtr, codeEnd);
831 } else if (flags & kInstrCanSwitch) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700832 processCanSwitch(cUnit.get(), curBlock, insn, curOffset, width, flags);
buzbee67bf8852011-08-17 17:51:35 -0700833 }
834 curOffset += width;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700835 BasicBlock *nextBlock = findBlock(cUnit.get(), curOffset,
buzbee67bf8852011-08-17 17:51:35 -0700836 /* split */
837 false,
838 /* create */
839 false);
840 if (nextBlock) {
841 /*
842 * The next instruction could be the target of a previously parsed
843 * forward branch so a block is already created. If the current
844 * instruction is not an unconditional branch, connect them through
845 * the fall-through link.
846 */
buzbeeed3e9302011-09-23 17:34:19 -0700847 DCHECK(curBlock->fallThrough == NULL ||
buzbee67bf8852011-08-17 17:51:35 -0700848 curBlock->fallThrough == nextBlock ||
849 curBlock->fallThrough == exitBlock);
850
851 if ((curBlock->fallThrough == NULL) &&
852 (flags & kInstrCanContinue)) {
853 curBlock->fallThrough = nextBlock;
854 oatSetBit(nextBlock->predecessors, curBlock->id);
855 }
856 curBlock = nextBlock;
857 }
858 }
859
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700860 if (cUnit->printMe) {
861 oatDumpCompilationUnit(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700862 }
863
buzbee67bf8852011-08-17 17:51:35 -0700864 /* Verify if all blocks are connected as claimed */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700865 oatDataFlowAnalysisDispatcher(cUnit.get(), verifyPredInfo, kAllNodes, false /* isIterative */);
buzbee67bf8852011-08-17 17:51:35 -0700866
867 /* Perform SSA transformation for the whole method */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700868 oatMethodSSATransformation(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700869
buzbee43a36422011-09-14 14:00:13 -0700870 /* Perform null check elimination */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700871 oatMethodNullCheckElimination(cUnit.get());
buzbee43a36422011-09-14 14:00:13 -0700872
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700873 oatInitializeRegAlloc(cUnit.get()); // Needs to happen after SSA naming
buzbee67bf8852011-08-17 17:51:35 -0700874
875 /* Allocate Registers using simple local allocation scheme */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700876 oatSimpleRegAlloc(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700877
878 /* Convert MIR to LIR, etc. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700879 oatMethodMIR2LIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700880
881 // Debugging only
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700882 if (cUnit->enableDebug & (1 << kDebugDumpCFG)) {
883 oatDumpCFG(cUnit.get(), "/sdcard/cfg/");
buzbeeec5adf32011-09-11 15:25:43 -0700884 }
buzbee67bf8852011-08-17 17:51:35 -0700885
886 /* Method is not empty */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700887 if (cUnit->firstLIRInsn) {
buzbee67bf8852011-08-17 17:51:35 -0700888
889 // mark the targets of switch statement case labels
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700890 oatProcessSwitchTables(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700891
892 /* Convert LIR into machine code. */
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700893 oatAssembleLIR(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700894
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700895 if (cUnit->printMe) {
896 oatCodegenDump(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -0700897 }
898 }
899
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700900 // Combine vmap tables - core regs, then fp regs - into vmapTable
901 std::vector<uint16_t> vmapTable;
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700902 for (size_t i = 0 ; i < cUnit->coreVmapTable.size(); i++) {
903 vmapTable.push_back(cUnit->coreVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700904 }
buzbeec41e5b52011-09-23 12:46:19 -0700905 // Add a marker to take place of lr
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -0700906 vmapTable.push_back(INVALID_VREG);
buzbeec41e5b52011-09-23 12:46:19 -0700907 // Combine vmap tables - core regs, then fp regs
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700908 for (uint32_t i = 0; i < cUnit->fpVmapTable.size(); i++) {
Elliott Hughes3b6baaa2011-10-14 19:13:56 -0700909 vmapTable.push_back(cUnit->fpVmapTable[i]);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700910 }
Brian Carlstrom0dd7dda2011-10-25 15:47:53 -0700911 DCHECK_EQ(vmapTable.size(),
912 static_cast<uint32_t>(__builtin_popcount(cUnit->coreSpillMask)
913 + __builtin_popcount(cUnit->fpSpillMask)));
914 DCHECK_GE(vmapTable.size(), 1U); // should always at least one INVALID_VREG for lr
915
Ian Rogers0571d352011-11-03 19:51:38 -0700916 CompiledMethod* result = new CompiledMethod(art::kThumb2, cUnit->codeBuffer,
917 cUnit->frameSize, cUnit->coreSpillMask,
918 cUnit->fpSpillMask, cUnit->mappingTable,
919 vmapTable);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700920
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800921 VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file)
922 << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0])) << " bytes)";
buzbee67bf8852011-08-17 17:51:35 -0700923
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700924 return result;
buzbee67bf8852011-08-17 17:51:35 -0700925}
926
Brian Carlstrom16192862011-09-12 17:50:06 -0700927void oatInit(const Compiler& compiler)
buzbee67bf8852011-08-17 17:51:35 -0700928{
buzbee67bf8852011-08-17 17:51:35 -0700929 static bool initialized = false;
930 if (initialized)
931 return;
932 initialized = true;
Elliott Hughes4dd9b4d2011-12-12 18:29:24 -0800933 VLOG(compiler) << "Initializing compiler";
buzbee67bf8852011-08-17 17:51:35 -0700934 if (!oatArchInit()) {
935 LOG(FATAL) << "Failed to initialize oat";
936 }
937 if (!oatHeapInit()) {
938 LOG(FATAL) << "Failed to initialize oat heap";
939 }
940}