blob: 4db75ad09995453c7c86cef5f2be004b997ed7b5 [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"
18#include "libdex/OpCode.h"
Ben Chengba4fc8b2009-06-01 13:00:29 -070019#include "interp/Jit.h"
20#include "CompilerInternals.h"
21
22/*
23 * Parse an instruction, return the length of the instruction
24 */
25static inline int parseInsn(const u2 *codePtr, DecodedInstruction *decInsn,
26 bool printMe)
27{
28 u2 instr = *codePtr;
29 OpCode opcode = instr & 0xff;
30 int insnWidth;
31
Ben Cheng8b258bf2009-06-24 17:27:07 -070032 // Don't parse instruction data
Ben Chengba4fc8b2009-06-01 13:00:29 -070033 if (opcode == OP_NOP && instr != 0) {
Ben Cheng8b258bf2009-06-24 17:27:07 -070034 return 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -070035 } else {
36 insnWidth = gDvm.instrWidth[opcode];
37 if (insnWidth < 0) {
38 insnWidth = -insnWidth;
39 }
40 }
41
42 dexDecodeInstruction(gDvm.instrFormat, codePtr, decInsn);
43 if (printMe) {
Ben Chengccd6c012009-10-15 14:52:45 -070044 char *decodedString = dvmCompilerGetDalvikDisassembly(decInsn);
45 LOGD("%p: %#06x %s\n", codePtr, opcode, decodedString);
Ben Chengba4fc8b2009-06-01 13:00:29 -070046 }
47 return insnWidth;
48}
49
Ben Cheng9c147b82009-10-07 16:41:46 -070050#define UNKNOWN_TARGET 0xffffffff
51
Ben Chengba4fc8b2009-06-01 13:00:29 -070052/*
53 * Identify block-ending instructions and collect supplemental information
54 * regarding the following instructions.
55 */
56static inline bool findBlockBoundary(const Method *caller, MIR *insn,
57 unsigned int curOffset,
58 unsigned int *target, bool *isInvoke,
59 const Method **callee)
60{
61 switch (insn->dalvikInsn.opCode) {
62 /* Target is not compile-time constant */
63 case OP_RETURN_VOID:
64 case OP_RETURN:
65 case OP_RETURN_WIDE:
66 case OP_RETURN_OBJECT:
67 case OP_THROW:
Ben Cheng9c147b82009-10-07 16:41:46 -070068 *target = UNKNOWN_TARGET;
69 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -070070 case OP_INVOKE_VIRTUAL:
71 case OP_INVOKE_VIRTUAL_RANGE:
72 case OP_INVOKE_INTERFACE:
73 case OP_INVOKE_INTERFACE_RANGE:
74 case OP_INVOKE_VIRTUAL_QUICK:
75 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
76 *isInvoke = true;
77 break;
78 case OP_INVOKE_SUPER:
79 case OP_INVOKE_SUPER_RANGE: {
80 int mIndex = caller->clazz->pDvmDex->
81 pResMethods[insn->dalvikInsn.vB]->methodIndex;
82 const Method *calleeMethod =
83 caller->clazz->super->vtable[mIndex];
84
Ben Cheng8b258bf2009-06-24 17:27:07 -070085 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -070086 *target = (unsigned int) calleeMethod->insns;
87 }
88 *isInvoke = true;
89 *callee = calleeMethod;
90 break;
91 }
92 case OP_INVOKE_STATIC:
93 case OP_INVOKE_STATIC_RANGE: {
94 const Method *calleeMethod =
95 caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
96
Ben Cheng8b258bf2009-06-24 17:27:07 -070097 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -070098 *target = (unsigned int) calleeMethod->insns;
99 }
100 *isInvoke = true;
101 *callee = calleeMethod;
102 break;
103 }
104 case OP_INVOKE_SUPER_QUICK:
105 case OP_INVOKE_SUPER_QUICK_RANGE: {
106 const Method *calleeMethod =
107 caller->clazz->super->vtable[insn->dalvikInsn.vB];
108
Ben Cheng8b258bf2009-06-24 17:27:07 -0700109 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700110 *target = (unsigned int) calleeMethod->insns;
111 }
112 *isInvoke = true;
113 *callee = calleeMethod;
114 break;
115 }
116 case OP_INVOKE_DIRECT:
117 case OP_INVOKE_DIRECT_RANGE: {
118 const Method *calleeMethod =
119 caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
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_GOTO:
128 case OP_GOTO_16:
129 case OP_GOTO_32:
130 *target = curOffset + (int) insn->dalvikInsn.vA;
131 break;
132
133 case OP_IF_EQ:
134 case OP_IF_NE:
135 case OP_IF_LT:
136 case OP_IF_GE:
137 case OP_IF_GT:
138 case OP_IF_LE:
139 *target = curOffset + (int) insn->dalvikInsn.vC;
140 break;
141
142 case OP_IF_EQZ:
143 case OP_IF_NEZ:
144 case OP_IF_LTZ:
145 case OP_IF_GEZ:
146 case OP_IF_GTZ:
147 case OP_IF_LEZ:
148 *target = curOffset + (int) insn->dalvikInsn.vB;
149 break;
150
151 default:
152 return false;
Ben Cheng9c147b82009-10-07 16:41:46 -0700153 }
154 return true;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700155}
156
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800157static inline bool isGoto(MIR *insn)
158{
159 switch (insn->dalvikInsn.opCode) {
160 case OP_GOTO:
161 case OP_GOTO_16:
162 case OP_GOTO_32:
163 return true;
164 default:
165 return false;
166 }
167}
168
Ben Chengba4fc8b2009-06-01 13:00:29 -0700169/*
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800170 * Identify unconditional branch instructions
Ben Chengba4fc8b2009-06-01 13:00:29 -0700171 */
172static inline bool isUnconditionalBranch(MIR *insn)
173{
174 switch (insn->dalvikInsn.opCode) {
175 case OP_RETURN_VOID:
176 case OP_RETURN:
177 case OP_RETURN_WIDE:
178 case OP_RETURN_OBJECT:
Ben Chengba4fc8b2009-06-01 13:00:29 -0700179 return true;
180 default:
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800181 return isGoto(insn);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700182 }
183}
184
185/*
Ben Cheng8b258bf2009-06-24 17:27:07 -0700186 * dvmHashTableLookup() callback
187 */
Carl Shapiroe3c01da2010-05-20 22:54:18 -0700188#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700189static int compareMethod(const CompilerMethodStats *m1,
190 const CompilerMethodStats *m2)
191{
192 return (int) m1->method - (int) m2->method;
193}
194
195/*
196 * Analyze each method whose traces are ever compiled. Collect a variety of
197 * statistics like the ratio of exercised vs overall code and code bloat
198 * ratios.
199 */
200static CompilerMethodStats *analyzeMethodBody(const Method *method)
201{
202 const DexCode *dexCode = dvmGetMethodCode(method);
203 const u2 *codePtr = dexCode->insns;
204 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
205 int insnSize = 0;
206 int hashValue = dvmComputeUtf8Hash(method->name);
207
208 CompilerMethodStats dummyMethodEntry; // For hash table lookup
209 CompilerMethodStats *realMethodEntry; // For hash table storage
210
211 /* For lookup only */
212 dummyMethodEntry.method = method;
213 realMethodEntry = dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
214 &dummyMethodEntry,
215 (HashCompareFunc) compareMethod,
216 false);
217
218 /* Part of this method has been compiled before - just return the entry */
219 if (realMethodEntry != NULL) {
220 return realMethodEntry;
221 }
222
223 /*
224 * First time to compile this method - set up a new entry in the hash table
225 */
226 realMethodEntry =
227 (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
228 realMethodEntry->method = method;
229
230 dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
231 realMethodEntry,
232 (HashCompareFunc) compareMethod,
233 true);
234
235 /* Count the number of instructions */
236 while (codePtr < codeEnd) {
237 DecodedInstruction dalvikInsn;
238 int width = parseInsn(codePtr, &dalvikInsn, false);
239
240 /* Terminate when the data section is seen */
241 if (width == 0)
242 break;
243
244 insnSize += width;
245 codePtr += width;
246 }
247
248 realMethodEntry->dalvikSize = insnSize * 2;
249 return realMethodEntry;
250}
Ben Cheng1357e942010-02-10 17:21:39 -0800251#endif
Ben Cheng8b258bf2009-06-24 17:27:07 -0700252
253/*
Ben Cheng33672452010-01-12 14:59:30 -0800254 * Crawl the stack of the thread that requesed compilation to see if any of the
255 * ancestors are on the blacklist.
256 */
257bool filterMethodByCallGraph(Thread *thread, const char *curMethodName)
258{
259 /* Crawl the Dalvik stack frames and compare the method name*/
260 StackSaveArea *ssaPtr = ((StackSaveArea *) thread->curFrame) - 1;
261 while (ssaPtr != ((StackSaveArea *) NULL) - 1) {
262 const Method *method = ssaPtr->method;
263 if (method) {
264 int hashValue = dvmComputeUtf8Hash(method->name);
265 bool found =
266 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
267 (char *) method->name,
268 (HashCompareFunc) strcmp, false) !=
269 NULL;
270 if (found) {
271 LOGD("Method %s (--> %s) found on the JIT %s list",
272 method->name, curMethodName,
273 gDvmJit.includeSelectedMethod ? "white" : "black");
274 return true;
275 }
276
277 }
278 ssaPtr = ((StackSaveArea *) ssaPtr->prevFrame) - 1;
279 };
280 return false;
281}
282
283/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700284 * Main entry point to start trace compilation. Basic blocks are constructed
285 * first and they will be passed to the codegen routines to convert Dalvik
286 * bytecode into machine code.
287 */
Bill Buzbee716f1202009-07-23 13:22:09 -0700288bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800289 JitTranslationInfo *info, jmp_buf *bailPtr)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700290{
291 const DexCode *dexCode = dvmGetMethodCode(desc->method);
292 const JitTraceRun* currRun = &desc->trace[0];
Ben Chengba4fc8b2009-06-01 13:00:29 -0700293 unsigned int curOffset = currRun->frag.startOffset;
294 unsigned int numInsts = currRun->frag.numInsts;
295 const u2 *codePtr = dexCode->insns + curOffset;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700296 int traceSize = 0; // # of half-words
Ben Chengba4fc8b2009-06-01 13:00:29 -0700297 const u2 *startCodePtr = codePtr;
298 BasicBlock *startBB, *curBB, *lastBB;
299 int numBlocks = 0;
300 static int compilationId;
301 CompilationUnit cUnit;
Ben Cheng1357e942010-02-10 17:21:39 -0800302#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700303 CompilerMethodStats *methodStats;
Ben Cheng1357e942010-02-10 17:21:39 -0800304#endif
Ben Chengba4fc8b2009-06-01 13:00:29 -0700305
Bill Buzbee964a7b02010-01-28 12:54:19 -0800306 /* If we've already compiled this trace, just return success */
jeffhao9e45c0b2010-02-03 10:24:05 -0800307 if (dvmJitGetCodeAddr(startCodePtr) && !info->discardResult) {
Bill Buzbee964a7b02010-01-28 12:54:19 -0800308 return true;
309 }
310
Ben Chenge9695e52009-06-16 16:11:47 -0700311 compilationId++;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700312 memset(&cUnit, 0, sizeof(CompilationUnit));
313
Ben Cheng1357e942010-02-10 17:21:39 -0800314#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700315 /* Locate the entry to store compilation statistics for this method */
316 methodStats = analyzeMethodBody(desc->method);
Ben Cheng1357e942010-02-10 17:21:39 -0800317#endif
Ben Chenge9695e52009-06-16 16:11:47 -0700318
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800319 /* Set the recover buffer pointer */
320 cUnit.bailPtr = bailPtr;
321
Ben Chengba4fc8b2009-06-01 13:00:29 -0700322 /* Initialize the printMe flag */
323 cUnit.printMe = gDvmJit.printMe;
324
Bill Buzbee6e963e12009-06-17 16:56:19 -0700325 /* Initialize the profile flag */
326 cUnit.executionCount = gDvmJit.profile;
327
Ben Chengba4fc8b2009-06-01 13:00:29 -0700328 /* Identify traces that we don't want to compile */
329 if (gDvmJit.methodTable) {
330 int len = strlen(desc->method->clazz->descriptor) +
331 strlen(desc->method->name) + 1;
332 char *fullSignature = dvmCompilerNew(len, true);
333 strcpy(fullSignature, desc->method->clazz->descriptor);
334 strcat(fullSignature, desc->method->name);
335
336 int hashValue = dvmComputeUtf8Hash(fullSignature);
337
338 /*
339 * Doing three levels of screening to see whether we want to skip
340 * compiling this method
341 */
342
343 /* First, check the full "class;method" signature */
344 bool methodFound =
345 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
346 fullSignature, (HashCompareFunc) strcmp,
347 false) !=
348 NULL;
349
350 /* Full signature not found - check the enclosing class */
351 if (methodFound == false) {
352 int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
353 methodFound =
354 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
355 (char *) desc->method->clazz->descriptor,
356 (HashCompareFunc) strcmp, false) !=
357 NULL;
358 /* Enclosing class not found - check the method name */
359 if (methodFound == false) {
360 int hashValue = dvmComputeUtf8Hash(desc->method->name);
361 methodFound =
362 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
363 (char *) desc->method->name,
364 (HashCompareFunc) strcmp, false) !=
365 NULL;
Ben Cheng33672452010-01-12 14:59:30 -0800366
367 /*
368 * Debug by call-graph is enabled. Check if the debug list
369 * covers any methods on the VM stack.
370 */
371 if (methodFound == false && gDvmJit.checkCallGraph == true) {
372 methodFound =
373 filterMethodByCallGraph(info->requestingThread,
374 desc->method->name);
375 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700376 }
377 }
378
379 /*
380 * Under the following conditions, the trace will be *conservatively*
381 * compiled by only containing single-step instructions to and from the
382 * interpreter.
383 * 1) If includeSelectedMethod == false, the method matches the full or
384 * partial signature stored in the hash table.
385 *
386 * 2) If includeSelectedMethod == true, the method does not match the
387 * full and partial signature stored in the hash table.
388 */
389 if (gDvmJit.includeSelectedMethod != methodFound) {
390 cUnit.allSingleStep = true;
391 } else {
392 /* Compile the trace as normal */
393
394 /* Print the method we cherry picked */
395 if (gDvmJit.includeSelectedMethod == true) {
396 cUnit.printMe = true;
397 }
398 }
399 }
400
Ben Cheng4238ec22009-08-24 16:32:22 -0700401 /* Allocate the entry block */
Bill Buzbee1465db52009-09-23 17:17:35 -0700402 lastBB = startBB = curBB = dvmCompilerNewBB(kEntryBlock);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700403 curBB->startOffset = curOffset;
404 curBB->id = numBlocks++;
405
Bill Buzbee1465db52009-09-23 17:17:35 -0700406 curBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Cheng4238ec22009-08-24 16:32:22 -0700407 curBB->startOffset = curOffset;
408 curBB->id = numBlocks++;
409
410 /* Make the first real dalvik block the fallthrough of the entry block */
411 startBB->fallThrough = curBB;
412 lastBB->next = curBB;
413 lastBB = curBB;
414
Ben Chengba4fc8b2009-06-01 13:00:29 -0700415 if (cUnit.printMe) {
416 LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n",
417 desc->method->name, curOffset);
418 }
419
Ben Cheng1efc9c52009-06-08 18:25:27 -0700420 /*
421 * Analyze the trace descriptor and include up to the maximal number
422 * of Dalvik instructions into the IR.
423 */
424 while (1) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700425 MIR *insn;
426 int width;
Ben Cheng4238ec22009-08-24 16:32:22 -0700427 insn = dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700428 insn->offset = curOffset;
429 width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700430
431 /* The trace should never incude instruction data */
432 assert(width);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700433 insn->width = width;
434 traceSize += width;
435 dvmCompilerAppendMIR(curBB, insn);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700436 cUnit.numInsts++;
437 /* Instruction limit reached - terminate the trace here */
438 if (cUnit.numInsts >= numMaxInsts) {
439 break;
440 }
441 if (--numInsts == 0) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700442 if (currRun->frag.runEnd) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700443 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700444 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700445 curBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700446 lastBB->next = curBB;
447 lastBB = curBB;
448 curBB->id = numBlocks++;
449 currRun++;
450 curOffset = currRun->frag.startOffset;
451 numInsts = currRun->frag.numInsts;
452 curBB->startOffset = curOffset;
453 codePtr = dexCode->insns + curOffset;
454 }
455 } else {
456 curOffset += width;
457 codePtr += width;
458 }
459 }
460
Ben Cheng1357e942010-02-10 17:21:39 -0800461#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700462 /* Convert # of half-word to bytes */
463 methodStats->compiledDalvikSize += traceSize * 2;
Ben Cheng1357e942010-02-10 17:21:39 -0800464#endif
Ben Cheng8b258bf2009-06-24 17:27:07 -0700465
Ben Chengba4fc8b2009-06-01 13:00:29 -0700466 /*
467 * Now scan basic blocks containing real code to connect the
468 * taken/fallthrough links. Also create chaining cells for code not included
469 * in the trace.
470 */
471 for (curBB = startBB; curBB; curBB = curBB->next) {
472 MIR *lastInsn = curBB->lastMIRInsn;
Ben Cheng4238ec22009-08-24 16:32:22 -0700473 /* Skip empty blocks */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700474 if (lastInsn == NULL) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700475 continue;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700476 }
477 curOffset = lastInsn->offset;
478 unsigned int targetOffset = curOffset;
479 unsigned int fallThroughOffset = curOffset + lastInsn->width;
480 bool isInvoke = false;
481 const Method *callee = NULL;
482
483 findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
484 &targetOffset, &isInvoke, &callee);
485
486 /* Link the taken and fallthrough blocks */
487 BasicBlock *searchBB;
488
489 /* No backward branch in the trace - start searching the next BB */
490 for (searchBB = curBB->next; searchBB; searchBB = searchBB->next) {
491 if (targetOffset == searchBB->startOffset) {
492 curBB->taken = searchBB;
493 }
494 if (fallThroughOffset == searchBB->startOffset) {
495 curBB->fallThrough = searchBB;
496 }
497 }
498
Ben Cheng1efc9c52009-06-08 18:25:27 -0700499 int flags = dexGetInstrFlags(gDvm.instrFlags,
500 lastInsn->dalvikInsn.opCode);
501
502 /*
503 * Some blocks are ended by non-control-flow-change instructions,
504 * currently only due to trace length constraint. In this case we need
505 * to generate an explicit branch at the end of the block to jump to
506 * the chaining cell.
Ben Cheng17f15ce2009-07-27 16:21:52 -0700507 *
508 * NOTE: INVOKE_DIRECT_EMPTY is actually not an invoke but a nop
Ben Cheng1efc9c52009-06-08 18:25:27 -0700509 */
510 curBB->needFallThroughBranch =
Ben Cheng17f15ce2009-07-27 16:21:52 -0700511 ((flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
512 kInstrInvoke)) == 0) ||
513 (lastInsn->dalvikInsn.opCode == OP_INVOKE_DIRECT_EMPTY);
514
Ben Cheng4238ec22009-08-24 16:32:22 -0700515 if (curBB->taken == NULL &&
516 curBB->fallThrough == NULL &&
517 flags == (kInstrCanBranch | kInstrCanContinue) &&
518 fallThroughOffset == startBB->startOffset) {
Ben Cheng0fd31e42009-09-03 14:40:16 -0700519 BasicBlock *loopBranch = curBB;
520 BasicBlock *exitBB;
521 BasicBlock *exitChainingCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700522
523 if (cUnit.printMe) {
524 LOGD("Natural loop detected!");
525 }
Bill Buzbee1465db52009-09-23 17:17:35 -0700526 exitBB = dvmCompilerNewBB(kExitBlock);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700527 lastBB->next = exitBB;
528 lastBB = exitBB;
Ben Cheng4238ec22009-08-24 16:32:22 -0700529
Ben Cheng0fd31e42009-09-03 14:40:16 -0700530 exitBB->startOffset = targetOffset;
531 exitBB->id = numBlocks++;
532 exitBB->needFallThroughBranch = true;
Ben Cheng4238ec22009-08-24 16:32:22 -0700533
Ben Cheng0fd31e42009-09-03 14:40:16 -0700534 loopBranch->taken = exitBB;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700535#if defined(WITH_SELF_VERIFICATION)
Ben Cheng0fd31e42009-09-03 14:40:16 -0700536 BasicBlock *backwardCell =
Bill Buzbee1465db52009-09-23 17:17:35 -0700537 dvmCompilerNewBB(kChainingCellBackwardBranch);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700538 lastBB->next = backwardCell;
539 lastBB = backwardCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700540
Ben Cheng0fd31e42009-09-03 14:40:16 -0700541 backwardCell->startOffset = startBB->startOffset;
542 backwardCell->id = numBlocks++;
543 loopBranch->fallThrough = backwardCell;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700544#elif defined(WITH_JIT_TUNING)
545 if (gDvmJit.profile) {
546 BasicBlock *backwardCell =
Bill Buzbee1465db52009-09-23 17:17:35 -0700547 dvmCompilerNewBB(kChainingCellBackwardBranch);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700548 lastBB->next = backwardCell;
549 lastBB = backwardCell;
550
551 backwardCell->startOffset = startBB->startOffset;
552 backwardCell->id = numBlocks++;
553 loopBranch->fallThrough = backwardCell;
554 } else {
555 loopBranch->fallThrough = startBB->next;
556 }
557#else
558 loopBranch->fallThrough = startBB->next;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700559#endif
560
561 /* Create the chaining cell as the fallthrough of the exit block */
Bill Buzbee1465db52009-09-23 17:17:35 -0700562 exitChainingCell = dvmCompilerNewBB(kChainingCellNormal);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700563 lastBB->next = exitChainingCell;
564 lastBB = exitChainingCell;
565
566 exitChainingCell->startOffset = targetOffset;
567 exitChainingCell->id = numBlocks++;
568
569 exitBB->fallThrough = exitChainingCell;
570
Ben Cheng4238ec22009-08-24 16:32:22 -0700571 cUnit.hasLoop = true;
572 }
573
Ben Cheng6c10a972009-10-29 14:39:18 -0700574 if (lastInsn->dalvikInsn.opCode == OP_PACKED_SWITCH ||
575 lastInsn->dalvikInsn.opCode == OP_SPARSE_SWITCH) {
576 int i;
577 const u2 *switchData = desc->method->insns + lastInsn->offset +
578 lastInsn->dalvikInsn.vB;
579 int size = switchData[1];
580 int maxChains = MIN(size, MAX_CHAINED_SWITCH_CASES);
581
582 /*
583 * Generate the landing pad for cases whose ranks are higher than
584 * MAX_CHAINED_SWITCH_CASES. The code will re-enter the interpreter
585 * through the NoChain point.
586 */
587 if (maxChains != size) {
588 cUnit.switchOverflowPad =
589 desc->method->insns + lastInsn->offset;
590 }
591
592 s4 *targets = (s4 *) (switchData + 2 +
593 (lastInsn->dalvikInsn.opCode == OP_PACKED_SWITCH ?
594 2 : size * 2));
595
596 /* One chaining cell for the first MAX_CHAINED_SWITCH_CASES cases */
597 for (i = 0; i < maxChains; i++) {
598 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal);
599 lastBB->next = caseChain;
600 lastBB = caseChain;
601
602 caseChain->startOffset = lastInsn->offset + targets[i];
603 caseChain->id = numBlocks++;
604 }
605
606 /* One more chaining cell for the default case */
607 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal);
608 lastBB->next = caseChain;
609 lastBB = caseChain;
610
611 caseChain->startOffset = lastInsn->offset + lastInsn->width;
612 caseChain->id = numBlocks++;
Ben Cheng6d576092009-09-01 17:01:58 -0700613 /* Fallthrough block not included in the trace */
Ben Cheng6c10a972009-10-29 14:39:18 -0700614 } else if (!isUnconditionalBranch(lastInsn) &&
615 curBB->fallThrough == NULL) {
Ben Cheng6d576092009-09-01 17:01:58 -0700616 /*
617 * If the chaining cell is after an invoke or
618 * instruction that cannot change the control flow, request a hot
619 * chaining cell.
620 */
621 if (isInvoke || curBB->needFallThroughBranch) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700622 lastBB->next = dvmCompilerNewBB(kChainingCellHot);
Ben Cheng6d576092009-09-01 17:01:58 -0700623 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700624 lastBB->next = dvmCompilerNewBB(kChainingCellNormal);
Ben Cheng6d576092009-09-01 17:01:58 -0700625 }
626 lastBB = lastBB->next;
627 lastBB->id = numBlocks++;
628 lastBB->startOffset = fallThroughOffset;
629 curBB->fallThrough = lastBB;
630 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700631 /* Target block not included in the trace */
Ben Cheng38329f52009-07-07 14:19:20 -0700632 if (curBB->taken == NULL &&
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800633 (isGoto(lastInsn) || isInvoke ||
634 (targetOffset != UNKNOWN_TARGET && targetOffset != curOffset))) {
Ben Cheng38329f52009-07-07 14:19:20 -0700635 BasicBlock *newBB;
Ben Cheng1efc9c52009-06-08 18:25:27 -0700636 if (isInvoke) {
Ben Cheng38329f52009-07-07 14:19:20 -0700637 /* Monomorphic callee */
638 if (callee) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700639 newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton);
Ben Cheng38329f52009-07-07 14:19:20 -0700640 newBB->startOffset = 0;
641 newBB->containingMethod = callee;
642 /* Will resolve at runtime */
643 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700644 newBB = dvmCompilerNewBB(kChainingCellInvokePredicted);
Ben Cheng38329f52009-07-07 14:19:20 -0700645 newBB->startOffset = 0;
646 }
Ben Cheng1efc9c52009-06-08 18:25:27 -0700647 /* For unconditional branches, request a hot chaining cell */
648 } else {
Jeff Hao97319a82009-08-12 16:57:15 -0700649#if !defined(WITH_SELF_VERIFICATION)
Ben Cheng38329f52009-07-07 14:19:20 -0700650 newBB = dvmCompilerNewBB(flags & kInstrUnconditional ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700651 kChainingCellHot :
652 kChainingCellNormal);
Ben Cheng38329f52009-07-07 14:19:20 -0700653 newBB->startOffset = targetOffset;
Jeff Hao97319a82009-08-12 16:57:15 -0700654#else
655 /* Handle branches that branch back into the block */
656 if (targetOffset >= curBB->firstMIRInsn->offset &&
657 targetOffset <= curBB->lastMIRInsn->offset) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700658 newBB = dvmCompilerNewBB(kChainingCellBackwardBranch);
Jeff Hao97319a82009-08-12 16:57:15 -0700659 } else {
660 newBB = dvmCompilerNewBB(flags & kInstrUnconditional ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700661 kChainingCellHot :
662 kChainingCellNormal);
Jeff Hao97319a82009-08-12 16:57:15 -0700663 }
664 newBB->startOffset = targetOffset;
665#endif
Ben Cheng1efc9c52009-06-08 18:25:27 -0700666 }
Ben Cheng38329f52009-07-07 14:19:20 -0700667 newBB->id = numBlocks++;
668 curBB->taken = newBB;
669 lastBB->next = newBB;
670 lastBB = newBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700671 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700672 }
673
674 /* Now create a special block to host PC reconstruction code */
Bill Buzbee1465db52009-09-23 17:17:35 -0700675 lastBB->next = dvmCompilerNewBB(kPCReconstruction);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700676 lastBB = lastBB->next;
677 lastBB->id = numBlocks++;
678
679 /* And one final block that publishes the PC and raise the exception */
Bill Buzbee1465db52009-09-23 17:17:35 -0700680 lastBB->next = dvmCompilerNewBB(kExceptionHandling);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700681 lastBB = lastBB->next;
682 lastBB->id = numBlocks++;
683
684 if (cUnit.printMe) {
Elliott Hughescc6fac82010-07-02 13:38:44 -0700685 char* signature = dexProtoCopyMethodDescriptor(&desc->method->prototype);
686 LOGD("TRACEINFO (%d): 0x%08x %s%s.%s 0x%x %d of %d, %d blocks",
Ben Chenge9695e52009-06-16 16:11:47 -0700687 compilationId,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700688 (intptr_t) desc->method->insns,
689 desc->method->clazz->descriptor,
690 desc->method->name,
Elliott Hughescc6fac82010-07-02 13:38:44 -0700691 signature,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700692 desc->trace[0].frag.startOffset,
693 traceSize,
694 dexCode->insnsSize,
695 numBlocks);
Elliott Hughescc6fac82010-07-02 13:38:44 -0700696 free(signature);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700697 }
698
699 BasicBlock **blockList;
700
701 cUnit.method = desc->method;
702 cUnit.traceDesc = desc;
703 cUnit.numBlocks = numBlocks;
704 dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
705 blockList = cUnit.blockList =
706 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
707
708 int i;
709
710 for (i = 0, curBB = startBB; i < numBlocks; i++) {
711 blockList[i] = curBB;
712 curBB = curBB->next;
713 }
714 /* Make sure all blocks are added to the cUnit */
715 assert(curBB == NULL);
716
Ben Cheng4238ec22009-08-24 16:32:22 -0700717 /* Preparation for SSA conversion */
718 dvmInitializeSSAConversion(&cUnit);
719
Bill Buzbee1465db52009-09-23 17:17:35 -0700720
Ben Cheng4238ec22009-08-24 16:32:22 -0700721 if (cUnit.hasLoop) {
722 dvmCompilerLoopOpt(&cUnit);
723 }
724 else {
725 dvmCompilerNonLoopAnalysis(&cUnit);
726 }
727
Bill Buzbee1465db52009-09-23 17:17:35 -0700728 dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
729
Ben Chengba4fc8b2009-06-01 13:00:29 -0700730 if (cUnit.printMe) {
731 dvmCompilerDumpCompilationUnit(&cUnit);
732 }
733
Bill Buzbee716f1202009-07-23 13:22:09 -0700734 /* Set the instruction set to use (NOTE: later components may change it) */
Ben Cheng5d90c202009-11-22 23:31:11 -0800735 cUnit.instructionSet = dvmCompilerInstructionSet();
Bill Buzbee716f1202009-07-23 13:22:09 -0700736
Bill Buzbee1465db52009-09-23 17:17:35 -0700737 /* Allocate Registers */
738 dvmCompilerRegAlloc(&cUnit);
739
Ben Chengba4fc8b2009-06-01 13:00:29 -0700740 /* Convert MIR to LIR, etc. */
741 dvmCompilerMIR2LIR(&cUnit);
742
Ben Cheng1efc9c52009-06-08 18:25:27 -0700743 /* Convert LIR into machine code. */
Bill Buzbee716f1202009-07-23 13:22:09 -0700744 dvmCompilerAssembleLIR(&cUnit, info);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700745
746 if (cUnit.printMe) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700747 if (cUnit.halveInstCount) {
748 LOGD("Assembler aborted");
749 } else {
750 dvmCompilerCodegenDump(&cUnit);
751 }
752 LOGD("End %s%s, %d Dalvik instructions",
753 desc->method->clazz->descriptor, desc->method->name,
754 cUnit.numInsts);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700755 }
756
757 /* Reset the compiler resource pool */
758 dvmCompilerArenaReset();
759
Bill Buzbee716f1202009-07-23 13:22:09 -0700760 /* Success */
Ben Cheng4238ec22009-08-24 16:32:22 -0700761 if (!cUnit.halveInstCount) {
Ben Cheng1357e942010-02-10 17:21:39 -0800762#if defined(WITH_JIT_TUNING)
Ben Cheng8b258bf2009-06-24 17:27:07 -0700763 methodStats->nativeSize += cUnit.totalSize;
Ben Cheng1357e942010-02-10 17:21:39 -0800764#endif
Bill Buzbee716f1202009-07-23 13:22:09 -0700765 return info->codeAddress != NULL;
Ben Cheng1efc9c52009-06-08 18:25:27 -0700766
767 /* Halve the instruction count and retry again */
768 } else {
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800769 return dvmCompileTrace(desc, cUnit.numInsts / 2, info, bailPtr);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700770 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700771}
772
773/*
774 * Similar to dvmCompileTrace, but the entity processed here is the whole
775 * method.
776 *
777 * TODO: implementation will be revisited when the trace builder can provide
778 * whole-method traces.
779 */
Bill Buzbee716f1202009-07-23 13:22:09 -0700780bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700781{
782 const DexCode *dexCode = dvmGetMethodCode(method);
783 const u2 *codePtr = dexCode->insns;
784 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
785 int blockID = 0;
786 unsigned int curOffset = 0;
787
Bill Buzbee1465db52009-09-23 17:17:35 -0700788 BasicBlock *firstBlock = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700789 firstBlock->id = blockID++;
790
791 /* Allocate the bit-vector to track the beginning of basic blocks */
Ben Cheng4238ec22009-08-24 16:32:22 -0700792 BitVector *bbStartAddr = dvmCompilerAllocBitVector(dexCode->insnsSize+1,
793 false);
794 dvmCompilerSetBit(bbStartAddr, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700795
796 /*
797 * Sequentially go through every instruction first and put them in a single
798 * basic block. Identify block boundaries at the mean time.
799 */
800 while (codePtr < codeEnd) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700801 MIR *insn = dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700802 insn->offset = curOffset;
803 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
804 bool isInvoke = false;
805 const Method *callee;
806 insn->width = width;
807
Ben Cheng8b258bf2009-06-24 17:27:07 -0700808 /* Terminate when the data section is seen */
809 if (width == 0)
810 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700811 dvmCompilerAppendMIR(firstBlock, insn);
812 /*
813 * Check whether this is a block ending instruction and whether it
814 * suggests the start of a new block
815 */
816 unsigned int target = curOffset;
817
818 /*
819 * If findBlockBoundary returns true, it means the current instruction
820 * is terminating the current block. If it is a branch, the target
821 * address will be recorded in target.
822 */
823 if (findBlockBoundary(method, insn, curOffset, &target, &isInvoke,
824 &callee)) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700825 dvmCompilerSetBit(bbStartAddr, curOffset + width);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700826 if (target != curOffset) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700827 dvmCompilerSetBit(bbStartAddr, target);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700828 }
829 }
830
831 codePtr += width;
832 /* each bit represents 16-bit quantity */
833 curOffset += width;
834 }
835
836 /*
837 * The number of blocks will be equal to the number of bits set to 1 in the
838 * bit vector minus 1, because the bit representing the location after the
839 * last instruction is set to one.
840 */
841 int numBlocks = dvmCountSetBits(bbStartAddr);
842 if (dvmIsBitSet(bbStartAddr, dexCode->insnsSize)) {
843 numBlocks--;
844 }
845
846 CompilationUnit cUnit;
847 BasicBlock **blockList;
848
849 memset(&cUnit, 0, sizeof(CompilationUnit));
850 cUnit.method = method;
851 blockList = cUnit.blockList =
852 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
853
854 /*
855 * Register the first block onto the list and start split it into block
856 * boundaries from there.
857 */
858 blockList[0] = firstBlock;
859 cUnit.numBlocks = 1;
860
861 int i;
862 for (i = 0; i < numBlocks; i++) {
863 MIR *insn;
864 BasicBlock *curBB = blockList[i];
865 curOffset = curBB->lastMIRInsn->offset;
866
867 for (insn = curBB->firstMIRInsn->next; insn; insn = insn->next) {
868 /* Found the beginning of a new block, see if it is created yet */
869 if (dvmIsBitSet(bbStartAddr, insn->offset)) {
870 int j;
871 for (j = 0; j < cUnit.numBlocks; j++) {
872 if (blockList[j]->firstMIRInsn->offset == insn->offset)
873 break;
874 }
875
876 /* Block not split yet - do it now */
877 if (j == cUnit.numBlocks) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700878 BasicBlock *newBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700879 newBB->id = blockID++;
880 newBB->firstMIRInsn = insn;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700881 newBB->startOffset = insn->offset;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700882 newBB->lastMIRInsn = curBB->lastMIRInsn;
883 curBB->lastMIRInsn = insn->prev;
884 insn->prev->next = NULL;
885 insn->prev = NULL;
886
887 /*
888 * If the insn is not an unconditional branch, set up the
889 * fallthrough link.
890 */
891 if (!isUnconditionalBranch(curBB->lastMIRInsn)) {
892 curBB->fallThrough = newBB;
893 }
894
895 /* enqueue the new block */
896 blockList[cUnit.numBlocks++] = newBB;
897 break;
898 }
899 }
900 }
901 }
902
903 if (numBlocks != cUnit.numBlocks) {
904 LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit.numBlocks);
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800905 dvmCompilerAbort(&cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700906 }
907
Ben Chengba4fc8b2009-06-01 13:00:29 -0700908 /* Connect the basic blocks through the taken links */
909 for (i = 0; i < numBlocks; i++) {
910 BasicBlock *curBB = blockList[i];
911 MIR *insn = curBB->lastMIRInsn;
912 unsigned int target = insn->offset;
913 bool isInvoke;
914 const Method *callee;
915
916 findBlockBoundary(method, insn, target, &target, &isInvoke, &callee);
917
918 /* Found a block ended on a branch */
919 if (target != insn->offset) {
920 int j;
921 /* Forward branch */
922 if (target > insn->offset) {
923 j = i + 1;
924 } else {
925 /* Backward branch */
926 j = 0;
927 }
928 for (; j < numBlocks; j++) {
929 if (blockList[j]->firstMIRInsn->offset == target) {
930 curBB->taken = blockList[j];
931 break;
932 }
933 }
934
Ben Cheng8b258bf2009-06-24 17:27:07 -0700935 /* Don't create dummy block for the callee yet */
936 if (j == numBlocks && !isInvoke) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700937 LOGE("Target not found for insn %x: expect target %x\n",
938 curBB->lastMIRInsn->offset, target);
Bill Buzbeefc519dc2010-03-06 23:30:57 -0800939 dvmCompilerAbort(&cUnit);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700940 }
941 }
942 }
943
Bill Buzbee716f1202009-07-23 13:22:09 -0700944 /* Set the instruction set to use (NOTE: later components may change it) */
Ben Cheng5d90c202009-11-22 23:31:11 -0800945 cUnit.instructionSet = dvmCompilerInstructionSet();
Bill Buzbee716f1202009-07-23 13:22:09 -0700946
Ben Chengba4fc8b2009-06-01 13:00:29 -0700947 dvmCompilerMIR2LIR(&cUnit);
948
Bill Buzbee716f1202009-07-23 13:22:09 -0700949 dvmCompilerAssembleLIR(&cUnit, info);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700950
951 dvmCompilerDumpCompilationUnit(&cUnit);
952
953 dvmCompilerArenaReset();
954
Bill Buzbee716f1202009-07-23 13:22:09 -0700955 return info->codeAddress != NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700956}