blob: 12eb9a7d562d90846c44fad1655481d6cc63f2c1 [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 */
188static int compareMethod(const CompilerMethodStats *m1,
189 const CompilerMethodStats *m2)
190{
191 return (int) m1->method - (int) m2->method;
192}
193
194/*
195 * Analyze each method whose traces are ever compiled. Collect a variety of
196 * statistics like the ratio of exercised vs overall code and code bloat
197 * ratios.
198 */
199static CompilerMethodStats *analyzeMethodBody(const Method *method)
200{
201 const DexCode *dexCode = dvmGetMethodCode(method);
202 const u2 *codePtr = dexCode->insns;
203 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
204 int insnSize = 0;
205 int hashValue = dvmComputeUtf8Hash(method->name);
206
207 CompilerMethodStats dummyMethodEntry; // For hash table lookup
208 CompilerMethodStats *realMethodEntry; // For hash table storage
209
210 /* For lookup only */
211 dummyMethodEntry.method = method;
212 realMethodEntry = dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
213 &dummyMethodEntry,
214 (HashCompareFunc) compareMethod,
215 false);
216
217 /* Part of this method has been compiled before - just return the entry */
218 if (realMethodEntry != NULL) {
219 return realMethodEntry;
220 }
221
222 /*
223 * First time to compile this method - set up a new entry in the hash table
224 */
225 realMethodEntry =
226 (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
227 realMethodEntry->method = method;
228
229 dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
230 realMethodEntry,
231 (HashCompareFunc) compareMethod,
232 true);
233
234 /* Count the number of instructions */
235 while (codePtr < codeEnd) {
236 DecodedInstruction dalvikInsn;
237 int width = parseInsn(codePtr, &dalvikInsn, false);
238
239 /* Terminate when the data section is seen */
240 if (width == 0)
241 break;
242
243 insnSize += width;
244 codePtr += width;
245 }
246
247 realMethodEntry->dalvikSize = insnSize * 2;
248 return realMethodEntry;
249}
250
251/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700252 * Main entry point to start trace compilation. Basic blocks are constructed
253 * first and they will be passed to the codegen routines to convert Dalvik
254 * bytecode into machine code.
255 */
Bill Buzbee716f1202009-07-23 13:22:09 -0700256bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
257 JitTranslationInfo *info)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700258{
259 const DexCode *dexCode = dvmGetMethodCode(desc->method);
260 const JitTraceRun* currRun = &desc->trace[0];
Ben Chengba4fc8b2009-06-01 13:00:29 -0700261 unsigned int curOffset = currRun->frag.startOffset;
262 unsigned int numInsts = currRun->frag.numInsts;
263 const u2 *codePtr = dexCode->insns + curOffset;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700264 int traceSize = 0; // # of half-words
Ben Chengba4fc8b2009-06-01 13:00:29 -0700265 const u2 *startCodePtr = codePtr;
266 BasicBlock *startBB, *curBB, *lastBB;
267 int numBlocks = 0;
268 static int compilationId;
269 CompilationUnit cUnit;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700270 CompilerMethodStats *methodStats;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700271
Ben Chenge9695e52009-06-16 16:11:47 -0700272 compilationId++;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700273 memset(&cUnit, 0, sizeof(CompilationUnit));
274
275 /* Locate the entry to store compilation statistics for this method */
276 methodStats = analyzeMethodBody(desc->method);
Ben Chenge9695e52009-06-16 16:11:47 -0700277
Ben Chengba4fc8b2009-06-01 13:00:29 -0700278 /* Initialize the printMe flag */
279 cUnit.printMe = gDvmJit.printMe;
280
Bill Buzbee6e963e12009-06-17 16:56:19 -0700281 /* Initialize the profile flag */
282 cUnit.executionCount = gDvmJit.profile;
283
Ben Chengba4fc8b2009-06-01 13:00:29 -0700284 /* Identify traces that we don't want to compile */
285 if (gDvmJit.methodTable) {
286 int len = strlen(desc->method->clazz->descriptor) +
287 strlen(desc->method->name) + 1;
288 char *fullSignature = dvmCompilerNew(len, true);
289 strcpy(fullSignature, desc->method->clazz->descriptor);
290 strcat(fullSignature, desc->method->name);
291
292 int hashValue = dvmComputeUtf8Hash(fullSignature);
293
294 /*
295 * Doing three levels of screening to see whether we want to skip
296 * compiling this method
297 */
298
299 /* First, check the full "class;method" signature */
300 bool methodFound =
301 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
302 fullSignature, (HashCompareFunc) strcmp,
303 false) !=
304 NULL;
305
306 /* Full signature not found - check the enclosing class */
307 if (methodFound == false) {
308 int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
309 methodFound =
310 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
311 (char *) desc->method->clazz->descriptor,
312 (HashCompareFunc) strcmp, false) !=
313 NULL;
314 /* Enclosing class not found - check the method name */
315 if (methodFound == false) {
316 int hashValue = dvmComputeUtf8Hash(desc->method->name);
317 methodFound =
318 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
319 (char *) desc->method->name,
320 (HashCompareFunc) strcmp, false) !=
321 NULL;
322 }
323 }
324
325 /*
326 * Under the following conditions, the trace will be *conservatively*
327 * compiled by only containing single-step instructions to and from the
328 * interpreter.
329 * 1) If includeSelectedMethod == false, the method matches the full or
330 * partial signature stored in the hash table.
331 *
332 * 2) If includeSelectedMethod == true, the method does not match the
333 * full and partial signature stored in the hash table.
334 */
335 if (gDvmJit.includeSelectedMethod != methodFound) {
336 cUnit.allSingleStep = true;
337 } else {
338 /* Compile the trace as normal */
339
340 /* Print the method we cherry picked */
341 if (gDvmJit.includeSelectedMethod == true) {
342 cUnit.printMe = true;
343 }
344 }
345 }
346
Ben Cheng4238ec22009-08-24 16:32:22 -0700347 /* Allocate the entry block */
Bill Buzbee1465db52009-09-23 17:17:35 -0700348 lastBB = startBB = curBB = dvmCompilerNewBB(kEntryBlock);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700349 curBB->startOffset = curOffset;
350 curBB->id = numBlocks++;
351
Bill Buzbee1465db52009-09-23 17:17:35 -0700352 curBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Cheng4238ec22009-08-24 16:32:22 -0700353 curBB->startOffset = curOffset;
354 curBB->id = numBlocks++;
355
356 /* Make the first real dalvik block the fallthrough of the entry block */
357 startBB->fallThrough = curBB;
358 lastBB->next = curBB;
359 lastBB = curBB;
360
Ben Chengba4fc8b2009-06-01 13:00:29 -0700361 if (cUnit.printMe) {
362 LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n",
363 desc->method->name, curOffset);
364 }
365
Ben Cheng1efc9c52009-06-08 18:25:27 -0700366 /*
367 * Analyze the trace descriptor and include up to the maximal number
368 * of Dalvik instructions into the IR.
369 */
370 while (1) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700371 MIR *insn;
372 int width;
Ben Cheng4238ec22009-08-24 16:32:22 -0700373 insn = dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700374 insn->offset = curOffset;
375 width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700376
377 /* The trace should never incude instruction data */
378 assert(width);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700379 insn->width = width;
380 traceSize += width;
381 dvmCompilerAppendMIR(curBB, insn);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700382 cUnit.numInsts++;
383 /* Instruction limit reached - terminate the trace here */
384 if (cUnit.numInsts >= numMaxInsts) {
385 break;
386 }
387 if (--numInsts == 0) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700388 if (currRun->frag.runEnd) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700389 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700390 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700391 curBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700392 lastBB->next = curBB;
393 lastBB = curBB;
394 curBB->id = numBlocks++;
395 currRun++;
396 curOffset = currRun->frag.startOffset;
397 numInsts = currRun->frag.numInsts;
398 curBB->startOffset = curOffset;
399 codePtr = dexCode->insns + curOffset;
400 }
401 } else {
402 curOffset += width;
403 codePtr += width;
404 }
405 }
406
Ben Cheng8b258bf2009-06-24 17:27:07 -0700407 /* Convert # of half-word to bytes */
408 methodStats->compiledDalvikSize += traceSize * 2;
409
Ben Chengba4fc8b2009-06-01 13:00:29 -0700410 /*
411 * Now scan basic blocks containing real code to connect the
412 * taken/fallthrough links. Also create chaining cells for code not included
413 * in the trace.
414 */
415 for (curBB = startBB; curBB; curBB = curBB->next) {
416 MIR *lastInsn = curBB->lastMIRInsn;
Ben Cheng4238ec22009-08-24 16:32:22 -0700417 /* Skip empty blocks */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700418 if (lastInsn == NULL) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700419 continue;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700420 }
421 curOffset = lastInsn->offset;
422 unsigned int targetOffset = curOffset;
423 unsigned int fallThroughOffset = curOffset + lastInsn->width;
424 bool isInvoke = false;
425 const Method *callee = NULL;
426
427 findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
428 &targetOffset, &isInvoke, &callee);
429
430 /* Link the taken and fallthrough blocks */
431 BasicBlock *searchBB;
432
433 /* No backward branch in the trace - start searching the next BB */
434 for (searchBB = curBB->next; searchBB; searchBB = searchBB->next) {
435 if (targetOffset == searchBB->startOffset) {
436 curBB->taken = searchBB;
437 }
438 if (fallThroughOffset == searchBB->startOffset) {
439 curBB->fallThrough = searchBB;
440 }
441 }
442
Ben Cheng1efc9c52009-06-08 18:25:27 -0700443 int flags = dexGetInstrFlags(gDvm.instrFlags,
444 lastInsn->dalvikInsn.opCode);
445
446 /*
447 * Some blocks are ended by non-control-flow-change instructions,
448 * currently only due to trace length constraint. In this case we need
449 * to generate an explicit branch at the end of the block to jump to
450 * the chaining cell.
Ben Cheng17f15ce2009-07-27 16:21:52 -0700451 *
452 * NOTE: INVOKE_DIRECT_EMPTY is actually not an invoke but a nop
Ben Cheng1efc9c52009-06-08 18:25:27 -0700453 */
454 curBB->needFallThroughBranch =
Ben Cheng17f15ce2009-07-27 16:21:52 -0700455 ((flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
456 kInstrInvoke)) == 0) ||
457 (lastInsn->dalvikInsn.opCode == OP_INVOKE_DIRECT_EMPTY);
458
Ben Cheng4238ec22009-08-24 16:32:22 -0700459 if (curBB->taken == NULL &&
460 curBB->fallThrough == NULL &&
461 flags == (kInstrCanBranch | kInstrCanContinue) &&
462 fallThroughOffset == startBB->startOffset) {
Ben Cheng0fd31e42009-09-03 14:40:16 -0700463 BasicBlock *loopBranch = curBB;
464 BasicBlock *exitBB;
465 BasicBlock *exitChainingCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700466
467 if (cUnit.printMe) {
468 LOGD("Natural loop detected!");
469 }
Bill Buzbee1465db52009-09-23 17:17:35 -0700470 exitBB = dvmCompilerNewBB(kExitBlock);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700471 lastBB->next = exitBB;
472 lastBB = exitBB;
Ben Cheng4238ec22009-08-24 16:32:22 -0700473
Ben Cheng0fd31e42009-09-03 14:40:16 -0700474 exitBB->startOffset = targetOffset;
475 exitBB->id = numBlocks++;
476 exitBB->needFallThroughBranch = true;
Ben Cheng4238ec22009-08-24 16:32:22 -0700477
Ben Cheng0fd31e42009-09-03 14:40:16 -0700478 loopBranch->taken = exitBB;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700479#if defined(WITH_SELF_VERIFICATION)
Ben Cheng0fd31e42009-09-03 14:40:16 -0700480 BasicBlock *backwardCell =
Bill Buzbee1465db52009-09-23 17:17:35 -0700481 dvmCompilerNewBB(kChainingCellBackwardBranch);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700482 lastBB->next = backwardCell;
483 lastBB = backwardCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700484
Ben Cheng0fd31e42009-09-03 14:40:16 -0700485 backwardCell->startOffset = startBB->startOffset;
486 backwardCell->id = numBlocks++;
487 loopBranch->fallThrough = backwardCell;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700488#elif defined(WITH_JIT_TUNING)
489 if (gDvmJit.profile) {
490 BasicBlock *backwardCell =
Bill Buzbee1465db52009-09-23 17:17:35 -0700491 dvmCompilerNewBB(kChainingCellBackwardBranch);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700492 lastBB->next = backwardCell;
493 lastBB = backwardCell;
494
495 backwardCell->startOffset = startBB->startOffset;
496 backwardCell->id = numBlocks++;
497 loopBranch->fallThrough = backwardCell;
498 } else {
499 loopBranch->fallThrough = startBB->next;
500 }
501#else
502 loopBranch->fallThrough = startBB->next;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700503#endif
504
505 /* Create the chaining cell as the fallthrough of the exit block */
Bill Buzbee1465db52009-09-23 17:17:35 -0700506 exitChainingCell = dvmCompilerNewBB(kChainingCellNormal);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700507 lastBB->next = exitChainingCell;
508 lastBB = exitChainingCell;
509
510 exitChainingCell->startOffset = targetOffset;
511 exitChainingCell->id = numBlocks++;
512
513 exitBB->fallThrough = exitChainingCell;
514
Ben Cheng4238ec22009-08-24 16:32:22 -0700515 cUnit.hasLoop = true;
516 }
517
Ben Cheng6c10a972009-10-29 14:39:18 -0700518 if (lastInsn->dalvikInsn.opCode == OP_PACKED_SWITCH ||
519 lastInsn->dalvikInsn.opCode == OP_SPARSE_SWITCH) {
520 int i;
521 const u2 *switchData = desc->method->insns + lastInsn->offset +
522 lastInsn->dalvikInsn.vB;
523 int size = switchData[1];
524 int maxChains = MIN(size, MAX_CHAINED_SWITCH_CASES);
525
526 /*
527 * Generate the landing pad for cases whose ranks are higher than
528 * MAX_CHAINED_SWITCH_CASES. The code will re-enter the interpreter
529 * through the NoChain point.
530 */
531 if (maxChains != size) {
532 cUnit.switchOverflowPad =
533 desc->method->insns + lastInsn->offset;
534 }
535
536 s4 *targets = (s4 *) (switchData + 2 +
537 (lastInsn->dalvikInsn.opCode == OP_PACKED_SWITCH ?
538 2 : size * 2));
539
540 /* One chaining cell for the first MAX_CHAINED_SWITCH_CASES cases */
541 for (i = 0; i < maxChains; i++) {
542 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal);
543 lastBB->next = caseChain;
544 lastBB = caseChain;
545
546 caseChain->startOffset = lastInsn->offset + targets[i];
547 caseChain->id = numBlocks++;
548 }
549
550 /* One more chaining cell for the default case */
551 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal);
552 lastBB->next = caseChain;
553 lastBB = caseChain;
554
555 caseChain->startOffset = lastInsn->offset + lastInsn->width;
556 caseChain->id = numBlocks++;
Ben Cheng6d576092009-09-01 17:01:58 -0700557 /* Fallthrough block not included in the trace */
Ben Cheng6c10a972009-10-29 14:39:18 -0700558 } else if (!isUnconditionalBranch(lastInsn) &&
559 curBB->fallThrough == NULL) {
Ben Cheng6d576092009-09-01 17:01:58 -0700560 /*
561 * If the chaining cell is after an invoke or
562 * instruction that cannot change the control flow, request a hot
563 * chaining cell.
564 */
565 if (isInvoke || curBB->needFallThroughBranch) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700566 lastBB->next = dvmCompilerNewBB(kChainingCellHot);
Ben Cheng6d576092009-09-01 17:01:58 -0700567 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700568 lastBB->next = dvmCompilerNewBB(kChainingCellNormal);
Ben Cheng6d576092009-09-01 17:01:58 -0700569 }
570 lastBB = lastBB->next;
571 lastBB->id = numBlocks++;
572 lastBB->startOffset = fallThroughOffset;
573 curBB->fallThrough = lastBB;
574 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700575 /* Target block not included in the trace */
Ben Cheng38329f52009-07-07 14:19:20 -0700576 if (curBB->taken == NULL &&
Bill Buzbee324b3ac2009-12-04 13:17:36 -0800577 (isGoto(lastInsn) || isInvoke ||
578 (targetOffset != UNKNOWN_TARGET && targetOffset != curOffset))) {
Ben Cheng38329f52009-07-07 14:19:20 -0700579 BasicBlock *newBB;
Ben Cheng1efc9c52009-06-08 18:25:27 -0700580 if (isInvoke) {
Ben Cheng38329f52009-07-07 14:19:20 -0700581 /* Monomorphic callee */
582 if (callee) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700583 newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton);
Ben Cheng38329f52009-07-07 14:19:20 -0700584 newBB->startOffset = 0;
585 newBB->containingMethod = callee;
586 /* Will resolve at runtime */
587 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700588 newBB = dvmCompilerNewBB(kChainingCellInvokePredicted);
Ben Cheng38329f52009-07-07 14:19:20 -0700589 newBB->startOffset = 0;
590 }
Ben Cheng1efc9c52009-06-08 18:25:27 -0700591 /* For unconditional branches, request a hot chaining cell */
592 } else {
Jeff Hao97319a82009-08-12 16:57:15 -0700593#if !defined(WITH_SELF_VERIFICATION)
Ben Cheng38329f52009-07-07 14:19:20 -0700594 newBB = dvmCompilerNewBB(flags & kInstrUnconditional ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700595 kChainingCellHot :
596 kChainingCellNormal);
Ben Cheng38329f52009-07-07 14:19:20 -0700597 newBB->startOffset = targetOffset;
Jeff Hao97319a82009-08-12 16:57:15 -0700598#else
599 /* Handle branches that branch back into the block */
600 if (targetOffset >= curBB->firstMIRInsn->offset &&
601 targetOffset <= curBB->lastMIRInsn->offset) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700602 newBB = dvmCompilerNewBB(kChainingCellBackwardBranch);
Jeff Hao97319a82009-08-12 16:57:15 -0700603 } else {
604 newBB = dvmCompilerNewBB(flags & kInstrUnconditional ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700605 kChainingCellHot :
606 kChainingCellNormal);
Jeff Hao97319a82009-08-12 16:57:15 -0700607 }
608 newBB->startOffset = targetOffset;
609#endif
Ben Cheng1efc9c52009-06-08 18:25:27 -0700610 }
Ben Cheng38329f52009-07-07 14:19:20 -0700611 newBB->id = numBlocks++;
612 curBB->taken = newBB;
613 lastBB->next = newBB;
614 lastBB = newBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700615 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700616 }
617
618 /* Now create a special block to host PC reconstruction code */
Bill Buzbee1465db52009-09-23 17:17:35 -0700619 lastBB->next = dvmCompilerNewBB(kPCReconstruction);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700620 lastBB = lastBB->next;
621 lastBB->id = numBlocks++;
622
623 /* And one final block that publishes the PC and raise the exception */
Bill Buzbee1465db52009-09-23 17:17:35 -0700624 lastBB->next = dvmCompilerNewBB(kExceptionHandling);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700625 lastBB = lastBB->next;
626 lastBB->id = numBlocks++;
627
628 if (cUnit.printMe) {
629 LOGD("TRACEINFO (%d): 0x%08x %s%s 0x%x %d of %d, %d blocks",
Ben Chenge9695e52009-06-16 16:11:47 -0700630 compilationId,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700631 (intptr_t) desc->method->insns,
632 desc->method->clazz->descriptor,
633 desc->method->name,
634 desc->trace[0].frag.startOffset,
635 traceSize,
636 dexCode->insnsSize,
637 numBlocks);
638 }
639
640 BasicBlock **blockList;
641
642 cUnit.method = desc->method;
643 cUnit.traceDesc = desc;
644 cUnit.numBlocks = numBlocks;
645 dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
646 blockList = cUnit.blockList =
647 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
648
649 int i;
650
651 for (i = 0, curBB = startBB; i < numBlocks; i++) {
652 blockList[i] = curBB;
653 curBB = curBB->next;
654 }
655 /* Make sure all blocks are added to the cUnit */
656 assert(curBB == NULL);
657
Ben Cheng4238ec22009-08-24 16:32:22 -0700658 /* Preparation for SSA conversion */
659 dvmInitializeSSAConversion(&cUnit);
660
Bill Buzbee1465db52009-09-23 17:17:35 -0700661
Ben Cheng4238ec22009-08-24 16:32:22 -0700662 if (cUnit.hasLoop) {
663 dvmCompilerLoopOpt(&cUnit);
664 }
665 else {
666 dvmCompilerNonLoopAnalysis(&cUnit);
667 }
668
Bill Buzbee1465db52009-09-23 17:17:35 -0700669 dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
670
Ben Chengba4fc8b2009-06-01 13:00:29 -0700671 if (cUnit.printMe) {
672 dvmCompilerDumpCompilationUnit(&cUnit);
673 }
674
Bill Buzbee716f1202009-07-23 13:22:09 -0700675 /* Set the instruction set to use (NOTE: later components may change it) */
Ben Cheng5d90c202009-11-22 23:31:11 -0800676 cUnit.instructionSet = dvmCompilerInstructionSet();
Bill Buzbee716f1202009-07-23 13:22:09 -0700677
Bill Buzbee1465db52009-09-23 17:17:35 -0700678 /* Allocate Registers */
679 dvmCompilerRegAlloc(&cUnit);
680
Ben Chengba4fc8b2009-06-01 13:00:29 -0700681 /* Convert MIR to LIR, etc. */
682 dvmCompilerMIR2LIR(&cUnit);
683
Ben Cheng1efc9c52009-06-08 18:25:27 -0700684 /* Convert LIR into machine code. */
Bill Buzbee716f1202009-07-23 13:22:09 -0700685 dvmCompilerAssembleLIR(&cUnit, info);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700686
687 if (cUnit.printMe) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700688 if (cUnit.halveInstCount) {
689 LOGD("Assembler aborted");
690 } else {
691 dvmCompilerCodegenDump(&cUnit);
692 }
693 LOGD("End %s%s, %d Dalvik instructions",
694 desc->method->clazz->descriptor, desc->method->name,
695 cUnit.numInsts);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700696 }
697
698 /* Reset the compiler resource pool */
699 dvmCompilerArenaReset();
700
Bill Buzbee716f1202009-07-23 13:22:09 -0700701 /* Success */
Ben Cheng4238ec22009-08-24 16:32:22 -0700702 if (!cUnit.halveInstCount) {
Ben Cheng8b258bf2009-06-24 17:27:07 -0700703 methodStats->nativeSize += cUnit.totalSize;
Bill Buzbee716f1202009-07-23 13:22:09 -0700704 return info->codeAddress != NULL;
Ben Cheng1efc9c52009-06-08 18:25:27 -0700705
706 /* Halve the instruction count and retry again */
707 } else {
Bill Buzbee716f1202009-07-23 13:22:09 -0700708 return dvmCompileTrace(desc, cUnit.numInsts / 2, info);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700709 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700710}
711
712/*
713 * Similar to dvmCompileTrace, but the entity processed here is the whole
714 * method.
715 *
716 * TODO: implementation will be revisited when the trace builder can provide
717 * whole-method traces.
718 */
Bill Buzbee716f1202009-07-23 13:22:09 -0700719bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700720{
721 const DexCode *dexCode = dvmGetMethodCode(method);
722 const u2 *codePtr = dexCode->insns;
723 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
724 int blockID = 0;
725 unsigned int curOffset = 0;
726
Bill Buzbee1465db52009-09-23 17:17:35 -0700727 BasicBlock *firstBlock = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700728 firstBlock->id = blockID++;
729
730 /* Allocate the bit-vector to track the beginning of basic blocks */
Ben Cheng4238ec22009-08-24 16:32:22 -0700731 BitVector *bbStartAddr = dvmCompilerAllocBitVector(dexCode->insnsSize+1,
732 false);
733 dvmCompilerSetBit(bbStartAddr, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700734
735 /*
736 * Sequentially go through every instruction first and put them in a single
737 * basic block. Identify block boundaries at the mean time.
738 */
739 while (codePtr < codeEnd) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700740 MIR *insn = dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700741 insn->offset = curOffset;
742 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
743 bool isInvoke = false;
744 const Method *callee;
745 insn->width = width;
746
Ben Cheng8b258bf2009-06-24 17:27:07 -0700747 /* Terminate when the data section is seen */
748 if (width == 0)
749 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700750 dvmCompilerAppendMIR(firstBlock, insn);
751 /*
752 * Check whether this is a block ending instruction and whether it
753 * suggests the start of a new block
754 */
755 unsigned int target = curOffset;
756
757 /*
758 * If findBlockBoundary returns true, it means the current instruction
759 * is terminating the current block. If it is a branch, the target
760 * address will be recorded in target.
761 */
762 if (findBlockBoundary(method, insn, curOffset, &target, &isInvoke,
763 &callee)) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700764 dvmCompilerSetBit(bbStartAddr, curOffset + width);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700765 if (target != curOffset) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700766 dvmCompilerSetBit(bbStartAddr, target);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700767 }
768 }
769
770 codePtr += width;
771 /* each bit represents 16-bit quantity */
772 curOffset += width;
773 }
774
775 /*
776 * The number of blocks will be equal to the number of bits set to 1 in the
777 * bit vector minus 1, because the bit representing the location after the
778 * last instruction is set to one.
779 */
780 int numBlocks = dvmCountSetBits(bbStartAddr);
781 if (dvmIsBitSet(bbStartAddr, dexCode->insnsSize)) {
782 numBlocks--;
783 }
784
785 CompilationUnit cUnit;
786 BasicBlock **blockList;
787
788 memset(&cUnit, 0, sizeof(CompilationUnit));
789 cUnit.method = method;
790 blockList = cUnit.blockList =
791 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
792
793 /*
794 * Register the first block onto the list and start split it into block
795 * boundaries from there.
796 */
797 blockList[0] = firstBlock;
798 cUnit.numBlocks = 1;
799
800 int i;
801 for (i = 0; i < numBlocks; i++) {
802 MIR *insn;
803 BasicBlock *curBB = blockList[i];
804 curOffset = curBB->lastMIRInsn->offset;
805
806 for (insn = curBB->firstMIRInsn->next; insn; insn = insn->next) {
807 /* Found the beginning of a new block, see if it is created yet */
808 if (dvmIsBitSet(bbStartAddr, insn->offset)) {
809 int j;
810 for (j = 0; j < cUnit.numBlocks; j++) {
811 if (blockList[j]->firstMIRInsn->offset == insn->offset)
812 break;
813 }
814
815 /* Block not split yet - do it now */
816 if (j == cUnit.numBlocks) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700817 BasicBlock *newBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700818 newBB->id = blockID++;
819 newBB->firstMIRInsn = insn;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700820 newBB->startOffset = insn->offset;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700821 newBB->lastMIRInsn = curBB->lastMIRInsn;
822 curBB->lastMIRInsn = insn->prev;
823 insn->prev->next = NULL;
824 insn->prev = NULL;
825
826 /*
827 * If the insn is not an unconditional branch, set up the
828 * fallthrough link.
829 */
830 if (!isUnconditionalBranch(curBB->lastMIRInsn)) {
831 curBB->fallThrough = newBB;
832 }
833
834 /* enqueue the new block */
835 blockList[cUnit.numBlocks++] = newBB;
836 break;
837 }
838 }
839 }
840 }
841
842 if (numBlocks != cUnit.numBlocks) {
843 LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit.numBlocks);
844 dvmAbort();
845 }
846
Ben Chengba4fc8b2009-06-01 13:00:29 -0700847 /* Connect the basic blocks through the taken links */
848 for (i = 0; i < numBlocks; i++) {
849 BasicBlock *curBB = blockList[i];
850 MIR *insn = curBB->lastMIRInsn;
851 unsigned int target = insn->offset;
852 bool isInvoke;
853 const Method *callee;
854
855 findBlockBoundary(method, insn, target, &target, &isInvoke, &callee);
856
857 /* Found a block ended on a branch */
858 if (target != insn->offset) {
859 int j;
860 /* Forward branch */
861 if (target > insn->offset) {
862 j = i + 1;
863 } else {
864 /* Backward branch */
865 j = 0;
866 }
867 for (; j < numBlocks; j++) {
868 if (blockList[j]->firstMIRInsn->offset == target) {
869 curBB->taken = blockList[j];
870 break;
871 }
872 }
873
Ben Cheng8b258bf2009-06-24 17:27:07 -0700874 /* Don't create dummy block for the callee yet */
875 if (j == numBlocks && !isInvoke) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700876 LOGE("Target not found for insn %x: expect target %x\n",
877 curBB->lastMIRInsn->offset, target);
878 dvmAbort();
879 }
880 }
881 }
882
Bill Buzbee716f1202009-07-23 13:22:09 -0700883 /* Set the instruction set to use (NOTE: later components may change it) */
Ben Cheng5d90c202009-11-22 23:31:11 -0800884 cUnit.instructionSet = dvmCompilerInstructionSet();
Bill Buzbee716f1202009-07-23 13:22:09 -0700885
Ben Chengba4fc8b2009-06-01 13:00:29 -0700886 dvmCompilerMIR2LIR(&cUnit);
887
Bill Buzbee716f1202009-07-23 13:22:09 -0700888 dvmCompilerAssembleLIR(&cUnit, info);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700889
890 dvmCompilerDumpCompilationUnit(&cUnit);
891
892 dvmCompilerArenaReset();
893
Bill Buzbee716f1202009-07-23 13:22:09 -0700894 return info->codeAddress != NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700895}