blob: 4e5a8821214a0a23ab5c3121f616c86a29ab9a0c [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 {
Dan Bornstein41e286c2010-11-19 12:36:19 -080037 insnWidth = dexGetInstrWidth(opcode);
Ben Chengba4fc8b2009-06-01 13:00:29 -070038 if (insnWidth < 0) {
39 insnWidth = -insnWidth;
40 }
41 }
42
Dan Bornstein54322392010-11-17 14:16:56 -080043 dexDecodeInstruction(codePtr, decInsn);
Ben Chengba4fc8b2009-06-01 13:00:29 -070044 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{
Dan Bornstein41e286c2010-11-19 12:36:19 -0800208 int flags = dexGetInstrFlags(dalvikInsn->opCode);
Ben Cheng34dc7962010-08-26 14:56:31 -0700209 int dalvikOpCode = dalvikInsn->opCode;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700210
211 if ((flags & kInstrInvoke) &&
Ben Cheng34dc7962010-08-26 14:56:31 -0700212 (dalvikOpCode != OP_INVOKE_DIRECT_EMPTY)) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700213 attributes &= ~METHOD_IS_LEAF;
214 }
215
216 if (!(flags & kInstrCanReturn)) {
Ben Cheng34dc7962010-08-26 14:56:31 -0700217 if (!(dvmCompilerDataFlowAttributes[dalvikOpCode] &
Ben Cheng7a2697d2010-06-07 13:44:23 -0700218 DF_IS_GETTER)) {
219 attributes &= ~METHOD_IS_GETTER;
220 }
Ben Cheng34dc7962010-08-26 14:56:31 -0700221 if (!(dvmCompilerDataFlowAttributes[dalvikOpCode] &
Ben Cheng7a2697d2010-06-07 13:44:23 -0700222 DF_IS_SETTER)) {
223 attributes &= ~METHOD_IS_SETTER;
224 }
225 }
226
227 /*
228 * The expected instruction sequence is setter will never return value and
229 * getter will also do. Clear the bits if the behavior is discovered
230 * otherwise.
231 */
232 if (flags & kInstrCanReturn) {
Ben Cheng34dc7962010-08-26 14:56:31 -0700233 if (dalvikOpCode == OP_RETURN_VOID) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700234 attributes &= ~METHOD_IS_GETTER;
235 }
236 else {
237 attributes &= ~METHOD_IS_SETTER;
238 }
239 }
240
241 if (flags & kInstrCanThrow) {
242 attributes &= ~METHOD_IS_THROW_FREE;
243 }
244
Ben Cheng34dc7962010-08-26 14:56:31 -0700245 if (offset == 0 && dalvikOpCode == OP_RETURN_VOID) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700246 attributes |= METHOD_IS_EMPTY;
247 }
248
Ben Cheng34dc7962010-08-26 14:56:31 -0700249 /*
250 * Check if this opcode is selected for single stepping.
251 * If so, don't inline the callee as there is no stack frame for the
252 * interpreter to single-step through the instruction.
253 */
254 if (SINGLE_STEP_OP(dalvikOpCode)) {
255 attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
256 }
257
Ben Cheng7a2697d2010-06-07 13:44:23 -0700258 return attributes;
259}
260
261/*
Ben Cheng8b258bf2009-06-24 17:27:07 -0700262 * Analyze each method whose traces are ever compiled. Collect a variety of
263 * statistics like the ratio of exercised vs overall code and code bloat
Ben Cheng7a2697d2010-06-07 13:44:23 -0700264 * ratios. If isCallee is true, also analyze each instruction in more details
265 * to see if it is suitable for inlining.
Ben Cheng8b258bf2009-06-24 17:27:07 -0700266 */
Ben Cheng7a2697d2010-06-07 13:44:23 -0700267CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
268 bool isCallee)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700269{
270 const DexCode *dexCode = dvmGetMethodCode(method);
271 const u2 *codePtr = dexCode->insns;
272 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
273 int insnSize = 0;
274 int hashValue = dvmComputeUtf8Hash(method->name);
275
276 CompilerMethodStats dummyMethodEntry; // For hash table lookup
277 CompilerMethodStats *realMethodEntry; // For hash table storage
278
279 /* For lookup only */
280 dummyMethodEntry.method = method;
281 realMethodEntry = dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
282 &dummyMethodEntry,
283 (HashCompareFunc) compareMethod,
284 false);
285
Ben Cheng7a2697d2010-06-07 13:44:23 -0700286 /* This method has never been analyzed before - create an entry */
287 if (realMethodEntry == NULL) {
288 realMethodEntry =
289 (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
290 realMethodEntry->method = method;
291
292 dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
293 realMethodEntry,
294 (HashCompareFunc) compareMethod,
295 true);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700296 }
297
Ben Cheng7a2697d2010-06-07 13:44:23 -0700298 /* This method is invoked as a callee and has been analyzed - just return */
299 if ((isCallee == true) && (realMethodEntry->attributes & METHOD_IS_CALLEE))
300 return realMethodEntry;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700301
Ben Cheng7a2697d2010-06-07 13:44:23 -0700302 /*
303 * Similarly, return if this method has been compiled before as a hot
304 * method already.
305 */
306 if ((isCallee == false) &&
307 (realMethodEntry->attributes & METHOD_IS_HOT))
308 return realMethodEntry;
309
310 int attributes;
311
312 /* Method hasn't been analyzed for the desired purpose yet */
313 if (isCallee) {
314 /* Aggressively set the attributes until proven otherwise */
315 attributes = METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE |
316 METHOD_IS_GETTER | METHOD_IS_SETTER;
317 } else {
318 attributes = METHOD_IS_HOT;
319 }
Ben Cheng8b258bf2009-06-24 17:27:07 -0700320
321 /* Count the number of instructions */
322 while (codePtr < codeEnd) {
323 DecodedInstruction dalvikInsn;
324 int width = parseInsn(codePtr, &dalvikInsn, false);
325
326 /* Terminate when the data section is seen */
327 if (width == 0)
328 break;
329
Ben Cheng7a2697d2010-06-07 13:44:23 -0700330 if (isCallee) {
331 attributes = analyzeInlineTarget(&dalvikInsn, attributes, insnSize);
332 }
333
Ben Cheng8b258bf2009-06-24 17:27:07 -0700334 insnSize += width;
335 codePtr += width;
336 }
337
Ben Cheng7a2697d2010-06-07 13:44:23 -0700338 /*
339 * Only handle simple getters/setters with one instruction followed by
340 * return
341 */
342 if ((attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) &&
343 (insnSize != 3)) {
344 attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
345 }
346
Ben Cheng8b258bf2009-06-24 17:27:07 -0700347 realMethodEntry->dalvikSize = insnSize * 2;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700348 realMethodEntry->attributes |= attributes;
349
350#if 0
351 /* Uncomment the following to explore various callee patterns */
352 if (attributes & METHOD_IS_THROW_FREE) {
353 LOGE("%s%s is inlinable%s", method->clazz->descriptor, method->name,
354 (attributes & METHOD_IS_EMPTY) ? " empty" : "");
355 }
356
357 if (attributes & METHOD_IS_LEAF) {
358 LOGE("%s%s is leaf %d%s", method->clazz->descriptor, method->name,
359 insnSize, insnSize < 5 ? " (small)" : "");
360 }
361
362 if (attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) {
363 LOGE("%s%s is %s", method->clazz->descriptor, method->name,
364 attributes & METHOD_IS_GETTER ? "getter": "setter");
365 }
366 if (attributes ==
367 (METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE)) {
368 LOGE("%s%s is inlinable non setter/getter", method->clazz->descriptor,
369 method->name);
370 }
371#endif
372
Ben Cheng8b258bf2009-06-24 17:27:07 -0700373 return realMethodEntry;
374}
375
376/*
Ben Cheng33672452010-01-12 14:59:30 -0800377 * Crawl the stack of the thread that requesed compilation to see if any of the
378 * ancestors are on the blacklist.
379 */
Andy McFadden953a0ed2010-09-17 15:48:38 -0700380static bool filterMethodByCallGraph(Thread *thread, const char *curMethodName)
Ben Cheng33672452010-01-12 14:59:30 -0800381{
382 /* Crawl the Dalvik stack frames and compare the method name*/
383 StackSaveArea *ssaPtr = ((StackSaveArea *) thread->curFrame) - 1;
384 while (ssaPtr != ((StackSaveArea *) NULL) - 1) {
385 const Method *method = ssaPtr->method;
386 if (method) {
387 int hashValue = dvmComputeUtf8Hash(method->name);
388 bool found =
389 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
390 (char *) method->name,
391 (HashCompareFunc) strcmp, false) !=
392 NULL;
393 if (found) {
394 LOGD("Method %s (--> %s) found on the JIT %s list",
395 method->name, curMethodName,
396 gDvmJit.includeSelectedMethod ? "white" : "black");
397 return true;
398 }
399
400 }
401 ssaPtr = ((StackSaveArea *) ssaPtr->prevFrame) - 1;
402 };
403 return false;
404}
405
406/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700407 * Main entry point to start trace compilation. Basic blocks are constructed
408 * first and they will be passed to the codegen routines to convert Dalvik
409 * bytecode into machine code.
410 */
Bill Buzbee716f1202009-07-23 13:22:09 -0700411bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
Ben Cheng4a419582010-08-04 13:23:09 -0700412 JitTranslationInfo *info, jmp_buf *bailPtr,
413 int optHints)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700414{
415 const DexCode *dexCode = dvmGetMethodCode(desc->method);
416 const JitTraceRun* currRun = &desc->trace[0];
Ben Chengba4fc8b2009-06-01 13:00:29 -0700417 unsigned int curOffset = currRun->frag.startOffset;
418 unsigned int numInsts = currRun->frag.numInsts;
419 const u2 *codePtr = dexCode->insns + curOffset;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700420 int traceSize = 0; // # of half-words
Ben Chengba4fc8b2009-06-01 13:00:29 -0700421 const u2 *startCodePtr = codePtr;
422 BasicBlock *startBB, *curBB, *lastBB;
423 int numBlocks = 0;
424 static int compilationId;
425 CompilationUnit cUnit;
Ben Cheng1357e942010-02-10 17:21:39 -0800426#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700427 CompilerMethodStats *methodStats;
Ben Cheng1357e942010-02-10 17:21:39 -0800428#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700429
Bill Buzbee964a7b02010-01-28 12:54:19 -0800430 /* If we've already compiled this trace, just return success */
jeffhao9e45c0b2010-02-03 10:24:05 -0800431 if (dvmJitGetCodeAddr(startCodePtr) && !info->discardResult) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700432 /*
433 * Make sure the codeAddress is NULL so that it won't clobber the
434 * existing entry.
435 */
436 info->codeAddress = NULL;
Bill Buzbee964a7b02010-01-28 12:54:19 -0800437 return true;
438 }
439
Ben Chenge9695e52009-06-16 16:11:47 -0700440 compilationId++;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700441 memset(&cUnit, 0, sizeof(CompilationUnit));
442
Ben Cheng1357e942010-02-10 17:21:39 -0800443#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700444 /* Locate the entry to store compilation statistics for this method */
Ben Cheng7a2697d2010-06-07 13:44:23 -0700445 methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
Ben Cheng1357e942010-02-10 17:21:39 -0800446#endif
Ben Chenge9695e52009-06-16 16:11:47 -0700447
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800448 /* Set the recover buffer pointer */
449 cUnit.bailPtr = bailPtr;
450
Ben Chengba4fc8b2009-06-01 13:00:29 -0700451 /* Initialize the printMe flag */
452 cUnit.printMe = gDvmJit.printMe;
453
Bill Buzbee6e963e12009-06-17 16:56:19 -0700454 /* Initialize the profile flag */
455 cUnit.executionCount = gDvmJit.profile;
456
Ben Cheng7a2697d2010-06-07 13:44:23 -0700457 /* Setup the method */
458 cUnit.method = desc->method;
459
460 /* Initialize the PC reconstruction list */
461 dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
462
Ben Chengba4fc8b2009-06-01 13:00:29 -0700463 /* Identify traces that we don't want to compile */
464 if (gDvmJit.methodTable) {
465 int len = strlen(desc->method->clazz->descriptor) +
466 strlen(desc->method->name) + 1;
467 char *fullSignature = dvmCompilerNew(len, true);
468 strcpy(fullSignature, desc->method->clazz->descriptor);
469 strcat(fullSignature, desc->method->name);
470
471 int hashValue = dvmComputeUtf8Hash(fullSignature);
472
473 /*
474 * Doing three levels of screening to see whether we want to skip
475 * compiling this method
476 */
477
478 /* First, check the full "class;method" signature */
479 bool methodFound =
480 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
481 fullSignature, (HashCompareFunc) strcmp,
482 false) !=
483 NULL;
484
485 /* Full signature not found - check the enclosing class */
486 if (methodFound == false) {
487 int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
488 methodFound =
489 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
490 (char *) desc->method->clazz->descriptor,
491 (HashCompareFunc) strcmp, false) !=
492 NULL;
493 /* Enclosing class not found - check the method name */
494 if (methodFound == false) {
495 int hashValue = dvmComputeUtf8Hash(desc->method->name);
496 methodFound =
497 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
498 (char *) desc->method->name,
499 (HashCompareFunc) strcmp, false) !=
500 NULL;
Ben Cheng33672452010-01-12 14:59:30 -0800501
502 /*
503 * Debug by call-graph is enabled. Check if the debug list
504 * covers any methods on the VM stack.
505 */
506 if (methodFound == false && gDvmJit.checkCallGraph == true) {
507 methodFound =
508 filterMethodByCallGraph(info->requestingThread,
509 desc->method->name);
510 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700511 }
512 }
513
514 /*
515 * Under the following conditions, the trace will be *conservatively*
516 * compiled by only containing single-step instructions to and from the
517 * interpreter.
518 * 1) If includeSelectedMethod == false, the method matches the full or
519 * partial signature stored in the hash table.
520 *
521 * 2) If includeSelectedMethod == true, the method does not match the
522 * full and partial signature stored in the hash table.
523 */
524 if (gDvmJit.includeSelectedMethod != methodFound) {
525 cUnit.allSingleStep = true;
526 } else {
527 /* Compile the trace as normal */
528
529 /* Print the method we cherry picked */
530 if (gDvmJit.includeSelectedMethod == true) {
531 cUnit.printMe = true;
532 }
533 }
534 }
535
Ben Cheng4238ec22009-08-24 16:32:22 -0700536 /* Allocate the entry block */
Ben Cheng7a2697d2010-06-07 13:44:23 -0700537 lastBB = startBB = curBB = dvmCompilerNewBB(kTraceEntryBlock);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700538 curBB->startOffset = curOffset;
539 curBB->id = numBlocks++;
540
Bill Buzbee1465db52009-09-23 17:17:35 -0700541 curBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Cheng4238ec22009-08-24 16:32:22 -0700542 curBB->startOffset = curOffset;
543 curBB->id = numBlocks++;
544
545 /* Make the first real dalvik block the fallthrough of the entry block */
546 startBB->fallThrough = curBB;
547 lastBB->next = curBB;
548 lastBB = curBB;
549
Ben Chengba4fc8b2009-06-01 13:00:29 -0700550 if (cUnit.printMe) {
551 LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n",
552 desc->method->name, curOffset);
553 }
554
Ben Cheng1efc9c52009-06-08 18:25:27 -0700555 /*
556 * Analyze the trace descriptor and include up to the maximal number
557 * of Dalvik instructions into the IR.
558 */
559 while (1) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700560 MIR *insn;
561 int width;
Ben Cheng4238ec22009-08-24 16:32:22 -0700562 insn = dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700563 insn->offset = curOffset;
564 width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700565
566 /* The trace should never incude instruction data */
567 assert(width);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700568 insn->width = width;
569 traceSize += width;
570 dvmCompilerAppendMIR(curBB, insn);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700571 cUnit.numInsts++;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700572
Dan Bornstein41e286c2010-11-19 12:36:19 -0800573 int flags = dexGetInstrFlags(insn->dalvikInsn.opCode);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700574
575 if ((flags & kInstrInvoke) &&
576 (insn->dalvikInsn.opCode != OP_INVOKE_DIRECT_EMPTY)) {
577 assert(numInsts == 1);
578 CallsiteInfo *callsiteInfo =
579 dvmCompilerNew(sizeof(CallsiteInfo), true);
580 callsiteInfo->clazz = currRun[1].meta;
581 callsiteInfo->method = currRun[2].meta;
582 insn->meta.callsiteInfo = callsiteInfo;
583 }
584
Ben Cheng1efc9c52009-06-08 18:25:27 -0700585 /* Instruction limit reached - terminate the trace here */
586 if (cUnit.numInsts >= numMaxInsts) {
587 break;
588 }
589 if (--numInsts == 0) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700590 if (currRun->frag.runEnd) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700591 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700592 } else {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700593 /* Advance to the next trace description (ie non-meta info) */
594 do {
595 currRun++;
596 } while (!currRun->frag.isCode);
597
598 /* Dummy end-of-run marker seen */
599 if (currRun->frag.numInsts == 0) {
600 break;
601 }
602
Bill Buzbee1465db52009-09-23 17:17:35 -0700603 curBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700604 lastBB->next = curBB;
605 lastBB = curBB;
606 curBB->id = numBlocks++;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700607 curOffset = currRun->frag.startOffset;
608 numInsts = currRun->frag.numInsts;
609 curBB->startOffset = curOffset;
610 codePtr = dexCode->insns + curOffset;
611 }
612 } else {
613 curOffset += width;
614 codePtr += width;
615 }
616 }
617
Ben Cheng1357e942010-02-10 17:21:39 -0800618#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700619 /* Convert # of half-word to bytes */
620 methodStats->compiledDalvikSize += traceSize * 2;
Ben Cheng1357e942010-02-10 17:21:39 -0800621#endif
Ben Cheng8b258bf2009-06-24 17:27:07 -0700622
Ben Chengba4fc8b2009-06-01 13:00:29 -0700623 /*
624 * Now scan basic blocks containing real code to connect the
625 * taken/fallthrough links. Also create chaining cells for code not included
626 * in the trace.
627 */
628 for (curBB = startBB; curBB; curBB = curBB->next) {
629 MIR *lastInsn = curBB->lastMIRInsn;
Ben Cheng4238ec22009-08-24 16:32:22 -0700630 /* Skip empty blocks */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700631 if (lastInsn == NULL) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700632 continue;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700633 }
634 curOffset = lastInsn->offset;
635 unsigned int targetOffset = curOffset;
636 unsigned int fallThroughOffset = curOffset + lastInsn->width;
637 bool isInvoke = false;
638 const Method *callee = NULL;
639
640 findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
641 &targetOffset, &isInvoke, &callee);
642
643 /* Link the taken and fallthrough blocks */
644 BasicBlock *searchBB;
645
Dan Bornstein41e286c2010-11-19 12:36:19 -0800646 int flags = dexGetInstrFlags(lastInsn->dalvikInsn.opCode);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700647
648 if (flags & kInstrInvoke) {
649 cUnit.hasInvoke = true;
650 }
651
Ben Chengba4fc8b2009-06-01 13:00:29 -0700652 /* No backward branch in the trace - start searching the next BB */
653 for (searchBB = curBB->next; searchBB; searchBB = searchBB->next) {
654 if (targetOffset == searchBB->startOffset) {
655 curBB->taken = searchBB;
656 }
657 if (fallThroughOffset == searchBB->startOffset) {
658 curBB->fallThrough = searchBB;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700659
660 /*
661 * Fallthrough block of an invoke instruction needs to be
662 * aligned to 4-byte boundary (alignment instruction to be
663 * inserted later.
664 */
665 if (flags & kInstrInvoke) {
666 searchBB->isFallThroughFromInvoke = true;
667 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700668 }
669 }
670
Ben Cheng1efc9c52009-06-08 18:25:27 -0700671 /*
672 * Some blocks are ended by non-control-flow-change instructions,
673 * currently only due to trace length constraint. In this case we need
674 * to generate an explicit branch at the end of the block to jump to
675 * the chaining cell.
Ben Cheng17f15ce2009-07-27 16:21:52 -0700676 *
677 * NOTE: INVOKE_DIRECT_EMPTY is actually not an invoke but a nop
Ben Cheng1efc9c52009-06-08 18:25:27 -0700678 */
679 curBB->needFallThroughBranch =
Ben Cheng17f15ce2009-07-27 16:21:52 -0700680 ((flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
681 kInstrInvoke)) == 0) ||
682 (lastInsn->dalvikInsn.opCode == OP_INVOKE_DIRECT_EMPTY);
683
Ben Cheng4a419582010-08-04 13:23:09 -0700684 /* Only form a loop if JIT_OPT_NO_LOOP is not set */
Ben Cheng4238ec22009-08-24 16:32:22 -0700685 if (curBB->taken == NULL &&
686 curBB->fallThrough == NULL &&
687 flags == (kInstrCanBranch | kInstrCanContinue) &&
Ben Cheng4a419582010-08-04 13:23:09 -0700688 fallThroughOffset == startBB->startOffset &&
689 JIT_OPT_NO_LOOP != (optHints & JIT_OPT_NO_LOOP)) {
Ben Cheng0fd31e42009-09-03 14:40:16 -0700690 BasicBlock *loopBranch = curBB;
691 BasicBlock *exitBB;
692 BasicBlock *exitChainingCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700693
694 if (cUnit.printMe) {
695 LOGD("Natural loop detected!");
696 }
Ben Cheng7a2697d2010-06-07 13:44:23 -0700697 exitBB = dvmCompilerNewBB(kTraceExitBlock);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700698 lastBB->next = exitBB;
699 lastBB = exitBB;
Ben Cheng4238ec22009-08-24 16:32:22 -0700700
Ben Cheng0fd31e42009-09-03 14:40:16 -0700701 exitBB->startOffset = targetOffset;
702 exitBB->id = numBlocks++;
703 exitBB->needFallThroughBranch = true;
Ben Cheng4238ec22009-08-24 16:32:22 -0700704
Ben Cheng0fd31e42009-09-03 14:40:16 -0700705 loopBranch->taken = exitBB;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700706#if defined(WITH_SELF_VERIFICATION)
Ben Cheng0fd31e42009-09-03 14:40:16 -0700707 BasicBlock *backwardCell =
Bill Buzbee1465db52009-09-23 17:17:35 -0700708 dvmCompilerNewBB(kChainingCellBackwardBranch);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700709 lastBB->next = backwardCell;
710 lastBB = backwardCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700711
Ben Cheng0fd31e42009-09-03 14:40:16 -0700712 backwardCell->startOffset = startBB->startOffset;
713 backwardCell->id = numBlocks++;
714 loopBranch->fallThrough = backwardCell;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700715#elif defined(WITH_JIT_TUNING)
716 if (gDvmJit.profile) {
717 BasicBlock *backwardCell =
Bill Buzbee1465db52009-09-23 17:17:35 -0700718 dvmCompilerNewBB(kChainingCellBackwardBranch);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700719 lastBB->next = backwardCell;
720 lastBB = backwardCell;
721
722 backwardCell->startOffset = startBB->startOffset;
723 backwardCell->id = numBlocks++;
724 loopBranch->fallThrough = backwardCell;
725 } else {
726 loopBranch->fallThrough = startBB->next;
727 }
728#else
729 loopBranch->fallThrough = startBB->next;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700730#endif
731
732 /* Create the chaining cell as the fallthrough of the exit block */
Bill Buzbee1465db52009-09-23 17:17:35 -0700733 exitChainingCell = dvmCompilerNewBB(kChainingCellNormal);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700734 lastBB->next = exitChainingCell;
735 lastBB = exitChainingCell;
736
737 exitChainingCell->startOffset = targetOffset;
738 exitChainingCell->id = numBlocks++;
739
740 exitBB->fallThrough = exitChainingCell;
741
Ben Cheng4238ec22009-08-24 16:32:22 -0700742 cUnit.hasLoop = true;
743 }
744
Ben Cheng6c10a972009-10-29 14:39:18 -0700745 if (lastInsn->dalvikInsn.opCode == OP_PACKED_SWITCH ||
746 lastInsn->dalvikInsn.opCode == OP_SPARSE_SWITCH) {
747 int i;
748 const u2 *switchData = desc->method->insns + lastInsn->offset +
749 lastInsn->dalvikInsn.vB;
750 int size = switchData[1];
751 int maxChains = MIN(size, MAX_CHAINED_SWITCH_CASES);
752
753 /*
754 * Generate the landing pad for cases whose ranks are higher than
755 * MAX_CHAINED_SWITCH_CASES. The code will re-enter the interpreter
756 * through the NoChain point.
757 */
758 if (maxChains != size) {
759 cUnit.switchOverflowPad =
760 desc->method->insns + lastInsn->offset;
761 }
762
763 s4 *targets = (s4 *) (switchData + 2 +
764 (lastInsn->dalvikInsn.opCode == OP_PACKED_SWITCH ?
765 2 : size * 2));
766
767 /* One chaining cell for the first MAX_CHAINED_SWITCH_CASES cases */
768 for (i = 0; i < maxChains; i++) {
769 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal);
770 lastBB->next = caseChain;
771 lastBB = caseChain;
772
773 caseChain->startOffset = lastInsn->offset + targets[i];
774 caseChain->id = numBlocks++;
775 }
776
777 /* One more chaining cell for the default case */
778 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal);
779 lastBB->next = caseChain;
780 lastBB = caseChain;
781
782 caseChain->startOffset = lastInsn->offset + lastInsn->width;
783 caseChain->id = numBlocks++;
Ben Cheng6d576092009-09-01 17:01:58 -0700784 /* Fallthrough block not included in the trace */
Ben Cheng6c10a972009-10-29 14:39:18 -0700785 } else if (!isUnconditionalBranch(lastInsn) &&
786 curBB->fallThrough == NULL) {
Ben Cheng6d576092009-09-01 17:01:58 -0700787 /*
788 * If the chaining cell is after an invoke or
789 * instruction that cannot change the control flow, request a hot
790 * chaining cell.
791 */
792 if (isInvoke || curBB->needFallThroughBranch) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700793 lastBB->next = dvmCompilerNewBB(kChainingCellHot);
Ben Cheng6d576092009-09-01 17:01:58 -0700794 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700795 lastBB->next = dvmCompilerNewBB(kChainingCellNormal);
Ben Cheng6d576092009-09-01 17:01:58 -0700796 }
797 lastBB = lastBB->next;
798 lastBB->id = numBlocks++;
799 lastBB->startOffset = fallThroughOffset;
800 curBB->fallThrough = lastBB;
801 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700802 /* Target block not included in the trace */
Ben Cheng38329f52009-07-07 14:19:20 -0700803 if (curBB->taken == NULL &&
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800804 (isGoto(lastInsn) || isInvoke ||
805 (targetOffset != UNKNOWN_TARGET && targetOffset != curOffset))) {
Ben Cheng38329f52009-07-07 14:19:20 -0700806 BasicBlock *newBB;
Ben Cheng1efc9c52009-06-08 18:25:27 -0700807 if (isInvoke) {
Ben Cheng38329f52009-07-07 14:19:20 -0700808 /* Monomorphic callee */
809 if (callee) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700810 newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton);
Ben Cheng38329f52009-07-07 14:19:20 -0700811 newBB->startOffset = 0;
812 newBB->containingMethod = callee;
813 /* Will resolve at runtime */
814 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700815 newBB = dvmCompilerNewBB(kChainingCellInvokePredicted);
Ben Cheng38329f52009-07-07 14:19:20 -0700816 newBB->startOffset = 0;
817 }
Ben Cheng1efc9c52009-06-08 18:25:27 -0700818 /* For unconditional branches, request a hot chaining cell */
819 } else {
Jeff Hao97319a82009-08-12 16:57:15 -0700820#if !defined(WITH_SELF_VERIFICATION)
Dan Bornsteinc2b486f2010-11-12 16:07:16 -0800821 newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700822 kChainingCellHot :
823 kChainingCellNormal);
Ben Cheng38329f52009-07-07 14:19:20 -0700824 newBB->startOffset = targetOffset;
Jeff Hao97319a82009-08-12 16:57:15 -0700825#else
826 /* Handle branches that branch back into the block */
827 if (targetOffset >= curBB->firstMIRInsn->offset &&
828 targetOffset <= curBB->lastMIRInsn->offset) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700829 newBB = dvmCompilerNewBB(kChainingCellBackwardBranch);
Jeff Hao97319a82009-08-12 16:57:15 -0700830 } else {
Dan Bornsteinc2b486f2010-11-12 16:07:16 -0800831 newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700832 kChainingCellHot :
833 kChainingCellNormal);
Jeff Hao97319a82009-08-12 16:57:15 -0700834 }
835 newBB->startOffset = targetOffset;
836#endif
Ben Cheng1efc9c52009-06-08 18:25:27 -0700837 }
Ben Cheng38329f52009-07-07 14:19:20 -0700838 newBB->id = numBlocks++;
839 curBB->taken = newBB;
840 lastBB->next = newBB;
841 lastBB = newBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700842 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700843 }
844
845 /* Now create a special block to host PC reconstruction code */
Bill Buzbee1465db52009-09-23 17:17:35 -0700846 lastBB->next = dvmCompilerNewBB(kPCReconstruction);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700847 lastBB = lastBB->next;
848 lastBB->id = numBlocks++;
849
850 /* And one final block that publishes the PC and raise the exception */
Bill Buzbee1465db52009-09-23 17:17:35 -0700851 lastBB->next = dvmCompilerNewBB(kExceptionHandling);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700852 lastBB = lastBB->next;
853 lastBB->id = numBlocks++;
854
855 if (cUnit.printMe) {
Elliott Hughescc6fac82010-07-02 13:38:44 -0700856 char* signature = dexProtoCopyMethodDescriptor(&desc->method->prototype);
857 LOGD("TRACEINFO (%d): 0x%08x %s%s.%s 0x%x %d of %d, %d blocks",
Ben Chenge9695e52009-06-16 16:11:47 -0700858 compilationId,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700859 (intptr_t) desc->method->insns,
860 desc->method->clazz->descriptor,
861 desc->method->name,
Elliott Hughescc6fac82010-07-02 13:38:44 -0700862 signature,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700863 desc->trace[0].frag.startOffset,
864 traceSize,
865 dexCode->insnsSize,
866 numBlocks);
Elliott Hughescc6fac82010-07-02 13:38:44 -0700867 free(signature);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700868 }
869
870 BasicBlock **blockList;
871
Ben Chengba4fc8b2009-06-01 13:00:29 -0700872 cUnit.traceDesc = desc;
873 cUnit.numBlocks = numBlocks;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700874 blockList = cUnit.blockList =
875 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
876
877 int i;
878
879 for (i = 0, curBB = startBB; i < numBlocks; i++) {
880 blockList[i] = curBB;
881 curBB = curBB->next;
882 }
883 /* Make sure all blocks are added to the cUnit */
884 assert(curBB == NULL);
885
Ben Cheng7a2697d2010-06-07 13:44:23 -0700886 /* Set the instruction set to use (NOTE: later components may change it) */
887 cUnit.instructionSet = dvmCompilerInstructionSet();
888
889 /* Inline transformation @ the MIR level */
890 if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) {
891 dvmCompilerInlineMIR(&cUnit);
892 }
893
Ben Cheng4238ec22009-08-24 16:32:22 -0700894 /* Preparation for SSA conversion */
895 dvmInitializeSSAConversion(&cUnit);
896
897 if (cUnit.hasLoop) {
Ben Cheng4a419582010-08-04 13:23:09 -0700898 /*
899 * Loop is not optimizable (for example lack of a single induction
900 * variable), punt and recompile the trace with loop optimization
901 * disabled.
902 */
903 bool loopOpt = dvmCompilerLoopOpt(&cUnit);
904 if (loopOpt == false) {
905 if (cUnit.printMe) {
906 LOGD("Loop is not optimizable - retry codegen");
907 }
908 /* Reset the compiler resource pool */
909 dvmCompilerArenaReset();
910 return dvmCompileTrace(desc, cUnit.numInsts, info, bailPtr,
911 optHints | JIT_OPT_NO_LOOP);
912 }
Ben Cheng4238ec22009-08-24 16:32:22 -0700913 }
914 else {
915 dvmCompilerNonLoopAnalysis(&cUnit);
916 }
917
Bill Buzbee1465db52009-09-23 17:17:35 -0700918 dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
919
Ben Chengba4fc8b2009-06-01 13:00:29 -0700920 if (cUnit.printMe) {
921 dvmCompilerDumpCompilationUnit(&cUnit);
922 }
923
Bill Buzbee1465db52009-09-23 17:17:35 -0700924 /* Allocate Registers */
925 dvmCompilerRegAlloc(&cUnit);
926
Ben Chengba4fc8b2009-06-01 13:00:29 -0700927 /* Convert MIR to LIR, etc. */
928 dvmCompilerMIR2LIR(&cUnit);
929
buzbeebff121a2010-08-04 15:25:06 -0700930 /* Convert LIR into machine code. Loop for recoverable retries */
931 do {
932 dvmCompilerAssembleLIR(&cUnit, info);
933 cUnit.assemblerRetries++;
934 if (cUnit.printMe && cUnit.assemblerStatus != kSuccess)
935 LOGD("Assembler abort #%d on %d",cUnit.assemblerRetries,
936 cUnit.assemblerStatus);
937 } while (cUnit.assemblerStatus == kRetryAll);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700938
939 if (cUnit.printMe) {
buzbeebff121a2010-08-04 15:25:06 -0700940 dvmCompilerCodegenDump(&cUnit);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700941 LOGD("End %s%s, %d Dalvik instructions",
942 desc->method->clazz->descriptor, desc->method->name,
943 cUnit.numInsts);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700944 }
945
946 /* Reset the compiler resource pool */
947 dvmCompilerArenaReset();
948
buzbeebff121a2010-08-04 15:25:06 -0700949 if (cUnit.assemblerStatus == kRetryHalve) {
950 /* Halve the instruction count and start from the top */
Ben Cheng4a419582010-08-04 13:23:09 -0700951 return dvmCompileTrace(desc, cUnit.numInsts / 2, info, bailPtr,
952 optHints);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700953 }
buzbeebff121a2010-08-04 15:25:06 -0700954
955 assert(cUnit.assemblerStatus == kSuccess);
956#if defined(WITH_JIT_TUNING)
957 methodStats->nativeSize += cUnit.totalSize;
958#endif
959 return info->codeAddress != NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700960}
961
962/*
Ben Cheng7a2697d2010-06-07 13:44:23 -0700963 * Since we are including instructions from possibly a cold method into the
964 * current trace, we need to make sure that all the associated information
965 * with the callee is properly initialized. If not, we punt on this inline
966 * target.
967 *
Ben Cheng34dc7962010-08-26 14:56:31 -0700968 * TODO: volatile instructions will be handled later.
Ben Cheng7a2697d2010-06-07 13:44:23 -0700969 */
970bool dvmCompilerCanIncludeThisInstruction(const Method *method,
971 const DecodedInstruction *insn)
972{
973 switch (insn->opCode) {
974 case OP_NEW_INSTANCE:
975 case OP_CHECK_CAST: {
976 ClassObject *classPtr = (void*)
977 (method->clazz->pDvmDex->pResClasses[insn->vB]);
978
979 /* Class hasn't been initialized yet */
980 if (classPtr == NULL) {
981 return false;
982 }
983 return true;
984 }
985 case OP_SGET_OBJECT:
986 case OP_SGET_BOOLEAN:
987 case OP_SGET_CHAR:
988 case OP_SGET_BYTE:
989 case OP_SGET_SHORT:
990 case OP_SGET:
991 case OP_SGET_WIDE:
992 case OP_SPUT_OBJECT:
993 case OP_SPUT_BOOLEAN:
994 case OP_SPUT_CHAR:
995 case OP_SPUT_BYTE:
996 case OP_SPUT_SHORT:
997 case OP_SPUT:
998 case OP_SPUT_WIDE: {
999 void *fieldPtr = (void*)
1000 (method->clazz->pDvmDex->pResFields[insn->vB]);
1001
1002 if (fieldPtr == NULL) {
1003 return false;
1004 }
1005 return true;
1006 }
1007 case OP_INVOKE_SUPER:
1008 case OP_INVOKE_SUPER_RANGE: {
1009 int mIndex = method->clazz->pDvmDex->
1010 pResMethods[insn->vB]->methodIndex;
1011 const Method *calleeMethod = method->clazz->super->vtable[mIndex];
1012 if (calleeMethod == NULL) {
1013 return false;
1014 }
1015 return true;
1016 }
1017 case OP_INVOKE_SUPER_QUICK:
1018 case OP_INVOKE_SUPER_QUICK_RANGE: {
1019 const Method *calleeMethod = method->clazz->super->vtable[insn->vB];
1020 if (calleeMethod == NULL) {
1021 return false;
1022 }
1023 return true;
1024 }
1025 case OP_INVOKE_STATIC:
1026 case OP_INVOKE_STATIC_RANGE:
1027 case OP_INVOKE_DIRECT:
1028 case OP_INVOKE_DIRECT_RANGE: {
1029 const Method *calleeMethod =
1030 method->clazz->pDvmDex->pResMethods[insn->vB];
1031 if (calleeMethod == NULL) {
1032 return false;
1033 }
1034 return true;
1035 }
1036 case OP_CONST_CLASS: {
1037 void *classPtr = (void*)
1038 (method->clazz->pDvmDex->pResClasses[insn->vB]);
1039
1040 if (classPtr == NULL) {
1041 return false;
1042 }
1043 return true;
1044 }
1045 case OP_CONST_STRING_JUMBO:
1046 case OP_CONST_STRING: {
1047 void *strPtr = (void*)
1048 (method->clazz->pDvmDex->pResStrings[insn->vB]);
1049
1050 if (strPtr == NULL) {
1051 return false;
1052 }
1053 return true;
1054 }
1055 default:
1056 return true;
1057 }
1058}
1059
1060/*
Ben Chengba4fc8b2009-06-01 13:00:29 -07001061 * Similar to dvmCompileTrace, but the entity processed here is the whole
1062 * method.
1063 *
1064 * TODO: implementation will be revisited when the trace builder can provide
1065 * whole-method traces.
1066 */
Ben Cheng7a2697d2010-06-07 13:44:23 -07001067bool dvmCompileMethod(CompilationUnit *cUnit, const Method *method,
1068 JitTranslationInfo *info)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001069{
1070 const DexCode *dexCode = dvmGetMethodCode(method);
1071 const u2 *codePtr = dexCode->insns;
1072 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
1073 int blockID = 0;
1074 unsigned int curOffset = 0;
1075
Ben Cheng7a2697d2010-06-07 13:44:23 -07001076 /* If we've already compiled this trace, just return success */
1077 if (dvmJitGetCodeAddr(codePtr) && !info->discardResult) {
1078 return true;
1079 }
1080
1081 /* Doing method-based compilation */
1082 cUnit->wholeMethod = true;
1083
Bill Buzbee1465db52009-09-23 17:17:35 -07001084 BasicBlock *firstBlock = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001085 firstBlock->id = blockID++;
1086
1087 /* Allocate the bit-vector to track the beginning of basic blocks */
Ben Cheng4238ec22009-08-24 16:32:22 -07001088 BitVector *bbStartAddr = dvmCompilerAllocBitVector(dexCode->insnsSize+1,
1089 false);
1090 dvmCompilerSetBit(bbStartAddr, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001091
Ben Cheng7a2697d2010-06-07 13:44:23 -07001092 int numInvokeTargets = 0;
1093
Ben Chengba4fc8b2009-06-01 13:00:29 -07001094 /*
1095 * Sequentially go through every instruction first and put them in a single
1096 * basic block. Identify block boundaries at the mean time.
1097 */
1098 while (codePtr < codeEnd) {
Ben Cheng4238ec22009-08-24 16:32:22 -07001099 MIR *insn = dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001100 insn->offset = curOffset;
1101 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
1102 bool isInvoke = false;
1103 const Method *callee;
1104 insn->width = width;
1105
Ben Cheng8b258bf2009-06-24 17:27:07 -07001106 /* Terminate when the data section is seen */
1107 if (width == 0)
1108 break;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001109
1110 if (!dvmCompilerCanIncludeThisInstruction(cUnit->method,
1111 &insn->dalvikInsn)) {
1112 return false;
1113 }
1114
Ben Chengba4fc8b2009-06-01 13:00:29 -07001115 dvmCompilerAppendMIR(firstBlock, insn);
1116 /*
1117 * Check whether this is a block ending instruction and whether it
1118 * suggests the start of a new block
1119 */
1120 unsigned int target = curOffset;
1121
1122 /*
1123 * If findBlockBoundary returns true, it means the current instruction
1124 * is terminating the current block. If it is a branch, the target
1125 * address will be recorded in target.
1126 */
1127 if (findBlockBoundary(method, insn, curOffset, &target, &isInvoke,
1128 &callee)) {
Ben Cheng4238ec22009-08-24 16:32:22 -07001129 dvmCompilerSetBit(bbStartAddr, curOffset + width);
Ben Cheng7a2697d2010-06-07 13:44:23 -07001130 /* Each invoke needs a chaining cell block */
1131 if (isInvoke) {
1132 numInvokeTargets++;
1133 }
1134 /* A branch will end the current block */
1135 else if (target != curOffset && target != UNKNOWN_TARGET) {
Ben Cheng4238ec22009-08-24 16:32:22 -07001136 dvmCompilerSetBit(bbStartAddr, target);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001137 }
1138 }
1139
1140 codePtr += width;
1141 /* each bit represents 16-bit quantity */
1142 curOffset += width;
1143 }
1144
1145 /*
1146 * The number of blocks will be equal to the number of bits set to 1 in the
1147 * bit vector minus 1, because the bit representing the location after the
1148 * last instruction is set to one.
Ben Cheng7a2697d2010-06-07 13:44:23 -07001149 *
1150 * We also add additional blocks for invoke chaining and the number is
1151 * denoted by numInvokeTargets.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001152 */
1153 int numBlocks = dvmCountSetBits(bbStartAddr);
1154 if (dvmIsBitSet(bbStartAddr, dexCode->insnsSize)) {
1155 numBlocks--;
1156 }
1157
Ben Chengba4fc8b2009-06-01 13:00:29 -07001158 BasicBlock **blockList;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001159 blockList = cUnit->blockList =
1160 dvmCompilerNew(sizeof(BasicBlock *) * (numBlocks + numInvokeTargets),
1161 true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001162
1163 /*
Ben Cheng7a2697d2010-06-07 13:44:23 -07001164 * Register the first block onto the list and start splitting it into
1165 * sub-blocks.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001166 */
1167 blockList[0] = firstBlock;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001168 cUnit->numBlocks = 1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001169
1170 int i;
1171 for (i = 0; i < numBlocks; i++) {
1172 MIR *insn;
1173 BasicBlock *curBB = blockList[i];
1174 curOffset = curBB->lastMIRInsn->offset;
1175
1176 for (insn = curBB->firstMIRInsn->next; insn; insn = insn->next) {
1177 /* Found the beginning of a new block, see if it is created yet */
1178 if (dvmIsBitSet(bbStartAddr, insn->offset)) {
1179 int j;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001180 for (j = 0; j < cUnit->numBlocks; j++) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07001181 if (blockList[j]->firstMIRInsn->offset == insn->offset)
1182 break;
1183 }
1184
1185 /* Block not split yet - do it now */
Ben Cheng7a2697d2010-06-07 13:44:23 -07001186 if (j == cUnit->numBlocks) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001187 BasicBlock *newBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001188 newBB->id = blockID++;
1189 newBB->firstMIRInsn = insn;
Ben Cheng8b258bf2009-06-24 17:27:07 -07001190 newBB->startOffset = insn->offset;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001191 newBB->lastMIRInsn = curBB->lastMIRInsn;
1192 curBB->lastMIRInsn = insn->prev;
1193 insn->prev->next = NULL;
1194 insn->prev = NULL;
1195
1196 /*
1197 * If the insn is not an unconditional branch, set up the
1198 * fallthrough link.
1199 */
1200 if (!isUnconditionalBranch(curBB->lastMIRInsn)) {
1201 curBB->fallThrough = newBB;
1202 }
1203
Ben Cheng7a2697d2010-06-07 13:44:23 -07001204 /*
1205 * Fallthrough block of an invoke instruction needs to be
1206 * aligned to 4-byte boundary (alignment instruction to be
1207 * inserted later.
1208 */
Dan Bornstein41e286c2010-11-19 12:36:19 -08001209 if (dexGetInstrFlags(curBB->lastMIRInsn->dalvikInsn.opCode)
1210 & kInstrInvoke) {
Ben Cheng7a2697d2010-06-07 13:44:23 -07001211 newBB->isFallThroughFromInvoke = true;
1212 }
1213
Ben Chengba4fc8b2009-06-01 13:00:29 -07001214 /* enqueue the new block */
Ben Cheng7a2697d2010-06-07 13:44:23 -07001215 blockList[cUnit->numBlocks++] = newBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001216 break;
1217 }
1218 }
1219 }
1220 }
1221
Ben Cheng7a2697d2010-06-07 13:44:23 -07001222 if (numBlocks != cUnit->numBlocks) {
1223 LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit->numBlocks);
1224 dvmCompilerAbort(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001225 }
1226
Ben Chengba4fc8b2009-06-01 13:00:29 -07001227 /* Connect the basic blocks through the taken links */
1228 for (i = 0; i < numBlocks; i++) {
1229 BasicBlock *curBB = blockList[i];
1230 MIR *insn = curBB->lastMIRInsn;
1231 unsigned int target = insn->offset;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001232 bool isInvoke = false;
1233 const Method *callee = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001234
1235 findBlockBoundary(method, insn, target, &target, &isInvoke, &callee);
1236
Ben Cheng7a2697d2010-06-07 13:44:23 -07001237 /* Found a block ended on a branch (not invoke) */
1238 if (isInvoke == false && target != insn->offset) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07001239 int j;
1240 /* Forward branch */
1241 if (target > insn->offset) {
1242 j = i + 1;
1243 } else {
1244 /* Backward branch */
1245 j = 0;
1246 }
1247 for (; j < numBlocks; j++) {
1248 if (blockList[j]->firstMIRInsn->offset == target) {
1249 curBB->taken = blockList[j];
1250 break;
1251 }
1252 }
Ben Cheng7a2697d2010-06-07 13:44:23 -07001253 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001254
Ben Cheng7a2697d2010-06-07 13:44:23 -07001255 if (isInvoke) {
1256 BasicBlock *newBB;
1257 /* Monomorphic callee */
1258 if (callee) {
1259 newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton);
1260 newBB->startOffset = 0;
1261 newBB->containingMethod = callee;
1262 /* Will resolve at runtime */
1263 } else {
1264 newBB = dvmCompilerNewBB(kChainingCellInvokePredicted);
1265 newBB->startOffset = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001266 }
Ben Cheng7a2697d2010-06-07 13:44:23 -07001267 newBB->id = blockID++;
1268 curBB->taken = newBB;
1269 /* enqueue the new block */
1270 blockList[cUnit->numBlocks++] = newBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001271 }
1272 }
1273
Ben Cheng7a2697d2010-06-07 13:44:23 -07001274 if (cUnit->numBlocks != numBlocks + numInvokeTargets) {
1275 LOGE("Expect %d vs %d total blocks\n", numBlocks + numInvokeTargets,
1276 cUnit->numBlocks);
1277 dvmCompilerDumpCompilationUnit(cUnit);
1278 dvmCompilerAbort(cUnit);
1279 }
1280
Bill Buzbee716f1202009-07-23 13:22:09 -07001281 /* Set the instruction set to use (NOTE: later components may change it) */
Ben Cheng7a2697d2010-06-07 13:44:23 -07001282 cUnit->instructionSet = dvmCompilerInstructionSet();
Bill Buzbee716f1202009-07-23 13:22:09 -07001283
Ben Cheng7a2697d2010-06-07 13:44:23 -07001284 /* Preparation for SSA conversion */
1285 dvmInitializeSSAConversion(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001286
Ben Cheng7a2697d2010-06-07 13:44:23 -07001287 /* SSA analysis */
1288 dvmCompilerNonLoopAnalysis(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001289
Ben Cheng7a2697d2010-06-07 13:44:23 -07001290 /* Needs to happen after SSA naming */
1291 dvmCompilerInitializeRegAlloc(cUnit);
1292
1293 /* Allocate Registers */
1294 dvmCompilerRegAlloc(cUnit);
1295
1296 /* Convert MIR to LIR, etc. */
1297 dvmCompilerMIR2LIR(cUnit);
1298
1299 /* Convert LIR into machine code. */
1300 dvmCompilerAssembleLIR(cUnit, info);
1301
buzbeebff121a2010-08-04 15:25:06 -07001302 if (cUnit->assemblerStatus != kSuccess) {
Ben Cheng7a2697d2010-06-07 13:44:23 -07001303 return false;
1304 }
1305
1306 dvmCompilerDumpCompilationUnit(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001307
1308 dvmCompilerArenaReset();
1309
Bill Buzbee716f1202009-07-23 13:22:09 -07001310 return info->codeAddress != NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001311}