blob: b224614ccee5fab1b4d11e9d1c3feff533a039b9 [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"
19#include "dexdump/OpCodeNames.h"
20#include "interp/Jit.h"
21#include "CompilerInternals.h"
22
23/*
24 * Parse an instruction, return the length of the instruction
25 */
26static inline int parseInsn(const u2 *codePtr, DecodedInstruction *decInsn,
27 bool printMe)
28{
29 u2 instr = *codePtr;
30 OpCode opcode = instr & 0xff;
31 int insnWidth;
32
Ben Cheng8b258bf2009-06-24 17:27:07 -070033 // Don't parse instruction data
Ben Chengba4fc8b2009-06-01 13:00:29 -070034 if (opcode == OP_NOP && instr != 0) {
Ben Cheng8b258bf2009-06-24 17:27:07 -070035 return 0;
Ben Chengba4fc8b2009-06-01 13:00:29 -070036 } else {
37 insnWidth = gDvm.instrWidth[opcode];
38 if (insnWidth < 0) {
39 insnWidth = -insnWidth;
40 }
41 }
42
43 dexDecodeInstruction(gDvm.instrFormat, codePtr, decInsn);
44 if (printMe) {
45 LOGD("%p: %#06x %s\n", codePtr, opcode, getOpcodeName(opcode));
46 }
47 return insnWidth;
48}
49
50/*
51 * Identify block-ending instructions and collect supplemental information
52 * regarding the following instructions.
53 */
54static inline bool findBlockBoundary(const Method *caller, MIR *insn,
55 unsigned int curOffset,
56 unsigned int *target, bool *isInvoke,
57 const Method **callee)
58{
59 switch (insn->dalvikInsn.opCode) {
60 /* Target is not compile-time constant */
61 case OP_RETURN_VOID:
62 case OP_RETURN:
63 case OP_RETURN_WIDE:
64 case OP_RETURN_OBJECT:
65 case OP_THROW:
66 case OP_INVOKE_VIRTUAL:
67 case OP_INVOKE_VIRTUAL_RANGE:
68 case OP_INVOKE_INTERFACE:
69 case OP_INVOKE_INTERFACE_RANGE:
70 case OP_INVOKE_VIRTUAL_QUICK:
71 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
72 *isInvoke = true;
73 break;
74 case OP_INVOKE_SUPER:
75 case OP_INVOKE_SUPER_RANGE: {
76 int mIndex = caller->clazz->pDvmDex->
77 pResMethods[insn->dalvikInsn.vB]->methodIndex;
78 const Method *calleeMethod =
79 caller->clazz->super->vtable[mIndex];
80
Ben Cheng8b258bf2009-06-24 17:27:07 -070081 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -070082 *target = (unsigned int) calleeMethod->insns;
83 }
84 *isInvoke = true;
85 *callee = calleeMethod;
86 break;
87 }
88 case OP_INVOKE_STATIC:
89 case OP_INVOKE_STATIC_RANGE: {
90 const Method *calleeMethod =
91 caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
92
Ben Cheng8b258bf2009-06-24 17:27:07 -070093 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -070094 *target = (unsigned int) calleeMethod->insns;
95 }
96 *isInvoke = true;
97 *callee = calleeMethod;
98 break;
99 }
100 case OP_INVOKE_SUPER_QUICK:
101 case OP_INVOKE_SUPER_QUICK_RANGE: {
102 const Method *calleeMethod =
103 caller->clazz->super->vtable[insn->dalvikInsn.vB];
104
Ben Cheng8b258bf2009-06-24 17:27:07 -0700105 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700106 *target = (unsigned int) calleeMethod->insns;
107 }
108 *isInvoke = true;
109 *callee = calleeMethod;
110 break;
111 }
112 case OP_INVOKE_DIRECT:
113 case OP_INVOKE_DIRECT_RANGE: {
114 const Method *calleeMethod =
115 caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
Ben Cheng8b258bf2009-06-24 17:27:07 -0700116 if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700117 *target = (unsigned int) calleeMethod->insns;
118 }
119 *isInvoke = true;
120 *callee = calleeMethod;
121 break;
122 }
123 case OP_GOTO:
124 case OP_GOTO_16:
125 case OP_GOTO_32:
126 *target = curOffset + (int) insn->dalvikInsn.vA;
127 break;
128
129 case OP_IF_EQ:
130 case OP_IF_NE:
131 case OP_IF_LT:
132 case OP_IF_GE:
133 case OP_IF_GT:
134 case OP_IF_LE:
135 *target = curOffset + (int) insn->dalvikInsn.vC;
136 break;
137
138 case OP_IF_EQZ:
139 case OP_IF_NEZ:
140 case OP_IF_LTZ:
141 case OP_IF_GEZ:
142 case OP_IF_GTZ:
143 case OP_IF_LEZ:
144 *target = curOffset + (int) insn->dalvikInsn.vB;
145 break;
146
147 default:
148 return false;
149 } return true;
150}
151
152/*
153 * Identify conditional branch instructions
154 */
155static inline bool isUnconditionalBranch(MIR *insn)
156{
157 switch (insn->dalvikInsn.opCode) {
158 case OP_RETURN_VOID:
159 case OP_RETURN:
160 case OP_RETURN_WIDE:
161 case OP_RETURN_OBJECT:
162 case OP_GOTO:
163 case OP_GOTO_16:
164 case OP_GOTO_32:
165 return true;
166 default:
167 return false;
168 }
169}
170
171/*
Ben Cheng8b258bf2009-06-24 17:27:07 -0700172 * dvmHashTableLookup() callback
173 */
174static int compareMethod(const CompilerMethodStats *m1,
175 const CompilerMethodStats *m2)
176{
177 return (int) m1->method - (int) m2->method;
178}
179
180/*
181 * Analyze each method whose traces are ever compiled. Collect a variety of
182 * statistics like the ratio of exercised vs overall code and code bloat
183 * ratios.
184 */
185static CompilerMethodStats *analyzeMethodBody(const Method *method)
186{
187 const DexCode *dexCode = dvmGetMethodCode(method);
188 const u2 *codePtr = dexCode->insns;
189 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
190 int insnSize = 0;
191 int hashValue = dvmComputeUtf8Hash(method->name);
192
193 CompilerMethodStats dummyMethodEntry; // For hash table lookup
194 CompilerMethodStats *realMethodEntry; // For hash table storage
195
196 /* For lookup only */
197 dummyMethodEntry.method = method;
198 realMethodEntry = dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
199 &dummyMethodEntry,
200 (HashCompareFunc) compareMethod,
201 false);
202
203 /* Part of this method has been compiled before - just return the entry */
204 if (realMethodEntry != NULL) {
205 return realMethodEntry;
206 }
207
208 /*
209 * First time to compile this method - set up a new entry in the hash table
210 */
211 realMethodEntry =
212 (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
213 realMethodEntry->method = method;
214
215 dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
216 realMethodEntry,
217 (HashCompareFunc) compareMethod,
218 true);
219
220 /* Count the number of instructions */
221 while (codePtr < codeEnd) {
222 DecodedInstruction dalvikInsn;
223 int width = parseInsn(codePtr, &dalvikInsn, false);
224
225 /* Terminate when the data section is seen */
226 if (width == 0)
227 break;
228
229 insnSize += width;
230 codePtr += width;
231 }
232
233 realMethodEntry->dalvikSize = insnSize * 2;
234 return realMethodEntry;
235}
236
237/*
Ben Chengba4fc8b2009-06-01 13:00:29 -0700238 * Main entry point to start trace compilation. Basic blocks are constructed
239 * first and they will be passed to the codegen routines to convert Dalvik
240 * bytecode into machine code.
241 */
Bill Buzbee716f1202009-07-23 13:22:09 -0700242bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
243 JitTranslationInfo *info)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700244{
245 const DexCode *dexCode = dvmGetMethodCode(desc->method);
246 const JitTraceRun* currRun = &desc->trace[0];
Ben Chengba4fc8b2009-06-01 13:00:29 -0700247 unsigned int curOffset = currRun->frag.startOffset;
248 unsigned int numInsts = currRun->frag.numInsts;
249 const u2 *codePtr = dexCode->insns + curOffset;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700250 int traceSize = 0; // # of half-words
Ben Chengba4fc8b2009-06-01 13:00:29 -0700251 const u2 *startCodePtr = codePtr;
252 BasicBlock *startBB, *curBB, *lastBB;
253 int numBlocks = 0;
254 static int compilationId;
255 CompilationUnit cUnit;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700256 CompilerMethodStats *methodStats;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700257
Ben Chenge9695e52009-06-16 16:11:47 -0700258 compilationId++;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700259 memset(&cUnit, 0, sizeof(CompilationUnit));
260
261 /* Locate the entry to store compilation statistics for this method */
262 methodStats = analyzeMethodBody(desc->method);
Ben Chenge9695e52009-06-16 16:11:47 -0700263
264 cUnit.registerScoreboard.nullCheckedRegs =
Ben Cheng4238ec22009-08-24 16:32:22 -0700265 dvmCompilerAllocBitVector(desc->method->registersSize, false);
Ben Chenge9695e52009-06-16 16:11:47 -0700266
Ben Chengba4fc8b2009-06-01 13:00:29 -0700267 /* Initialize the printMe flag */
268 cUnit.printMe = gDvmJit.printMe;
269
Bill Buzbee6e963e12009-06-17 16:56:19 -0700270 /* Initialize the profile flag */
271 cUnit.executionCount = gDvmJit.profile;
272
Ben Chengba4fc8b2009-06-01 13:00:29 -0700273 /* Identify traces that we don't want to compile */
274 if (gDvmJit.methodTable) {
275 int len = strlen(desc->method->clazz->descriptor) +
276 strlen(desc->method->name) + 1;
277 char *fullSignature = dvmCompilerNew(len, true);
278 strcpy(fullSignature, desc->method->clazz->descriptor);
279 strcat(fullSignature, desc->method->name);
280
281 int hashValue = dvmComputeUtf8Hash(fullSignature);
282
283 /*
284 * Doing three levels of screening to see whether we want to skip
285 * compiling this method
286 */
287
288 /* First, check the full "class;method" signature */
289 bool methodFound =
290 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
291 fullSignature, (HashCompareFunc) strcmp,
292 false) !=
293 NULL;
294
295 /* Full signature not found - check the enclosing class */
296 if (methodFound == false) {
297 int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
298 methodFound =
299 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
300 (char *) desc->method->clazz->descriptor,
301 (HashCompareFunc) strcmp, false) !=
302 NULL;
303 /* Enclosing class not found - check the method name */
304 if (methodFound == false) {
305 int hashValue = dvmComputeUtf8Hash(desc->method->name);
306 methodFound =
307 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
308 (char *) desc->method->name,
309 (HashCompareFunc) strcmp, false) !=
310 NULL;
311 }
312 }
313
314 /*
315 * Under the following conditions, the trace will be *conservatively*
316 * compiled by only containing single-step instructions to and from the
317 * interpreter.
318 * 1) If includeSelectedMethod == false, the method matches the full or
319 * partial signature stored in the hash table.
320 *
321 * 2) If includeSelectedMethod == true, the method does not match the
322 * full and partial signature stored in the hash table.
323 */
324 if (gDvmJit.includeSelectedMethod != methodFound) {
325 cUnit.allSingleStep = true;
326 } else {
327 /* Compile the trace as normal */
328
329 /* Print the method we cherry picked */
330 if (gDvmJit.includeSelectedMethod == true) {
331 cUnit.printMe = true;
332 }
333 }
334 }
335
Ben Cheng4238ec22009-08-24 16:32:22 -0700336 /* Allocate the entry block */
337 lastBB = startBB = curBB = dvmCompilerNewBB(ENTRY_BLOCK);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700338 curBB->startOffset = curOffset;
339 curBB->id = numBlocks++;
340
Ben Cheng4238ec22009-08-24 16:32:22 -0700341 curBB = dvmCompilerNewBB(DALVIK_BYTECODE);
342 curBB->startOffset = curOffset;
343 curBB->id = numBlocks++;
344
345 /* Make the first real dalvik block the fallthrough of the entry block */
346 startBB->fallThrough = curBB;
347 lastBB->next = curBB;
348 lastBB = curBB;
349
Ben Chengba4fc8b2009-06-01 13:00:29 -0700350 if (cUnit.printMe) {
351 LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n",
352 desc->method->name, curOffset);
353 }
354
Ben Cheng1efc9c52009-06-08 18:25:27 -0700355 /*
356 * Analyze the trace descriptor and include up to the maximal number
357 * of Dalvik instructions into the IR.
358 */
359 while (1) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700360 MIR *insn;
361 int width;
Ben Cheng4238ec22009-08-24 16:32:22 -0700362 insn = dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700363 insn->offset = curOffset;
364 width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700365
366 /* The trace should never incude instruction data */
367 assert(width);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700368 insn->width = width;
369 traceSize += width;
370 dvmCompilerAppendMIR(curBB, insn);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700371 cUnit.numInsts++;
372 /* Instruction limit reached - terminate the trace here */
373 if (cUnit.numInsts >= numMaxInsts) {
374 break;
375 }
376 if (--numInsts == 0) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700377 if (currRun->frag.runEnd) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700378 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700379 } else {
380 curBB = dvmCompilerNewBB(DALVIK_BYTECODE);
381 lastBB->next = curBB;
382 lastBB = curBB;
383 curBB->id = numBlocks++;
384 currRun++;
385 curOffset = currRun->frag.startOffset;
386 numInsts = currRun->frag.numInsts;
387 curBB->startOffset = curOffset;
388 codePtr = dexCode->insns + curOffset;
389 }
390 } else {
391 curOffset += width;
392 codePtr += width;
393 }
394 }
395
Ben Cheng8b258bf2009-06-24 17:27:07 -0700396 /* Convert # of half-word to bytes */
397 methodStats->compiledDalvikSize += traceSize * 2;
398
Ben Chengba4fc8b2009-06-01 13:00:29 -0700399 /*
400 * Now scan basic blocks containing real code to connect the
401 * taken/fallthrough links. Also create chaining cells for code not included
402 * in the trace.
403 */
404 for (curBB = startBB; curBB; curBB = curBB->next) {
405 MIR *lastInsn = curBB->lastMIRInsn;
Ben Cheng4238ec22009-08-24 16:32:22 -0700406 /* Skip empty blocks */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700407 if (lastInsn == NULL) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700408 continue;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700409 }
410 curOffset = lastInsn->offset;
411 unsigned int targetOffset = curOffset;
412 unsigned int fallThroughOffset = curOffset + lastInsn->width;
413 bool isInvoke = false;
414 const Method *callee = NULL;
415
416 findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
417 &targetOffset, &isInvoke, &callee);
418
419 /* Link the taken and fallthrough blocks */
420 BasicBlock *searchBB;
421
422 /* No backward branch in the trace - start searching the next BB */
423 for (searchBB = curBB->next; searchBB; searchBB = searchBB->next) {
424 if (targetOffset == searchBB->startOffset) {
425 curBB->taken = searchBB;
426 }
427 if (fallThroughOffset == searchBB->startOffset) {
428 curBB->fallThrough = searchBB;
429 }
430 }
431
Ben Cheng1efc9c52009-06-08 18:25:27 -0700432 int flags = dexGetInstrFlags(gDvm.instrFlags,
433 lastInsn->dalvikInsn.opCode);
434
435 /*
436 * Some blocks are ended by non-control-flow-change instructions,
437 * currently only due to trace length constraint. In this case we need
438 * to generate an explicit branch at the end of the block to jump to
439 * the chaining cell.
Ben Cheng17f15ce2009-07-27 16:21:52 -0700440 *
441 * NOTE: INVOKE_DIRECT_EMPTY is actually not an invoke but a nop
Ben Cheng1efc9c52009-06-08 18:25:27 -0700442 */
443 curBB->needFallThroughBranch =
Ben Cheng17f15ce2009-07-27 16:21:52 -0700444 ((flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
445 kInstrInvoke)) == 0) ||
446 (lastInsn->dalvikInsn.opCode == OP_INVOKE_DIRECT_EMPTY);
447
Ben Cheng4238ec22009-08-24 16:32:22 -0700448 if (curBB->taken == NULL &&
449 curBB->fallThrough == NULL &&
450 flags == (kInstrCanBranch | kInstrCanContinue) &&
451 fallThroughOffset == startBB->startOffset) {
Ben Cheng0fd31e42009-09-03 14:40:16 -0700452 BasicBlock *loopBranch = curBB;
453 BasicBlock *exitBB;
454 BasicBlock *exitChainingCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700455
456 if (cUnit.printMe) {
457 LOGD("Natural loop detected!");
458 }
Ben Cheng0fd31e42009-09-03 14:40:16 -0700459 exitBB = dvmCompilerNewBB(EXIT_BLOCK);
460 lastBB->next = exitBB;
461 lastBB = exitBB;
Ben Cheng4238ec22009-08-24 16:32:22 -0700462
Ben Cheng0fd31e42009-09-03 14:40:16 -0700463 exitBB->startOffset = targetOffset;
464 exitBB->id = numBlocks++;
465 exitBB->needFallThroughBranch = true;
Ben Cheng4238ec22009-08-24 16:32:22 -0700466
Ben Cheng0fd31e42009-09-03 14:40:16 -0700467 loopBranch->taken = exitBB;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700468#if defined(WITH_SELF_VERIFICATION)
Ben Cheng0fd31e42009-09-03 14:40:16 -0700469 BasicBlock *backwardCell =
470 dvmCompilerNewBB(CHAINING_CELL_BACKWARD_BRANCH);
471 lastBB->next = backwardCell;
472 lastBB = backwardCell;
Ben Cheng4238ec22009-08-24 16:32:22 -0700473
Ben Cheng0fd31e42009-09-03 14:40:16 -0700474 backwardCell->startOffset = startBB->startOffset;
475 backwardCell->id = numBlocks++;
476 loopBranch->fallThrough = backwardCell;
Bill Buzbee9c4b7c82009-09-10 10:10:38 -0700477#elif defined(WITH_JIT_TUNING)
478 if (gDvmJit.profile) {
479 BasicBlock *backwardCell =
480 dvmCompilerNewBB(CHAINING_CELL_BACKWARD_BRANCH);
481 lastBB->next = backwardCell;
482 lastBB = backwardCell;
483
484 backwardCell->startOffset = startBB->startOffset;
485 backwardCell->id = numBlocks++;
486 loopBranch->fallThrough = backwardCell;
487 } else {
488 loopBranch->fallThrough = startBB->next;
489 }
490#else
491 loopBranch->fallThrough = startBB->next;
Ben Cheng0fd31e42009-09-03 14:40:16 -0700492#endif
493
494 /* Create the chaining cell as the fallthrough of the exit block */
495 exitChainingCell = dvmCompilerNewBB(CHAINING_CELL_NORMAL);
496 lastBB->next = exitChainingCell;
497 lastBB = exitChainingCell;
498
499 exitChainingCell->startOffset = targetOffset;
500 exitChainingCell->id = numBlocks++;
501
502 exitBB->fallThrough = exitChainingCell;
503
Ben Cheng4238ec22009-08-24 16:32:22 -0700504 cUnit.hasLoop = true;
505 }
506
Ben Cheng6d576092009-09-01 17:01:58 -0700507 /* Fallthrough block not included in the trace */
508 if (!isUnconditionalBranch(lastInsn) && curBB->fallThrough == NULL) {
509 /*
510 * If the chaining cell is after an invoke or
511 * instruction that cannot change the control flow, request a hot
512 * chaining cell.
513 */
514 if (isInvoke || curBB->needFallThroughBranch) {
515 lastBB->next = dvmCompilerNewBB(CHAINING_CELL_HOT);
516 } else {
517 lastBB->next = dvmCompilerNewBB(CHAINING_CELL_NORMAL);
518 }
519 lastBB = lastBB->next;
520 lastBB->id = numBlocks++;
521 lastBB->startOffset = fallThroughOffset;
522 curBB->fallThrough = lastBB;
523 }
524
Ben Chengba4fc8b2009-06-01 13:00:29 -0700525 /* Target block not included in the trace */
Ben Cheng38329f52009-07-07 14:19:20 -0700526 if (curBB->taken == NULL &&
527 (isInvoke || (targetOffset != curOffset))) {
528 BasicBlock *newBB;
Ben Cheng1efc9c52009-06-08 18:25:27 -0700529 if (isInvoke) {
Ben Cheng38329f52009-07-07 14:19:20 -0700530 /* Monomorphic callee */
531 if (callee) {
532 newBB = dvmCompilerNewBB(CHAINING_CELL_INVOKE_SINGLETON);
533 newBB->startOffset = 0;
534 newBB->containingMethod = callee;
535 /* Will resolve at runtime */
536 } else {
537 newBB = dvmCompilerNewBB(CHAINING_CELL_INVOKE_PREDICTED);
538 newBB->startOffset = 0;
539 }
Ben Cheng1efc9c52009-06-08 18:25:27 -0700540 /* For unconditional branches, request a hot chaining cell */
541 } else {
Jeff Hao97319a82009-08-12 16:57:15 -0700542#if !defined(WITH_SELF_VERIFICATION)
Ben Cheng38329f52009-07-07 14:19:20 -0700543 newBB = dvmCompilerNewBB(flags & kInstrUnconditional ?
Ben Cheng1efc9c52009-06-08 18:25:27 -0700544 CHAINING_CELL_HOT :
545 CHAINING_CELL_NORMAL);
Ben Cheng38329f52009-07-07 14:19:20 -0700546 newBB->startOffset = targetOffset;
Jeff Hao97319a82009-08-12 16:57:15 -0700547#else
548 /* Handle branches that branch back into the block */
549 if (targetOffset >= curBB->firstMIRInsn->offset &&
550 targetOffset <= curBB->lastMIRInsn->offset) {
551 newBB = dvmCompilerNewBB(CHAINING_CELL_BACKWARD_BRANCH);
552 } else {
553 newBB = dvmCompilerNewBB(flags & kInstrUnconditional ?
554 CHAINING_CELL_HOT :
555 CHAINING_CELL_NORMAL);
556 }
557 newBB->startOffset = targetOffset;
558#endif
Ben Cheng1efc9c52009-06-08 18:25:27 -0700559 }
Ben Cheng38329f52009-07-07 14:19:20 -0700560 newBB->id = numBlocks++;
561 curBB->taken = newBB;
562 lastBB->next = newBB;
563 lastBB = newBB;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700564 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700565 }
566
567 /* Now create a special block to host PC reconstruction code */
568 lastBB->next = dvmCompilerNewBB(PC_RECONSTRUCTION);
569 lastBB = lastBB->next;
570 lastBB->id = numBlocks++;
571
572 /* And one final block that publishes the PC and raise the exception */
573 lastBB->next = dvmCompilerNewBB(EXCEPTION_HANDLING);
574 lastBB = lastBB->next;
575 lastBB->id = numBlocks++;
576
577 if (cUnit.printMe) {
578 LOGD("TRACEINFO (%d): 0x%08x %s%s 0x%x %d of %d, %d blocks",
Ben Chenge9695e52009-06-16 16:11:47 -0700579 compilationId,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700580 (intptr_t) desc->method->insns,
581 desc->method->clazz->descriptor,
582 desc->method->name,
583 desc->trace[0].frag.startOffset,
584 traceSize,
585 dexCode->insnsSize,
586 numBlocks);
587 }
588
589 BasicBlock **blockList;
590
591 cUnit.method = desc->method;
592 cUnit.traceDesc = desc;
593 cUnit.numBlocks = numBlocks;
594 dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
595 blockList = cUnit.blockList =
596 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
597
598 int i;
599
600 for (i = 0, curBB = startBB; i < numBlocks; i++) {
601 blockList[i] = curBB;
602 curBB = curBB->next;
603 }
604 /* Make sure all blocks are added to the cUnit */
605 assert(curBB == NULL);
606
Ben Cheng4238ec22009-08-24 16:32:22 -0700607 /* Preparation for SSA conversion */
608 dvmInitializeSSAConversion(&cUnit);
609
610 if (cUnit.hasLoop) {
611 dvmCompilerLoopOpt(&cUnit);
612 }
613 else {
614 dvmCompilerNonLoopAnalysis(&cUnit);
615 }
616
Ben Chengba4fc8b2009-06-01 13:00:29 -0700617 if (cUnit.printMe) {
618 dvmCompilerDumpCompilationUnit(&cUnit);
619 }
620
Bill Buzbee716f1202009-07-23 13:22:09 -0700621 /* Set the instruction set to use (NOTE: later components may change it) */
622 cUnit.instructionSet = dvmCompilerInstructionSet(&cUnit);
623
Ben Chengba4fc8b2009-06-01 13:00:29 -0700624 /* Convert MIR to LIR, etc. */
625 dvmCompilerMIR2LIR(&cUnit);
626
Ben Cheng1efc9c52009-06-08 18:25:27 -0700627 /* Convert LIR into machine code. */
Bill Buzbee716f1202009-07-23 13:22:09 -0700628 dvmCompilerAssembleLIR(&cUnit, info);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700629
630 if (cUnit.printMe) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700631 if (cUnit.halveInstCount) {
632 LOGD("Assembler aborted");
633 } else {
634 dvmCompilerCodegenDump(&cUnit);
635 }
636 LOGD("End %s%s, %d Dalvik instructions",
637 desc->method->clazz->descriptor, desc->method->name,
638 cUnit.numInsts);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700639 }
640
641 /* Reset the compiler resource pool */
642 dvmCompilerArenaReset();
643
Bill Buzbee716f1202009-07-23 13:22:09 -0700644 /* Success */
Ben Cheng4238ec22009-08-24 16:32:22 -0700645 if (!cUnit.halveInstCount) {
Ben Cheng8b258bf2009-06-24 17:27:07 -0700646 methodStats->nativeSize += cUnit.totalSize;
Bill Buzbee716f1202009-07-23 13:22:09 -0700647 return info->codeAddress != NULL;
Ben Cheng1efc9c52009-06-08 18:25:27 -0700648
649 /* Halve the instruction count and retry again */
650 } else {
Bill Buzbee716f1202009-07-23 13:22:09 -0700651 return dvmCompileTrace(desc, cUnit.numInsts / 2, info);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700652 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700653}
654
655/*
656 * Similar to dvmCompileTrace, but the entity processed here is the whole
657 * method.
658 *
659 * TODO: implementation will be revisited when the trace builder can provide
660 * whole-method traces.
661 */
Bill Buzbee716f1202009-07-23 13:22:09 -0700662bool dvmCompileMethod(const Method *method, JitTranslationInfo *info)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700663{
664 const DexCode *dexCode = dvmGetMethodCode(method);
665 const u2 *codePtr = dexCode->insns;
666 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
667 int blockID = 0;
668 unsigned int curOffset = 0;
669
670 BasicBlock *firstBlock = dvmCompilerNewBB(DALVIK_BYTECODE);
671 firstBlock->id = blockID++;
672
673 /* Allocate the bit-vector to track the beginning of basic blocks */
Ben Cheng4238ec22009-08-24 16:32:22 -0700674 BitVector *bbStartAddr = dvmCompilerAllocBitVector(dexCode->insnsSize+1,
675 false);
676 dvmCompilerSetBit(bbStartAddr, 0);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700677
678 /*
679 * Sequentially go through every instruction first and put them in a single
680 * basic block. Identify block boundaries at the mean time.
681 */
682 while (codePtr < codeEnd) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700683 MIR *insn = dvmCompilerNew(sizeof(MIR), true);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700684 insn->offset = curOffset;
685 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
686 bool isInvoke = false;
687 const Method *callee;
688 insn->width = width;
689
Ben Cheng8b258bf2009-06-24 17:27:07 -0700690 /* Terminate when the data section is seen */
691 if (width == 0)
692 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700693 dvmCompilerAppendMIR(firstBlock, insn);
694 /*
695 * Check whether this is a block ending instruction and whether it
696 * suggests the start of a new block
697 */
698 unsigned int target = curOffset;
699
700 /*
701 * If findBlockBoundary returns true, it means the current instruction
702 * is terminating the current block. If it is a branch, the target
703 * address will be recorded in target.
704 */
705 if (findBlockBoundary(method, insn, curOffset, &target, &isInvoke,
706 &callee)) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700707 dvmCompilerSetBit(bbStartAddr, curOffset + width);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700708 if (target != curOffset) {
Ben Cheng4238ec22009-08-24 16:32:22 -0700709 dvmCompilerSetBit(bbStartAddr, target);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700710 }
711 }
712
713 codePtr += width;
714 /* each bit represents 16-bit quantity */
715 curOffset += width;
716 }
717
718 /*
719 * The number of blocks will be equal to the number of bits set to 1 in the
720 * bit vector minus 1, because the bit representing the location after the
721 * last instruction is set to one.
722 */
723 int numBlocks = dvmCountSetBits(bbStartAddr);
724 if (dvmIsBitSet(bbStartAddr, dexCode->insnsSize)) {
725 numBlocks--;
726 }
727
728 CompilationUnit cUnit;
729 BasicBlock **blockList;
730
731 memset(&cUnit, 0, sizeof(CompilationUnit));
732 cUnit.method = method;
733 blockList = cUnit.blockList =
734 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
735
736 /*
737 * Register the first block onto the list and start split it into block
738 * boundaries from there.
739 */
740 blockList[0] = firstBlock;
741 cUnit.numBlocks = 1;
742
743 int i;
744 for (i = 0; i < numBlocks; i++) {
745 MIR *insn;
746 BasicBlock *curBB = blockList[i];
747 curOffset = curBB->lastMIRInsn->offset;
748
749 for (insn = curBB->firstMIRInsn->next; insn; insn = insn->next) {
750 /* Found the beginning of a new block, see if it is created yet */
751 if (dvmIsBitSet(bbStartAddr, insn->offset)) {
752 int j;
753 for (j = 0; j < cUnit.numBlocks; j++) {
754 if (blockList[j]->firstMIRInsn->offset == insn->offset)
755 break;
756 }
757
758 /* Block not split yet - do it now */
759 if (j == cUnit.numBlocks) {
760 BasicBlock *newBB = dvmCompilerNewBB(DALVIK_BYTECODE);
761 newBB->id = blockID++;
762 newBB->firstMIRInsn = insn;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700763 newBB->startOffset = insn->offset;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700764 newBB->lastMIRInsn = curBB->lastMIRInsn;
765 curBB->lastMIRInsn = insn->prev;
766 insn->prev->next = NULL;
767 insn->prev = NULL;
768
769 /*
770 * If the insn is not an unconditional branch, set up the
771 * fallthrough link.
772 */
773 if (!isUnconditionalBranch(curBB->lastMIRInsn)) {
774 curBB->fallThrough = newBB;
775 }
776
777 /* enqueue the new block */
778 blockList[cUnit.numBlocks++] = newBB;
779 break;
780 }
781 }
782 }
783 }
784
785 if (numBlocks != cUnit.numBlocks) {
786 LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit.numBlocks);
787 dvmAbort();
788 }
789
Ben Chengba4fc8b2009-06-01 13:00:29 -0700790 /* Connect the basic blocks through the taken links */
791 for (i = 0; i < numBlocks; i++) {
792 BasicBlock *curBB = blockList[i];
793 MIR *insn = curBB->lastMIRInsn;
794 unsigned int target = insn->offset;
795 bool isInvoke;
796 const Method *callee;
797
798 findBlockBoundary(method, insn, target, &target, &isInvoke, &callee);
799
800 /* Found a block ended on a branch */
801 if (target != insn->offset) {
802 int j;
803 /* Forward branch */
804 if (target > insn->offset) {
805 j = i + 1;
806 } else {
807 /* Backward branch */
808 j = 0;
809 }
810 for (; j < numBlocks; j++) {
811 if (blockList[j]->firstMIRInsn->offset == target) {
812 curBB->taken = blockList[j];
813 break;
814 }
815 }
816
Ben Cheng8b258bf2009-06-24 17:27:07 -0700817 /* Don't create dummy block for the callee yet */
818 if (j == numBlocks && !isInvoke) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700819 LOGE("Target not found for insn %x: expect target %x\n",
820 curBB->lastMIRInsn->offset, target);
821 dvmAbort();
822 }
823 }
824 }
825
Bill Buzbee716f1202009-07-23 13:22:09 -0700826 /* Set the instruction set to use (NOTE: later components may change it) */
827 cUnit.instructionSet = dvmCompilerInstructionSet(&cUnit);
828
Ben Chengba4fc8b2009-06-01 13:00:29 -0700829 dvmCompilerMIR2LIR(&cUnit);
830
Bill Buzbee716f1202009-07-23 13:22:09 -0700831 dvmCompilerAssembleLIR(&cUnit, info);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700832
833 dvmCompilerDumpCompilationUnit(&cUnit);
834
835 dvmCompilerArenaReset();
836
Bill Buzbee716f1202009-07-23 13:22:09 -0700837 return info->codeAddress != NULL;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700838}