blob: 8272fb6578d9be441e2c3324fcd89977e7540730 [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;
Ben Chengcfdeca32011-01-14 11:36:46 -0800291 realMethodEntry = (CompilerMethodStats *)
292 dvmHashTableLookup(gDvmJit.methodStatsTable,
293 hashValue,
294 &dummyMethodEntry,
295 (HashCompareFunc) compareMethod,
296 false);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700297
Ben Cheng7a2697d2010-06-07 13:44:23 -0700298 /* This method has never been analyzed before - create an entry */
299 if (realMethodEntry == NULL) {
300 realMethodEntry =
301 (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
302 realMethodEntry->method = method;
303
304 dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
305 realMethodEntry,
306 (HashCompareFunc) compareMethod,
307 true);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700308 }
309
Ben Cheng7a2697d2010-06-07 13:44:23 -0700310 /* This method is invoked as a callee and has been analyzed - just return */
311 if ((isCallee == true) && (realMethodEntry->attributes & METHOD_IS_CALLEE))
312 return realMethodEntry;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700313
Ben Cheng7a2697d2010-06-07 13:44:23 -0700314 /*
315 * Similarly, return if this method has been compiled before as a hot
316 * method already.
317 */
318 if ((isCallee == false) &&
319 (realMethodEntry->attributes & METHOD_IS_HOT))
320 return realMethodEntry;
321
322 int attributes;
323
324 /* Method hasn't been analyzed for the desired purpose yet */
325 if (isCallee) {
326 /* Aggressively set the attributes until proven otherwise */
327 attributes = METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE |
328 METHOD_IS_GETTER | METHOD_IS_SETTER;
329 } else {
330 attributes = METHOD_IS_HOT;
331 }
Ben Cheng8b258bf2009-06-24 17:27:07 -0700332
333 /* Count the number of instructions */
334 while (codePtr < codeEnd) {
335 DecodedInstruction dalvikInsn;
336 int width = parseInsn(codePtr, &dalvikInsn, false);
337
338 /* Terminate when the data section is seen */
339 if (width == 0)
340 break;
341
Ben Cheng7a2697d2010-06-07 13:44:23 -0700342 if (isCallee) {
343 attributes = analyzeInlineTarget(&dalvikInsn, attributes, insnSize);
344 }
345
Ben Cheng8b258bf2009-06-24 17:27:07 -0700346 insnSize += width;
347 codePtr += width;
348 }
349
Ben Cheng7a2697d2010-06-07 13:44:23 -0700350 /*
351 * Only handle simple getters/setters with one instruction followed by
352 * return
353 */
354 if ((attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) &&
355 (insnSize != 3)) {
356 attributes &= ~(METHOD_IS_GETTER | METHOD_IS_SETTER);
357 }
358
Ben Cheng8b258bf2009-06-24 17:27:07 -0700359 realMethodEntry->dalvikSize = insnSize * 2;
Ben Cheng7a2697d2010-06-07 13:44:23 -0700360 realMethodEntry->attributes |= attributes;
361
362#if 0
363 /* Uncomment the following to explore various callee patterns */
364 if (attributes & METHOD_IS_THROW_FREE) {
365 LOGE("%s%s is inlinable%s", method->clazz->descriptor, method->name,
366 (attributes & METHOD_IS_EMPTY) ? " empty" : "");
367 }
368
369 if (attributes & METHOD_IS_LEAF) {
370 LOGE("%s%s is leaf %d%s", method->clazz->descriptor, method->name,
371 insnSize, insnSize < 5 ? " (small)" : "");
372 }
373
374 if (attributes & (METHOD_IS_GETTER | METHOD_IS_SETTER)) {
375 LOGE("%s%s is %s", method->clazz->descriptor, method->name,
376 attributes & METHOD_IS_GETTER ? "getter": "setter");
377 }
378 if (attributes ==
379 (METHOD_IS_LEAF | METHOD_IS_THROW_FREE | METHOD_IS_CALLEE)) {
380 LOGE("%s%s is inlinable non setter/getter", method->clazz->descriptor,
381 method->name);
382 }
383#endif
384
Ben Cheng8b258bf2009-06-24 17:27:07 -0700385 return realMethodEntry;
386}
387
388/*
Ben Cheng33672452010-01-12 14:59:30 -0800389 * Crawl the stack of the thread that requesed compilation to see if any of the
390 * ancestors are on the blacklist.
391 */
Andy McFadden953a0ed2010-09-17 15:48:38 -0700392static bool filterMethodByCallGraph(Thread *thread, const char *curMethodName)
Ben Cheng33672452010-01-12 14:59:30 -0800393{
394 /* Crawl the Dalvik stack frames and compare the method name*/
395 StackSaveArea *ssaPtr = ((StackSaveArea *) thread->curFrame) - 1;
396 while (ssaPtr != ((StackSaveArea *) NULL) - 1) {
397 const Method *method = ssaPtr->method;
398 if (method) {
399 int hashValue = dvmComputeUtf8Hash(method->name);
400 bool found =
401 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
402 (char *) method->name,
403 (HashCompareFunc) strcmp, false) !=
404 NULL;
405 if (found) {
406 LOGD("Method %s (--> %s) found on the JIT %s list",
407 method->name, curMethodName,
408 gDvmJit.includeSelectedMethod ? "white" : "black");
409 return true;
410 }
411
412 }
413 ssaPtr = ((StackSaveArea *) ssaPtr->prevFrame) - 1;
414 };
415 return false;
416}
417
418/*
Ben Cheng46cd4fb2011-03-16 17:19:06 -0700419 * Since we are including instructions from possibly a cold method into the
420 * current trace, we need to make sure that all the associated information
421 * with the callee is properly initialized. If not, we punt on this inline
422 * target.
423 *
424 * TODO: volatile instructions will be handled later.
425 */
426bool dvmCompilerCanIncludeThisInstruction(const Method *method,
427 const DecodedInstruction *insn)
428{
429 switch (insn->opcode) {
430 case OP_NEW_INSTANCE:
431 case OP_NEW_INSTANCE_JUMBO:
432 case OP_CHECK_CAST:
433 case OP_CHECK_CAST_JUMBO: {
434 ClassObject *classPtr = (ClassObject *)(void*)
435 (method->clazz->pDvmDex->pResClasses[insn->vB]);
436
437 /* Class hasn't been initialized yet */
438 if (classPtr == NULL) {
439 return false;
440 }
441 return true;
442 }
443 case OP_SGET:
444 case OP_SGET_JUMBO:
445 case OP_SGET_WIDE:
446 case OP_SGET_WIDE_JUMBO:
447 case OP_SGET_OBJECT:
448 case OP_SGET_OBJECT_JUMBO:
449 case OP_SGET_BOOLEAN:
450 case OP_SGET_BOOLEAN_JUMBO:
451 case OP_SGET_BYTE:
452 case OP_SGET_BYTE_JUMBO:
453 case OP_SGET_CHAR:
454 case OP_SGET_CHAR_JUMBO:
455 case OP_SGET_SHORT:
456 case OP_SGET_SHORT_JUMBO:
457 case OP_SPUT:
458 case OP_SPUT_JUMBO:
459 case OP_SPUT_WIDE:
460 case OP_SPUT_WIDE_JUMBO:
461 case OP_SPUT_OBJECT:
462 case OP_SPUT_OBJECT_JUMBO:
463 case OP_SPUT_BOOLEAN:
464 case OP_SPUT_BOOLEAN_JUMBO:
465 case OP_SPUT_BYTE:
466 case OP_SPUT_BYTE_JUMBO:
467 case OP_SPUT_CHAR:
468 case OP_SPUT_CHAR_JUMBO:
469 case OP_SPUT_SHORT:
470 case OP_SPUT_SHORT_JUMBO: {
471 void *fieldPtr = (void*)
472 (method->clazz->pDvmDex->pResFields[insn->vB]);
473
474 if (fieldPtr == NULL) {
475 return false;
476 }
477 return true;
478 }
479 case OP_INVOKE_SUPER:
480 case OP_INVOKE_SUPER_RANGE:
481 case OP_INVOKE_SUPER_JUMBO: {
482 int mIndex = method->clazz->pDvmDex->
483 pResMethods[insn->vB]->methodIndex;
484 const Method *calleeMethod = method->clazz->super->vtable[mIndex];
485 if (calleeMethod == NULL) {
486 return false;
487 }
488 return true;
489 }
490 case OP_INVOKE_SUPER_QUICK:
491 case OP_INVOKE_SUPER_QUICK_RANGE: {
492 const Method *calleeMethod = method->clazz->super->vtable[insn->vB];
493 if (calleeMethod == NULL) {
494 return false;
495 }
496 return true;
497 }
498 case OP_INVOKE_STATIC:
499 case OP_INVOKE_STATIC_RANGE:
500 case OP_INVOKE_STATIC_JUMBO:
501 case OP_INVOKE_DIRECT:
502 case OP_INVOKE_DIRECT_RANGE:
503 case OP_INVOKE_DIRECT_JUMBO: {
504 const Method *calleeMethod =
505 method->clazz->pDvmDex->pResMethods[insn->vB];
506 if (calleeMethod == NULL) {
507 return false;
508 }
509 return true;
510 }
511 case OP_CONST_CLASS:
512 case OP_CONST_CLASS_JUMBO: {
513 void *classPtr = (void*)
514 (method->clazz->pDvmDex->pResClasses[insn->vB]);
515
516 if (classPtr == NULL) {
517 return false;
518 }
519 return true;
520 }
521 case OP_CONST_STRING_JUMBO:
522 case OP_CONST_STRING: {
523 void *strPtr = (void*)
524 (method->clazz->pDvmDex->pResStrings[insn->vB]);
525
526 if (strPtr == NULL) {
527 return false;
528 }
529 return true;
530 }
531 default:
532 return true;
533 }
534}
535
536/* Split an existing block from the specified code offset into two */
537static BasicBlock *splitBlock(CompilationUnit *cUnit,
538 unsigned int codeOffset,
539 BasicBlock *origBlock)
540{
541 MIR *insn = origBlock->firstMIRInsn;
542 while (insn) {
543 if (insn->offset == codeOffset) break;
544 insn = insn->next;
545 }
546 if (insn == NULL) {
547 LOGE("Break split failed");
548 dvmAbort();
549 }
550 BasicBlock *bottomBlock = dvmCompilerNewBB(kDalvikByteCode,
551 cUnit->numBlocks++);
552 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bottomBlock);
553
554 bottomBlock->startOffset = codeOffset;
555 bottomBlock->firstMIRInsn = insn;
556 bottomBlock->lastMIRInsn = origBlock->lastMIRInsn;
557
558 /* Handle the taken path */
559 bottomBlock->taken = origBlock->taken;
560 if (bottomBlock->taken) {
561 origBlock->taken = NULL;
562 dvmCompilerClearBit(bottomBlock->taken->predecessors, origBlock->id);
563 dvmCompilerSetBit(bottomBlock->taken->predecessors, bottomBlock->id);
564 }
565
566 /* Handle the fallthrough path */
567 bottomBlock->fallThrough = origBlock->fallThrough;
568 origBlock->fallThrough = bottomBlock;
569 dvmCompilerSetBit(bottomBlock->predecessors, origBlock->id);
570 if (bottomBlock->fallThrough) {
571 dvmCompilerClearBit(bottomBlock->fallThrough->predecessors,
572 origBlock->id);
573 dvmCompilerSetBit(bottomBlock->fallThrough->predecessors,
574 bottomBlock->id);
575 }
576
577 /* Handle the successor list */
578 if (origBlock->successorBlockList.blockListType != kNotUsed) {
579 bottomBlock->successorBlockList = origBlock->successorBlockList;
580 origBlock->successorBlockList.blockListType = kNotUsed;
581 GrowableListIterator iterator;
582
583 dvmGrowableListIteratorInit(&bottomBlock->successorBlockList.blocks,
584 &iterator);
585 while (true) {
586 SuccessorBlockInfo *successorBlockInfo =
587 (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
588 if (successorBlockInfo == NULL) break;
589 BasicBlock *bb = successorBlockInfo->block;
590 dvmCompilerClearBit(bb->predecessors, origBlock->id);
591 dvmCompilerSetBit(bb->predecessors, bottomBlock->id);
592 }
593 }
594
595 origBlock->lastMIRInsn = insn->prev;
596
597 insn->prev->next = NULL;
598 insn->prev = NULL;
599 return bottomBlock;
600}
601
602/*
603 * Given a code offset, find out the block that starts with it. If the offset
604 * is in the middle of an existing block, split it into two.
605 */
606static BasicBlock *findBlock(CompilationUnit *cUnit,
607 unsigned int codeOffset,
608 bool split, bool create)
609{
610 GrowableList *blockList = &cUnit->blockList;
611 BasicBlock *bb;
612 unsigned int i;
613
614 for (i = 0; i < blockList->numUsed; i++) {
615 bb = (BasicBlock *) blockList->elemList[i];
616 if (bb->blockType != kDalvikByteCode) continue;
617 if (bb->startOffset == codeOffset) return bb;
618 /* Check if a branch jumps into the middle of an existing block */
619 if ((split == true) && (codeOffset > bb->startOffset) &&
620 (bb->lastMIRInsn != NULL) &&
621 (codeOffset <= bb->lastMIRInsn->offset)) {
622 BasicBlock *newBB = splitBlock(cUnit, codeOffset, bb);
623 return newBB;
624 }
625 }
626 if (create) {
627 bb = dvmCompilerNewBB(kDalvikByteCode, cUnit->numBlocks++);
628 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) bb);
629 bb->startOffset = codeOffset;
630 return bb;
631 }
632 return NULL;
633}
634
635/* Dump the CFG into a DOT graph */
636void dumpCFG(CompilationUnit *cUnit, const char *dirPrefix)
637{
638 const Method *method = cUnit->method;
639 FILE *file;
640 char *signature = dexProtoCopyMethodDescriptor(&method->prototype);
641 char startOffset[80];
642 sprintf(startOffset, "_%x", cUnit->entryBlock->fallThrough->startOffset);
643 char *fileName = (char *) dvmCompilerNew(
644 strlen(dirPrefix) +
645 strlen(method->clazz->descriptor) +
646 strlen(method->name) +
647 strlen(signature) +
648 strlen(startOffset) +
649 strlen(".dot") + 1, true);
650 sprintf(fileName, "%s%s%s%s%s.dot", dirPrefix,
651 method->clazz->descriptor, method->name, signature, startOffset);
652 free(signature);
653
654 /*
655 * Convert the special characters into a filesystem- and shell-friendly
656 * format.
657 */
658 int i;
659 for (i = strlen(dirPrefix); fileName[i]; i++) {
660 if (fileName[i] == '/') {
661 fileName[i] = '_';
662 } else if (fileName[i] == ';') {
663 fileName[i] = '#';
664 } else if (fileName[i] == '$') {
665 fileName[i] = '+';
666 } else if (fileName[i] == '(' || fileName[i] == ')') {
667 fileName[i] = '@';
668 } else if (fileName[i] == '<' || fileName[i] == '>') {
669 fileName[i] = '=';
670 }
671 }
672 file = fopen(fileName, "w");
673 if (file == NULL) {
674 return;
675 }
676 fprintf(file, "digraph G {\n");
677
678 fprintf(file, " rankdir=TB\n");
679
680 int numReachableBlocks = cUnit->numReachableBlocks;
681 int idx;
682 const GrowableList *blockList = &cUnit->blockList;
683
684 for (idx = 0; idx < numReachableBlocks; idx++) {
685 int blockIdx = cUnit->dfsOrder.elemList[idx];
686 BasicBlock *bb = (BasicBlock *) dvmGrowableListGetElement(blockList,
687 blockIdx);
688 if (bb == NULL) break;
689 if (bb->blockType == kMethodEntryBlock) {
690 fprintf(file, " entry [shape=Mdiamond];\n");
691 } else if (bb->blockType == kMethodExitBlock) {
692 fprintf(file, " exit [shape=Mdiamond];\n");
693 } else if (bb->blockType == kDalvikByteCode) {
694 fprintf(file, " block%04x [shape=record,label = \"{ \\\n",
695 bb->startOffset);
696 const MIR *mir;
697 for (mir = bb->firstMIRInsn; mir; mir = mir->next) {
698 fprintf(file, " {%04x %s\\l}%s\\\n", mir->offset,
699 mir->ssaRep ?
700 dvmCompilerFullDisassembler(cUnit, mir) :
701 dexGetOpcodeName(mir->dalvikInsn.opcode),
702 mir->next ? " | " : " ");
703 }
704 fprintf(file, " }\"];\n\n");
705 } else if (bb->blockType == kExceptionHandling) {
706 char blockName[BLOCK_NAME_LEN];
707
708 dvmGetBlockName(bb, blockName);
709 fprintf(file, " %s [shape=invhouse];\n", blockName);
710 }
711
712 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
713
714 if (bb->taken) {
715 dvmGetBlockName(bb, blockName1);
716 dvmGetBlockName(bb->taken, blockName2);
717 fprintf(file, " %s:s -> %s:n [style=dotted]\n",
718 blockName1, blockName2);
719 }
720 if (bb->fallThrough) {
721 dvmGetBlockName(bb, blockName1);
722 dvmGetBlockName(bb->fallThrough, blockName2);
723 fprintf(file, " %s:s -> %s:n\n", blockName1, blockName2);
724 }
725
726 if (bb->successorBlockList.blockListType != kNotUsed) {
727 fprintf(file, " succ%04x [shape=%s,label = \"{ \\\n",
728 bb->startOffset,
729 (bb->successorBlockList.blockListType == kCatch) ?
730 "Mrecord" : "record");
731 GrowableListIterator iterator;
732 dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
733 &iterator);
734 SuccessorBlockInfo *successorBlockInfo =
735 (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
736
737 int succId = 0;
738 while (true) {
739 if (successorBlockInfo == NULL) break;
740
741 BasicBlock *destBlock = successorBlockInfo->block;
742 SuccessorBlockInfo *nextSuccessorBlockInfo =
743 (SuccessorBlockInfo *) dvmGrowableListIteratorNext(&iterator);
744
745 fprintf(file, " {<f%d> %04x: %04x\\l}%s\\\n",
746 succId++,
747 successorBlockInfo->key,
748 destBlock->startOffset,
749 (nextSuccessorBlockInfo != NULL) ? " | " : " ");
750
751 successorBlockInfo = nextSuccessorBlockInfo;
752 }
753 fprintf(file, " }\"];\n\n");
754
755 dvmGetBlockName(bb, blockName1);
756 fprintf(file, " %s:s -> succ%04x:n [style=dashed]\n",
757 blockName1, bb->startOffset);
758
759 if (bb->successorBlockList.blockListType == kPackedSwitch ||
760 bb->successorBlockList.blockListType == kSparseSwitch) {
761
762 dvmGrowableListIteratorInit(&bb->successorBlockList.blocks,
763 &iterator);
764
765 succId = 0;
766 while (true) {
767 SuccessorBlockInfo *successorBlockInfo =
768 (SuccessorBlockInfo *)
769 dvmGrowableListIteratorNext(&iterator);
770 if (successorBlockInfo == NULL) break;
771
772 BasicBlock *destBlock = successorBlockInfo->block;
773
774 dvmGetBlockName(destBlock, blockName2);
775 fprintf(file, " succ%04x:f%d:e -> %s:n\n",
776 bb->startOffset, succId++,
777 blockName2);
778 }
779 }
780 }
781 fprintf(file, "\n");
782
783 /*
784 * If we need to debug the dominator tree, uncomment the following code
785 */
786#if 1
787 dvmGetBlockName(bb, blockName1);
788 fprintf(file, " cfg%s [label=\"%s\", shape=none];\n",
789 blockName1, blockName1);
790 if (bb->iDom) {
791 dvmGetBlockName(bb->iDom, blockName2);
792 fprintf(file, " cfg%s:s -> cfg%s:n\n\n",
793 blockName2, blockName1);
794 }
795#endif
796 }
797 fprintf(file, "}\n");
798 fclose(file);
799}
800
801/* Verify if all the successor is connected with all the claimed predecessors */
802static bool verifyPredInfo(CompilationUnit *cUnit, BasicBlock *bb)
803{
804 BitVectorIterator bvIterator;
805
806 dvmBitVectorIteratorInit(bb->predecessors, &bvIterator);
807 while (true) {
808 int blockIdx = dvmBitVectorIteratorNext(&bvIterator);
809 if (blockIdx == -1) break;
810 BasicBlock *predBB = (BasicBlock *)
811 dvmGrowableListGetElement(&cUnit->blockList, blockIdx);
812 bool found = false;
813 if (predBB->taken == bb) {
814 found = true;
815 } else if (predBB->fallThrough == bb) {
816 found = true;
817 } else if (predBB->successorBlockList.blockListType != kNotUsed) {
818 GrowableListIterator iterator;
819 dvmGrowableListIteratorInit(&predBB->successorBlockList.blocks,
820 &iterator);
821 while (true) {
822 SuccessorBlockInfo *successorBlockInfo =
823 (SuccessorBlockInfo *)
824 dvmGrowableListIteratorNext(&iterator);
825 if (successorBlockInfo == NULL) break;
826 BasicBlock *succBB = successorBlockInfo->block;
827 if (succBB == bb) {
828 found = true;
829 break;
830 }
831 }
832 }
833 if (found == false) {
834 char blockName1[BLOCK_NAME_LEN], blockName2[BLOCK_NAME_LEN];
835 dvmGetBlockName(bb, blockName1);
836 dvmGetBlockName(predBB, blockName2);
837 dumpCFG(cUnit, "/sdcard/cfg/");
838 LOGE("Successor %s not found from %s",
839 blockName1, blockName2);
840 dvmAbort();
841 }
842 }
843 return true;
844}
845
846/* Identify code range in try blocks and set up the empty catch blocks */
847static void processTryCatchBlocks(CompilationUnit *cUnit)
848{
849 const Method *meth = cUnit->method;
850 const DexCode *pCode = dvmGetMethodCode(meth);
851 int triesSize = pCode->triesSize;
852 int i;
853 int offset;
854
855 if (triesSize == 0) {
856 return;
857 }
858
859 const DexTry *pTries = dexGetTries(pCode);
860 BitVector *tryBlockAddr = cUnit->tryBlockAddr;
861
862 /* Mark all the insn offsets in Try blocks */
863 for (i = 0; i < triesSize; i++) {
864 const DexTry* pTry = &pTries[i];
865 /* all in 16-bit units */
866 int startOffset = pTry->startAddr;
867 int endOffset = startOffset + pTry->insnCount;
868
869 for (offset = startOffset; offset < endOffset; offset++) {
870 dvmCompilerSetBit(tryBlockAddr, offset);
871 }
872 }
873
874 /* Iterate over each of the handlers to enqueue the empty Catch blocks */
875 offset = dexGetFirstHandlerOffset(pCode);
876 int handlersSize = dexGetHandlersSize(pCode);
877
878 for (i = 0; i < handlersSize; i++) {
879 DexCatchIterator iterator;
880 dexCatchIteratorInit(&iterator, pCode, offset);
881
882 for (;;) {
883 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
884
885 if (handler == NULL) {
886 break;
887 }
888
889 /*
890 * Create dummy catch blocks first. Since these are created before
891 * other blocks are processed, "split" is specified as false.
892 */
893 findBlock(cUnit, handler->address,
894 /* split */
895 false,
896 /* create */
897 true);
898 }
899
900 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
901 }
902}
903
904/* Process instructions with the kInstrCanBranch flag */
905static void processCanBranch(CompilationUnit *cUnit, BasicBlock *curBlock,
906 MIR *insn, int curOffset, int width, int flags,
907 const u2* codePtr, const u2* codeEnd)
908{
909 int target = curOffset;
910 switch (insn->dalvikInsn.opcode) {
911 case OP_GOTO:
912 case OP_GOTO_16:
913 case OP_GOTO_32:
914 target += (int) insn->dalvikInsn.vA;
915 break;
916 case OP_IF_EQ:
917 case OP_IF_NE:
918 case OP_IF_LT:
919 case OP_IF_GE:
920 case OP_IF_GT:
921 case OP_IF_LE:
922 target += (int) insn->dalvikInsn.vC;
923 break;
924 case OP_IF_EQZ:
925 case OP_IF_NEZ:
926 case OP_IF_LTZ:
927 case OP_IF_GEZ:
928 case OP_IF_GTZ:
929 case OP_IF_LEZ:
930 target += (int) insn->dalvikInsn.vB;
931 break;
932 default:
933 LOGE("Unexpected opcode(%d) with kInstrCanBranch set",
934 insn->dalvikInsn.opcode);
935 dvmAbort();
936 }
937 BasicBlock *takenBlock = findBlock(cUnit, target,
938 /* split */
939 true,
940 /* create */
941 true);
942 curBlock->taken = takenBlock;
943 dvmCompilerSetBit(takenBlock->predecessors, curBlock->id);
944
945 /* Always terminate the current block for conditional branches */
946 if (flags & kInstrCanContinue) {
947 BasicBlock *fallthroughBlock = findBlock(cUnit,
948 curOffset + width,
949 /*
950 * If the method is processed
951 * in sequential order from the
952 * beginning, we don't need to
953 * specify split for continue
954 * blocks. However, this
955 * routine can be called by
956 * compileLoop, which starts
957 * parsing the method from an
958 * arbitrary address in the
959 * method body.
960 */
961 true,
962 /* create */
963 true);
964 curBlock->fallThrough = fallthroughBlock;
965 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
966 } else if (codePtr < codeEnd) {
967 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
968 if (contentIsInsn(codePtr)) {
969 findBlock(cUnit, curOffset + width,
970 /* split */
971 false,
972 /* create */
973 true);
974 }
975 }
976}
977
978/* Process instructions with the kInstrCanSwitch flag */
979static void processCanSwitch(CompilationUnit *cUnit, BasicBlock *curBlock,
980 MIR *insn, int curOffset, int width, int flags)
981{
982 u2 *switchData= (u2 *) (cUnit->method->insns + curOffset +
983 insn->dalvikInsn.vB);
984 int size;
985 int *keyTable;
986 int *targetTable;
987 int i;
988 int firstKey;
989
990 /*
991 * Packed switch data format:
992 * ushort ident = 0x0100 magic value
993 * ushort size number of entries in the table
994 * int first_key first (and lowest) switch case value
995 * int targets[size] branch targets, relative to switch opcode
996 *
997 * Total size is (4+size*2) 16-bit code units.
998 */
999 if (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) {
1000 assert(switchData[0] == kPackedSwitchSignature);
1001 size = switchData[1];
1002 firstKey = switchData[2] | (switchData[3] << 16);
1003 targetTable = (int *) &switchData[4];
1004 keyTable = NULL; // Make the compiler happy
1005 /*
1006 * Sparse switch data format:
1007 * ushort ident = 0x0200 magic value
1008 * ushort size number of entries in the table; > 0
1009 * int keys[size] keys, sorted low-to-high; 32-bit aligned
1010 * int targets[size] branch targets, relative to switch opcode
1011 *
1012 * Total size is (2+size*4) 16-bit code units.
1013 */
1014 } else {
1015 assert(switchData[0] == kSparseSwitchSignature);
1016 size = switchData[1];
1017 keyTable = (int *) &switchData[2];
1018 targetTable = (int *) &switchData[2 + size*2];
1019 firstKey = 0; // To make the compiler happy
1020 }
1021
1022 if (curBlock->successorBlockList.blockListType != kNotUsed) {
1023 LOGE("Successor block list already in use: %d",
1024 curBlock->successorBlockList.blockListType);
1025 dvmAbort();
1026 }
1027 curBlock->successorBlockList.blockListType =
1028 (insn->dalvikInsn.opcode == OP_PACKED_SWITCH) ?
1029 kPackedSwitch : kSparseSwitch;
1030 dvmInitGrowableList(&curBlock->successorBlockList.blocks, size);
1031
1032 for (i = 0; i < size; i++) {
1033 BasicBlock *caseBlock = findBlock(cUnit, curOffset + targetTable[i],
1034 /* split */
1035 true,
1036 /* create */
1037 true);
1038 SuccessorBlockInfo *successorBlockInfo =
1039 (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo),
1040 false);
1041 successorBlockInfo->block = caseBlock;
1042 successorBlockInfo->key = (insn->dalvikInsn.opcode == OP_PACKED_SWITCH)?
1043 firstKey + i : keyTable[i];
1044 dvmInsertGrowableList(&curBlock->successorBlockList.blocks,
1045 (intptr_t) successorBlockInfo);
1046 dvmCompilerSetBit(caseBlock->predecessors, curBlock->id);
1047 }
1048
1049 /* Fall-through case */
1050 BasicBlock *fallthroughBlock = findBlock(cUnit,
1051 curOffset + width,
1052 /* split */
1053 false,
1054 /* create */
1055 true);
1056 curBlock->fallThrough = fallthroughBlock;
1057 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
1058}
1059
1060/* Process instructions with the kInstrCanThrow flag */
1061static void processCanThrow(CompilationUnit *cUnit, BasicBlock *curBlock,
1062 MIR *insn, int curOffset, int width, int flags,
1063 BitVector *tryBlockAddr, const u2 *codePtr,
1064 const u2* codeEnd)
1065{
1066 const Method *method = cUnit->method;
1067 const DexCode *dexCode = dvmGetMethodCode(method);
1068
1069 /* In try block */
1070 if (dvmIsBitSet(tryBlockAddr, curOffset)) {
1071 DexCatchIterator iterator;
1072
1073 if (!dexFindCatchHandler(&iterator, dexCode, curOffset)) {
1074 LOGE("Catch block not found in dexfile for insn %x in %s",
1075 curOffset, method->name);
1076 dvmAbort();
1077
1078 }
1079 if (curBlock->successorBlockList.blockListType != kNotUsed) {
1080 LOGE("Successor block list already in use: %d",
1081 curBlock->successorBlockList.blockListType);
1082 dvmAbort();
1083 }
1084 curBlock->successorBlockList.blockListType = kCatch;
1085 dvmInitGrowableList(&curBlock->successorBlockList.blocks, 2);
1086
1087 for (;;) {
1088 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
1089
1090 if (handler == NULL) {
1091 break;
1092 }
1093
1094 BasicBlock *catchBlock = findBlock(cUnit, handler->address,
1095 /* split */
1096 false,
1097 /* create */
1098 false);
1099
1100 SuccessorBlockInfo *successorBlockInfo =
1101 (SuccessorBlockInfo *) dvmCompilerNew(sizeof(SuccessorBlockInfo),
1102 false);
1103 successorBlockInfo->block = catchBlock;
1104 successorBlockInfo->key = handler->typeIdx;
1105 dvmInsertGrowableList(&curBlock->successorBlockList.blocks,
1106 (intptr_t) successorBlockInfo);
1107 dvmCompilerSetBit(catchBlock->predecessors, curBlock->id);
1108 }
1109 } else {
1110 BasicBlock *ehBlock = dvmCompilerNewBB(kExceptionHandling,
1111 cUnit->numBlocks++);
1112 curBlock->taken = ehBlock;
1113 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) ehBlock);
1114 ehBlock->startOffset = curOffset;
1115 dvmCompilerSetBit(ehBlock->predecessors, curBlock->id);
1116 }
1117
1118 /*
1119 * Force the current block to terminate.
1120 *
1121 * Data may be present before codeEnd, so we need to parse it to know
1122 * whether it is code or data.
1123 */
1124 if (codePtr < codeEnd) {
1125 /* Create a fallthrough block for real instructions (incl. OP_NOP) */
1126 if (contentIsInsn(codePtr)) {
1127 BasicBlock *fallthroughBlock = findBlock(cUnit,
1128 curOffset + width,
1129 /* split */
1130 false,
1131 /* create */
1132 true);
1133 /*
1134 * OP_THROW and OP_THROW_VERIFICATION_ERROR are unconditional
1135 * branches.
1136 */
1137 if (insn->dalvikInsn.opcode != OP_THROW_VERIFICATION_ERROR &&
1138 insn->dalvikInsn.opcode != OP_THROW) {
1139 curBlock->fallThrough = fallthroughBlock;
1140 dvmCompilerSetBit(fallthroughBlock->predecessors, curBlock->id);
1141 }
1142 }
1143 }
1144}
1145
1146/*
1147 * Similar to dvmCompileTrace, but the entity processed here is the whole
1148 * method.
1149 *
1150 * TODO: implementation will be revisited when the trace builder can provide
1151 * whole-method traces.
1152 */
1153bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
1154{
1155 CompilationUnit cUnit;
1156 const DexCode *dexCode = dvmGetMethodCode(method);
1157 const u2 *codePtr = dexCode->insns;
1158 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
1159 int numBlocks = 0;
1160 unsigned int curOffset = 0;
1161
1162 /* Method already compiled */
1163 if (dvmJitGetMethodAddr(codePtr)) {
1164 info->codeAddress = NULL;
1165 return false;
1166 }
1167
1168 memset(&cUnit, 0, sizeof(cUnit));
1169 cUnit.method = method;
1170
1171 cUnit.jitMode = kJitMethod;
1172
1173 /* Initialize the block list */
1174 dvmInitGrowableList(&cUnit.blockList, 4);
1175
1176 /*
1177 * FIXME - PC reconstruction list won't be needed after the codegen routines
1178 * are enhanced to true method mode.
1179 */
1180 /* Initialize the PC reconstruction list */
1181 dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
1182
1183 /* Allocate the bit-vector to track the beginning of basic blocks */
1184 BitVector *tryBlockAddr = dvmCompilerAllocBitVector(dexCode->insnsSize,
1185 true /* expandable */);
1186 cUnit.tryBlockAddr = tryBlockAddr;
1187
1188 /* Create the default entry and exit blocks and enter them to the list */
1189 BasicBlock *entryBlock = dvmCompilerNewBB(kMethodEntryBlock, numBlocks++);
1190 BasicBlock *exitBlock = dvmCompilerNewBB(kMethodExitBlock, numBlocks++);
1191
1192 cUnit.entryBlock = entryBlock;
1193 cUnit.exitBlock = exitBlock;
1194
1195 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) entryBlock);
1196 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) exitBlock);
1197
1198 /* Current block to record parsed instructions */
1199 BasicBlock *curBlock = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
1200 curBlock->startOffset = 0;
1201 dvmInsertGrowableList(&cUnit.blockList, (intptr_t) curBlock);
1202 entryBlock->fallThrough = curBlock;
1203 dvmCompilerSetBit(curBlock->predecessors, entryBlock->id);
1204
1205 /*
1206 * Store back the number of blocks since new blocks may be created of
1207 * accessing cUnit.
1208 */
1209 cUnit.numBlocks = numBlocks;
1210
1211 /* Identify code range in try blocks and set up the empty catch blocks */
1212 processTryCatchBlocks(&cUnit);
1213
1214 /* Parse all instructions and put them into containing basic blocks */
1215 while (codePtr < codeEnd) {
1216 MIR *insn = (MIR *) dvmCompilerNew(sizeof(MIR), true);
1217 insn->offset = curOffset;
1218 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
1219 insn->width = width;
1220
1221 /* Terminate when the data section is seen */
1222 if (width == 0)
1223 break;
1224
1225 dvmCompilerAppendMIR(curBlock, insn);
1226
1227 codePtr += width;
1228 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
1229
1230 if (flags & kInstrCanBranch) {
1231 processCanBranch(&cUnit, curBlock, insn, curOffset, width, flags,
1232 codePtr, codeEnd);
1233 } else if (flags & kInstrCanReturn) {
1234 curBlock->fallThrough = exitBlock;
1235 dvmCompilerSetBit(exitBlock->predecessors, curBlock->id);
1236 /*
1237 * Terminate the current block if there are instructions
1238 * afterwards.
1239 */
1240 if (codePtr < codeEnd) {
1241 /*
1242 * Create a fallthrough block for real instructions
1243 * (incl. OP_NOP).
1244 */
1245 if (contentIsInsn(codePtr)) {
1246 findBlock(&cUnit, curOffset + width,
1247 /* split */
1248 false,
1249 /* create */
1250 true);
1251 }
1252 }
1253 } else if (flags & kInstrCanThrow) {
1254 processCanThrow(&cUnit, curBlock, insn, curOffset, width, flags,
1255 tryBlockAddr, codePtr, codeEnd);
1256 } else if (flags & kInstrCanSwitch) {
1257 processCanSwitch(&cUnit, curBlock, insn, curOffset, width, flags);
1258 }
1259 curOffset += width;
1260 BasicBlock *nextBlock = findBlock(&cUnit, curOffset,
1261 /* split */
1262 false,
1263 /* create */
1264 false);
1265 if (nextBlock) {
1266 /*
1267 * The next instruction could be the target of a previously parsed
1268 * forward branch so a block is already created. If the current
1269 * instruction is not an unconditional branch, connect them through
1270 * the fall-through link.
1271 */
1272 assert(curBlock->fallThrough == NULL ||
1273 curBlock->fallThrough == nextBlock ||
1274 curBlock->fallThrough == exitBlock);
1275
1276 if ((curBlock->fallThrough == NULL) &&
1277 (flags & kInstrCanContinue)) {
1278 curBlock->fallThrough = nextBlock;
1279 dvmCompilerSetBit(nextBlock->predecessors, curBlock->id);
1280 }
1281 curBlock = nextBlock;
1282 }
1283 }
1284
1285 if (cUnit.printMe) {
1286 dvmCompilerDumpCompilationUnit(&cUnit);
1287 }
1288
1289 /* Adjust this value accordingly once inlining is performed */
1290 cUnit.numDalvikRegisters = cUnit.method->registersSize;
1291
1292 /* Verify if all blocks are connected as claimed */
1293 /* FIXME - to be disabled in the future */
1294 dvmCompilerDataFlowAnalysisDispatcher(&cUnit, verifyPredInfo,
1295 kAllNodes,
1296 false /* isIterative */);
1297
1298
1299 /* Perform SSA transformation for the whole method */
1300 dvmCompilerMethodSSATransformation(&cUnit);
1301
1302 dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
1303
1304 /* Allocate Registers using simple local allocation scheme */
1305 dvmCompilerLocalRegAlloc(&cUnit);
1306
1307 /* Convert MIR to LIR, etc. */
1308 dvmCompilerMethodMIR2LIR(&cUnit);
1309
1310 // Debugging only
1311 //dumpCFG(&cUnit, "/sdcard/cfg/");
1312
1313 /* Method is not empty */
1314 if (cUnit.firstLIRInsn) {
1315 /* Convert LIR into machine code. Loop for recoverable retries */
1316 do {
1317 dvmCompilerAssembleLIR(&cUnit, info);
1318 cUnit.assemblerRetries++;
1319 if (cUnit.printMe && cUnit.assemblerStatus != kSuccess)
1320 LOGD("Assembler abort #%d on %d",cUnit.assemblerRetries,
1321 cUnit.assemblerStatus);
1322 } while (cUnit.assemblerStatus == kRetryAll);
1323
1324 if (cUnit.printMe) {
1325 dvmCompilerCodegenDump(&cUnit);
1326 }
1327
1328 if (info->codeAddress) {
1329 dvmJitSetCodeAddr(dexCode->insns, info->codeAddress,
1330 info->instructionSet, true, 0);
1331 /*
1332 * Clear the codeAddress for the enclosing trace to reuse the info
1333 */
1334 info->codeAddress = NULL;
1335 }
1336 }
1337
1338 return false;
1339}
1340
1341/* Extending the trace by crawling the code from curBlock */
1342static bool exhaustTrace(CompilationUnit *cUnit, BasicBlock *curBlock)
1343{
1344 unsigned int curOffset = curBlock->startOffset;
1345 const u2 *codePtr = cUnit->method->insns + curOffset;
1346
1347 if (curBlock->visited == true) return false;
1348
1349 curBlock->visited = true;
1350
1351 if (curBlock->blockType == kMethodEntryBlock ||
1352 curBlock->blockType == kMethodExitBlock) {
1353 return false;
1354 }
1355
1356 /*
1357 * Block has been parsed - check the taken/fallThrough in case it is a split
1358 * block.
1359 */
1360 if (curBlock->firstMIRInsn != NULL) {
1361 bool changed = false;
1362 if (curBlock->taken)
1363 changed |= exhaustTrace(cUnit, curBlock->taken);
1364 if (curBlock->fallThrough)
1365 changed |= exhaustTrace(cUnit, curBlock->fallThrough);
1366 return changed;
1367 }
1368 while (true) {
1369 MIR *insn = (MIR *) dvmCompilerNew(sizeof(MIR), true);
1370 insn->offset = curOffset;
1371 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
1372 insn->width = width;
1373
1374 /* Terminate when the data section is seen */
1375 if (width == 0)
1376 break;
1377
1378 dvmCompilerAppendMIR(curBlock, insn);
1379
1380 codePtr += width;
1381 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
1382
1383 /* Stop extending the trace after seeing these instructions */
1384 if (flags & (kInstrCanReturn | kInstrCanSwitch | kInstrInvoke)) {
1385 curBlock->fallThrough = cUnit->exitBlock;
1386 dvmCompilerSetBit(cUnit->exitBlock->predecessors, curBlock->id);
1387 break;
1388 } else if (flags & kInstrCanBranch) {
1389 processCanBranch(cUnit, curBlock, insn, curOffset, width, flags,
1390 codePtr, NULL);
1391 if (curBlock->taken) {
1392 exhaustTrace(cUnit, curBlock->taken);
1393 }
1394 if (curBlock->fallThrough) {
1395 exhaustTrace(cUnit, curBlock->fallThrough);
1396 }
1397 break;
1398 }
1399 curOffset += width;
1400 }
1401 return true;
1402}
1403
1404/* Compile a loop */
1405static bool compileLoop(CompilationUnit *cUnit, unsigned int startOffset,
1406 JitTraceDescription *desc, int numMaxInsts,
1407 JitTranslationInfo *info, jmp_buf *bailPtr,
1408 int optHints)
1409{
1410 int numBlocks = 0;
1411 unsigned int curOffset = startOffset;
1412 bool changed;
1413
1414 cUnit->jitMode = kJitLoop;
1415
1416 /* Initialize the block list */
1417 dvmInitGrowableList(&cUnit->blockList, 4);
1418
1419 /* Initialize the PC reconstruction list */
1420 dvmInitGrowableList(&cUnit->pcReconstructionList, 8);
1421
1422 /* Create the default entry and exit blocks and enter them to the list */
1423 BasicBlock *entryBlock = dvmCompilerNewBB(kMethodEntryBlock, numBlocks++);
1424 entryBlock->startOffset = curOffset;
1425 BasicBlock *exitBlock = dvmCompilerNewBB(kMethodExitBlock, numBlocks++);
1426
1427 cUnit->entryBlock = entryBlock;
1428 cUnit->exitBlock = exitBlock;
1429
1430 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) entryBlock);
1431 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) exitBlock);
1432
1433 /* Current block to record parsed instructions */
1434 BasicBlock *curBlock = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
1435 curBlock->startOffset = curOffset;
1436
1437 dvmInsertGrowableList(&cUnit->blockList, (intptr_t) curBlock);
1438 entryBlock->fallThrough = curBlock;
1439 dvmCompilerSetBit(curBlock->predecessors, entryBlock->id);
1440
1441 /*
1442 * Store back the number of blocks since new blocks may be created of
1443 * accessing cUnit.
1444 */
1445 cUnit->numBlocks = numBlocks;
1446
1447 do {
1448 dvmCompilerDataFlowAnalysisDispatcher(cUnit,
1449 dvmCompilerClearVisitedFlag,
1450 kAllNodes,
1451 false /* isIterative */);
1452 changed = exhaustTrace(cUnit, curBlock);
1453 } while (changed);
1454
1455 cUnit->numDalvikRegisters = cUnit->method->registersSize;
1456
1457 /* Verify if all blocks are connected as claimed */
1458 /* FIXME - to be disabled in the future */
1459 dvmCompilerDataFlowAnalysisDispatcher(cUnit, verifyPredInfo,
1460 kAllNodes,
1461 false /* isIterative */);
1462
1463
1464 /* Try to identify a loop */
1465 if (!dvmCompilerBuildLoop(cUnit))
1466 goto bail;
1467
1468 dvmCompilerInitializeRegAlloc(cUnit);
1469
1470 /* Allocate Registers using simple local allocation scheme */
1471 dvmCompilerLocalRegAlloc(cUnit);
1472
1473 if (gDvmJit.receivedSIGUSR2) {
1474 dumpCFG(cUnit, "/sdcard/cfg/");
1475 }
1476
1477bail:
1478 /* Retry the original trace with JIT_OPT_NO_LOOP disabled */
1479 dvmCompilerArenaReset();
1480 return dvmCompileTrace(desc, numMaxInsts, info, bailPtr,
1481 optHints | JIT_OPT_NO_LOOP);
1482}
1483
1484/*
Ben Chengba4fc8b2009-06-01 13:00:29 -07001485 * Main entry point to start trace compilation. Basic blocks are constructed
1486 * first and they will be passed to the codegen routines to convert Dalvik
1487 * bytecode into machine code.
1488 */
Bill Buzbee716f1202009-07-23 13:22:09 -07001489bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
Ben Cheng4a419582010-08-04 13:23:09 -07001490 JitTranslationInfo *info, jmp_buf *bailPtr,
1491 int optHints)
Ben Chengba4fc8b2009-06-01 13:00:29 -07001492{
1493 const DexCode *dexCode = dvmGetMethodCode(desc->method);
1494 const JitTraceRun* currRun = &desc->trace[0];
Ben Cheng385828e2011-03-04 16:48:33 -08001495 unsigned int curOffset = currRun->info.frag.startOffset;
Ben Cheng46cd4fb2011-03-16 17:19:06 -07001496 unsigned int startOffset = curOffset;
Ben Cheng385828e2011-03-04 16:48:33 -08001497 unsigned int numInsts = currRun->info.frag.numInsts;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001498 const u2 *codePtr = dexCode->insns + curOffset;
Ben Cheng8b258bf2009-06-24 17:27:07 -07001499 int traceSize = 0; // # of half-words
Ben Chengba4fc8b2009-06-01 13:00:29 -07001500 const u2 *startCodePtr = codePtr;
Ben Cheng00603072010-10-28 11:13:58 -07001501 BasicBlock *curBB, *entryCodeBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001502 int numBlocks = 0;
1503 static int compilationId;
1504 CompilationUnit cUnit;
Ben Cheng00603072010-10-28 11:13:58 -07001505 GrowableList *blockList;
Ben Cheng1357e942010-02-10 17:21:39 -08001506#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -07001507 CompilerMethodStats *methodStats;
Ben Cheng1357e942010-02-10 17:21:39 -08001508#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -07001509
Bill Buzbee964a7b02010-01-28 12:54:19 -08001510 /* If we've already compiled this trace, just return success */
Ben Chengcfdeca32011-01-14 11:36:46 -08001511 if (dvmJitGetTraceAddr(startCodePtr) && !info->discardResult) {
Ben Cheng7a2697d2010-06-07 13:44:23 -07001512 /*
1513 * Make sure the codeAddress is NULL so that it won't clobber the
1514 * existing entry.
1515 */
1516 info->codeAddress = NULL;
Bill Buzbee964a7b02010-01-28 12:54:19 -08001517 return true;
1518 }
1519
buzbee18fba342011-01-19 15:31:15 -08001520 /* If the work order is stale, discard it */
1521 if (info->cacheVersion != gDvmJit.cacheVersion) {
1522 return false;
1523 }
1524
Ben Chenge9695e52009-06-16 16:11:47 -07001525 compilationId++;
Ben Cheng8b258bf2009-06-24 17:27:07 -07001526 memset(&cUnit, 0, sizeof(CompilationUnit));
1527
Ben Cheng1357e942010-02-10 17:21:39 -08001528#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -07001529 /* Locate the entry to store compilation statistics for this method */
Ben Cheng7a2697d2010-06-07 13:44:23 -07001530 methodStats = dvmCompilerAnalyzeMethodBody(desc->method, false);
Ben Cheng1357e942010-02-10 17:21:39 -08001531#endif
Ben Chenge9695e52009-06-16 16:11:47 -07001532
Bill Buzbeefc519dc2010-03-06 23:30:57 -08001533 /* Set the recover buffer pointer */
1534 cUnit.bailPtr = bailPtr;
1535
Ben Chengba4fc8b2009-06-01 13:00:29 -07001536 /* Initialize the printMe flag */
1537 cUnit.printMe = gDvmJit.printMe;
1538
Ben Cheng7a2697d2010-06-07 13:44:23 -07001539 /* Setup the method */
1540 cUnit.method = desc->method;
1541
1542 /* Initialize the PC reconstruction list */
1543 dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
1544
Ben Cheng00603072010-10-28 11:13:58 -07001545 /* Initialize the basic block list */
1546 blockList = &cUnit.blockList;
1547 dvmInitGrowableList(blockList, 8);
1548
Ben Chengba4fc8b2009-06-01 13:00:29 -07001549 /* Identify traces that we don't want to compile */
1550 if (gDvmJit.methodTable) {
1551 int len = strlen(desc->method->clazz->descriptor) +
1552 strlen(desc->method->name) + 1;
Carl Shapirofc75f3e2010-12-07 11:43:38 -08001553 char *fullSignature = (char *)dvmCompilerNew(len, true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001554 strcpy(fullSignature, desc->method->clazz->descriptor);
1555 strcat(fullSignature, desc->method->name);
1556
1557 int hashValue = dvmComputeUtf8Hash(fullSignature);
1558
1559 /*
1560 * Doing three levels of screening to see whether we want to skip
1561 * compiling this method
1562 */
1563
1564 /* First, check the full "class;method" signature */
1565 bool methodFound =
1566 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
1567 fullSignature, (HashCompareFunc) strcmp,
1568 false) !=
1569 NULL;
1570
1571 /* Full signature not found - check the enclosing class */
1572 if (methodFound == false) {
1573 int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
1574 methodFound =
1575 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
1576 (char *) desc->method->clazz->descriptor,
1577 (HashCompareFunc) strcmp, false) !=
1578 NULL;
1579 /* Enclosing class not found - check the method name */
1580 if (methodFound == false) {
1581 int hashValue = dvmComputeUtf8Hash(desc->method->name);
1582 methodFound =
1583 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
1584 (char *) desc->method->name,
1585 (HashCompareFunc) strcmp, false) !=
1586 NULL;
Ben Cheng33672452010-01-12 14:59:30 -08001587
1588 /*
1589 * Debug by call-graph is enabled. Check if the debug list
1590 * covers any methods on the VM stack.
1591 */
1592 if (methodFound == false && gDvmJit.checkCallGraph == true) {
1593 methodFound =
1594 filterMethodByCallGraph(info->requestingThread,
1595 desc->method->name);
1596 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001597 }
1598 }
1599
1600 /*
1601 * Under the following conditions, the trace will be *conservatively*
1602 * compiled by only containing single-step instructions to and from the
1603 * interpreter.
1604 * 1) If includeSelectedMethod == false, the method matches the full or
1605 * partial signature stored in the hash table.
1606 *
1607 * 2) If includeSelectedMethod == true, the method does not match the
1608 * full and partial signature stored in the hash table.
1609 */
1610 if (gDvmJit.includeSelectedMethod != methodFound) {
1611 cUnit.allSingleStep = true;
1612 } else {
1613 /* Compile the trace as normal */
1614
1615 /* Print the method we cherry picked */
1616 if (gDvmJit.includeSelectedMethod == true) {
1617 cUnit.printMe = true;
1618 }
1619 }
1620 }
1621
Ben Cheng4238ec22009-08-24 16:32:22 -07001622 /* Allocate the entry block */
Ben Cheng00603072010-10-28 11:13:58 -07001623 curBB = dvmCompilerNewBB(kTraceEntryBlock, numBlocks++);
1624 dvmInsertGrowableList(blockList, (intptr_t) curBB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001625 curBB->startOffset = curOffset;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001626
Ben Cheng00603072010-10-28 11:13:58 -07001627 entryCodeBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
1628 dvmInsertGrowableList(blockList, (intptr_t) entryCodeBB);
1629 entryCodeBB->startOffset = curOffset;
1630 curBB->fallThrough = entryCodeBB;
1631 curBB = entryCodeBB;
Ben Cheng4238ec22009-08-24 16:32:22 -07001632
Ben Chengba4fc8b2009-06-01 13:00:29 -07001633 if (cUnit.printMe) {
1634 LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n",
1635 desc->method->name, curOffset);
1636 }
1637
Ben Cheng1efc9c52009-06-08 18:25:27 -07001638 /*
1639 * Analyze the trace descriptor and include up to the maximal number
1640 * of Dalvik instructions into the IR.
1641 */
1642 while (1) {
Ben Chengba4fc8b2009-06-01 13:00:29 -07001643 MIR *insn;
1644 int width;
Carl Shapirofc75f3e2010-12-07 11:43:38 -08001645 insn = (MIR *)dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001646 insn->offset = curOffset;
1647 width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
Ben Cheng8b258bf2009-06-24 17:27:07 -07001648
1649 /* The trace should never incude instruction data */
1650 assert(width);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001651 insn->width = width;
1652 traceSize += width;
1653 dvmCompilerAppendMIR(curBB, insn);
Ben Cheng1efc9c52009-06-08 18:25:27 -07001654 cUnit.numInsts++;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001655
Dan Bornsteine4852762010-12-02 12:45:00 -08001656 int flags = dexGetFlagsFromOpcode(insn->dalvikInsn.opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -07001657
Dan Bornstein0759f522010-11-30 14:58:53 -08001658 if (flags & kInstrInvoke) {
Ben Cheng385828e2011-03-04 16:48:33 -08001659 const Method *calleeMethod = (const Method *)
1660 currRun[JIT_TRACE_CUR_METHOD].info.meta;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001661 assert(numInsts == 1);
1662 CallsiteInfo *callsiteInfo =
Carl Shapirofc75f3e2010-12-07 11:43:38 -08001663 (CallsiteInfo *)dvmCompilerNew(sizeof(CallsiteInfo), true);
Ben Cheng385828e2011-03-04 16:48:33 -08001664 callsiteInfo->classDescriptor = (const char *)
1665 currRun[JIT_TRACE_CLASS_DESC].info.meta;
1666 callsiteInfo->classLoader = (Object *)
1667 currRun[JIT_TRACE_CLASS_LOADER].info.meta;
Ben Chengcfdeca32011-01-14 11:36:46 -08001668 callsiteInfo->method = calleeMethod;
Ben Cheng7a2697d2010-06-07 13:44:23 -07001669 insn->meta.callsiteInfo = callsiteInfo;
1670 }
1671
Ben Cheng1efc9c52009-06-08 18:25:27 -07001672 /* Instruction limit reached - terminate the trace here */
1673 if (cUnit.numInsts >= numMaxInsts) {
1674 break;
1675 }
1676 if (--numInsts == 0) {
Ben Cheng385828e2011-03-04 16:48:33 -08001677 if (currRun->info.frag.runEnd) {
Ben Cheng1efc9c52009-06-08 18:25:27 -07001678 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001679 } else {
Ben Cheng7a2697d2010-06-07 13:44:23 -07001680 /* Advance to the next trace description (ie non-meta info) */
1681 do {
1682 currRun++;
Ben Cheng385828e2011-03-04 16:48:33 -08001683 } while (!currRun->isCode);
Ben Cheng7a2697d2010-06-07 13:44:23 -07001684
1685 /* Dummy end-of-run marker seen */
Ben Cheng385828e2011-03-04 16:48:33 -08001686 if (currRun->info.frag.numInsts == 0) {
Ben Cheng7a2697d2010-06-07 13:44:23 -07001687 break;
1688 }
1689
Ben Cheng00603072010-10-28 11:13:58 -07001690 curBB = dvmCompilerNewBB(kDalvikByteCode, numBlocks++);
1691 dvmInsertGrowableList(blockList, (intptr_t) curBB);
Ben Cheng385828e2011-03-04 16:48:33 -08001692 curOffset = currRun->info.frag.startOffset;
1693 numInsts = currRun->info.frag.numInsts;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001694 curBB->startOffset = curOffset;
1695 codePtr = dexCode->insns + curOffset;
1696 }
1697 } else {
1698 curOffset += width;
1699 codePtr += width;
1700 }
1701 }
1702
Ben Cheng1357e942010-02-10 17:21:39 -08001703#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -07001704 /* Convert # of half-word to bytes */
1705 methodStats->compiledDalvikSize += traceSize * 2;
Ben Cheng1357e942010-02-10 17:21:39 -08001706#endif
Ben Cheng8b258bf2009-06-24 17:27:07 -07001707
Ben Chengba4fc8b2009-06-01 13:00:29 -07001708 /*
1709 * Now scan basic blocks containing real code to connect the
1710 * taken/fallthrough links. Also create chaining cells for code not included
1711 * in the trace.
1712 */
Ben Cheng00603072010-10-28 11:13:58 -07001713 size_t blockId;
1714 for (blockId = 0; blockId < blockList->numUsed; blockId++) {
1715 curBB = (BasicBlock *) dvmGrowableListGetElement(blockList, blockId);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001716 MIR *lastInsn = curBB->lastMIRInsn;
buzbee2e152ba2010-12-15 16:32:35 -08001717 BasicBlock *backwardCell;
Ben Cheng4238ec22009-08-24 16:32:22 -07001718 /* Skip empty blocks */
Ben Chengba4fc8b2009-06-01 13:00:29 -07001719 if (lastInsn == NULL) {
Ben Cheng4238ec22009-08-24 16:32:22 -07001720 continue;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001721 }
1722 curOffset = lastInsn->offset;
1723 unsigned int targetOffset = curOffset;
1724 unsigned int fallThroughOffset = curOffset + lastInsn->width;
1725 bool isInvoke = false;
1726 const Method *callee = NULL;
1727
1728 findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
1729 &targetOffset, &isInvoke, &callee);
1730
1731 /* Link the taken and fallthrough blocks */
1732 BasicBlock *searchBB;
1733
Dan Bornsteine4852762010-12-02 12:45:00 -08001734 int flags = dexGetFlagsFromOpcode(lastInsn->dalvikInsn.opcode);
Ben Cheng7a2697d2010-06-07 13:44:23 -07001735
1736 if (flags & kInstrInvoke) {
1737 cUnit.hasInvoke = true;
1738 }
1739
Ben Cheng46cd4fb2011-03-16 17:19:06 -07001740 /* Backward branch seen */
1741 if (isInvoke == false &&
1742 (flags & kInstrCanBranch) != 0 &&
1743 targetOffset < curOffset &&
1744 (optHints & JIT_OPT_NO_LOOP) == 0) {
1745 dvmCompilerArenaReset();
1746 /* TODO - constructed loop is abandoned for now */
1747 return compileLoop(&cUnit, startOffset, desc, numMaxInsts,
1748 info, bailPtr, optHints);
1749 }
1750
Ben Chengba4fc8b2009-06-01 13:00:29 -07001751 /* No backward branch in the trace - start searching the next BB */
Ben Cheng00603072010-10-28 11:13:58 -07001752 size_t searchBlockId;
1753 for (searchBlockId = blockId+1; searchBlockId < blockList->numUsed;
1754 searchBlockId++) {
1755 searchBB = (BasicBlock *) dvmGrowableListGetElement(blockList,
1756 searchBlockId);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001757 if (targetOffset == searchBB->startOffset) {
1758 curBB->taken = searchBB;
Ben Cheng7ab74e12011-02-03 14:02:06 -08001759 dvmCompilerSetBit(searchBB->predecessors, curBB->id);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001760 }
1761 if (fallThroughOffset == searchBB->startOffset) {
1762 curBB->fallThrough = searchBB;
Ben Cheng7ab74e12011-02-03 14:02:06 -08001763 dvmCompilerSetBit(searchBB->predecessors, curBB->id);
Ben Cheng7a2697d2010-06-07 13:44:23 -07001764
1765 /*
1766 * Fallthrough block of an invoke instruction needs to be
1767 * aligned to 4-byte boundary (alignment instruction to be
1768 * inserted later.
1769 */
1770 if (flags & kInstrInvoke) {
1771 searchBB->isFallThroughFromInvoke = true;
1772 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001773 }
1774 }
1775
Ben Cheng1efc9c52009-06-08 18:25:27 -07001776 /*
1777 * Some blocks are ended by non-control-flow-change instructions,
1778 * currently only due to trace length constraint. In this case we need
1779 * to generate an explicit branch at the end of the block to jump to
1780 * the chaining cell.
1781 */
1782 curBB->needFallThroughBranch =
Ben Cheng17f15ce2009-07-27 16:21:52 -07001783 ((flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
Dan Bornstein0759f522010-11-30 14:58:53 -08001784 kInstrInvoke)) == 0);
Ben Cheng17f15ce2009-07-27 16:21:52 -07001785
Ben Cheng4a419582010-08-04 13:23:09 -07001786 /* Only form a loop if JIT_OPT_NO_LOOP is not set */
Ben Cheng4238ec22009-08-24 16:32:22 -07001787 if (curBB->taken == NULL &&
1788 curBB->fallThrough == NULL &&
1789 flags == (kInstrCanBranch | kInstrCanContinue) &&
Ben Cheng00603072010-10-28 11:13:58 -07001790 fallThroughOffset == entryCodeBB->startOffset &&
Ben Cheng4a419582010-08-04 13:23:09 -07001791 JIT_OPT_NO_LOOP != (optHints & JIT_OPT_NO_LOOP)) {
Ben Cheng0fd31e42009-09-03 14:40:16 -07001792 BasicBlock *loopBranch = curBB;
1793 BasicBlock *exitBB;
1794 BasicBlock *exitChainingCell;
Ben Cheng4238ec22009-08-24 16:32:22 -07001795
1796 if (cUnit.printMe) {
1797 LOGD("Natural loop detected!");
1798 }
Ben Cheng00603072010-10-28 11:13:58 -07001799 exitBB = dvmCompilerNewBB(kTraceExitBlock, numBlocks++);
1800 dvmInsertGrowableList(blockList, (intptr_t) exitBB);
Ben Cheng0fd31e42009-09-03 14:40:16 -07001801 exitBB->startOffset = targetOffset;
Ben Cheng0fd31e42009-09-03 14:40:16 -07001802 exitBB->needFallThroughBranch = true;
Ben Cheng4238ec22009-08-24 16:32:22 -07001803
Ben Cheng0fd31e42009-09-03 14:40:16 -07001804 loopBranch->taken = exitBB;
Ben Cheng7ab74e12011-02-03 14:02:06 -08001805 dvmCompilerSetBit(exitBB->predecessors, loopBranch->id);
buzbee2e152ba2010-12-15 16:32:35 -08001806 backwardCell =
Ben Cheng00603072010-10-28 11:13:58 -07001807 dvmCompilerNewBB(kChainingCellBackwardBranch, numBlocks++);
1808 dvmInsertGrowableList(blockList, (intptr_t) backwardCell);
1809 backwardCell->startOffset = entryCodeBB->startOffset;
Ben Cheng0fd31e42009-09-03 14:40:16 -07001810 loopBranch->fallThrough = backwardCell;
Ben Cheng7ab74e12011-02-03 14:02:06 -08001811 dvmCompilerSetBit(backwardCell->predecessors, loopBranch->id);
Ben Cheng0fd31e42009-09-03 14:40:16 -07001812
1813 /* Create the chaining cell as the fallthrough of the exit block */
Ben Cheng00603072010-10-28 11:13:58 -07001814 exitChainingCell = dvmCompilerNewBB(kChainingCellNormal,
1815 numBlocks++);
1816 dvmInsertGrowableList(blockList, (intptr_t) exitChainingCell);
Ben Cheng0fd31e42009-09-03 14:40:16 -07001817 exitChainingCell->startOffset = targetOffset;
Ben Cheng0fd31e42009-09-03 14:40:16 -07001818
1819 exitBB->fallThrough = exitChainingCell;
Ben Cheng7ab74e12011-02-03 14:02:06 -08001820 dvmCompilerSetBit(exitChainingCell->predecessors, exitBB->id);
Ben Cheng0fd31e42009-09-03 14:40:16 -07001821
Ben Cheng4238ec22009-08-24 16:32:22 -07001822 cUnit.hasLoop = true;
1823 }
1824
Dan Bornstein9a1f8162010-12-01 17:02:26 -08001825 if (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ||
1826 lastInsn->dalvikInsn.opcode == OP_SPARSE_SWITCH) {
Ben Cheng6c10a972009-10-29 14:39:18 -07001827 int i;
1828 const u2 *switchData = desc->method->insns + lastInsn->offset +
1829 lastInsn->dalvikInsn.vB;
1830 int size = switchData[1];
1831 int maxChains = MIN(size, MAX_CHAINED_SWITCH_CASES);
1832
1833 /*
1834 * Generate the landing pad for cases whose ranks are higher than
1835 * MAX_CHAINED_SWITCH_CASES. The code will re-enter the interpreter
1836 * through the NoChain point.
1837 */
1838 if (maxChains != size) {
1839 cUnit.switchOverflowPad =
1840 desc->method->insns + lastInsn->offset;
1841 }
1842
1843 s4 *targets = (s4 *) (switchData + 2 +
Dan Bornstein9a1f8162010-12-01 17:02:26 -08001844 (lastInsn->dalvikInsn.opcode == OP_PACKED_SWITCH ?
Ben Cheng6c10a972009-10-29 14:39:18 -07001845 2 : size * 2));
1846
1847 /* One chaining cell for the first MAX_CHAINED_SWITCH_CASES cases */
1848 for (i = 0; i < maxChains; i++) {
Ben Cheng00603072010-10-28 11:13:58 -07001849 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal,
1850 numBlocks++);
1851 dvmInsertGrowableList(blockList, (intptr_t) caseChain);
Ben Cheng6c10a972009-10-29 14:39:18 -07001852 caseChain->startOffset = lastInsn->offset + targets[i];
Ben Cheng6c10a972009-10-29 14:39:18 -07001853 }
1854
1855 /* One more chaining cell for the default case */
Ben Cheng00603072010-10-28 11:13:58 -07001856 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal,
1857 numBlocks++);
1858 dvmInsertGrowableList(blockList, (intptr_t) caseChain);
Ben Cheng6c10a972009-10-29 14:39:18 -07001859 caseChain->startOffset = lastInsn->offset + lastInsn->width;
Ben Cheng6d576092009-09-01 17:01:58 -07001860 /* Fallthrough block not included in the trace */
Ben Cheng6c10a972009-10-29 14:39:18 -07001861 } else if (!isUnconditionalBranch(lastInsn) &&
1862 curBB->fallThrough == NULL) {
Ben Cheng00603072010-10-28 11:13:58 -07001863 BasicBlock *fallThroughBB;
Ben Cheng6d576092009-09-01 17:01:58 -07001864 /*
1865 * If the chaining cell is after an invoke or
1866 * instruction that cannot change the control flow, request a hot
1867 * chaining cell.
1868 */
1869 if (isInvoke || curBB->needFallThroughBranch) {
Ben Cheng00603072010-10-28 11:13:58 -07001870 fallThroughBB = dvmCompilerNewBB(kChainingCellHot, numBlocks++);
Ben Cheng6d576092009-09-01 17:01:58 -07001871 } else {
Ben Cheng00603072010-10-28 11:13:58 -07001872 fallThroughBB = dvmCompilerNewBB(kChainingCellNormal,
1873 numBlocks++);
Ben Cheng6d576092009-09-01 17:01:58 -07001874 }
Ben Cheng00603072010-10-28 11:13:58 -07001875 dvmInsertGrowableList(blockList, (intptr_t) fallThroughBB);
1876 fallThroughBB->startOffset = fallThroughOffset;
1877 curBB->fallThrough = fallThroughBB;
Ben Cheng7ab74e12011-02-03 14:02:06 -08001878 dvmCompilerSetBit(fallThroughBB->predecessors, curBB->id);
Ben Cheng6d576092009-09-01 17:01:58 -07001879 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001880 /* Target block not included in the trace */
Ben Cheng38329f52009-07-07 14:19:20 -07001881 if (curBB->taken == NULL &&
Bill Buzbee324b3ac2009-12-04 13:17:36 -08001882 (isGoto(lastInsn) || isInvoke ||
1883 (targetOffset != UNKNOWN_TARGET && targetOffset != curOffset))) {
Ben Cheng7e2c3c72010-12-22 16:40:46 -08001884 BasicBlock *newBB = NULL;
Ben Cheng1efc9c52009-06-08 18:25:27 -07001885 if (isInvoke) {
Ben Cheng38329f52009-07-07 14:19:20 -07001886 /* Monomorphic callee */
1887 if (callee) {
Ben Cheng7e2c3c72010-12-22 16:40:46 -08001888 /* JNI call doesn't need a chaining cell */
1889 if (!dvmIsNativeMethod(callee)) {
1890 newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton,
1891 numBlocks++);
1892 newBB->startOffset = 0;
1893 newBB->containingMethod = callee;
1894 }
Ben Cheng38329f52009-07-07 14:19:20 -07001895 /* Will resolve at runtime */
1896 } else {
Ben Cheng00603072010-10-28 11:13:58 -07001897 newBB = dvmCompilerNewBB(kChainingCellInvokePredicted,
1898 numBlocks++);
Ben Cheng38329f52009-07-07 14:19:20 -07001899 newBB->startOffset = 0;
1900 }
Ben Cheng1efc9c52009-06-08 18:25:27 -07001901 /* For unconditional branches, request a hot chaining cell */
1902 } else {
Jeff Hao97319a82009-08-12 16:57:15 -07001903#if !defined(WITH_SELF_VERIFICATION)
Dan Bornsteinc2b486f2010-11-12 16:07:16 -08001904 newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
Bill Buzbee1465db52009-09-23 17:17:35 -07001905 kChainingCellHot :
Ben Cheng00603072010-10-28 11:13:58 -07001906 kChainingCellNormal,
1907 numBlocks++);
Ben Cheng38329f52009-07-07 14:19:20 -07001908 newBB->startOffset = targetOffset;
Jeff Hao97319a82009-08-12 16:57:15 -07001909#else
1910 /* Handle branches that branch back into the block */
1911 if (targetOffset >= curBB->firstMIRInsn->offset &&
1912 targetOffset <= curBB->lastMIRInsn->offset) {
Ben Cheng00603072010-10-28 11:13:58 -07001913 newBB = dvmCompilerNewBB(kChainingCellBackwardBranch,
1914 numBlocks++);
Jeff Hao97319a82009-08-12 16:57:15 -07001915 } else {
Dan Bornsteinc2b486f2010-11-12 16:07:16 -08001916 newBB = dvmCompilerNewBB(dexIsGoto(flags) ?
Bill Buzbee1465db52009-09-23 17:17:35 -07001917 kChainingCellHot :
Ben Cheng00603072010-10-28 11:13:58 -07001918 kChainingCellNormal,
1919 numBlocks++);
Jeff Hao97319a82009-08-12 16:57:15 -07001920 }
1921 newBB->startOffset = targetOffset;
1922#endif
Ben Cheng1efc9c52009-06-08 18:25:27 -07001923 }
Ben Cheng7e2c3c72010-12-22 16:40:46 -08001924 if (newBB) {
1925 curBB->taken = newBB;
Ben Cheng7ab74e12011-02-03 14:02:06 -08001926 dvmCompilerSetBit(newBB->predecessors, curBB->id);
Ben Cheng7e2c3c72010-12-22 16:40:46 -08001927 dvmInsertGrowableList(blockList, (intptr_t) newBB);
1928 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001929 }
Ben Chengba4fc8b2009-06-01 13:00:29 -07001930 }
1931
1932 /* Now create a special block to host PC reconstruction code */
Ben Cheng00603072010-10-28 11:13:58 -07001933 curBB = dvmCompilerNewBB(kPCReconstruction, numBlocks++);
1934 dvmInsertGrowableList(blockList, (intptr_t) curBB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001935
1936 /* And one final block that publishes the PC and raise the exception */
Ben Cheng00603072010-10-28 11:13:58 -07001937 curBB = dvmCompilerNewBB(kExceptionHandling, numBlocks++);
1938 dvmInsertGrowableList(blockList, (intptr_t) curBB);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001939
1940 if (cUnit.printMe) {
Ben Cheng00603072010-10-28 11:13:58 -07001941 char* signature =
1942 dexProtoCopyMethodDescriptor(&desc->method->prototype);
Elliott Hughescc6fac82010-07-02 13:38:44 -07001943 LOGD("TRACEINFO (%d): 0x%08x %s%s.%s 0x%x %d of %d, %d blocks",
Ben Chenge9695e52009-06-16 16:11:47 -07001944 compilationId,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001945 (intptr_t) desc->method->insns,
1946 desc->method->clazz->descriptor,
1947 desc->method->name,
Elliott Hughescc6fac82010-07-02 13:38:44 -07001948 signature,
Ben Cheng385828e2011-03-04 16:48:33 -08001949 desc->trace[0].info.frag.startOffset,
Ben Chengba4fc8b2009-06-01 13:00:29 -07001950 traceSize,
1951 dexCode->insnsSize,
1952 numBlocks);
Elliott Hughescc6fac82010-07-02 13:38:44 -07001953 free(signature);
Ben Chengba4fc8b2009-06-01 13:00:29 -07001954 }
1955
Ben Chengba4fc8b2009-06-01 13:00:29 -07001956 cUnit.traceDesc = desc;
1957 cUnit.numBlocks = numBlocks;
Ben Chengba4fc8b2009-06-01 13:00:29 -07001958
Ben Cheng7a2697d2010-06-07 13:44:23 -07001959 /* Set the instruction set to use (NOTE: later components may change it) */
1960 cUnit.instructionSet = dvmCompilerInstructionSet();
1961
1962 /* Inline transformation @ the MIR level */
1963 if (cUnit.hasInvoke && !(gDvmJit.disableOpt & (1 << kMethodInlining))) {
Ben Chengcfdeca32011-01-14 11:36:46 -08001964 dvmCompilerInlineMIR(&cUnit, info);
Ben Cheng7a2697d2010-06-07 13:44:23 -07001965 }
1966
Ben Cheng00603072010-10-28 11:13:58 -07001967 cUnit.numDalvikRegisters = cUnit.method->registersSize;
1968
Ben Cheng4238ec22009-08-24 16:32:22 -07001969 /* Preparation for SSA conversion */
1970 dvmInitializeSSAConversion(&cUnit);
1971
1972 if (cUnit.hasLoop) {
Ben Cheng4a419582010-08-04 13:23:09 -07001973 /*
1974 * Loop is not optimizable (for example lack of a single induction
1975 * variable), punt and recompile the trace with loop optimization
1976 * disabled.
1977 */
1978 bool loopOpt = dvmCompilerLoopOpt(&cUnit);
1979 if (loopOpt == false) {
1980 if (cUnit.printMe) {
1981 LOGD("Loop is not optimizable - retry codegen");
1982 }
1983 /* Reset the compiler resource pool */
1984 dvmCompilerArenaReset();
1985 return dvmCompileTrace(desc, cUnit.numInsts, info, bailPtr,
1986 optHints | JIT_OPT_NO_LOOP);
1987 }
Ben Cheng4238ec22009-08-24 16:32:22 -07001988 }
1989 else {
1990 dvmCompilerNonLoopAnalysis(&cUnit);
1991 }
1992
Bill Buzbee1465db52009-09-23 17:17:35 -07001993 dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
1994
Ben Chengba4fc8b2009-06-01 13:00:29 -07001995 if (cUnit.printMe) {
1996 dvmCompilerDumpCompilationUnit(&cUnit);
1997 }
1998
buzbee23d95d02010-12-14 13:16:43 -08001999 /* Allocate Registers using simple local allocation scheme */
2000 dvmCompilerLocalRegAlloc(&cUnit);
Bill Buzbee1465db52009-09-23 17:17:35 -07002001
Ben Chengba4fc8b2009-06-01 13:00:29 -07002002 /* Convert MIR to LIR, etc. */
2003 dvmCompilerMIR2LIR(&cUnit);
2004
buzbeebff121a2010-08-04 15:25:06 -07002005 /* Convert LIR into machine code. Loop for recoverable retries */
2006 do {
2007 dvmCompilerAssembleLIR(&cUnit, info);
2008 cUnit.assemblerRetries++;
2009 if (cUnit.printMe && cUnit.assemblerStatus != kSuccess)
2010 LOGD("Assembler abort #%d on %d",cUnit.assemblerRetries,
2011 cUnit.assemblerStatus);
2012 } while (cUnit.assemblerStatus == kRetryAll);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002013
2014 if (cUnit.printMe) {
Ben Chengcfdeca32011-01-14 11:36:46 -08002015 LOGD("Trace Dalvik PC: %p", startCodePtr);
buzbeebff121a2010-08-04 15:25:06 -07002016 dvmCompilerCodegenDump(&cUnit);
Ben Cheng1efc9c52009-06-08 18:25:27 -07002017 LOGD("End %s%s, %d Dalvik instructions",
2018 desc->method->clazz->descriptor, desc->method->name,
2019 cUnit.numInsts);
Ben Chengba4fc8b2009-06-01 13:00:29 -07002020 }
2021
buzbeebff121a2010-08-04 15:25:06 -07002022 if (cUnit.assemblerStatus == kRetryHalve) {
Ben Cheng385828e2011-03-04 16:48:33 -08002023 /* Reset the compiler resource pool before retry */
2024 dvmCompilerArenaReset();
2025
buzbeebff121a2010-08-04 15:25:06 -07002026 /* Halve the instruction count and start from the top */
Ben Cheng4a419582010-08-04 13:23:09 -07002027 return dvmCompileTrace(desc, cUnit.numInsts / 2, info, bailPtr,
2028 optHints);
Ben Cheng1efc9c52009-06-08 18:25:27 -07002029 }
buzbeebff121a2010-08-04 15:25:06 -07002030
Ben Cheng385828e2011-03-04 16:48:33 -08002031 /*
2032 * If this trace uses class objects as constants,
2033 * dvmJitInstallClassObjectPointers will switch the thread state
2034 * to running and look up the class pointers using the descriptor/loader
2035 * tuple stored in the callsite info structure. We need to make this window
2036 * as short as possible since it is blocking GC.
2037 */
2038 if (cUnit.hasClassLiterals && info->codeAddress) {
2039 dvmJitInstallClassObjectPointers(&cUnit, (char *) info->codeAddress);
2040 }
2041
2042 /*
2043 * Since callsiteinfo is allocated from the arena, delay the reset until
2044 * class pointers are resolved.
2045 */
2046 dvmCompilerArenaReset();
2047
buzbeebff121a2010-08-04 15:25:06 -07002048 assert(cUnit.assemblerStatus == kSuccess);
2049#if defined(WITH_JIT_TUNING)
2050 methodStats->nativeSize += cUnit.totalSize;
2051#endif
Ben Cheng00603072010-10-28 11:13:58 -07002052
buzbeebff121a2010-08-04 15:25:06 -07002053 return info->codeAddress != NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -07002054}