blob: 1095225b37cd6f3012fb46403bf357a3ab1b022c [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:
jeffhao71eee1f2011-01-04 14:18:54 -080079 case OP_INVOKE_VIRTUAL_JUMBO:
Ben Chengba4fc8b2009-06-01 13:00:29 -070080 case OP_INVOKE_INTERFACE:
81 case OP_INVOKE_INTERFACE_RANGE:
jeffhao71eee1f2011-01-04 14:18:54 -080082 case OP_INVOKE_INTERFACE_JUMBO:
Ben Chengba4fc8b2009-06-01 13:00:29 -070083 case OP_INVOKE_VIRTUAL_QUICK:
84 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
85 *isInvoke = true;
86 break;
87 case OP_INVOKE_SUPER:
jeffhao71eee1f2011-01-04 14:18:54 -080088 case OP_INVOKE_SUPER_RANGE:
89 case OP_INVOKE_SUPER_JUMBO: {
Ben Chengba4fc8b2009-06-01 13:00:29 -070090 int mIndex = caller->clazz->pDvmDex->
91 pResMethods[insn->dalvikInsn.vB]->methodIndex;
92 const Method *calleeMethod =
93 caller->clazz->super->vtable[mIndex];
94
Ben Cheng8b258bf2009-06-24 17:27:07 -070095 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -070096 *target = (unsigned int) calleeMethod->insns;
97 }
98 *isInvoke = true;
99 *callee = calleeMethod;
100 break;
101 }
102 case OP_INVOKE_STATIC:
jeffhao71eee1f2011-01-04 14:18:54 -0800103 case OP_INVOKE_STATIC_RANGE:
104 case OP_INVOKE_STATIC_JUMBO: {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700105 const Method *calleeMethod =
106 caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
107
Ben Cheng8b258bf2009-06-24 17:27:07 -0700108 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700109 *target = (unsigned int) calleeMethod->insns;
110 }
111 *isInvoke = true;
112 *callee = calleeMethod;
113 break;
114 }
115 case OP_INVOKE_SUPER_QUICK:
116 case OP_INVOKE_SUPER_QUICK_RANGE: {
117 const Method *calleeMethod =
118 caller->clazz->super->vtable[insn->dalvikInsn.vB];
119
Ben Cheng8b258bf2009-06-24 17:27:07 -0700120 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700121 *target = (unsigned int) calleeMethod->insns;
122 }
123 *isInvoke = true;
124 *callee = calleeMethod;
125 break;
126 }
127 case OP_INVOKE_DIRECT:
jeffhao71eee1f2011-01-04 14:18:54 -0800128 case OP_INVOKE_DIRECT_RANGE:
129 case OP_INVOKE_DIRECT_JUMBO: {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700130 const Method *calleeMethod =
131 caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
Ben Cheng8b258bf2009-06-24 17:27:07 -0700132 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700133 *target = (unsigned int) calleeMethod->insns;
134 }
135 *isInvoke = true;
136 *callee = calleeMethod;
137 break;
138 }
139 case OP_GOTO:
140 case OP_GOTO_16:
141 case OP_GOTO_32:
142 *target = curOffset + (int) insn->dalvikInsn.vA;
143 break;
144
145 case OP_IF_EQ:
146 case OP_IF_NE:
147 case OP_IF_LT:
148 case OP_IF_GE:
149 case OP_IF_GT:
150 case OP_IF_LE:
151 *target = curOffset + (int) insn->dalvikInsn.vC;
152 break;
153
154 case OP_IF_EQZ:
155 case OP_IF_NEZ:
156 case OP_IF_LTZ:
157 case OP_IF_GEZ:
158 case OP_IF_GTZ:
159 case OP_IF_LEZ:
160 *target = curOffset + (int) insn->dalvikInsn.vB;
161 break;
162
163 default:
164 return false;
Ben Cheng9c147b82009-10-07 16:41:46 -0700165 }
166 return true;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700167}
168
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800169static inline bool isGoto(MIR *insn)
170{
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800171 switch (insn->dalvikInsn.opcode) {
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800172 case OP_GOTO:
173 case OP_GOTO_16:
174 case OP_GOTO_32:
175 return true;
176 default:
177 return false;
178 }
179}
180
Ben Chengba4fc8b2009-06-01 13:00:29 -0700181/*
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800182 * Identify unconditional branch instructions
Ben Chengba4fc8b2009-06-01 13:00:29 -0700183 */
184static inline bool isUnconditionalBranch(MIR *insn)
185{
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800186 switch (insn->dalvikInsn.opcode) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700187 case OP_RETURN_VOID:
188 case OP_RETURN:
189 case OP_RETURN_WIDE:
190 case OP_RETURN_OBJECT:
Ben Chengba4fc8b2009-06-01 13:00:29 -0700191 return true;
192 default:
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800193 return isGoto(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700194 }
195}
196
197/*
Ben Cheng8b258bf2009-06-24 17:27:07 -0700198 * dvmHashTableLookup() callback
199 */
200static int compareMethod(const CompilerMethodStats *m1,
201 const CompilerMethodStats *m2)
202{
203 return (int) m1->method - (int) m2->method;
204}
205
206/*
Ben Cheng7a2697d2010-06-07 13:44:23 -0700207 * Analyze the body of the method to collect high-level information regarding
208 * inlining:
209 * - is empty method?
210 * - is getter/setter?
211 * - can throw exception?
212 *
213 * Currently the inliner only handles getters and setters. When its capability
214 * becomes more sophisticated more information will be retrieved here.
215 */
216static int analyzeInlineTarget(DecodedInstruction *dalvikInsn, int attributes,
217 int offset)
218{
Dan Bornsteine4852762010-12-02 12:45:00 -0800219 int flags = dexGetFlagsFromOpcode(dalvikInsn->opcode);
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800220 int dalvikOpcode = dalvikInsn->opcode;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700221
Dan Bornstein0759f522010-11-30 14:58:53 -0800222 if (flags & kInstrInvoke) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700223 attributes &= ~METHOD_IS_LEAF;
224 }
225
226 if (!(flags & kInstrCanReturn)) {
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800227 if (!(dvmCompilerDataFlowAttributes[dalvikOpcode] &
Ben Cheng7a2697d2010-06-07 13:44:23 -0700228 DF_IS_GETTER)) {
229 attributes &= ~METHOD_IS_GETTER;
230 }
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800231 if (!(dvmCompilerDataFlowAttributes[dalvikOpcode] &
Ben Cheng7a2697d2010-06-07 13:44:23 -0700232 DF_IS_SETTER)) {
233 attributes &= ~METHOD_IS_SETTER;
234 }
235 }
236
237 /*
238 * The expected instruction sequence is setter will never return value and
239 * getter will also do. Clear the bits if the behavior is discovered
240 * otherwise.
241 */
242 if (flags & kInstrCanReturn) {
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800243 if (dalvikOpcode == OP_RETURN_VOID) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700244 attributes &= ~METHOD_IS_GETTER;
245 }
246 else {
247 attributes &= ~METHOD_IS_SETTER;
248 }
249 }
250
251 if (flags & kInstrCanThrow) {
252 attributes &= ~METHOD_IS_THROW_FREE;
253 }
254
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800255 if (offset == 0 && dalvikOpcode == OP_RETURN_VOID) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700256 attributes |= METHOD_IS_EMPTY;
257 }
258
Ben Cheng34dc7962010-08-26 14:56:31 -0700259 /*
260 * Check if this opcode is selected for single stepping.
261 * If so, don't inline the callee as there is no stack frame for the
262 * interpreter to single-step through the instruction.
263 */
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800264 if (SINGLE_STEP_OP(dalvikOpcode)) {
Ben Cheng34dc7962010-08-26 14:56:31 -0700265 attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
266 }
267
Ben Cheng7a2697d2010-06-07 13:44:23 -0700268 return attributes;
269}
270
271/*
Ben Cheng8b258bf2009-06-24 17:27:07 -0700272 * Analyze each method whose traces are ever compiled. Collect a variety of
273 * statistics like the ratio of exercised vs overall code and code bloat
Ben Cheng7a2697d2010-06-07 13:44:23 -0700274 * ratios. If isCallee is true, also analyze each instruction in more details
275 * to see if it is suitable for inlining.
Ben Cheng8b258bf2009-06-24 17:27:07 -0700276 */
Ben Cheng7a2697d2010-06-07 13:44:23 -0700277CompilerMethodStats *dvmCompilerAnalyzeMethodBody(const Method *method,
278 bool isCallee)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700279{
280 const DexCode *dexCode = dvmGetMethodCode(method);
281 const u2 *codePtr = dexCode->insns;
282 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
283 int insnSize = 0;
284 int hashValue = dvmComputeUtf8Hash(method->name);
285
286 CompilerMethodStats dummyMethodEntry; // For hash table lookup
287 CompilerMethodStats *realMethodEntry; // For hash table storage
288
289 /* For lookup only */
290 dummyMethodEntry.method = method;
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800291 realMethodEntry =
292 (CompilerMethodStats *) dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
293 &dummyMethodEntry,
294 (HashCompareFunc) compareMethod,
295 false);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700296
Ben Cheng7a2697d2010-06-07 13:44:23 -0700297 /* This method has never been analyzed before - create an entry */
298 if (realMethodEntry == NULL) {
299 realMethodEntry =
300 (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
301 realMethodEntry->method = method;
302
303 dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
304 realMethodEntry,
305 (HashCompareFunc) compareMethod,
306 true);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700307 }
308
Ben Cheng7a2697d2010-06-07 13:44:23 -0700309 /* This method is invoked as a callee and has been analyzed - just return */
310 if ((isCallee == true) && (realMethodEntry->attributes & METHOD_IS_CALLEE))
311 return realMethodEntry;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700312
Ben Cheng7a2697d2010-06-07 13:44:23 -0700313 /*
314 * Similarly, return if this method has been compiled before as a hot
315 * method already.
316 */
317 if ((isCallee == false) &&
318 (realMethodEntry->attributes & METHOD_IS_HOT))
319 return realMethodEntry;
320
321 int attributes;
322
323 /* Method hasn't been analyzed for the desired purpose yet */
324 if (isCallee) {
325 /* Aggressively set the attributes until proven otherwise */
326 attributes = METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE |
327 METHOD_IS_GETTER | METHOD_IS_SETTER;
328 } else {
329 attributes = METHOD_IS_HOT;
330 }
Ben Cheng8b258bf2009-06-24 17:27:07 -0700331
332 /* Count the number of instructions */
333 while (codePtr < codeEnd) {
334 DecodedInstruction dalvikInsn;
335 int width = parseInsn(codePtr, &dalvikInsn, false);
336
337 /* Terminate when the data section is seen */
338 if (width == 0)
339 break;
340
Ben Cheng7a2697d2010-06-07 13:44:23 -0700341 if (isCallee) {
342 attributes = analyzeInlineTarget(&dalvikInsn, attributes, insnSize);
343 }
344
Ben Cheng8b258bf2009-06-24 17:27:07 -0700345 insnSize += width;
346 codePtr += width;
347 }
348
Ben Cheng7a2697d2010-06-07 13:44:23 -0700349 /*
350 * Only handle simple getters/setters with one instruction followed by
351 * return
352 */
353 if ((attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) &&
354 (insnSize != 3)) {
355 attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
356 }
357
Ben Cheng8b258bf2009-06-24 17:27:07 -0700358 realMethodEntry->dalvikSize = insnSize * 2;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700359 realMethodEntry->attributes |= attributes;
360
361#if 0
362 /* Uncomment the following to explore various callee patterns */
363 if (attributes & METHOD_IS_THROW_FREE) {
364 LOGE("%s%s is inlinable%s", method->clazz->descriptor, method->name,
365 (attributes & METHOD_IS_EMPTY) ? " empty" : "");
366 }
367
368 if (attributes & METHOD_IS_LEAF) {
369 LOGE("%s%s is leaf %d%s", method->clazz->descriptor, method->name,
370 insnSize, insnSize < 5 ? " (small)" : "");
371 }
372
373 if (attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) {
374 LOGE("%s%s is %s", method->clazz->descriptor, method->name,
375 attributes & METHOD_IS_GETTER ? "getter": "setter");
376 }
377 if (attributes ==
378 (METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE)) {
379 LOGE("%s%s is inlinable non setter/getter", method->clazz->descriptor,
380 method->name);
381 }
382#endif
383
Ben Cheng8b258bf2009-06-24 17:27:07 -0700384 return realMethodEntry;
385}
386
387/*
Ben Cheng33672452010-01-12 14:59:30 -0800388 * Crawl the stack of the thread that requesed compilation to see if any of the
389 * ancestors are on the blacklist.
390 */
Andy McFadden953a0ed2010-09-17 15:48:38 -0700391static bool filterMethodByCallGraph(Thread *thread, const char *curMethodName)
Ben Cheng33672452010-01-12 14:59:30 -0800392{
393 /* Crawl the Dalvik stack frames and compare the method name*/
394 StackSaveArea *ssaPtr = ((StackSaveArea *) thread->curFrame) - 1;
395 while (ssaPtr != ((StackSaveArea *) NULL) - 1) {
396 const Method *method = ssaPtr->method;
397 if (method) {
398 int hashValue = dvmComputeUtf8Hash(method->name);
399 bool found =
400 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
401 (char *) method->name,
402 (HashCompareFunc) strcmp, false) !=
403 NULL;
404 if (found) {
405 LOGD("Method %s (--> %s) found on the JIT %s list",
406 method->name, curMethodName,
407 gDvmJit.includeSelectedMethod ? "white" : "black");
408 return true;
409 }
410
411 }
412 ssaPtr = ((StackSaveArea *) ssaPtr->prevFrame) - 1;
413 };
414 return false;
415}
416
417/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700418 * Main entry point to start trace compilation. Basic blocks are constructed
419 * first and they will be passed to the codegen routines to convert Dalvik
420 * bytecode into machine code.
421 */
Bill Buzbee716f1202009-07-23 13:22:09 -0700422bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
Ben Cheng4a419582010-08-04 13:23:09 -0700423 JitTranslationInfo *info, jmp_buf *bailPtr,
424 int optHints)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700425{
426 const DexCode *dexCode = dvmGetMethodCode(desc->method);
427 const JitTraceRun* currRun = &desc->trace[0];
Ben Chengba4fc8b2009-06-01 13:00:29 -0700428 unsigned int curOffset = currRun->frag.startOffset;
429 unsigned int numInsts = currRun->frag.numInsts;
430 const u2 *codePtr = dexCode->insns + curOffset;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700431 int traceSize = 0; // # of half-words
Ben Chengba4fc8b2009-06-01 13:00:29 -0700432 const u2 *startCodePtr = codePtr;
Ben Cheng00603072010-10-28 11:13:58 -0700433 BasicBlock *curBB, *entryCodeBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700434 int numBlocks = 0;
435 static int compilationId;
436 CompilationUnit cUnit;
Ben Cheng00603072010-10-28 11:13:58 -0700437 GrowableList *blockList;
Ben Cheng1357e942010-02-10 17:21:39 -0800438#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700439 CompilerMethodStats *methodStats;
Ben Cheng1357e942010-02-10 17:21:39 -0800440#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700441
Bill Buzbee964a7b02010-01-28 12:54:19 -0800442 /* If we've already compiled this trace, just return success */
jeffhao9e45c0b2010-02-03 10:24:05 -0800443 if (dvmJitGetCodeAddr(startCodePtr) && !info->discardResult) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700444 /*
445 * Make sure the codeAddress is NULL so that it won't clobber the
446 * existing entry.
447 */
448 info->codeAddress = NULL;
Bill Buzbee964a7b02010-01-28 12:54:19 -0800449 return true;
450 }
451
buzbee18fba342011-01-19 15:31:15 -0800452 /* If the work order is stale, discard it */
453 if (info->cacheVersion != gDvmJit.cacheVersion) {
454 return false;
455 }
456
Ben Chenge9695e52009-06-16 16:11:47 -0700457 compilationId++;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700458 memset(&cUnit, 0, sizeof(CompilationUnit));
459
Ben Cheng1357e942010-02-10 17:21:39 -0800460#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700461 /* Locate the entry to store compilation statistics for this method */
Ben Cheng7a2697d2010-06-07 13:44:23 -0700462 methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
Ben Cheng1357e942010-02-10 17:21:39 -0800463#endif
Ben Chenge9695e52009-06-16 16:11:47 -0700464
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800465 /* Set the recover buffer pointer */
466 cUnit.bailPtr = bailPtr;
467
Ben Chengba4fc8b2009-06-01 13:00:29 -0700468 /* Initialize the printMe flag */
469 cUnit.printMe = gDvmJit.printMe;
470
Ben Cheng7a2697d2010-06-07 13:44:23 -0700471 /* Setup the method */
472 cUnit.method = desc->method;
473
474 /* Initialize the PC reconstruction list */
475 dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
476
Ben Cheng00603072010-10-28 11:13:58 -0700477 /* Initialize the basic block list */
478 blockList = &cUnit.blockList;
479 dvmInitGrowableList(blockList, 8);
480
Ben Chengba4fc8b2009-06-01 13:00:29 -0700481 /* Identify traces that we don't want to compile */
482 if (gDvmJit.methodTable) {
483 int len = strlen(desc->method->clazz->descriptor) +
484 strlen(desc->method->name) + 1;
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800485 char *fullSignature = (char *)dvmCompilerNew(len, true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700486 strcpy(fullSignature, desc->method->clazz->descriptor);
487 strcat(fullSignature, desc->method->name);
488
489 int hashValue = dvmComputeUtf8Hash(fullSignature);
490
491 /*
492 * Doing three levels of screening to see whether we want to skip
493 * compiling this method
494 */
495
496 /* First, check the full "class;method" signature */
497 bool methodFound =
498 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
499 fullSignature, (HashCompareFunc) strcmp,
500 false) !=
501 NULL;
502
503 /* Full signature not found - check the enclosing class */
504 if (methodFound == false) {
505 int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
506 methodFound =
507 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
508 (char *) desc->method->clazz->descriptor,
509 (HashCompareFunc) strcmp, false) !=
510 NULL;
511 /* Enclosing class not found - check the method name */
512 if (methodFound == false) {
513 int hashValue = dvmComputeUtf8Hash(desc->method->name);
514 methodFound =
515 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
516 (char *) desc->method->name,
517 (HashCompareFunc) strcmp, false) !=
518 NULL;
Ben Cheng33672452010-01-12 14:59:30 -0800519
520 /*
521 * Debug by call-graph is enabled. Check if the debug list
522 * covers any methods on the VM stack.
523 */
524 if (methodFound == false && gDvmJit.checkCallGraph == true) {
525 methodFound =
526 filterMethodByCallGraph(info->requestingThread,
527 desc->method->name);
528 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700529 }
530 }
531
532 /*
533 * Under the following conditions, the trace will be *conservatively*
534 * compiled by only containing single-step instructions to and from the
535 * interpreter.
536 * 1) If includeSelectedMethod == false, the method matches the full or
537 * partial signature stored in the hash table.
538 *
539 * 2) If includeSelectedMethod == true, the method does not match the
540 * full and partial signature stored in the hash table.
541 */
542 if (gDvmJit.includeSelectedMethod != methodFound) {
543 cUnit.allSingleStep = true;
544 } else {
545 /* Compile the trace as normal */
546
547 /* Print the method we cherry picked */
548 if (gDvmJit.includeSelectedMethod == true) {
549 cUnit.printMe = true;
550 }
551 }
552 }
553
Ben Cheng4238ec22009-08-24 16:32:22 -0700554 /* Allocate the entry block */
Ben Cheng00603072010-10-28 11:13:58 -0700555 curBB = dvmCompilerNewBB(kTraceEntryBlock, numBlocks++);
556 dvmInsertGrowableList(blockList, (intptr_t) curBB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700557 curBB->startOffset = curOffset;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700558
Ben Cheng00603072010-10-28 11:13:58 -0700559 entryCodeBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
560 dvmInsertGrowableList(blockList, (intptr_t) entryCodeBB);
561 entryCodeBB->startOffset = curOffset;
562 curBB->fallThrough = entryCodeBB;
563 curBB = entryCodeBB;
Ben Cheng4238ec22009-08-24 16:32:22 -0700564
Ben Chengba4fc8b2009-06-01 13:00:29 -0700565 if (cUnit.printMe) {
566 LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n",
567 desc->method->name, curOffset);
568 }
569
Ben Cheng1efc9c52009-06-08 18:25:27 -0700570 /*
571 * Analyze the trace descriptor and include up to the maximal number
572 * of Dalvik instructions into the IR.
573 */
574 while (1) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700575 MIR *insn;
576 int width;
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800577 insn = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700578 insn->offset = curOffset;
579 width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700580
581 /* The trace should never incude instruction data */
582 assert(width);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700583 insn->width = width;
584 traceSize += width;
585 dvmCompilerAppendMIR(curBB, insn);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700586 cUnit.numInsts++;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700587
Dan Bornsteine4852762010-12-02 12:45:00 -0800588 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700589
Dan Bornstein0759f522010-11-30 14:58:53 -0800590 if (flags & kInstrInvoke) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700591 assert(numInsts == 1);
592 CallsiteInfo *callsiteInfo =
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800593 (CallsiteInfo *)dvmCompilerNew(sizeof(CallsiteInfo), true);
594 callsiteInfo->clazz = (ClassObject *)currRun[1].meta;
595 callsiteInfo->method = (Method *)currRun[2].meta;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700596 insn->meta.callsiteInfo = callsiteInfo;
597 }
598
Ben Cheng1efc9c52009-06-08 18:25:27 -0700599 /* Instruction limit reached - terminate the trace here */
600 if (cUnit.numInsts >= numMaxInsts) {
601 break;
602 }
603 if (--numInsts == 0) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700604 if (currRun->frag.runEnd) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700605 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700606 } else {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700607 /* Advance to the next trace description (ie non-meta info) */
608 do {
609 currRun++;
610 } while (!currRun->frag.isCode);
611
612 /* Dummy end-of-run marker seen */
613 if (currRun->frag.numInsts == 0) {
614 break;
615 }
616
Ben Cheng00603072010-10-28 11:13:58 -0700617 curBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
618 dvmInsertGrowableList(blockList, (intptr_t) curBB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700619 curOffset = currRun->frag.startOffset;
620 numInsts = currRun->frag.numInsts;
621 curBB->startOffset = curOffset;
622 codePtr = dexCode->insns + curOffset;
623 }
624 } else {
625 curOffset += width;
626 codePtr += width;
627 }
628 }
629
Ben Cheng1357e942010-02-10 17:21:39 -0800630#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700631 /* Convert # of half-word to bytes */
632 methodStats->compiledDalvikSize += traceSize * 2;
Ben Cheng1357e942010-02-10 17:21:39 -0800633#endif
Ben Cheng8b258bf2009-06-24 17:27:07 -0700634
Ben Chengba4fc8b2009-06-01 13:00:29 -0700635 /*
636 * Now scan basic blocks containing real code to connect the
637 * taken/fallthrough links. Also create chaining cells for code not included
638 * in the trace.
639 */
Ben Cheng00603072010-10-28 11:13:58 -0700640 size_t blockId;
641 for (blockId = 0; blockId < blockList->numUsed; blockId++) {
642 curBB = (BasicBlock *) dvmGrowableListGetElement(blockList, blockId);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700643 MIR *lastInsn = curBB->lastMIRInsn;
buzbee2e152ba2010-12-15 16:32:35 -0800644 BasicBlock *backwardCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700645 /* Skip empty blocks */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700646 if (lastInsn == NULL) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700647 continue;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700648 }
649 curOffset = lastInsn->offset;
650 unsigned int targetOffset = curOffset;
651 unsigned int fallThroughOffset = curOffset + lastInsn->width;
652 bool isInvoke = false;
653 const Method *callee = NULL;
654
655 findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
656 &targetOffset, &isInvoke, &callee);
657
658 /* Link the taken and fallthrough blocks */
659 BasicBlock *searchBB;
660
Dan Bornsteine4852762010-12-02 12:45:00 -0800661 int flags = dexGetFlagsFromOpcode(lastInsn->dalvikInsn.opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -0700662
663 if (flags & kInstrInvoke) {
664 cUnit.hasInvoke = true;
665 }
666
Ben Chengba4fc8b2009-06-01 13:00:29 -0700667 /* No backward branch in the trace - start searching the next BB */
Ben Cheng00603072010-10-28 11:13:58 -0700668 size_t searchBlockId;
669 for (searchBlockId = blockId+1; searchBlockId < blockList->numUsed;
670 searchBlockId++) {
671 searchBB = (BasicBlock *) dvmGrowableListGetElement(blockList,
672 searchBlockId);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700673 if (targetOffset == searchBB->startOffset) {
674 curBB->taken = searchBB;
675 }
676 if (fallThroughOffset == searchBB->startOffset) {
677 curBB->fallThrough = searchBB;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700678
679 /*
680 * Fallthrough block of an invoke instruction needs to be
681 * aligned to 4-byte boundary (alignment instruction to be
682 * inserted later.
683 */
684 if (flags & kInstrInvoke) {
685 searchBB->isFallThroughFromInvoke = true;
686 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700687 }
688 }
689
Ben Cheng1efc9c52009-06-08 18:25:27 -0700690 /*
691 * Some blocks are ended by non-control-flow-change instructions,
692 * currently only due to trace length constraint. In this case we need
693 * to generate an explicit branch at the end of the block to jump to
694 * the chaining cell.
695 */
696 curBB->needFallThroughBranch =
Ben Cheng17f15ce2009-07-27 16:21:52 -0700697 ((flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
Dan Bornstein0759f522010-11-30 14:58:53 -0800698 kInstrInvoke)) == 0);
Ben Cheng17f15ce2009-07-27 16:21:52 -0700699
Ben Cheng4a419582010-08-04 13:23:09 -0700700 /* Only form a loop if JIT_OPT_NO_LOOP is not set */
Ben Cheng4238ec22009-08-24 16:32:22 -0700701 if (curBB->taken == NULL &&
702 curBB->fallThrough == NULL &&
703 flags == (kInstrCanBranch | kInstrCanContinue) &&
Ben Cheng00603072010-10-28 11:13:58 -0700704 fallThroughOffset == entryCodeBB->startOffset &&
Ben Cheng4a419582010-08-04 13:23:09 -0700705 JIT_OPT_NO_LOOP != (optHints & JIT_OPT_NO_LOOP)) {
Ben Cheng0fd31e42009-09-03 14:40:16 -0700706 BasicBlock *loopBranch = curBB;
707 BasicBlock *exitBB;
708 BasicBlock *exitChainingCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700709
710 if (cUnit.printMe) {
711 LOGD("Natural loop detected!");
712 }
Ben Cheng00603072010-10-28 11:13:58 -0700713 exitBB = dvmCompilerNewBB(kTraceExitBlock, numBlocks++);
714 dvmInsertGrowableList(blockList, (intptr_t) exitBB);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700715 exitBB->startOffset = targetOffset;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700716 exitBB->needFallThroughBranch = true;
Ben Cheng4238ec22009-08-24 16:32:22 -0700717
Ben Cheng0fd31e42009-09-03 14:40:16 -0700718 loopBranch->taken = exitBB;
buzbee2e152ba2010-12-15 16:32:35 -0800719 backwardCell =
Ben Cheng00603072010-10-28 11:13:58 -0700720 dvmCompilerNewBB(kChainingCellBackwardBranch, numBlocks++);
721 dvmInsertGrowableList(blockList, (intptr_t) backwardCell);
722 backwardCell->startOffset = entryCodeBB->startOffset;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700723 loopBranch->fallThrough = backwardCell;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700724
725 /* Create the chaining cell as the fallthrough of the exit block */
Ben Cheng00603072010-10-28 11:13:58 -0700726 exitChainingCell = dvmCompilerNewBB(kChainingCellNormal,
727 numBlocks++);
728 dvmInsertGrowableList(blockList, (intptr_t) exitChainingCell);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700729 exitChainingCell->startOffset = targetOffset;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700730
731 exitBB->fallThrough = exitChainingCell;
732
Ben Cheng4238ec22009-08-24 16:32:22 -0700733 cUnit.hasLoop = true;
734 }
735
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800736 if (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ||
737 lastInsn->dalvikInsn.opcode == OP_SPARSE_SWITCH) {
Ben Cheng6c10a972009-10-29 14:39:18 -0700738 int i;
739 const u2 *switchData = desc->method->insns + lastInsn->offset +
740 lastInsn->dalvikInsn.vB;
741 int size = switchData[1];
742 int maxChains = MIN(size, MAX_CHAINED_SWITCH_CASES);
743
744 /*
745 * Generate the landing pad for cases whose ranks are higher than
746 * MAX_CHAINED_SWITCH_CASES. The code will re-enter the interpreter
747 * through the NoChain point.
748 */
749 if (maxChains != size) {
750 cUnit.switchOverflowPad =
751 desc->method->insns + lastInsn->offset;
752 }
753
754 s4 *targets = (s4 *) (switchData + 2 +
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800755 (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ?
Ben Cheng6c10a972009-10-29 14:39:18 -0700756 2 : size * 2));
757
758 /* One chaining cell for the first MAX_CHAINED_SWITCH_CASES cases */
759 for (i = 0; i < maxChains; i++) {
Ben Cheng00603072010-10-28 11:13:58 -0700760 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal,
761 numBlocks++);
762 dvmInsertGrowableList(blockList, (intptr_t) caseChain);
Ben Cheng6c10a972009-10-29 14:39:18 -0700763 caseChain->startOffset = lastInsn->offset + targets[i];
Ben Cheng6c10a972009-10-29 14:39:18 -0700764 }
765
766 /* One more chaining cell for the default case */
Ben Cheng00603072010-10-28 11:13:58 -0700767 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal,
768 numBlocks++);
769 dvmInsertGrowableList(blockList, (intptr_t) caseChain);
Ben Cheng6c10a972009-10-29 14:39:18 -0700770 caseChain->startOffset = lastInsn->offset + lastInsn->width;
Ben Cheng6d576092009-09-01 17:01:58 -0700771 /* Fallthrough block not included in the trace */
Ben Cheng6c10a972009-10-29 14:39:18 -0700772 } else if (!isUnconditionalBranch(lastInsn) &&
773 curBB->fallThrough == NULL) {
Ben Cheng00603072010-10-28 11:13:58 -0700774 BasicBlock *fallThroughBB;
Ben Cheng6d576092009-09-01 17:01:58 -0700775 /*
776 * If the chaining cell is after an invoke or
777 * instruction that cannot change the control flow, request a hot
778 * chaining cell.
779 */
780 if (isInvoke || curBB->needFallThroughBranch) {
Ben Cheng00603072010-10-28 11:13:58 -0700781 fallThroughBB = dvmCompilerNewBB(kChainingCellHot, numBlocks++);
Ben Cheng6d576092009-09-01 17:01:58 -0700782 } else {
Ben Cheng00603072010-10-28 11:13:58 -0700783 fallThroughBB = dvmCompilerNewBB(kChainingCellNormal,
784 numBlocks++);
Ben Cheng6d576092009-09-01 17:01:58 -0700785 }
Ben Cheng00603072010-10-28 11:13:58 -0700786 dvmInsertGrowableList(blockList, (intptr_t) fallThroughBB);
787 fallThroughBB->startOffset = fallThroughOffset;
788 curBB->fallThrough = fallThroughBB;
Ben Cheng6d576092009-09-01 17:01:58 -0700789 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700790 /* Target block not included in the trace */
Ben Cheng38329f52009-07-07 14:19:20 -0700791 if (curBB->taken == NULL &&
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800792 (isGoto(lastInsn) || isInvoke ||
793 (targetOffset != UNKNOWN_TARGET && targetOffset != curOffset))) {
Ben Cheng7e2c3c72010-12-22 16:40:46 -0800794 BasicBlock *newBB = NULL;
Ben Cheng1efc9c52009-06-08 18:25:27 -0700795 if (isInvoke) {
Ben Cheng38329f52009-07-07 14:19:20 -0700796 /* Monomorphic callee */
797 if (callee) {
Ben Cheng7e2c3c72010-12-22 16:40:46 -0800798 /* JNI call doesn't need a chaining cell */
799 if (!dvmIsNativeMethod(callee)) {
800 newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton,
801 numBlocks++);
802 newBB->startOffset = 0;
803 newBB->containingMethod = callee;
804 }
Ben Cheng38329f52009-07-07 14:19:20 -0700805 /* Will resolve at runtime */
806 } else {
Ben Cheng00603072010-10-28 11:13:58 -0700807 newBB = dvmCompilerNewBB(kChainingCellInvokePredicted,
808 numBlocks++);
Ben Cheng38329f52009-07-07 14:19:20 -0700809 newBB->startOffset = 0;
810 }
Ben Cheng1efc9c52009-06-08 18:25:27 -0700811 /* For unconditional branches, request a hot chaining cell */
812 } else {
Jeff Hao97319a82009-08-12 16:57:15 -0700813#if !defined(WITH_SELF_VERIFICATION)
Dan Bornsteinc2b486f2010-11-12 16:07:16 -0800814 newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700815 kChainingCellHot :
Ben Cheng00603072010-10-28 11:13:58 -0700816 kChainingCellNormal,
817 numBlocks++);
Ben Cheng38329f52009-07-07 14:19:20 -0700818 newBB->startOffset = targetOffset;
Jeff Hao97319a82009-08-12 16:57:15 -0700819#else
820 /* Handle branches that branch back into the block */
821 if (targetOffset >= curBB->firstMIRInsn->offset &&
822 targetOffset <= curBB->lastMIRInsn->offset) {
Ben Cheng00603072010-10-28 11:13:58 -0700823 newBB = dvmCompilerNewBB(kChainingCellBackwardBranch,
824 numBlocks++);
Jeff Hao97319a82009-08-12 16:57:15 -0700825 } else {
Dan Bornsteinc2b486f2010-11-12 16:07:16 -0800826 newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700827 kChainingCellHot :
Ben Cheng00603072010-10-28 11:13:58 -0700828 kChainingCellNormal,
829 numBlocks++);
Jeff Hao97319a82009-08-12 16:57:15 -0700830 }
831 newBB->startOffset = targetOffset;
832#endif
Ben Cheng1efc9c52009-06-08 18:25:27 -0700833 }
Ben Cheng7e2c3c72010-12-22 16:40:46 -0800834 if (newBB) {
835 curBB->taken = newBB;
836 dvmInsertGrowableList(blockList, (intptr_t) newBB);
837 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700838 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700839 }
840
841 /* Now create a special block to host PC reconstruction code */
Ben Cheng00603072010-10-28 11:13:58 -0700842 curBB = dvmCompilerNewBB(kPCReconstruction, numBlocks++);
843 dvmInsertGrowableList(blockList, (intptr_t) curBB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700844
845 /* And one final block that publishes the PC and raise the exception */
Ben Cheng00603072010-10-28 11:13:58 -0700846 curBB = dvmCompilerNewBB(kExceptionHandling, numBlocks++);
847 dvmInsertGrowableList(blockList, (intptr_t) curBB);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700848
849 if (cUnit.printMe) {
Ben Cheng00603072010-10-28 11:13:58 -0700850 char* signature =
851 dexProtoCopyMethodDescriptor(&desc->method->prototype);
Elliott Hughescc6fac82010-07-02 13:38:44 -0700852 LOGD("TRACEINFO (%d): 0x%08x %s%s.%s 0x%x %d of %d, %d blocks",
Ben Chenge9695e52009-06-16 16:11:47 -0700853 compilationId,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700854 (intptr_t) desc->method->insns,
855 desc->method->clazz->descriptor,
856 desc->method->name,
Elliott Hughescc6fac82010-07-02 13:38:44 -0700857 signature,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700858 desc->trace[0].frag.startOffset,
859 traceSize,
860 dexCode->insnsSize,
861 numBlocks);
Elliott Hughescc6fac82010-07-02 13:38:44 -0700862 free(signature);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700863 }
864
Ben Chengba4fc8b2009-06-01 13:00:29 -0700865 cUnit.traceDesc = desc;
866 cUnit.numBlocks = numBlocks;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700867
Ben Cheng7a2697d2010-06-07 13:44:23 -0700868 /* Set the instruction set to use (NOTE: later components may change it) */
869 cUnit.instructionSet = dvmCompilerInstructionSet();
870
871 /* Inline transformation @ the MIR level */
872 if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) {
873 dvmCompilerInlineMIR(&cUnit);
874 }
875
Ben Cheng00603072010-10-28 11:13:58 -0700876 cUnit.numDalvikRegisters = cUnit.method->registersSize;
877
Ben Cheng4238ec22009-08-24 16:32:22 -0700878 /* Preparation for SSA conversion */
879 dvmInitializeSSAConversion(&cUnit);
880
881 if (cUnit.hasLoop) {
Ben Cheng4a419582010-08-04 13:23:09 -0700882 /*
883 * Loop is not optimizable (for example lack of a single induction
884 * variable), punt and recompile the trace with loop optimization
885 * disabled.
886 */
887 bool loopOpt = dvmCompilerLoopOpt(&cUnit);
888 if (loopOpt == false) {
889 if (cUnit.printMe) {
890 LOGD("Loop is not optimizable - retry codegen");
891 }
892 /* Reset the compiler resource pool */
893 dvmCompilerArenaReset();
894 return dvmCompileTrace(desc, cUnit.numInsts, info, bailPtr,
895 optHints | JIT_OPT_NO_LOOP);
896 }
Ben Cheng4238ec22009-08-24 16:32:22 -0700897 }
898 else {
899 dvmCompilerNonLoopAnalysis(&cUnit);
900 }
901
Bill Buzbee1465db52009-09-23 17:17:35 -0700902 dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
903
Ben Chengba4fc8b2009-06-01 13:00:29 -0700904 if (cUnit.printMe) {
905 dvmCompilerDumpCompilationUnit(&cUnit);
906 }
907
buzbee23d95d02010-12-14 13:16:43 -0800908 /* Allocate Registers using simple local allocation scheme */
909 dvmCompilerLocalRegAlloc(&cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -0700910
Ben Chengba4fc8b2009-06-01 13:00:29 -0700911 /* Convert MIR to LIR, etc. */
912 dvmCompilerMIR2LIR(&cUnit);
913
buzbeebff121a2010-08-04 15:25:06 -0700914 /* Convert LIR into machine code. Loop for recoverable retries */
915 do {
916 dvmCompilerAssembleLIR(&cUnit, info);
917 cUnit.assemblerRetries++;
918 if (cUnit.printMe && cUnit.assemblerStatus != kSuccess)
919 LOGD("Assembler abort #%d on %d",cUnit.assemblerRetries,
920 cUnit.assemblerStatus);
921 } while (cUnit.assemblerStatus == kRetryAll);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700922
923 if (cUnit.printMe) {
buzbeebff121a2010-08-04 15:25:06 -0700924 dvmCompilerCodegenDump(&cUnit);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700925 LOGD("End %s%s, %d Dalvik instructions",
926 desc->method->clazz->descriptor, desc->method->name,
927 cUnit.numInsts);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700928 }
929
930 /* Reset the compiler resource pool */
931 dvmCompilerArenaReset();
932
buzbeebff121a2010-08-04 15:25:06 -0700933 if (cUnit.assemblerStatus == kRetryHalve) {
934 /* Halve the instruction count and start from the top */
Ben Cheng4a419582010-08-04 13:23:09 -0700935 return dvmCompileTrace(desc, cUnit.numInsts / 2, info, bailPtr,
936 optHints);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700937 }
buzbeebff121a2010-08-04 15:25:06 -0700938
939 assert(cUnit.assemblerStatus == kSuccess);
940#if defined(WITH_JIT_TUNING)
941 methodStats->nativeSize += cUnit.totalSize;
942#endif
Ben Cheng00603072010-10-28 11:13:58 -0700943
944 /* FIXME - to exercise the method parser, uncomment the following code */
945#if 0
946 bool dvmCompileMethod(const Method *method);
947 if (desc->trace[0].frag.startOffset == 0) {
948 dvmCompileMethod(desc->method);
949 }
950#endif
951
buzbeebff121a2010-08-04 15:25:06 -0700952 return info->codeAddress != NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700953}
954
955/*
Ben Cheng7a2697d2010-06-07 13:44:23 -0700956 * Since we are including instructions from possibly a cold method into the
957 * current trace, we need to make sure that all the associated information
958 * with the callee is properly initialized. If not, we punt on this inline
959 * target.
960 *
Ben Cheng34dc7962010-08-26 14:56:31 -0700961 * TODO: volatile instructions will be handled later.
Ben Cheng7a2697d2010-06-07 13:44:23 -0700962 */
963bool dvmCompilerCanIncludeThisInstruction(const Method *method,
964 const DecodedInstruction *insn)
965{
Dan Bornstein9a1f8162010-12-01 17:02:26 -0800966 switch (insn->opcode) {
Ben Cheng7a2697d2010-06-07 13:44:23 -0700967 case OP_NEW_INSTANCE:
jeffhao71eee1f2011-01-04 14:18:54 -0800968 case OP_NEW_INSTANCE_JUMBO:
969 case OP_CHECK_CAST:
970 case OP_CHECK_CAST_JUMBO: {
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800971 ClassObject *classPtr = (ClassObject *)(void*)
Ben Cheng7a2697d2010-06-07 13:44:23 -0700972 (method->clazz->pDvmDex->pResClasses[insn->vB]);
973
974 /* Class hasn't been initialized yet */
975 if (classPtr == NULL) {
976 return false;
977 }
978 return true;
979 }
Ben Cheng7a2697d2010-06-07 13:44:23 -0700980 case OP_SGET:
jeffhao71eee1f2011-01-04 14:18:54 -0800981 case OP_SGET_JUMBO:
Ben Cheng7a2697d2010-06-07 13:44:23 -0700982 case OP_SGET_WIDE:
jeffhao71eee1f2011-01-04 14:18:54 -0800983 case OP_SGET_WIDE_JUMBO:
984 case OP_SGET_OBJECT:
985 case OP_SGET_OBJECT_JUMBO:
986 case OP_SGET_BOOLEAN:
987 case OP_SGET_BOOLEAN_JUMBO:
988 case OP_SGET_BYTE:
989 case OP_SGET_BYTE_JUMBO:
990 case OP_SGET_CHAR:
991 case OP_SGET_CHAR_JUMBO:
992 case OP_SGET_SHORT:
993 case OP_SGET_SHORT_JUMBO:
Ben Cheng7a2697d2010-06-07 13:44:23 -0700994 case OP_SPUT:
jeffhao71eee1f2011-01-04 14:18:54 -0800995 case OP_SPUT_JUMBO:
996 case OP_SPUT_WIDE:
997 case OP_SPUT_WIDE_JUMBO:
998 case OP_SPUT_OBJECT:
999 case OP_SPUT_OBJECT_JUMBO:
1000 case OP_SPUT_BOOLEAN:
1001 case OP_SPUT_BOOLEAN_JUMBO:
1002 case OP_SPUT_BYTE:
1003 case OP_SPUT_BYTE_JUMBO:
1004 case OP_SPUT_CHAR:
1005 case OP_SPUT_CHAR_JUMBO:
1006 case OP_SPUT_SHORT:
1007 case OP_SPUT_SHORT_JUMBO: {
Ben Cheng7a2697d2010-06-07 13:44:23 -07001008 void *fieldPtr = (void*)
1009 (method->clazz->pDvmDex->pResFields[insn->vB]);
1010
1011 if (fieldPtr == NULL) {
1012 return false;
1013 }
1014 return true;
1015 }
1016 case OP_INVOKE_SUPER:
jeffhao71eee1f2011-01-04 14:18:54 -08001017 case OP_INVOKE_SUPER_RANGE:
1018 case OP_INVOKE_SUPER_JUMBO: {
Ben Cheng7a2697d2010-06-07 13:44:23 -07001019 int mIndex = method->clazz->pDvmDex->
1020 pResMethods[insn->vB]->methodIndex;
1021 const Method *calleeMethod = method->clazz->super->vtable[mIndex];
1022 if (calleeMethod == NULL) {
1023 return false;
1024 }
1025 return true;
1026 }
1027 case OP_INVOKE_SUPER_QUICK:
1028 case OP_INVOKE_SUPER_QUICK_RANGE: {
1029 const Method *calleeMethod = method->clazz->super->vtable[insn->vB];
1030 if (calleeMethod == NULL) {
1031 return false;
1032 }
1033 return true;
1034 }
1035 case OP_INVOKE_STATIC:
1036 case OP_INVOKE_STATIC_RANGE:
jeffhao71eee1f2011-01-04 14:18:54 -08001037 case OP_INVOKE_STATIC_JUMBO:
Ben Cheng7a2697d2010-06-07 13:44:23 -07001038 case OP_INVOKE_DIRECT:
jeffhao71eee1f2011-01-04 14:18:54 -08001039 case OP_INVOKE_DIRECT_RANGE:
1040 case OP_INVOKE_DIRECT_JUMBO: {
Ben Cheng7a2697d2010-06-07 13:44:23 -07001041 const Method *calleeMethod =
1042 method->clazz->pDvmDex->pResMethods[insn->vB];
1043 if (calleeMethod == NULL) {
1044 return false;
1045 }
1046 return true;
1047 }
jeffhao71eee1f2011-01-04 14:18:54 -08001048 case OP_CONST_CLASS:
1049 case OP_CONST_CLASS_JUMBO: {
Ben Cheng7a2697d2010-06-07 13:44:23 -07001050 void *classPtr = (void*)
1051 (method->clazz->pDvmDex->pResClasses[insn->vB]);
1052
1053 if (classPtr == NULL) {
1054 return false;
1055 }
1056 return true;
1057 }
1058 case OP_CONST_STRING_JUMBO:
1059 case OP_CONST_STRING: {
1060 void *strPtr = (void*)
1061 (method->clazz->pDvmDex->pResStrings[insn->vB]);
1062
1063 if (strPtr == NULL) {
1064 return false;
1065 }
1066 return true;
1067 }
1068 default:
1069 return true;
1070 }
1071}
1072
Ben Cheng00603072010-10-28 11:13:58 -07001073/* Split an existing block from the specified code offset into two */
1074static BasicBlock *splitBlock(CompilationUnit *cUnit,
1075 unsigned int codeOffset,
1076 BasicBlock *origBlock)
1077{
1078 MIR *insn = origBlock->firstMIRInsn;
1079 while (insn) {
1080 if (insn->offset == codeOffset) break;
1081 insn = insn->next;
1082 }
1083 if (insn == NULL) {
1084 LOGE("Break split failed");
1085 dvmAbort();
1086 }
1087 BasicBlock *bottomBlock = dvmCompilerNewBB(kDalvikByteCode,
1088 cUnit->numBlocks++);
1089 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bottomBlock);
1090
1091 bottomBlock->startOffset = codeOffset;
1092 bottomBlock->firstMIRInsn = insn;
1093 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
1094
Ben Cheng00603072010-10-28 11:13:58 -07001095 /* Handle the taken path */
1096 bottomBlock->taken = origBlock->taken;
1097 if (bottomBlock->taken) {
1098 origBlock->taken = NULL;
1099 dvmCompilerClearBit(bottomBlock->taken->predecessors, origBlock->id);
1100 dvmCompilerSetBit(bottomBlock->taken->predecessors, bottomBlock->id);
1101 }
1102
1103 /* Handle the fallthrough path */
1104 bottomBlock->fallThrough = origBlock->fallThrough;
1105 origBlock->fallThrough = bottomBlock;
1106 dvmCompilerSetBit(bottomBlock->predecessors, origBlock->id);
1107 if (bottomBlock->fallThrough) {
1108 dvmCompilerClearBit(bottomBlock->fallThrough->predecessors,
1109 origBlock->id);
1110 dvmCompilerSetBit(bottomBlock->fallThrough->predecessors,
1111 bottomBlock->id);
1112 }
1113
1114 /* Handle the successor list */
1115 if (origBlock->successorBlockList.blockListType != kNotUsed) {
1116 bottomBlock->successorBlockList = origBlock->successorBlockList;
1117 origBlock->successorBlockList.blockListType = kNotUsed;
1118 GrowableListIterator iterator;
1119
1120 dvmGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
1121 &iterator);
1122 while (true) {
Ben Cheng7a02cb12010-12-15 14:18:31 -08001123 SuccessorBlockInfo *successorBlockInfo =
1124 (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
1125 if (successorBlockInfo == NULL) break;
1126 BasicBlock *bb = successorBlockInfo->block;
Ben Cheng00603072010-10-28 11:13:58 -07001127 dvmCompilerClearBit(bb->predecessors, origBlock->id);
1128 dvmCompilerSetBit(bb->predecessors, bottomBlock->id);
1129 }
1130 }
1131
1132 origBlock->lastMIRInsn = insn->prev;
Ben Cheng00603072010-10-28 11:13:58 -07001133
1134 insn->prev->next = NULL;
1135 insn->prev = NULL;
1136 return bottomBlock;
1137}
1138
1139/*
1140 * Given a code offset, find out the block that starts with it. If the offset
1141 * is in the middle of an existing block, split it into two.
1142 */
1143static BasicBlock *findBlock(CompilationUnit *cUnit,
1144 unsigned int codeOffset,
1145 bool split, bool create)
1146{
1147 GrowableList *blockList = &cUnit->blockList;
1148 BasicBlock *bb;
1149 unsigned int i;
1150
1151 for (i = 0; i < blockList->numUsed; i++) {
1152 bb = (BasicBlock *) blockList->elemList[i];
1153 if (bb->blockType != kDalvikByteCode) continue;
1154 if (bb->startOffset == codeOffset) return bb;
1155 /* Check if a branch jumps into the middle of an existing block */
1156 if ((split == true) && (codeOffset > bb->startOffset) &&
1157 (bb->lastMIRInsn != NULL) &&
1158 (codeOffset <= bb->lastMIRInsn->offset)) {
1159 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb);
1160 return newBB;
1161 }
1162 }
1163 if (create) {
1164 bb = dvmCompilerNewBB(kDalvikByteCode, cUnit->numBlocks++);
1165 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
1166 bb->startOffset = codeOffset;
1167 return bb;
1168 }
1169 return NULL;
1170}
1171
1172/* Dump the CFG into a DOT graph */
1173void dumpCFG(CompilationUnit *cUnit, const char *dirPrefix)
1174{
1175 const Method *method = cUnit->method;
1176 FILE *file;
1177 char* signature = dexProtoCopyMethodDescriptor(&method->prototype);
1178 char *fileName = (char *) dvmCompilerNew(
1179 strlen(dirPrefix) +
1180 strlen(method->clazz->descriptor) +
1181 strlen(method->name) +
1182 strlen(signature) +
1183 strlen(".dot") + 1, true);
1184 sprintf(fileName, "%s%s%s%s.dot", dirPrefix,
1185 method->clazz->descriptor, method->name, signature);
1186 free(signature);
1187
1188 /*
1189 * Convert the special characters into a filesystem- and shell-friendly
1190 * format.
1191 */
1192 int i;
1193 for (i = strlen(dirPrefix); fileName[i]; i++) {
1194 if (fileName[i] == '/') {
1195 fileName[i] = '_';
1196 } else if (fileName[i] == ';') {
1197 fileName[i] = '#';
1198 } else if (fileName[i] == '$') {
1199 fileName[i] = '+';
1200 } else if (fileName[i] == '(' || fileName[i] == ')') {
1201 fileName[i] = '@';
1202 } else if (fileName[i] == '<' || fileName[i] == '>') {
1203 fileName[i] = '=';
1204 }
1205 }
1206 file = fopen(fileName, "w");
1207 if (file == NULL) {
1208 return;
1209 }
1210 fprintf(file, "digraph G {\n");
1211
1212 fprintf(file, " rankdir=TB\n");
1213
1214 int numReachableBlocks = cUnit->numReachableBlocks;
1215 int idx;
1216 const GrowableList *blockList = &cUnit->blockList;
1217
1218 for (idx = 0; idx < numReachableBlocks; idx++) {
1219 int blockIdx = cUnit->dfsOrder.elemList[idx];
1220 BasicBlock *bb = (BasicBlock *) dvmGrowableListGetElement(blockList,
1221 blockIdx);
1222 if (bb == NULL) break;
1223 if (bb->blockType == kMethodEntryBlock) {
1224 fprintf(file, " entry [shape=Mdiamond];\n");
1225 } else if (bb->blockType == kMethodExitBlock) {
1226 fprintf(file, " exit [shape=Mdiamond];\n");
1227 } else if (bb->blockType == kDalvikByteCode) {
Ben Cheng7a02cb12010-12-15 14:18:31 -08001228 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
1229 bb->startOffset);
Ben Cheng00603072010-10-28 11:13:58 -07001230 const MIR *mir;
1231 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
1232 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
1233 dvmCompilerFullDisassembler(cUnit, mir),
1234 mir->next ? " | " : " ");
1235 }
1236 fprintf(file, " }\"];\n\n");
1237 } else if (bb->blockType == kExceptionHandling) {
1238 char blockName[BLOCK_NAME_LEN];
1239
1240 dvmGetBlockName(bb, blockName);
1241 fprintf(file, " %s [shape=invhouse];\n", blockName);
1242 }
1243
1244 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
1245
1246 if (bb->taken) {
1247 dvmGetBlockName(bb, blockName1);
1248 dvmGetBlockName(bb->taken, blockName2);
1249 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
1250 blockName1, blockName2);
1251 }
1252 if (bb->fallThrough) {
1253 dvmGetBlockName(bb, blockName1);
1254 dvmGetBlockName(bb->fallThrough, blockName2);
1255 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
1256 }
1257
1258 if (bb->successorBlockList.blockListType != kNotUsed) {
1259 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
1260 bb->startOffset,
1261 (bb->successorBlockList.blockListType == kCatch) ?
1262 "Mrecord" : "record");
1263 GrowableListIterator iterator;
1264 dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
1265 &iterator);
Ben Cheng7a02cb12010-12-15 14:18:31 -08001266 SuccessorBlockInfo *successorBlockInfo =
1267 (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
Ben Cheng00603072010-10-28 11:13:58 -07001268
1269 int succId = 0;
1270 while (true) {
Ben Cheng7a02cb12010-12-15 14:18:31 -08001271 if (successorBlockInfo == NULL) break;
1272
1273 BasicBlock *destBlock = successorBlockInfo->block;
1274 SuccessorBlockInfo *nextSuccessorBlockInfo =
1275 (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
1276
1277 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
Ben Cheng00603072010-10-28 11:13:58 -07001278 succId++,
Ben Cheng7a02cb12010-12-15 14:18:31 -08001279 successorBlockInfo->key,
Ben Cheng00603072010-10-28 11:13:58 -07001280 destBlock->startOffset,
Ben Cheng7a02cb12010-12-15 14:18:31 -08001281 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
1282
1283 successorBlockInfo = nextSuccessorBlockInfo;
Ben Cheng00603072010-10-28 11:13:58 -07001284 }
1285 fprintf(file, " }\"];\n\n");
1286
1287 dvmGetBlockName(bb, blockName1);
1288 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
1289 blockName1, bb->startOffset);
1290
1291 if (bb->successorBlockList.blockListType == kPackedSwitch ||
1292 bb->successorBlockList.blockListType == kSparseSwitch) {
1293
1294 dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
1295 &iterator);
1296
1297 succId = 0;
1298 while (true) {
Ben Cheng7a02cb12010-12-15 14:18:31 -08001299 SuccessorBlockInfo *successorBlockInfo =
1300 (SuccessorBlockInfo *)
1301 dvmGrowableListIteratorNext(&iterator);
1302 if (successorBlockInfo == NULL) break;
1303
1304 BasicBlock *destBlock = successorBlockInfo->block;
Ben Cheng00603072010-10-28 11:13:58 -07001305
1306 dvmGetBlockName(destBlock, blockName2);
1307 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
1308 bb->startOffset, succId++,
1309 blockName2);
1310 }
1311 }
1312 }
1313 fprintf(file, "\n");
1314
1315 /*
1316 * If we need to debug the dominator tree, uncomment the following code
1317 */
1318#if 0
1319 dvmGetBlockName(bb, blockName1);
1320 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
1321 blockName1, blockName1);
1322 if (bb->iDom) {
1323 dvmGetBlockName(bb->iDom, blockName2);
1324 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
1325 blockName2, blockName1);
1326 }
1327#endif
1328 }
1329 fprintf(file, "}\n");
1330 fclose(file);
1331}
1332
1333/* Verify if all the successor is connected with all the claimed predecessors */
1334static bool verifyPredInfo(CompilationUnit *cUnit, BasicBlock *bb)
1335{
1336 BitVectorIterator bvIterator;
1337
1338 dvmBitVectorIteratorInit(bb->predecessors, &bvIterator);
1339 while (true) {
1340 int blockIdx = dvmBitVectorIteratorNext(&bvIterator);
1341 if (blockIdx == -1) break;
1342 BasicBlock *predBB = (BasicBlock *)
1343 dvmGrowableListGetElement(&cUnit->blockList, blockIdx);
1344 bool found = false;
1345 if (predBB->taken == bb) {
1346 found = true;
1347 } else if (predBB->fallThrough == bb) {
1348 found = true;
1349 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
1350 GrowableListIterator iterator;
1351 dvmGrowableListIteratorInit(&predBB->successorBlockList.blocks,
1352 &iterator);
1353 while (true) {
Ben Cheng7a02cb12010-12-15 14:18:31 -08001354 SuccessorBlockInfo *successorBlockInfo =
1355 (SuccessorBlockInfo *)
1356 dvmGrowableListIteratorNext(&iterator);
1357 if (successorBlockInfo == NULL) break;
1358 BasicBlock *succBB = successorBlockInfo->block;
Ben Cheng00603072010-10-28 11:13:58 -07001359 if (succBB == bb) {
1360 found = true;
1361 break;
1362 }
1363 }
1364 }
1365 if (found == false) {
1366 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
1367 dvmGetBlockName(bb, blockName1);
1368 dvmGetBlockName(predBB, blockName2);
1369 dumpCFG(cUnit, "/data/tombstones/");
1370 LOGE("Successor %s not found from %s",
1371 blockName1, blockName2);
1372 dvmAbort();
1373 }
1374 }
1375 return true;
1376}
1377
1378/* Identify code range in try blocks and set up the empty catch blocks */
1379static void processTryCatchBlocks(CompilationUnit *cUnit)
1380{
1381 const Method *meth = cUnit->method;
1382 const DexCode *pCode = dvmGetMethodCode(meth);
1383 int triesSize = pCode->triesSize;
1384 int i;
1385 int offset;
1386
1387 if (triesSize == 0) {
1388 return;
1389 }
1390
1391 const DexTry *pTries = dexGetTries(pCode);
1392 BitVector *tryBlockAddr = cUnit->tryBlockAddr;
1393
1394 /* Mark all the insn offsets in Try blocks */
1395 for (i = 0; i < triesSize; i++) {
1396 const DexTry* pTry = &pTries[i];
1397 /* all in 16-bit units */
1398 int startOffset = pTry->startAddr;
1399 int endOffset = startOffset + pTry->insnCount;
1400
1401 for (offset = startOffset; offset < endOffset; offset++) {
1402 dvmCompilerSetBit(tryBlockAddr, offset);
1403 }
1404 }
1405
1406 /* Iterate over each of the handlers to enqueue the empty Catch blocks */
1407 offset = dexGetFirstHandlerOffset(pCode);
1408 int handlersSize = dexGetHandlersSize(pCode);
1409
1410 for (i = 0; i < handlersSize; i++) {
1411 DexCatchIterator iterator;
1412 dexCatchIteratorInit(&iterator, pCode, offset);
1413
1414 for (;;) {
1415 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
1416
1417 if (handler == NULL) {
1418 break;
1419 }
1420
Ben Cheng7a02cb12010-12-15 14:18:31 -08001421 /*
1422 * Create dummy catch blocks first. Since these are created before
1423 * other blocks are processed, "split" is specified as false.
1424 */
1425 findBlock(cUnit, handler->address,
1426 /* split */
1427 false,
1428 /* create */
1429 true);
Ben Cheng00603072010-10-28 11:13:58 -07001430 }
1431
1432 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
1433 }
1434}
1435
1436/* Process instructions with the kInstrCanBranch flag */
1437static void processCanBranch(CompilationUnit *cUnit, BasicBlock *curBlock,
1438 MIR *insn, int curOffset, int width, int flags,
1439 const u2* codePtr, const u2* codeEnd)
1440{
1441 int target = curOffset;
1442 switch (insn->dalvikInsn.opcode) {
1443 case OP_GOTO:
1444 case OP_GOTO_16:
1445 case OP_GOTO_32:
1446 target += (int) insn->dalvikInsn.vA;
1447 break;
1448 case OP_IF_EQ:
1449 case OP_IF_NE:
1450 case OP_IF_LT:
1451 case OP_IF_GE:
1452 case OP_IF_GT:
1453 case OP_IF_LE:
1454 target += (int) insn->dalvikInsn.vC;
1455 break;
1456 case OP_IF_EQZ:
1457 case OP_IF_NEZ:
1458 case OP_IF_LTZ:
1459 case OP_IF_GEZ:
1460 case OP_IF_GTZ:
1461 case OP_IF_LEZ:
1462 target += (int) insn->dalvikInsn.vB;
1463 break;
1464 default:
1465 LOGE("Unexpected opcode(%d) with kInstrCanBranch set",
1466 insn->dalvikInsn.opcode);
1467 dvmAbort();
1468 }
1469 BasicBlock *takenBlock = findBlock(cUnit, target,
1470 /* split */
1471 true,
1472 /* create */
1473 true);
1474 curBlock->taken = takenBlock;
1475 dvmCompilerSetBit(takenBlock->predecessors, curBlock->id);
1476
1477 /* Always terminate the current block for conditional branches */
1478 if (flags & kInstrCanContinue) {
1479 BasicBlock *fallthroughBlock = findBlock(cUnit,
1480 curOffset + width,
1481 /* split */
1482 false,
1483 /* create */
1484 true);
1485 curBlock->fallThrough = fallthroughBlock;
1486 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
1487 } else if (codePtr < codeEnd) {
1488 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
1489 if (contentIsInsn(codePtr)) {
1490 findBlock(cUnit, curOffset + width,
1491 /* split */
1492 false,
1493 /* create */
1494 true);
1495 }
1496 }
1497}
1498
1499/* Process instructions with the kInstrCanSwitch flag */
1500static void processCanSwitch(CompilationUnit *cUnit, BasicBlock *curBlock,
1501 MIR *insn, int curOffset, int width, int flags)
1502{
1503 u2 *switchData= (u2 *) (cUnit->method->insns + curOffset +
1504 insn->dalvikInsn.vB);
1505 int size;
Ben Cheng7a02cb12010-12-15 14:18:31 -08001506 int *keyTable;
Ben Cheng00603072010-10-28 11:13:58 -07001507 int *targetTable;
1508 int i;
Ben Cheng7a02cb12010-12-15 14:18:31 -08001509 int firstKey;
Ben Cheng00603072010-10-28 11:13:58 -07001510
1511 /*
1512 * Packed switch data format:
1513 * ushort ident = 0x0100 magic value
1514 * ushort size number of entries in the table
1515 * int first_key first (and lowest) switch case value
1516 * int targets[size] branch targets, relative to switch opcode
1517 *
1518 * Total size is (4+size*2) 16-bit code units.
1519 */
1520 if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
1521 assert(switchData[0] == kPackedSwitchSignature);
1522 size = switchData[1];
Ben Cheng7a02cb12010-12-15 14:18:31 -08001523 firstKey = switchData[2] | (switchData[3] << 16);
Ben Cheng00603072010-10-28 11:13:58 -07001524 targetTable = (int *) &switchData[4];
Ben Cheng7a02cb12010-12-15 14:18:31 -08001525 keyTable = NULL; // Make the compiler happy
Ben Cheng00603072010-10-28 11:13:58 -07001526 /*
1527 * Sparse switch data format:
1528 * ushort ident = 0x0200 magic value
1529 * ushort size number of entries in the table; > 0
1530 * int keys[size] keys, sorted low-to-high; 32-bit aligned
1531 * int targets[size] branch targets, relative to switch opcode
1532 *
1533 * Total size is (2+size*4) 16-bit code units.
1534 */
1535 } else {
1536 assert(switchData[0] == kSparseSwitchSignature);
1537 size = switchData[1];
Ben Cheng7a02cb12010-12-15 14:18:31 -08001538 keyTable = (int *) &switchData[2];
Ben Cheng00603072010-10-28 11:13:58 -07001539 targetTable = (int *) &switchData[2 + size*2];
Ben Cheng7a02cb12010-12-15 14:18:31 -08001540 firstKey = 0; // To make the compiler happy
Ben Cheng00603072010-10-28 11:13:58 -07001541 }
1542
1543 if (curBlock->successorBlockList.blockListType != kNotUsed) {
1544 LOGE("Successor block list already in use: %d",
1545 curBlock->successorBlockList.blockListType);
1546 dvmAbort();
1547 }
1548 curBlock->successorBlockList.blockListType =
1549 (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
1550 kPackedSwitch : kSparseSwitch;
1551 dvmInitGrowableList(&curBlock->successorBlockList.blocks, size);
1552
1553 for (i = 0; i < size; i++) {
1554 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
1555 /* split */
1556 true,
1557 /* create */
1558 true);
Ben Cheng7a02cb12010-12-15 14:18:31 -08001559 SuccessorBlockInfo *successorBlockInfo =
1560 (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo),
1561 false);
1562 successorBlockInfo->block = caseBlock;
1563 successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)?
1564 firstKey + i : keyTable[i];
Ben Cheng00603072010-10-28 11:13:58 -07001565 dvmInsertGrowableList(&curBlock->successorBlockList.blocks,
Ben Cheng7a02cb12010-12-15 14:18:31 -08001566 (intptr_t) successorBlockInfo);
Ben Cheng00603072010-10-28 11:13:58 -07001567 dvmCompilerSetBit(caseBlock->predecessors, curBlock->id);
1568 }
1569
1570 /* Fall-through case */
1571 BasicBlock *fallthroughBlock = findBlock(cUnit,
1572 curOffset + width,
1573 /* split */
1574 false,
1575 /* create */
1576 true);
1577 curBlock->fallThrough = fallthroughBlock;
1578 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
1579}
1580
1581/* Process instructions with the kInstrCanThrow flag */
1582static void processCanThrow(CompilationUnit *cUnit, BasicBlock *curBlock,
1583 MIR *insn, int curOffset, int width, int flags,
1584 BitVector *tryBlockAddr, const u2 *codePtr,
1585 const u2* codeEnd)
1586{
1587 const Method *method = cUnit->method;
1588 const DexCode *dexCode = dvmGetMethodCode(method);
1589
Ben Cheng00603072010-10-28 11:13:58 -07001590 /* In try block */
1591 if (dvmIsBitSet(tryBlockAddr, curOffset)) {
1592 DexCatchIterator iterator;
1593
1594 if (!dexFindCatchHandler(&iterator, dexCode, curOffset)) {
1595 LOGE("Catch block not found in dexfile for insn %x in %s",
1596 curOffset, method->name);
1597 dvmAbort();
1598
1599 }
1600 if (curBlock->successorBlockList.blockListType != kNotUsed) {
1601 LOGE("Successor block list already in use: %d",
1602 curBlock->successorBlockList.blockListType);
1603 dvmAbort();
1604 }
1605 curBlock->successorBlockList.blockListType = kCatch;
1606 dvmInitGrowableList(&curBlock->successorBlockList.blocks, 2);
1607
1608 for (;;) {
1609 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
1610
1611 if (handler == NULL) {
1612 break;
1613 }
1614
1615 BasicBlock *catchBlock = findBlock(cUnit, handler->address,
1616 /* split */
1617 false,
1618 /* create */
1619 false);
1620
Ben Cheng7a02cb12010-12-15 14:18:31 -08001621 SuccessorBlockInfo *successorBlockInfo =
1622 (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo),
1623 false);
1624 successorBlockInfo->block = catchBlock;
1625 successorBlockInfo->key = handler->typeIdx;
Ben Cheng00603072010-10-28 11:13:58 -07001626 dvmInsertGrowableList(&curBlock->successorBlockList.blocks,
Ben Cheng7a02cb12010-12-15 14:18:31 -08001627 (intptr_t) successorBlockInfo);
Ben Cheng00603072010-10-28 11:13:58 -07001628 dvmCompilerSetBit(catchBlock->predecessors, curBlock->id);
1629 }
1630 } else {
1631 BasicBlock *ehBlock = dvmCompilerNewBB(kExceptionHandling,
1632 cUnit->numBlocks++);
1633 curBlock->taken = ehBlock;
1634 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) ehBlock);
1635 ehBlock->startOffset = curOffset;
1636 dvmCompilerSetBit(ehBlock->predecessors, curBlock->id);
1637 }
1638
1639 /*
1640 * Force the current block to terminate.
1641 *
1642 * Data may be present before codeEnd, so we need to parse it to know
1643 * whether it is code or data.
1644 */
1645 if (codePtr < codeEnd) {
1646 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
1647 if (contentIsInsn(codePtr)) {
1648 BasicBlock *fallthroughBlock = findBlock(cUnit,
1649 curOffset + width,
1650 /* split */
1651 false,
1652 /* create */
1653 true);
1654 /*
1655 * OP_THROW and OP_THROW_VERIFICATION_ERROR are unconditional
1656 * branches.
1657 */
1658 if (insn->dalvikInsn.opcode != OP_THROW_VERIFICATION_ERROR &&
1659 insn->dalvikInsn.opcode != OP_THROW) {
1660 curBlock->fallThrough = fallthroughBlock;
1661 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
1662 }
1663 }
1664 }
1665}
1666
Ben Cheng7a2697d2010-06-07 13:44:23 -07001667/*
Ben Chengba4fc8b2009-06-01 13:00:29 -07001668 * Similar to dvmCompileTrace, but the entity processed here is the whole
1669 * method.
1670 *
1671 * TODO: implementation will be revisited when the trace builder can provide
1672 * whole-method traces.
1673 */
Ben Cheng00603072010-10-28 11:13:58 -07001674bool dvmCompileMethod(const Method *method)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001675{
Ben Cheng00603072010-10-28 11:13:58 -07001676 CompilationUnit cUnit;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001677 const DexCode *dexCode = dvmGetMethodCode(method);
1678 const u2 *codePtr = dexCode->insns;
1679 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
Ben Cheng00603072010-10-28 11:13:58 -07001680 int numBlocks = 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001681 unsigned int curOffset = 0;
1682
Ben Cheng00603072010-10-28 11:13:58 -07001683 memset(&cUnit, 0, sizeof(cUnit));
1684 cUnit.method = method;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001685
Ben Cheng00603072010-10-28 11:13:58 -07001686 /* Initialize the block list */
1687 dvmInitGrowableList(&cUnit.blockList, 4);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001688
1689 /* Allocate the bit-vector to track the beginning of basic blocks */
Ben Cheng00603072010-10-28 11:13:58 -07001690 BitVector *tryBlockAddr = dvmCompilerAllocBitVector(dexCode->insnsSize,
1691 true /* expandable */);
1692 cUnit.tryBlockAddr = tryBlockAddr;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001693
Ben Cheng00603072010-10-28 11:13:58 -07001694 /* Create the default entry and exit blocks and enter them to the list */
1695 BasicBlock *entryBlock = dvmCompilerNewBB(kMethodEntryBlock, numBlocks++);
1696 BasicBlock *exitBlock = dvmCompilerNewBB(kMethodExitBlock, numBlocks++);
1697
1698 cUnit.entryBlock = entryBlock;
1699 cUnit.exitBlock = exitBlock;
1700
1701 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) entryBlock);
1702 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) exitBlock);
1703
1704 /* Current block to record parsed instructions */
1705 BasicBlock *curBlock = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
1706 curBlock->startOffset = 0;
1707 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) curBlock);
1708 entryBlock->fallThrough = curBlock;
1709 dvmCompilerSetBit(curBlock->predecessors, entryBlock->id);
Ben Cheng7a2697d2010-06-07 13:44:23 -07001710
Ben Chengba4fc8b2009-06-01 13:00:29 -07001711 /*
Ben Cheng00603072010-10-28 11:13:58 -07001712 * Store back the number of blocks since new blocks may be created of
1713 * accessing cUnit.
Ben Chengba4fc8b2009-06-01 13:00:29 -07001714 */
Ben Cheng00603072010-10-28 11:13:58 -07001715 cUnit.numBlocks = numBlocks;
1716
1717 /* Identify code range in try blocks and set up the empty catch blocks */
1718 processTryCatchBlocks(&cUnit);
1719
1720 /* Parse all instructions and put them into containing basic blocks */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001721 while (codePtr < codeEnd) {
Ben Cheng00603072010-10-28 11:13:58 -07001722 MIR *insn = (MIR *) dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001723 insn->offset = curOffset;
1724 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001725 insn->width = width;
1726
Ben Cheng8b258bf2009-06-24 17:27:07 -07001727 /* Terminate when the data section is seen */
1728 if (width == 0)
1729 break;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001730
Ben Cheng00603072010-10-28 11:13:58 -07001731 dvmCompilerAppendMIR(curBlock, insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001732
1733 codePtr += width;
Ben Cheng00603072010-10-28 11:13:58 -07001734 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
1735
1736 if (flags & kInstrCanBranch) {
1737 processCanBranch(&cUnit, curBlock, insn, curOffset, width, flags,
1738 codePtr, codeEnd);
1739 } else if (flags & kInstrCanReturn) {
1740 curBlock->fallThrough = exitBlock;
1741 dvmCompilerSetBit(exitBlock->predecessors, curBlock->id);
1742 /*
1743 * Terminate the current block if there are instructions
1744 * afterwards.
1745 */
1746 if (codePtr < codeEnd) {
1747 /*
1748 * Create a fallthrough block for real instructions
1749 * (incl. OP_NOP).
1750 */
1751 if (contentIsInsn(codePtr)) {
1752 findBlock(&cUnit, curOffset + width,
1753 /* split */
1754 false,
1755 /* create */
1756 true);
1757 }
1758 }
1759 } else if (flags & kInstrCanThrow) {
1760 processCanThrow(&cUnit, curBlock, insn, curOffset, width, flags,
1761 tryBlockAddr, codePtr, codeEnd);
1762 } else if (flags & kInstrCanSwitch) {
1763 processCanSwitch(&cUnit, curBlock, insn, curOffset, width, flags);
1764 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001765 curOffset += width;
Ben Cheng00603072010-10-28 11:13:58 -07001766 BasicBlock *nextBlock = findBlock(&cUnit, curOffset,
1767 /* split */
1768 false,
1769 /* create */
1770 false);
1771 if (nextBlock) {
1772 /*
1773 * The next instruction could be the target of a previously parsed
1774 * forward branch so a block is already created. If the current
1775 * instruction is not an unconditional branch, connect them through
1776 * the fall-through link.
1777 */
1778 assert(curBlock->fallThrough == NULL ||
1779 curBlock->fallThrough == nextBlock ||
1780 curBlock->fallThrough == exitBlock);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001781
Ben Cheng00603072010-10-28 11:13:58 -07001782 if ((curBlock->fallThrough == NULL) &&
1783 !dexIsGoto(flags) &&
1784 !(flags & kInstrCanReturn)) {
1785 curBlock->fallThrough = nextBlock;
1786 dvmCompilerSetBit(nextBlock->predecessors, curBlock->id);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001787 }
Ben Cheng00603072010-10-28 11:13:58 -07001788 curBlock = nextBlock;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001789 }
1790 }
1791
Ben Cheng00603072010-10-28 11:13:58 -07001792 /* Adjust this value accordingly once inlining is performed */
1793 cUnit.numDalvikRegisters = cUnit.method->registersSize;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001794
Ben Cheng00603072010-10-28 11:13:58 -07001795 /* Verify if all blocks are connected as claimed */
1796 /* FIXME - to be disabled in the future */
1797 dvmCompilerDataFlowAnalysisDispatcher(&cUnit, verifyPredInfo,
1798 kAllNodes,
1799 false /* isIterative */);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001800
Ben Chengba4fc8b2009-06-01 13:00:29 -07001801
Ben Cheng00603072010-10-28 11:13:58 -07001802 /* Perform SSA transformation for the whole method */
1803 dvmCompilerMethodSSATransformation(&cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001804
Ben Cheng00603072010-10-28 11:13:58 -07001805 if (cUnit.printMe) dumpCFG(&cUnit, "/data/tombstones/");
Ben Chengba4fc8b2009-06-01 13:00:29 -07001806
Ben Cheng00603072010-10-28 11:13:58 -07001807 /* Reset the compiler resource pool */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001808 dvmCompilerArenaReset();
1809
Ben Cheng00603072010-10-28 11:13:58 -07001810 return false;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001811}