blob: 8e5a5e2168c91366a533f97a2b50a8589cf83761 [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,
Ben Cheng4a419582010-08-04 13:23:09 -0700402 JitTranslationInfo *info, jmp_buf *bailPtr,
403 int optHints)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700404{
405 const DexCode *dexCode = dvmGetMethodCode(desc->method);
406 const JitTraceRun* currRun = &desc->trace[0];
Ben Chengba4fc8b2009-06-01 13:00:29 -0700407 unsigned int curOffset = currRun->frag.startOffset;
408 unsigned int numInsts = currRun->frag.numInsts;
409 const u2 *codePtr = dexCode->insns + curOffset;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700410 int traceSize = 0; // # of half-words
Ben Chengba4fc8b2009-06-01 13:00:29 -0700411 const u2 *startCodePtr = codePtr;
412 BasicBlock *startBB, *curBB, *lastBB;
413 int numBlocks = 0;
414 static int compilationId;
415 CompilationUnit cUnit;
Ben Cheng1357e942010-02-10 17:21:39 -0800416#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700417 CompilerMethodStats *methodStats;
Ben Cheng1357e942010-02-10 17:21:39 -0800418#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700419
Bill Buzbee964a7b02010-01-28 12:54:19 -0800420 /* If we've already compiled this trace, just return success */
jeffhao9e45c0b2010-02-03 10:24:05 -0800421 if (dvmJitGetCodeAddr(startCodePtr) && !info->discardResult) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700422 /*
423 * Make sure the codeAddress is NULL so that it won't clobber the
424 * existing entry.
425 */
426 info->codeAddress = NULL;
Bill Buzbee964a7b02010-01-28 12:54:19 -0800427 return true;
428 }
429
Ben Chenge9695e52009-06-16 16:11:47 -0700430 compilationId++;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700431 memset(&cUnit, 0, sizeof(CompilationUnit));
432
Ben Cheng1357e942010-02-10 17:21:39 -0800433#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700434 /* Locate the entry to store compilation statistics for this method */
Ben Cheng7a2697d2010-06-07 13:44:23 -0700435 methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
Ben Cheng1357e942010-02-10 17:21:39 -0800436#endif
Ben Chenge9695e52009-06-16 16:11:47 -0700437
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800438 /* Set the recover buffer pointer */
439 cUnit.bailPtr = bailPtr;
440
Ben Chengba4fc8b2009-06-01 13:00:29 -0700441 /* Initialize the printMe flag */
442 cUnit.printMe = gDvmJit.printMe;
443
Bill Buzbee6e963e12009-06-17 16:56:19 -0700444 /* Initialize the profile flag */
445 cUnit.executionCount = gDvmJit.profile;
446
Ben Cheng7a2697d2010-06-07 13:44:23 -0700447 /* Setup the method */
448 cUnit.method = desc->method;
449
450 /* Initialize the PC reconstruction list */
451 dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
452
Ben Chengba4fc8b2009-06-01 13:00:29 -0700453 /* Identify traces that we don't want to compile */
454 if (gDvmJit.methodTable) {
455 int len = strlen(desc->method->clazz->descriptor) +
456 strlen(desc->method->name) + 1;
457 char *fullSignature = dvmCompilerNew(len, true);
458 strcpy(fullSignature, desc->method->clazz->descriptor);
459 strcat(fullSignature, desc->method->name);
460
461 int hashValue = dvmComputeUtf8Hash(fullSignature);
462
463 /*
464 * Doing three levels of screening to see whether we want to skip
465 * compiling this method
466 */
467
468 /* First, check the full "class;method" signature */
469 bool methodFound =
470 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
471 fullSignature, (HashCompareFunc) strcmp,
472 false) !=
473 NULL;
474
475 /* Full signature not found - check the enclosing class */
476 if (methodFound == false) {
477 int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
478 methodFound =
479 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
480 (char *) desc->method->clazz->descriptor,
481 (HashCompareFunc) strcmp, false) !=
482 NULL;
483 /* Enclosing class not found - check the method name */
484 if (methodFound == false) {
485 int hashValue = dvmComputeUtf8Hash(desc->method->name);
486 methodFound =
487 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
488 (char *) desc->method->name,
489 (HashCompareFunc) strcmp, false) !=
490 NULL;
Ben Cheng33672452010-01-12 14:59:30 -0800491
492 /*
493 * Debug by call-graph is enabled. Check if the debug list
494 * covers any methods on the VM stack.
495 */
496 if (methodFound == false && gDvmJit.checkCallGraph == true) {
497 methodFound =
498 filterMethodByCallGraph(info->requestingThread,
499 desc->method->name);
500 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700501 }
502 }
503
504 /*
505 * Under the following conditions, the trace will be *conservatively*
506 * compiled by only containing single-step instructions to and from the
507 * interpreter.
508 * 1) If includeSelectedMethod == false, the method matches the full or
509 * partial signature stored in the hash table.
510 *
511 * 2) If includeSelectedMethod == true, the method does not match the
512 * full and partial signature stored in the hash table.
513 */
514 if (gDvmJit.includeSelectedMethod != methodFound) {
515 cUnit.allSingleStep = true;
516 } else {
517 /* Compile the trace as normal */
518
519 /* Print the method we cherry picked */
520 if (gDvmJit.includeSelectedMethod == true) {
521 cUnit.printMe = true;
522 }
523 }
524 }
525
Ben Cheng4238ec22009-08-24 16:32:22 -0700526 /* Allocate the entry block */
Ben Cheng7a2697d2010-06-07 13:44:23 -0700527 lastBB = startBB = curBB = dvmCompilerNewBB(kTraceEntryBlock);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700528 curBB->startOffset = curOffset;
529 curBB->id = numBlocks++;
530
Bill Buzbee1465db52009-09-23 17:17:35 -0700531 curBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Cheng4238ec22009-08-24 16:32:22 -0700532 curBB->startOffset = curOffset;
533 curBB->id = numBlocks++;
534
535 /* Make the first real dalvik block the fallthrough of the entry block */
536 startBB->fallThrough = curBB;
537 lastBB->next = curBB;
538 lastBB = curBB;
539
Ben Chengba4fc8b2009-06-01 13:00:29 -0700540 if (cUnit.printMe) {
541 LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n",
542 desc->method->name, curOffset);
543 }
544
Ben Cheng1efc9c52009-06-08 18:25:27 -0700545 /*
546 * Analyze the trace descriptor and include up to the maximal number
547 * of Dalvik instructions into the IR.
548 */
549 while (1) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700550 MIR *insn;
551 int width;
Ben Cheng4238ec22009-08-24 16:32:22 -0700552 insn = dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700553 insn->offset = curOffset;
554 width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700555
556 /* The trace should never incude instruction data */
557 assert(width);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700558 insn->width = width;
559 traceSize += width;
560 dvmCompilerAppendMIR(curBB, insn);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700561 cUnit.numInsts++;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700562
563 int flags = dexGetInstrFlags(gDvm.instrFlags, insn->dalvikInsn.opCode);
564
565 if ((flags & kInstrInvoke) &&
566 (insn->dalvikInsn.opCode != OP_INVOKE_DIRECT_EMPTY)) {
567 assert(numInsts == 1);
568 CallsiteInfo *callsiteInfo =
569 dvmCompilerNew(sizeof(CallsiteInfo), true);
570 callsiteInfo->clazz = currRun[1].meta;
571 callsiteInfo->method = currRun[2].meta;
572 insn->meta.callsiteInfo = callsiteInfo;
573 }
574
Ben Cheng1efc9c52009-06-08 18:25:27 -0700575 /* Instruction limit reached - terminate the trace here */
576 if (cUnit.numInsts >= numMaxInsts) {
577 break;
578 }
579 if (--numInsts == 0) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700580 if (currRun->frag.runEnd) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700581 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700582 } else {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700583 /* Advance to the next trace description (ie non-meta info) */
584 do {
585 currRun++;
586 } while (!currRun->frag.isCode);
587
588 /* Dummy end-of-run marker seen */
589 if (currRun->frag.numInsts == 0) {
590 break;
591 }
592
Bill Buzbee1465db52009-09-23 17:17:35 -0700593 curBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700594 lastBB->next = curBB;
595 lastBB = curBB;
596 curBB->id = numBlocks++;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700597 curOffset = currRun->frag.startOffset;
598 numInsts = currRun->frag.numInsts;
599 curBB->startOffset = curOffset;
600 codePtr = dexCode->insns + curOffset;
601 }
602 } else {
603 curOffset += width;
604 codePtr += width;
605 }
606 }
607
Ben Cheng1357e942010-02-10 17:21:39 -0800608#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700609 /* Convert # of half-word to bytes */
610 methodStats->compiledDalvikSize += traceSize * 2;
Ben Cheng1357e942010-02-10 17:21:39 -0800611#endif
Ben Cheng8b258bf2009-06-24 17:27:07 -0700612
Ben Chengba4fc8b2009-06-01 13:00:29 -0700613 /*
614 * Now scan basic blocks containing real code to connect the
615 * taken/fallthrough links. Also create chaining cells for code not included
616 * in the trace.
617 */
618 for (curBB = startBB; curBB; curBB = curBB->next) {
619 MIR *lastInsn = curBB->lastMIRInsn;
Ben Cheng4238ec22009-08-24 16:32:22 -0700620 /* Skip empty blocks */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700621 if (lastInsn == NULL) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700622 continue;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700623 }
624 curOffset = lastInsn->offset;
625 unsigned int targetOffset = curOffset;
626 unsigned int fallThroughOffset = curOffset + lastInsn->width;
627 bool isInvoke = false;
628 const Method *callee = NULL;
629
630 findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
631 &targetOffset, &isInvoke, &callee);
632
633 /* Link the taken and fallthrough blocks */
634 BasicBlock *searchBB;
635
Ben Cheng7a2697d2010-06-07 13:44:23 -0700636 int flags = dexGetInstrFlags(gDvm.instrFlags,
637 lastInsn->dalvikInsn.opCode);
638
639 if (flags & kInstrInvoke) {
640 cUnit.hasInvoke = true;
641 }
642
Ben Chengba4fc8b2009-06-01 13:00:29 -0700643 /* No backward branch in the trace - start searching the next BB */
644 for (searchBB = curBB->next; searchBB; searchBB = searchBB->next) {
645 if (targetOffset == searchBB->startOffset) {
646 curBB->taken = searchBB;
647 }
648 if (fallThroughOffset == searchBB->startOffset) {
649 curBB->fallThrough = searchBB;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700650
651 /*
652 * Fallthrough block of an invoke instruction needs to be
653 * aligned to 4-byte boundary (alignment instruction to be
654 * inserted later.
655 */
656 if (flags & kInstrInvoke) {
657 searchBB->isFallThroughFromInvoke = true;
658 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700659 }
660 }
661
Ben Cheng1efc9c52009-06-08 18:25:27 -0700662 /*
663 * Some blocks are ended by non-control-flow-change instructions,
664 * currently only due to trace length constraint. In this case we need
665 * to generate an explicit branch at the end of the block to jump to
666 * the chaining cell.
Ben Cheng17f15ce2009-07-27 16:21:52 -0700667 *
668 * NOTE: INVOKE_DIRECT_EMPTY is actually not an invoke but a nop
Ben Cheng1efc9c52009-06-08 18:25:27 -0700669 */
670 curBB->needFallThroughBranch =
Ben Cheng17f15ce2009-07-27 16:21:52 -0700671 ((flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
672 kInstrInvoke)) == 0) ||
673 (lastInsn->dalvikInsn.opCode == OP_INVOKE_DIRECT_EMPTY);
674
Ben Cheng4a419582010-08-04 13:23:09 -0700675 /* Only form a loop if JIT_OPT_NO_LOOP is not set */
Ben Cheng4238ec22009-08-24 16:32:22 -0700676 if (curBB->taken == NULL &&
677 curBB->fallThrough == NULL &&
678 flags == (kInstrCanBranch | kInstrCanContinue) &&
Ben Cheng4a419582010-08-04 13:23:09 -0700679 fallThroughOffset == startBB->startOffset &&
680 JIT_OPT_NO_LOOP != (optHints & JIT_OPT_NO_LOOP)) {
Ben Cheng0fd31e42009-09-03 14:40:16 -0700681 BasicBlock *loopBranch = curBB;
682 BasicBlock *exitBB;
683 BasicBlock *exitChainingCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700684
685 if (cUnit.printMe) {
686 LOGD("Natural loop detected!");
687 }
Ben Cheng7a2697d2010-06-07 13:44:23 -0700688 exitBB = dvmCompilerNewBB(kTraceExitBlock);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700689 lastBB->next = exitBB;
690 lastBB = exitBB;
Ben Cheng4238ec22009-08-24 16:32:22 -0700691
Ben Cheng0fd31e42009-09-03 14:40:16 -0700692 exitBB->startOffset = targetOffset;
693 exitBB->id = numBlocks++;
694 exitBB->needFallThroughBranch = true;
Ben Cheng4238ec22009-08-24 16:32:22 -0700695
Ben Cheng0fd31e42009-09-03 14:40:16 -0700696 loopBranch->taken = exitBB;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700697#if defined(WITH_SELF_VERIFICATION)
Ben Cheng0fd31e42009-09-03 14:40:16 -0700698 BasicBlock *backwardCell =
Bill Buzbee1465db52009-09-23 17:17:35 -0700699 dvmCompilerNewBB(kChainingCellBackwardBranch);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700700 lastBB->next = backwardCell;
701 lastBB = backwardCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700702
Ben Cheng0fd31e42009-09-03 14:40:16 -0700703 backwardCell->startOffset = startBB->startOffset;
704 backwardCell->id = numBlocks++;
705 loopBranch->fallThrough = backwardCell;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700706#elif defined(WITH_JIT_TUNING)
707 if (gDvmJit.profile) {
708 BasicBlock *backwardCell =
Bill Buzbee1465db52009-09-23 17:17:35 -0700709 dvmCompilerNewBB(kChainingCellBackwardBranch);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700710 lastBB->next = backwardCell;
711 lastBB = backwardCell;
712
713 backwardCell->startOffset = startBB->startOffset;
714 backwardCell->id = numBlocks++;
715 loopBranch->fallThrough = backwardCell;
716 } else {
717 loopBranch->fallThrough = startBB->next;
718 }
719#else
720 loopBranch->fallThrough = startBB->next;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700721#endif
722
723 /* Create the chaining cell as the fallthrough of the exit block */
Bill Buzbee1465db52009-09-23 17:17:35 -0700724 exitChainingCell = dvmCompilerNewBB(kChainingCellNormal);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700725 lastBB->next = exitChainingCell;
726 lastBB = exitChainingCell;
727
728 exitChainingCell->startOffset = targetOffset;
729 exitChainingCell->id = numBlocks++;
730
731 exitBB->fallThrough = exitChainingCell;
732
Ben Cheng4238ec22009-08-24 16:32:22 -0700733 cUnit.hasLoop = true;
734 }
735
Ben Cheng6c10a972009-10-29 14:39:18 -0700736 if (lastInsn->dalvikInsn.opCode == OP_PACKED_SWITCH ||
737 lastInsn->dalvikInsn.opCode == OP_SPARSE_SWITCH) {
738 int i;
739 const u2 *switchData = desc->method->insns + lastInsn->offset +
740 lastInsn->dalvikInsn.vB;
741 int size = switchData[1];
742 int maxChains = MIN(size, MAX_CHAINED_SWITCH_CASES);
743
744 /*
745 * Generate the landing pad for cases whose ranks are higher than
746 * MAX_CHAINED_SWITCH_CASES. The code will re-enter the interpreter
747 * through the NoChain point.
748 */
749 if (maxChains != size) {
750 cUnit.switchOverflowPad =
751 desc->method->insns + lastInsn->offset;
752 }
753
754 s4 *targets = (s4 *) (switchData + 2 +
755 (lastInsn->dalvikInsn.opCode == OP_PACKED_SWITCH ?
756 2 : size * 2));
757
758 /* One chaining cell for the first MAX_CHAINED_SWITCH_CASES cases */
759 for (i = 0; i < maxChains; i++) {
760 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal);
761 lastBB->next = caseChain;
762 lastBB = caseChain;
763
764 caseChain->startOffset = lastInsn->offset + targets[i];
765 caseChain->id = numBlocks++;
766 }
767
768 /* One more chaining cell for the default case */
769 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal);
770 lastBB->next = caseChain;
771 lastBB = caseChain;
772
773 caseChain->startOffset = lastInsn->offset + lastInsn->width;
774 caseChain->id = numBlocks++;
Ben Cheng6d576092009-09-01 17:01:58 -0700775 /* Fallthrough block not included in the trace */
Ben Cheng6c10a972009-10-29 14:39:18 -0700776 } else if (!isUnconditionalBranch(lastInsn) &&
777 curBB->fallThrough == NULL) {
Ben Cheng6d576092009-09-01 17:01:58 -0700778 /*
779 * If the chaining cell is after an invoke or
780 * instruction that cannot change the control flow, request a hot
781 * chaining cell.
782 */
783 if (isInvoke || curBB->needFallThroughBranch) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700784 lastBB->next = dvmCompilerNewBB(kChainingCellHot);
Ben Cheng6d576092009-09-01 17:01:58 -0700785 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700786 lastBB->next = dvmCompilerNewBB(kChainingCellNormal);
Ben Cheng6d576092009-09-01 17:01:58 -0700787 }
788 lastBB = lastBB->next;
789 lastBB->id = numBlocks++;
790 lastBB->startOffset = fallThroughOffset;
791 curBB->fallThrough = lastBB;
792 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700793 /* Target block not included in the trace */
Ben Cheng38329f52009-07-07 14:19:20 -0700794 if (curBB->taken == NULL &&
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800795 (isGoto(lastInsn) || isInvoke ||
796 (targetOffset != UNKNOWN_TARGET && targetOffset != curOffset))) {
Ben Cheng38329f52009-07-07 14:19:20 -0700797 BasicBlock *newBB;
Ben Cheng1efc9c52009-06-08 18:25:27 -0700798 if (isInvoke) {
Ben Cheng38329f52009-07-07 14:19:20 -0700799 /* Monomorphic callee */
800 if (callee) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700801 newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton);
Ben Cheng38329f52009-07-07 14:19:20 -0700802 newBB->startOffset = 0;
803 newBB->containingMethod = callee;
804 /* Will resolve at runtime */
805 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700806 newBB = dvmCompilerNewBB(kChainingCellInvokePredicted);
Ben Cheng38329f52009-07-07 14:19:20 -0700807 newBB->startOffset = 0;
808 }
Ben Cheng1efc9c52009-06-08 18:25:27 -0700809 /* For unconditional branches, request a hot chaining cell */
810 } else {
Jeff Hao97319a82009-08-12 16:57:15 -0700811#if !defined(WITH_SELF_VERIFICATION)
Ben Cheng38329f52009-07-07 14:19:20 -0700812 newBB = dvmCompilerNewBB(flags & kInstrUnconditional ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700813 kChainingCellHot :
814 kChainingCellNormal);
Ben Cheng38329f52009-07-07 14:19:20 -0700815 newBB->startOffset = targetOffset;
Jeff Hao97319a82009-08-12 16:57:15 -0700816#else
817 /* Handle branches that branch back into the block */
818 if (targetOffset >= curBB->firstMIRInsn->offset &&
819 targetOffset <= curBB->lastMIRInsn->offset) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700820 newBB = dvmCompilerNewBB(kChainingCellBackwardBranch);
Jeff Hao97319a82009-08-12 16:57:15 -0700821 } else {
822 newBB = dvmCompilerNewBB(flags & kInstrUnconditional ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700823 kChainingCellHot :
824 kChainingCellNormal);
Jeff Hao97319a82009-08-12 16:57:15 -0700825 }
826 newBB->startOffset = targetOffset;
827#endif
Ben Cheng1efc9c52009-06-08 18:25:27 -0700828 }
Ben Cheng38329f52009-07-07 14:19:20 -0700829 newBB->id = numBlocks++;
830 curBB->taken = newBB;
831 lastBB->next = newBB;
832 lastBB = newBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700833 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700834 }
835
836 /* Now create a special block to host PC reconstruction code */
Bill Buzbee1465db52009-09-23 17:17:35 -0700837 lastBB->next = dvmCompilerNewBB(kPCReconstruction);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700838 lastBB = lastBB->next;
839 lastBB->id = numBlocks++;
840
841 /* And one final block that publishes the PC and raise the exception */
Bill Buzbee1465db52009-09-23 17:17:35 -0700842 lastBB->next = dvmCompilerNewBB(kExceptionHandling);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700843 lastBB = lastBB->next;
844 lastBB->id = numBlocks++;
845
846 if (cUnit.printMe) {
Elliott Hughescc6fac82010-07-02 13:38:44 -0700847 char* signature = dexProtoCopyMethodDescriptor(&desc->method->prototype);
848 LOGD("TRACEINFO (%d): 0x%08x %s%s.%s 0x%x %d of %d, %d blocks",
Ben Chenge9695e52009-06-16 16:11:47 -0700849 compilationId,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700850 (intptr_t) desc->method->insns,
851 desc->method->clazz->descriptor,
852 desc->method->name,
Elliott Hughescc6fac82010-07-02 13:38:44 -0700853 signature,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700854 desc->trace[0].frag.startOffset,
855 traceSize,
856 dexCode->insnsSize,
857 numBlocks);
Elliott Hughescc6fac82010-07-02 13:38:44 -0700858 free(signature);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700859 }
860
861 BasicBlock **blockList;
862
Ben Chengba4fc8b2009-06-01 13:00:29 -0700863 cUnit.traceDesc = desc;
864 cUnit.numBlocks = numBlocks;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700865 blockList = cUnit.blockList =
866 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
867
868 int i;
869
870 for (i = 0, curBB = startBB; i < numBlocks; i++) {
871 blockList[i] = curBB;
872 curBB = curBB->next;
873 }
874 /* Make sure all blocks are added to the cUnit */
875 assert(curBB == NULL);
876
Ben Cheng7a2697d2010-06-07 13:44:23 -0700877 /* Set the instruction set to use (NOTE: later components may change it) */
878 cUnit.instructionSet = dvmCompilerInstructionSet();
879
880 /* Inline transformation @ the MIR level */
881 if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) {
882 dvmCompilerInlineMIR(&cUnit);
883 }
884
Ben Cheng4238ec22009-08-24 16:32:22 -0700885 /* Preparation for SSA conversion */
886 dvmInitializeSSAConversion(&cUnit);
887
888 if (cUnit.hasLoop) {
Ben Cheng4a419582010-08-04 13:23:09 -0700889 /*
890 * Loop is not optimizable (for example lack of a single induction
891 * variable), punt and recompile the trace with loop optimization
892 * disabled.
893 */
894 bool loopOpt = dvmCompilerLoopOpt(&cUnit);
895 if (loopOpt == false) {
896 if (cUnit.printMe) {
897 LOGD("Loop is not optimizable - retry codegen");
898 }
899 /* Reset the compiler resource pool */
900 dvmCompilerArenaReset();
901 return dvmCompileTrace(desc, cUnit.numInsts, info, bailPtr,
902 optHints | JIT_OPT_NO_LOOP);
903 }
Ben Cheng4238ec22009-08-24 16:32:22 -0700904 }
905 else {
906 dvmCompilerNonLoopAnalysis(&cUnit);
907 }
908
Bill Buzbee1465db52009-09-23 17:17:35 -0700909 dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
910
Ben Chengba4fc8b2009-06-01 13:00:29 -0700911 if (cUnit.printMe) {
912 dvmCompilerDumpCompilationUnit(&cUnit);
913 }
914
Bill Buzbee1465db52009-09-23 17:17:35 -0700915 /* Allocate Registers */
916 dvmCompilerRegAlloc(&cUnit);
917
Ben Chengba4fc8b2009-06-01 13:00:29 -0700918 /* Convert MIR to LIR, etc. */
919 dvmCompilerMIR2LIR(&cUnit);
920
buzbeebff121a2010-08-04 15:25:06 -0700921 /* Convert LIR into machine code. Loop for recoverable retries */
922 do {
923 dvmCompilerAssembleLIR(&cUnit, info);
924 cUnit.assemblerRetries++;
925 if (cUnit.printMe && cUnit.assemblerStatus != kSuccess)
926 LOGD("Assembler abort #%d on %d",cUnit.assemblerRetries,
927 cUnit.assemblerStatus);
928 } while (cUnit.assemblerStatus == kRetryAll);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700929
930 if (cUnit.printMe) {
buzbeebff121a2010-08-04 15:25:06 -0700931 dvmCompilerCodegenDump(&cUnit);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700932 LOGD("End %s%s, %d Dalvik instructions",
933 desc->method->clazz->descriptor, desc->method->name,
934 cUnit.numInsts);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700935 }
936
937 /* Reset the compiler resource pool */
938 dvmCompilerArenaReset();
939
buzbeebff121a2010-08-04 15:25:06 -0700940 if (cUnit.assemblerStatus == kRetryHalve) {
941 /* Halve the instruction count and start from the top */
Ben Cheng4a419582010-08-04 13:23:09 -0700942 return dvmCompileTrace(desc, cUnit.numInsts / 2, info, bailPtr,
943 optHints);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700944 }
buzbeebff121a2010-08-04 15:25:06 -0700945
946 assert(cUnit.assemblerStatus == kSuccess);
947#if defined(WITH_JIT_TUNING)
948 methodStats->nativeSize += cUnit.totalSize;
949#endif
950 return info->codeAddress != NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700951}
952
953/*
Ben Cheng7a2697d2010-06-07 13:44:23 -0700954 * Since we are including instructions from possibly a cold method into the
955 * current trace, we need to make sure that all the associated information
956 * with the callee is properly initialized. If not, we punt on this inline
957 * target.
958 *
959 * TODO: volatile instructions will handled later.
960 */
961bool dvmCompilerCanIncludeThisInstruction(const Method *method,
962 const DecodedInstruction *insn)
963{
964 switch (insn->opCode) {
965 case OP_NEW_INSTANCE:
966 case OP_CHECK_CAST: {
967 ClassObject *classPtr = (void*)
968 (method->clazz->pDvmDex->pResClasses[insn->vB]);
969
970 /* Class hasn't been initialized yet */
971 if (classPtr == NULL) {
972 return false;
973 }
974 return true;
975 }
976 case OP_SGET_OBJECT:
977 case OP_SGET_BOOLEAN:
978 case OP_SGET_CHAR:
979 case OP_SGET_BYTE:
980 case OP_SGET_SHORT:
981 case OP_SGET:
982 case OP_SGET_WIDE:
983 case OP_SPUT_OBJECT:
984 case OP_SPUT_BOOLEAN:
985 case OP_SPUT_CHAR:
986 case OP_SPUT_BYTE:
987 case OP_SPUT_SHORT:
988 case OP_SPUT:
989 case OP_SPUT_WIDE: {
990 void *fieldPtr = (void*)
991 (method->clazz->pDvmDex->pResFields[insn->vB]);
992
993 if (fieldPtr == NULL) {
994 return false;
995 }
996 return true;
997 }
998 case OP_INVOKE_SUPER:
999 case OP_INVOKE_SUPER_RANGE: {
1000 int mIndex = method->clazz->pDvmDex->
1001 pResMethods[insn->vB]->methodIndex;
1002 const Method *calleeMethod = method->clazz->super->vtable[mIndex];
1003 if (calleeMethod == NULL) {
1004 return false;
1005 }
1006 return true;
1007 }
1008 case OP_INVOKE_SUPER_QUICK:
1009 case OP_INVOKE_SUPER_QUICK_RANGE: {
1010 const Method *calleeMethod = method->clazz->super->vtable[insn->vB];
1011 if (calleeMethod == NULL) {
1012 return false;
1013 }
1014 return true;
1015 }
1016 case OP_INVOKE_STATIC:
1017 case OP_INVOKE_STATIC_RANGE:
1018 case OP_INVOKE_DIRECT:
1019 case OP_INVOKE_DIRECT_RANGE: {
1020 const Method *calleeMethod =
1021 method->clazz->pDvmDex->pResMethods[insn->vB];
1022 if (calleeMethod == NULL) {
1023 return false;
1024 }
1025 return true;
1026 }
1027 case OP_CONST_CLASS: {
1028 void *classPtr = (void*)
1029 (method->clazz->pDvmDex->pResClasses[insn->vB]);
1030
1031 if (classPtr == NULL) {
1032 return false;
1033 }
1034 return true;
1035 }
1036 case OP_CONST_STRING_JUMBO:
1037 case OP_CONST_STRING: {
1038 void *strPtr = (void*)
1039 (method->clazz->pDvmDex->pResStrings[insn->vB]);
1040
1041 if (strPtr == NULL) {
1042 return false;
1043 }
1044 return true;
1045 }
1046 default:
1047 return true;
1048 }
1049}
1050
1051/*
Ben Chengba4fc8b2009-06-01 13:00:29 -07001052 * Similar to dvmCompileTrace, but the entity processed here is the whole
1053 * method.
1054 *
1055 * TODO: implementation will be revisited when the trace builder can provide
1056 * whole-method traces.
1057 */
Ben Cheng7a2697d2010-06-07 13:44:23 -07001058bool dvmCompileMethod(CompilationUnit *cUnit, const Method *method,
1059 JitTranslationInfo *info)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001060{
1061 const DexCode *dexCode = dvmGetMethodCode(method);
1062 const u2 *codePtr = dexCode->insns;
1063 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
1064 int blockID = 0;
1065 unsigned int curOffset = 0;
1066
Ben Cheng7a2697d2010-06-07 13:44:23 -07001067 /* If we've already compiled this trace, just return success */
1068 if (dvmJitGetCodeAddr(codePtr) && !info->discardResult) {
1069 return true;
1070 }
1071
1072 /* Doing method-based compilation */
1073 cUnit->wholeMethod = true;
1074
Bill Buzbee1465db52009-09-23 17:17:35 -07001075 BasicBlock *firstBlock = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001076 firstBlock->id = blockID++;
1077
1078 /* Allocate the bit-vector to track the beginning of basic blocks */
Ben Cheng4238ec22009-08-24 16:32:22 -07001079 BitVector *bbStartAddr = dvmCompilerAllocBitVector(dexCode->insnsSize+1,
1080 false);
1081 dvmCompilerSetBit(bbStartAddr, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001082
Ben Cheng7a2697d2010-06-07 13:44:23 -07001083 int numInvokeTargets = 0;
1084
Ben Chengba4fc8b2009-06-01 13:00:29 -07001085 /*
1086 * Sequentially go through every instruction first and put them in a single
1087 * basic block. Identify block boundaries at the mean time.
1088 */
1089 while (codePtr < codeEnd) {
Ben Cheng4238ec22009-08-24 16:32:22 -07001090 MIR *insn = dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001091 insn->offset = curOffset;
1092 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
1093 bool isInvoke = false;
1094 const Method *callee;
1095 insn->width = width;
1096
Ben Cheng8b258bf2009-06-24 17:27:07 -07001097 /* Terminate when the data section is seen */
1098 if (width == 0)
1099 break;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001100
1101 if (!dvmCompilerCanIncludeThisInstruction(cUnit->method,
1102 &insn->dalvikInsn)) {
1103 return false;
1104 }
1105
Ben Chengba4fc8b2009-06-01 13:00:29 -07001106 dvmCompilerAppendMIR(firstBlock, insn);
1107 /*
1108 * Check whether this is a block ending instruction and whether it
1109 * suggests the start of a new block
1110 */
1111 unsigned int target = curOffset;
1112
1113 /*
1114 * If findBlockBoundary returns true, it means the current instruction
1115 * is terminating the current block. If it is a branch, the target
1116 * address will be recorded in target.
1117 */
1118 if (findBlockBoundary(method, insn, curOffset, &target, &isInvoke,
1119 &callee)) {
Ben Cheng4238ec22009-08-24 16:32:22 -07001120 dvmCompilerSetBit(bbStartAddr, curOffset + width);
Ben Cheng7a2697d2010-06-07 13:44:23 -07001121 /* Each invoke needs a chaining cell block */
1122 if (isInvoke) {
1123 numInvokeTargets++;
1124 }
1125 /* A branch will end the current block */
1126 else if (target != curOffset && target != UNKNOWN_TARGET) {
Ben Cheng4238ec22009-08-24 16:32:22 -07001127 dvmCompilerSetBit(bbStartAddr, target);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001128 }
1129 }
1130
1131 codePtr += width;
1132 /* each bit represents 16-bit quantity */
1133 curOffset += width;
1134 }
1135
1136 /*
1137 * The number of blocks will be equal to the number of bits set to 1 in the
1138 * bit vector minus 1, because the bit representing the location after the
1139 * last instruction is set to one.
Ben Cheng7a2697d2010-06-07 13:44:23 -07001140 *
1141 * We also add additional blocks for invoke chaining and the number is
1142 * denoted by numInvokeTargets.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001143 */
1144 int numBlocks = dvmCountSetBits(bbStartAddr);
1145 if (dvmIsBitSet(bbStartAddr, dexCode->insnsSize)) {
1146 numBlocks--;
1147 }
1148
Ben Chengba4fc8b2009-06-01 13:00:29 -07001149 BasicBlock **blockList;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001150 blockList = cUnit->blockList =
1151 dvmCompilerNew(sizeof(BasicBlock *) * (numBlocks + numInvokeTargets),
1152 true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001153
1154 /*
Ben Cheng7a2697d2010-06-07 13:44:23 -07001155 * Register the first block onto the list and start splitting it into
1156 * sub-blocks.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001157 */
1158 blockList[0] = firstBlock;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001159 cUnit->numBlocks = 1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001160
1161 int i;
1162 for (i = 0; i < numBlocks; i++) {
1163 MIR *insn;
1164 BasicBlock *curBB = blockList[i];
1165 curOffset = curBB->lastMIRInsn->offset;
1166
1167 for (insn = curBB->firstMIRInsn->next; insn; insn = insn->next) {
1168 /* Found the beginning of a new block, see if it is created yet */
1169 if (dvmIsBitSet(bbStartAddr, insn->offset)) {
1170 int j;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001171 for (j = 0; j < cUnit->numBlocks; j++) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07001172 if (blockList[j]->firstMIRInsn->offset == insn->offset)
1173 break;
1174 }
1175
1176 /* Block not split yet - do it now */
Ben Cheng7a2697d2010-06-07 13:44:23 -07001177 if (j == cUnit->numBlocks) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001178 BasicBlock *newBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001179 newBB->id = blockID++;
1180 newBB->firstMIRInsn = insn;
Ben Cheng8b258bf2009-06-24 17:27:07 -07001181 newBB->startOffset = insn->offset;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001182 newBB->lastMIRInsn = curBB->lastMIRInsn;
1183 curBB->lastMIRInsn = insn->prev;
1184 insn->prev->next = NULL;
1185 insn->prev = NULL;
1186
1187 /*
1188 * If the insn is not an unconditional branch, set up the
1189 * fallthrough link.
1190 */
1191 if (!isUnconditionalBranch(curBB->lastMIRInsn)) {
1192 curBB->fallThrough = newBB;
1193 }
1194
Ben Cheng7a2697d2010-06-07 13:44:23 -07001195 /*
1196 * Fallthrough block of an invoke instruction needs to be
1197 * aligned to 4-byte boundary (alignment instruction to be
1198 * inserted later.
1199 */
1200 if (dexGetInstrFlags(gDvm.instrFlags,
1201 curBB->lastMIRInsn->dalvikInsn.opCode) &
1202 kInstrInvoke) {
1203 newBB->isFallThroughFromInvoke = true;
1204 }
1205
Ben Chengba4fc8b2009-06-01 13:00:29 -07001206 /* enqueue the new block */
Ben Cheng7a2697d2010-06-07 13:44:23 -07001207 blockList[cUnit->numBlocks++] = newBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001208 break;
1209 }
1210 }
1211 }
1212 }
1213
Ben Cheng7a2697d2010-06-07 13:44:23 -07001214 if (numBlocks != cUnit->numBlocks) {
1215 LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit->numBlocks);
1216 dvmCompilerAbort(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001217 }
1218
Ben Chengba4fc8b2009-06-01 13:00:29 -07001219 /* Connect the basic blocks through the taken links */
1220 for (i = 0; i < numBlocks; i++) {
1221 BasicBlock *curBB = blockList[i];
1222 MIR *insn = curBB->lastMIRInsn;
1223 unsigned int target = insn->offset;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001224 bool isInvoke = false;
1225 const Method *callee = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001226
1227 findBlockBoundary(method, insn, target, &target, &isInvoke, &callee);
1228
Ben Cheng7a2697d2010-06-07 13:44:23 -07001229 /* Found a block ended on a branch (not invoke) */
1230 if (isInvoke == false && target != insn->offset) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07001231 int j;
1232 /* Forward branch */
1233 if (target > insn->offset) {
1234 j = i + 1;
1235 } else {
1236 /* Backward branch */
1237 j = 0;
1238 }
1239 for (; j < numBlocks; j++) {
1240 if (blockList[j]->firstMIRInsn->offset == target) {
1241 curBB->taken = blockList[j];
1242 break;
1243 }
1244 }
Ben Cheng7a2697d2010-06-07 13:44:23 -07001245 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001246
Ben Cheng7a2697d2010-06-07 13:44:23 -07001247 if (isInvoke) {
1248 BasicBlock *newBB;
1249 /* Monomorphic callee */
1250 if (callee) {
1251 newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton);
1252 newBB->startOffset = 0;
1253 newBB->containingMethod = callee;
1254 /* Will resolve at runtime */
1255 } else {
1256 newBB = dvmCompilerNewBB(kChainingCellInvokePredicted);
1257 newBB->startOffset = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001258 }
Ben Cheng7a2697d2010-06-07 13:44:23 -07001259 newBB->id = blockID++;
1260 curBB->taken = newBB;
1261 /* enqueue the new block */
1262 blockList[cUnit->numBlocks++] = newBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001263 }
1264 }
1265
Ben Cheng7a2697d2010-06-07 13:44:23 -07001266 if (cUnit->numBlocks != numBlocks + numInvokeTargets) {
1267 LOGE("Expect %d vs %d total blocks\n", numBlocks + numInvokeTargets,
1268 cUnit->numBlocks);
1269 dvmCompilerDumpCompilationUnit(cUnit);
1270 dvmCompilerAbort(cUnit);
1271 }
1272
Bill Buzbee716f1202009-07-23 13:22:09 -07001273 /* Set the instruction set to use (NOTE: later components may change it) */
Ben Cheng7a2697d2010-06-07 13:44:23 -07001274 cUnit->instructionSet = dvmCompilerInstructionSet();
Bill Buzbee716f1202009-07-23 13:22:09 -07001275
Ben Cheng7a2697d2010-06-07 13:44:23 -07001276 /* Preparation for SSA conversion */
1277 dvmInitializeSSAConversion(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001278
Ben Cheng7a2697d2010-06-07 13:44:23 -07001279 /* SSA analysis */
1280 dvmCompilerNonLoopAnalysis(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001281
Ben Cheng7a2697d2010-06-07 13:44:23 -07001282 /* Needs to happen after SSA naming */
1283 dvmCompilerInitializeRegAlloc(cUnit);
1284
1285 /* Allocate Registers */
1286 dvmCompilerRegAlloc(cUnit);
1287
1288 /* Convert MIR to LIR, etc. */
1289 dvmCompilerMIR2LIR(cUnit);
1290
1291 /* Convert LIR into machine code. */
1292 dvmCompilerAssembleLIR(cUnit, info);
1293
buzbeebff121a2010-08-04 15:25:06 -07001294 if (cUnit->assemblerStatus != kSuccess) {
Ben Cheng7a2697d2010-06-07 13:44:23 -07001295 return false;
1296 }
1297
1298 dvmCompilerDumpCompilationUnit(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001299
1300 dvmCompilerArenaReset();
1301
Bill Buzbee716f1202009-07-23 13:22:09 -07001302 return info->codeAddress != NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001303}