blob: 915e5f3fe1f815ed0cf03c50c4d6d7e77450ab03 [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 Cheng00603072010-10-28 11:13:58 -070019#include "libdex/DexCatch.h"
Ben Chengba4fc8b2009-06-01 13:00:29 -070020#include "interp/Jit.h"
21#include "CompilerInternals.h"
Ben Cheng7a2697d2010-06-07 13:44:23 -070022#include "Dataflow.h"
Ben Chengba4fc8b2009-06-01 13:00:29 -070023
Ben Cheng00603072010-10-28 11:13:58 -070024static inline bool contentIsInsn(const u2 *codePtr) {
25 u2 instr = *codePtr;
26 Opcode opcode = instr & 0xff;
27
28 /*
29 * Since the low 8-bit in metadata may look like OP_NOP, we need to check
30 * both the low and whole sub-word to determine whether it is code or data.
31 */
32 return (opcode != OP_NOP || instr == 0);
33}
34
Ben Chengba4fc8b2009-06-01 13:00:29 -070035/*
36 * Parse an instruction, return the length of the instruction
37 */
38static inline int parseInsn(const u2 *codePtr, DecodedInstruction *decInsn,
39 bool printMe)
40{
Ben Cheng00603072010-10-28 11:13:58 -070041 // Don't parse instruction data
42 if (!contentIsInsn(codePtr)) {
43 return 0;
44 }
45
Ben Chengba4fc8b2009-06-01 13:00:29 -070046 u2 instr = *codePtr;
Dan Bornstein9a1f8162010-12-01 17:02:26 -080047 Opcode opcode = dexOpcodeFromCodeUnit(instr);
Ben Chengba4fc8b2009-06-01 13:00:29 -070048
Dan Bornstein54322392010-11-17 14:16:56 -080049 dexDecodeInstruction(codePtr, decInsn);
Ben Chengba4fc8b2009-06-01 13:00:29 -070050 if (printMe) {
Ben Cheng7a2697d2010-06-07 13:44:23 -070051 char *decodedString = dvmCompilerGetDalvikDisassembly(decInsn, NULL);
Ben Chengccd6c012009-10-15 14:52:45 -070052 LOGD("%p: %#06x %s\n", codePtr, opcode, decodedString);
Ben Chengba4fc8b2009-06-01 13:00:29 -070053 }
Ben Cheng00603072010-10-28 11:13:58 -070054 return dexGetWidthFromOpcode(opcode);
Ben Chengba4fc8b2009-06-01 13:00:29 -070055}
56
Ben Cheng9c147b82009-10-07 16:41:46 -070057#define UNKNOWN_TARGET 0xffffffff
58
Ben Chengba4fc8b2009-06-01 13:00:29 -070059/*
60 * Identify block-ending instructions and collect supplemental information
61 * regarding the following instructions.
62 */
63static inline bool findBlockBoundary(const Method *caller, MIR *insn,
64 unsigned int curOffset,
65 unsigned int *target, bool *isInvoke,
66 const Method **callee)
67{
Dan Bornstein9a1f8162010-12-01 17:02:26 -080068 switch (insn->dalvikInsn.opcode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -070069 /* Target is not compile-time constant */
70 case OP_RETURN_VOID:
71 case OP_RETURN:
72 case OP_RETURN_WIDE:
73 case OP_RETURN_OBJECT:
74 case OP_THROW:
Ben Cheng9c147b82009-10-07 16:41:46 -070075 *target = UNKNOWN_TARGET;
76 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -070077 case OP_INVOKE_VIRTUAL:
78 case OP_INVOKE_VIRTUAL_RANGE:
79 case OP_INVOKE_INTERFACE:
80 case OP_INVOKE_INTERFACE_RANGE:
81 case OP_INVOKE_VIRTUAL_QUICK:
82 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
83 *isInvoke = true;
84 break;
85 case OP_INVOKE_SUPER:
86 case OP_INVOKE_SUPER_RANGE: {
87 int mIndex = caller->clazz->pDvmDex->
88 pResMethods[insn->dalvikInsn.vB]->methodIndex;
89 const Method *calleeMethod =
90 caller->clazz->super->vtable[mIndex];
91
Ben Cheng8b258bf2009-06-24 17:27:07 -070092 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -070093 *target = (unsigned int) calleeMethod->insns;
94 }
95 *isInvoke = true;
96 *callee = calleeMethod;
97 break;
98 }
99 case OP_INVOKE_STATIC:
100 case OP_INVOKE_STATIC_RANGE: {
101 const Method *calleeMethod =
102 caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
103
Ben Cheng8b258bf2009-06-24 17:27:07 -0700104 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700105 *target = (unsigned int) calleeMethod->insns;
106 }
107 *isInvoke = true;
108 *callee = calleeMethod;
109 break;
110 }
111 case OP_INVOKE_SUPER_QUICK:
112 case OP_INVOKE_SUPER_QUICK_RANGE: {
113 const Method *calleeMethod =
114 caller->clazz->super->vtable[insn->dalvikInsn.vB];
115
Ben Cheng8b258bf2009-06-24 17:27:07 -0700116 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700117 *target = (unsigned int) calleeMethod->insns;
118 }
119 *isInvoke = true;
120 *callee = calleeMethod;
121 break;
122 }
123 case OP_INVOKE_DIRECT:
124 case OP_INVOKE_DIRECT_RANGE: {
125 const Method *calleeMethod =
126 caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
Ben Cheng8b258bf2009-06-24 17:27:07 -0700127 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700128 *target = (unsigned int) calleeMethod->insns;
129 }
130 *isInvoke = true;
131 *callee = calleeMethod;
132 break;
133 }
134 case OP_GOTO:
135 case OP_GOTO_16:
136 case OP_GOTO_32:
137 *target = curOffset + (int) insn->dalvikInsn.vA;
138 break;
139
140 case OP_IF_EQ:
141 case OP_IF_NE:
142 case OP_IF_LT:
143 case OP_IF_GE:
144 case OP_IF_GT:
145 case OP_IF_LE:
146 *target = curOffset + (int) insn->dalvikInsn.vC;
147 break;
148
149 case OP_IF_EQZ:
150 case OP_IF_NEZ:
151 case OP_IF_LTZ:
152 case OP_IF_GEZ:
153 case OP_IF_GTZ:
154 case OP_IF_LEZ:
155 *target = curOffset + (int) insn->dalvikInsn.vB;
156 break;
157
158 default:
159 return false;
Ben Cheng9c147b82009-10-07 16:41:46 -0700160 }
161 return true;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700162}
163
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800164static inline bool isGoto(MIR *insn)
165{
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800166 switch (insn->dalvikInsn.opcode) {
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800167 case OP_GOTO:
168 case OP_GOTO_16:
169 case OP_GOTO_32:
170 return true;
171 default:
172 return false;
173 }
174}
175
Ben Chengba4fc8b2009-06-01 13:00:29 -0700176/*
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800177 * Identify unconditional branch instructions
Ben Chengba4fc8b2009-06-01 13:00:29 -0700178 */
179static inline bool isUnconditionalBranch(MIR *insn)
180{
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800181 switch (insn->dalvikInsn.opcode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700182 case OP_RETURN_VOID:
183 case OP_RETURN:
184 case OP_RETURN_WIDE:
185 case OP_RETURN_OBJECT:
Ben Chengba4fc8b2009-06-01 13:00:29 -0700186 return true;
187 default:
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800188 return isGoto(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700189 }
190}
191
192/*
Ben Cheng8b258bf2009-06-24 17:27:07 -0700193 * dvmHashTableLookup() callback
194 */
195static int compareMethod(const CompilerMethodStats *m1,
196 const CompilerMethodStats *m2)
197{
198 return (int) m1->method - (int) m2->method;
199}
200
201/*
Ben Cheng7a2697d2010-06-07 13:44:23 -0700202 * Analyze the body of the method to collect high-level information regarding
203 * inlining:
204 * - is empty method?
205 * - is getter/setter?
206 * - can throw exception?
207 *
208 * Currently the inliner only handles getters and setters. When its capability
209 * becomes more sophisticated more information will be retrieved here.
210 */
211static int analyzeInlineTarget(DecodedInstruction *dalvikInsn, int attributes,
212 int offset)
213{
Dan Bornsteine4852762010-12-02 12:45:00 -0800214 int flags = dexGetFlagsFromOpcode(dalvikInsn->opcode);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800215 int dalvikOpcode = dalvikInsn->opcode;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700216
Dan Bornstein0759f522010-11-30 14:58:53 -0800217 if (flags & kInstrInvoke) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700218 attributes &= ~METHOD_IS_LEAF;
219 }
220
221 if (!(flags & kInstrCanReturn)) {
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800222 if (!(dvmCompilerDataFlowAttributes[dalvikOpcode] &
Ben Cheng7a2697d2010-06-07 13:44:23 -0700223 DF_IS_GETTER)) {
224 attributes &= ~METHOD_IS_GETTER;
225 }
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800226 if (!(dvmCompilerDataFlowAttributes[dalvikOpcode] &
Ben Cheng7a2697d2010-06-07 13:44:23 -0700227 DF_IS_SETTER)) {
228 attributes &= ~METHOD_IS_SETTER;
229 }
230 }
231
232 /*
233 * The expected instruction sequence is setter will never return value and
234 * getter will also do. Clear the bits if the behavior is discovered
235 * otherwise.
236 */
237 if (flags & kInstrCanReturn) {
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800238 if (dalvikOpcode == OP_RETURN_VOID) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700239 attributes &= ~METHOD_IS_GETTER;
240 }
241 else {
242 attributes &= ~METHOD_IS_SETTER;
243 }
244 }
245
246 if (flags & kInstrCanThrow) {
247 attributes &= ~METHOD_IS_THROW_FREE;
248 }
249
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800250 if (offset == 0 && dalvikOpcode == OP_RETURN_VOID) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700251 attributes |= METHOD_IS_EMPTY;
252 }
253
Ben Cheng34dc7962010-08-26 14:56:31 -0700254 /*
255 * Check if this opcode is selected for single stepping.
256 * If so, don't inline the callee as there is no stack frame for the
257 * interpreter to single-step through the instruction.
258 */
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800259 if (SINGLE_STEP_OP(dalvikOpcode)) {
Ben Cheng34dc7962010-08-26 14:56:31 -0700260 attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
261 }
262
Ben Cheng7a2697d2010-06-07 13:44:23 -0700263 return attributes;
264}
265
266/*
Ben Cheng8b258bf2009-06-24 17:27:07 -0700267 * Analyze each method whose traces are ever compiled. Collect a variety of
268 * statistics like the ratio of exercised vs overall code and code bloat
Ben Cheng7a2697d2010-06-07 13:44:23 -0700269 * ratios. If isCallee is true, also analyze each instruction in more details
270 * to see if it is suitable for inlining.
Ben Cheng8b258bf2009-06-24 17:27:07 -0700271 */
Ben Cheng7a2697d2010-06-07 13:44:23 -0700272CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
273 bool isCallee)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700274{
275 const DexCode *dexCode = dvmGetMethodCode(method);
276 const u2 *codePtr = dexCode->insns;
277 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
278 int insnSize = 0;
279 int hashValue = dvmComputeUtf8Hash(method->name);
280
281 CompilerMethodStats dummyMethodEntry; // For hash table lookup
282 CompilerMethodStats *realMethodEntry; // For hash table storage
283
284 /* For lookup only */
285 dummyMethodEntry.method = method;
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800286 realMethodEntry =
287 (CompilerMethodStats *) dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
288 &dummyMethodEntry,
289 (HashCompareFunc) compareMethod,
290 false);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700291
Ben Cheng7a2697d2010-06-07 13:44:23 -0700292 /* This method has never been analyzed before - create an entry */
293 if (realMethodEntry == NULL) {
294 realMethodEntry =
295 (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
296 realMethodEntry->method = method;
297
298 dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
299 realMethodEntry,
300 (HashCompareFunc) compareMethod,
301 true);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700302 }
303
Ben Cheng7a2697d2010-06-07 13:44:23 -0700304 /* This method is invoked as a callee and has been analyzed - just return */
305 if ((isCallee == true) && (realMethodEntry->attributes & METHOD_IS_CALLEE))
306 return realMethodEntry;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700307
Ben Cheng7a2697d2010-06-07 13:44:23 -0700308 /*
309 * Similarly, return if this method has been compiled before as a hot
310 * method already.
311 */
312 if ((isCallee == false) &&
313 (realMethodEntry->attributes & METHOD_IS_HOT))
314 return realMethodEntry;
315
316 int attributes;
317
318 /* Method hasn't been analyzed for the desired purpose yet */
319 if (isCallee) {
320 /* Aggressively set the attributes until proven otherwise */
321 attributes = METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE |
322 METHOD_IS_GETTER | METHOD_IS_SETTER;
323 } else {
324 attributes = METHOD_IS_HOT;
325 }
Ben Cheng8b258bf2009-06-24 17:27:07 -0700326
327 /* Count the number of instructions */
328 while (codePtr < codeEnd) {
329 DecodedInstruction dalvikInsn;
330 int width = parseInsn(codePtr, &dalvikInsn, false);
331
332 /* Terminate when the data section is seen */
333 if (width == 0)
334 break;
335
Ben Cheng7a2697d2010-06-07 13:44:23 -0700336 if (isCallee) {
337 attributes = analyzeInlineTarget(&dalvikInsn, attributes, insnSize);
338 }
339
Ben Cheng8b258bf2009-06-24 17:27:07 -0700340 insnSize += width;
341 codePtr += width;
342 }
343
Ben Cheng7a2697d2010-06-07 13:44:23 -0700344 /*
345 * Only handle simple getters/setters with one instruction followed by
346 * return
347 */
348 if ((attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) &&
349 (insnSize != 3)) {
350 attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
351 }
352
Ben Cheng8b258bf2009-06-24 17:27:07 -0700353 realMethodEntry->dalvikSize = insnSize * 2;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700354 realMethodEntry->attributes |= attributes;
355
356#if 0
357 /* Uncomment the following to explore various callee patterns */
358 if (attributes & METHOD_IS_THROW_FREE) {
359 LOGE("%s%s is inlinable%s", method->clazz->descriptor, method->name,
360 (attributes & METHOD_IS_EMPTY) ? " empty" : "");
361 }
362
363 if (attributes & METHOD_IS_LEAF) {
364 LOGE("%s%s is leaf %d%s", method->clazz->descriptor, method->name,
365 insnSize, insnSize < 5 ? " (small)" : "");
366 }
367
368 if (attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) {
369 LOGE("%s%s is %s", method->clazz->descriptor, method->name,
370 attributes & METHOD_IS_GETTER ? "getter": "setter");
371 }
372 if (attributes ==
373 (METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE)) {
374 LOGE("%s%s is inlinable non setter/getter", method->clazz->descriptor,
375 method->name);
376 }
377#endif
378
Ben Cheng8b258bf2009-06-24 17:27:07 -0700379 return realMethodEntry;
380}
381
382/*
Ben Cheng33672452010-01-12 14:59:30 -0800383 * Crawl the stack of the thread that requesed compilation to see if any of the
384 * ancestors are on the blacklist.
385 */
Andy McFadden953a0ed2010-09-17 15:48:38 -0700386static bool filterMethodByCallGraph(Thread *thread, const char *curMethodName)
Ben Cheng33672452010-01-12 14:59:30 -0800387{
388 /* Crawl the Dalvik stack frames and compare the method name*/
389 StackSaveArea *ssaPtr = ((StackSaveArea *) thread->curFrame) - 1;
390 while (ssaPtr != ((StackSaveArea *) NULL) - 1) {
391 const Method *method = ssaPtr->method;
392 if (method) {
393 int hashValue = dvmComputeUtf8Hash(method->name);
394 bool found =
395 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
396 (char *) method->name,
397 (HashCompareFunc) strcmp, false) !=
398 NULL;
399 if (found) {
400 LOGD("Method %s (--> %s) found on the JIT %s list",
401 method->name, curMethodName,
402 gDvmJit.includeSelectedMethod ? "white" : "black");
403 return true;
404 }
405
406 }
407 ssaPtr = ((StackSaveArea *) ssaPtr->prevFrame) - 1;
408 };
409 return false;
410}
411
412/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700413 * Main entry point to start trace compilation. Basic blocks are constructed
414 * first and they will be passed to the codegen routines to convert Dalvik
415 * bytecode into machine code.
416 */
Bill Buzbee716f1202009-07-23 13:22:09 -0700417bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
Ben Cheng4a419582010-08-04 13:23:09 -0700418 JitTranslationInfo *info, jmp_buf *bailPtr,
419 int optHints)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700420{
421 const DexCode *dexCode = dvmGetMethodCode(desc->method);
422 const JitTraceRun* currRun = &desc->trace[0];
Ben Chengba4fc8b2009-06-01 13:00:29 -0700423 unsigned int curOffset = currRun->frag.startOffset;
424 unsigned int numInsts = currRun->frag.numInsts;
425 const u2 *codePtr = dexCode->insns + curOffset;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700426 int traceSize = 0; // # of half-words
Ben Chengba4fc8b2009-06-01 13:00:29 -0700427 const u2 *startCodePtr = codePtr;
Ben Cheng00603072010-10-28 11:13:58 -0700428 BasicBlock *curBB, *entryCodeBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700429 int numBlocks = 0;
430 static int compilationId;
431 CompilationUnit cUnit;
Ben Cheng00603072010-10-28 11:13:58 -0700432 GrowableList *blockList;
Ben Cheng1357e942010-02-10 17:21:39 -0800433#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700434 CompilerMethodStats *methodStats;
Ben Cheng1357e942010-02-10 17:21:39 -0800435#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700436
Bill Buzbee964a7b02010-01-28 12:54:19 -0800437 /* If we've already compiled this trace, just return success */
jeffhao9e45c0b2010-02-03 10:24:05 -0800438 if (dvmJitGetCodeAddr(startCodePtr) && !info->discardResult) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700439 /*
440 * Make sure the codeAddress is NULL so that it won't clobber the
441 * existing entry.
442 */
443 info->codeAddress = NULL;
Bill Buzbee964a7b02010-01-28 12:54:19 -0800444 return true;
445 }
446
Ben Chenge9695e52009-06-16 16:11:47 -0700447 compilationId++;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700448 memset(&cUnit, 0, sizeof(CompilationUnit));
449
Ben Cheng1357e942010-02-10 17:21:39 -0800450#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700451 /* Locate the entry to store compilation statistics for this method */
Ben Cheng7a2697d2010-06-07 13:44:23 -0700452 methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
Ben Cheng1357e942010-02-10 17:21:39 -0800453#endif
Ben Chenge9695e52009-06-16 16:11:47 -0700454
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800455 /* Set the recover buffer pointer */
456 cUnit.bailPtr = bailPtr;
457
Ben Chengba4fc8b2009-06-01 13:00:29 -0700458 /* Initialize the printMe flag */
459 cUnit.printMe = gDvmJit.printMe;
460
Ben Cheng7a2697d2010-06-07 13:44:23 -0700461 /* Setup the method */
462 cUnit.method = desc->method;
463
464 /* Initialize the PC reconstruction list */
465 dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
466
Ben Cheng00603072010-10-28 11:13:58 -0700467 /* Initialize the basic block list */
468 blockList = &cUnit.blockList;
469 dvmInitGrowableList(blockList, 8);
470
Ben Chengba4fc8b2009-06-01 13:00:29 -0700471 /* Identify traces that we don't want to compile */
472 if (gDvmJit.methodTable) {
473 int len = strlen(desc->method->clazz->descriptor) +
474 strlen(desc->method->name) + 1;
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800475 char *fullSignature = (char *)dvmCompilerNew(len, true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700476 strcpy(fullSignature, desc->method->clazz->descriptor);
477 strcat(fullSignature, desc->method->name);
478
479 int hashValue = dvmComputeUtf8Hash(fullSignature);
480
481 /*
482 * Doing three levels of screening to see whether we want to skip
483 * compiling this method
484 */
485
486 /* First, check the full "class;method" signature */
487 bool methodFound =
488 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
489 fullSignature, (HashCompareFunc) strcmp,
490 false) !=
491 NULL;
492
493 /* Full signature not found - check the enclosing class */
494 if (methodFound == false) {
495 int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
496 methodFound =
497 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
498 (char *) desc->method->clazz->descriptor,
499 (HashCompareFunc) strcmp, false) !=
500 NULL;
501 /* Enclosing class not found - check the method name */
502 if (methodFound == false) {
503 int hashValue = dvmComputeUtf8Hash(desc->method->name);
504 methodFound =
505 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
506 (char *) desc->method->name,
507 (HashCompareFunc) strcmp, false) !=
508 NULL;
Ben Cheng33672452010-01-12 14:59:30 -0800509
510 /*
511 * Debug by call-graph is enabled. Check if the debug list
512 * covers any methods on the VM stack.
513 */
514 if (methodFound == false && gDvmJit.checkCallGraph == true) {
515 methodFound =
516 filterMethodByCallGraph(info->requestingThread,
517 desc->method->name);
518 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700519 }
520 }
521
522 /*
523 * Under the following conditions, the trace will be *conservatively*
524 * compiled by only containing single-step instructions to and from the
525 * interpreter.
526 * 1) If includeSelectedMethod == false, the method matches the full or
527 * partial signature stored in the hash table.
528 *
529 * 2) If includeSelectedMethod == true, the method does not match the
530 * full and partial signature stored in the hash table.
531 */
532 if (gDvmJit.includeSelectedMethod != methodFound) {
533 cUnit.allSingleStep = true;
534 } else {
535 /* Compile the trace as normal */
536
537 /* Print the method we cherry picked */
538 if (gDvmJit.includeSelectedMethod == true) {
539 cUnit.printMe = true;
540 }
541 }
542 }
543
Ben Cheng4238ec22009-08-24 16:32:22 -0700544 /* Allocate the entry block */
Ben Cheng00603072010-10-28 11:13:58 -0700545 curBB = dvmCompilerNewBB(kTraceEntryBlock, numBlocks++);
546 dvmInsertGrowableList(blockList, (intptr_t) curBB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700547 curBB->startOffset = curOffset;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700548
Ben Cheng00603072010-10-28 11:13:58 -0700549 entryCodeBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
550 dvmInsertGrowableList(blockList, (intptr_t) entryCodeBB);
551 entryCodeBB->startOffset = curOffset;
552 curBB->fallThrough = entryCodeBB;
553 curBB = entryCodeBB;
Ben Cheng4238ec22009-08-24 16:32:22 -0700554
Ben Chengba4fc8b2009-06-01 13:00:29 -0700555 if (cUnit.printMe) {
556 LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n",
557 desc->method->name, curOffset);
558 }
559
Ben Cheng1efc9c52009-06-08 18:25:27 -0700560 /*
561 * Analyze the trace descriptor and include up to the maximal number
562 * of Dalvik instructions into the IR.
563 */
564 while (1) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700565 MIR *insn;
566 int width;
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800567 insn = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700568 insn->offset = curOffset;
569 width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700570
571 /* The trace should never incude instruction data */
572 assert(width);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700573 insn->width = width;
574 traceSize += width;
575 dvmCompilerAppendMIR(curBB, insn);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700576 cUnit.numInsts++;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700577
Dan Bornsteine4852762010-12-02 12:45:00 -0800578 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700579
Dan Bornstein0759f522010-11-30 14:58:53 -0800580 if (flags & kInstrInvoke) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700581 assert(numInsts == 1);
582 CallsiteInfo *callsiteInfo =
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800583 (CallsiteInfo *)dvmCompilerNew(sizeof(CallsiteInfo), true);
584 callsiteInfo->clazz = (ClassObject *)currRun[1].meta;
585 callsiteInfo->method = (Method *)currRun[2].meta;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700586 insn->meta.callsiteInfo = callsiteInfo;
587 }
588
Ben Cheng1efc9c52009-06-08 18:25:27 -0700589 /* Instruction limit reached - terminate the trace here */
590 if (cUnit.numInsts >= numMaxInsts) {
591 break;
592 }
593 if (--numInsts == 0) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700594 if (currRun->frag.runEnd) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700595 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700596 } else {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700597 /* Advance to the next trace description (ie non-meta info) */
598 do {
599 currRun++;
600 } while (!currRun->frag.isCode);
601
602 /* Dummy end-of-run marker seen */
603 if (currRun->frag.numInsts == 0) {
604 break;
605 }
606
Ben Cheng00603072010-10-28 11:13:58 -0700607 curBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
608 dvmInsertGrowableList(blockList, (intptr_t) curBB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700609 curOffset = currRun->frag.startOffset;
610 numInsts = currRun->frag.numInsts;
611 curBB->startOffset = curOffset;
612 codePtr = dexCode->insns + curOffset;
613 }
614 } else {
615 curOffset += width;
616 codePtr += width;
617 }
618 }
619
Ben Cheng1357e942010-02-10 17:21:39 -0800620#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700621 /* Convert # of half-word to bytes */
622 methodStats->compiledDalvikSize += traceSize * 2;
Ben Cheng1357e942010-02-10 17:21:39 -0800623#endif
Ben Cheng8b258bf2009-06-24 17:27:07 -0700624
Ben Chengba4fc8b2009-06-01 13:00:29 -0700625 /*
626 * Now scan basic blocks containing real code to connect the
627 * taken/fallthrough links. Also create chaining cells for code not included
628 * in the trace.
629 */
Ben Cheng00603072010-10-28 11:13:58 -0700630 size_t blockId;
631 for (blockId = 0; blockId < blockList->numUsed; blockId++) {
632 curBB = (BasicBlock *) dvmGrowableListGetElement(blockList, blockId);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700633 MIR *lastInsn = curBB->lastMIRInsn;
buzbee2e152ba2010-12-15 16:32:35 -0800634 BasicBlock *backwardCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700635 /* Skip empty blocks */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700636 if (lastInsn == NULL) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700637 continue;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700638 }
639 curOffset = lastInsn->offset;
640 unsigned int targetOffset = curOffset;
641 unsigned int fallThroughOffset = curOffset + lastInsn->width;
642 bool isInvoke = false;
643 const Method *callee = NULL;
644
645 findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
646 &targetOffset, &isInvoke, &callee);
647
648 /* Link the taken and fallthrough blocks */
649 BasicBlock *searchBB;
650
Dan Bornsteine4852762010-12-02 12:45:00 -0800651 int flags = dexGetFlagsFromOpcode(lastInsn->dalvikInsn.opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700652
653 if (flags & kInstrInvoke) {
654 cUnit.hasInvoke = true;
655 }
656
Ben Chengba4fc8b2009-06-01 13:00:29 -0700657 /* No backward branch in the trace - start searching the next BB */
Ben Cheng00603072010-10-28 11:13:58 -0700658 size_t searchBlockId;
659 for (searchBlockId = blockId+1; searchBlockId < blockList->numUsed;
660 searchBlockId++) {
661 searchBB = (BasicBlock *) dvmGrowableListGetElement(blockList,
662 searchBlockId);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700663 if (targetOffset == searchBB->startOffset) {
664 curBB->taken = searchBB;
665 }
666 if (fallThroughOffset == searchBB->startOffset) {
667 curBB->fallThrough = searchBB;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700668
669 /*
670 * Fallthrough block of an invoke instruction needs to be
671 * aligned to 4-byte boundary (alignment instruction to be
672 * inserted later.
673 */
674 if (flags & kInstrInvoke) {
675 searchBB->isFallThroughFromInvoke = true;
676 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700677 }
678 }
679
Ben Cheng1efc9c52009-06-08 18:25:27 -0700680 /*
681 * Some blocks are ended by non-control-flow-change instructions,
682 * currently only due to trace length constraint. In this case we need
683 * to generate an explicit branch at the end of the block to jump to
684 * the chaining cell.
685 */
686 curBB->needFallThroughBranch =
Ben Cheng17f15ce2009-07-27 16:21:52 -0700687 ((flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
Dan Bornstein0759f522010-11-30 14:58:53 -0800688 kInstrInvoke)) == 0);
Ben Cheng17f15ce2009-07-27 16:21:52 -0700689
Ben Cheng4a419582010-08-04 13:23:09 -0700690 /* Only form a loop if JIT_OPT_NO_LOOP is not set */
Ben Cheng4238ec22009-08-24 16:32:22 -0700691 if (curBB->taken == NULL &&
692 curBB->fallThrough == NULL &&
693 flags == (kInstrCanBranch | kInstrCanContinue) &&
Ben Cheng00603072010-10-28 11:13:58 -0700694 fallThroughOffset == entryCodeBB->startOffset &&
Ben Cheng4a419582010-08-04 13:23:09 -0700695 JIT_OPT_NO_LOOP != (optHints & JIT_OPT_NO_LOOP)) {
Ben Cheng0fd31e42009-09-03 14:40:16 -0700696 BasicBlock *loopBranch = curBB;
697 BasicBlock *exitBB;
698 BasicBlock *exitChainingCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700699
700 if (cUnit.printMe) {
701 LOGD("Natural loop detected!");
702 }
Ben Cheng00603072010-10-28 11:13:58 -0700703 exitBB = dvmCompilerNewBB(kTraceExitBlock, numBlocks++);
704 dvmInsertGrowableList(blockList, (intptr_t) exitBB);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700705 exitBB->startOffset = targetOffset;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700706 exitBB->needFallThroughBranch = true;
Ben Cheng4238ec22009-08-24 16:32:22 -0700707
Ben Cheng0fd31e42009-09-03 14:40:16 -0700708 loopBranch->taken = exitBB;
buzbee2e152ba2010-12-15 16:32:35 -0800709 backwardCell =
Ben Cheng00603072010-10-28 11:13:58 -0700710 dvmCompilerNewBB(kChainingCellBackwardBranch, numBlocks++);
711 dvmInsertGrowableList(blockList, (intptr_t) backwardCell);
712 backwardCell->startOffset = entryCodeBB->startOffset;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700713 loopBranch->fallThrough = backwardCell;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700714
715 /* Create the chaining cell as the fallthrough of the exit block */
Ben Cheng00603072010-10-28 11:13:58 -0700716 exitChainingCell = dvmCompilerNewBB(kChainingCellNormal,
717 numBlocks++);
718 dvmInsertGrowableList(blockList, (intptr_t) exitChainingCell);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700719 exitChainingCell->startOffset = targetOffset;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700720
721 exitBB->fallThrough = exitChainingCell;
722
Ben Cheng4238ec22009-08-24 16:32:22 -0700723 cUnit.hasLoop = true;
724 }
725
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800726 if (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ||
727 lastInsn->dalvikInsn.opcode == OP_SPARSE_SWITCH) {
Ben Cheng6c10a972009-10-29 14:39:18 -0700728 int i;
729 const u2 *switchData = desc->method->insns + lastInsn->offset +
730 lastInsn->dalvikInsn.vB;
731 int size = switchData[1];
732 int maxChains = MIN(size, MAX_CHAINED_SWITCH_CASES);
733
734 /*
735 * Generate the landing pad for cases whose ranks are higher than
736 * MAX_CHAINED_SWITCH_CASES. The code will re-enter the interpreter
737 * through the NoChain point.
738 */
739 if (maxChains != size) {
740 cUnit.switchOverflowPad =
741 desc->method->insns + lastInsn->offset;
742 }
743
744 s4 *targets = (s4 *) (switchData + 2 +
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800745 (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ?
Ben Cheng6c10a972009-10-29 14:39:18 -0700746 2 : size * 2));
747
748 /* One chaining cell for the first MAX_CHAINED_SWITCH_CASES cases */
749 for (i = 0; i < maxChains; i++) {
Ben Cheng00603072010-10-28 11:13:58 -0700750 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal,
751 numBlocks++);
752 dvmInsertGrowableList(blockList, (intptr_t) caseChain);
Ben Cheng6c10a972009-10-29 14:39:18 -0700753 caseChain->startOffset = lastInsn->offset + targets[i];
Ben Cheng6c10a972009-10-29 14:39:18 -0700754 }
755
756 /* One more chaining cell for the default case */
Ben Cheng00603072010-10-28 11:13:58 -0700757 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal,
758 numBlocks++);
759 dvmInsertGrowableList(blockList, (intptr_t) caseChain);
Ben Cheng6c10a972009-10-29 14:39:18 -0700760 caseChain->startOffset = lastInsn->offset + lastInsn->width;
Ben Cheng6d576092009-09-01 17:01:58 -0700761 /* Fallthrough block not included in the trace */
Ben Cheng6c10a972009-10-29 14:39:18 -0700762 } else if (!isUnconditionalBranch(lastInsn) &&
763 curBB->fallThrough == NULL) {
Ben Cheng00603072010-10-28 11:13:58 -0700764 BasicBlock *fallThroughBB;
Ben Cheng6d576092009-09-01 17:01:58 -0700765 /*
766 * If the chaining cell is after an invoke or
767 * instruction that cannot change the control flow, request a hot
768 * chaining cell.
769 */
770 if (isInvoke || curBB->needFallThroughBranch) {
Ben Cheng00603072010-10-28 11:13:58 -0700771 fallThroughBB = dvmCompilerNewBB(kChainingCellHot, numBlocks++);
Ben Cheng6d576092009-09-01 17:01:58 -0700772 } else {
Ben Cheng00603072010-10-28 11:13:58 -0700773 fallThroughBB = dvmCompilerNewBB(kChainingCellNormal,
774 numBlocks++);
Ben Cheng6d576092009-09-01 17:01:58 -0700775 }
Ben Cheng00603072010-10-28 11:13:58 -0700776 dvmInsertGrowableList(blockList, (intptr_t) fallThroughBB);
777 fallThroughBB->startOffset = fallThroughOffset;
778 curBB->fallThrough = fallThroughBB;
Ben Cheng6d576092009-09-01 17:01:58 -0700779 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700780 /* Target block not included in the trace */
Ben Cheng38329f52009-07-07 14:19:20 -0700781 if (curBB->taken == NULL &&
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800782 (isGoto(lastInsn) || isInvoke ||
783 (targetOffset != UNKNOWN_TARGET && targetOffset != curOffset))) {
Ben Cheng38329f52009-07-07 14:19:20 -0700784 BasicBlock *newBB;
Ben Cheng1efc9c52009-06-08 18:25:27 -0700785 if (isInvoke) {
Ben Cheng38329f52009-07-07 14:19:20 -0700786 /* Monomorphic callee */
787 if (callee) {
Ben Cheng00603072010-10-28 11:13:58 -0700788 newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton,
789 numBlocks++);
Ben Cheng38329f52009-07-07 14:19:20 -0700790 newBB->startOffset = 0;
791 newBB->containingMethod = callee;
792 /* Will resolve at runtime */
793 } else {
Ben Cheng00603072010-10-28 11:13:58 -0700794 newBB = dvmCompilerNewBB(kChainingCellInvokePredicted,
795 numBlocks++);
Ben Cheng38329f52009-07-07 14:19:20 -0700796 newBB->startOffset = 0;
797 }
Ben Cheng1efc9c52009-06-08 18:25:27 -0700798 /* For unconditional branches, request a hot chaining cell */
799 } else {
Jeff Hao97319a82009-08-12 16:57:15 -0700800#if !defined(WITH_SELF_VERIFICATION)
Dan Bornsteinc2b486f2010-11-12 16:07:16 -0800801 newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700802 kChainingCellHot :
Ben Cheng00603072010-10-28 11:13:58 -0700803 kChainingCellNormal,
804 numBlocks++);
Ben Cheng38329f52009-07-07 14:19:20 -0700805 newBB->startOffset = targetOffset;
Jeff Hao97319a82009-08-12 16:57:15 -0700806#else
807 /* Handle branches that branch back into the block */
808 if (targetOffset >= curBB->firstMIRInsn->offset &&
809 targetOffset <= curBB->lastMIRInsn->offset) {
Ben Cheng00603072010-10-28 11:13:58 -0700810 newBB = dvmCompilerNewBB(kChainingCellBackwardBranch,
811 numBlocks++);
Jeff Hao97319a82009-08-12 16:57:15 -0700812 } else {
Dan Bornsteinc2b486f2010-11-12 16:07:16 -0800813 newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700814 kChainingCellHot :
Ben Cheng00603072010-10-28 11:13:58 -0700815 kChainingCellNormal,
816 numBlocks++);
Jeff Hao97319a82009-08-12 16:57:15 -0700817 }
818 newBB->startOffset = targetOffset;
819#endif
Ben Cheng1efc9c52009-06-08 18:25:27 -0700820 }
Ben Cheng38329f52009-07-07 14:19:20 -0700821 curBB->taken = newBB;
Ben Cheng00603072010-10-28 11:13:58 -0700822 dvmInsertGrowableList(blockList, (intptr_t) newBB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700823 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700824 }
825
826 /* Now create a special block to host PC reconstruction code */
Ben Cheng00603072010-10-28 11:13:58 -0700827 curBB = dvmCompilerNewBB(kPCReconstruction, numBlocks++);
828 dvmInsertGrowableList(blockList, (intptr_t) curBB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700829
830 /* And one final block that publishes the PC and raise the exception */
Ben Cheng00603072010-10-28 11:13:58 -0700831 curBB = dvmCompilerNewBB(kExceptionHandling, numBlocks++);
832 dvmInsertGrowableList(blockList, (intptr_t) curBB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700833
834 if (cUnit.printMe) {
Ben Cheng00603072010-10-28 11:13:58 -0700835 char* signature =
836 dexProtoCopyMethodDescriptor(&desc->method->prototype);
Elliott Hughescc6fac82010-07-02 13:38:44 -0700837 LOGD("TRACEINFO (%d): 0x%08x %s%s.%s 0x%x %d of %d, %d blocks",
Ben Chenge9695e52009-06-16 16:11:47 -0700838 compilationId,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700839 (intptr_t) desc->method->insns,
840 desc->method->clazz->descriptor,
841 desc->method->name,
Elliott Hughescc6fac82010-07-02 13:38:44 -0700842 signature,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700843 desc->trace[0].frag.startOffset,
844 traceSize,
845 dexCode->insnsSize,
846 numBlocks);
Elliott Hughescc6fac82010-07-02 13:38:44 -0700847 free(signature);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700848 }
849
Ben Chengba4fc8b2009-06-01 13:00:29 -0700850 cUnit.traceDesc = desc;
851 cUnit.numBlocks = numBlocks;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700852
Ben Cheng7a2697d2010-06-07 13:44:23 -0700853 /* Set the instruction set to use (NOTE: later components may change it) */
854 cUnit.instructionSet = dvmCompilerInstructionSet();
855
856 /* Inline transformation @ the MIR level */
857 if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) {
858 dvmCompilerInlineMIR(&cUnit);
859 }
860
Ben Cheng00603072010-10-28 11:13:58 -0700861 cUnit.numDalvikRegisters = cUnit.method->registersSize;
862
Ben Cheng4238ec22009-08-24 16:32:22 -0700863 /* Preparation for SSA conversion */
864 dvmInitializeSSAConversion(&cUnit);
865
866 if (cUnit.hasLoop) {
Ben Cheng4a419582010-08-04 13:23:09 -0700867 /*
868 * Loop is not optimizable (for example lack of a single induction
869 * variable), punt and recompile the trace with loop optimization
870 * disabled.
871 */
872 bool loopOpt = dvmCompilerLoopOpt(&cUnit);
873 if (loopOpt == false) {
874 if (cUnit.printMe) {
875 LOGD("Loop is not optimizable - retry codegen");
876 }
877 /* Reset the compiler resource pool */
878 dvmCompilerArenaReset();
879 return dvmCompileTrace(desc, cUnit.numInsts, info, bailPtr,
880 optHints | JIT_OPT_NO_LOOP);
881 }
Ben Cheng4238ec22009-08-24 16:32:22 -0700882 }
883 else {
884 dvmCompilerNonLoopAnalysis(&cUnit);
885 }
886
Bill Buzbee1465db52009-09-23 17:17:35 -0700887 dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
888
Ben Chengba4fc8b2009-06-01 13:00:29 -0700889 if (cUnit.printMe) {
890 dvmCompilerDumpCompilationUnit(&cUnit);
891 }
892
buzbee23d95d02010-12-14 13:16:43 -0800893 /* Allocate Registers using simple local allocation scheme */
894 dvmCompilerLocalRegAlloc(&cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700895
Ben Chengba4fc8b2009-06-01 13:00:29 -0700896 /* Convert MIR to LIR, etc. */
897 dvmCompilerMIR2LIR(&cUnit);
898
buzbeebff121a2010-08-04 15:25:06 -0700899 /* Convert LIR into machine code. Loop for recoverable retries */
900 do {
901 dvmCompilerAssembleLIR(&cUnit, info);
902 cUnit.assemblerRetries++;
903 if (cUnit.printMe && cUnit.assemblerStatus != kSuccess)
904 LOGD("Assembler abort #%d on %d",cUnit.assemblerRetries,
905 cUnit.assemblerStatus);
906 } while (cUnit.assemblerStatus == kRetryAll);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700907
908 if (cUnit.printMe) {
buzbeebff121a2010-08-04 15:25:06 -0700909 dvmCompilerCodegenDump(&cUnit);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700910 LOGD("End %s%s, %d Dalvik instructions",
911 desc->method->clazz->descriptor, desc->method->name,
912 cUnit.numInsts);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700913 }
914
915 /* Reset the compiler resource pool */
916 dvmCompilerArenaReset();
917
buzbeebff121a2010-08-04 15:25:06 -0700918 if (cUnit.assemblerStatus == kRetryHalve) {
919 /* Halve the instruction count and start from the top */
Ben Cheng4a419582010-08-04 13:23:09 -0700920 return dvmCompileTrace(desc, cUnit.numInsts / 2, info, bailPtr,
921 optHints);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700922 }
buzbeebff121a2010-08-04 15:25:06 -0700923
924 assert(cUnit.assemblerStatus == kSuccess);
925#if defined(WITH_JIT_TUNING)
926 methodStats->nativeSize += cUnit.totalSize;
927#endif
Ben Cheng00603072010-10-28 11:13:58 -0700928
929 /* FIXME - to exercise the method parser, uncomment the following code */
930#if 0
931 bool dvmCompileMethod(const Method *method);
932 if (desc->trace[0].frag.startOffset == 0) {
933 dvmCompileMethod(desc->method);
934 }
935#endif
936
buzbeebff121a2010-08-04 15:25:06 -0700937 return info->codeAddress != NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700938}
939
940/*
Ben Cheng7a2697d2010-06-07 13:44:23 -0700941 * Since we are including instructions from possibly a cold method into the
942 * current trace, we need to make sure that all the associated information
943 * with the callee is properly initialized. If not, we punt on this inline
944 * target.
945 *
Ben Cheng34dc7962010-08-26 14:56:31 -0700946 * TODO: volatile instructions will be handled later.
Ben Cheng7a2697d2010-06-07 13:44:23 -0700947 */
948bool dvmCompilerCanIncludeThisInstruction(const Method *method,
949 const DecodedInstruction *insn)
950{
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800951 switch (insn->opcode) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700952 case OP_NEW_INSTANCE:
953 case OP_CHECK_CAST: {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800954 ClassObject *classPtr = (ClassObject *)(void*)
Ben Cheng7a2697d2010-06-07 13:44:23 -0700955 (method->clazz->pDvmDex->pResClasses[insn->vB]);
956
957 /* Class hasn't been initialized yet */
958 if (classPtr == NULL) {
959 return false;
960 }
961 return true;
962 }
963 case OP_SGET_OBJECT:
964 case OP_SGET_BOOLEAN:
965 case OP_SGET_CHAR:
966 case OP_SGET_BYTE:
967 case OP_SGET_SHORT:
968 case OP_SGET:
969 case OP_SGET_WIDE:
970 case OP_SPUT_OBJECT:
971 case OP_SPUT_BOOLEAN:
972 case OP_SPUT_CHAR:
973 case OP_SPUT_BYTE:
974 case OP_SPUT_SHORT:
975 case OP_SPUT:
976 case OP_SPUT_WIDE: {
977 void *fieldPtr = (void*)
978 (method->clazz->pDvmDex->pResFields[insn->vB]);
979
980 if (fieldPtr == NULL) {
981 return false;
982 }
983 return true;
984 }
985 case OP_INVOKE_SUPER:
986 case OP_INVOKE_SUPER_RANGE: {
987 int mIndex = method->clazz->pDvmDex->
988 pResMethods[insn->vB]->methodIndex;
989 const Method *calleeMethod = method->clazz->super->vtable[mIndex];
990 if (calleeMethod == NULL) {
991 return false;
992 }
993 return true;
994 }
995 case OP_INVOKE_SUPER_QUICK:
996 case OP_INVOKE_SUPER_QUICK_RANGE: {
997 const Method *calleeMethod = method->clazz->super->vtable[insn->vB];
998 if (calleeMethod == NULL) {
999 return false;
1000 }
1001 return true;
1002 }
1003 case OP_INVOKE_STATIC:
1004 case OP_INVOKE_STATIC_RANGE:
1005 case OP_INVOKE_DIRECT:
1006 case OP_INVOKE_DIRECT_RANGE: {
1007 const Method *calleeMethod =
1008 method->clazz->pDvmDex->pResMethods[insn->vB];
1009 if (calleeMethod == NULL) {
1010 return false;
1011 }
1012 return true;
1013 }
1014 case OP_CONST_CLASS: {
1015 void *classPtr = (void*)
1016 (method->clazz->pDvmDex->pResClasses[insn->vB]);
1017
1018 if (classPtr == NULL) {
1019 return false;
1020 }
1021 return true;
1022 }
1023 case OP_CONST_STRING_JUMBO:
1024 case OP_CONST_STRING: {
1025 void *strPtr = (void*)
1026 (method->clazz->pDvmDex->pResStrings[insn->vB]);
1027
1028 if (strPtr == NULL) {
1029 return false;
1030 }
1031 return true;
1032 }
1033 default:
1034 return true;
1035 }
1036}
1037
Ben Cheng00603072010-10-28 11:13:58 -07001038/* Split an existing block from the specified code offset into two */
1039static BasicBlock *splitBlock(CompilationUnit *cUnit,
1040 unsigned int codeOffset,
1041 BasicBlock *origBlock)
1042{
1043 MIR *insn = origBlock->firstMIRInsn;
1044 while (insn) {
1045 if (insn->offset == codeOffset) break;
1046 insn = insn->next;
1047 }
1048 if (insn == NULL) {
1049 LOGE("Break split failed");
1050 dvmAbort();
1051 }
1052 BasicBlock *bottomBlock = dvmCompilerNewBB(kDalvikByteCode,
1053 cUnit->numBlocks++);
1054 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bottomBlock);
1055
1056 bottomBlock->startOffset = codeOffset;
1057 bottomBlock->firstMIRInsn = insn;
1058 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
1059
Ben Cheng00603072010-10-28 11:13:58 -07001060 /* Handle the taken path */
1061 bottomBlock->taken = origBlock->taken;
1062 if (bottomBlock->taken) {
1063 origBlock->taken = NULL;
1064 dvmCompilerClearBit(bottomBlock->taken->predecessors, origBlock->id);
1065 dvmCompilerSetBit(bottomBlock->taken->predecessors, bottomBlock->id);
1066 }
1067
1068 /* Handle the fallthrough path */
1069 bottomBlock->fallThrough = origBlock->fallThrough;
1070 origBlock->fallThrough = bottomBlock;
1071 dvmCompilerSetBit(bottomBlock->predecessors, origBlock->id);
1072 if (bottomBlock->fallThrough) {
1073 dvmCompilerClearBit(bottomBlock->fallThrough->predecessors,
1074 origBlock->id);
1075 dvmCompilerSetBit(bottomBlock->fallThrough->predecessors,
1076 bottomBlock->id);
1077 }
1078
1079 /* Handle the successor list */
1080 if (origBlock->successorBlockList.blockListType != kNotUsed) {
1081 bottomBlock->successorBlockList = origBlock->successorBlockList;
1082 origBlock->successorBlockList.blockListType = kNotUsed;
1083 GrowableListIterator iterator;
1084
1085 dvmGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
1086 &iterator);
1087 while (true) {
Ben Cheng7a02cb12010-12-15 14:18:31 -08001088 SuccessorBlockInfo *successorBlockInfo =
1089 (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
1090 if (successorBlockInfo == NULL) break;
1091 BasicBlock *bb = successorBlockInfo->block;
Ben Cheng00603072010-10-28 11:13:58 -07001092 dvmCompilerClearBit(bb->predecessors, origBlock->id);
1093 dvmCompilerSetBit(bb->predecessors, bottomBlock->id);
1094 }
1095 }
1096
1097 origBlock->lastMIRInsn = insn->prev;
Ben Cheng00603072010-10-28 11:13:58 -07001098
1099 insn->prev->next = NULL;
1100 insn->prev = NULL;
1101 return bottomBlock;
1102}
1103
1104/*
1105 * Given a code offset, find out the block that starts with it. If the offset
1106 * is in the middle of an existing block, split it into two.
1107 */
1108static BasicBlock *findBlock(CompilationUnit *cUnit,
1109 unsigned int codeOffset,
1110 bool split, bool create)
1111{
1112 GrowableList *blockList = &cUnit->blockList;
1113 BasicBlock *bb;
1114 unsigned int i;
1115
1116 for (i = 0; i < blockList->numUsed; i++) {
1117 bb = (BasicBlock *) blockList->elemList[i];
1118 if (bb->blockType != kDalvikByteCode) continue;
1119 if (bb->startOffset == codeOffset) return bb;
1120 /* Check if a branch jumps into the middle of an existing block */
1121 if ((split == true) && (codeOffset > bb->startOffset) &&
1122 (bb->lastMIRInsn != NULL) &&
1123 (codeOffset <= bb->lastMIRInsn->offset)) {
1124 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb);
1125 return newBB;
1126 }
1127 }
1128 if (create) {
1129 bb = dvmCompilerNewBB(kDalvikByteCode, cUnit->numBlocks++);
1130 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
1131 bb->startOffset = codeOffset;
1132 return bb;
1133 }
1134 return NULL;
1135}
1136
1137/* Dump the CFG into a DOT graph */
1138void dumpCFG(CompilationUnit *cUnit, const char *dirPrefix)
1139{
1140 const Method *method = cUnit->method;
1141 FILE *file;
1142 char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
1143 char *fileName = (char *) dvmCompilerNew(
1144 strlen(dirPrefix) +
1145 strlen(method->clazz->descriptor) +
1146 strlen(method->name) +
1147 strlen(signature) +
1148 strlen(".dot") + 1, true);
1149 sprintf(fileName, "%s%s%s%s.dot", dirPrefix,
1150 method->clazz->descriptor, method->name, signature);
1151 free(signature);
1152
1153 /*
1154 * Convert the special characters into a filesystem- and shell-friendly
1155 * format.
1156 */
1157 int i;
1158 for (i = strlen(dirPrefix); fileName[i]; i++) {
1159 if (fileName[i] == '/') {
1160 fileName[i] = '_';
1161 } else if (fileName[i] == ';') {
1162 fileName[i] = '#';
1163 } else if (fileName[i] == '$') {
1164 fileName[i] = '+';
1165 } else if (fileName[i] == '(' || fileName[i] == ')') {
1166 fileName[i] = '@';
1167 } else if (fileName[i] == '<' || fileName[i] == '>') {
1168 fileName[i] = '=';
1169 }
1170 }
1171 file = fopen(fileName, "w");
1172 if (file == NULL) {
1173 return;
1174 }
1175 fprintf(file, "digraph G {\n");
1176
1177 fprintf(file, " rankdir=TB\n");
1178
1179 int numReachableBlocks = cUnit->numReachableBlocks;
1180 int idx;
1181 const GrowableList *blockList = &cUnit->blockList;
1182
1183 for (idx = 0; idx < numReachableBlocks; idx++) {
1184 int blockIdx = cUnit->dfsOrder.elemList[idx];
1185 BasicBlock *bb = (BasicBlock *) dvmGrowableListGetElement(blockList,
1186 blockIdx);
1187 if (bb == NULL) break;
1188 if (bb->blockType == kMethodEntryBlock) {
1189 fprintf(file, " entry [shape=Mdiamond];\n");
1190 } else if (bb->blockType == kMethodExitBlock) {
1191 fprintf(file, " exit [shape=Mdiamond];\n");
1192 } else if (bb->blockType == kDalvikByteCode) {
Ben Cheng7a02cb12010-12-15 14:18:31 -08001193 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
1194 bb->startOffset);
Ben Cheng00603072010-10-28 11:13:58 -07001195 const MIR *mir;
1196 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1197 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
1198 dvmCompilerFullDisassembler(cUnit, mir),
1199 mir->next ? " | " : " ");
1200 }
1201 fprintf(file, " }\"];\n\n");
1202 } else if (bb->blockType == kExceptionHandling) {
1203 char blockName[BLOCK_NAME_LEN];
1204
1205 dvmGetBlockName(bb, blockName);
1206 fprintf(file, " %s [shape=invhouse];\n", blockName);
1207 }
1208
1209 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
1210
1211 if (bb->taken) {
1212 dvmGetBlockName(bb, blockName1);
1213 dvmGetBlockName(bb->taken, blockName2);
1214 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
1215 blockName1, blockName2);
1216 }
1217 if (bb->fallThrough) {
1218 dvmGetBlockName(bb, blockName1);
1219 dvmGetBlockName(bb->fallThrough, blockName2);
1220 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
1221 }
1222
1223 if (bb->successorBlockList.blockListType != kNotUsed) {
1224 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
1225 bb->startOffset,
1226 (bb->successorBlockList.blockListType == kCatch) ?
1227 "Mrecord" : "record");
1228 GrowableListIterator iterator;
1229 dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
1230 &iterator);
Ben Cheng7a02cb12010-12-15 14:18:31 -08001231 SuccessorBlockInfo *successorBlockInfo =
1232 (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
Ben Cheng00603072010-10-28 11:13:58 -07001233
1234 int succId = 0;
1235 while (true) {
Ben Cheng7a02cb12010-12-15 14:18:31 -08001236 if (successorBlockInfo == NULL) break;
1237
1238 BasicBlock *destBlock = successorBlockInfo->block;
1239 SuccessorBlockInfo *nextSuccessorBlockInfo =
1240 (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
1241
1242 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
Ben Cheng00603072010-10-28 11:13:58 -07001243 succId++,
Ben Cheng7a02cb12010-12-15 14:18:31 -08001244 successorBlockInfo->key,
Ben Cheng00603072010-10-28 11:13:58 -07001245 destBlock->startOffset,
Ben Cheng7a02cb12010-12-15 14:18:31 -08001246 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
1247
1248 successorBlockInfo = nextSuccessorBlockInfo;
Ben Cheng00603072010-10-28 11:13:58 -07001249 }
1250 fprintf(file, " }\"];\n\n");
1251
1252 dvmGetBlockName(bb, blockName1);
1253 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
1254 blockName1, bb->startOffset);
1255
1256 if (bb->successorBlockList.blockListType == kPackedSwitch ||
1257 bb->successorBlockList.blockListType == kSparseSwitch) {
1258
1259 dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
1260 &iterator);
1261
1262 succId = 0;
1263 while (true) {
Ben Cheng7a02cb12010-12-15 14:18:31 -08001264 SuccessorBlockInfo *successorBlockInfo =
1265 (SuccessorBlockInfo *)
1266 dvmGrowableListIteratorNext(&iterator);
1267 if (successorBlockInfo == NULL) break;
1268
1269 BasicBlock *destBlock = successorBlockInfo->block;
Ben Cheng00603072010-10-28 11:13:58 -07001270
1271 dvmGetBlockName(destBlock, blockName2);
1272 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
1273 bb->startOffset, succId++,
1274 blockName2);
1275 }
1276 }
1277 }
1278 fprintf(file, "\n");
1279
1280 /*
1281 * If we need to debug the dominator tree, uncomment the following code
1282 */
1283#if 0
1284 dvmGetBlockName(bb, blockName1);
1285 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
1286 blockName1, blockName1);
1287 if (bb->iDom) {
1288 dvmGetBlockName(bb->iDom, blockName2);
1289 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
1290 blockName2, blockName1);
1291 }
1292#endif
1293 }
1294 fprintf(file, "}\n");
1295 fclose(file);
1296}
1297
1298/* Verify if all the successor is connected with all the claimed predecessors */
1299static bool verifyPredInfo(CompilationUnit *cUnit, BasicBlock *bb)
1300{
1301 BitVectorIterator bvIterator;
1302
1303 dvmBitVectorIteratorInit(bb->predecessors, &bvIterator);
1304 while (true) {
1305 int blockIdx = dvmBitVectorIteratorNext(&bvIterator);
1306 if (blockIdx == -1) break;
1307 BasicBlock *predBB = (BasicBlock *)
1308 dvmGrowableListGetElement(&cUnit->blockList, blockIdx);
1309 bool found = false;
1310 if (predBB->taken == bb) {
1311 found = true;
1312 } else if (predBB->fallThrough == bb) {
1313 found = true;
1314 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
1315 GrowableListIterator iterator;
1316 dvmGrowableListIteratorInit(&predBB->successorBlockList.blocks,
1317 &iterator);
1318 while (true) {
Ben Cheng7a02cb12010-12-15 14:18:31 -08001319 SuccessorBlockInfo *successorBlockInfo =
1320 (SuccessorBlockInfo *)
1321 dvmGrowableListIteratorNext(&iterator);
1322 if (successorBlockInfo == NULL) break;
1323 BasicBlock *succBB = successorBlockInfo->block;
Ben Cheng00603072010-10-28 11:13:58 -07001324 if (succBB == bb) {
1325 found = true;
1326 break;
1327 }
1328 }
1329 }
1330 if (found == false) {
1331 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
1332 dvmGetBlockName(bb, blockName1);
1333 dvmGetBlockName(predBB, blockName2);
1334 dumpCFG(cUnit, "/data/tombstones/");
1335 LOGE("Successor %s not found from %s",
1336 blockName1, blockName2);
1337 dvmAbort();
1338 }
1339 }
1340 return true;
1341}
1342
1343/* Identify code range in try blocks and set up the empty catch blocks */
1344static void processTryCatchBlocks(CompilationUnit *cUnit)
1345{
1346 const Method *meth = cUnit->method;
1347 const DexCode *pCode = dvmGetMethodCode(meth);
1348 int triesSize = pCode->triesSize;
1349 int i;
1350 int offset;
1351
1352 if (triesSize == 0) {
1353 return;
1354 }
1355
1356 const DexTry *pTries = dexGetTries(pCode);
1357 BitVector *tryBlockAddr = cUnit->tryBlockAddr;
1358
1359 /* Mark all the insn offsets in Try blocks */
1360 for (i = 0; i < triesSize; i++) {
1361 const DexTry* pTry = &pTries[i];
1362 /* all in 16-bit units */
1363 int startOffset = pTry->startAddr;
1364 int endOffset = startOffset + pTry->insnCount;
1365
1366 for (offset = startOffset; offset < endOffset; offset++) {
1367 dvmCompilerSetBit(tryBlockAddr, offset);
1368 }
1369 }
1370
1371 /* Iterate over each of the handlers to enqueue the empty Catch blocks */
1372 offset = dexGetFirstHandlerOffset(pCode);
1373 int handlersSize = dexGetHandlersSize(pCode);
1374
1375 for (i = 0; i < handlersSize; i++) {
1376 DexCatchIterator iterator;
1377 dexCatchIteratorInit(&iterator, pCode, offset);
1378
1379 for (;;) {
1380 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
1381
1382 if (handler == NULL) {
1383 break;
1384 }
1385
Ben Cheng7a02cb12010-12-15 14:18:31 -08001386 /*
1387 * Create dummy catch blocks first. Since these are created before
1388 * other blocks are processed, "split" is specified as false.
1389 */
1390 findBlock(cUnit, handler->address,
1391 /* split */
1392 false,
1393 /* create */
1394 true);
Ben Cheng00603072010-10-28 11:13:58 -07001395 }
1396
1397 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
1398 }
1399}
1400
1401/* Process instructions with the kInstrCanBranch flag */
1402static void processCanBranch(CompilationUnit *cUnit, BasicBlock *curBlock,
1403 MIR *insn, int curOffset, int width, int flags,
1404 const u2* codePtr, const u2* codeEnd)
1405{
1406 int target = curOffset;
1407 switch (insn->dalvikInsn.opcode) {
1408 case OP_GOTO:
1409 case OP_GOTO_16:
1410 case OP_GOTO_32:
1411 target += (int) insn->dalvikInsn.vA;
1412 break;
1413 case OP_IF_EQ:
1414 case OP_IF_NE:
1415 case OP_IF_LT:
1416 case OP_IF_GE:
1417 case OP_IF_GT:
1418 case OP_IF_LE:
1419 target += (int) insn->dalvikInsn.vC;
1420 break;
1421 case OP_IF_EQZ:
1422 case OP_IF_NEZ:
1423 case OP_IF_LTZ:
1424 case OP_IF_GEZ:
1425 case OP_IF_GTZ:
1426 case OP_IF_LEZ:
1427 target += (int) insn->dalvikInsn.vB;
1428 break;
1429 default:
1430 LOGE("Unexpected opcode(%d) with kInstrCanBranch set",
1431 insn->dalvikInsn.opcode);
1432 dvmAbort();
1433 }
1434 BasicBlock *takenBlock = findBlock(cUnit, target,
1435 /* split */
1436 true,
1437 /* create */
1438 true);
1439 curBlock->taken = takenBlock;
1440 dvmCompilerSetBit(takenBlock->predecessors, curBlock->id);
1441
1442 /* Always terminate the current block for conditional branches */
1443 if (flags & kInstrCanContinue) {
1444 BasicBlock *fallthroughBlock = findBlock(cUnit,
1445 curOffset + width,
1446 /* split */
1447 false,
1448 /* create */
1449 true);
1450 curBlock->fallThrough = fallthroughBlock;
1451 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
1452 } else if (codePtr < codeEnd) {
1453 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
1454 if (contentIsInsn(codePtr)) {
1455 findBlock(cUnit, curOffset + width,
1456 /* split */
1457 false,
1458 /* create */
1459 true);
1460 }
1461 }
1462}
1463
1464/* Process instructions with the kInstrCanSwitch flag */
1465static void processCanSwitch(CompilationUnit *cUnit, BasicBlock *curBlock,
1466 MIR *insn, int curOffset, int width, int flags)
1467{
1468 u2 *switchData= (u2 *) (cUnit->method->insns + curOffset +
1469 insn->dalvikInsn.vB);
1470 int size;
Ben Cheng7a02cb12010-12-15 14:18:31 -08001471 int *keyTable;
Ben Cheng00603072010-10-28 11:13:58 -07001472 int *targetTable;
1473 int i;
Ben Cheng7a02cb12010-12-15 14:18:31 -08001474 int firstKey;
Ben Cheng00603072010-10-28 11:13:58 -07001475
1476 /*
1477 * Packed switch data format:
1478 * ushort ident = 0x0100 magic value
1479 * ushort size number of entries in the table
1480 * int first_key first (and lowest) switch case value
1481 * int targets[size] branch targets, relative to switch opcode
1482 *
1483 * Total size is (4+size*2) 16-bit code units.
1484 */
1485 if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
1486 assert(switchData[0] == kPackedSwitchSignature);
1487 size = switchData[1];
Ben Cheng7a02cb12010-12-15 14:18:31 -08001488 firstKey = switchData[2] | (switchData[3] << 16);
Ben Cheng00603072010-10-28 11:13:58 -07001489 targetTable = (int *) &switchData[4];
Ben Cheng7a02cb12010-12-15 14:18:31 -08001490 keyTable = NULL; // Make the compiler happy
Ben Cheng00603072010-10-28 11:13:58 -07001491 /*
1492 * Sparse switch data format:
1493 * ushort ident = 0x0200 magic value
1494 * ushort size number of entries in the table; > 0
1495 * int keys[size] keys, sorted low-to-high; 32-bit aligned
1496 * int targets[size] branch targets, relative to switch opcode
1497 *
1498 * Total size is (2+size*4) 16-bit code units.
1499 */
1500 } else {
1501 assert(switchData[0] == kSparseSwitchSignature);
1502 size = switchData[1];
Ben Cheng7a02cb12010-12-15 14:18:31 -08001503 keyTable = (int *) &switchData[2];
Ben Cheng00603072010-10-28 11:13:58 -07001504 targetTable = (int *) &switchData[2 + size*2];
Ben Cheng7a02cb12010-12-15 14:18:31 -08001505 firstKey = 0; // To make the compiler happy
Ben Cheng00603072010-10-28 11:13:58 -07001506 }
1507
1508 if (curBlock->successorBlockList.blockListType != kNotUsed) {
1509 LOGE("Successor block list already in use: %d",
1510 curBlock->successorBlockList.blockListType);
1511 dvmAbort();
1512 }
1513 curBlock->successorBlockList.blockListType =
1514 (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
1515 kPackedSwitch : kSparseSwitch;
1516 dvmInitGrowableList(&curBlock->successorBlockList.blocks, size);
1517
1518 for (i = 0; i < size; i++) {
1519 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
1520 /* split */
1521 true,
1522 /* create */
1523 true);
Ben Cheng7a02cb12010-12-15 14:18:31 -08001524 SuccessorBlockInfo *successorBlockInfo =
1525 (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo),
1526 false);
1527 successorBlockInfo->block = caseBlock;
1528 successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)?
1529 firstKey + i : keyTable[i];
Ben Cheng00603072010-10-28 11:13:58 -07001530 dvmInsertGrowableList(&curBlock->successorBlockList.blocks,
Ben Cheng7a02cb12010-12-15 14:18:31 -08001531 (intptr_t) successorBlockInfo);
Ben Cheng00603072010-10-28 11:13:58 -07001532 dvmCompilerSetBit(caseBlock->predecessors, curBlock->id);
1533 }
1534
1535 /* Fall-through case */
1536 BasicBlock *fallthroughBlock = findBlock(cUnit,
1537 curOffset + width,
1538 /* split */
1539 false,
1540 /* create */
1541 true);
1542 curBlock->fallThrough = fallthroughBlock;
1543 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
1544}
1545
1546/* Process instructions with the kInstrCanThrow flag */
1547static void processCanThrow(CompilationUnit *cUnit, BasicBlock *curBlock,
1548 MIR *insn, int curOffset, int width, int flags,
1549 BitVector *tryBlockAddr, const u2 *codePtr,
1550 const u2* codeEnd)
1551{
1552 const Method *method = cUnit->method;
1553 const DexCode *dexCode = dvmGetMethodCode(method);
1554
Ben Cheng00603072010-10-28 11:13:58 -07001555 /* In try block */
1556 if (dvmIsBitSet(tryBlockAddr, curOffset)) {
1557 DexCatchIterator iterator;
1558
1559 if (!dexFindCatchHandler(&iterator, dexCode, curOffset)) {
1560 LOGE("Catch block not found in dexfile for insn %x in %s",
1561 curOffset, method->name);
1562 dvmAbort();
1563
1564 }
1565 if (curBlock->successorBlockList.blockListType != kNotUsed) {
1566 LOGE("Successor block list already in use: %d",
1567 curBlock->successorBlockList.blockListType);
1568 dvmAbort();
1569 }
1570 curBlock->successorBlockList.blockListType = kCatch;
1571 dvmInitGrowableList(&curBlock->successorBlockList.blocks, 2);
1572
1573 for (;;) {
1574 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
1575
1576 if (handler == NULL) {
1577 break;
1578 }
1579
1580 BasicBlock *catchBlock = findBlock(cUnit, handler->address,
1581 /* split */
1582 false,
1583 /* create */
1584 false);
1585
Ben Cheng7a02cb12010-12-15 14:18:31 -08001586 SuccessorBlockInfo *successorBlockInfo =
1587 (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo),
1588 false);
1589 successorBlockInfo->block = catchBlock;
1590 successorBlockInfo->key = handler->typeIdx;
Ben Cheng00603072010-10-28 11:13:58 -07001591 dvmInsertGrowableList(&curBlock->successorBlockList.blocks,
Ben Cheng7a02cb12010-12-15 14:18:31 -08001592 (intptr_t) successorBlockInfo);
Ben Cheng00603072010-10-28 11:13:58 -07001593 dvmCompilerSetBit(catchBlock->predecessors, curBlock->id);
1594 }
1595 } else {
1596 BasicBlock *ehBlock = dvmCompilerNewBB(kExceptionHandling,
1597 cUnit->numBlocks++);
1598 curBlock->taken = ehBlock;
1599 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) ehBlock);
1600 ehBlock->startOffset = curOffset;
1601 dvmCompilerSetBit(ehBlock->predecessors, curBlock->id);
1602 }
1603
1604 /*
1605 * Force the current block to terminate.
1606 *
1607 * Data may be present before codeEnd, so we need to parse it to know
1608 * whether it is code or data.
1609 */
1610 if (codePtr < codeEnd) {
1611 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
1612 if (contentIsInsn(codePtr)) {
1613 BasicBlock *fallthroughBlock = findBlock(cUnit,
1614 curOffset + width,
1615 /* split */
1616 false,
1617 /* create */
1618 true);
1619 /*
1620 * OP_THROW and OP_THROW_VERIFICATION_ERROR are unconditional
1621 * branches.
1622 */
1623 if (insn->dalvikInsn.opcode != OP_THROW_VERIFICATION_ERROR &&
1624 insn->dalvikInsn.opcode != OP_THROW) {
1625 curBlock->fallThrough = fallthroughBlock;
1626 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
1627 }
1628 }
1629 }
1630}
1631
Ben Cheng7a2697d2010-06-07 13:44:23 -07001632/*
Ben Chengba4fc8b2009-06-01 13:00:29 -07001633 * Similar to dvmCompileTrace, but the entity processed here is the whole
1634 * method.
1635 *
1636 * TODO: implementation will be revisited when the trace builder can provide
1637 * whole-method traces.
1638 */
Ben Cheng00603072010-10-28 11:13:58 -07001639bool dvmCompileMethod(const Method *method)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001640{
Ben Cheng00603072010-10-28 11:13:58 -07001641 CompilationUnit cUnit;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001642 const DexCode *dexCode = dvmGetMethodCode(method);
1643 const u2 *codePtr = dexCode->insns;
1644 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
Ben Cheng00603072010-10-28 11:13:58 -07001645 int numBlocks = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001646 unsigned int curOffset = 0;
1647
Ben Cheng00603072010-10-28 11:13:58 -07001648 memset(&cUnit, 0, sizeof(cUnit));
1649 cUnit.method = method;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001650
Ben Cheng00603072010-10-28 11:13:58 -07001651 /* Initialize the block list */
1652 dvmInitGrowableList(&cUnit.blockList, 4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001653
1654 /* Allocate the bit-vector to track the beginning of basic blocks */
Ben Cheng00603072010-10-28 11:13:58 -07001655 BitVector *tryBlockAddr = dvmCompilerAllocBitVector(dexCode->insnsSize,
1656 true /* expandable */);
1657 cUnit.tryBlockAddr = tryBlockAddr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001658
Ben Cheng00603072010-10-28 11:13:58 -07001659 /* Create the default entry and exit blocks and enter them to the list */
1660 BasicBlock *entryBlock = dvmCompilerNewBB(kMethodEntryBlock, numBlocks++);
1661 BasicBlock *exitBlock = dvmCompilerNewBB(kMethodExitBlock, numBlocks++);
1662
1663 cUnit.entryBlock = entryBlock;
1664 cUnit.exitBlock = exitBlock;
1665
1666 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) entryBlock);
1667 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) exitBlock);
1668
1669 /* Current block to record parsed instructions */
1670 BasicBlock *curBlock = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
1671 curBlock->startOffset = 0;
1672 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) curBlock);
1673 entryBlock->fallThrough = curBlock;
1674 dvmCompilerSetBit(curBlock->predecessors, entryBlock->id);
Ben Cheng7a2697d2010-06-07 13:44:23 -07001675
Ben Chengba4fc8b2009-06-01 13:00:29 -07001676 /*
Ben Cheng00603072010-10-28 11:13:58 -07001677 * Store back the number of blocks since new blocks may be created of
1678 * accessing cUnit.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001679 */
Ben Cheng00603072010-10-28 11:13:58 -07001680 cUnit.numBlocks = numBlocks;
1681
1682 /* Identify code range in try blocks and set up the empty catch blocks */
1683 processTryCatchBlocks(&cUnit);
1684
1685 /* Parse all instructions and put them into containing basic blocks */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001686 while (codePtr < codeEnd) {
Ben Cheng00603072010-10-28 11:13:58 -07001687 MIR *insn = (MIR *) dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001688 insn->offset = curOffset;
1689 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001690 insn->width = width;
1691
Ben Cheng8b258bf2009-06-24 17:27:07 -07001692 /* Terminate when the data section is seen */
1693 if (width == 0)
1694 break;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001695
Ben Cheng00603072010-10-28 11:13:58 -07001696 dvmCompilerAppendMIR(curBlock, insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001697
1698 codePtr += width;
Ben Cheng00603072010-10-28 11:13:58 -07001699 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
1700
1701 if (flags & kInstrCanBranch) {
1702 processCanBranch(&cUnit, curBlock, insn, curOffset, width, flags,
1703 codePtr, codeEnd);
1704 } else if (flags & kInstrCanReturn) {
1705 curBlock->fallThrough = exitBlock;
1706 dvmCompilerSetBit(exitBlock->predecessors, curBlock->id);
1707 /*
1708 * Terminate the current block if there are instructions
1709 * afterwards.
1710 */
1711 if (codePtr < codeEnd) {
1712 /*
1713 * Create a fallthrough block for real instructions
1714 * (incl. OP_NOP).
1715 */
1716 if (contentIsInsn(codePtr)) {
1717 findBlock(&cUnit, curOffset + width,
1718 /* split */
1719 false,
1720 /* create */
1721 true);
1722 }
1723 }
1724 } else if (flags & kInstrCanThrow) {
1725 processCanThrow(&cUnit, curBlock, insn, curOffset, width, flags,
1726 tryBlockAddr, codePtr, codeEnd);
1727 } else if (flags & kInstrCanSwitch) {
1728 processCanSwitch(&cUnit, curBlock, insn, curOffset, width, flags);
1729 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001730 curOffset += width;
Ben Cheng00603072010-10-28 11:13:58 -07001731 BasicBlock *nextBlock = findBlock(&cUnit, curOffset,
1732 /* split */
1733 false,
1734 /* create */
1735 false);
1736 if (nextBlock) {
1737 /*
1738 * The next instruction could be the target of a previously parsed
1739 * forward branch so a block is already created. If the current
1740 * instruction is not an unconditional branch, connect them through
1741 * the fall-through link.
1742 */
1743 assert(curBlock->fallThrough == NULL ||
1744 curBlock->fallThrough == nextBlock ||
1745 curBlock->fallThrough == exitBlock);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001746
Ben Cheng00603072010-10-28 11:13:58 -07001747 if ((curBlock->fallThrough == NULL) &&
1748 !dexIsGoto(flags) &&
1749 !(flags & kInstrCanReturn)) {
1750 curBlock->fallThrough = nextBlock;
1751 dvmCompilerSetBit(nextBlock->predecessors, curBlock->id);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001752 }
Ben Cheng00603072010-10-28 11:13:58 -07001753 curBlock = nextBlock;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001754 }
1755 }
1756
Ben Cheng00603072010-10-28 11:13:58 -07001757 /* Adjust this value accordingly once inlining is performed */
1758 cUnit.numDalvikRegisters = cUnit.method->registersSize;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001759
Ben Cheng00603072010-10-28 11:13:58 -07001760 /* Verify if all blocks are connected as claimed */
1761 /* FIXME - to be disabled in the future */
1762 dvmCompilerDataFlowAnalysisDispatcher(&cUnit, verifyPredInfo,
1763 kAllNodes,
1764 false /* isIterative */);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001765
Ben Chengba4fc8b2009-06-01 13:00:29 -07001766
Ben Cheng00603072010-10-28 11:13:58 -07001767 /* Perform SSA transformation for the whole method */
1768 dvmCompilerMethodSSATransformation(&cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001769
Ben Cheng00603072010-10-28 11:13:58 -07001770 if (cUnit.printMe) dumpCFG(&cUnit, "/data/tombstones/");
Ben Chengba4fc8b2009-06-01 13:00:29 -07001771
Ben Cheng00603072010-10-28 11:13:58 -07001772 /* Reset the compiler resource pool */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001773 dvmCompilerArenaReset();
1774
Ben Cheng00603072010-10-28 11:13:58 -07001775 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001776}