blob: c5d5c21d43cd5673983aefb8ba0ae10429523db7 [file] [log] [blame]
buzbee67bf8852011-08-17 17:51:35 -07001/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Dalvik.h"
18#include "CompilerInternals.h"
19#include "Dataflow.h"
Ian Rogers0571d352011-11-03 19:51:38 -070020#include "leb128.h"
Brian Carlstrom9baa4ae2011-09-01 21:14:14 -070021#include "object.h"
Brian Carlstrom1f870082011-08-23 16:02:11 -070022#include "runtime.h"
buzbee67bf8852011-08-17 17:51:35 -070023
buzbee4df2bbd2012-10-11 14:46:06 -070024#include <llvm/Support/Threading.h>
25
26namespace {
Shih-wei Liao215a9262012-10-12 10:29:46 -070027#if !defined(ART_USE_LLVM_COMPILER)
buzbee4df2bbd2012-10-11 14:46:06 -070028 pthread_once_t llvm_multi_init = PTHREAD_ONCE_INIT;
Shih-wei Liao215a9262012-10-12 10:29:46 -070029#endif
buzbee4df2bbd2012-10-11 14:46:06 -070030 void InitializeLLVMForQuick() {
31 llvm::llvm_start_multithreaded();
32 }
33}
buzbee4df2bbd2012-10-11 14:46:06 -070034
Elliott Hughes11d1b0c2012-01-23 16:57:47 -080035namespace art {
36
buzbee4df2bbd2012-10-11 14:46:06 -070037LLVMInfo::LLVMInfo() {
38#if !defined(ART_USE_LLVM_COMPILER)
39 pthread_once(&llvm_multi_init, InitializeLLVMForQuick);
40#endif
buzbee692be802012-08-29 15:52:59 -070041 // Create context, module, intrinsic helper & ir builder
42 llvm_context_.reset(new llvm::LLVMContext());
TDYa12755e5e6c2012-09-11 15:14:42 -070043 llvm_module_ = new llvm::Module("art", *llvm_context_);
buzbee692be802012-08-29 15:52:59 -070044 llvm::StructType::create(*llvm_context_, "JavaObject");
buzbee692be802012-08-29 15:52:59 -070045 intrinsic_helper_.reset( new greenland::IntrinsicHelper(*llvm_context_, *llvm_module_));
46 ir_builder_.reset(new greenland::IRBuilder(*llvm_context_, *llvm_module_, *intrinsic_helper_));
47}
48
buzbee4df2bbd2012-10-11 14:46:06 -070049LLVMInfo::~LLVMInfo() {
buzbee692be802012-08-29 15:52:59 -070050}
51
52extern "C" void ArtInitQuickCompilerContext(art::Compiler& compiler) {
53 CHECK(compiler.GetCompilerContext() == NULL);
buzbee4df2bbd2012-10-11 14:46:06 -070054 LLVMInfo* llvmInfo = new LLVMInfo();
55 compiler.SetCompilerContext(llvmInfo);
buzbee692be802012-08-29 15:52:59 -070056}
57
58extern "C" void ArtUnInitQuickCompilerContext(art::Compiler& compiler) {
buzbee4df2bbd2012-10-11 14:46:06 -070059 delete reinterpret_cast<LLVMInfo*>(compiler.GetCompilerContext());
buzbee692be802012-08-29 15:52:59 -070060 compiler.SetCompilerContext(NULL);
61}
buzbee692be802012-08-29 15:52:59 -070062
buzbeece302932011-10-04 14:32:18 -070063/* Default optimizer/debug setting for the compiler. */
Elliott Hughese52e49b2012-04-02 16:05:44 -070064static uint32_t kCompilerOptimizerDisableFlags = 0 | // Disable specific optimizations
Bill Buzbeea114add2012-05-03 15:00:40 -070065 //(1 << kLoadStoreElimination) |
66 //(1 << kLoadHoisting) |
67 //(1 << kSuppressLoads) |
68 //(1 << kNullCheckElimination) |
69 //(1 << kPromoteRegs) |
70 //(1 << kTrackLiveTemps) |
71 //(1 << kSkipLargeMethodOptimization) |
72 //(1 << kSafeOptimizations) |
73 //(1 << kBBOpt) |
74 //(1 << kMatch) |
75 //(1 << kPromoteCompilerTemps) |
76 0;
buzbeece302932011-10-04 14:32:18 -070077
Elliott Hughese52e49b2012-04-02 16:05:44 -070078static uint32_t kCompilerDebugFlags = 0 | // Enable debug/testing modes
Bill Buzbeea114add2012-05-03 15:00:40 -070079 //(1 << kDebugDisplayMissingTargets) |
80 //(1 << kDebugVerbose) |
81 //(1 << kDebugDumpCFG) |
82 //(1 << kDebugSlowFieldPath) |
83 //(1 << kDebugSlowInvokePath) |
84 //(1 << kDebugSlowStringPath) |
85 //(1 << kDebugSlowestFieldPath) |
86 //(1 << kDebugSlowestStringPath) |
87 //(1 << kDebugExerciseResolveMethod) |
88 //(1 << kDebugVerifyDataflow) |
89 //(1 << kDebugShowMemoryUsage) |
90 //(1 << kDebugShowNops) |
91 //(1 << kDebugCountOpcodes) |
buzbeed1643e42012-09-05 14:06:51 -070092 //(1 << kDebugDumpCheckStats) |
buzbeead8f15e2012-06-18 14:49:45 -070093 //(1 << kDebugDumpBitcodeFile) |
Bill Buzbeec9f40dd2012-08-15 11:35:25 -070094 //(1 << kDebugVerifyBitcode) |
Bill Buzbeea114add2012-05-03 15:00:40 -070095 0;
buzbeece302932011-10-04 14:32:18 -070096
buzbee31a4a6f2012-02-28 15:36:15 -080097inline bool contentIsInsn(const u2* codePtr) {
Bill Buzbeea114add2012-05-03 15:00:40 -070098 u2 instr = *codePtr;
99 Instruction::Code opcode = (Instruction::Code)(instr & 0xff);
buzbee67bf8852011-08-17 17:51:35 -0700100
Bill Buzbeea114add2012-05-03 15:00:40 -0700101 /*
102 * Since the low 8-bit in metadata may look like NOP, we need to check
103 * both the low and whole sub-word to determine whether it is code or data.
104 */
105 return (opcode != Instruction::NOP || instr == 0);
buzbee67bf8852011-08-17 17:51:35 -0700106}
107
108/*
109 * Parse an instruction, return the length of the instruction
110 */
buzbee31a4a6f2012-02-28 15:36:15 -0800111inline int parseInsn(CompilationUnit* cUnit, const u2* codePtr,
Bill Buzbeea114add2012-05-03 15:00:40 -0700112 DecodedInstruction* decoded_instruction, bool printMe)
buzbee67bf8852011-08-17 17:51:35 -0700113{
Elliott Hughesadb8c672012-03-06 16:49:32 -0800114 // Don't parse instruction data
115 if (!contentIsInsn(codePtr)) {
116 return 0;
117 }
buzbee67bf8852011-08-17 17:51:35 -0700118
Elliott Hughesadb8c672012-03-06 16:49:32 -0800119 const Instruction* instruction = Instruction::At(codePtr);
120 *decoded_instruction = DecodedInstruction(instruction);
buzbee67bf8852011-08-17 17:51:35 -0700121
Elliott Hughesadb8c672012-03-06 16:49:32 -0800122 if (printMe) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700123 char* decodedString = oatGetDalvikDisassembly(cUnit, *decoded_instruction,
124 NULL);
125 LOG(INFO) << codePtr << ": 0x"
126 << std::hex << static_cast<int>(decoded_instruction->opcode)
Elliott Hughesadb8c672012-03-06 16:49:32 -0800127 << " " << decodedString;
128 }
129 return instruction->SizeInCodeUnits();
buzbee67bf8852011-08-17 17:51:35 -0700130}
131
132#define UNKNOWN_TARGET 0xffffffff
133
Elliott Hughesadb8c672012-03-06 16:49:32 -0800134inline bool isGoto(MIR* insn) {
135 switch (insn->dalvikInsn.opcode) {
136 case Instruction::GOTO:
137 case Instruction::GOTO_16:
138 case Instruction::GOTO_32:
139 return true;
140 default:
141 return false;
Bill Buzbeea114add2012-05-03 15:00:40 -0700142 }
buzbee67bf8852011-08-17 17:51:35 -0700143}
144
145/*
146 * Identify unconditional branch instructions
147 */
Elliott Hughesadb8c672012-03-06 16:49:32 -0800148inline bool isUnconditionalBranch(MIR* insn) {
149 switch (insn->dalvikInsn.opcode) {
150 case Instruction::RETURN_VOID:
151 case Instruction::RETURN:
152 case Instruction::RETURN_WIDE:
153 case Instruction::RETURN_OBJECT:
154 return true;
Bill Buzbeea114add2012-05-03 15:00:40 -0700155 default:
156 return isGoto(insn);
Elliott Hughesadb8c672012-03-06 16:49:32 -0800157 }
buzbee67bf8852011-08-17 17:51:35 -0700158}
159
160/* Split an existing block from the specified code offset into two */
buzbee31a4a6f2012-02-28 15:36:15 -0800161BasicBlock *splitBlock(CompilationUnit* cUnit, unsigned int codeOffset,
Bill Buzbeea114add2012-05-03 15:00:40 -0700162 BasicBlock* origBlock, BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700163{
Bill Buzbeea114add2012-05-03 15:00:40 -0700164 MIR* insn = origBlock->firstMIRInsn;
165 while (insn) {
166 if (insn->offset == codeOffset) break;
167 insn = insn->next;
168 }
169 if (insn == NULL) {
170 LOG(FATAL) << "Break split failed";
171 }
172 BasicBlock *bottomBlock = oatNewBB(cUnit, kDalvikByteCode,
173 cUnit->numBlocks++);
174 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700175
Bill Buzbeea114add2012-05-03 15:00:40 -0700176 bottomBlock->startOffset = codeOffset;
177 bottomBlock->firstMIRInsn = insn;
178 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
buzbee67bf8852011-08-17 17:51:35 -0700179
Bill Buzbeea114add2012-05-03 15:00:40 -0700180 /* Add it to the quick lookup cache */
181 cUnit->blockMap.Put(bottomBlock->startOffset, bottomBlock);
buzbee5b537102012-01-17 17:33:47 -0800182
Bill Buzbeea114add2012-05-03 15:00:40 -0700183 /* Handle the taken path */
184 bottomBlock->taken = origBlock->taken;
185 if (bottomBlock->taken) {
186 origBlock->taken = NULL;
187 oatDeleteGrowableList(bottomBlock->taken->predecessors,
buzbeeba938cb2012-02-03 14:47:55 -0800188 (intptr_t)origBlock);
Bill Buzbeea114add2012-05-03 15:00:40 -0700189 oatInsertGrowableList(cUnit, bottomBlock->taken->predecessors,
190 (intptr_t)bottomBlock);
191 }
192
193 /* Handle the fallthrough path */
Bill Buzbeea114add2012-05-03 15:00:40 -0700194 bottomBlock->fallThrough = origBlock->fallThrough;
195 origBlock->fallThrough = bottomBlock;
Bill Buzbeea114add2012-05-03 15:00:40 -0700196 oatInsertGrowableList(cUnit, bottomBlock->predecessors,
197 (intptr_t)origBlock);
198 if (bottomBlock->fallThrough) {
199 oatDeleteGrowableList(bottomBlock->fallThrough->predecessors,
200 (intptr_t)origBlock);
201 oatInsertGrowableList(cUnit, bottomBlock->fallThrough->predecessors,
202 (intptr_t)bottomBlock);
203 }
204
205 /* Handle the successor list */
206 if (origBlock->successorBlockList.blockListType != kNotUsed) {
207 bottomBlock->successorBlockList = origBlock->successorBlockList;
208 origBlock->successorBlockList.blockListType = kNotUsed;
209 GrowableListIterator iterator;
210
211 oatGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
212 &iterator);
213 while (true) {
214 SuccessorBlockInfo *successorBlockInfo =
215 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
216 if (successorBlockInfo == NULL) break;
217 BasicBlock *bb = successorBlockInfo->block;
218 oatDeleteGrowableList(bb->predecessors, (intptr_t)origBlock);
219 oatInsertGrowableList(cUnit, bb->predecessors, (intptr_t)bottomBlock);
buzbee67bf8852011-08-17 17:51:35 -0700220 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700221 }
buzbee67bf8852011-08-17 17:51:35 -0700222
Bill Buzbeea114add2012-05-03 15:00:40 -0700223 origBlock->lastMIRInsn = insn->prev;
buzbee67bf8852011-08-17 17:51:35 -0700224
Bill Buzbeea114add2012-05-03 15:00:40 -0700225 insn->prev->next = NULL;
226 insn->prev = NULL;
227 /*
228 * Update the immediate predecessor block pointer so that outgoing edges
229 * can be applied to the proper block.
230 */
231 if (immedPredBlockP) {
232 DCHECK_EQ(*immedPredBlockP, origBlock);
233 *immedPredBlockP = bottomBlock;
234 }
235 return bottomBlock;
buzbee67bf8852011-08-17 17:51:35 -0700236}
237
238/*
239 * Given a code offset, find out the block that starts with it. If the offset
buzbee9ab05de2012-01-18 15:43:48 -0800240 * is in the middle of an existing block, split it into two. If immedPredBlockP
241 * is not non-null and is the block being split, update *immedPredBlockP to
242 * point to the bottom block so that outgoing edges can be set up properly
243 * (by the caller)
buzbee5b537102012-01-17 17:33:47 -0800244 * Utilizes a map for fast lookup of the typical cases.
buzbee67bf8852011-08-17 17:51:35 -0700245 */
buzbee31a4a6f2012-02-28 15:36:15 -0800246BasicBlock *findBlock(CompilationUnit* cUnit, unsigned int codeOffset,
247 bool split, bool create, BasicBlock** immedPredBlockP)
buzbee67bf8852011-08-17 17:51:35 -0700248{
Bill Buzbeea114add2012-05-03 15:00:40 -0700249 GrowableList* blockList = &cUnit->blockList;
250 BasicBlock* bb;
251 unsigned int i;
252 SafeMap<unsigned int, BasicBlock*>::iterator it;
buzbee67bf8852011-08-17 17:51:35 -0700253
Bill Buzbeea114add2012-05-03 15:00:40 -0700254 it = cUnit->blockMap.find(codeOffset);
255 if (it != cUnit->blockMap.end()) {
256 return it->second;
257 } else if (!create) {
258 return NULL;
259 }
260
261 if (split) {
262 for (i = 0; i < blockList->numUsed; i++) {
263 bb = (BasicBlock *) blockList->elemList[i];
264 if (bb->blockType != kDalvikByteCode) continue;
265 /* Check if a branch jumps into the middle of an existing block */
266 if ((codeOffset > bb->startOffset) && (bb->lastMIRInsn != NULL) &&
267 (codeOffset <= bb->lastMIRInsn->offset)) {
268 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb,
269 bb == *immedPredBlockP ?
270 immedPredBlockP : NULL);
271 return newBB;
272 }
buzbee5b537102012-01-17 17:33:47 -0800273 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700274 }
buzbee5b537102012-01-17 17:33:47 -0800275
Bill Buzbeea114add2012-05-03 15:00:40 -0700276 /* Create a new one */
277 bb = oatNewBB(cUnit, kDalvikByteCode, cUnit->numBlocks++);
278 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) bb);
279 bb->startOffset = codeOffset;
280 cUnit->blockMap.Put(bb->startOffset, bb);
281 return bb;
buzbee67bf8852011-08-17 17:51:35 -0700282}
283
buzbeef58c12c2012-07-03 15:06:29 -0700284/* Find existing block */
285BasicBlock* oatFindBlock(CompilationUnit* cUnit, unsigned int codeOffset)
286{
287 return findBlock(cUnit, codeOffset, false, false, NULL);
288}
289
buzbeead8f15e2012-06-18 14:49:45 -0700290/* Turn method name into a legal Linux file name */
291void oatReplaceSpecialChars(std::string& str)
292{
293 static const struct { const char before; const char after; } match[] =
294 {{'/','-'}, {';','#'}, {' ','#'}, {'$','+'},
295 {'(','@'}, {')','@'}, {'<','='}, {'>','='}};
296 for (unsigned int i = 0; i < sizeof(match)/sizeof(match[0]); i++) {
297 std::replace(str.begin(), str.end(), match[i].before, match[i].after);
298 }
299}
300
buzbee67bf8852011-08-17 17:51:35 -0700301/* Dump the CFG into a DOT graph */
302void oatDumpCFG(CompilationUnit* cUnit, const char* dirPrefix)
303{
Bill Buzbeea114add2012-05-03 15:00:40 -0700304 FILE* file;
buzbeead8f15e2012-06-18 14:49:45 -0700305 std::string fname(PrettyMethod(cUnit->method_idx, *cUnit->dex_file));
306 oatReplaceSpecialChars(fname);
307 fname = StringPrintf("%s%s%x.dot", dirPrefix, fname.c_str(),
308 cUnit->entryBlock->fallThrough->startOffset);
309 file = fopen(fname.c_str(), "w");
Bill Buzbeea114add2012-05-03 15:00:40 -0700310 if (file == NULL) {
311 return;
312 }
313 fprintf(file, "digraph G {\n");
314
315 fprintf(file, " rankdir=TB\n");
316
317 int numReachableBlocks = cUnit->numReachableBlocks;
318 int idx;
319 const GrowableList *blockList = &cUnit->blockList;
320
321 for (idx = 0; idx < numReachableBlocks; idx++) {
322 int blockIdx = cUnit->dfsOrder.elemList[idx];
323 BasicBlock *bb = (BasicBlock *) oatGrowableListGetElement(blockList,
324 blockIdx);
325 if (bb == NULL) break;
buzbeed1643e42012-09-05 14:06:51 -0700326 if (bb->blockType == kDead) continue;
Bill Buzbeea114add2012-05-03 15:00:40 -0700327 if (bb->blockType == kEntryBlock) {
Bill Buzbeec9f40dd2012-08-15 11:35:25 -0700328 fprintf(file, " entry_%d [shape=Mdiamond];\n", bb->id);
Bill Buzbeea114add2012-05-03 15:00:40 -0700329 } else if (bb->blockType == kExitBlock) {
Bill Buzbeec9f40dd2012-08-15 11:35:25 -0700330 fprintf(file, " exit_%d [shape=Mdiamond];\n", bb->id);
Bill Buzbeea114add2012-05-03 15:00:40 -0700331 } else if (bb->blockType == kDalvikByteCode) {
Bill Buzbeec9f40dd2012-08-15 11:35:25 -0700332 fprintf(file, " block%04x_%d [shape=record,label = \"{ \\\n",
333 bb->startOffset, bb->id);
Bill Buzbeea114add2012-05-03 15:00:40 -0700334 const MIR *mir;
335 fprintf(file, " {block id %d\\l}%s\\\n", bb->id,
336 bb->firstMIRInsn ? " | " : " ");
337 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
338 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
339 mir->ssaRep ? oatFullDisassembler(cUnit, mir) :
340 Instruction::Name(mir->dalvikInsn.opcode),
341 mir->next ? " | " : " ");
342 }
343 fprintf(file, " }\"];\n\n");
344 } else if (bb->blockType == kExceptionHandling) {
345 char blockName[BLOCK_NAME_LEN];
346
347 oatGetBlockName(bb, blockName);
348 fprintf(file, " %s [shape=invhouse];\n", blockName);
buzbee67bf8852011-08-17 17:51:35 -0700349 }
buzbee67bf8852011-08-17 17:51:35 -0700350
Bill Buzbeea114add2012-05-03 15:00:40 -0700351 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
buzbee67bf8852011-08-17 17:51:35 -0700352
Bill Buzbeea114add2012-05-03 15:00:40 -0700353 if (bb->taken) {
354 oatGetBlockName(bb, blockName1);
355 oatGetBlockName(bb->taken, blockName2);
356 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
357 blockName1, blockName2);
buzbee67bf8852011-08-17 17:51:35 -0700358 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700359 if (bb->fallThrough) {
360 oatGetBlockName(bb, blockName1);
361 oatGetBlockName(bb->fallThrough, blockName2);
362 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
363 }
364
365 if (bb->successorBlockList.blockListType != kNotUsed) {
Bill Buzbeec9f40dd2012-08-15 11:35:25 -0700366 fprintf(file, " succ%04x_%d [shape=%s,label = \"{ \\\n",
367 bb->startOffset, bb->id,
Bill Buzbeea114add2012-05-03 15:00:40 -0700368 (bb->successorBlockList.blockListType == kCatch) ?
369 "Mrecord" : "record");
370 GrowableListIterator iterator;
371 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
372 &iterator);
373 SuccessorBlockInfo *successorBlockInfo =
374 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
375
376 int succId = 0;
377 while (true) {
378 if (successorBlockInfo == NULL) break;
379
380 BasicBlock *destBlock = successorBlockInfo->block;
381 SuccessorBlockInfo *nextSuccessorBlockInfo =
382 (SuccessorBlockInfo *) oatGrowableListIteratorNext(&iterator);
383
384 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
385 succId++,
386 successorBlockInfo->key,
387 destBlock->startOffset,
388 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
389
390 successorBlockInfo = nextSuccessorBlockInfo;
391 }
392 fprintf(file, " }\"];\n\n");
393
394 oatGetBlockName(bb, blockName1);
Bill Buzbeec9f40dd2012-08-15 11:35:25 -0700395 fprintf(file, " %s:s -> succ%04x_%d:n [style=dashed]\n",
396 blockName1, bb->startOffset, bb->id);
Bill Buzbeea114add2012-05-03 15:00:40 -0700397
398 if (bb->successorBlockList.blockListType == kPackedSwitch ||
399 bb->successorBlockList.blockListType == kSparseSwitch) {
400
401 oatGrowableListIteratorInit(&bb->successorBlockList.blocks,
402 &iterator);
403
404 succId = 0;
405 while (true) {
406 SuccessorBlockInfo *successorBlockInfo = (SuccessorBlockInfo *)
407 oatGrowableListIteratorNext(&iterator);
408 if (successorBlockInfo == NULL) break;
409
410 BasicBlock *destBlock = successorBlockInfo->block;
411
412 oatGetBlockName(destBlock, blockName2);
Bill Buzbeec9f40dd2012-08-15 11:35:25 -0700413 fprintf(file, " succ%04x_%d:f%d:e -> %s:n\n", bb->startOffset,
414 bb->id, succId++, blockName2);
Bill Buzbeea114add2012-05-03 15:00:40 -0700415 }
416 }
417 }
418 fprintf(file, "\n");
419
420 /* Display the dominator tree */
421 oatGetBlockName(bb, blockName1);
422 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
423 blockName1, blockName1);
424 if (bb->iDom) {
425 oatGetBlockName(bb->iDom, blockName2);
426 fprintf(file, " cfg%s:s -> cfg%s:n\n\n", blockName2, blockName1);
427 }
428 }
429 fprintf(file, "}\n");
430 fclose(file);
buzbee67bf8852011-08-17 17:51:35 -0700431}
432
433/* Verify if all the successor is connected with all the claimed predecessors */
buzbee31a4a6f2012-02-28 15:36:15 -0800434bool verifyPredInfo(CompilationUnit* cUnit, BasicBlock* bb)
buzbee67bf8852011-08-17 17:51:35 -0700435{
Bill Buzbeea114add2012-05-03 15:00:40 -0700436 GrowableListIterator iter;
buzbee67bf8852011-08-17 17:51:35 -0700437
Bill Buzbeea114add2012-05-03 15:00:40 -0700438 oatGrowableListIteratorInit(bb->predecessors, &iter);
439 while (true) {
440 BasicBlock *predBB = (BasicBlock*)oatGrowableListIteratorNext(&iter);
441 if (!predBB) break;
442 bool found = false;
443 if (predBB->taken == bb) {
444 found = true;
445 } else if (predBB->fallThrough == bb) {
446 found = true;
447 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
448 GrowableListIterator iterator;
449 oatGrowableListIteratorInit(&predBB->successorBlockList.blocks,
450 &iterator);
451 while (true) {
452 SuccessorBlockInfo *successorBlockInfo = (SuccessorBlockInfo *)
453 oatGrowableListIteratorNext(&iterator);
454 if (successorBlockInfo == NULL) break;
455 BasicBlock *succBB = successorBlockInfo->block;
456 if (succBB == bb) {
buzbee67bf8852011-08-17 17:51:35 -0700457 found = true;
Bill Buzbeea114add2012-05-03 15:00:40 -0700458 break;
buzbee67bf8852011-08-17 17:51:35 -0700459 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700460 }
buzbee67bf8852011-08-17 17:51:35 -0700461 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700462 if (found == false) {
463 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
464 oatGetBlockName(bb, blockName1);
465 oatGetBlockName(predBB, blockName2);
466 oatDumpCFG(cUnit, "/sdcard/cfg/");
467 LOG(FATAL) << "Successor " << blockName1 << "not found from "
468 << blockName2;
469 }
470 }
471 return true;
buzbee67bf8852011-08-17 17:51:35 -0700472}
473
474/* Identify code range in try blocks and set up the empty catch blocks */
buzbee31a4a6f2012-02-28 15:36:15 -0800475void processTryCatchBlocks(CompilationUnit* cUnit)
buzbee67bf8852011-08-17 17:51:35 -0700476{
Bill Buzbeea114add2012-05-03 15:00:40 -0700477 const DexFile::CodeItem* code_item = cUnit->code_item;
478 int triesSize = code_item->tries_size_;
479 int offset;
buzbee67bf8852011-08-17 17:51:35 -0700480
Bill Buzbeea114add2012-05-03 15:00:40 -0700481 if (triesSize == 0) {
482 return;
483 }
484
485 ArenaBitVector* tryBlockAddr = cUnit->tryBlockAddr;
486
487 for (int i = 0; i < triesSize; i++) {
488 const DexFile::TryItem* pTry =
489 DexFile::GetTryItems(*code_item, i);
490 int startOffset = pTry->start_addr_;
491 int endOffset = startOffset + pTry->insn_count_;
492 for (offset = startOffset; offset < endOffset; offset++) {
493 oatSetBit(cUnit, tryBlockAddr, offset);
buzbee67bf8852011-08-17 17:51:35 -0700494 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700495 }
buzbee67bf8852011-08-17 17:51:35 -0700496
Bill Buzbeea114add2012-05-03 15:00:40 -0700497 // Iterate over each of the handlers to enqueue the empty Catch blocks
498 const byte* handlers_ptr = DexFile::GetCatchHandlerData(*code_item, 0);
499 uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_ptr);
500 for (uint32_t idx = 0; idx < handlers_size; idx++) {
501 CatchHandlerIterator iterator(handlers_ptr);
502 for (; iterator.HasNext(); iterator.Next()) {
503 uint32_t address = iterator.GetHandlerAddress();
504 findBlock(cUnit, address, false /* split */, true /*create*/,
505 /* immedPredBlockP */ NULL);
buzbee67bf8852011-08-17 17:51:35 -0700506 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700507 handlers_ptr = iterator.EndDataPointer();
508 }
buzbee67bf8852011-08-17 17:51:35 -0700509}
510
Elliott Hughesadb8c672012-03-06 16:49:32 -0800511/* Process instructions with the kBranch flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800512BasicBlock* processCanBranch(CompilationUnit* cUnit, BasicBlock* curBlock,
Bill Buzbeea114add2012-05-03 15:00:40 -0700513 MIR* insn, int curOffset, int width, int flags,
514 const u2* codePtr, const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700515{
Bill Buzbeea114add2012-05-03 15:00:40 -0700516 int target = curOffset;
517 switch (insn->dalvikInsn.opcode) {
518 case Instruction::GOTO:
519 case Instruction::GOTO_16:
520 case Instruction::GOTO_32:
521 target += (int) insn->dalvikInsn.vA;
522 break;
523 case Instruction::IF_EQ:
524 case Instruction::IF_NE:
525 case Instruction::IF_LT:
526 case Instruction::IF_GE:
527 case Instruction::IF_GT:
528 case Instruction::IF_LE:
buzbee0967a252012-09-14 10:43:54 -0700529 curBlock->conditionalBranch = true;
Bill Buzbeea114add2012-05-03 15:00:40 -0700530 target += (int) insn->dalvikInsn.vC;
531 break;
532 case Instruction::IF_EQZ:
533 case Instruction::IF_NEZ:
534 case Instruction::IF_LTZ:
535 case Instruction::IF_GEZ:
536 case Instruction::IF_GTZ:
537 case Instruction::IF_LEZ:
buzbee0967a252012-09-14 10:43:54 -0700538 curBlock->conditionalBranch = true;
Bill Buzbeea114add2012-05-03 15:00:40 -0700539 target += (int) insn->dalvikInsn.vB;
540 break;
541 default:
542 LOG(FATAL) << "Unexpected opcode(" << (int)insn->dalvikInsn.opcode
543 << ") with kBranch set";
544 }
545 BasicBlock *takenBlock = findBlock(cUnit, target,
546 /* split */
547 true,
548 /* create */
549 true,
550 /* immedPredBlockP */
551 &curBlock);
552 curBlock->taken = takenBlock;
553 oatInsertGrowableList(cUnit, takenBlock->predecessors, (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700554
Bill Buzbeea114add2012-05-03 15:00:40 -0700555 /* Always terminate the current block for conditional branches */
556 if (flags & Instruction::kContinue) {
557 BasicBlock *fallthroughBlock = findBlock(cUnit,
558 curOffset + width,
559 /*
560 * If the method is processed
561 * in sequential order from the
562 * beginning, we don't need to
563 * specify split for continue
564 * blocks. However, this
565 * routine can be called by
566 * compileLoop, which starts
567 * parsing the method from an
568 * arbitrary address in the
569 * method body.
570 */
571 true,
572 /* create */
573 true,
574 /* immedPredBlockP */
575 &curBlock);
576 curBlock->fallThrough = fallthroughBlock;
577 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
578 (intptr_t)curBlock);
579 } else if (codePtr < codeEnd) {
580 /* Create a fallthrough block for real instructions (incl. NOP) */
581 if (contentIsInsn(codePtr)) {
582 findBlock(cUnit, curOffset + width,
583 /* split */
584 false,
585 /* create */
586 true,
587 /* immedPredBlockP */
588 NULL);
buzbee67bf8852011-08-17 17:51:35 -0700589 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700590 }
591 return curBlock;
buzbee67bf8852011-08-17 17:51:35 -0700592}
593
Elliott Hughesadb8c672012-03-06 16:49:32 -0800594/* Process instructions with the kSwitch flag */
buzbee31a4a6f2012-02-28 15:36:15 -0800595void processCanSwitch(CompilationUnit* cUnit, BasicBlock* curBlock,
596 MIR* insn, int curOffset, int width, int flags)
buzbee67bf8852011-08-17 17:51:35 -0700597{
Bill Buzbeea114add2012-05-03 15:00:40 -0700598 u2* switchData= (u2 *) (cUnit->insns + curOffset + insn->dalvikInsn.vB);
599 int size;
600 int* keyTable;
601 int* targetTable;
602 int i;
603 int firstKey;
buzbee67bf8852011-08-17 17:51:35 -0700604
Bill Buzbeea114add2012-05-03 15:00:40 -0700605 /*
606 * Packed switch data format:
607 * ushort ident = 0x0100 magic value
608 * ushort size number of entries in the table
609 * int first_key first (and lowest) switch case value
610 * int targets[size] branch targets, relative to switch opcode
611 *
612 * Total size is (4+size*2) 16-bit code units.
613 */
614 if (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) {
615 DCHECK_EQ(static_cast<int>(switchData[0]),
616 static_cast<int>(Instruction::kPackedSwitchSignature));
617 size = switchData[1];
618 firstKey = switchData[2] | (switchData[3] << 16);
619 targetTable = (int *) &switchData[4];
620 keyTable = NULL; // Make the compiler happy
621 /*
622 * Sparse switch data format:
623 * ushort ident = 0x0200 magic value
624 * ushort size number of entries in the table; > 0
625 * int keys[size] keys, sorted low-to-high; 32-bit aligned
626 * int targets[size] branch targets, relative to switch opcode
627 *
628 * Total size is (2+size*4) 16-bit code units.
629 */
630 } else {
631 DCHECK_EQ(static_cast<int>(switchData[0]),
632 static_cast<int>(Instruction::kSparseSwitchSignature));
633 size = switchData[1];
634 keyTable = (int *) &switchData[2];
635 targetTable = (int *) &switchData[2 + size*2];
636 firstKey = 0; // To make the compiler happy
637 }
buzbee67bf8852011-08-17 17:51:35 -0700638
Bill Buzbeea114add2012-05-03 15:00:40 -0700639 if (curBlock->successorBlockList.blockListType != kNotUsed) {
640 LOG(FATAL) << "Successor block list already in use: "
641 << (int)curBlock->successorBlockList.blockListType;
642 }
643 curBlock->successorBlockList.blockListType =
644 (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) ?
645 kPackedSwitch : kSparseSwitch;
646 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, size,
647 kListSuccessorBlocks);
648
649 for (i = 0; i < size; i++) {
650 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
651 /* split */
652 true,
653 /* create */
654 true,
655 /* immedPredBlockP */
656 &curBlock);
657 SuccessorBlockInfo *successorBlockInfo =
658 (SuccessorBlockInfo *) oatNew(cUnit, sizeof(SuccessorBlockInfo),
659 false, kAllocSuccessor);
660 successorBlockInfo->block = caseBlock;
661 successorBlockInfo->key =
Elliott Hughesadb8c672012-03-06 16:49:32 -0800662 (insn->dalvikInsn.opcode == Instruction::PACKED_SWITCH) ?
Bill Buzbeea114add2012-05-03 15:00:40 -0700663 firstKey + i : keyTable[i];
664 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
665 (intptr_t) successorBlockInfo);
666 oatInsertGrowableList(cUnit, caseBlock->predecessors,
buzbeeba938cb2012-02-03 14:47:55 -0800667 (intptr_t)curBlock);
Bill Buzbeea114add2012-05-03 15:00:40 -0700668 }
669
670 /* Fall-through case */
671 BasicBlock* fallthroughBlock = findBlock(cUnit,
672 curOffset + width,
673 /* split */
674 false,
675 /* create */
676 true,
677 /* immedPredBlockP */
678 NULL);
679 curBlock->fallThrough = fallthroughBlock;
680 oatInsertGrowableList(cUnit, fallthroughBlock->predecessors,
681 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700682}
683
Elliott Hughesadb8c672012-03-06 16:49:32 -0800684/* Process instructions with the kThrow flag */
Bill Buzbeec9f40dd2012-08-15 11:35:25 -0700685BasicBlock* processCanThrow(CompilationUnit* cUnit, BasicBlock* curBlock,
686 MIR* insn, int curOffset, int width, int flags,
687 ArenaBitVector* tryBlockAddr, const u2* codePtr,
688 const u2* codeEnd)
buzbee67bf8852011-08-17 17:51:35 -0700689{
Bill Buzbeea114add2012-05-03 15:00:40 -0700690 const DexFile::CodeItem* code_item = cUnit->code_item;
Bill Buzbeec9f40dd2012-08-15 11:35:25 -0700691 bool inTryBlock = oatIsBitSet(tryBlockAddr, curOffset);
buzbee67bf8852011-08-17 17:51:35 -0700692
Bill Buzbeea114add2012-05-03 15:00:40 -0700693 /* In try block */
Bill Buzbeec9f40dd2012-08-15 11:35:25 -0700694 if (inTryBlock) {
Bill Buzbeea114add2012-05-03 15:00:40 -0700695 CatchHandlerIterator iterator(*code_item, curOffset);
buzbee67bf8852011-08-17 17:51:35 -0700696
Bill Buzbeea114add2012-05-03 15:00:40 -0700697 if (curBlock->successorBlockList.blockListType != kNotUsed) {
Bill Buzbeec9f40dd2012-08-15 11:35:25 -0700698 LOG(INFO) << PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
Bill Buzbeea114add2012-05-03 15:00:40 -0700699 LOG(FATAL) << "Successor block list already in use: "
700 << (int)curBlock->successorBlockList.blockListType;
buzbee67bf8852011-08-17 17:51:35 -0700701 }
702
Bill Buzbeea114add2012-05-03 15:00:40 -0700703 curBlock->successorBlockList.blockListType = kCatch;
704 oatInitGrowableList(cUnit, &curBlock->successorBlockList.blocks, 2,
705 kListSuccessorBlocks);
706
707 for (;iterator.HasNext(); iterator.Next()) {
708 BasicBlock *catchBlock = findBlock(cUnit, iterator.GetHandlerAddress(),
709 false /* split*/,
710 false /* creat */,
711 NULL /* immedPredBlockP */);
712 catchBlock->catchEntry = true;
buzbee6459e7c2012-10-02 14:42:41 -0700713 cUnit->catches.insert(catchBlock->startOffset);
Bill Buzbeea114add2012-05-03 15:00:40 -0700714 SuccessorBlockInfo *successorBlockInfo = (SuccessorBlockInfo *)
715 oatNew(cUnit, sizeof(SuccessorBlockInfo), false, kAllocSuccessor);
716 successorBlockInfo->block = catchBlock;
717 successorBlockInfo->key = iterator.GetHandlerTypeIndex();
718 oatInsertGrowableList(cUnit, &curBlock->successorBlockList.blocks,
719 (intptr_t) successorBlockInfo);
720 oatInsertGrowableList(cUnit, catchBlock->predecessors,
721 (intptr_t)curBlock);
buzbee67bf8852011-08-17 17:51:35 -0700722 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700723 } else {
724 BasicBlock *ehBlock = oatNewBB(cUnit, kExceptionHandling,
725 cUnit->numBlocks++);
726 curBlock->taken = ehBlock;
727 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t) ehBlock);
728 ehBlock->startOffset = curOffset;
729 oatInsertGrowableList(cUnit, ehBlock->predecessors, (intptr_t)curBlock);
730 }
731
Bill Buzbeec9f40dd2012-08-15 11:35:25 -0700732 if (insn->dalvikInsn.opcode == Instruction::THROW){
buzbee0967a252012-09-14 10:43:54 -0700733 curBlock->explicitThrow = true;
Bill Buzbeec9f40dd2012-08-15 11:35:25 -0700734 if ((codePtr < codeEnd) && contentIsInsn(codePtr)) {
735 // Force creation of new block following THROW via side-effect
736 findBlock(cUnit, curOffset + width, /* split */ false,
737 /* create */ true, /* immedPredBlockP */ NULL);
738 }
739 if (!inTryBlock) {
740 // Don't split a THROW that can't rethrow - we're done.
741 return curBlock;
Bill Buzbeea114add2012-05-03 15:00:40 -0700742 }
743 }
Bill Buzbeec9f40dd2012-08-15 11:35:25 -0700744
745 /*
746 * Split the potentially-throwing instruction into two parts.
747 * The first half will be a pseudo-op that captures the exception
748 * edges and terminates the basic block. It always falls through.
749 * Then, create a new basic block that begins with the throwing instruction
750 * (minus exceptions). Note: this new basic block must NOT be entered into
751 * the blockMap. If the potentially-throwing instruction is the target of a
752 * future branch, we need to find the check psuedo half. The new
753 * basic block containing the work portion of the instruction should
754 * only be entered via fallthrough from the block containing the
755 * pseudo exception edge MIR. Note also that this new block is
756 * not automatically terminated after the work portion, and may
757 * contain following instructions.
758 */
759 BasicBlock *newBlock = oatNewBB(cUnit, kDalvikByteCode, cUnit->numBlocks++);
760 oatInsertGrowableList(cUnit, &cUnit->blockList, (intptr_t)newBlock);
761 newBlock->startOffset = insn->offset;
762 curBlock->fallThrough = newBlock;
763 oatInsertGrowableList(cUnit, newBlock->predecessors, (intptr_t)curBlock);
764 MIR* newInsn = (MIR*)oatNew(cUnit, sizeof(MIR), true, kAllocMIR);
765 *newInsn = *insn;
766 insn->dalvikInsn.opcode =
767 static_cast<Instruction::Code>(kMirOpCheck);
768 // Associate the two halves
769 insn->meta.throwInsn = newInsn;
770 newInsn->meta.throwInsn = insn;
771 oatAppendMIR(newBlock, newInsn);
772 return newBlock;
buzbee67bf8852011-08-17 17:51:35 -0700773}
774
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800775void oatInit(CompilationUnit* cUnit, const Compiler& compiler) {
776 if (!oatArchInit()) {
777 LOG(FATAL) << "Failed to initialize oat";
778 }
779 if (!oatHeapInit(cUnit)) {
780 LOG(FATAL) << "Failed to initialize oat heap";
781 }
782}
783
buzbeeabc4c6b2012-08-23 08:17:15 -0700784CompiledMethod* compileMethod(Compiler& compiler,
buzbeec531cef2012-10-18 07:09:20 -0700785 const CompilerBackend compilerBackend,
buzbeeabc4c6b2012-08-23 08:17:15 -0700786 const DexFile::CodeItem* code_item,
787 uint32_t access_flags, InvokeType invoke_type,
788 uint32_t method_idx, jobject class_loader,
buzbeec531cef2012-10-18 07:09:20 -0700789 const DexFile& dex_file,
790 LLVMInfo* llvm_info
buzbeeabc4c6b2012-08-23 08:17:15 -0700791 )
buzbee67bf8852011-08-17 17:51:35 -0700792{
Bill Buzbeea114add2012-05-03 15:00:40 -0700793 VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
Brian Carlstrom94496d32011-08-22 09:22:47 -0700794
Bill Buzbeea114add2012-05-03 15:00:40 -0700795 const u2* codePtr = code_item->insns_;
796 const u2* codeEnd = code_item->insns_ + code_item->insns_size_in_code_units_;
797 int numBlocks = 0;
798 unsigned int curOffset = 0;
buzbee67bf8852011-08-17 17:51:35 -0700799
Bill Buzbeea114add2012-05-03 15:00:40 -0700800 ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
801 UniquePtr<CompilationUnit> cUnit(new CompilationUnit);
buzbeeba938cb2012-02-03 14:47:55 -0800802
Bill Buzbeea114add2012-05-03 15:00:40 -0700803 oatInit(cUnit.get(), compiler);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -0800804
Bill Buzbeea114add2012-05-03 15:00:40 -0700805 cUnit->compiler = &compiler;
806 cUnit->class_linker = class_linker;
807 cUnit->dex_file = &dex_file;
Bill Buzbeea114add2012-05-03 15:00:40 -0700808 cUnit->method_idx = method_idx;
809 cUnit->code_item = code_item;
810 cUnit->access_flags = access_flags;
Ian Rogers08f753d2012-08-24 14:35:25 -0700811 cUnit->invoke_type = invoke_type;
Bill Buzbeea114add2012-05-03 15:00:40 -0700812 cUnit->shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx));
813 cUnit->instructionSet = compiler.GetInstructionSet();
814 cUnit->insns = code_item->insns_;
815 cUnit->insnsSize = code_item->insns_size_in_code_units_;
816 cUnit->numIns = code_item->ins_size_;
817 cUnit->numRegs = code_item->registers_size_ - cUnit->numIns;
818 cUnit->numOuts = code_item->outs_size_;
Bill Buzbeec9f40dd2012-08-15 11:35:25 -0700819 DCHECK((cUnit->instructionSet == kThumb2) ||
820 (cUnit->instructionSet == kX86) ||
821 (cUnit->instructionSet == kMips));
buzbeec531cef2012-10-18 07:09:20 -0700822 if ((compilerBackend == kQuickGBC) || (compilerBackend == kPortable)) {
buzbee85eee022012-07-16 22:12:38 -0700823 cUnit->genBitcode = true;
824 }
buzbeec531cef2012-10-18 07:09:20 -0700825 DCHECK_NE(compilerBackend, kIceland); // TODO: remove when Portable/Iceland merge complete
826 // TODO: remove this once x86 is tested
827 if (cUnit->genBitcode && (cUnit->instructionSet != kThumb2)) {
828 UNIMPLEMENTED(WARNING) << "GBC generation untested for non-Thumb targets";
829 }
830 cUnit->llvm_info = llvm_info;
Bill Buzbeea114add2012-05-03 15:00:40 -0700831 /* Adjust this value accordingly once inlining is performed */
832 cUnit->numDalvikRegisters = code_item->registers_size_;
833 // TODO: set this from command line
834 cUnit->compilerFlipMatch = false;
835 bool useMatch = !cUnit->compilerMethodMatch.empty();
836 bool match = useMatch && (cUnit->compilerFlipMatch ^
837 (PrettyMethod(method_idx, dex_file).find(cUnit->compilerMethodMatch) !=
838 std::string::npos));
839 if (!useMatch || match) {
840 cUnit->disableOpt = kCompilerOptimizerDisableFlags;
841 cUnit->enableDebug = kCompilerDebugFlags;
842 cUnit->printMe = VLOG_IS_ON(compiler) ||
843 (cUnit->enableDebug & (1 << kDebugVerbose));
844 }
buzbee6459e7c2012-10-02 14:42:41 -0700845#ifndef NDEBUG
buzbeec531cef2012-10-18 07:09:20 -0700846 if (cUnit->genBitcode) {
buzbee6459e7c2012-10-02 14:42:41 -0700847 cUnit->enableDebug |= (1 << kDebugVerifyBitcode);
buzbee6969d502012-06-15 16:40:31 -0700848 }
buzbee2cfc6392012-05-07 14:51:40 -0700849#endif
buzbee9281f002012-10-24 12:17:24 -0700850
851#if 1
852// *** Temporary ****
853// For use in debugging issue 7250540. Disable optimization in problem method
854// to see if monkey results change. Should be removed after monkey runs
855// complete.
856if (PrettyMethod(method_idx, dex_file).find("void com.android.inputmethod.keyboard.Key.<init>(android.content.res.Resources, com.android.inputmethod.keyboard.Keyboard$Params, com.android.inputmethod.keyboard.Keyboard$Builder$Row, org.xmlpull.v1.XmlPullParser)") != std::string::npos) {
857 cUnit->disableOpt |= (
858 (1 << kLoadStoreElimination) |
859 (1 << kLoadHoisting) |
860 (1 << kSuppressLoads) |
861 (1 << kNullCheckElimination) |
862 (1 << kPromoteRegs) |
863 (1 << kTrackLiveTemps) |
864 (1 << kSkipLargeMethodOptimization) |
865 (1 << kSafeOptimizations) |
866 (1 << kBBOpt) |
867 (1 << kMatch) |
868 (1 << kPromoteCompilerTemps));
869}
870#endif
871
jeffhao7fbee072012-08-24 17:56:54 -0700872 if (cUnit->instructionSet == kMips) {
873 // Disable some optimizations for mips for now
874 cUnit->disableOpt |= (
875 (1 << kLoadStoreElimination) |
876 (1 << kLoadHoisting) |
877 (1 << kSuppressLoads) |
878 (1 << kNullCheckElimination) |
879 (1 << kPromoteRegs) |
880 (1 << kTrackLiveTemps) |
881 (1 << kSkipLargeMethodOptimization) |
882 (1 << kSafeOptimizations) |
883 (1 << kBBOpt) |
884 (1 << kMatch) |
885 (1 << kPromoteCompilerTemps));
886 }
Bill Buzbeea114add2012-05-03 15:00:40 -0700887 /* Are we generating code for the debugger? */
888 if (compiler.IsDebuggingSupported()) {
889 cUnit->genDebugger = true;
890 // Yes, disable most optimizations
891 cUnit->disableOpt |= (
892 (1 << kLoadStoreElimination) |
893 (1 << kLoadHoisting) |
894 (1 << kSuppressLoads) |
895 (1 << kPromoteRegs) |
896 (1 << kBBOpt) |
897 (1 << kMatch) |
898 (1 << kTrackLiveTemps));
899 }
900
901 /* Gathering opcode stats? */
902 if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) {
903 cUnit->opcodeCount = (int*)oatNew(cUnit.get(),
904 kNumPackedOpcodes * sizeof(int), true, kAllocMisc);
905 }
906
907 /* Assume non-throwing leaf */
908 cUnit->attrs = (METHOD_IS_LEAF | METHOD_IS_THROW_FREE);
909
910 /* Initialize the block list, estimate size based on insnsSize */
911 oatInitGrowableList(cUnit.get(), &cUnit->blockList, cUnit->insnsSize,
912 kListBlockList);
913
914 /* Initialize the switchTables list */
915 oatInitGrowableList(cUnit.get(), &cUnit->switchTables, 4,
916 kListSwitchTables);
917
918 /* Intialize the fillArrayData list */
919 oatInitGrowableList(cUnit.get(), &cUnit->fillArrayData, 4,
920 kListFillArrayData);
921
922 /* Intialize the throwLaunchpads list, estimate size based on insnsSize */
923 oatInitGrowableList(cUnit.get(), &cUnit->throwLaunchpads, cUnit->insnsSize,
924 kListThrowLaunchPads);
925
926 /* Intialize the instrinsicLaunchpads list */
927 oatInitGrowableList(cUnit.get(), &cUnit->intrinsicLaunchpads, 4,
928 kListMisc);
929
930
931 /* Intialize the suspendLaunchpads list */
932 oatInitGrowableList(cUnit.get(), &cUnit->suspendLaunchpads, 2048,
933 kListSuspendLaunchPads);
934
935 /* Allocate the bit-vector to track the beginning of basic blocks */
936 ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit.get(),
937 cUnit->insnsSize,
938 true /* expandable */);
939 cUnit->tryBlockAddr = tryBlockAddr;
940
941 /* Create the default entry and exit blocks and enter them to the list */
942 BasicBlock *entryBlock = oatNewBB(cUnit.get(), kEntryBlock, numBlocks++);
943 BasicBlock *exitBlock = oatNewBB(cUnit.get(), kExitBlock, numBlocks++);
944
945 cUnit->entryBlock = entryBlock;
946 cUnit->exitBlock = exitBlock;
947
948 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) entryBlock);
949 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) exitBlock);
950
951 /* Current block to record parsed instructions */
952 BasicBlock *curBlock = oatNewBB(cUnit.get(), kDalvikByteCode, numBlocks++);
953 curBlock->startOffset = 0;
954 oatInsertGrowableList(cUnit.get(), &cUnit->blockList, (intptr_t) curBlock);
955 /* Add first block to the fast lookup cache */
956 cUnit->blockMap.Put(curBlock->startOffset, curBlock);
957 entryBlock->fallThrough = curBlock;
958 oatInsertGrowableList(cUnit.get(), curBlock->predecessors,
959 (intptr_t)entryBlock);
960
961 /*
962 * Store back the number of blocks since new blocks may be created of
963 * accessing cUnit.
964 */
965 cUnit->numBlocks = numBlocks;
966
967 /* Identify code range in try blocks and set up the empty catch blocks */
968 processTryCatchBlocks(cUnit.get());
969
970 /* Set up for simple method detection */
971 int numPatterns = sizeof(specialPatterns)/sizeof(specialPatterns[0]);
972 bool livePattern = (numPatterns > 0) && !(cUnit->disableOpt & (1 << kMatch));
Elliott Hughesabe64aa2012-05-30 17:34:45 -0700973 bool* deadPattern = (bool*)oatNew(cUnit.get(), sizeof(bool) * numPatterns, true,
Bill Buzbeea114add2012-05-03 15:00:40 -0700974 kAllocMisc);
975 SpecialCaseHandler specialCase = kNoHandler;
976 int patternPos = 0;
977
978 /* Parse all instructions and put them into containing basic blocks */
979 while (codePtr < codeEnd) {
980 MIR *insn = (MIR *) oatNew(cUnit.get(), sizeof(MIR), true, kAllocMIR);
981 insn->offset = curOffset;
982 int width = parseInsn(cUnit.get(), codePtr, &insn->dalvikInsn, false);
983 insn->width = width;
984 Instruction::Code opcode = insn->dalvikInsn.opcode;
985 if (cUnit->opcodeCount != NULL) {
986 cUnit->opcodeCount[static_cast<int>(opcode)]++;
buzbee44b412b2012-02-04 08:50:53 -0800987 }
988
Bill Buzbeea114add2012-05-03 15:00:40 -0700989 /* Terminate when the data section is seen */
990 if (width == 0)
991 break;
992
993 /* Possible simple method? */
994 if (livePattern) {
995 livePattern = false;
996 specialCase = kNoHandler;
997 for (int i = 0; i < numPatterns; i++) {
998 if (!deadPattern[i]) {
999 if (specialPatterns[i].opcodes[patternPos] == opcode) {
1000 livePattern = true;
1001 specialCase = specialPatterns[i].handlerCode;
1002 } else {
1003 deadPattern[i] = true;
1004 }
1005 }
1006 }
1007 patternPos++;
buzbeea7c12682012-03-19 13:13:53 -07001008 }
1009
Bill Buzbeea114add2012-05-03 15:00:40 -07001010 oatAppendMIR(curBlock, insn);
buzbeecefd1872011-09-09 09:59:52 -07001011
Bill Buzbeea114add2012-05-03 15:00:40 -07001012 codePtr += width;
Ian Rogersa75a0132012-09-28 11:41:42 -07001013 int flags = Instruction::FlagsOf(insn->dalvikInsn.opcode);
buzbee67bf8852011-08-17 17:51:35 -07001014
Bill Buzbeea114add2012-05-03 15:00:40 -07001015 int dfFlags = oatDataFlowAttributes[insn->dalvikInsn.opcode];
buzbee67bf8852011-08-17 17:51:35 -07001016
Bill Buzbeea114add2012-05-03 15:00:40 -07001017 if (dfFlags & DF_HAS_DEFS) {
buzbeebff24652012-05-06 16:22:05 -07001018 cUnit->defCount += (dfFlags & DF_A_WIDE) ? 2 : 1;
Bill Buzbeea114add2012-05-03 15:00:40 -07001019 }
buzbee67bf8852011-08-17 17:51:35 -07001020
Bill Buzbeea114add2012-05-03 15:00:40 -07001021 if (flags & Instruction::kBranch) {
1022 curBlock = processCanBranch(cUnit.get(), curBlock, insn, curOffset,
1023 width, flags, codePtr, codeEnd);
1024 } else if (flags & Instruction::kReturn) {
1025 curBlock->fallThrough = exitBlock;
1026 oatInsertGrowableList(cUnit.get(), exitBlock->predecessors,
1027 (intptr_t)curBlock);
1028 /*
1029 * Terminate the current block if there are instructions
1030 * afterwards.
1031 */
1032 if (codePtr < codeEnd) {
1033 /*
1034 * Create a fallthrough block for real instructions
1035 * (incl. NOP).
1036 */
1037 if (contentIsInsn(codePtr)) {
1038 findBlock(cUnit.get(), curOffset + width,
1039 /* split */
1040 false,
1041 /* create */
1042 true,
1043 /* immedPredBlockP */
1044 NULL);
1045 }
1046 }
1047 } else if (flags & Instruction::kThrow) {
Bill Buzbeec9f40dd2012-08-15 11:35:25 -07001048 curBlock = processCanThrow(cUnit.get(), curBlock, insn, curOffset,
1049 width, flags, tryBlockAddr, codePtr, codeEnd);
Bill Buzbeea114add2012-05-03 15:00:40 -07001050 } else if (flags & Instruction::kSwitch) {
1051 processCanSwitch(cUnit.get(), curBlock, insn, curOffset, width, flags);
1052 }
1053 curOffset += width;
1054 BasicBlock *nextBlock = findBlock(cUnit.get(), curOffset,
1055 /* split */
1056 false,
1057 /* create */
1058 false,
1059 /* immedPredBlockP */
1060 NULL);
1061 if (nextBlock) {
1062 /*
1063 * The next instruction could be the target of a previously parsed
1064 * forward branch so a block is already created. If the current
1065 * instruction is not an unconditional branch, connect them through
1066 * the fall-through link.
1067 */
1068 DCHECK(curBlock->fallThrough == NULL ||
1069 curBlock->fallThrough == nextBlock ||
1070 curBlock->fallThrough == exitBlock);
buzbee5ade1d22011-09-09 14:44:52 -07001071
Bill Buzbeea114add2012-05-03 15:00:40 -07001072 if ((curBlock->fallThrough == NULL) && (flags & Instruction::kContinue)) {
1073 curBlock->fallThrough = nextBlock;
1074 oatInsertGrowableList(cUnit.get(), nextBlock->predecessors,
1075 (intptr_t)curBlock);
1076 }
1077 curBlock = nextBlock;
1078 }
1079 }
buzbeefc9e6fa2012-03-23 15:14:29 -07001080
Bill Buzbeea114add2012-05-03 15:00:40 -07001081 if (!(cUnit->disableOpt & (1 << kSkipLargeMethodOptimization))) {
1082 if ((cUnit->numBlocks > MANY_BLOCKS) ||
1083 ((cUnit->numBlocks > MANY_BLOCKS_INITIALIZER) &&
1084 PrettyMethod(method_idx, dex_file, false).find("init>") !=
1085 std::string::npos)) {
1086 cUnit->qdMode = true;
1087 }
1088 }
buzbeefc9e6fa2012-03-23 15:14:29 -07001089
Bill Buzbeea114add2012-05-03 15:00:40 -07001090 if (cUnit->qdMode) {
buzbeed1643e42012-09-05 14:06:51 -07001091 // Bitcode generation requires full dataflow analysis
buzbeec531cef2012-10-18 07:09:20 -07001092 cUnit->disableDataflow = !cUnit->genBitcode;
Bill Buzbeea114add2012-05-03 15:00:40 -07001093 // Disable optimization which require dataflow/ssa
buzbeec531cef2012-10-18 07:09:20 -07001094 cUnit->disableOpt |= (1 << kBBOpt) | (1 << kPromoteRegs) | (1 << kNullCheckElimination);
Bill Buzbeea114add2012-05-03 15:00:40 -07001095 if (cUnit->printMe) {
1096 LOG(INFO) << "QD mode enabled: "
1097 << PrettyMethod(method_idx, dex_file)
buzbeec531cef2012-10-18 07:09:20 -07001098 << " num blocks: " << cUnit->numBlocks;
Bill Buzbeea114add2012-05-03 15:00:40 -07001099 }
1100 }
buzbeec1f45042011-09-21 16:03:19 -07001101
Bill Buzbeea114add2012-05-03 15:00:40 -07001102 if (cUnit->printMe) {
1103 oatDumpCompilationUnit(cUnit.get());
1104 }
buzbee67bf8852011-08-17 17:51:35 -07001105
buzbee0967a252012-09-14 10:43:54 -07001106 /* Do a code layout pass */
1107 oatMethodCodeLayout(cUnit.get());
1108
Bill Buzbeea114add2012-05-03 15:00:40 -07001109 if (cUnit->enableDebug & (1 << kDebugVerifyDataflow)) {
1110 /* Verify if all blocks are connected as claimed */
1111 oatDataFlowAnalysisDispatcher(cUnit.get(), verifyPredInfo, kAllNodes,
1112 false /* isIterative */);
1113 }
buzbee67bf8852011-08-17 17:51:35 -07001114
Bill Buzbeea114add2012-05-03 15:00:40 -07001115 /* Perform SSA transformation for the whole method */
1116 oatMethodSSATransformation(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001117
buzbee2cfc6392012-05-07 14:51:40 -07001118 /* Do constant propagation */
1119 // TODO: Probably need to make these expandable to support new ssa names
1120 // introducted during MIR optimization passes
1121 cUnit->isConstantV = oatAllocBitVector(cUnit.get(), cUnit->numSSARegs,
1122 false /* not expandable */);
1123 cUnit->constantValues =
1124 (int*)oatNew(cUnit.get(), sizeof(int) * cUnit->numSSARegs, true,
1125 kAllocDFInfo);
1126 oatDataFlowAnalysisDispatcher(cUnit.get(), oatDoConstantPropagation,
1127 kAllNodes,
1128 false /* isIterative */);
1129
Bill Buzbeea114add2012-05-03 15:00:40 -07001130 /* Detect loops */
1131 oatMethodLoopDetection(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001132
Bill Buzbeea114add2012-05-03 15:00:40 -07001133 /* Count uses */
1134 oatMethodUseCount(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001135
Bill Buzbeea114add2012-05-03 15:00:40 -07001136 /* Perform null check elimination */
1137 oatMethodNullCheckElimination(cUnit.get());
1138
buzbeed1643e42012-09-05 14:06:51 -07001139 /* Combine basic blocks where possible */
1140 oatMethodBasicBlockCombine(cUnit.get());
1141
Bill Buzbeea114add2012-05-03 15:00:40 -07001142 /* Do some basic block optimizations */
1143 oatMethodBasicBlockOptimization(cUnit.get());
1144
buzbeed1643e42012-09-05 14:06:51 -07001145 if (cUnit->enableDebug & (1 << kDebugDumpCheckStats)) {
1146 oatDumpCheckStats(cUnit.get());
1147 }
1148
Bill Buzbeea114add2012-05-03 15:00:40 -07001149 oatInitializeRegAlloc(cUnit.get()); // Needs to happen after SSA naming
1150
1151 /* Allocate Registers using simple local allocation scheme */
1152 oatSimpleRegAlloc(cUnit.get());
1153
buzbee2cfc6392012-05-07 14:51:40 -07001154 /* Go the LLVM path? */
1155 if (cUnit->genBitcode) {
1156 // MIR->Bitcode
1157 oatMethodMIR2Bitcode(cUnit.get());
buzbeec531cef2012-10-18 07:09:20 -07001158 if (compilerBackend == kPortable) {
buzbeeabc4c6b2012-08-23 08:17:15 -07001159 // all done
1160 oatArenaReset(cUnit.get());
1161 return NULL;
1162 }
buzbee2cfc6392012-05-07 14:51:40 -07001163 // Bitcode->LIR
1164 oatMethodBitcode2LIR(cUnit.get());
1165 } else {
buzbee2cfc6392012-05-07 14:51:40 -07001166 if (specialCase != kNoHandler) {
1167 /*
1168 * Custom codegen for special cases. If for any reason the
1169 * special codegen doesn't succeed, cUnit->firstLIRInsn will
1170 * set to NULL;
1171 */
1172 oatSpecialMIR2LIR(cUnit.get(), specialCase);
1173 }
buzbee67bf8852011-08-17 17:51:35 -07001174
buzbee2cfc6392012-05-07 14:51:40 -07001175 /* Convert MIR to LIR, etc. */
1176 if (cUnit->firstLIRInsn == NULL) {
1177 oatMethodMIR2LIR(cUnit.get());
1178 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001179 }
buzbee67bf8852011-08-17 17:51:35 -07001180
Bill Buzbeea114add2012-05-03 15:00:40 -07001181 // Debugging only
1182 if (cUnit->enableDebug & (1 << kDebugDumpCFG)) {
1183 oatDumpCFG(cUnit.get(), "/sdcard/cfg/");
1184 }
buzbee16da88c2012-03-20 10:38:17 -07001185
Bill Buzbeea114add2012-05-03 15:00:40 -07001186 /* Method is not empty */
1187 if (cUnit->firstLIRInsn) {
buzbee67bf8852011-08-17 17:51:35 -07001188
Bill Buzbeea114add2012-05-03 15:00:40 -07001189 // mark the targets of switch statement case labels
1190 oatProcessSwitchTables(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001191
Bill Buzbeea114add2012-05-03 15:00:40 -07001192 /* Convert LIR into machine code. */
1193 oatAssembleLIR(cUnit.get());
buzbee99ba9642012-01-25 14:23:14 -08001194
Elliott Hughes3b6baaa2011-10-14 19:13:56 -07001195 if (cUnit->printMe) {
Bill Buzbeea114add2012-05-03 15:00:40 -07001196 oatCodegenDump(cUnit.get());
buzbee67bf8852011-08-17 17:51:35 -07001197 }
1198
Bill Buzbeea114add2012-05-03 15:00:40 -07001199 if (cUnit->opcodeCount != NULL) {
1200 LOG(INFO) << "Opcode Count";
1201 for (int i = 0; i < kNumPackedOpcodes; i++) {
1202 if (cUnit->opcodeCount[i] != 0) {
1203 LOG(INFO) << "-C- "
1204 << Instruction::Name(static_cast<Instruction::Code>(i))
1205 << " " << cUnit->opcodeCount[i];
buzbee67bf8852011-08-17 17:51:35 -07001206 }
Bill Buzbeea114add2012-05-03 15:00:40 -07001207 }
1208 }
1209 }
buzbeea7c12682012-03-19 13:13:53 -07001210
Bill Buzbeea114add2012-05-03 15:00:40 -07001211 // Combine vmap tables - core regs, then fp regs - into vmapTable
1212 std::vector<uint16_t> vmapTable;
buzbeeca7a5e42012-08-20 11:12:18 -07001213 // Core regs may have been inserted out of order - sort first
1214 std::sort(cUnit->coreVmapTable.begin(), cUnit->coreVmapTable.end());
Bill Buzbeea114add2012-05-03 15:00:40 -07001215 for (size_t i = 0 ; i < cUnit->coreVmapTable.size(); i++) {
buzbeeca7a5e42012-08-20 11:12:18 -07001216 // Copy, stripping out the phys register sort key
1217 vmapTable.push_back(~(-1 << VREG_NUM_WIDTH) & cUnit->coreVmapTable[i]);
Bill Buzbeea114add2012-05-03 15:00:40 -07001218 }
1219 // If we have a frame, push a marker to take place of lr
1220 if (cUnit->frameSize > 0) {
1221 vmapTable.push_back(INVALID_VREG);
1222 } else {
1223 DCHECK_EQ(__builtin_popcount(cUnit->coreSpillMask), 0);
1224 DCHECK_EQ(__builtin_popcount(cUnit->fpSpillMask), 0);
1225 }
buzbeeca7a5e42012-08-20 11:12:18 -07001226 // Combine vmap tables - core regs, then fp regs. fp regs already sorted
Bill Buzbeea114add2012-05-03 15:00:40 -07001227 for (uint32_t i = 0; i < cUnit->fpVmapTable.size(); i++) {
1228 vmapTable.push_back(cUnit->fpVmapTable[i]);
1229 }
1230 CompiledMethod* result =
1231 new CompiledMethod(cUnit->instructionSet, cUnit->codeBuffer,
Bill Buzbeea5b30242012-09-28 07:19:44 -07001232 cUnit->frameSize, cUnit->coreSpillMask, cUnit->fpSpillMask,
1233 cUnit->combinedMappingTable, vmapTable, cUnit->nativeGcMap);
buzbee67bf8852011-08-17 17:51:35 -07001234
Bill Buzbeea114add2012-05-03 15:00:40 -07001235 VLOG(compiler) << "Compiled " << PrettyMethod(method_idx, dex_file)
1236 << " (" << (cUnit->codeBuffer.size() * sizeof(cUnit->codeBuffer[0]))
1237 << " bytes)";
buzbee5abfa3e2012-01-31 17:01:43 -08001238
1239#ifdef WITH_MEMSTATS
Bill Buzbeea114add2012-05-03 15:00:40 -07001240 if (cUnit->enableDebug & (1 << kDebugShowMemoryUsage)) {
1241 oatDumpMemStats(cUnit.get());
1242 }
buzbee5abfa3e2012-01-31 17:01:43 -08001243#endif
buzbee67bf8852011-08-17 17:51:35 -07001244
Bill Buzbeea114add2012-05-03 15:00:40 -07001245 oatArenaReset(cUnit.get());
buzbeeba938cb2012-02-03 14:47:55 -08001246
Bill Buzbeea114add2012-05-03 15:00:40 -07001247 return result;
buzbee67bf8852011-08-17 17:51:35 -07001248}
1249
buzbeeabc4c6b2012-08-23 08:17:15 -07001250CompiledMethod* oatCompileMethod(Compiler& compiler,
buzbeec531cef2012-10-18 07:09:20 -07001251 const CompilerBackend backend,
buzbeeabc4c6b2012-08-23 08:17:15 -07001252 const DexFile::CodeItem* code_item,
1253 uint32_t access_flags, InvokeType invoke_type,
1254 uint32_t method_idx, jobject class_loader,
buzbeec531cef2012-10-18 07:09:20 -07001255 const DexFile& dex_file,
1256 LLVMInfo* llvmInfo)
buzbeeabc4c6b2012-08-23 08:17:15 -07001257{
buzbeec531cef2012-10-18 07:09:20 -07001258 return compileMethod(compiler, backend, code_item, access_flags, invoke_type, method_idx, class_loader,
1259 dex_file, llvmInfo);
buzbeeabc4c6b2012-08-23 08:17:15 -07001260}
1261
Elliott Hughes11d1b0c2012-01-23 16:57:47 -08001262} // namespace art
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001263
Bill Buzbeea114add2012-05-03 15:00:40 -07001264extern "C" art::CompiledMethod*
buzbeec531cef2012-10-18 07:09:20 -07001265 ArtQuickCompileMethod(art::Compiler& compiler,
1266 const art::DexFile::CodeItem* code_item,
1267 uint32_t access_flags, art::InvokeType invoke_type,
1268 uint32_t method_idx, jobject class_loader,
1269 const art::DexFile& dex_file)
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001270{
1271 CHECK_EQ(compiler.GetInstructionSet(), art::oatInstructionSet());
buzbeec531cef2012-10-18 07:09:20 -07001272 // TODO: check method fingerprint here to determine appropriate backend type. Until then, use build default
1273 art::CompilerBackend backend = compiler.GetCompilerBackend();
1274 return art::oatCompileMethod(compiler, backend, code_item, access_flags, invoke_type,
1275 method_idx, class_loader, dex_file, NULL /* use thread llvmInfo */);
Elliott Hughesb3bd5f02012-03-08 21:05:27 -08001276}