blob: 1cd821f3cb0fa14513134220e5a892a3bce9bec8 [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
157/*
158 * Identify conditional branch instructions
159 */
160static inline bool isUnconditionalBranch(MIR *insn)
161{
162 switch (insn->dalvikInsn.opCode) {
163 case OP_RETURN_VOID:
164 case OP_RETURN:
165 case OP_RETURN_WIDE:
166 case OP_RETURN_OBJECT:
167 case OP_GOTO:
168 case OP_GOTO_16:
169 case OP_GOTO_32:
170 return true;
171 default:
172 return false;
173 }
174}
175
176/*
Ben Cheng8b258bf2009-06-24 17:27:07 -0700177 * dvmHashTableLookup() callback
178 */
179static int compareMethod(const CompilerMethodStats *m1,
180 const CompilerMethodStats *m2)
181{
182 return (int) m1->method - (int) m2->method;
183}
184
185/*
186 * Analyze each method whose traces are ever compiled. Collect a variety of
187 * statistics like the ratio of exercised vs overall code and code bloat
188 * ratios.
189 */
190static CompilerMethodStats *analyzeMethodBody(const Method *method)
191{
192 const DexCode *dexCode = dvmGetMethodCode(method);
193 const u2 *codePtr = dexCode->insns;
194 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
195 int insnSize = 0;
196 int hashValue = dvmComputeUtf8Hash(method->name);
197
198 CompilerMethodStats dummyMethodEntry; // For hash table lookup
199 CompilerMethodStats *realMethodEntry; // For hash table storage
200
201 /* For lookup only */
202 dummyMethodEntry.method = method;
203 realMethodEntry = dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
204 &dummyMethodEntry,
205 (HashCompareFunc) compareMethod,
206 false);
207
208 /* Part of this method has been compiled before - just return the entry */
209 if (realMethodEntry != NULL) {
210 return realMethodEntry;
211 }
212
213 /*
214 * First time to compile this method - set up a new entry in the hash table
215 */
216 realMethodEntry =
217 (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
218 realMethodEntry->method = method;
219
220 dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
221 realMethodEntry,
222 (HashCompareFunc) compareMethod,
223 true);
224
225 /* Count the number of instructions */
226 while (codePtr < codeEnd) {
227 DecodedInstruction dalvikInsn;
228 int width = parseInsn(codePtr, &dalvikInsn, false);
229
230 /* Terminate when the data section is seen */
231 if (width == 0)
232 break;
233
234 insnSize += width;
235 codePtr += width;
236 }
237
238 realMethodEntry->dalvikSize = insnSize * 2;
239 return realMethodEntry;
240}
241
242/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700243 * Main entry point to start trace compilation. Basic blocks are constructed
244 * first and they will be passed to the codegen routines to convert Dalvik
245 * bytecode into machine code.
246 */
Bill Buzbee716f1202009-07-23 13:22:09 -0700247bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
248 JitTranslationInfo *info)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700249{
250 const DexCode *dexCode = dvmGetMethodCode(desc->method);
251 const JitTraceRun* currRun = &desc->trace[0];
Ben Chengba4fc8b2009-06-01 13:00:29 -0700252 unsigned int curOffset = currRun->frag.startOffset;
253 unsigned int numInsts = currRun->frag.numInsts;
254 const u2 *codePtr = dexCode->insns + curOffset;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700255 int traceSize = 0; // # of half-words
Ben Chengba4fc8b2009-06-01 13:00:29 -0700256 const u2 *startCodePtr = codePtr;
257 BasicBlock *startBB, *curBB, *lastBB;
258 int numBlocks = 0;
259 static int compilationId;
260 CompilationUnit cUnit;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700261 CompilerMethodStats *methodStats;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700262
Ben Chenge9695e52009-06-16 16:11:47 -0700263 compilationId++;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700264 memset(&cUnit, 0, sizeof(CompilationUnit));
265
266 /* Locate the entry to store compilation statistics for this method */
267 methodStats = analyzeMethodBody(desc->method);
Ben Chenge9695e52009-06-16 16:11:47 -0700268
Ben Chengba4fc8b2009-06-01 13:00:29 -0700269 /* Initialize the printMe flag */
270 cUnit.printMe = gDvmJit.printMe;
271
Bill Buzbee6e963e12009-06-17 16:56:19 -0700272 /* Initialize the profile flag */
273 cUnit.executionCount = gDvmJit.profile;
274
Ben Chengba4fc8b2009-06-01 13:00:29 -0700275 /* Identify traces that we don't want to compile */
276 if (gDvmJit.methodTable) {
277 int len = strlen(desc->method->clazz->descriptor) +
278 strlen(desc->method->name) + 1;
279 char *fullSignature = dvmCompilerNew(len, true);
280 strcpy(fullSignature, desc->method->clazz->descriptor);
281 strcat(fullSignature, desc->method->name);
282
283 int hashValue = dvmComputeUtf8Hash(fullSignature);
284
285 /*
286 * Doing three levels of screening to see whether we want to skip
287 * compiling this method
288 */
289
290 /* First, check the full "class;method" signature */
291 bool methodFound =
292 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
293 fullSignature, (HashCompareFunc) strcmp,
294 false) !=
295 NULL;
296
297 /* Full signature not found - check the enclosing class */
298 if (methodFound == false) {
299 int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
300 methodFound =
301 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
302 (char *) desc->method->clazz->descriptor,
303 (HashCompareFunc) strcmp, false) !=
304 NULL;
305 /* Enclosing class not found - check the method name */
306 if (methodFound == false) {
307 int hashValue = dvmComputeUtf8Hash(desc->method->name);
308 methodFound =
309 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
310 (char *) desc->method->name,
311 (HashCompareFunc) strcmp, false) !=
312 NULL;
313 }
314 }
315
316 /*
317 * Under the following conditions, the trace will be *conservatively*
318 * compiled by only containing single-step instructions to and from the
319 * interpreter.
320 * 1) If includeSelectedMethod == false, the method matches the full or
321 * partial signature stored in the hash table.
322 *
323 * 2) If includeSelectedMethod == true, the method does not match the
324 * full and partial signature stored in the hash table.
325 */
326 if (gDvmJit.includeSelectedMethod != methodFound) {
327 cUnit.allSingleStep = true;
328 } else {
329 /* Compile the trace as normal */
330
331 /* Print the method we cherry picked */
332 if (gDvmJit.includeSelectedMethod == true) {
333 cUnit.printMe = true;
334 }
335 }
336 }
337
Ben Cheng4238ec22009-08-24 16:32:22 -0700338 /* Allocate the entry block */
Bill Buzbee1465db52009-09-23 17:17:35 -0700339 lastBB = startBB = curBB = dvmCompilerNewBB(kEntryBlock);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700340 curBB->startOffset = curOffset;
341 curBB->id = numBlocks++;
342
Bill Buzbee1465db52009-09-23 17:17:35 -0700343 curBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Cheng4238ec22009-08-24 16:32:22 -0700344 curBB->startOffset = curOffset;
345 curBB->id = numBlocks++;
346
347 /* Make the first real dalvik block the fallthrough of the entry block */
348 startBB->fallThrough = curBB;
349 lastBB->next = curBB;
350 lastBB = curBB;
351
Ben Chengba4fc8b2009-06-01 13:00:29 -0700352 if (cUnit.printMe) {
353 LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n",
354 desc->method->name, curOffset);
355 }
356
Ben Cheng1efc9c52009-06-08 18:25:27 -0700357 /*
358 * Analyze the trace descriptor and include up to the maximal number
359 * of Dalvik instructions into the IR.
360 */
361 while (1) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700362 MIR *insn;
363 int width;
Ben Cheng4238ec22009-08-24 16:32:22 -0700364 insn = dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700365 insn->offset = curOffset;
366 width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700367
368 /* The trace should never incude instruction data */
369 assert(width);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700370 insn->width = width;
371 traceSize += width;
372 dvmCompilerAppendMIR(curBB, insn);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700373 cUnit.numInsts++;
374 /* Instruction limit reached - terminate the trace here */
375 if (cUnit.numInsts >= numMaxInsts) {
376 break;
377 }
378 if (--numInsts == 0) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700379 if (currRun->frag.runEnd) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700380 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700381 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700382 curBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700383 lastBB->next = curBB;
384 lastBB = curBB;
385 curBB->id = numBlocks++;
386 currRun++;
387 curOffset = currRun->frag.startOffset;
388 numInsts = currRun->frag.numInsts;
389 curBB->startOffset = curOffset;
390 codePtr = dexCode->insns + curOffset;
391 }
392 } else {
393 curOffset += width;
394 codePtr += width;
395 }
396 }
397
Ben Cheng8b258bf2009-06-24 17:27:07 -0700398 /* Convert # of half-word to bytes */
399 methodStats->compiledDalvikSize += traceSize * 2;
400
Ben Chengba4fc8b2009-06-01 13:00:29 -0700401 /*
402 * Now scan basic blocks containing real code to connect the
403 * taken/fallthrough links. Also create chaining cells for code not included
404 * in the trace.
405 */
406 for (curBB = startBB; curBB; curBB = curBB->next) {
407 MIR *lastInsn = curBB->lastMIRInsn;
Ben Cheng4238ec22009-08-24 16:32:22 -0700408 /* Skip empty blocks */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700409 if (lastInsn == NULL) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700410 continue;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700411 }
412 curOffset = lastInsn->offset;
413 unsigned int targetOffset = curOffset;
414 unsigned int fallThroughOffset = curOffset + lastInsn->width;
415 bool isInvoke = false;
416 const Method *callee = NULL;
417
418 findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
419 &targetOffset, &isInvoke, &callee);
420
421 /* Link the taken and fallthrough blocks */
422 BasicBlock *searchBB;
423
424 /* No backward branch in the trace - start searching the next BB */
425 for (searchBB = curBB->next; searchBB; searchBB = searchBB->next) {
426 if (targetOffset == searchBB->startOffset) {
427 curBB->taken = searchBB;
428 }
429 if (fallThroughOffset == searchBB->startOffset) {
430 curBB->fallThrough = searchBB;
431 }
432 }
433
Ben Cheng1efc9c52009-06-08 18:25:27 -0700434 int flags = dexGetInstrFlags(gDvm.instrFlags,
435 lastInsn->dalvikInsn.opCode);
436
437 /*
438 * Some blocks are ended by non-control-flow-change instructions,
439 * currently only due to trace length constraint. In this case we need
440 * to generate an explicit branch at the end of the block to jump to
441 * the chaining cell.
Ben Cheng17f15ce2009-07-27 16:21:52 -0700442 *
443 * NOTE: INVOKE_DIRECT_EMPTY is actually not an invoke but a nop
Ben Cheng1efc9c52009-06-08 18:25:27 -0700444 */
445 curBB->needFallThroughBranch =
Ben Cheng17f15ce2009-07-27 16:21:52 -0700446 ((flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
447 kInstrInvoke)) == 0) ||
448 (lastInsn->dalvikInsn.opCode == OP_INVOKE_DIRECT_EMPTY);
449
Ben Cheng4238ec22009-08-24 16:32:22 -0700450 if (curBB->taken == NULL &&
451 curBB->fallThrough == NULL &&
452 flags == (kInstrCanBranch | kInstrCanContinue) &&
453 fallThroughOffset == startBB->startOffset) {
Ben Cheng0fd31e42009-09-03 14:40:16 -0700454 BasicBlock *loopBranch = curBB;
455 BasicBlock *exitBB;
456 BasicBlock *exitChainingCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700457
458 if (cUnit.printMe) {
459 LOGD("Natural loop detected!");
460 }
Bill Buzbee1465db52009-09-23 17:17:35 -0700461 exitBB = dvmCompilerNewBB(kExitBlock);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700462 lastBB->next = exitBB;
463 lastBB = exitBB;
Ben Cheng4238ec22009-08-24 16:32:22 -0700464
Ben Cheng0fd31e42009-09-03 14:40:16 -0700465 exitBB->startOffset = targetOffset;
466 exitBB->id = numBlocks++;
467 exitBB->needFallThroughBranch = true;
Ben Cheng4238ec22009-08-24 16:32:22 -0700468
Ben Cheng0fd31e42009-09-03 14:40:16 -0700469 loopBranch->taken = exitBB;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700470#if defined(WITH_SELF_VERIFICATION)
Ben Cheng0fd31e42009-09-03 14:40:16 -0700471 BasicBlock *backwardCell =
Bill Buzbee1465db52009-09-23 17:17:35 -0700472 dvmCompilerNewBB(kChainingCellBackwardBranch);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700473 lastBB->next = backwardCell;
474 lastBB = backwardCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700475
Ben Cheng0fd31e42009-09-03 14:40:16 -0700476 backwardCell->startOffset = startBB->startOffset;
477 backwardCell->id = numBlocks++;
478 loopBranch->fallThrough = backwardCell;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700479#elif defined(WITH_JIT_TUNING)
480 if (gDvmJit.profile) {
481 BasicBlock *backwardCell =
Bill Buzbee1465db52009-09-23 17:17:35 -0700482 dvmCompilerNewBB(kChainingCellBackwardBranch);
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700483 lastBB->next = backwardCell;
484 lastBB = backwardCell;
485
486 backwardCell->startOffset = startBB->startOffset;
487 backwardCell->id = numBlocks++;
488 loopBranch->fallThrough = backwardCell;
489 } else {
490 loopBranch->fallThrough = startBB->next;
491 }
492#else
493 loopBranch->fallThrough = startBB->next;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700494#endif
495
496 /* Create the chaining cell as the fallthrough of the exit block */
Bill Buzbee1465db52009-09-23 17:17:35 -0700497 exitChainingCell = dvmCompilerNewBB(kChainingCellNormal);
Ben Cheng0fd31e42009-09-03 14:40:16 -0700498 lastBB->next = exitChainingCell;
499 lastBB = exitChainingCell;
500
501 exitChainingCell->startOffset = targetOffset;
502 exitChainingCell->id = numBlocks++;
503
504 exitBB->fallThrough = exitChainingCell;
505
Ben Cheng4238ec22009-08-24 16:32:22 -0700506 cUnit.hasLoop = true;
507 }
508
Ben Cheng6c10a972009-10-29 14:39:18 -0700509 if (lastInsn->dalvikInsn.opCode == OP_PACKED_SWITCH ||
510 lastInsn->dalvikInsn.opCode == OP_SPARSE_SWITCH) {
511 int i;
512 const u2 *switchData = desc->method->insns + lastInsn->offset +
513 lastInsn->dalvikInsn.vB;
514 int size = switchData[1];
515 int maxChains = MIN(size, MAX_CHAINED_SWITCH_CASES);
516
517 /*
518 * Generate the landing pad for cases whose ranks are higher than
519 * MAX_CHAINED_SWITCH_CASES. The code will re-enter the interpreter
520 * through the NoChain point.
521 */
522 if (maxChains != size) {
523 cUnit.switchOverflowPad =
524 desc->method->insns + lastInsn->offset;
525 }
526
527 s4 *targets = (s4 *) (switchData + 2 +
528 (lastInsn->dalvikInsn.opCode == OP_PACKED_SWITCH ?
529 2 : size * 2));
530
531 /* One chaining cell for the first MAX_CHAINED_SWITCH_CASES cases */
532 for (i = 0; i < maxChains; i++) {
533 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal);
534 lastBB->next = caseChain;
535 lastBB = caseChain;
536
537 caseChain->startOffset = lastInsn->offset + targets[i];
538 caseChain->id = numBlocks++;
539 }
540
541 /* One more chaining cell for the default case */
542 BasicBlock *caseChain = dvmCompilerNewBB(kChainingCellNormal);
543 lastBB->next = caseChain;
544 lastBB = caseChain;
545
546 caseChain->startOffset = lastInsn->offset + lastInsn->width;
547 caseChain->id = numBlocks++;
Ben Cheng6d576092009-09-01 17:01:58 -0700548 /* Fallthrough block not included in the trace */
Ben Cheng6c10a972009-10-29 14:39:18 -0700549 } else if (!isUnconditionalBranch(lastInsn) &&
550 curBB->fallThrough == NULL) {
Ben Cheng6d576092009-09-01 17:01:58 -0700551 /*
552 * If the chaining cell is after an invoke or
553 * instruction that cannot change the control flow, request a hot
554 * chaining cell.
555 */
556 if (isInvoke || curBB->needFallThroughBranch) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700557 lastBB->next = dvmCompilerNewBB(kChainingCellHot);
Ben Cheng6d576092009-09-01 17:01:58 -0700558 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700559 lastBB->next = dvmCompilerNewBB(kChainingCellNormal);
Ben Cheng6d576092009-09-01 17:01:58 -0700560 }
561 lastBB = lastBB->next;
562 lastBB->id = numBlocks++;
563 lastBB->startOffset = fallThroughOffset;
564 curBB->fallThrough = lastBB;
565 }
566
Ben Chengba4fc8b2009-06-01 13:00:29 -0700567 /* Target block not included in the trace */
Ben Cheng38329f52009-07-07 14:19:20 -0700568 if (curBB->taken == NULL &&
Ben Cheng9c147b82009-10-07 16:41:46 -0700569 (isInvoke || (targetOffset != UNKNOWN_TARGET &&
570 targetOffset != curOffset))) {
Ben Cheng38329f52009-07-07 14:19:20 -0700571 BasicBlock *newBB;
Ben Cheng1efc9c52009-06-08 18:25:27 -0700572 if (isInvoke) {
Ben Cheng38329f52009-07-07 14:19:20 -0700573 /* Monomorphic callee */
574 if (callee) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700575 newBB = dvmCompilerNewBB(kChainingCellInvokeSingleton);
Ben Cheng38329f52009-07-07 14:19:20 -0700576 newBB->startOffset = 0;
577 newBB->containingMethod = callee;
578 /* Will resolve at runtime */
579 } else {
Bill Buzbee1465db52009-09-23 17:17:35 -0700580 newBB = dvmCompilerNewBB(kChainingCellInvokePredicted);
Ben Cheng38329f52009-07-07 14:19:20 -0700581 newBB->startOffset = 0;
582 }
Ben Cheng1efc9c52009-06-08 18:25:27 -0700583 /* For unconditional branches, request a hot chaining cell */
584 } else {
Jeff Hao97319a82009-08-12 16:57:15 -0700585#if !defined(WITH_SELF_VERIFICATION)
Ben Cheng38329f52009-07-07 14:19:20 -0700586 newBB = dvmCompilerNewBB(flags & kInstrUnconditional ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700587 kChainingCellHot :
588 kChainingCellNormal);
Ben Cheng38329f52009-07-07 14:19:20 -0700589 newBB->startOffset = targetOffset;
Jeff Hao97319a82009-08-12 16:57:15 -0700590#else
591 /* Handle branches that branch back into the block */
592 if (targetOffset >= curBB->firstMIRInsn->offset &&
593 targetOffset <= curBB->lastMIRInsn->offset) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700594 newBB = dvmCompilerNewBB(kChainingCellBackwardBranch);
Jeff Hao97319a82009-08-12 16:57:15 -0700595 } else {
596 newBB = dvmCompilerNewBB(flags & kInstrUnconditional ?
Bill Buzbee1465db52009-09-23 17:17:35 -0700597 kChainingCellHot :
598 kChainingCellNormal);
Jeff Hao97319a82009-08-12 16:57:15 -0700599 }
600 newBB->startOffset = targetOffset;
601#endif
Ben Cheng1efc9c52009-06-08 18:25:27 -0700602 }
Ben Cheng38329f52009-07-07 14:19:20 -0700603 newBB->id = numBlocks++;
604 curBB->taken = newBB;
605 lastBB->next = newBB;
606 lastBB = newBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700607 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700608 }
609
610 /* Now create a special block to host PC reconstruction code */
Bill Buzbee1465db52009-09-23 17:17:35 -0700611 lastBB->next = dvmCompilerNewBB(kPCReconstruction);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700612 lastBB = lastBB->next;
613 lastBB->id = numBlocks++;
614
615 /* And one final block that publishes the PC and raise the exception */
Bill Buzbee1465db52009-09-23 17:17:35 -0700616 lastBB->next = dvmCompilerNewBB(kExceptionHandling);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700617 lastBB = lastBB->next;
618 lastBB->id = numBlocks++;
619
620 if (cUnit.printMe) {
621 LOGD("TRACEINFO (%d): 0x%08x %s%s 0x%x %d of %d, %d blocks",
Ben Chenge9695e52009-06-16 16:11:47 -0700622 compilationId,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700623 (intptr_t) desc->method->insns,
624 desc->method->clazz->descriptor,
625 desc->method->name,
626 desc->trace[0].frag.startOffset,
627 traceSize,
628 dexCode->insnsSize,
629 numBlocks);
630 }
631
632 BasicBlock **blockList;
633
634 cUnit.method = desc->method;
635 cUnit.traceDesc = desc;
636 cUnit.numBlocks = numBlocks;
637 dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
638 blockList = cUnit.blockList =
639 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
640
641 int i;
642
643 for (i = 0, curBB = startBB; i < numBlocks; i++) {
644 blockList[i] = curBB;
645 curBB = curBB->next;
646 }
647 /* Make sure all blocks are added to the cUnit */
648 assert(curBB == NULL);
649
Ben Cheng4238ec22009-08-24 16:32:22 -0700650 /* Preparation for SSA conversion */
651 dvmInitializeSSAConversion(&cUnit);
652
Bill Buzbee1465db52009-09-23 17:17:35 -0700653
Ben Cheng4238ec22009-08-24 16:32:22 -0700654 if (cUnit.hasLoop) {
655 dvmCompilerLoopOpt(&cUnit);
656 }
657 else {
658 dvmCompilerNonLoopAnalysis(&cUnit);
659 }
660
Bill Buzbee1465db52009-09-23 17:17:35 -0700661 dvmCompilerInitializeRegAlloc(&cUnit); // Needs to happen after SSA naming
662
Ben Chengba4fc8b2009-06-01 13:00:29 -0700663 if (cUnit.printMe) {
664 dvmCompilerDumpCompilationUnit(&cUnit);
665 }
666
Bill Buzbee716f1202009-07-23 13:22:09 -0700667 /* Set the instruction set to use (NOTE: later components may change it) */
668 cUnit.instructionSet = dvmCompilerInstructionSet(&cUnit);
669
Bill Buzbee1465db52009-09-23 17:17:35 -0700670 /* Allocate Registers */
671 dvmCompilerRegAlloc(&cUnit);
672
Ben Chengba4fc8b2009-06-01 13:00:29 -0700673 /* Convert MIR to LIR, etc. */
674 dvmCompilerMIR2LIR(&cUnit);
675
Ben Cheng1efc9c52009-06-08 18:25:27 -0700676 /* Convert LIR into machine code. */
Bill Buzbee716f1202009-07-23 13:22:09 -0700677 dvmCompilerAssembleLIR(&cUnit, info);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700678
679 if (cUnit.printMe) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700680 if (cUnit.halveInstCount) {
681 LOGD("Assembler aborted");
682 } else {
683 dvmCompilerCodegenDump(&cUnit);
684 }
685 LOGD("End %s%s, %d Dalvik instructions",
686 desc->method->clazz->descriptor, desc->method->name,
687 cUnit.numInsts);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700688 }
689
690 /* Reset the compiler resource pool */
691 dvmCompilerArenaReset();
692
Bill Buzbee716f1202009-07-23 13:22:09 -0700693 /* Success */
Ben Cheng4238ec22009-08-24 16:32:22 -0700694 if (!cUnit.halveInstCount) {
Ben Cheng8b258bf2009-06-24 17:27:07 -0700695 methodStats->nativeSize += cUnit.totalSize;
Bill Buzbee716f1202009-07-23 13:22:09 -0700696 return info->codeAddress != NULL;
Ben Cheng1efc9c52009-06-08 18:25:27 -0700697
698 /* Halve the instruction count and retry again */
699 } else {
Bill Buzbee716f1202009-07-23 13:22:09 -0700700 return dvmCompileTrace(desc, cUnit.numInsts / 2, info);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700701 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700702}
703
704/*
705 * Similar to dvmCompileTrace, but the entity processed here is the whole
706 * method.
707 *
708 * TODO: implementation will be revisited when the trace builder can provide
709 * whole-method traces.
710 */
Bill Buzbee716f1202009-07-23 13:22:09 -0700711bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700712{
713 const DexCode *dexCode = dvmGetMethodCode(method);
714 const u2 *codePtr = dexCode->insns;
715 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
716 int blockID = 0;
717 unsigned int curOffset = 0;
718
Bill Buzbee1465db52009-09-23 17:17:35 -0700719 BasicBlock *firstBlock = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700720 firstBlock->id = blockID++;
721
722 /* Allocate the bit-vector to track the beginning of basic blocks */
Ben Cheng4238ec22009-08-24 16:32:22 -0700723 BitVector *bbStartAddr = dvmCompilerAllocBitVector(dexCode->insnsSize+1,
724 false);
725 dvmCompilerSetBit(bbStartAddr, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700726
727 /*
728 * Sequentially go through every instruction first and put them in a single
729 * basic block. Identify block boundaries at the mean time.
730 */
731 while (codePtr < codeEnd) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700732 MIR *insn = dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700733 insn->offset = curOffset;
734 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
735 bool isInvoke = false;
736 const Method *callee;
737 insn->width = width;
738
Ben Cheng8b258bf2009-06-24 17:27:07 -0700739 /* Terminate when the data section is seen */
740 if (width == 0)
741 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700742 dvmCompilerAppendMIR(firstBlock, insn);
743 /*
744 * Check whether this is a block ending instruction and whether it
745 * suggests the start of a new block
746 */
747 unsigned int target = curOffset;
748
749 /*
750 * If findBlockBoundary returns true, it means the current instruction
751 * is terminating the current block. If it is a branch, the target
752 * address will be recorded in target.
753 */
754 if (findBlockBoundary(method, insn, curOffset, &target, &isInvoke,
755 &callee)) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700756 dvmCompilerSetBit(bbStartAddr, curOffset + width);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700757 if (target != curOffset) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700758 dvmCompilerSetBit(bbStartAddr, target);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700759 }
760 }
761
762 codePtr += width;
763 /* each bit represents 16-bit quantity */
764 curOffset += width;
765 }
766
767 /*
768 * The number of blocks will be equal to the number of bits set to 1 in the
769 * bit vector minus 1, because the bit representing the location after the
770 * last instruction is set to one.
771 */
772 int numBlocks = dvmCountSetBits(bbStartAddr);
773 if (dvmIsBitSet(bbStartAddr, dexCode->insnsSize)) {
774 numBlocks--;
775 }
776
777 CompilationUnit cUnit;
778 BasicBlock **blockList;
779
780 memset(&cUnit, 0, sizeof(CompilationUnit));
781 cUnit.method = method;
782 blockList = cUnit.blockList =
783 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
784
785 /*
786 * Register the first block onto the list and start split it into block
787 * boundaries from there.
788 */
789 blockList[0] = firstBlock;
790 cUnit.numBlocks = 1;
791
792 int i;
793 for (i = 0; i < numBlocks; i++) {
794 MIR *insn;
795 BasicBlock *curBB = blockList[i];
796 curOffset = curBB->lastMIRInsn->offset;
797
798 for (insn = curBB->firstMIRInsn->next; insn; insn = insn->next) {
799 /* Found the beginning of a new block, see if it is created yet */
800 if (dvmIsBitSet(bbStartAddr, insn->offset)) {
801 int j;
802 for (j = 0; j < cUnit.numBlocks; j++) {
803 if (blockList[j]->firstMIRInsn->offset == insn->offset)
804 break;
805 }
806
807 /* Block not split yet - do it now */
808 if (j == cUnit.numBlocks) {
Bill Buzbee1465db52009-09-23 17:17:35 -0700809 BasicBlock *newBB = dvmCompilerNewBB(kDalvikByteCode);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700810 newBB->id = blockID++;
811 newBB->firstMIRInsn = insn;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700812 newBB->startOffset = insn->offset;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700813 newBB->lastMIRInsn = curBB->lastMIRInsn;
814 curBB->lastMIRInsn = insn->prev;
815 insn->prev->next = NULL;
816 insn->prev = NULL;
817
818 /*
819 * If the insn is not an unconditional branch, set up the
820 * fallthrough link.
821 */
822 if (!isUnconditionalBranch(curBB->lastMIRInsn)) {
823 curBB->fallThrough = newBB;
824 }
825
826 /* enqueue the new block */
827 blockList[cUnit.numBlocks++] = newBB;
828 break;
829 }
830 }
831 }
832 }
833
834 if (numBlocks != cUnit.numBlocks) {
835 LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit.numBlocks);
836 dvmAbort();
837 }
838
Ben Chengba4fc8b2009-06-01 13:00:29 -0700839 /* Connect the basic blocks through the taken links */
840 for (i = 0; i < numBlocks; i++) {
841 BasicBlock *curBB = blockList[i];
842 MIR *insn = curBB->lastMIRInsn;
843 unsigned int target = insn->offset;
844 bool isInvoke;
845 const Method *callee;
846
847 findBlockBoundary(method, insn, target, &target, &isInvoke, &callee);
848
849 /* Found a block ended on a branch */
850 if (target != insn->offset) {
851 int j;
852 /* Forward branch */
853 if (target > insn->offset) {
854 j = i + 1;
855 } else {
856 /* Backward branch */
857 j = 0;
858 }
859 for (; j < numBlocks; j++) {
860 if (blockList[j]->firstMIRInsn->offset == target) {
861 curBB->taken = blockList[j];
862 break;
863 }
864 }
865
Ben Cheng8b258bf2009-06-24 17:27:07 -0700866 /* Don't create dummy block for the callee yet */
867 if (j == numBlocks && !isInvoke) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700868 LOGE("Target not found for insn %x: expect target %x\n",
869 curBB->lastMIRInsn->offset, target);
870 dvmAbort();
871 }
872 }
873 }
874
Bill Buzbee716f1202009-07-23 13:22:09 -0700875 /* Set the instruction set to use (NOTE: later components may change it) */
876 cUnit.instructionSet = dvmCompilerInstructionSet(&cUnit);
877
Ben Chengba4fc8b2009-06-01 13:00:29 -0700878 dvmCompilerMIR2LIR(&cUnit);
879
Bill Buzbee716f1202009-07-23 13:22:09 -0700880 dvmCompilerAssembleLIR(&cUnit, info);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700881
882 dvmCompilerDumpCompilationUnit(&cUnit);
883
884 dvmCompilerArenaReset();
885
Bill Buzbee716f1202009-07-23 13:22:09 -0700886 return info->codeAddress != NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700887}