blob: a44c4894ea9f09a4630faeb83a66358153638271 [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"
Dan Bornsteindf4daaf2010-12-01 14:23:44 -080018#include "libdex/DexOpcodes.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;
Dan Bornstein9a1f8162010-12-01 17:02:26 -080030 Opcode opcode = dexOpcodeFromCodeUnit(instr);
Ben Chengba4fc8b2009-06-01 13:00:29 -070031 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 Bornsteine4852762010-12-02 12:45:00 -080037 insnWidth = dexGetWidthFromOpcode(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{
Dan Bornstein9a1f8162010-12-01 17:02:26 -080062 switch (insn->dalvikInsn.opcode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -070063 /* 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{
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800160 switch (insn->dalvikInsn.opcode) {
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800161 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{
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800175 switch (insn->dalvikInsn.opcode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700176 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 Bornsteine4852762010-12-02 12:45:00 -0800208 int flags = dexGetFlagsFromOpcode(dalvikInsn->opcode);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800209 int dalvikOpcode = dalvikInsn->opcode;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700210
Dan Bornstein0759f522010-11-30 14:58:53 -0800211 if (flags & kInstrInvoke) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700212 attributes &= ~METHOD_IS_LEAF;
213 }
214
215 if (!(flags & kInstrCanReturn)) {
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800216 if (!(dvmCompilerDataFlowAttributes[dalvikOpcode] &
Ben Cheng7a2697d2010-06-07 13:44:23 -0700217 DF_IS_GETTER)) {
218 attributes &= ~METHOD_IS_GETTER;
219 }
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800220 if (!(dvmCompilerDataFlowAttributes[dalvikOpcode] &
Ben Cheng7a2697d2010-06-07 13:44:23 -0700221 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) {
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800232 if (dalvikOpcode == OP_RETURN_VOID) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700233 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
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800244 if (offset == 0 && dalvikOpcode == OP_RETURN_VOID) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700245 attributes |= METHOD_IS_EMPTY;
246 }
247
Ben Cheng34dc7962010-08-26 14:56:31 -0700248 /*
249 * Check if this opcode is selected for single stepping.
250 * If so, don't inline the callee as there is no stack frame for the
251 * interpreter to single-step through the instruction.
252 */
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800253 if (SINGLE_STEP_OP(dalvikOpcode)) {
Ben Cheng34dc7962010-08-26 14:56:31 -0700254 attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
255 }
256
Ben Cheng7a2697d2010-06-07 13:44:23 -0700257 return attributes;
258}
259
260/*
Ben Cheng8b258bf2009-06-24 17:27:07 -0700261 * Analyze each method whose traces are ever compiled. Collect a variety of
262 * statistics like the ratio of exercised vs overall code and code bloat
Ben Cheng7a2697d2010-06-07 13:44:23 -0700263 * ratios. If isCallee is true, also analyze each instruction in more details
264 * to see if it is suitable for inlining.
Ben Cheng8b258bf2009-06-24 17:27:07 -0700265 */
Ben Cheng7a2697d2010-06-07 13:44:23 -0700266CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
267 bool isCallee)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700268{
269 const DexCode *dexCode = dvmGetMethodCode(method);
270 const u2 *codePtr = dexCode->insns;
271 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
272 int insnSize = 0;
273 int hashValue = dvmComputeUtf8Hash(method->name);
274
275 CompilerMethodStats dummyMethodEntry; // For hash table lookup
276 CompilerMethodStats *realMethodEntry; // For hash table storage
277
278 /* For lookup only */
279 dummyMethodEntry.method = method;
280 realMethodEntry = dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
281 &dummyMethodEntry,
282 (HashCompareFunc) compareMethod,
283 false);
284
Ben Cheng7a2697d2010-06-07 13:44:23 -0700285 /* This method has never been analyzed before - create an entry */
286 if (realMethodEntry == NULL) {
287 realMethodEntry =
288 (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
289 realMethodEntry->method = method;
290
291 dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
292 realMethodEntry,
293 (HashCompareFunc) compareMethod,
294 true);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700295 }
296
Ben Cheng7a2697d2010-06-07 13:44:23 -0700297 /* This method is invoked as a callee and has been analyzed - just return */
298 if ((isCallee == true) && (realMethodEntry->attributes & METHOD_IS_CALLEE))
299 return realMethodEntry;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700300
Ben Cheng7a2697d2010-06-07 13:44:23 -0700301 /*
302 * Similarly, return if this method has been compiled before as a hot
303 * method already.
304 */
305 if ((isCallee == false) &&
306 (realMethodEntry->attributes & METHOD_IS_HOT))
307 return realMethodEntry;
308
309 int attributes;
310
311 /* Method hasn't been analyzed for the desired purpose yet */
312 if (isCallee) {
313 /* Aggressively set the attributes until proven otherwise */
314 attributes = METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE |
315 METHOD_IS_GETTER | METHOD_IS_SETTER;
316 } else {
317 attributes = METHOD_IS_HOT;
318 }
Ben Cheng8b258bf2009-06-24 17:27:07 -0700319
320 /* Count the number of instructions */
321 while (codePtr < codeEnd) {
322 DecodedInstruction dalvikInsn;
323 int width = parseInsn(codePtr, &dalvikInsn, false);
324
325 /* Terminate when the data section is seen */
326 if (width == 0)
327 break;
328
Ben Cheng7a2697d2010-06-07 13:44:23 -0700329 if (isCallee) {
330 attributes = analyzeInlineTarget(&dalvikInsn, attributes, insnSize);
331 }
332
Ben Cheng8b258bf2009-06-24 17:27:07 -0700333 insnSize += width;
334 codePtr += width;
335 }
336
Ben Cheng7a2697d2010-06-07 13:44:23 -0700337 /*
338 * Only handle simple getters/setters with one instruction followed by
339 * return
340 */
341 if ((attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) &&
342 (insnSize != 3)) {
343 attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
344 }
345
Ben Cheng8b258bf2009-06-24 17:27:07 -0700346 realMethodEntry->dalvikSize = insnSize * 2;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700347 realMethodEntry->attributes |= attributes;
348
349#if 0
350 /* Uncomment the following to explore various callee patterns */
351 if (attributes & METHOD_IS_THROW_FREE) {
352 LOGE("%s%s is inlinable%s", method->clazz->descriptor, method->name,
353 (attributes & METHOD_IS_EMPTY) ? " empty" : "");
354 }
355
356 if (attributes & METHOD_IS_LEAF) {
357 LOGE("%s%s is leaf %d%s", method->clazz->descriptor, method->name,
358 insnSize, insnSize < 5 ? " (small)" : "");
359 }
360
361 if (attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) {
362 LOGE("%s%s is %s", method->clazz->descriptor, method->name,
363 attributes & METHOD_IS_GETTER ? "getter": "setter");
364 }
365 if (attributes ==
366 (METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE)) {
367 LOGE("%s%s is inlinable non setter/getter", method->clazz->descriptor,
368 method->name);
369 }
370#endif
371
Ben Cheng8b258bf2009-06-24 17:27:07 -0700372 return realMethodEntry;
373}
374
375/*
Ben Cheng33672452010-01-12 14:59:30 -0800376 * Crawl the stack of the thread that requesed compilation to see if any of the
377 * ancestors are on the blacklist.
378 */
Andy McFadden953a0ed2010-09-17 15:48:38 -0700379static bool filterMethodByCallGraph(Thread *thread, const char *curMethodName)
Ben Cheng33672452010-01-12 14:59:30 -0800380{
381 /* Crawl the Dalvik stack frames and compare the method name*/
382 StackSaveArea *ssaPtr = ((StackSaveArea *) thread->curFrame) - 1;
383 while (ssaPtr != ((StackSaveArea *) NULL) - 1) {
384 const Method *method = ssaPtr->method;
385 if (method) {
386 int hashValue = dvmComputeUtf8Hash(method->name);
387 bool found =
388 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
389 (char *) method->name,
390 (HashCompareFunc) strcmp, false) !=
391 NULL;
392 if (found) {
393 LOGD("Method %s (--> %s) found on the JIT %s list",
394 method->name, curMethodName,
395 gDvmJit.includeSelectedMethod ? "white" : "black");
396 return true;
397 }
398
399 }
400 ssaPtr = ((StackSaveArea *) ssaPtr->prevFrame) - 1;
401 };
402 return false;
403}
404
405/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700406 * Main entry point to start trace compilation. Basic blocks are constructed
407 * first and they will be passed to the codegen routines to convert Dalvik
408 * bytecode into machine code.
409 */
Bill Buzbee716f1202009-07-23 13:22:09 -0700410bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
Ben Cheng4a419582010-08-04 13:23:09 -0700411 JitTranslationInfo *info, jmp_buf *bailPtr,
412 int optHints)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700413{
414 const DexCode *dexCode = dvmGetMethodCode(desc->method);
415 const JitTraceRun* currRun = &desc->trace[0];
Ben Chengba4fc8b2009-06-01 13:00:29 -0700416 unsigned int curOffset = currRun->frag.startOffset;
417 unsigned int numInsts = currRun->frag.numInsts;
418 const u2 *codePtr = dexCode->insns + curOffset;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700419 int traceSize = 0; // # of half-words
Ben Chengba4fc8b2009-06-01 13:00:29 -0700420 const u2 *startCodePtr = codePtr;
421 BasicBlock *startBB, *curBB, *lastBB;
422 int numBlocks = 0;
423 static int compilationId;
424 CompilationUnit cUnit;
Ben Cheng1357e942010-02-10 17:21:39 -0800425#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700426 CompilerMethodStats *methodStats;
Ben Cheng1357e942010-02-10 17:21:39 -0800427#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700428
Bill Buzbee964a7b02010-01-28 12:54:19 -0800429 /* If we've already compiled this trace, just return success */
jeffhao9e45c0b2010-02-03 10:24:05 -0800430 if (dvmJitGetCodeAddr(startCodePtr) && !info->discardResult) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700431 /*
432 * Make sure the codeAddress is NULL so that it won't clobber the
433 * existing entry.
434 */
435 info->codeAddress = NULL;
Bill Buzbee964a7b02010-01-28 12:54:19 -0800436 return true;
437 }
438
Ben Chenge9695e52009-06-16 16:11:47 -0700439 compilationId++;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700440 memset(&cUnit, 0, sizeof(CompilationUnit));
441
Ben Cheng1357e942010-02-10 17:21:39 -0800442#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700443 /* Locate the entry to store compilation statistics for this method */
Ben Cheng7a2697d2010-06-07 13:44:23 -0700444 methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
Ben Cheng1357e942010-02-10 17:21:39 -0800445#endif
Ben Chenge9695e52009-06-16 16:11:47 -0700446
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800447 /* Set the recover buffer pointer */
448 cUnit.bailPtr = bailPtr;
449
Ben Chengba4fc8b2009-06-01 13:00:29 -0700450 /* Initialize the printMe flag */
451 cUnit.printMe = gDvmJit.printMe;
452
Bill Buzbee6e963e12009-06-17 16:56:19 -0700453 /* Initialize the profile flag */
454 cUnit.executionCount = gDvmJit.profile;
455
Ben Cheng7a2697d2010-06-07 13:44:23 -0700456 /* Setup the method */
457 cUnit.method = desc->method;
458
459 /* Initialize the PC reconstruction list */
460 dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
461
Ben Chengba4fc8b2009-06-01 13:00:29 -0700462 /* Identify traces that we don't want to compile */
463 if (gDvmJit.methodTable) {
464 int len = strlen(desc->method->clazz->descriptor) +
465 strlen(desc->method->name) + 1;
466 char *fullSignature = dvmCompilerNew(len, true);
467 strcpy(fullSignature, desc->method->clazz->descriptor);
468 strcat(fullSignature, desc->method->name);
469
470 int hashValue = dvmComputeUtf8Hash(fullSignature);
471
472 /*
473 * Doing three levels of screening to see whether we want to skip
474 * compiling this method
475 */
476
477 /* First, check the full "class;method" signature */
478 bool methodFound =
479 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
480 fullSignature, (HashCompareFunc) strcmp,
481 false) !=
482 NULL;
483
484 /* Full signature not found - check the enclosing class */
485 if (methodFound == false) {
486 int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
487 methodFound =
488 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
489 (char *) desc->method->clazz->descriptor,
490 (HashCompareFunc) strcmp, false) !=
491 NULL;
492 /* Enclosing class not found - check the method name */
493 if (methodFound == false) {
494 int hashValue = dvmComputeUtf8Hash(desc->method->name);
495 methodFound =
496 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
497 (char *) desc->method->name,
498 (HashCompareFunc) strcmp, false) !=
499 NULL;
Ben Cheng33672452010-01-12 14:59:30 -0800500
501 /*
502 * Debug by call-graph is enabled. Check if the debug list
503 * covers any methods on the VM stack.
504 */
505 if (methodFound == false && gDvmJit.checkCallGraph == true) {
506 methodFound =
507 filterMethodByCallGraph(info->requestingThread,
508 desc->method->name);
509 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700510 }
511 }
512
513 /*
514 * Under the following conditions, the trace will be *conservatively*
515 * compiled by only containing single-step instructions to and from the
516 * interpreter.
517 * 1) If includeSelectedMethod == false, the method matches the full or
518 * partial signature stored in the hash table.
519 *
520 * 2) If includeSelectedMethod == true, the method does not match the
521 * full and partial signature stored in the hash table.
522 */
523 if (gDvmJit.includeSelectedMethod != methodFound) {
524 cUnit.allSingleStep = true;
525 } else {
526 /* Compile the trace as normal */
527
528 /* Print the method we cherry picked */
529 if (gDvmJit.includeSelectedMethod == true) {
530 cUnit.printMe = true;
531 }
532 }
533 }
534
Ben Cheng4238ec22009-08-24 16:32:22 -0700535 /* Allocate the entry block */
Ben Cheng7a2697d2010-06-07 13:44:23 -0700536 lastBB = startBB = curBB = dvmCompilerNewBB(kTraceEntryBlock);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700537 curBB->startOffset = curOffset;
538 curBB->id = numBlocks++;
539
Bill Buzbee1465db52009-09-23 17:17:35 -0700540 curBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Cheng4238ec22009-08-24 16:32:22 -0700541 curBB->startOffset = curOffset;
542 curBB->id = numBlocks++;
543
544 /* Make the first real dalvik block the fallthrough of the entry block */
545 startBB->fallThrough = curBB;
546 lastBB->next = curBB;
547 lastBB = curBB;
548
Ben Chengba4fc8b2009-06-01 13:00:29 -0700549 if (cUnit.printMe) {
550 LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n",
551 desc->method->name, curOffset);
552 }
553
Ben Cheng1efc9c52009-06-08 18:25:27 -0700554 /*
555 * Analyze the trace descriptor and include up to the maximal number
556 * of Dalvik instructions into the IR.
557 */
558 while (1) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700559 MIR *insn;
560 int width;
Ben Cheng4238ec22009-08-24 16:32:22 -0700561 insn = dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700562 insn->offset = curOffset;
563 width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700564
565 /* The trace should never incude instruction data */
566 assert(width);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700567 insn->width = width;
568 traceSize += width;
569 dvmCompilerAppendMIR(curBB, insn);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700570 cUnit.numInsts++;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700571
Dan Bornsteine4852762010-12-02 12:45:00 -0800572 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700573
Dan Bornstein0759f522010-11-30 14:58:53 -0800574 if (flags & kInstrInvoke) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700575 assert(numInsts == 1);
576 CallsiteInfo *callsiteInfo =
577 dvmCompilerNew(sizeof(CallsiteInfo), true);
578 callsiteInfo->clazz = currRun[1].meta;
579 callsiteInfo->method = currRun[2].meta;
580 insn->meta.callsiteInfo = callsiteInfo;
581 }
582
Ben Cheng1efc9c52009-06-08 18:25:27 -0700583 /* Instruction limit reached - terminate the trace here */
584 if (cUnit.numInsts >= numMaxInsts) {
585 break;
586 }
587 if (--numInsts == 0) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700588 if (currRun->frag.runEnd) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700589 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700590 } else {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700591 /* Advance to the next trace description (ie non-meta info) */
592 do {
593 currRun++;
594 } while (!currRun->frag.isCode);
595
596 /* Dummy end-of-run marker seen */
597 if (currRun->frag.numInsts == 0) {
598 break;
599 }
600
Bill Buzbee1465db52009-09-23 17:17:35 -0700601 curBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700602 lastBB->next = curBB;
603 lastBB = curBB;
604 curBB->id = numBlocks++;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700605 curOffset = currRun->frag.startOffset;
606 numInsts = currRun->frag.numInsts;
607 curBB->startOffset = curOffset;
608 codePtr = dexCode->insns + curOffset;
609 }
610 } else {
611 curOffset += width;
612 codePtr += width;
613 }
614 }
615
Ben Cheng1357e942010-02-10 17:21:39 -0800616#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700617 /* Convert # of half-word to bytes */
618 methodStats->compiledDalvikSize += traceSize * 2;
Ben Cheng1357e942010-02-10 17:21:39 -0800619#endif
Ben Cheng8b258bf2009-06-24 17:27:07 -0700620
Ben Chengba4fc8b2009-06-01 13:00:29 -0700621 /*
622 * Now scan basic blocks containing real code to connect the
623 * taken/fallthrough links. Also create chaining cells for code not included
624 * in the trace.
625 */
626 for (curBB = startBB; curBB; curBB = curBB->next) {
627 MIR *lastInsn = curBB->lastMIRInsn;
Ben Cheng4238ec22009-08-24 16:32:22 -0700628 /* Skip empty blocks */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700629 if (lastInsn == NULL) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700630 continue;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700631 }
632 curOffset = lastInsn->offset;
633 unsigned int targetOffset = curOffset;
634 unsigned int fallThroughOffset = curOffset + lastInsn->width;
635 bool isInvoke = false;
636 const Method *callee = NULL;
637
638 findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
639 &targetOffset, &isInvoke, &callee);
640
641 /* Link the taken and fallthrough blocks */
642 BasicBlock *searchBB;
643
Dan Bornsteine4852762010-12-02 12:45:00 -0800644 int flags = dexGetFlagsFromOpcode(lastInsn->dalvikInsn.opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700645
646 if (flags & kInstrInvoke) {
647 cUnit.hasInvoke = true;
648 }
649
Ben Chengba4fc8b2009-06-01 13:00:29 -0700650 /* No backward branch in the trace - start searching the next BB */
651 for (searchBB = curBB->next; searchBB; searchBB = searchBB->next) {
652 if (targetOffset == searchBB->startOffset) {
653 curBB->taken = searchBB;
654 }
655 if (fallThroughOffset == searchBB->startOffset) {
656 curBB->fallThrough = searchBB;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700657
658 /*
659 * Fallthrough block of an invoke instruction needs to be
660 * aligned to 4-byte boundary (alignment instruction to be
661 * inserted later.
662 */
663 if (flags & kInstrInvoke) {
664 searchBB->isFallThroughFromInvoke = true;
665 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700666 }
667 }
668
Ben Cheng1efc9c52009-06-08 18:25:27 -0700669 /*
670 * Some blocks are ended by non-control-flow-change instructions,
671 * currently only due to trace length constraint. In this case we need
672 * to generate an explicit branch at the end of the block to jump to
673 * the chaining cell.
674 */
675 curBB->needFallThroughBranch =
Ben Cheng17f15ce2009-07-27 16:21:52 -0700676 ((flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
Dan Bornstein0759f522010-11-30 14:58:53 -0800677 kInstrInvoke)) == 0);
Ben Cheng17f15ce2009-07-27 16:21:52 -0700678
Ben Cheng4a419582010-08-04 13:23:09 -0700679 /* Only form a loop if JIT_OPT_NO_LOOP is not set */
Ben Cheng4238ec22009-08-24 16:32:22 -0700680 if (curBB->taken == NULL &&
681 curBB->fallThrough == NULL &&
682 flags == (kInstrCanBranch | kInstrCanContinue) &&
Ben Cheng4a419582010-08-04 13:23:09 -0700683 fallThroughOffset == startBB->startOffset &&
684 JIT_OPT_NO_LOOP != (optHints & JIT_OPT_NO_LOOP)) {
Ben Cheng0fd31e42009-09-03 14:40:16 -0700685 BasicBlock *loopBranch = curBB;
686 BasicBlock *exitBB;
687 BasicBlock *exitChainingCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700688
689 if (cUnit.printMe) {
690 LOGD("Natural loop detected!");
691 }
Ben Cheng7a2697d2010-06-07 13:44:23 -0700692 exitBB = dvmCompilerNewBB(kTraceExitBlock);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700693 lastBB->next = exitBB;
694 lastBB = exitBB;
Ben Cheng4238ec22009-08-24 16:32:22 -0700695
Ben Cheng0fd31e42009-09-03 14:40:16 -0700696 exitBB->startOffset = targetOffset;
697 exitBB->id = numBlocks++;
698 exitBB->needFallThroughBranch = true;
Ben Cheng4238ec22009-08-24 16:32:22 -0700699
Ben Cheng0fd31e42009-09-03 14:40:16 -0700700 loopBranch->taken = exitBB;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700701#if defined(WITH_SELF_VERIFICATION)
Ben Cheng0fd31e42009-09-03 14:40:16 -0700702 BasicBlock *backwardCell =
Bill Buzbee1465db52009-09-23 17:17:35 -0700703 dvmCompilerNewBB(kChainingCellBackwardBranch);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700704 lastBB->next = backwardCell;
705 lastBB = backwardCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700706
Ben Cheng0fd31e42009-09-03 14:40:16 -0700707 backwardCell->startOffset = startBB->startOffset;
708 backwardCell->id = numBlocks++;
709 loopBranch->fallThrough = backwardCell;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700710#elif defined(WITH_JIT_TUNING)
711 if (gDvmJit.profile) {
712 BasicBlock *backwardCell =
Bill Buzbee1465db52009-09-23 17:17:35 -0700713 dvmCompilerNewBB(kChainingCellBackwardBranch);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700714 lastBB->next = backwardCell;
715 lastBB = backwardCell;
716
717 backwardCell->startOffset = startBB->startOffset;
718 backwardCell->id = numBlocks++;
719 loopBranch->fallThrough = backwardCell;
720 } else {
721 loopBranch->fallThrough = startBB->next;
722 }
723#else
724 loopBranch->fallThrough = startBB->next;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700725#endif
726
727 /* Create the chaining cell as the fallthrough of the exit block */
Bill Buzbee1465db52009-09-23 17:17:35 -0700728 exitChainingCell = dvmCompilerNewBB(kChainingCellNormal);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700729 lastBB->next = exitChainingCell;
730 lastBB = exitChainingCell;
731
732 exitChainingCell->startOffset = targetOffset;
733 exitChainingCell->id = numBlocks++;
734
735 exitBB->fallThrough = exitChainingCell;
736
Ben Cheng4238ec22009-08-24 16:32:22 -0700737 cUnit.hasLoop = true;
738 }
739
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800740 if (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ||
741 lastInsn->dalvikInsn.opcode == OP_SPARSE_SWITCH) {
Ben Cheng6c10a972009-10-29 14:39:18 -0700742 int i;
743 const u2 *switchData = desc->method->insns + lastInsn->offset +
744 lastInsn->dalvikInsn.vB;
745 int size = switchData[1];
746 int maxChains = MIN(size, MAX_CHAINED_SWITCH_CASES);
747
748 /*
749 * Generate the landing pad for cases whose ranks are higher than
750 * MAX_CHAINED_SWITCH_CASES. The code will re-enter the interpreter
751 * through the NoChain point.
752 */
753 if (maxChains != size) {
754 cUnit.switchOverflowPad =
755 desc->method->insns + lastInsn->offset;
756 }
757
758 s4 *targets = (s4 *) (switchData + 2 +
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800759 (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ?
Ben Cheng6c10a972009-10-29 14:39:18 -0700760 2 : size * 2));
761
762 /* One chaining cell for the first MAX_CHAINED_SWITCH_CASES cases */
763 for (i = 0; i < maxChains; i++) {
764 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal);
765 lastBB->next = caseChain;
766 lastBB = caseChain;
767
768 caseChain->startOffset = lastInsn->offset + targets[i];
769 caseChain->id = numBlocks++;
770 }
771
772 /* One more chaining cell for the default case */
773 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal);
774 lastBB->next = caseChain;
775 lastBB = caseChain;
776
777 caseChain->startOffset = lastInsn->offset + lastInsn->width;
778 caseChain->id = numBlocks++;
Ben Cheng6d576092009-09-01 17:01:58 -0700779 /* Fallthrough block not included in the trace */
Ben Cheng6c10a972009-10-29 14:39:18 -0700780 } else if (!isUnconditionalBranch(lastInsn) &&
781 curBB->fallThrough == NULL) {
Ben Cheng6d576092009-09-01 17:01:58 -0700782 /*
783 * If the chaining cell is after an invoke or
784 * instruction that cannot change the control flow, request a hot
785 * chaining cell.
786 */
787 if (isInvoke || curBB->needFallThroughBranch) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700788 lastBB->next = dvmCompilerNewBB(kChainingCellHot);
Ben Cheng6d576092009-09-01 17:01:58 -0700789 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700790 lastBB->next = dvmCompilerNewBB(kChainingCellNormal);
Ben Cheng6d576092009-09-01 17:01:58 -0700791 }
792 lastBB = lastBB->next;
793 lastBB->id = numBlocks++;
794 lastBB->startOffset = fallThroughOffset;
795 curBB->fallThrough = lastBB;
796 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700797 /* Target block not included in the trace */
Ben Cheng38329f52009-07-07 14:19:20 -0700798 if (curBB->taken == NULL &&
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800799 (isGoto(lastInsn) || isInvoke ||
800 (targetOffset != UNKNOWN_TARGET && targetOffset != curOffset))) {
Ben Cheng38329f52009-07-07 14:19:20 -0700801 BasicBlock *newBB;
Ben Cheng1efc9c52009-06-08 18:25:27 -0700802 if (isInvoke) {
Ben Cheng38329f52009-07-07 14:19:20 -0700803 /* Monomorphic callee */
804 if (callee) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700805 newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton);
Ben Cheng38329f52009-07-07 14:19:20 -0700806 newBB->startOffset = 0;
807 newBB->containingMethod = callee;
808 /* Will resolve at runtime */
809 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700810 newBB = dvmCompilerNewBB(kChainingCellInvokePredicted);
Ben Cheng38329f52009-07-07 14:19:20 -0700811 newBB->startOffset = 0;
812 }
Ben Cheng1efc9c52009-06-08 18:25:27 -0700813 /* For unconditional branches, request a hot chaining cell */
814 } else {
Jeff Hao97319a82009-08-12 16:57:15 -0700815#if !defined(WITH_SELF_VERIFICATION)
Dan Bornsteinc2b486f2010-11-12 16:07:16 -0800816 newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700817 kChainingCellHot :
818 kChainingCellNormal);
Ben Cheng38329f52009-07-07 14:19:20 -0700819 newBB->startOffset = targetOffset;
Jeff Hao97319a82009-08-12 16:57:15 -0700820#else
821 /* Handle branches that branch back into the block */
822 if (targetOffset >= curBB->firstMIRInsn->offset &&
823 targetOffset <= curBB->lastMIRInsn->offset) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700824 newBB = dvmCompilerNewBB(kChainingCellBackwardBranch);
Jeff Hao97319a82009-08-12 16:57:15 -0700825 } else {
Dan Bornsteinc2b486f2010-11-12 16:07:16 -0800826 newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700827 kChainingCellHot :
828 kChainingCellNormal);
Jeff Hao97319a82009-08-12 16:57:15 -0700829 }
830 newBB->startOffset = targetOffset;
831#endif
Ben Cheng1efc9c52009-06-08 18:25:27 -0700832 }
Ben Cheng38329f52009-07-07 14:19:20 -0700833 newBB->id = numBlocks++;
834 curBB->taken = newBB;
835 lastBB->next = newBB;
836 lastBB = newBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700837 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700838 }
839
840 /* Now create a special block to host PC reconstruction code */
Bill Buzbee1465db52009-09-23 17:17:35 -0700841 lastBB->next = dvmCompilerNewBB(kPCReconstruction);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700842 lastBB = lastBB->next;
843 lastBB->id = numBlocks++;
844
845 /* And one final block that publishes the PC and raise the exception */
Bill Buzbee1465db52009-09-23 17:17:35 -0700846 lastBB->next = dvmCompilerNewBB(kExceptionHandling);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700847 lastBB = lastBB->next;
848 lastBB->id = numBlocks++;
849
850 if (cUnit.printMe) {
Elliott Hughescc6fac82010-07-02 13:38:44 -0700851 char* signature = dexProtoCopyMethodDescriptor(&desc->method->prototype);
852 LOGD("TRACEINFO (%d): 0x%08x %s%s.%s 0x%x %d of %d, %d blocks",
Ben Chenge9695e52009-06-16 16:11:47 -0700853 compilationId,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700854 (intptr_t) desc->method->insns,
855 desc->method->clazz->descriptor,
856 desc->method->name,
Elliott Hughescc6fac82010-07-02 13:38:44 -0700857 signature,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700858 desc->trace[0].frag.startOffset,
859 traceSize,
860 dexCode->insnsSize,
861 numBlocks);
Elliott Hughescc6fac82010-07-02 13:38:44 -0700862 free(signature);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700863 }
864
865 BasicBlock **blockList;
866
Ben Chengba4fc8b2009-06-01 13:00:29 -0700867 cUnit.traceDesc = desc;
868 cUnit.numBlocks = numBlocks;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700869 blockList = cUnit.blockList =
870 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
871
872 int i;
873
874 for (i = 0, curBB = startBB; i < numBlocks; i++) {
875 blockList[i] = curBB;
876 curBB = curBB->next;
877 }
878 /* Make sure all blocks are added to the cUnit */
879 assert(curBB == NULL);
880
Ben Cheng7a2697d2010-06-07 13:44:23 -0700881 /* Set the instruction set to use (NOTE: later components may change it) */
882 cUnit.instructionSet = dvmCompilerInstructionSet();
883
884 /* Inline transformation @ the MIR level */
885 if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) {
886 dvmCompilerInlineMIR(&cUnit);
887 }
888
Ben Cheng4238ec22009-08-24 16:32:22 -0700889 /* Preparation for SSA conversion */
890 dvmInitializeSSAConversion(&cUnit);
891
892 if (cUnit.hasLoop) {
Ben Cheng4a419582010-08-04 13:23:09 -0700893 /*
894 * Loop is not optimizable (for example lack of a single induction
895 * variable), punt and recompile the trace with loop optimization
896 * disabled.
897 */
898 bool loopOpt = dvmCompilerLoopOpt(&cUnit);
899 if (loopOpt == false) {
900 if (cUnit.printMe) {
901 LOGD("Loop is not optimizable - retry codegen");
902 }
903 /* Reset the compiler resource pool */
904 dvmCompilerArenaReset();
905 return dvmCompileTrace(desc, cUnit.numInsts, info, bailPtr,
906 optHints | JIT_OPT_NO_LOOP);
907 }
Ben Cheng4238ec22009-08-24 16:32:22 -0700908 }
909 else {
910 dvmCompilerNonLoopAnalysis(&cUnit);
911 }
912
Bill Buzbee1465db52009-09-23 17:17:35 -0700913 dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
914
Ben Chengba4fc8b2009-06-01 13:00:29 -0700915 if (cUnit.printMe) {
916 dvmCompilerDumpCompilationUnit(&cUnit);
917 }
918
Bill Buzbee1465db52009-09-23 17:17:35 -0700919 /* Allocate Registers */
920 dvmCompilerRegAlloc(&cUnit);
921
Ben Chengba4fc8b2009-06-01 13:00:29 -0700922 /* Convert MIR to LIR, etc. */
923 dvmCompilerMIR2LIR(&cUnit);
924
buzbeebff121a2010-08-04 15:25:06 -0700925 /* Convert LIR into machine code. Loop for recoverable retries */
926 do {
927 dvmCompilerAssembleLIR(&cUnit, info);
928 cUnit.assemblerRetries++;
929 if (cUnit.printMe && cUnit.assemblerStatus != kSuccess)
930 LOGD("Assembler abort #%d on %d",cUnit.assemblerRetries,
931 cUnit.assemblerStatus);
932 } while (cUnit.assemblerStatus == kRetryAll);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700933
934 if (cUnit.printMe) {
buzbeebff121a2010-08-04 15:25:06 -0700935 dvmCompilerCodegenDump(&cUnit);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700936 LOGD("End %s%s, %d Dalvik instructions",
937 desc->method->clazz->descriptor, desc->method->name,
938 cUnit.numInsts);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700939 }
940
941 /* Reset the compiler resource pool */
942 dvmCompilerArenaReset();
943
buzbeebff121a2010-08-04 15:25:06 -0700944 if (cUnit.assemblerStatus == kRetryHalve) {
945 /* Halve the instruction count and start from the top */
Ben Cheng4a419582010-08-04 13:23:09 -0700946 return dvmCompileTrace(desc, cUnit.numInsts / 2, info, bailPtr,
947 optHints);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700948 }
buzbeebff121a2010-08-04 15:25:06 -0700949
950 assert(cUnit.assemblerStatus == kSuccess);
951#if defined(WITH_JIT_TUNING)
952 methodStats->nativeSize += cUnit.totalSize;
953#endif
954 return info->codeAddress != NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700955}
956
957/*
Ben Cheng7a2697d2010-06-07 13:44:23 -0700958 * Since we are including instructions from possibly a cold method into the
959 * current trace, we need to make sure that all the associated information
960 * with the callee is properly initialized. If not, we punt on this inline
961 * target.
962 *
Ben Cheng34dc7962010-08-26 14:56:31 -0700963 * TODO: volatile instructions will be handled later.
Ben Cheng7a2697d2010-06-07 13:44:23 -0700964 */
965bool dvmCompilerCanIncludeThisInstruction(const Method *method,
966 const DecodedInstruction *insn)
967{
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800968 switch (insn->opcode) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700969 case OP_NEW_INSTANCE:
970 case OP_CHECK_CAST: {
971 ClassObject *classPtr = (void*)
972 (method->clazz->pDvmDex->pResClasses[insn->vB]);
973
974 /* Class hasn't been initialized yet */
975 if (classPtr == NULL) {
976 return false;
977 }
978 return true;
979 }
980 case OP_SGET_OBJECT:
981 case OP_SGET_BOOLEAN:
982 case OP_SGET_CHAR:
983 case OP_SGET_BYTE:
984 case OP_SGET_SHORT:
985 case OP_SGET:
986 case OP_SGET_WIDE:
987 case OP_SPUT_OBJECT:
988 case OP_SPUT_BOOLEAN:
989 case OP_SPUT_CHAR:
990 case OP_SPUT_BYTE:
991 case OP_SPUT_SHORT:
992 case OP_SPUT:
993 case OP_SPUT_WIDE: {
994 void *fieldPtr = (void*)
995 (method->clazz->pDvmDex->pResFields[insn->vB]);
996
997 if (fieldPtr == NULL) {
998 return false;
999 }
1000 return true;
1001 }
1002 case OP_INVOKE_SUPER:
1003 case OP_INVOKE_SUPER_RANGE: {
1004 int mIndex = method->clazz->pDvmDex->
1005 pResMethods[insn->vB]->methodIndex;
1006 const Method *calleeMethod = method->clazz->super->vtable[mIndex];
1007 if (calleeMethod == NULL) {
1008 return false;
1009 }
1010 return true;
1011 }
1012 case OP_INVOKE_SUPER_QUICK:
1013 case OP_INVOKE_SUPER_QUICK_RANGE: {
1014 const Method *calleeMethod = method->clazz->super->vtable[insn->vB];
1015 if (calleeMethod == NULL) {
1016 return false;
1017 }
1018 return true;
1019 }
1020 case OP_INVOKE_STATIC:
1021 case OP_INVOKE_STATIC_RANGE:
1022 case OP_INVOKE_DIRECT:
1023 case OP_INVOKE_DIRECT_RANGE: {
1024 const Method *calleeMethod =
1025 method->clazz->pDvmDex->pResMethods[insn->vB];
1026 if (calleeMethod == NULL) {
1027 return false;
1028 }
1029 return true;
1030 }
1031 case OP_CONST_CLASS: {
1032 void *classPtr = (void*)
1033 (method->clazz->pDvmDex->pResClasses[insn->vB]);
1034
1035 if (classPtr == NULL) {
1036 return false;
1037 }
1038 return true;
1039 }
1040 case OP_CONST_STRING_JUMBO:
1041 case OP_CONST_STRING: {
1042 void *strPtr = (void*)
1043 (method->clazz->pDvmDex->pResStrings[insn->vB]);
1044
1045 if (strPtr == NULL) {
1046 return false;
1047 }
1048 return true;
1049 }
1050 default:
1051 return true;
1052 }
1053}
1054
1055/*
Ben Chengba4fc8b2009-06-01 13:00:29 -07001056 * Similar to dvmCompileTrace, but the entity processed here is the whole
1057 * method.
1058 *
1059 * TODO: implementation will be revisited when the trace builder can provide
1060 * whole-method traces.
1061 */
Ben Cheng7a2697d2010-06-07 13:44:23 -07001062bool dvmCompileMethod(CompilationUnit *cUnit, const Method *method,
1063 JitTranslationInfo *info)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001064{
1065 const DexCode *dexCode = dvmGetMethodCode(method);
1066 const u2 *codePtr = dexCode->insns;
1067 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
1068 int blockID = 0;
1069 unsigned int curOffset = 0;
1070
Ben Cheng7a2697d2010-06-07 13:44:23 -07001071 /* If we've already compiled this trace, just return success */
1072 if (dvmJitGetCodeAddr(codePtr) && !info->discardResult) {
1073 return true;
1074 }
1075
1076 /* Doing method-based compilation */
1077 cUnit->wholeMethod = true;
1078
Bill Buzbee1465db52009-09-23 17:17:35 -07001079 BasicBlock *firstBlock = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001080 firstBlock->id = blockID++;
1081
1082 /* Allocate the bit-vector to track the beginning of basic blocks */
Ben Cheng4238ec22009-08-24 16:32:22 -07001083 BitVector *bbStartAddr = dvmCompilerAllocBitVector(dexCode->insnsSize+1,
1084 false);
1085 dvmCompilerSetBit(bbStartAddr, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001086
Ben Cheng7a2697d2010-06-07 13:44:23 -07001087 int numInvokeTargets = 0;
1088
Ben Chengba4fc8b2009-06-01 13:00:29 -07001089 /*
1090 * Sequentially go through every instruction first and put them in a single
1091 * basic block. Identify block boundaries at the mean time.
1092 */
1093 while (codePtr < codeEnd) {
Ben Cheng4238ec22009-08-24 16:32:22 -07001094 MIR *insn = dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001095 insn->offset = curOffset;
1096 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
1097 bool isInvoke = false;
1098 const Method *callee;
1099 insn->width = width;
1100
Ben Cheng8b258bf2009-06-24 17:27:07 -07001101 /* Terminate when the data section is seen */
1102 if (width == 0)
1103 break;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001104
1105 if (!dvmCompilerCanIncludeThisInstruction(cUnit->method,
1106 &insn->dalvikInsn)) {
1107 return false;
1108 }
1109
Ben Chengba4fc8b2009-06-01 13:00:29 -07001110 dvmCompilerAppendMIR(firstBlock, insn);
1111 /*
1112 * Check whether this is a block ending instruction and whether it
1113 * suggests the start of a new block
1114 */
1115 unsigned int target = curOffset;
1116
1117 /*
1118 * If findBlockBoundary returns true, it means the current instruction
1119 * is terminating the current block. If it is a branch, the target
1120 * address will be recorded in target.
1121 */
1122 if (findBlockBoundary(method, insn, curOffset, &target, &isInvoke,
1123 &callee)) {
Ben Cheng4238ec22009-08-24 16:32:22 -07001124 dvmCompilerSetBit(bbStartAddr, curOffset + width);
Ben Cheng7a2697d2010-06-07 13:44:23 -07001125 /* Each invoke needs a chaining cell block */
1126 if (isInvoke) {
1127 numInvokeTargets++;
1128 }
1129 /* A branch will end the current block */
1130 else if (target != curOffset && target != UNKNOWN_TARGET) {
Ben Cheng4238ec22009-08-24 16:32:22 -07001131 dvmCompilerSetBit(bbStartAddr, target);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001132 }
1133 }
1134
1135 codePtr += width;
1136 /* each bit represents 16-bit quantity */
1137 curOffset += width;
1138 }
1139
1140 /*
1141 * The number of blocks will be equal to the number of bits set to 1 in the
1142 * bit vector minus 1, because the bit representing the location after the
1143 * last instruction is set to one.
Ben Cheng7a2697d2010-06-07 13:44:23 -07001144 *
1145 * We also add additional blocks for invoke chaining and the number is
1146 * denoted by numInvokeTargets.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001147 */
1148 int numBlocks = dvmCountSetBits(bbStartAddr);
1149 if (dvmIsBitSet(bbStartAddr, dexCode->insnsSize)) {
1150 numBlocks--;
1151 }
1152
Ben Chengba4fc8b2009-06-01 13:00:29 -07001153 BasicBlock **blockList;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001154 blockList = cUnit->blockList =
1155 dvmCompilerNew(sizeof(BasicBlock *) * (numBlocks + numInvokeTargets),
1156 true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001157
1158 /*
Ben Cheng7a2697d2010-06-07 13:44:23 -07001159 * Register the first block onto the list and start splitting it into
1160 * sub-blocks.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001161 */
1162 blockList[0] = firstBlock;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001163 cUnit->numBlocks = 1;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001164
1165 int i;
1166 for (i = 0; i < numBlocks; i++) {
1167 MIR *insn;
1168 BasicBlock *curBB = blockList[i];
1169 curOffset = curBB->lastMIRInsn->offset;
1170
1171 for (insn = curBB->firstMIRInsn->next; insn; insn = insn->next) {
1172 /* Found the beginning of a new block, see if it is created yet */
1173 if (dvmIsBitSet(bbStartAddr, insn->offset)) {
1174 int j;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001175 for (j = 0; j < cUnit->numBlocks; j++) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07001176 if (blockList[j]->firstMIRInsn->offset == insn->offset)
1177 break;
1178 }
1179
1180 /* Block not split yet - do it now */
Ben Cheng7a2697d2010-06-07 13:44:23 -07001181 if (j == cUnit->numBlocks) {
Bill Buzbee1465db52009-09-23 17:17:35 -07001182 BasicBlock *newBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001183 newBB->id = blockID++;
1184 newBB->firstMIRInsn = insn;
Ben Cheng8b258bf2009-06-24 17:27:07 -07001185 newBB->startOffset = insn->offset;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001186 newBB->lastMIRInsn = curBB->lastMIRInsn;
1187 curBB->lastMIRInsn = insn->prev;
1188 insn->prev->next = NULL;
1189 insn->prev = NULL;
1190
1191 /*
1192 * If the insn is not an unconditional branch, set up the
1193 * fallthrough link.
1194 */
1195 if (!isUnconditionalBranch(curBB->lastMIRInsn)) {
1196 curBB->fallThrough = newBB;
1197 }
1198
Ben Cheng7a2697d2010-06-07 13:44:23 -07001199 /*
1200 * Fallthrough block of an invoke instruction needs to be
1201 * aligned to 4-byte boundary (alignment instruction to be
1202 * inserted later.
1203 */
Dan Bornsteine4852762010-12-02 12:45:00 -08001204 if (dexGetFlagsFromOpcode(curBB->lastMIRInsn->dalvikInsn.opcode)
Dan Bornstein41e286c2010-11-19 12:36:19 -08001205 & kInstrInvoke) {
Ben Cheng7a2697d2010-06-07 13:44:23 -07001206 newBB->isFallThroughFromInvoke = true;
1207 }
1208
Ben Chengba4fc8b2009-06-01 13:00:29 -07001209 /* enqueue the new block */
Ben Cheng7a2697d2010-06-07 13:44:23 -07001210 blockList[cUnit->numBlocks++] = newBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001211 break;
1212 }
1213 }
1214 }
1215 }
1216
Ben Cheng7a2697d2010-06-07 13:44:23 -07001217 if (numBlocks != cUnit->numBlocks) {
1218 LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit->numBlocks);
1219 dvmCompilerAbort(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001220 }
1221
Ben Chengba4fc8b2009-06-01 13:00:29 -07001222 /* Connect the basic blocks through the taken links */
1223 for (i = 0; i < numBlocks; i++) {
1224 BasicBlock *curBB = blockList[i];
1225 MIR *insn = curBB->lastMIRInsn;
1226 unsigned int target = insn->offset;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001227 bool isInvoke = false;
1228 const Method *callee = NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001229
1230 findBlockBoundary(method, insn, target, &target, &isInvoke, &callee);
1231
Ben Cheng7a2697d2010-06-07 13:44:23 -07001232 /* Found a block ended on a branch (not invoke) */
1233 if (isInvoke == false && target != insn->offset) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07001234 int j;
1235 /* Forward branch */
1236 if (target > insn->offset) {
1237 j = i + 1;
1238 } else {
1239 /* Backward branch */
1240 j = 0;
1241 }
1242 for (; j < numBlocks; j++) {
1243 if (blockList[j]->firstMIRInsn->offset == target) {
1244 curBB->taken = blockList[j];
1245 break;
1246 }
1247 }
Ben Cheng7a2697d2010-06-07 13:44:23 -07001248 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001249
Ben Cheng7a2697d2010-06-07 13:44:23 -07001250 if (isInvoke) {
1251 BasicBlock *newBB;
1252 /* Monomorphic callee */
1253 if (callee) {
1254 newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton);
1255 newBB->startOffset = 0;
1256 newBB->containingMethod = callee;
1257 /* Will resolve at runtime */
1258 } else {
1259 newBB = dvmCompilerNewBB(kChainingCellInvokePredicted);
1260 newBB->startOffset = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001261 }
Ben Cheng7a2697d2010-06-07 13:44:23 -07001262 newBB->id = blockID++;
1263 curBB->taken = newBB;
1264 /* enqueue the new block */
1265 blockList[cUnit->numBlocks++] = newBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001266 }
1267 }
1268
Ben Cheng7a2697d2010-06-07 13:44:23 -07001269 if (cUnit->numBlocks != numBlocks + numInvokeTargets) {
1270 LOGE("Expect %d vs %d total blocks\n", numBlocks + numInvokeTargets,
1271 cUnit->numBlocks);
1272 dvmCompilerDumpCompilationUnit(cUnit);
1273 dvmCompilerAbort(cUnit);
1274 }
1275
Bill Buzbee716f1202009-07-23 13:22:09 -07001276 /* Set the instruction set to use (NOTE: later components may change it) */
Ben Cheng7a2697d2010-06-07 13:44:23 -07001277 cUnit->instructionSet = dvmCompilerInstructionSet();
Bill Buzbee716f1202009-07-23 13:22:09 -07001278
Ben Cheng7a2697d2010-06-07 13:44:23 -07001279 /* Preparation for SSA conversion */
1280 dvmInitializeSSAConversion(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001281
Ben Cheng7a2697d2010-06-07 13:44:23 -07001282 /* SSA analysis */
1283 dvmCompilerNonLoopAnalysis(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001284
Ben Cheng7a2697d2010-06-07 13:44:23 -07001285 /* Needs to happen after SSA naming */
1286 dvmCompilerInitializeRegAlloc(cUnit);
1287
1288 /* Allocate Registers */
1289 dvmCompilerRegAlloc(cUnit);
1290
1291 /* Convert MIR to LIR, etc. */
1292 dvmCompilerMIR2LIR(cUnit);
1293
1294 /* Convert LIR into machine code. */
1295 dvmCompilerAssembleLIR(cUnit, info);
1296
buzbeebff121a2010-08-04 15:25:06 -07001297 if (cUnit->assemblerStatus != kSuccess) {
Ben Cheng7a2697d2010-06-07 13:44:23 -07001298 return false;
1299 }
1300
1301 dvmCompilerDumpCompilationUnit(cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001302
1303 dvmCompilerArenaReset();
1304
Bill Buzbee716f1202009-07-23 13:22:09 -07001305 return info->codeAddress != NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001306}