blob: 95ef026c0897a22a1abe3a6dceccd680181d7713 [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
Bill Buzbee6e963e12009-06-17 16:56:19 -0700461 /* Initialize the profile flag */
462 cUnit.executionCount = gDvmJit.profile;
463
Ben Cheng7a2697d2010-06-07 13:44:23 -0700464 /* Setup the method */
465 cUnit.method = desc->method;
466
467 /* Initialize the PC reconstruction list */
468 dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
469
Ben Cheng00603072010-10-28 11:13:58 -0700470 /* Initialize the basic block list */
471 blockList = &cUnit.blockList;
472 dvmInitGrowableList(blockList, 8);
473
Ben Chengba4fc8b2009-06-01 13:00:29 -0700474 /* Identify traces that we don't want to compile */
475 if (gDvmJit.methodTable) {
476 int len = strlen(desc->method->clazz->descriptor) +
477 strlen(desc->method->name) + 1;
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800478 char *fullSignature = (char *)dvmCompilerNew(len, true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700479 strcpy(fullSignature, desc->method->clazz->descriptor);
480 strcat(fullSignature, desc->method->name);
481
482 int hashValue = dvmComputeUtf8Hash(fullSignature);
483
484 /*
485 * Doing three levels of screening to see whether we want to skip
486 * compiling this method
487 */
488
489 /* First, check the full "class;method" signature */
490 bool methodFound =
491 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
492 fullSignature, (HashCompareFunc) strcmp,
493 false) !=
494 NULL;
495
496 /* Full signature not found - check the enclosing class */
497 if (methodFound == false) {
498 int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
499 methodFound =
500 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
501 (char *) desc->method->clazz->descriptor,
502 (HashCompareFunc) strcmp, false) !=
503 NULL;
504 /* Enclosing class not found - check the method name */
505 if (methodFound == false) {
506 int hashValue = dvmComputeUtf8Hash(desc->method->name);
507 methodFound =
508 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
509 (char *) desc->method->name,
510 (HashCompareFunc) strcmp, false) !=
511 NULL;
Ben Cheng33672452010-01-12 14:59:30 -0800512
513 /*
514 * Debug by call-graph is enabled. Check if the debug list
515 * covers any methods on the VM stack.
516 */
517 if (methodFound == false && gDvmJit.checkCallGraph == true) {
518 methodFound =
519 filterMethodByCallGraph(info->requestingThread,
520 desc->method->name);
521 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700522 }
523 }
524
525 /*
526 * Under the following conditions, the trace will be *conservatively*
527 * compiled by only containing single-step instructions to and from the
528 * interpreter.
529 * 1) If includeSelectedMethod == false, the method matches the full or
530 * partial signature stored in the hash table.
531 *
532 * 2) If includeSelectedMethod == true, the method does not match the
533 * full and partial signature stored in the hash table.
534 */
535 if (gDvmJit.includeSelectedMethod != methodFound) {
536 cUnit.allSingleStep = true;
537 } else {
538 /* Compile the trace as normal */
539
540 /* Print the method we cherry picked */
541 if (gDvmJit.includeSelectedMethod == true) {
542 cUnit.printMe = true;
543 }
544 }
545 }
546
Ben Cheng4238ec22009-08-24 16:32:22 -0700547 /* Allocate the entry block */
Ben Cheng00603072010-10-28 11:13:58 -0700548 curBB = dvmCompilerNewBB(kTraceEntryBlock, numBlocks++);
549 dvmInsertGrowableList(blockList, (intptr_t) curBB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700550 curBB->startOffset = curOffset;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700551
Ben Cheng00603072010-10-28 11:13:58 -0700552 entryCodeBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
553 dvmInsertGrowableList(blockList, (intptr_t) entryCodeBB);
554 entryCodeBB->startOffset = curOffset;
555 curBB->fallThrough = entryCodeBB;
556 curBB = entryCodeBB;
Ben Cheng4238ec22009-08-24 16:32:22 -0700557
Ben Chengba4fc8b2009-06-01 13:00:29 -0700558 if (cUnit.printMe) {
559 LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n",
560 desc->method->name, curOffset);
561 }
562
Ben Cheng1efc9c52009-06-08 18:25:27 -0700563 /*
564 * Analyze the trace descriptor and include up to the maximal number
565 * of Dalvik instructions into the IR.
566 */
567 while (1) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700568 MIR *insn;
569 int width;
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800570 insn = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700571 insn->offset = curOffset;
572 width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700573
574 /* The trace should never incude instruction data */
575 assert(width);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700576 insn->width = width;
577 traceSize += width;
578 dvmCompilerAppendMIR(curBB, insn);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700579 cUnit.numInsts++;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700580
Dan Bornsteine4852762010-12-02 12:45:00 -0800581 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700582
Dan Bornstein0759f522010-11-30 14:58:53 -0800583 if (flags & kInstrInvoke) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700584 assert(numInsts == 1);
585 CallsiteInfo *callsiteInfo =
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800586 (CallsiteInfo *)dvmCompilerNew(sizeof(CallsiteInfo), true);
587 callsiteInfo->clazz = (ClassObject *)currRun[1].meta;
588 callsiteInfo->method = (Method *)currRun[2].meta;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700589 insn->meta.callsiteInfo = callsiteInfo;
590 }
591
Ben Cheng1efc9c52009-06-08 18:25:27 -0700592 /* Instruction limit reached - terminate the trace here */
593 if (cUnit.numInsts >= numMaxInsts) {
594 break;
595 }
596 if (--numInsts == 0) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700597 if (currRun->frag.runEnd) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700598 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700599 } else {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700600 /* Advance to the next trace description (ie non-meta info) */
601 do {
602 currRun++;
603 } while (!currRun->frag.isCode);
604
605 /* Dummy end-of-run marker seen */
606 if (currRun->frag.numInsts == 0) {
607 break;
608 }
609
Ben Cheng00603072010-10-28 11:13:58 -0700610 curBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
611 dvmInsertGrowableList(blockList, (intptr_t) curBB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700612 curOffset = currRun->frag.startOffset;
613 numInsts = currRun->frag.numInsts;
614 curBB->startOffset = curOffset;
615 codePtr = dexCode->insns + curOffset;
616 }
617 } else {
618 curOffset += width;
619 codePtr += width;
620 }
621 }
622
Ben Cheng1357e942010-02-10 17:21:39 -0800623#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700624 /* Convert # of half-word to bytes */
625 methodStats->compiledDalvikSize += traceSize * 2;
Ben Cheng1357e942010-02-10 17:21:39 -0800626#endif
Ben Cheng8b258bf2009-06-24 17:27:07 -0700627
Ben Chengba4fc8b2009-06-01 13:00:29 -0700628 /*
629 * Now scan basic blocks containing real code to connect the
630 * taken/fallthrough links. Also create chaining cells for code not included
631 * in the trace.
632 */
Ben Cheng00603072010-10-28 11:13:58 -0700633 size_t blockId;
634 for (blockId = 0; blockId < blockList->numUsed; blockId++) {
635 curBB = (BasicBlock *) dvmGrowableListGetElement(blockList, blockId);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700636 MIR *lastInsn = curBB->lastMIRInsn;
Ben Cheng4238ec22009-08-24 16:32:22 -0700637 /* Skip empty blocks */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700638 if (lastInsn == NULL) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700639 continue;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700640 }
641 curOffset = lastInsn->offset;
642 unsigned int targetOffset = curOffset;
643 unsigned int fallThroughOffset = curOffset + lastInsn->width;
644 bool isInvoke = false;
645 const Method *callee = NULL;
646
647 findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
648 &targetOffset, &isInvoke, &callee);
649
650 /* Link the taken and fallthrough blocks */
651 BasicBlock *searchBB;
652
Dan Bornsteine4852762010-12-02 12:45:00 -0800653 int flags = dexGetFlagsFromOpcode(lastInsn->dalvikInsn.opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700654
655 if (flags & kInstrInvoke) {
656 cUnit.hasInvoke = true;
657 }
658
Ben Chengba4fc8b2009-06-01 13:00:29 -0700659 /* No backward branch in the trace - start searching the next BB */
Ben Cheng00603072010-10-28 11:13:58 -0700660 size_t searchBlockId;
661 for (searchBlockId = blockId+1; searchBlockId < blockList->numUsed;
662 searchBlockId++) {
663 searchBB = (BasicBlock *) dvmGrowableListGetElement(blockList,
664 searchBlockId);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700665 if (targetOffset == searchBB->startOffset) {
666 curBB->taken = searchBB;
667 }
668 if (fallThroughOffset == searchBB->startOffset) {
669 curBB->fallThrough = searchBB;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700670
671 /*
672 * Fallthrough block of an invoke instruction needs to be
673 * aligned to 4-byte boundary (alignment instruction to be
674 * inserted later.
675 */
676 if (flags & kInstrInvoke) {
677 searchBB->isFallThroughFromInvoke = true;
678 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700679 }
680 }
681
Ben Cheng1efc9c52009-06-08 18:25:27 -0700682 /*
683 * Some blocks are ended by non-control-flow-change instructions,
684 * currently only due to trace length constraint. In this case we need
685 * to generate an explicit branch at the end of the block to jump to
686 * the chaining cell.
687 */
688 curBB->needFallThroughBranch =
Ben Cheng17f15ce2009-07-27 16:21:52 -0700689 ((flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
Dan Bornstein0759f522010-11-30 14:58:53 -0800690 kInstrInvoke)) == 0);
Ben Cheng17f15ce2009-07-27 16:21:52 -0700691
Ben Cheng4a419582010-08-04 13:23:09 -0700692 /* Only form a loop if JIT_OPT_NO_LOOP is not set */
Ben Cheng4238ec22009-08-24 16:32:22 -0700693 if (curBB->taken == NULL &&
694 curBB->fallThrough == NULL &&
695 flags == (kInstrCanBranch | kInstrCanContinue) &&
Ben Cheng00603072010-10-28 11:13:58 -0700696 fallThroughOffset == entryCodeBB->startOffset &&
Ben Cheng4a419582010-08-04 13:23:09 -0700697 JIT_OPT_NO_LOOP != (optHints & JIT_OPT_NO_LOOP)) {
Ben Cheng0fd31e42009-09-03 14:40:16 -0700698 BasicBlock *loopBranch = curBB;
699 BasicBlock *exitBB;
700 BasicBlock *exitChainingCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700701
702 if (cUnit.printMe) {
703 LOGD("Natural loop detected!");
704 }
Ben Cheng00603072010-10-28 11:13:58 -0700705 exitBB = dvmCompilerNewBB(kTraceExitBlock, numBlocks++);
706 dvmInsertGrowableList(blockList, (intptr_t) exitBB);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700707 exitBB->startOffset = targetOffset;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700708 exitBB->needFallThroughBranch = true;
Ben Cheng4238ec22009-08-24 16:32:22 -0700709
Ben Cheng0fd31e42009-09-03 14:40:16 -0700710 loopBranch->taken = exitBB;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700711#if defined(WITH_SELF_VERIFICATION)
Ben Cheng0fd31e42009-09-03 14:40:16 -0700712 BasicBlock *backwardCell =
Ben Cheng00603072010-10-28 11:13:58 -0700713 dvmCompilerNewBB(kChainingCellBackwardBranch, numBlocks++);
714 dvmInsertGrowableList(blockList, (intptr_t) backwardCell);
715 backwardCell->startOffset = entryCodeBB->startOffset;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700716 loopBranch->fallThrough = backwardCell;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700717#elif defined(WITH_JIT_TUNING)
718 if (gDvmJit.profile) {
719 BasicBlock *backwardCell =
Ben Cheng00603072010-10-28 11:13:58 -0700720 dvmCompilerNewBB(kChainingCellBackwardBranch, numBlocks++);
721 dvmInsertGrowableList(blockList, (intptr_t) backwardCell);
722 backwardCell->startOffset = entryCodeBB->startOffset;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700723 loopBranch->fallThrough = backwardCell;
724 } else {
Ben Cheng00603072010-10-28 11:13:58 -0700725 loopBranch->fallThrough = entryCodeBB;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700726 }
727#else
Ben Cheng00603072010-10-28 11:13:58 -0700728 loopBranch->fallThrough = entryCodeBB;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700729#endif
730
731 /* Create the chaining cell as the fallthrough of the exit block */
Ben Cheng00603072010-10-28 11:13:58 -0700732 exitChainingCell = dvmCompilerNewBB(kChainingCellNormal,
733 numBlocks++);
734 dvmInsertGrowableList(blockList, (intptr_t) exitChainingCell);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700735 exitChainingCell->startOffset = targetOffset;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700736
737 exitBB->fallThrough = exitChainingCell;
738
Ben Cheng4238ec22009-08-24 16:32:22 -0700739 cUnit.hasLoop = true;
740 }
741
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800742 if (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ||
743 lastInsn->dalvikInsn.opcode == OP_SPARSE_SWITCH) {
Ben Cheng6c10a972009-10-29 14:39:18 -0700744 int i;
745 const u2 *switchData = desc->method->insns + lastInsn->offset +
746 lastInsn->dalvikInsn.vB;
747 int size = switchData[1];
748 int maxChains = MIN(size, MAX_CHAINED_SWITCH_CASES);
749
750 /*
751 * Generate the landing pad for cases whose ranks are higher than
752 * MAX_CHAINED_SWITCH_CASES. The code will re-enter the interpreter
753 * through the NoChain point.
754 */
755 if (maxChains != size) {
756 cUnit.switchOverflowPad =
757 desc->method->insns + lastInsn->offset;
758 }
759
760 s4 *targets = (s4 *) (switchData + 2 +
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800761 (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ?
Ben Cheng6c10a972009-10-29 14:39:18 -0700762 2 : size * 2));
763
764 /* One chaining cell for the first MAX_CHAINED_SWITCH_CASES cases */
765 for (i = 0; i < maxChains; i++) {
Ben Cheng00603072010-10-28 11:13:58 -0700766 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal,
767 numBlocks++);
768 dvmInsertGrowableList(blockList, (intptr_t) caseChain);
Ben Cheng6c10a972009-10-29 14:39:18 -0700769 caseChain->startOffset = lastInsn->offset + targets[i];
Ben Cheng6c10a972009-10-29 14:39:18 -0700770 }
771
772 /* One more chaining cell for the default case */
Ben Cheng00603072010-10-28 11:13:58 -0700773 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal,
774 numBlocks++);
775 dvmInsertGrowableList(blockList, (intptr_t) caseChain);
Ben Cheng6c10a972009-10-29 14:39:18 -0700776 caseChain->startOffset = lastInsn->offset + lastInsn->width;
Ben Cheng6d576092009-09-01 17:01:58 -0700777 /* Fallthrough block not included in the trace */
Ben Cheng6c10a972009-10-29 14:39:18 -0700778 } else if (!isUnconditionalBranch(lastInsn) &&
779 curBB->fallThrough == NULL) {
Ben Cheng00603072010-10-28 11:13:58 -0700780 BasicBlock *fallThroughBB;
Ben Cheng6d576092009-09-01 17:01:58 -0700781 /*
782 * If the chaining cell is after an invoke or
783 * instruction that cannot change the control flow, request a hot
784 * chaining cell.
785 */
786 if (isInvoke || curBB->needFallThroughBranch) {
Ben Cheng00603072010-10-28 11:13:58 -0700787 fallThroughBB = dvmCompilerNewBB(kChainingCellHot, numBlocks++);
Ben Cheng6d576092009-09-01 17:01:58 -0700788 } else {
Ben Cheng00603072010-10-28 11:13:58 -0700789 fallThroughBB = dvmCompilerNewBB(kChainingCellNormal,
790 numBlocks++);
Ben Cheng6d576092009-09-01 17:01:58 -0700791 }
Ben Cheng00603072010-10-28 11:13:58 -0700792 dvmInsertGrowableList(blockList, (intptr_t) fallThroughBB);
793 fallThroughBB->startOffset = fallThroughOffset;
794 curBB->fallThrough = fallThroughBB;
Ben Cheng6d576092009-09-01 17:01:58 -0700795 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700796 /* Target block not included in the trace */
Ben Cheng38329f52009-07-07 14:19:20 -0700797 if (curBB->taken == NULL &&
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800798 (isGoto(lastInsn) || isInvoke ||
799 (targetOffset != UNKNOWN_TARGET && targetOffset != curOffset))) {
Ben Cheng38329f52009-07-07 14:19:20 -0700800 BasicBlock *newBB;
Ben Cheng1efc9c52009-06-08 18:25:27 -0700801 if (isInvoke) {
Ben Cheng38329f52009-07-07 14:19:20 -0700802 /* Monomorphic callee */
803 if (callee) {
Ben Cheng00603072010-10-28 11:13:58 -0700804 newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton,
805 numBlocks++);
Ben Cheng38329f52009-07-07 14:19:20 -0700806 newBB->startOffset = 0;
807 newBB->containingMethod = callee;
808 /* Will resolve at runtime */
809 } else {
Ben Cheng00603072010-10-28 11:13:58 -0700810 newBB = dvmCompilerNewBB(kChainingCellInvokePredicted,
811 numBlocks++);
Ben Cheng38329f52009-07-07 14:19:20 -0700812 newBB->startOffset = 0;
813 }
Ben Cheng1efc9c52009-06-08 18:25:27 -0700814 /* For unconditional branches, request a hot chaining cell */
815 } else {
Jeff Hao97319a82009-08-12 16:57:15 -0700816#if !defined(WITH_SELF_VERIFICATION)
Dan Bornsteinc2b486f2010-11-12 16:07:16 -0800817 newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700818 kChainingCellHot :
Ben Cheng00603072010-10-28 11:13:58 -0700819 kChainingCellNormal,
820 numBlocks++);
Ben Cheng38329f52009-07-07 14:19:20 -0700821 newBB->startOffset = targetOffset;
Jeff Hao97319a82009-08-12 16:57:15 -0700822#else
823 /* Handle branches that branch back into the block */
824 if (targetOffset >= curBB->firstMIRInsn->offset &&
825 targetOffset <= curBB->lastMIRInsn->offset) {
Ben Cheng00603072010-10-28 11:13:58 -0700826 newBB = dvmCompilerNewBB(kChainingCellBackwardBranch,
827 numBlocks++);
Jeff Hao97319a82009-08-12 16:57:15 -0700828 } else {
Dan Bornsteinc2b486f2010-11-12 16:07:16 -0800829 newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700830 kChainingCellHot :
Ben Cheng00603072010-10-28 11:13:58 -0700831 kChainingCellNormal,
832 numBlocks++);
Jeff Hao97319a82009-08-12 16:57:15 -0700833 }
834 newBB->startOffset = targetOffset;
835#endif
Ben Cheng1efc9c52009-06-08 18:25:27 -0700836 }
Ben Cheng38329f52009-07-07 14:19:20 -0700837 curBB->taken = newBB;
Ben Cheng00603072010-10-28 11:13:58 -0700838 dvmInsertGrowableList(blockList, (intptr_t) newBB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700839 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700840 }
841
842 /* Now create a special block to host PC reconstruction code */
Ben Cheng00603072010-10-28 11:13:58 -0700843 curBB = dvmCompilerNewBB(kPCReconstruction, numBlocks++);
844 dvmInsertGrowableList(blockList, (intptr_t) curBB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700845
846 /* And one final block that publishes the PC and raise the exception */
Ben Cheng00603072010-10-28 11:13:58 -0700847 curBB = dvmCompilerNewBB(kExceptionHandling, numBlocks++);
848 dvmInsertGrowableList(blockList, (intptr_t) curBB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700849
850 if (cUnit.printMe) {
Ben Cheng00603072010-10-28 11:13:58 -0700851 char* signature =
852 dexProtoCopyMethodDescriptor(&desc->method->prototype);
Elliott Hughescc6fac82010-07-02 13:38:44 -0700853 LOGD("TRACEINFO (%d): 0x%08x %s%s.%s 0x%x %d of %d, %d blocks",
Ben Chenge9695e52009-06-16 16:11:47 -0700854 compilationId,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700855 (intptr_t) desc->method->insns,
856 desc->method->clazz->descriptor,
857 desc->method->name,
Elliott Hughescc6fac82010-07-02 13:38:44 -0700858 signature,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700859 desc->trace[0].frag.startOffset,
860 traceSize,
861 dexCode->insnsSize,
862 numBlocks);
Elliott Hughescc6fac82010-07-02 13:38:44 -0700863 free(signature);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700864 }
865
Ben Chengba4fc8b2009-06-01 13:00:29 -0700866 cUnit.traceDesc = desc;
867 cUnit.numBlocks = numBlocks;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700868
Ben Cheng7a2697d2010-06-07 13:44:23 -0700869 /* Set the instruction set to use (NOTE: later components may change it) */
870 cUnit.instructionSet = dvmCompilerInstructionSet();
871
872 /* Inline transformation @ the MIR level */
873 if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) {
874 dvmCompilerInlineMIR(&cUnit);
875 }
876
Ben Cheng00603072010-10-28 11:13:58 -0700877 cUnit.numDalvikRegisters = cUnit.method->registersSize;
878
Ben Cheng4238ec22009-08-24 16:32:22 -0700879 /* Preparation for SSA conversion */
880 dvmInitializeSSAConversion(&cUnit);
881
882 if (cUnit.hasLoop) {
Ben Cheng4a419582010-08-04 13:23:09 -0700883 /*
884 * Loop is not optimizable (for example lack of a single induction
885 * variable), punt and recompile the trace with loop optimization
886 * disabled.
887 */
888 bool loopOpt = dvmCompilerLoopOpt(&cUnit);
889 if (loopOpt == false) {
890 if (cUnit.printMe) {
891 LOGD("Loop is not optimizable - retry codegen");
892 }
893 /* Reset the compiler resource pool */
894 dvmCompilerArenaReset();
895 return dvmCompileTrace(desc, cUnit.numInsts, info, bailPtr,
896 optHints | JIT_OPT_NO_LOOP);
897 }
Ben Cheng4238ec22009-08-24 16:32:22 -0700898 }
899 else {
900 dvmCompilerNonLoopAnalysis(&cUnit);
901 }
902
Bill Buzbee1465db52009-09-23 17:17:35 -0700903 dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
904
Ben Chengba4fc8b2009-06-01 13:00:29 -0700905 if (cUnit.printMe) {
906 dvmCompilerDumpCompilationUnit(&cUnit);
907 }
908
buzbee23d95d02010-12-14 13:16:43 -0800909 /* Allocate Registers using simple local allocation scheme */
910 dvmCompilerLocalRegAlloc(&cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700911
Ben Chengba4fc8b2009-06-01 13:00:29 -0700912 /* Convert MIR to LIR, etc. */
913 dvmCompilerMIR2LIR(&cUnit);
914
buzbeebff121a2010-08-04 15:25:06 -0700915 /* Convert LIR into machine code. Loop for recoverable retries */
916 do {
917 dvmCompilerAssembleLIR(&cUnit, info);
918 cUnit.assemblerRetries++;
919 if (cUnit.printMe && cUnit.assemblerStatus != kSuccess)
920 LOGD("Assembler abort #%d on %d",cUnit.assemblerRetries,
921 cUnit.assemblerStatus);
922 } while (cUnit.assemblerStatus == kRetryAll);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700923
924 if (cUnit.printMe) {
buzbeebff121a2010-08-04 15:25:06 -0700925 dvmCompilerCodegenDump(&cUnit);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700926 LOGD("End %s%s, %d Dalvik instructions",
927 desc->method->clazz->descriptor, desc->method->name,
928 cUnit.numInsts);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700929 }
930
931 /* Reset the compiler resource pool */
932 dvmCompilerArenaReset();
933
buzbeebff121a2010-08-04 15:25:06 -0700934 if (cUnit.assemblerStatus == kRetryHalve) {
935 /* Halve the instruction count and start from the top */
Ben Cheng4a419582010-08-04 13:23:09 -0700936 return dvmCompileTrace(desc, cUnit.numInsts / 2, info, bailPtr,
937 optHints);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700938 }
buzbeebff121a2010-08-04 15:25:06 -0700939
940 assert(cUnit.assemblerStatus == kSuccess);
941#if defined(WITH_JIT_TUNING)
942 methodStats->nativeSize += cUnit.totalSize;
943#endif
Ben Cheng00603072010-10-28 11:13:58 -0700944
945 /* FIXME - to exercise the method parser, uncomment the following code */
946#if 0
947 bool dvmCompileMethod(const Method *method);
948 if (desc->trace[0].frag.startOffset == 0) {
949 dvmCompileMethod(desc->method);
950 }
951#endif
952
buzbeebff121a2010-08-04 15:25:06 -0700953 return info->codeAddress != NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700954}
955
956/*
Ben Cheng7a2697d2010-06-07 13:44:23 -0700957 * Since we are including instructions from possibly a cold method into the
958 * current trace, we need to make sure that all the associated information
959 * with the callee is properly initialized. If not, we punt on this inline
960 * target.
961 *
Ben Cheng34dc7962010-08-26 14:56:31 -0700962 * TODO: volatile instructions will be handled later.
Ben Cheng7a2697d2010-06-07 13:44:23 -0700963 */
964bool dvmCompilerCanIncludeThisInstruction(const Method *method,
965 const DecodedInstruction *insn)
966{
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800967 switch (insn->opcode) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700968 case OP_NEW_INSTANCE:
969 case OP_CHECK_CAST: {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800970 ClassObject *classPtr = (ClassObject *)(void*)
Ben Cheng7a2697d2010-06-07 13:44:23 -0700971 (method->clazz->pDvmDex->pResClasses[insn->vB]);
972
973 /* Class hasn't been initialized yet */
974 if (classPtr == NULL) {
975 return false;
976 }
977 return true;
978 }
979 case OP_SGET_OBJECT:
980 case OP_SGET_BOOLEAN:
981 case OP_SGET_CHAR:
982 case OP_SGET_BYTE:
983 case OP_SGET_SHORT:
984 case OP_SGET:
985 case OP_SGET_WIDE:
986 case OP_SPUT_OBJECT:
987 case OP_SPUT_BOOLEAN:
988 case OP_SPUT_CHAR:
989 case OP_SPUT_BYTE:
990 case OP_SPUT_SHORT:
991 case OP_SPUT:
992 case OP_SPUT_WIDE: {
993 void *fieldPtr = (void*)
994 (method->clazz->pDvmDex->pResFields[insn->vB]);
995
996 if (fieldPtr == NULL) {
997 return false;
998 }
999 return true;
1000 }
1001 case OP_INVOKE_SUPER:
1002 case OP_INVOKE_SUPER_RANGE: {
1003 int mIndex = method->clazz->pDvmDex->
1004 pResMethods[insn->vB]->methodIndex;
1005 const Method *calleeMethod = method->clazz->super->vtable[mIndex];
1006 if (calleeMethod == NULL) {
1007 return false;
1008 }
1009 return true;
1010 }
1011 case OP_INVOKE_SUPER_QUICK:
1012 case OP_INVOKE_SUPER_QUICK_RANGE: {
1013 const Method *calleeMethod = method->clazz->super->vtable[insn->vB];
1014 if (calleeMethod == NULL) {
1015 return false;
1016 }
1017 return true;
1018 }
1019 case OP_INVOKE_STATIC:
1020 case OP_INVOKE_STATIC_RANGE:
1021 case OP_INVOKE_DIRECT:
1022 case OP_INVOKE_DIRECT_RANGE: {
1023 const Method *calleeMethod =
1024 method->clazz->pDvmDex->pResMethods[insn->vB];
1025 if (calleeMethod == NULL) {
1026 return false;
1027 }
1028 return true;
1029 }
1030 case OP_CONST_CLASS: {
1031 void *classPtr = (void*)
1032 (method->clazz->pDvmDex->pResClasses[insn->vB]);
1033
1034 if (classPtr == NULL) {
1035 return false;
1036 }
1037 return true;
1038 }
1039 case OP_CONST_STRING_JUMBO:
1040 case OP_CONST_STRING: {
1041 void *strPtr = (void*)
1042 (method->clazz->pDvmDex->pResStrings[insn->vB]);
1043
1044 if (strPtr == NULL) {
1045 return false;
1046 }
1047 return true;
1048 }
1049 default:
1050 return true;
1051 }
1052}
1053
Ben Cheng00603072010-10-28 11:13:58 -07001054/* Split an existing block from the specified code offset into two */
1055static BasicBlock *splitBlock(CompilationUnit *cUnit,
1056 unsigned int codeOffset,
1057 BasicBlock *origBlock)
1058{
1059 MIR *insn = origBlock->firstMIRInsn;
1060 while (insn) {
1061 if (insn->offset == codeOffset) break;
1062 insn = insn->next;
1063 }
1064 if (insn == NULL) {
1065 LOGE("Break split failed");
1066 dvmAbort();
1067 }
1068 BasicBlock *bottomBlock = dvmCompilerNewBB(kDalvikByteCode,
1069 cUnit->numBlocks++);
1070 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bottomBlock);
1071
1072 bottomBlock->startOffset = codeOffset;
1073 bottomBlock->firstMIRInsn = insn;
1074 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
1075
Ben Cheng00603072010-10-28 11:13:58 -07001076 /* Handle the taken path */
1077 bottomBlock->taken = origBlock->taken;
1078 if (bottomBlock->taken) {
1079 origBlock->taken = NULL;
1080 dvmCompilerClearBit(bottomBlock->taken->predecessors, origBlock->id);
1081 dvmCompilerSetBit(bottomBlock->taken->predecessors, bottomBlock->id);
1082 }
1083
1084 /* Handle the fallthrough path */
1085 bottomBlock->fallThrough = origBlock->fallThrough;
1086 origBlock->fallThrough = bottomBlock;
1087 dvmCompilerSetBit(bottomBlock->predecessors, origBlock->id);
1088 if (bottomBlock->fallThrough) {
1089 dvmCompilerClearBit(bottomBlock->fallThrough->predecessors,
1090 origBlock->id);
1091 dvmCompilerSetBit(bottomBlock->fallThrough->predecessors,
1092 bottomBlock->id);
1093 }
1094
1095 /* Handle the successor list */
1096 if (origBlock->successorBlockList.blockListType != kNotUsed) {
1097 bottomBlock->successorBlockList = origBlock->successorBlockList;
1098 origBlock->successorBlockList.blockListType = kNotUsed;
1099 GrowableListIterator iterator;
1100
1101 dvmGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
1102 &iterator);
1103 while (true) {
Ben Cheng7a02cb12010-12-15 14:18:31 -08001104 SuccessorBlockInfo *successorBlockInfo =
1105 (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
1106 if (successorBlockInfo == NULL) break;
1107 BasicBlock *bb = successorBlockInfo->block;
Ben Cheng00603072010-10-28 11:13:58 -07001108 dvmCompilerClearBit(bb->predecessors, origBlock->id);
1109 dvmCompilerSetBit(bb->predecessors, bottomBlock->id);
1110 }
1111 }
1112
1113 origBlock->lastMIRInsn = insn->prev;
Ben Cheng00603072010-10-28 11:13:58 -07001114
1115 insn->prev->next = NULL;
1116 insn->prev = NULL;
1117 return bottomBlock;
1118}
1119
1120/*
1121 * Given a code offset, find out the block that starts with it. If the offset
1122 * is in the middle of an existing block, split it into two.
1123 */
1124static BasicBlock *findBlock(CompilationUnit *cUnit,
1125 unsigned int codeOffset,
1126 bool split, bool create)
1127{
1128 GrowableList *blockList = &cUnit->blockList;
1129 BasicBlock *bb;
1130 unsigned int i;
1131
1132 for (i = 0; i < blockList->numUsed; i++) {
1133 bb = (BasicBlock *) blockList->elemList[i];
1134 if (bb->blockType != kDalvikByteCode) continue;
1135 if (bb->startOffset == codeOffset) return bb;
1136 /* Check if a branch jumps into the middle of an existing block */
1137 if ((split == true) && (codeOffset > bb->startOffset) &&
1138 (bb->lastMIRInsn != NULL) &&
1139 (codeOffset <= bb->lastMIRInsn->offset)) {
1140 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb);
1141 return newBB;
1142 }
1143 }
1144 if (create) {
1145 bb = dvmCompilerNewBB(kDalvikByteCode, cUnit->numBlocks++);
1146 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
1147 bb->startOffset = codeOffset;
1148 return bb;
1149 }
1150 return NULL;
1151}
1152
1153/* Dump the CFG into a DOT graph */
1154void dumpCFG(CompilationUnit *cUnit, const char *dirPrefix)
1155{
1156 const Method *method = cUnit->method;
1157 FILE *file;
1158 char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
1159 char *fileName = (char *) dvmCompilerNew(
1160 strlen(dirPrefix) +
1161 strlen(method->clazz->descriptor) +
1162 strlen(method->name) +
1163 strlen(signature) +
1164 strlen(".dot") + 1, true);
1165 sprintf(fileName, "%s%s%s%s.dot", dirPrefix,
1166 method->clazz->descriptor, method->name, signature);
1167 free(signature);
1168
1169 /*
1170 * Convert the special characters into a filesystem- and shell-friendly
1171 * format.
1172 */
1173 int i;
1174 for (i = strlen(dirPrefix); fileName[i]; i++) {
1175 if (fileName[i] == '/') {
1176 fileName[i] = '_';
1177 } else if (fileName[i] == ';') {
1178 fileName[i] = '#';
1179 } else if (fileName[i] == '$') {
1180 fileName[i] = '+';
1181 } else if (fileName[i] == '(' || fileName[i] == ')') {
1182 fileName[i] = '@';
1183 } else if (fileName[i] == '<' || fileName[i] == '>') {
1184 fileName[i] = '=';
1185 }
1186 }
1187 file = fopen(fileName, "w");
1188 if (file == NULL) {
1189 return;
1190 }
1191 fprintf(file, "digraph G {\n");
1192
1193 fprintf(file, " rankdir=TB\n");
1194
1195 int numReachableBlocks = cUnit->numReachableBlocks;
1196 int idx;
1197 const GrowableList *blockList = &cUnit->blockList;
1198
1199 for (idx = 0; idx < numReachableBlocks; idx++) {
1200 int blockIdx = cUnit->dfsOrder.elemList[idx];
1201 BasicBlock *bb = (BasicBlock *) dvmGrowableListGetElement(blockList,
1202 blockIdx);
1203 if (bb == NULL) break;
1204 if (bb->blockType == kMethodEntryBlock) {
1205 fprintf(file, " entry [shape=Mdiamond];\n");
1206 } else if (bb->blockType == kMethodExitBlock) {
1207 fprintf(file, " exit [shape=Mdiamond];\n");
1208 } else if (bb->blockType == kDalvikByteCode) {
Ben Cheng7a02cb12010-12-15 14:18:31 -08001209 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
1210 bb->startOffset);
Ben Cheng00603072010-10-28 11:13:58 -07001211 const MIR *mir;
1212 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1213 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
1214 dvmCompilerFullDisassembler(cUnit, mir),
1215 mir->next ? " | " : " ");
1216 }
1217 fprintf(file, " }\"];\n\n");
1218 } else if (bb->blockType == kExceptionHandling) {
1219 char blockName[BLOCK_NAME_LEN];
1220
1221 dvmGetBlockName(bb, blockName);
1222 fprintf(file, " %s [shape=invhouse];\n", blockName);
1223 }
1224
1225 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
1226
1227 if (bb->taken) {
1228 dvmGetBlockName(bb, blockName1);
1229 dvmGetBlockName(bb->taken, blockName2);
1230 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
1231 blockName1, blockName2);
1232 }
1233 if (bb->fallThrough) {
1234 dvmGetBlockName(bb, blockName1);
1235 dvmGetBlockName(bb->fallThrough, blockName2);
1236 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
1237 }
1238
1239 if (bb->successorBlockList.blockListType != kNotUsed) {
1240 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
1241 bb->startOffset,
1242 (bb->successorBlockList.blockListType == kCatch) ?
1243 "Mrecord" : "record");
1244 GrowableListIterator iterator;
1245 dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
1246 &iterator);
Ben Cheng7a02cb12010-12-15 14:18:31 -08001247 SuccessorBlockInfo *successorBlockInfo =
1248 (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
Ben Cheng00603072010-10-28 11:13:58 -07001249
1250 int succId = 0;
1251 while (true) {
Ben Cheng7a02cb12010-12-15 14:18:31 -08001252 if (successorBlockInfo == NULL) break;
1253
1254 BasicBlock *destBlock = successorBlockInfo->block;
1255 SuccessorBlockInfo *nextSuccessorBlockInfo =
1256 (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
1257
1258 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
Ben Cheng00603072010-10-28 11:13:58 -07001259 succId++,
Ben Cheng7a02cb12010-12-15 14:18:31 -08001260 successorBlockInfo->key,
Ben Cheng00603072010-10-28 11:13:58 -07001261 destBlock->startOffset,
Ben Cheng7a02cb12010-12-15 14:18:31 -08001262 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
1263
1264 successorBlockInfo = nextSuccessorBlockInfo;
Ben Cheng00603072010-10-28 11:13:58 -07001265 }
1266 fprintf(file, " }\"];\n\n");
1267
1268 dvmGetBlockName(bb, blockName1);
1269 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
1270 blockName1, bb->startOffset);
1271
1272 if (bb->successorBlockList.blockListType == kPackedSwitch ||
1273 bb->successorBlockList.blockListType == kSparseSwitch) {
1274
1275 dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
1276 &iterator);
1277
1278 succId = 0;
1279 while (true) {
Ben Cheng7a02cb12010-12-15 14:18:31 -08001280 SuccessorBlockInfo *successorBlockInfo =
1281 (SuccessorBlockInfo *)
1282 dvmGrowableListIteratorNext(&iterator);
1283 if (successorBlockInfo == NULL) break;
1284
1285 BasicBlock *destBlock = successorBlockInfo->block;
Ben Cheng00603072010-10-28 11:13:58 -07001286
1287 dvmGetBlockName(destBlock, blockName2);
1288 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
1289 bb->startOffset, succId++,
1290 blockName2);
1291 }
1292 }
1293 }
1294 fprintf(file, "\n");
1295
1296 /*
1297 * If we need to debug the dominator tree, uncomment the following code
1298 */
1299#if 0
1300 dvmGetBlockName(bb, blockName1);
1301 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
1302 blockName1, blockName1);
1303 if (bb->iDom) {
1304 dvmGetBlockName(bb->iDom, blockName2);
1305 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
1306 blockName2, blockName1);
1307 }
1308#endif
1309 }
1310 fprintf(file, "}\n");
1311 fclose(file);
1312}
1313
1314/* Verify if all the successor is connected with all the claimed predecessors */
1315static bool verifyPredInfo(CompilationUnit *cUnit, BasicBlock *bb)
1316{
1317 BitVectorIterator bvIterator;
1318
1319 dvmBitVectorIteratorInit(bb->predecessors, &bvIterator);
1320 while (true) {
1321 int blockIdx = dvmBitVectorIteratorNext(&bvIterator);
1322 if (blockIdx == -1) break;
1323 BasicBlock *predBB = (BasicBlock *)
1324 dvmGrowableListGetElement(&cUnit->blockList, blockIdx);
1325 bool found = false;
1326 if (predBB->taken == bb) {
1327 found = true;
1328 } else if (predBB->fallThrough == bb) {
1329 found = true;
1330 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
1331 GrowableListIterator iterator;
1332 dvmGrowableListIteratorInit(&predBB->successorBlockList.blocks,
1333 &iterator);
1334 while (true) {
Ben Cheng7a02cb12010-12-15 14:18:31 -08001335 SuccessorBlockInfo *successorBlockInfo =
1336 (SuccessorBlockInfo *)
1337 dvmGrowableListIteratorNext(&iterator);
1338 if (successorBlockInfo == NULL) break;
1339 BasicBlock *succBB = successorBlockInfo->block;
Ben Cheng00603072010-10-28 11:13:58 -07001340 if (succBB == bb) {
1341 found = true;
1342 break;
1343 }
1344 }
1345 }
1346 if (found == false) {
1347 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
1348 dvmGetBlockName(bb, blockName1);
1349 dvmGetBlockName(predBB, blockName2);
1350 dumpCFG(cUnit, "/data/tombstones/");
1351 LOGE("Successor %s not found from %s",
1352 blockName1, blockName2);
1353 dvmAbort();
1354 }
1355 }
1356 return true;
1357}
1358
1359/* Identify code range in try blocks and set up the empty catch blocks */
1360static void processTryCatchBlocks(CompilationUnit *cUnit)
1361{
1362 const Method *meth = cUnit->method;
1363 const DexCode *pCode = dvmGetMethodCode(meth);
1364 int triesSize = pCode->triesSize;
1365 int i;
1366 int offset;
1367
1368 if (triesSize == 0) {
1369 return;
1370 }
1371
1372 const DexTry *pTries = dexGetTries(pCode);
1373 BitVector *tryBlockAddr = cUnit->tryBlockAddr;
1374
1375 /* Mark all the insn offsets in Try blocks */
1376 for (i = 0; i < triesSize; i++) {
1377 const DexTry* pTry = &pTries[i];
1378 /* all in 16-bit units */
1379 int startOffset = pTry->startAddr;
1380 int endOffset = startOffset + pTry->insnCount;
1381
1382 for (offset = startOffset; offset < endOffset; offset++) {
1383 dvmCompilerSetBit(tryBlockAddr, offset);
1384 }
1385 }
1386
1387 /* Iterate over each of the handlers to enqueue the empty Catch blocks */
1388 offset = dexGetFirstHandlerOffset(pCode);
1389 int handlersSize = dexGetHandlersSize(pCode);
1390
1391 for (i = 0; i < handlersSize; i++) {
1392 DexCatchIterator iterator;
1393 dexCatchIteratorInit(&iterator, pCode, offset);
1394
1395 for (;;) {
1396 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
1397
1398 if (handler == NULL) {
1399 break;
1400 }
1401
Ben Cheng7a02cb12010-12-15 14:18:31 -08001402 /*
1403 * Create dummy catch blocks first. Since these are created before
1404 * other blocks are processed, "split" is specified as false.
1405 */
1406 findBlock(cUnit, handler->address,
1407 /* split */
1408 false,
1409 /* create */
1410 true);
Ben Cheng00603072010-10-28 11:13:58 -07001411 }
1412
1413 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
1414 }
1415}
1416
1417/* Process instructions with the kInstrCanBranch flag */
1418static void processCanBranch(CompilationUnit *cUnit, BasicBlock *curBlock,
1419 MIR *insn, int curOffset, int width, int flags,
1420 const u2* codePtr, const u2* codeEnd)
1421{
1422 int target = curOffset;
1423 switch (insn->dalvikInsn.opcode) {
1424 case OP_GOTO:
1425 case OP_GOTO_16:
1426 case OP_GOTO_32:
1427 target += (int) insn->dalvikInsn.vA;
1428 break;
1429 case OP_IF_EQ:
1430 case OP_IF_NE:
1431 case OP_IF_LT:
1432 case OP_IF_GE:
1433 case OP_IF_GT:
1434 case OP_IF_LE:
1435 target += (int) insn->dalvikInsn.vC;
1436 break;
1437 case OP_IF_EQZ:
1438 case OP_IF_NEZ:
1439 case OP_IF_LTZ:
1440 case OP_IF_GEZ:
1441 case OP_IF_GTZ:
1442 case OP_IF_LEZ:
1443 target += (int) insn->dalvikInsn.vB;
1444 break;
1445 default:
1446 LOGE("Unexpected opcode(%d) with kInstrCanBranch set",
1447 insn->dalvikInsn.opcode);
1448 dvmAbort();
1449 }
1450 BasicBlock *takenBlock = findBlock(cUnit, target,
1451 /* split */
1452 true,
1453 /* create */
1454 true);
1455 curBlock->taken = takenBlock;
1456 dvmCompilerSetBit(takenBlock->predecessors, curBlock->id);
1457
1458 /* Always terminate the current block for conditional branches */
1459 if (flags & kInstrCanContinue) {
1460 BasicBlock *fallthroughBlock = findBlock(cUnit,
1461 curOffset + width,
1462 /* split */
1463 false,
1464 /* create */
1465 true);
1466 curBlock->fallThrough = fallthroughBlock;
1467 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
1468 } else if (codePtr < codeEnd) {
1469 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
1470 if (contentIsInsn(codePtr)) {
1471 findBlock(cUnit, curOffset + width,
1472 /* split */
1473 false,
1474 /* create */
1475 true);
1476 }
1477 }
1478}
1479
1480/* Process instructions with the kInstrCanSwitch flag */
1481static void processCanSwitch(CompilationUnit *cUnit, BasicBlock *curBlock,
1482 MIR *insn, int curOffset, int width, int flags)
1483{
1484 u2 *switchData= (u2 *) (cUnit->method->insns + curOffset +
1485 insn->dalvikInsn.vB);
1486 int size;
Ben Cheng7a02cb12010-12-15 14:18:31 -08001487 int *keyTable;
Ben Cheng00603072010-10-28 11:13:58 -07001488 int *targetTable;
1489 int i;
Ben Cheng7a02cb12010-12-15 14:18:31 -08001490 int firstKey;
Ben Cheng00603072010-10-28 11:13:58 -07001491
1492 /*
1493 * Packed switch data format:
1494 * ushort ident = 0x0100 magic value
1495 * ushort size number of entries in the table
1496 * int first_key first (and lowest) switch case value
1497 * int targets[size] branch targets, relative to switch opcode
1498 *
1499 * Total size is (4+size*2) 16-bit code units.
1500 */
1501 if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
1502 assert(switchData[0] == kPackedSwitchSignature);
1503 size = switchData[1];
Ben Cheng7a02cb12010-12-15 14:18:31 -08001504 firstKey = switchData[2] | (switchData[3] << 16);
Ben Cheng00603072010-10-28 11:13:58 -07001505 targetTable = (int *) &switchData[4];
Ben Cheng7a02cb12010-12-15 14:18:31 -08001506 keyTable = NULL; // Make the compiler happy
Ben Cheng00603072010-10-28 11:13:58 -07001507 /*
1508 * Sparse switch data format:
1509 * ushort ident = 0x0200 magic value
1510 * ushort size number of entries in the table; > 0
1511 * int keys[size] keys, sorted low-to-high; 32-bit aligned
1512 * int targets[size] branch targets, relative to switch opcode
1513 *
1514 * Total size is (2+size*4) 16-bit code units.
1515 */
1516 } else {
1517 assert(switchData[0] == kSparseSwitchSignature);
1518 size = switchData[1];
Ben Cheng7a02cb12010-12-15 14:18:31 -08001519 keyTable = (int *) &switchData[2];
Ben Cheng00603072010-10-28 11:13:58 -07001520 targetTable = (int *) &switchData[2 + size*2];
Ben Cheng7a02cb12010-12-15 14:18:31 -08001521 firstKey = 0; // To make the compiler happy
Ben Cheng00603072010-10-28 11:13:58 -07001522 }
1523
1524 if (curBlock->successorBlockList.blockListType != kNotUsed) {
1525 LOGE("Successor block list already in use: %d",
1526 curBlock->successorBlockList.blockListType);
1527 dvmAbort();
1528 }
1529 curBlock->successorBlockList.blockListType =
1530 (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
1531 kPackedSwitch : kSparseSwitch;
1532 dvmInitGrowableList(&curBlock->successorBlockList.blocks, size);
1533
1534 for (i = 0; i < size; i++) {
1535 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
1536 /* split */
1537 true,
1538 /* create */
1539 true);
Ben Cheng7a02cb12010-12-15 14:18:31 -08001540 SuccessorBlockInfo *successorBlockInfo =
1541 (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo),
1542 false);
1543 successorBlockInfo->block = caseBlock;
1544 successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)?
1545 firstKey + i : keyTable[i];
Ben Cheng00603072010-10-28 11:13:58 -07001546 dvmInsertGrowableList(&curBlock->successorBlockList.blocks,
Ben Cheng7a02cb12010-12-15 14:18:31 -08001547 (intptr_t) successorBlockInfo);
Ben Cheng00603072010-10-28 11:13:58 -07001548 dvmCompilerSetBit(caseBlock->predecessors, curBlock->id);
1549 }
1550
1551 /* Fall-through case */
1552 BasicBlock *fallthroughBlock = findBlock(cUnit,
1553 curOffset + width,
1554 /* split */
1555 false,
1556 /* create */
1557 true);
1558 curBlock->fallThrough = fallthroughBlock;
1559 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
1560}
1561
1562/* Process instructions with the kInstrCanThrow flag */
1563static void processCanThrow(CompilationUnit *cUnit, BasicBlock *curBlock,
1564 MIR *insn, int curOffset, int width, int flags,
1565 BitVector *tryBlockAddr, const u2 *codePtr,
1566 const u2* codeEnd)
1567{
1568 const Method *method = cUnit->method;
1569 const DexCode *dexCode = dvmGetMethodCode(method);
1570
Ben Cheng00603072010-10-28 11:13:58 -07001571 /* In try block */
1572 if (dvmIsBitSet(tryBlockAddr, curOffset)) {
1573 DexCatchIterator iterator;
1574
1575 if (!dexFindCatchHandler(&iterator, dexCode, curOffset)) {
1576 LOGE("Catch block not found in dexfile for insn %x in %s",
1577 curOffset, method->name);
1578 dvmAbort();
1579
1580 }
1581 if (curBlock->successorBlockList.blockListType != kNotUsed) {
1582 LOGE("Successor block list already in use: %d",
1583 curBlock->successorBlockList.blockListType);
1584 dvmAbort();
1585 }
1586 curBlock->successorBlockList.blockListType = kCatch;
1587 dvmInitGrowableList(&curBlock->successorBlockList.blocks, 2);
1588
1589 for (;;) {
1590 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
1591
1592 if (handler == NULL) {
1593 break;
1594 }
1595
1596 BasicBlock *catchBlock = findBlock(cUnit, handler->address,
1597 /* split */
1598 false,
1599 /* create */
1600 false);
1601
Ben Cheng7a02cb12010-12-15 14:18:31 -08001602 SuccessorBlockInfo *successorBlockInfo =
1603 (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo),
1604 false);
1605 successorBlockInfo->block = catchBlock;
1606 successorBlockInfo->key = handler->typeIdx;
Ben Cheng00603072010-10-28 11:13:58 -07001607 dvmInsertGrowableList(&curBlock->successorBlockList.blocks,
Ben Cheng7a02cb12010-12-15 14:18:31 -08001608 (intptr_t) successorBlockInfo);
Ben Cheng00603072010-10-28 11:13:58 -07001609 dvmCompilerSetBit(catchBlock->predecessors, curBlock->id);
1610 }
1611 } else {
1612 BasicBlock *ehBlock = dvmCompilerNewBB(kExceptionHandling,
1613 cUnit->numBlocks++);
1614 curBlock->taken = ehBlock;
1615 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) ehBlock);
1616 ehBlock->startOffset = curOffset;
1617 dvmCompilerSetBit(ehBlock->predecessors, curBlock->id);
1618 }
1619
1620 /*
1621 * Force the current block to terminate.
1622 *
1623 * Data may be present before codeEnd, so we need to parse it to know
1624 * whether it is code or data.
1625 */
1626 if (codePtr < codeEnd) {
1627 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
1628 if (contentIsInsn(codePtr)) {
1629 BasicBlock *fallthroughBlock = findBlock(cUnit,
1630 curOffset + width,
1631 /* split */
1632 false,
1633 /* create */
1634 true);
1635 /*
1636 * OP_THROW and OP_THROW_VERIFICATION_ERROR are unconditional
1637 * branches.
1638 */
1639 if (insn->dalvikInsn.opcode != OP_THROW_VERIFICATION_ERROR &&
1640 insn->dalvikInsn.opcode != OP_THROW) {
1641 curBlock->fallThrough = fallthroughBlock;
1642 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
1643 }
1644 }
1645 }
1646}
1647
Ben Cheng7a2697d2010-06-07 13:44:23 -07001648/*
Ben Chengba4fc8b2009-06-01 13:00:29 -07001649 * Similar to dvmCompileTrace, but the entity processed here is the whole
1650 * method.
1651 *
1652 * TODO: implementation will be revisited when the trace builder can provide
1653 * whole-method traces.
1654 */
Ben Cheng00603072010-10-28 11:13:58 -07001655bool dvmCompileMethod(const Method *method)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001656{
Ben Cheng00603072010-10-28 11:13:58 -07001657 CompilationUnit cUnit;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001658 const DexCode *dexCode = dvmGetMethodCode(method);
1659 const u2 *codePtr = dexCode->insns;
1660 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
Ben Cheng00603072010-10-28 11:13:58 -07001661 int numBlocks = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001662 unsigned int curOffset = 0;
1663
Ben Cheng00603072010-10-28 11:13:58 -07001664 memset(&cUnit, 0, sizeof(cUnit));
1665 cUnit.method = method;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001666
Ben Cheng00603072010-10-28 11:13:58 -07001667 /* Initialize the block list */
1668 dvmInitGrowableList(&cUnit.blockList, 4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001669
1670 /* Allocate the bit-vector to track the beginning of basic blocks */
Ben Cheng00603072010-10-28 11:13:58 -07001671 BitVector *tryBlockAddr = dvmCompilerAllocBitVector(dexCode->insnsSize,
1672 true /* expandable */);
1673 cUnit.tryBlockAddr = tryBlockAddr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001674
Ben Cheng00603072010-10-28 11:13:58 -07001675 /* Create the default entry and exit blocks and enter them to the list */
1676 BasicBlock *entryBlock = dvmCompilerNewBB(kMethodEntryBlock, numBlocks++);
1677 BasicBlock *exitBlock = dvmCompilerNewBB(kMethodExitBlock, numBlocks++);
1678
1679 cUnit.entryBlock = entryBlock;
1680 cUnit.exitBlock = exitBlock;
1681
1682 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) entryBlock);
1683 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) exitBlock);
1684
1685 /* Current block to record parsed instructions */
1686 BasicBlock *curBlock = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
1687 curBlock->startOffset = 0;
1688 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) curBlock);
1689 entryBlock->fallThrough = curBlock;
1690 dvmCompilerSetBit(curBlock->predecessors, entryBlock->id);
Ben Cheng7a2697d2010-06-07 13:44:23 -07001691
Ben Chengba4fc8b2009-06-01 13:00:29 -07001692 /*
Ben Cheng00603072010-10-28 11:13:58 -07001693 * Store back the number of blocks since new blocks may be created of
1694 * accessing cUnit.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001695 */
Ben Cheng00603072010-10-28 11:13:58 -07001696 cUnit.numBlocks = numBlocks;
1697
1698 /* Identify code range in try blocks and set up the empty catch blocks */
1699 processTryCatchBlocks(&cUnit);
1700
1701 /* Parse all instructions and put them into containing basic blocks */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001702 while (codePtr < codeEnd) {
Ben Cheng00603072010-10-28 11:13:58 -07001703 MIR *insn = (MIR *) dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001704 insn->offset = curOffset;
1705 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001706 insn->width = width;
1707
Ben Cheng8b258bf2009-06-24 17:27:07 -07001708 /* Terminate when the data section is seen */
1709 if (width == 0)
1710 break;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001711
Ben Cheng00603072010-10-28 11:13:58 -07001712 dvmCompilerAppendMIR(curBlock, insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001713
1714 codePtr += width;
Ben Cheng00603072010-10-28 11:13:58 -07001715 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
1716
1717 if (flags & kInstrCanBranch) {
1718 processCanBranch(&cUnit, curBlock, insn, curOffset, width, flags,
1719 codePtr, codeEnd);
1720 } else if (flags & kInstrCanReturn) {
1721 curBlock->fallThrough = exitBlock;
1722 dvmCompilerSetBit(exitBlock->predecessors, curBlock->id);
1723 /*
1724 * Terminate the current block if there are instructions
1725 * afterwards.
1726 */
1727 if (codePtr < codeEnd) {
1728 /*
1729 * Create a fallthrough block for real instructions
1730 * (incl. OP_NOP).
1731 */
1732 if (contentIsInsn(codePtr)) {
1733 findBlock(&cUnit, curOffset + width,
1734 /* split */
1735 false,
1736 /* create */
1737 true);
1738 }
1739 }
1740 } else if (flags & kInstrCanThrow) {
1741 processCanThrow(&cUnit, curBlock, insn, curOffset, width, flags,
1742 tryBlockAddr, codePtr, codeEnd);
1743 } else if (flags & kInstrCanSwitch) {
1744 processCanSwitch(&cUnit, curBlock, insn, curOffset, width, flags);
1745 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001746 curOffset += width;
Ben Cheng00603072010-10-28 11:13:58 -07001747 BasicBlock *nextBlock = findBlock(&cUnit, curOffset,
1748 /* split */
1749 false,
1750 /* create */
1751 false);
1752 if (nextBlock) {
1753 /*
1754 * The next instruction could be the target of a previously parsed
1755 * forward branch so a block is already created. If the current
1756 * instruction is not an unconditional branch, connect them through
1757 * the fall-through link.
1758 */
1759 assert(curBlock->fallThrough == NULL ||
1760 curBlock->fallThrough == nextBlock ||
1761 curBlock->fallThrough == exitBlock);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001762
Ben Cheng00603072010-10-28 11:13:58 -07001763 if ((curBlock->fallThrough == NULL) &&
1764 !dexIsGoto(flags) &&
1765 !(flags & kInstrCanReturn)) {
1766 curBlock->fallThrough = nextBlock;
1767 dvmCompilerSetBit(nextBlock->predecessors, curBlock->id);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001768 }
Ben Cheng00603072010-10-28 11:13:58 -07001769 curBlock = nextBlock;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001770 }
1771 }
1772
Ben Cheng00603072010-10-28 11:13:58 -07001773 /* Adjust this value accordingly once inlining is performed */
1774 cUnit.numDalvikRegisters = cUnit.method->registersSize;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001775
Ben Cheng00603072010-10-28 11:13:58 -07001776 /* Verify if all blocks are connected as claimed */
1777 /* FIXME - to be disabled in the future */
1778 dvmCompilerDataFlowAnalysisDispatcher(&cUnit, verifyPredInfo,
1779 kAllNodes,
1780 false /* isIterative */);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001781
Ben Chengba4fc8b2009-06-01 13:00:29 -07001782
Ben Cheng00603072010-10-28 11:13:58 -07001783 /* Perform SSA transformation for the whole method */
1784 dvmCompilerMethodSSATransformation(&cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001785
Ben Cheng00603072010-10-28 11:13:58 -07001786 if (cUnit.printMe) dumpCFG(&cUnit, "/data/tombstones/");
Ben Chengba4fc8b2009-06-01 13:00:29 -07001787
Ben Cheng00603072010-10-28 11:13:58 -07001788 /* Reset the compiler resource pool */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001789 dvmCompilerArenaReset();
1790
Ben Cheng00603072010-10-28 11:13:58 -07001791 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001792}