blob: 40da0e1d8b2fd1dd9db6d6bca41d9b0b4ad9fcb2 [file] [log] [blame]
Ben Chengba4fc8b2009-06-01 13:00:29 -07001/*
2 * Copyright (C) 2009 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 "libdex/OpCode.h"
Ben Chengba4fc8b2009-06-01 13:00:29 -070019#include "interp/Jit.h"
20#include "CompilerInternals.h"
Ben Cheng7a2697d2010-06-07 13:44:23 -070021#include "Dataflow.h"
Ben Chengba4fc8b2009-06-01 13:00:29 -070022
23/*
24 * Parse an instruction, return the length of the instruction
25 */
26static inline int parseInsn(const u2 *codePtr, DecodedInstruction *decInsn,
27 bool printMe)
28{
29 u2 instr = *codePtr;
30 OpCode opcode = instr & 0xff;
31 int insnWidth;
32
Ben Cheng8b258bf2009-06-24 17:27:07 -070033 // Don't parse instruction data
Ben Chengba4fc8b2009-06-01 13:00:29 -070034 if (opcode == OP_NOP && instr != 0) {
Ben Cheng8b258bf2009-06-24 17:27:07 -070035 return 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -070036 } else {
37 insnWidth = gDvm.instrWidth[opcode];
38 if (insnWidth < 0) {
39 insnWidth = -insnWidth;
40 }
41 }
42
43 dexDecodeInstruction(gDvm.instrFormat, codePtr, decInsn);
44 if (printMe) {
Ben Cheng7a2697d2010-06-07 13:44:23 -070045 char *decodedString = dvmCompilerGetDalvikDisassembly(decInsn, NULL);
Ben Chengccd6c012009-10-15 14:52:45 -070046 LOGD("%p: %#06x %s\n", codePtr, opcode, decodedString);
Ben Chengba4fc8b2009-06-01 13:00:29 -070047 }
48 return insnWidth;
49}
50
Ben Cheng9c147b82009-10-07 16:41:46 -070051#define UNKNOWN_TARGET 0xffffffff
52
Ben Chengba4fc8b2009-06-01 13:00:29 -070053/*
54 * Identify block-ending instructions and collect supplemental information
55 * regarding the following instructions.
56 */
57static inline bool findBlockBoundary(const Method *caller, MIR *insn,
58 unsigned int curOffset,
59 unsigned int *target, bool *isInvoke,
60 const Method **callee)
61{
62 switch (insn->dalvikInsn.opCode) {
63 /* Target is not compile-time constant */
64 case OP_RETURN_VOID:
65 case OP_RETURN:
66 case OP_RETURN_WIDE:
67 case OP_RETURN_OBJECT:
68 case OP_THROW:
Ben Cheng9c147b82009-10-07 16:41:46 -070069 *target = UNKNOWN_TARGET;
70 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -070071 case OP_INVOKE_VIRTUAL:
72 case OP_INVOKE_VIRTUAL_RANGE:
73 case OP_INVOKE_INTERFACE:
74 case OP_INVOKE_INTERFACE_RANGE:
75 case OP_INVOKE_VIRTUAL_QUICK:
76 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
77 *isInvoke = true;
78 break;
79 case OP_INVOKE_SUPER:
80 case OP_INVOKE_SUPER_RANGE: {
81 int mIndex = caller->clazz->pDvmDex->
82 pResMethods[insn->dalvikInsn.vB]->methodIndex;
83 const Method *calleeMethod =
84 caller->clazz->super->vtable[mIndex];
85
Ben Cheng8b258bf2009-06-24 17:27:07 -070086 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -070087 *target = (unsigned int) calleeMethod->insns;
88 }
89 *isInvoke = true;
90 *callee = calleeMethod;
91 break;
92 }
93 case OP_INVOKE_STATIC:
94 case OP_INVOKE_STATIC_RANGE: {
95 const Method *calleeMethod =
96 caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
97
Ben Cheng8b258bf2009-06-24 17:27:07 -070098 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -070099 *target = (unsigned int) calleeMethod->insns;
100 }
101 *isInvoke = true;
102 *callee = calleeMethod;
103 break;
104 }
105 case OP_INVOKE_SUPER_QUICK:
106 case OP_INVOKE_SUPER_QUICK_RANGE: {
107 const Method *calleeMethod =
108 caller->clazz->super->vtable[insn->dalvikInsn.vB];
109
Ben Cheng8b258bf2009-06-24 17:27:07 -0700110 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700111 *target = (unsigned int) calleeMethod->insns;
112 }
113 *isInvoke = true;
114 *callee = calleeMethod;
115 break;
116 }
117 case OP_INVOKE_DIRECT:
118 case OP_INVOKE_DIRECT_RANGE: {
119 const Method *calleeMethod =
120 caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
Ben Cheng8b258bf2009-06-24 17:27:07 -0700121 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700122 *target = (unsigned int) calleeMethod->insns;
123 }
124 *isInvoke = true;
125 *callee = calleeMethod;
126 break;
127 }
128 case OP_GOTO:
129 case OP_GOTO_16:
130 case OP_GOTO_32:
131 *target = curOffset + (int) insn->dalvikInsn.vA;
132 break;
133
134 case OP_IF_EQ:
135 case OP_IF_NE:
136 case OP_IF_LT:
137 case OP_IF_GE:
138 case OP_IF_GT:
139 case OP_IF_LE:
140 *target = curOffset + (int) insn->dalvikInsn.vC;
141 break;
142
143 case OP_IF_EQZ:
144 case OP_IF_NEZ:
145 case OP_IF_LTZ:
146 case OP_IF_GEZ:
147 case OP_IF_GTZ:
148 case OP_IF_LEZ:
149 *target = curOffset + (int) insn->dalvikInsn.vB;
150 break;
151
152 default:
153 return false;
Ben Cheng9c147b82009-10-07 16:41:46 -0700154 }
155 return true;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700156}
157
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800158static inline bool isGoto(MIR *insn)
159{
160 switch (insn->dalvikInsn.opCode) {
161 case OP_GOTO:
162 case OP_GOTO_16:
163 case OP_GOTO_32:
164 return true;
165 default:
166 return false;
167 }
168}
169
Ben Chengba4fc8b2009-06-01 13:00:29 -0700170/*
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800171 * Identify unconditional branch instructions
Ben Chengba4fc8b2009-06-01 13:00:29 -0700172 */
173static inline bool isUnconditionalBranch(MIR *insn)
174{
175 switch (insn->dalvikInsn.opCode) {
176 case OP_RETURN_VOID:
177 case OP_RETURN:
178 case OP_RETURN_WIDE:
179 case OP_RETURN_OBJECT:
Ben Chengba4fc8b2009-06-01 13:00:29 -0700180 return true;
181 default:
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800182 return isGoto(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700183 }
184}
185
186/*
Ben Cheng8b258bf2009-06-24 17:27:07 -0700187 * dvmHashTableLookup() callback
188 */
189static int compareMethod(const CompilerMethodStats *m1,
190 const CompilerMethodStats *m2)
191{
192 return (int) m1->method - (int) m2->method;
193}
194
195/*
Ben Cheng7a2697d2010-06-07 13:44:23 -0700196 * Analyze the body of the method to collect high-level information regarding
197 * inlining:
198 * - is empty method?
199 * - is getter/setter?
200 * - can throw exception?
201 *
202 * Currently the inliner only handles getters and setters. When its capability
203 * becomes more sophisticated more information will be retrieved here.
204 */
205static int analyzeInlineTarget(DecodedInstruction *dalvikInsn, int attributes,
206 int offset)
207{
208 int flags = dexGetInstrFlags(gDvm.instrFlags, dalvikInsn->opCode);
209
210 if ((flags & kInstrInvoke) &&
211 (dalvikInsn->opCode != OP_INVOKE_DIRECT_EMPTY)) {
212 attributes &= ~METHOD_IS_LEAF;
213 }
214
215 if (!(flags & kInstrCanReturn)) {
216 if (!(dvmCompilerDataFlowAttributes[dalvikInsn->opCode] &
217 DF_IS_GETTER)) {
218 attributes &= ~METHOD_IS_GETTER;
219 }
220 if (!(dvmCompilerDataFlowAttributes[dalvikInsn->opCode] &
221 DF_IS_SETTER)) {
222 attributes &= ~METHOD_IS_SETTER;
223 }
224 }
225
226 /*
227 * The expected instruction sequence is setter will never return value and
228 * getter will also do. Clear the bits if the behavior is discovered
229 * otherwise.
230 */
231 if (flags & kInstrCanReturn) {
232 if (dalvikInsn->opCode == OP_RETURN_VOID) {
233 attributes &= ~METHOD_IS_GETTER;
234 }
235 else {
236 attributes &= ~METHOD_IS_SETTER;
237 }
238 }
239
240 if (flags & kInstrCanThrow) {
241 attributes &= ~METHOD_IS_THROW_FREE;
242 }
243
244 if (offset == 0 && dalvikInsn->opCode == OP_RETURN_VOID) {
245 attributes |= METHOD_IS_EMPTY;
246 }
247
248 return attributes;
249}
250
251/*
Ben Cheng8b258bf2009-06-24 17:27:07 -0700252 * Analyze each method whose traces are ever compiled. Collect a variety of
253 * statistics like the ratio of exercised vs overall code and code bloat
Ben Cheng7a2697d2010-06-07 13:44:23 -0700254 * ratios. If isCallee is true, also analyze each instruction in more details
255 * to see if it is suitable for inlining.
Ben Cheng8b258bf2009-06-24 17:27:07 -0700256 */
Ben Cheng7a2697d2010-06-07 13:44:23 -0700257CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
258 bool isCallee)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700259{
260 const DexCode *dexCode = dvmGetMethodCode(method);
261 const u2 *codePtr = dexCode->insns;
262 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
263 int insnSize = 0;
264 int hashValue = dvmComputeUtf8Hash(method->name);
265
266 CompilerMethodStats dummyMethodEntry; // For hash table lookup
267 CompilerMethodStats *realMethodEntry; // For hash table storage
268
269 /* For lookup only */
270 dummyMethodEntry.method = method;
271 realMethodEntry = dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
272 &dummyMethodEntry,
273 (HashCompareFunc) compareMethod,
274 false);
275
Ben Cheng7a2697d2010-06-07 13:44:23 -0700276 /* This method has never been analyzed before - create an entry */
277 if (realMethodEntry == NULL) {
278 realMethodEntry =
279 (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
280 realMethodEntry->method = method;
281
282 dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
283 realMethodEntry,
284 (HashCompareFunc) compareMethod,
285 true);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700286 }
287
Ben Cheng7a2697d2010-06-07 13:44:23 -0700288 /* This method is invoked as a callee and has been analyzed - just return */
289 if ((isCallee == true) && (realMethodEntry->attributes & METHOD_IS_CALLEE))
290 return realMethodEntry;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700291
Ben Cheng7a2697d2010-06-07 13:44:23 -0700292 /*
293 * Similarly, return if this method has been compiled before as a hot
294 * method already.
295 */
296 if ((isCallee == false) &&
297 (realMethodEntry->attributes & METHOD_IS_HOT))
298 return realMethodEntry;
299
300 int attributes;
301
302 /* Method hasn't been analyzed for the desired purpose yet */
303 if (isCallee) {
304 /* Aggressively set the attributes until proven otherwise */
305 attributes = METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE |
306 METHOD_IS_GETTER | METHOD_IS_SETTER;
307 } else {
308 attributes = METHOD_IS_HOT;
309 }
Ben Cheng8b258bf2009-06-24 17:27:07 -0700310
311 /* Count the number of instructions */
312 while (codePtr < codeEnd) {
313 DecodedInstruction dalvikInsn;
314 int width = parseInsn(codePtr, &dalvikInsn, false);
315
316 /* Terminate when the data section is seen */
317 if (width == 0)
318 break;
319
Ben Cheng7a2697d2010-06-07 13:44:23 -0700320 if (isCallee) {
321 attributes = analyzeInlineTarget(&dalvikInsn, attributes, insnSize);
322 }
323
Ben Cheng8b258bf2009-06-24 17:27:07 -0700324 insnSize += width;
325 codePtr += width;
326 }
327
Ben Cheng7a2697d2010-06-07 13:44:23 -0700328 /*
329 * Only handle simple getters/setters with one instruction followed by
330 * return
331 */
332 if ((attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) &&
333 (insnSize != 3)) {
334 attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
335 }
336
Ben Cheng8b258bf2009-06-24 17:27:07 -0700337 realMethodEntry->dalvikSize = insnSize * 2;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700338 realMethodEntry->attributes |= attributes;
339
340#if 0
341 /* Uncomment the following to explore various callee patterns */
342 if (attributes & METHOD_IS_THROW_FREE) {
343 LOGE("%s%s is inlinable%s", method->clazz->descriptor, method->name,
344 (attributes & METHOD_IS_EMPTY) ? " empty" : "");
345 }
346
347 if (attributes & METHOD_IS_LEAF) {
348 LOGE("%s%s is leaf %d%s", method->clazz->descriptor, method->name,
349 insnSize, insnSize < 5 ? " (small)" : "");
350 }
351
352 if (attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) {
353 LOGE("%s%s is %s", method->clazz->descriptor, method->name,
354 attributes & METHOD_IS_GETTER ? "getter": "setter");
355 }
356 if (attributes ==
357 (METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE)) {
358 LOGE("%s%s is inlinable non setter/getter", method->clazz->descriptor,
359 method->name);
360 }
361#endif
362
Ben Cheng8b258bf2009-06-24 17:27:07 -0700363 return realMethodEntry;
364}
365
366/*
Ben Cheng33672452010-01-12 14:59:30 -0800367 * Crawl the stack of the thread that requesed compilation to see if any of the
368 * ancestors are on the blacklist.
369 */
370bool filterMethodByCallGraph(Thread *thread, const char *curMethodName)
371{
372 /* Crawl the Dalvik stack frames and compare the method name*/
373 StackSaveArea *ssaPtr = ((StackSaveArea *) thread->curFrame) - 1;
374 while (ssaPtr != ((StackSaveArea *) NULL) - 1) {
375 const Method *method = ssaPtr->method;
376 if (method) {
377 int hashValue = dvmComputeUtf8Hash(method->name);
378 bool found =
379 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
380 (char *) method->name,
381 (HashCompareFunc) strcmp, false) !=
382 NULL;
383 if (found) {
384 LOGD("Method %s (--> %s) found on the JIT %s list",
385 method->name, curMethodName,
386 gDvmJit.includeSelectedMethod ? "white" : "black");
387 return true;
388 }
389
390 }
391 ssaPtr = ((StackSaveArea *) ssaPtr->prevFrame) - 1;
392 };
393 return false;
394}
395
396/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700397 * Main entry point to start trace compilation. Basic blocks are constructed
398 * first and they will be passed to the codegen routines to convert Dalvik
399 * bytecode into machine code.
400 */
Bill Buzbee716f1202009-07-23 13:22:09 -0700401bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800402 JitTranslationInfo *info, jmp_buf *bailPtr)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700403{
404 const DexCode *dexCode = dvmGetMethodCode(desc->method);
405 const JitTraceRun* currRun = &desc->trace[0];
Ben Chengba4fc8b2009-06-01 13:00:29 -0700406 unsigned int curOffset = currRun->frag.startOffset;
407 unsigned int numInsts = currRun->frag.numInsts;
408 const u2 *codePtr = dexCode->insns + curOffset;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700409 int traceSize = 0; // # of half-words
Ben Chengba4fc8b2009-06-01 13:00:29 -0700410 const u2 *startCodePtr = codePtr;
411 BasicBlock *startBB, *curBB, *lastBB;
412 int numBlocks = 0;
413 static int compilationId;
414 CompilationUnit cUnit;
Ben Cheng1357e942010-02-10 17:21:39 -0800415#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700416 CompilerMethodStats *methodStats;
Ben Cheng1357e942010-02-10 17:21:39 -0800417#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700418
Bill Buzbee964a7b02010-01-28 12:54:19 -0800419 /* If we've already compiled this trace, just return success */
jeffhao9e45c0b2010-02-03 10:24:05 -0800420 if (dvmJitGetCodeAddr(startCodePtr) && !info->discardResult) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700421 /*
422 * Make sure the codeAddress is NULL so that it won't clobber the
423 * existing entry.
424 */
425 info->codeAddress = NULL;
Bill Buzbee964a7b02010-01-28 12:54:19 -0800426 return true;
427 }
428
Ben Chenge9695e52009-06-16 16:11:47 -0700429 compilationId++;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700430 memset(&cUnit, 0, sizeof(CompilationUnit));
431
Ben Cheng1357e942010-02-10 17:21:39 -0800432#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700433 /* Locate the entry to store compilation statistics for this method */
Ben Cheng7a2697d2010-06-07 13:44:23 -0700434 methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
Ben Cheng1357e942010-02-10 17:21:39 -0800435#endif
Ben Chenge9695e52009-06-16 16:11:47 -0700436
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800437 /* Set the recover buffer pointer */
438 cUnit.bailPtr = bailPtr;
439
Ben Chengba4fc8b2009-06-01 13:00:29 -0700440 /* Initialize the printMe flag */
441 cUnit.printMe = gDvmJit.printMe;
442
Bill Buzbee6e963e12009-06-17 16:56:19 -0700443 /* Initialize the profile flag */
444 cUnit.executionCount = gDvmJit.profile;
445
Ben Cheng7a2697d2010-06-07 13:44:23 -0700446 /* Setup the method */
447 cUnit.method = desc->method;
448
449 /* Initialize the PC reconstruction list */
450 dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
451
Ben Chengba4fc8b2009-06-01 13:00:29 -0700452 /* Identify traces that we don't want to compile */
453 if (gDvmJit.methodTable) {
454 int len = strlen(desc->method->clazz->descriptor) +
455 strlen(desc->method->name) + 1;
456 char *fullSignature = dvmCompilerNew(len, true);
457 strcpy(fullSignature, desc->method->clazz->descriptor);
458 strcat(fullSignature, desc->method->name);
459
460 int hashValue = dvmComputeUtf8Hash(fullSignature);
461
462 /*
463 * Doing three levels of screening to see whether we want to skip
464 * compiling this method
465 */
466
467 /* First, check the full "class;method" signature */
468 bool methodFound =
469 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
470 fullSignature, (HashCompareFunc) strcmp,
471 false) !=
472 NULL;
473
474 /* Full signature not found - check the enclosing class */
475 if (methodFound == false) {
476 int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
477 methodFound =
478 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
479 (char *) desc->method->clazz->descriptor,
480 (HashCompareFunc) strcmp, false) !=
481 NULL;
482 /* Enclosing class not found - check the method name */
483 if (methodFound == false) {
484 int hashValue = dvmComputeUtf8Hash(desc->method->name);
485 methodFound =
486 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
487 (char *) desc->method->name,
488 (HashCompareFunc) strcmp, false) !=
489 NULL;
Ben Cheng33672452010-01-12 14:59:30 -0800490
491 /*
492 * Debug by call-graph is enabled. Check if the debug list
493 * covers any methods on the VM stack.
494 */
495 if (methodFound == false && gDvmJit.checkCallGraph == true) {
496 methodFound =
497 filterMethodByCallGraph(info->requestingThread,
498 desc->method->name);
499 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700500 }
501 }
502
503 /*
504 * Under the following conditions, the trace will be *conservatively*
505 * compiled by only containing single-step instructions to and from the
506 * interpreter.
507 * 1) If includeSelectedMethod == false, the method matches the full or
508 * partial signature stored in the hash table.
509 *
510 * 2) If includeSelectedMethod == true, the method does not match the
511 * full and partial signature stored in the hash table.
512 */
513 if (gDvmJit.includeSelectedMethod != methodFound) {
514 cUnit.allSingleStep = true;
515 } else {
516 /* Compile the trace as normal */
517
518 /* Print the method we cherry picked */
519 if (gDvmJit.includeSelectedMethod == true) {
520 cUnit.printMe = true;
521 }
522 }
523 }
524
Ben Cheng4238ec22009-08-24 16:32:22 -0700525 /* Allocate the entry block */
Ben Cheng7a2697d2010-06-07 13:44:23 -0700526 lastBB = startBB = curBB = dvmCompilerNewBB(kTraceEntryBlock);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700527 curBB->startOffset = curOffset;
528 curBB->id = numBlocks++;
529
Bill Buzbee1465db52009-09-23 17:17:35 -0700530 curBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Cheng4238ec22009-08-24 16:32:22 -0700531 curBB->startOffset = curOffset;
532 curBB->id = numBlocks++;
533
534 /* Make the first real dalvik block the fallthrough of the entry block */
535 startBB->fallThrough = curBB;
536 lastBB->next = curBB;
537 lastBB = curBB;
538
Ben Chengba4fc8b2009-06-01 13:00:29 -0700539 if (cUnit.printMe) {
540 LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n",
541 desc->method->name, curOffset);
542 }
543
Ben Cheng1efc9c52009-06-08 18:25:27 -0700544 /*
545 * Analyze the trace descriptor and include up to the maximal number
546 * of Dalvik instructions into the IR.
547 */
548 while (1) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700549 MIR *insn;
550 int width;
Ben Cheng4238ec22009-08-24 16:32:22 -0700551 insn = dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700552 insn->offset = curOffset;
553 width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700554
555 /* The trace should never incude instruction data */
556 assert(width);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700557 insn->width = width;
558 traceSize += width;
559 dvmCompilerAppendMIR(curBB, insn);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700560 cUnit.numInsts++;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700561
562 int flags = dexGetInstrFlags(gDvm.instrFlags, insn->dalvikInsn.opCode);
563
564 if ((flags & kInstrInvoke) &&
565 (insn->dalvikInsn.opCode != OP_INVOKE_DIRECT_EMPTY)) {
566 assert(numInsts == 1);
567 CallsiteInfo *callsiteInfo =
568 dvmCompilerNew(sizeof(CallsiteInfo), true);
569 callsiteInfo->clazz = currRun[1].meta;
570 callsiteInfo->method = currRun[2].meta;
571 insn->meta.callsiteInfo = callsiteInfo;
572 }
573
Ben Cheng1efc9c52009-06-08 18:25:27 -0700574 /* Instruction limit reached - terminate the trace here */
575 if (cUnit.numInsts >= numMaxInsts) {
576 break;
577 }
578 if (--numInsts == 0) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700579 if (currRun->frag.runEnd) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700580 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700581 } else {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700582 /* Advance to the next trace description (ie non-meta info) */
583 do {
584 currRun++;
585 } while (!currRun->frag.isCode);
586
587 /* Dummy end-of-run marker seen */
588 if (currRun->frag.numInsts == 0) {
589 break;
590 }
591
Bill Buzbee1465db52009-09-23 17:17:35 -0700592 curBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700593 lastBB->next = curBB;
594 lastBB = curBB;
595 curBB->id = numBlocks++;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700596 curOffset = currRun->frag.startOffset;
597 numInsts = currRun->frag.numInsts;
598 curBB->startOffset = curOffset;
599 codePtr = dexCode->insns + curOffset;
600 }
601 } else {
602 curOffset += width;
603 codePtr += width;
604 }
605 }
606
Ben Cheng1357e942010-02-10 17:21:39 -0800607#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700608 /* Convert # of half-word to bytes */
609 methodStats->compiledDalvikSize += traceSize * 2;
Ben Cheng1357e942010-02-10 17:21:39 -0800610#endif
Ben Cheng8b258bf2009-06-24 17:27:07 -0700611
Ben Chengba4fc8b2009-06-01 13:00:29 -0700612 /*
613 * Now scan basic blocks containing real code to connect the
614 * taken/fallthrough links. Also create chaining cells for code not included
615 * in the trace.
616 */
617 for (curBB = startBB; curBB; curBB = curBB->next) {
618 MIR *lastInsn = curBB->lastMIRInsn;
Ben Cheng4238ec22009-08-24 16:32:22 -0700619 /* Skip empty blocks */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700620 if (lastInsn == NULL) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700621 continue;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700622 }
623 curOffset = lastInsn->offset;
624 unsigned int targetOffset = curOffset;
625 unsigned int fallThroughOffset = curOffset + lastInsn->width;
626 bool isInvoke = false;
627 const Method *callee = NULL;
628
629 findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
630 &targetOffset, &isInvoke, &callee);
631
632 /* Link the taken and fallthrough blocks */
633 BasicBlock *searchBB;
634
Ben Cheng7a2697d2010-06-07 13:44:23 -0700635 int flags = dexGetInstrFlags(gDvm.instrFlags,
636 lastInsn->dalvikInsn.opCode);
637
638 if (flags & kInstrInvoke) {
639 cUnit.hasInvoke = true;
640 }
641
Ben Chengba4fc8b2009-06-01 13:00:29 -0700642 /* No backward branch in the trace - start searching the next BB */
643 for (searchBB = curBB->next; searchBB; searchBB = searchBB->next) {
644 if (targetOffset == searchBB->startOffset) {
645 curBB->taken = searchBB;
646 }
647 if (fallThroughOffset == searchBB->startOffset) {
648 curBB->fallThrough = searchBB;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700649
650 /*
651 * Fallthrough block of an invoke instruction needs to be
652 * aligned to 4-byte boundary (alignment instruction to be
653 * inserted later.
654 */
655 if (flags & kInstrInvoke) {
656 searchBB->isFallThroughFromInvoke = true;
657 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700658 }
659 }
660
Ben Cheng1efc9c52009-06-08 18:25:27 -0700661 /*
662 * Some blocks are ended by non-control-flow-change instructions,
663 * currently only due to trace length constraint. In this case we need
664 * to generate an explicit branch at the end of the block to jump to
665 * the chaining cell.
Ben Cheng17f15ce2009-07-27 16:21:52 -0700666 *
667 * NOTE: INVOKE_DIRECT_EMPTY is actually not an invoke but a nop
Ben Cheng1efc9c52009-06-08 18:25:27 -0700668 */
669 curBB->needFallThroughBranch =
Ben Cheng17f15ce2009-07-27 16:21:52 -0700670 ((flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
671 kInstrInvoke)) == 0) ||
672 (lastInsn->dalvikInsn.opCode == OP_INVOKE_DIRECT_EMPTY);
673
Ben Cheng4238ec22009-08-24 16:32:22 -0700674 if (curBB->taken == NULL &&
675 curBB->fallThrough == NULL &&
676 flags == (kInstrCanBranch | kInstrCanContinue) &&
677 fallThroughOffset == startBB->startOffset) {
Ben Cheng0fd31e42009-09-03 14:40:16 -0700678 BasicBlock *loopBranch = curBB;
679 BasicBlock *exitBB;
680 BasicBlock *exitChainingCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700681
682 if (cUnit.printMe) {
683 LOGD("Natural loop detected!");
684 }
Ben Cheng7a2697d2010-06-07 13:44:23 -0700685 exitBB = dvmCompilerNewBB(kTraceExitBlock);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700686 lastBB->next = exitBB;
687 lastBB = exitBB;
Ben Cheng4238ec22009-08-24 16:32:22 -0700688
Ben Cheng0fd31e42009-09-03 14:40:16 -0700689 exitBB->startOffset = targetOffset;
690 exitBB->id = numBlocks++;
691 exitBB->needFallThroughBranch = true;
Ben Cheng4238ec22009-08-24 16:32:22 -0700692
Ben Cheng0fd31e42009-09-03 14:40:16 -0700693 loopBranch->taken = exitBB;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700694#if defined(WITH_SELF_VERIFICATION)
Ben Cheng0fd31e42009-09-03 14:40:16 -0700695 BasicBlock *backwardCell =
Bill Buzbee1465db52009-09-23 17:17:35 -0700696 dvmCompilerNewBB(kChainingCellBackwardBranch);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700697 lastBB->next = backwardCell;
698 lastBB = backwardCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700699
Ben Cheng0fd31e42009-09-03 14:40:16 -0700700 backwardCell->startOffset = startBB->startOffset;
701 backwardCell->id = numBlocks++;
702 loopBranch->fallThrough = backwardCell;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700703#elif defined(WITH_JIT_TUNING)
704 if (gDvmJit.profile) {
705 BasicBlock *backwardCell =
Bill Buzbee1465db52009-09-23 17:17:35 -0700706 dvmCompilerNewBB(kChainingCellBackwardBranch);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700707 lastBB->next = backwardCell;
708 lastBB = backwardCell;
709
710 backwardCell->startOffset = startBB->startOffset;
711 backwardCell->id = numBlocks++;
712 loopBranch->fallThrough = backwardCell;
713 } else {
714 loopBranch->fallThrough = startBB->next;
715 }
716#else
717 loopBranch->fallThrough = startBB->next;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700718#endif
719
720 /* Create the chaining cell as the fallthrough of the exit block */
Bill Buzbee1465db52009-09-23 17:17:35 -0700721 exitChainingCell = dvmCompilerNewBB(kChainingCellNormal);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700722 lastBB->next = exitChainingCell;
723 lastBB = exitChainingCell;
724
725 exitChainingCell->startOffset = targetOffset;
726 exitChainingCell->id = numBlocks++;
727
728 exitBB->fallThrough = exitChainingCell;
729
Ben Cheng4238ec22009-08-24 16:32:22 -0700730 cUnit.hasLoop = true;
731 }
732
Ben Cheng6c10a972009-10-29 14:39:18 -0700733 if (lastInsn->dalvikInsn.opCode == OP_PACKED_SWITCH ||
734 lastInsn->dalvikInsn.opCode == OP_SPARSE_SWITCH) {
735 int i;
736 const u2 *switchData = desc->method->insns + lastInsn->offset +
737 lastInsn->dalvikInsn.vB;
738 int size = switchData[1];
739 int maxChains = MIN(size, MAX_CHAINED_SWITCH_CASES);
740
741 /*
742 * Generate the landing pad for cases whose ranks are higher than
743 * MAX_CHAINED_SWITCH_CASES. The code will re-enter the interpreter
744 * through the NoChain point.
745 */
746 if (maxChains != size) {
747 cUnit.switchOverflowPad =
748 desc->method->insns + lastInsn->offset;
749 }
750
751 s4 *targets = (s4 *) (switchData + 2 +
752 (lastInsn->dalvikInsn.opCode == OP_PACKED_SWITCH ?
753 2 : size * 2));
754
755 /* One chaining cell for the first MAX_CHAINED_SWITCH_CASES cases */
756 for (i = 0; i < maxChains; i++) {
757 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal);
758 lastBB->next = caseChain;
759 lastBB = caseChain;
760
761 caseChain->startOffset = lastInsn->offset + targets[i];
762 caseChain->id = numBlocks++;
763 }
764
765 /* One more chaining cell for the default case */
766 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal);
767 lastBB->next = caseChain;
768 lastBB = caseChain;
769
770 caseChain->startOffset = lastInsn->offset + lastInsn->width;
771 caseChain->id = numBlocks++;
Ben Cheng6d576092009-09-01 17:01:58 -0700772 /* Fallthrough block not included in the trace */
Ben Cheng6c10a972009-10-29 14:39:18 -0700773 } else if (!isUnconditionalBranch(lastInsn) &&
774 curBB->fallThrough == NULL) {
Ben Cheng6d576092009-09-01 17:01:58 -0700775 /*
776 * If the chaining cell is after an invoke or
777 * instruction that cannot change the control flow, request a hot
778 * chaining cell.
779 */
780 if (isInvoke || curBB->needFallThroughBranch) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700781 lastBB->next = dvmCompilerNewBB(kChainingCellHot);
Ben Cheng6d576092009-09-01 17:01:58 -0700782 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700783 lastBB->next = dvmCompilerNewBB(kChainingCellNormal);
Ben Cheng6d576092009-09-01 17:01:58 -0700784 }
785 lastBB = lastBB->next;
786 lastBB->id = numBlocks++;
787 lastBB->startOffset = fallThroughOffset;
788 curBB->fallThrough = lastBB;
789 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700790 /* Target block not included in the trace */
Ben Cheng38329f52009-07-07 14:19:20 -0700791 if (curBB->taken == NULL &&
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800792 (isGoto(lastInsn) || isInvoke ||
793 (targetOffset != UNKNOWN_TARGET && targetOffset != curOffset))) {
Ben Cheng38329f52009-07-07 14:19:20 -0700794 BasicBlock *newBB;
Ben Cheng1efc9c52009-06-08 18:25:27 -0700795 if (isInvoke) {
Ben Cheng38329f52009-07-07 14:19:20 -0700796 /* Monomorphic callee */
797 if (callee) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700798 newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton);
Ben Cheng38329f52009-07-07 14:19:20 -0700799 newBB->startOffset = 0;
800 newBB->containingMethod = callee;
801 /* Will resolve at runtime */
802 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700803 newBB = dvmCompilerNewBB(kChainingCellInvokePredicted);
Ben Cheng38329f52009-07-07 14:19:20 -0700804 newBB->startOffset = 0;
805 }
Ben Cheng1efc9c52009-06-08 18:25:27 -0700806 /* For unconditional branches, request a hot chaining cell */
807 } else {
Jeff Hao97319a82009-08-12 16:57:15 -0700808#if !defined(WITH_SELF_VERIFICATION)
Ben Cheng38329f52009-07-07 14:19:20 -0700809 newBB = dvmCompilerNewBB(flags & kInstrUnconditional ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700810 kChainingCellHot :
811 kChainingCellNormal);
Ben Cheng38329f52009-07-07 14:19:20 -0700812 newBB->startOffset = targetOffset;
Jeff Hao97319a82009-08-12 16:57:15 -0700813#else
814 /* Handle branches that branch back into the block */
815 if (targetOffset >= curBB->firstMIRInsn->offset &&
816 targetOffset <= curBB->lastMIRInsn->offset) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700817 newBB = dvmCompilerNewBB(kChainingCellBackwardBranch);
Jeff Hao97319a82009-08-12 16:57:15 -0700818 } else {
819 newBB = dvmCompilerNewBB(flags & kInstrUnconditional ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700820 kChainingCellHot :
821 kChainingCellNormal);
Jeff Hao97319a82009-08-12 16:57:15 -0700822 }
823 newBB->startOffset = targetOffset;
824#endif
Ben Cheng1efc9c52009-06-08 18:25:27 -0700825 }
Ben Cheng38329f52009-07-07 14:19:20 -0700826 newBB->id = numBlocks++;
827 curBB->taken = newBB;
828 lastBB->next = newBB;
829 lastBB = newBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700830 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700831 }
832
833 /* Now create a special block to host PC reconstruction code */
Bill Buzbee1465db52009-09-23 17:17:35 -0700834 lastBB->next = dvmCompilerNewBB(kPCReconstruction);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700835 lastBB = lastBB->next;
836 lastBB->id = numBlocks++;
837
838 /* And one final block that publishes the PC and raise the exception */
Bill Buzbee1465db52009-09-23 17:17:35 -0700839 lastBB->next = dvmCompilerNewBB(kExceptionHandling);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700840 lastBB = lastBB->next;
841 lastBB->id = numBlocks++;
842
843 if (cUnit.printMe) {
Elliott Hughescc6fac82010-07-02 13:38:44 -0700844 char* signature = dexProtoCopyMethodDescriptor(&desc->method->prototype);
845 LOGD("TRACEINFO (%d): 0x%08x %s%s.%s 0x%x %d of %d, %d blocks",
Ben Chenge9695e52009-06-16 16:11:47 -0700846 compilationId,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700847 (intptr_t) desc->method->insns,
848 desc->method->clazz->descriptor,
849 desc->method->name,
Elliott Hughescc6fac82010-07-02 13:38:44 -0700850 signature,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700851 desc->trace[0].frag.startOffset,
852 traceSize,
853 dexCode->insnsSize,
854 numBlocks);
Elliott Hughescc6fac82010-07-02 13:38:44 -0700855 free(signature);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700856 }
857
858 BasicBlock **blockList;
859
Ben Chengba4fc8b2009-06-01 13:00:29 -0700860 cUnit.traceDesc = desc;
861 cUnit.numBlocks = numBlocks;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700862 blockList = cUnit.blockList =
863 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
864
865 int i;
866
867 for (i = 0, curBB = startBB; i < numBlocks; i++) {
868 blockList[i] = curBB;
869 curBB = curBB->next;
870 }
871 /* Make sure all blocks are added to the cUnit */
872 assert(curBB == NULL);
873
Ben Cheng7a2697d2010-06-07 13:44:23 -0700874 /* Set the instruction set to use (NOTE: later components may change it) */
875 cUnit.instructionSet = dvmCompilerInstructionSet();
876
877 /* Inline transformation @ the MIR level */
878 if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) {
879 dvmCompilerInlineMIR(&cUnit);
880 }
881
Ben Cheng4238ec22009-08-24 16:32:22 -0700882 /* Preparation for SSA conversion */
883 dvmInitializeSSAConversion(&cUnit);
884
885 if (cUnit.hasLoop) {
886 dvmCompilerLoopOpt(&cUnit);
887 }
888 else {
889 dvmCompilerNonLoopAnalysis(&cUnit);
890 }
891
Bill Buzbee1465db52009-09-23 17:17:35 -0700892 dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
893
Ben Chengba4fc8b2009-06-01 13:00:29 -0700894 if (cUnit.printMe) {
895 dvmCompilerDumpCompilationUnit(&cUnit);
896 }
897
Bill Buzbee1465db52009-09-23 17:17:35 -0700898 /* Allocate Registers */
899 dvmCompilerRegAlloc(&cUnit);
900
Ben Chengba4fc8b2009-06-01 13:00:29 -0700901 /* Convert MIR to LIR, etc. */
902 dvmCompilerMIR2LIR(&cUnit);
903
Ben Cheng1efc9c52009-06-08 18:25:27 -0700904 /* Convert LIR into machine code. */
Bill Buzbee716f1202009-07-23 13:22:09 -0700905 dvmCompilerAssembleLIR(&cUnit, info);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700906
907 if (cUnit.printMe) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700908 if (cUnit.halveInstCount) {
909 LOGD("Assembler aborted");
910 } else {
911 dvmCompilerCodegenDump(&cUnit);
912 }
913 LOGD("End %s%s, %d Dalvik instructions",
914 desc->method->clazz->descriptor, desc->method->name,
915 cUnit.numInsts);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700916 }
917
918 /* Reset the compiler resource pool */
919 dvmCompilerArenaReset();
920
Bill Buzbee716f1202009-07-23 13:22:09 -0700921 /* Success */
Ben Cheng4238ec22009-08-24 16:32:22 -0700922 if (!cUnit.halveInstCount) {
Ben Cheng1357e942010-02-10 17:21:39 -0800923#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700924 methodStats->nativeSize += cUnit.totalSize;
Ben Cheng1357e942010-02-10 17:21:39 -0800925#endif
Bill Buzbee716f1202009-07-23 13:22:09 -0700926 return info->codeAddress != NULL;
Ben Cheng1efc9c52009-06-08 18:25:27 -0700927
928 /* Halve the instruction count and retry again */
929 } else {
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800930 return dvmCompileTrace(desc, cUnit.numInsts / 2, info, bailPtr);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700931 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700932}
933
934/*
Ben Cheng7a2697d2010-06-07 13:44:23 -0700935 * Since we are including instructions from possibly a cold method into the
936 * current trace, we need to make sure that all the associated information
937 * with the callee is properly initialized. If not, we punt on this inline
938 * target.
939 *
940 * TODO: volatile instructions will handled later.
941 */
942bool dvmCompilerCanIncludeThisInstruction(const Method *method,
943 const DecodedInstruction *insn)
944{
945 switch (insn->opCode) {
946 case OP_NEW_INSTANCE:
947 case OP_CHECK_CAST: {
948 ClassObject *classPtr = (void*)
949 (method->clazz->pDvmDex->pResClasses[insn->vB]);
950
951 /* Class hasn't been initialized yet */
952 if (classPtr == NULL) {
953 return false;
954 }
955 return true;
956 }
957 case OP_SGET_OBJECT:
958 case OP_SGET_BOOLEAN:
959 case OP_SGET_CHAR:
960 case OP_SGET_BYTE:
961 case OP_SGET_SHORT:
962 case OP_SGET:
963 case OP_SGET_WIDE:
964 case OP_SPUT_OBJECT:
965 case OP_SPUT_BOOLEAN:
966 case OP_SPUT_CHAR:
967 case OP_SPUT_BYTE:
968 case OP_SPUT_SHORT:
969 case OP_SPUT:
970 case OP_SPUT_WIDE: {
971 void *fieldPtr = (void*)
972 (method->clazz->pDvmDex->pResFields[insn->vB]);
973
974 if (fieldPtr == NULL) {
975 return false;
976 }
977 return true;
978 }
979 case OP_INVOKE_SUPER:
980 case OP_INVOKE_SUPER_RANGE: {
981 int mIndex = method->clazz->pDvmDex->
982 pResMethods[insn->vB]->methodIndex;
983 const Method *calleeMethod = method->clazz->super->vtable[mIndex];
984 if (calleeMethod == NULL) {
985 return false;
986 }
987 return true;
988 }
989 case OP_INVOKE_SUPER_QUICK:
990 case OP_INVOKE_SUPER_QUICK_RANGE: {
991 const Method *calleeMethod = method->clazz->super->vtable[insn->vB];
992 if (calleeMethod == NULL) {
993 return false;
994 }
995 return true;
996 }
997 case OP_INVOKE_STATIC:
998 case OP_INVOKE_STATIC_RANGE:
999 case OP_INVOKE_DIRECT:
1000 case OP_INVOKE_DIRECT_RANGE: {
1001 const Method *calleeMethod =
1002 method->clazz->pDvmDex->pResMethods[insn->vB];
1003 if (calleeMethod == NULL) {
1004 return false;
1005 }
1006 return true;
1007 }
1008 case OP_CONST_CLASS: {
1009 void *classPtr = (void*)
1010 (method->clazz->pDvmDex->pResClasses[insn->vB]);
1011
1012 if (classPtr == NULL) {
1013 return false;
1014 }
1015 return true;
1016 }
1017 case OP_CONST_STRING_JUMBO:
1018 case OP_CONST_STRING: {
1019 void *strPtr = (void*)
1020 (method->clazz->pDvmDex->pResStrings[insn->vB]);
1021
1022 if (strPtr == NULL) {
1023 return false;
1024 }
1025 return true;
1026 }
1027 default:
1028 return true;
1029 }
1030}
1031
1032/*
Ben Chengba4fc8b2009-06-01 13:00:29 -07001033 * Similar to dvmCompileTrace, but the entity processed here is the whole
1034 * method.
1035 *
1036 * TODO: implementation will be revisited when the trace builder can provide
1037 * whole-method traces.
1038 */
Ben Cheng7a2697d2010-06-07 13:44:23 -07001039bool dvmCompileMethod(CompilationUnit *cUnit, const Method *method,
1040 JitTranslationInfo *info)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001041{
1042 const DexCode *dexCode = dvmGetMethodCode(method);
1043 const u2 *codePtr = dexCode->insns;
1044 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
1045 int blockID = 0;
1046 unsigned int curOffset = 0;
1047
Ben Cheng7a2697d2010-06-07 13:44:23 -07001048 /* If we've already compiled this trace, just return success */
1049 if (dvmJitGetCodeAddr(codePtr) && !info->discardResult) {
1050 return true;
1051 }
1052
1053 /* Doing method-based compilation */
1054 cUnit->wholeMethod = true;
1055
Bill Buzbee1465db52009-09-23 17:17:35 -07001056 BasicBlock *firstBlock = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001057 firstBlock->id = blockID++;
1058
1059 /* Allocate the bit-vector to track the beginning of basic blocks */
Ben Cheng4238ec22009-08-24 16:32:22 -07001060 BitVector *bbStartAddr = dvmCompilerAllocBitVector(dexCode->insnsSize+1,
1061 false);
1062 dvmCompilerSetBit(bbStartAddr, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001063
Ben Cheng7a2697d2010-06-07 13:44:23 -07001064 int numInvokeTargets = 0;
1065
Ben Chengba4fc8b2009-06-01 13:00:29 -07001066 /*
1067 * Sequentially go through every instruction first and put them in a single
1068 * basic block. Identify block boundaries at the mean time.
1069 */
1070 while (codePtr < codeEnd) {
Ben Cheng4238ec22009-08-24 16:32:22 -07001071 MIR *insn = dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001072 insn->offset = curOffset;
1073 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
1074 bool isInvoke = false;
1075 const Method *callee;
1076 insn->width = width;
1077
Ben Cheng8b258bf2009-06-24 17:27:07 -07001078 /* Terminate when the data section is seen */
1079 if (width == 0)
1080 break;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001081
1082 if (!dvmCompilerCanIncludeThisInstruction(cUnit->method,
1083 &insn->dalvikInsn)) {
1084 return false;
1085 }
1086
Ben Chengba4fc8b2009-06-01 13:00:29 -07001087 dvmCompilerAppendMIR(firstBlock, insn);
1088 /*
1089 * Check whether this is a block ending instruction and whether it
1090 * suggests the start of a new block
1091 */
1092 unsigned int target = curOffset;
1093
1094 /*
1095 * If findBlockBoundary returns true, it means the current instruction
1096 * is terminating the current block. If it is a branch, the target
1097 * address will be recorded in target.
1098 */
1099 if (findBlockBoundary(method, insn, curOffset, &target, &isInvoke,
1100 &callee)) {
Ben Cheng4238ec22009-08-24 16:32:22 -07001101 dvmCompilerSetBit(bbStartAddr, curOffset + width);
Ben Cheng7a2697d2010-06-07 13:44:23 -07001102 /* Each invoke needs a chaining cell block */
1103 if (isInvoke) {
1104 numInvokeTargets++;
1105 }
1106 /* A branch will end the current block */
1107 else if (target != curOffset && target != UNKNOWN_TARGET) {
Ben Cheng4238ec22009-08-24 16:32:22 -07001108 dvmCompilerSetBit(bbStartAddr, target);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001109 }
1110 }
1111
1112 codePtr += width;
1113 /* each bit represents 16-bit quantity */
1114 curOffset += width;
1115 }
1116
1117 /*
1118 * The number of blocks will be equal to the number of bits set to 1 in the
1119 * bit vector minus 1, because the bit representing the location after the
1120 * last instruction is set to one.
Ben Cheng7a2697d2010-06-07 13:44:23 -07001121 *
1122 * We also add additional blocks for invoke chaining and the number is
1123 * denoted by numInvokeTargets.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001124 */
1125 int numBlocks = dvmCountSetBits(bbStartAddr);
1126 if (dvmIsBitSet(bbStartAddr, dexCode->insnsSize)) {
1127 numBlocks--;
1128 }
1129
Ben Chengba4fc8b2009-06-01 13:00:29 -07001130 BasicBlock **blockList;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001131 blockList = cUnit->blockList =
1132 dvmCompilerNew(sizeof(BasicBlock *) * (numBlocks + numInvokeTargets),
1133 true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001134
1135 /*
Ben Cheng7a2697d2010-06-07 13:44:23 -07001136 * Register the first block onto the list and start splitting it into
1137 * sub-blocks.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001138 */
1139 blockList[0] = firstBlock;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001140 cUnit->numBlocks = 1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001141
1142 int i;
1143 for (i = 0; i < numBlocks; i++) {
1144 MIR *insn;
1145 BasicBlock *curBB = blockList[i];
1146 curOffset = curBB->lastMIRInsn->offset;
1147
1148 for (insn = curBB->firstMIRInsn->next; insn; insn = insn->next) {
1149 /* Found the beginning of a new block, see if it is created yet */
1150 if (dvmIsBitSet(bbStartAddr, insn->offset)) {
1151 int j;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001152 for (j = 0; j < cUnit->numBlocks; j++) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07001153 if (blockList[j]->firstMIRInsn->offset == insn->offset)
1154 break;
1155 }
1156
1157 /* Block not split yet - do it now */
Ben Cheng7a2697d2010-06-07 13:44:23 -07001158 if (j == cUnit->numBlocks) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001159 BasicBlock *newBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001160 newBB->id = blockID++;
1161 newBB->firstMIRInsn = insn;
Ben Cheng8b258bf2009-06-24 17:27:07 -07001162 newBB->startOffset = insn->offset;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001163 newBB->lastMIRInsn = curBB->lastMIRInsn;
1164 curBB->lastMIRInsn = insn->prev;
1165 insn->prev->next = NULL;
1166 insn->prev = NULL;
1167
1168 /*
1169 * If the insn is not an unconditional branch, set up the
1170 * fallthrough link.
1171 */
1172 if (!isUnconditionalBranch(curBB->lastMIRInsn)) {
1173 curBB->fallThrough = newBB;
1174 }
1175
Ben Cheng7a2697d2010-06-07 13:44:23 -07001176 /*
1177 * Fallthrough block of an invoke instruction needs to be
1178 * aligned to 4-byte boundary (alignment instruction to be
1179 * inserted later.
1180 */
1181 if (dexGetInstrFlags(gDvm.instrFlags,
1182 curBB->lastMIRInsn->dalvikInsn.opCode) &
1183 kInstrInvoke) {
1184 newBB->isFallThroughFromInvoke = true;
1185 }
1186
Ben Chengba4fc8b2009-06-01 13:00:29 -07001187 /* enqueue the new block */
Ben Cheng7a2697d2010-06-07 13:44:23 -07001188 blockList[cUnit->numBlocks++] = newBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001189 break;
1190 }
1191 }
1192 }
1193 }
1194
Ben Cheng7a2697d2010-06-07 13:44:23 -07001195 if (numBlocks != cUnit->numBlocks) {
1196 LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit->numBlocks);
1197 dvmCompilerAbort(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001198 }
1199
Ben Chengba4fc8b2009-06-01 13:00:29 -07001200 /* Connect the basic blocks through the taken links */
1201 for (i = 0; i < numBlocks; i++) {
1202 BasicBlock *curBB = blockList[i];
1203 MIR *insn = curBB->lastMIRInsn;
1204 unsigned int target = insn->offset;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001205 bool isInvoke = false;
1206 const Method *callee = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001207
1208 findBlockBoundary(method, insn, target, &target, &isInvoke, &callee);
1209
Ben Cheng7a2697d2010-06-07 13:44:23 -07001210 /* Found a block ended on a branch (not invoke) */
1211 if (isInvoke == false && target != insn->offset) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07001212 int j;
1213 /* Forward branch */
1214 if (target > insn->offset) {
1215 j = i + 1;
1216 } else {
1217 /* Backward branch */
1218 j = 0;
1219 }
1220 for (; j < numBlocks; j++) {
1221 if (blockList[j]->firstMIRInsn->offset == target) {
1222 curBB->taken = blockList[j];
1223 break;
1224 }
1225 }
Ben Cheng7a2697d2010-06-07 13:44:23 -07001226 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001227
Ben Cheng7a2697d2010-06-07 13:44:23 -07001228 if (isInvoke) {
1229 BasicBlock *newBB;
1230 /* Monomorphic callee */
1231 if (callee) {
1232 newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton);
1233 newBB->startOffset = 0;
1234 newBB->containingMethod = callee;
1235 /* Will resolve at runtime */
1236 } else {
1237 newBB = dvmCompilerNewBB(kChainingCellInvokePredicted);
1238 newBB->startOffset = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001239 }
Ben Cheng7a2697d2010-06-07 13:44:23 -07001240 newBB->id = blockID++;
1241 curBB->taken = newBB;
1242 /* enqueue the new block */
1243 blockList[cUnit->numBlocks++] = newBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001244 }
1245 }
1246
Ben Cheng7a2697d2010-06-07 13:44:23 -07001247 if (cUnit->numBlocks != numBlocks + numInvokeTargets) {
1248 LOGE("Expect %d vs %d total blocks\n", numBlocks + numInvokeTargets,
1249 cUnit->numBlocks);
1250 dvmCompilerDumpCompilationUnit(cUnit);
1251 dvmCompilerAbort(cUnit);
1252 }
1253
Bill Buzbee716f1202009-07-23 13:22:09 -07001254 /* Set the instruction set to use (NOTE: later components may change it) */
Ben Cheng7a2697d2010-06-07 13:44:23 -07001255 cUnit->instructionSet = dvmCompilerInstructionSet();
Bill Buzbee716f1202009-07-23 13:22:09 -07001256
Ben Cheng7a2697d2010-06-07 13:44:23 -07001257 /* Preparation for SSA conversion */
1258 dvmInitializeSSAConversion(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001259
Ben Cheng7a2697d2010-06-07 13:44:23 -07001260 /* SSA analysis */
1261 dvmCompilerNonLoopAnalysis(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001262
Ben Cheng7a2697d2010-06-07 13:44:23 -07001263 /* Needs to happen after SSA naming */
1264 dvmCompilerInitializeRegAlloc(cUnit);
1265
1266 /* Allocate Registers */
1267 dvmCompilerRegAlloc(cUnit);
1268
1269 /* Convert MIR to LIR, etc. */
1270 dvmCompilerMIR2LIR(cUnit);
1271
1272 /* Convert LIR into machine code. */
1273 dvmCompilerAssembleLIR(cUnit, info);
1274
1275 if (cUnit->halveInstCount) {
1276 return false;
1277 }
1278
1279 dvmCompilerDumpCompilationUnit(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001280
1281 dvmCompilerArenaReset();
1282
Bill Buzbee716f1202009-07-23 13:22:09 -07001283 return info->codeAddress != NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001284}