blob: 76d931207c4f59eb268cdb766457aa70152ed3f0 [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 */
Ben Cheng1efc9c52009-06-08 18:25:27 -0700242void *dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700243{
244 const DexCode *dexCode = dvmGetMethodCode(desc->method);
245 const JitTraceRun* currRun = &desc->trace[0];
Ben Chengba4fc8b2009-06-01 13:00:29 -0700246 unsigned int curOffset = currRun->frag.startOffset;
247 unsigned int numInsts = currRun->frag.numInsts;
248 const u2 *codePtr = dexCode->insns + curOffset;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700249 int traceSize = 0; // # of half-words
Ben Chengba4fc8b2009-06-01 13:00:29 -0700250 const u2 *startCodePtr = codePtr;
251 BasicBlock *startBB, *curBB, *lastBB;
252 int numBlocks = 0;
253 static int compilationId;
254 CompilationUnit cUnit;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700255 CompilerMethodStats *methodStats;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700256
Ben Chenge9695e52009-06-16 16:11:47 -0700257 compilationId++;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700258 memset(&cUnit, 0, sizeof(CompilationUnit));
259
260 /* Locate the entry to store compilation statistics for this method */
261 methodStats = analyzeMethodBody(desc->method);
Ben Chenge9695e52009-06-16 16:11:47 -0700262
263 cUnit.registerScoreboard.nullCheckedRegs =
264 dvmAllocBitVector(desc->method->registersSize, false);
265
Ben Chengba4fc8b2009-06-01 13:00:29 -0700266 /* Initialize the printMe flag */
267 cUnit.printMe = gDvmJit.printMe;
268
Bill Buzbee6e963e12009-06-17 16:56:19 -0700269 /* Initialize the profile flag */
270 cUnit.executionCount = gDvmJit.profile;
271
Ben Chengba4fc8b2009-06-01 13:00:29 -0700272 /* Identify traces that we don't want to compile */
273 if (gDvmJit.methodTable) {
274 int len = strlen(desc->method->clazz->descriptor) +
275 strlen(desc->method->name) + 1;
276 char *fullSignature = dvmCompilerNew(len, true);
277 strcpy(fullSignature, desc->method->clazz->descriptor);
278 strcat(fullSignature, desc->method->name);
279
280 int hashValue = dvmComputeUtf8Hash(fullSignature);
281
282 /*
283 * Doing three levels of screening to see whether we want to skip
284 * compiling this method
285 */
286
287 /* First, check the full "class;method" signature */
288 bool methodFound =
289 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
290 fullSignature, (HashCompareFunc) strcmp,
291 false) !=
292 NULL;
293
294 /* Full signature not found - check the enclosing class */
295 if (methodFound == false) {
296 int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
297 methodFound =
298 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
299 (char *) desc->method->clazz->descriptor,
300 (HashCompareFunc) strcmp, false) !=
301 NULL;
302 /* Enclosing class not found - check the method name */
303 if (methodFound == false) {
304 int hashValue = dvmComputeUtf8Hash(desc->method->name);
305 methodFound =
306 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
307 (char *) desc->method->name,
308 (HashCompareFunc) strcmp, false) !=
309 NULL;
310 }
311 }
312
313 /*
314 * Under the following conditions, the trace will be *conservatively*
315 * compiled by only containing single-step instructions to and from the
316 * interpreter.
317 * 1) If includeSelectedMethod == false, the method matches the full or
318 * partial signature stored in the hash table.
319 *
320 * 2) If includeSelectedMethod == true, the method does not match the
321 * full and partial signature stored in the hash table.
322 */
323 if (gDvmJit.includeSelectedMethod != methodFound) {
324 cUnit.allSingleStep = true;
325 } else {
326 /* Compile the trace as normal */
327
328 /* Print the method we cherry picked */
329 if (gDvmJit.includeSelectedMethod == true) {
330 cUnit.printMe = true;
331 }
332 }
333 }
334
335 /* Allocate the first basic block */
336 lastBB = startBB = curBB = dvmCompilerNewBB(DALVIK_BYTECODE);
337 curBB->startOffset = curOffset;
338 curBB->id = numBlocks++;
339
340 if (cUnit.printMe) {
341 LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n",
342 desc->method->name, curOffset);
343 }
344
Ben Cheng1efc9c52009-06-08 18:25:27 -0700345 /*
346 * Analyze the trace descriptor and include up to the maximal number
347 * of Dalvik instructions into the IR.
348 */
349 while (1) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700350 MIR *insn;
351 int width;
352 insn = dvmCompilerNew(sizeof(MIR),false);
353 insn->offset = curOffset;
354 width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
Ben Cheng8b258bf2009-06-24 17:27:07 -0700355
356 /* The trace should never incude instruction data */
357 assert(width);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700358 insn->width = width;
359 traceSize += width;
360 dvmCompilerAppendMIR(curBB, insn);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700361 cUnit.numInsts++;
362 /* Instruction limit reached - terminate the trace here */
363 if (cUnit.numInsts >= numMaxInsts) {
364 break;
365 }
366 if (--numInsts == 0) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700367 if (currRun->frag.runEnd) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700368 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700369 } else {
370 curBB = dvmCompilerNewBB(DALVIK_BYTECODE);
371 lastBB->next = curBB;
372 lastBB = curBB;
373 curBB->id = numBlocks++;
374 currRun++;
375 curOffset = currRun->frag.startOffset;
376 numInsts = currRun->frag.numInsts;
377 curBB->startOffset = curOffset;
378 codePtr = dexCode->insns + curOffset;
379 }
380 } else {
381 curOffset += width;
382 codePtr += width;
383 }
384 }
385
Ben Cheng8b258bf2009-06-24 17:27:07 -0700386 /* Convert # of half-word to bytes */
387 methodStats->compiledDalvikSize += traceSize * 2;
388
Ben Chengba4fc8b2009-06-01 13:00:29 -0700389 /*
390 * Now scan basic blocks containing real code to connect the
391 * taken/fallthrough links. Also create chaining cells for code not included
392 * in the trace.
393 */
394 for (curBB = startBB; curBB; curBB = curBB->next) {
395 MIR *lastInsn = curBB->lastMIRInsn;
396 /* Hit a pseudo block - exit the search now */
397 if (lastInsn == NULL) {
398 break;
399 }
400 curOffset = lastInsn->offset;
401 unsigned int targetOffset = curOffset;
402 unsigned int fallThroughOffset = curOffset + lastInsn->width;
403 bool isInvoke = false;
404 const Method *callee = NULL;
405
406 findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
407 &targetOffset, &isInvoke, &callee);
408
409 /* Link the taken and fallthrough blocks */
410 BasicBlock *searchBB;
411
412 /* No backward branch in the trace - start searching the next BB */
413 for (searchBB = curBB->next; searchBB; searchBB = searchBB->next) {
414 if (targetOffset == searchBB->startOffset) {
415 curBB->taken = searchBB;
416 }
417 if (fallThroughOffset == searchBB->startOffset) {
418 curBB->fallThrough = searchBB;
419 }
420 }
421
Ben Cheng1efc9c52009-06-08 18:25:27 -0700422 int flags = dexGetInstrFlags(gDvm.instrFlags,
423 lastInsn->dalvikInsn.opCode);
424
425 /*
426 * Some blocks are ended by non-control-flow-change instructions,
427 * currently only due to trace length constraint. In this case we need
428 * to generate an explicit branch at the end of the block to jump to
429 * the chaining cell.
430 */
431 curBB->needFallThroughBranch =
432 (flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
433 kInstrInvoke)) == 0;
434
Ben Chengba4fc8b2009-06-01 13:00:29 -0700435 /* Target block not included in the trace */
436 if (targetOffset != curOffset && curBB->taken == NULL) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700437 if (isInvoke) {
438 lastBB->next = dvmCompilerNewBB(CHAINING_CELL_INVOKE);
439 /* For unconditional branches, request a hot chaining cell */
440 } else {
441 lastBB->next = dvmCompilerNewBB(flags & kInstrUnconditional ?
442 CHAINING_CELL_HOT :
443 CHAINING_CELL_NORMAL);
444 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700445 lastBB = lastBB->next;
446 lastBB->id = numBlocks++;
447 if (isInvoke) {
448 lastBB->startOffset = 0;
449 lastBB->containingMethod = callee;
450 } else {
451 lastBB->startOffset = targetOffset;
452 }
453 curBB->taken = lastBB;
454 }
455
456 /* Fallthrough block not included in the trace */
457 if (!isUnconditionalBranch(lastInsn) && curBB->fallThrough == NULL) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700458 /*
459 * If the chaining cell is after an invoke or
460 * instruction that cannot change the control flow, request a hot
461 * chaining cell.
462 */
463 if (isInvoke || curBB->needFallThroughBranch) {
464 lastBB->next = dvmCompilerNewBB(CHAINING_CELL_HOT);
465 } else {
466 lastBB->next = dvmCompilerNewBB(CHAINING_CELL_NORMAL);
467 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700468 lastBB = lastBB->next;
469 lastBB->id = numBlocks++;
470 lastBB->startOffset = fallThroughOffset;
471 curBB->fallThrough = lastBB;
472 }
473 }
474
475 /* Now create a special block to host PC reconstruction code */
476 lastBB->next = dvmCompilerNewBB(PC_RECONSTRUCTION);
477 lastBB = lastBB->next;
478 lastBB->id = numBlocks++;
479
480 /* And one final block that publishes the PC and raise the exception */
481 lastBB->next = dvmCompilerNewBB(EXCEPTION_HANDLING);
482 lastBB = lastBB->next;
483 lastBB->id = numBlocks++;
484
485 if (cUnit.printMe) {
486 LOGD("TRACEINFO (%d): 0x%08x %s%s 0x%x %d of %d, %d blocks",
Ben Chenge9695e52009-06-16 16:11:47 -0700487 compilationId,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700488 (intptr_t) desc->method->insns,
489 desc->method->clazz->descriptor,
490 desc->method->name,
491 desc->trace[0].frag.startOffset,
492 traceSize,
493 dexCode->insnsSize,
494 numBlocks);
495 }
496
497 BasicBlock **blockList;
498
499 cUnit.method = desc->method;
500 cUnit.traceDesc = desc;
501 cUnit.numBlocks = numBlocks;
502 dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
503 blockList = cUnit.blockList =
504 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
505
506 int i;
507
508 for (i = 0, curBB = startBB; i < numBlocks; i++) {
509 blockList[i] = curBB;
510 curBB = curBB->next;
511 }
512 /* Make sure all blocks are added to the cUnit */
513 assert(curBB == NULL);
514
515 if (cUnit.printMe) {
516 dvmCompilerDumpCompilationUnit(&cUnit);
517 }
518
519 /* Convert MIR to LIR, etc. */
520 dvmCompilerMIR2LIR(&cUnit);
521
Ben Cheng1efc9c52009-06-08 18:25:27 -0700522 /* Convert LIR into machine code. */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700523 dvmCompilerAssembleLIR(&cUnit);
524
525 if (cUnit.printMe) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700526 if (cUnit.halveInstCount) {
527 LOGD("Assembler aborted");
528 } else {
529 dvmCompilerCodegenDump(&cUnit);
530 }
531 LOGD("End %s%s, %d Dalvik instructions",
532 desc->method->clazz->descriptor, desc->method->name,
533 cUnit.numInsts);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700534 }
535
536 /* Reset the compiler resource pool */
537 dvmCompilerArenaReset();
538
Ben Chenge9695e52009-06-16 16:11:47 -0700539 /* Free the bit vector tracking null-checked registers */
540 dvmFreeBitVector(cUnit.registerScoreboard.nullCheckedRegs);
541
Ben Cheng1efc9c52009-06-08 18:25:27 -0700542 /*
543 * Things have gone smoothly - publish the starting address of
544 * translation's entry point.
545 */
546 if (!cUnit.halveInstCount) {
Ben Cheng8b258bf2009-06-24 17:27:07 -0700547 methodStats->nativeSize += cUnit.totalSize;
Ben Cheng1efc9c52009-06-08 18:25:27 -0700548 return cUnit.baseAddr + cUnit.headerSize;
549
550 /* Halve the instruction count and retry again */
551 } else {
552 return dvmCompileTrace(desc, cUnit.numInsts / 2);
553 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700554}
555
556/*
557 * Similar to dvmCompileTrace, but the entity processed here is the whole
558 * method.
559 *
560 * TODO: implementation will be revisited when the trace builder can provide
561 * whole-method traces.
562 */
Ben Cheng8b258bf2009-06-24 17:27:07 -0700563void *dvmCompileMethod(const Method *method)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700564{
565 const DexCode *dexCode = dvmGetMethodCode(method);
566 const u2 *codePtr = dexCode->insns;
567 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
568 int blockID = 0;
569 unsigned int curOffset = 0;
570
571 BasicBlock *firstBlock = dvmCompilerNewBB(DALVIK_BYTECODE);
572 firstBlock->id = blockID++;
573
574 /* Allocate the bit-vector to track the beginning of basic blocks */
575 BitVector *bbStartAddr = dvmAllocBitVector(dexCode->insnsSize+1, false);
576 dvmSetBit(bbStartAddr, 0);
577
578 /*
579 * Sequentially go through every instruction first and put them in a single
580 * basic block. Identify block boundaries at the mean time.
581 */
582 while (codePtr < codeEnd) {
583 MIR *insn = dvmCompilerNew(sizeof(MIR), false);
584 insn->offset = curOffset;
585 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
586 bool isInvoke = false;
587 const Method *callee;
588 insn->width = width;
589
Ben Cheng8b258bf2009-06-24 17:27:07 -0700590 /* Terminate when the data section is seen */
591 if (width == 0)
592 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700593 dvmCompilerAppendMIR(firstBlock, insn);
594 /*
595 * Check whether this is a block ending instruction and whether it
596 * suggests the start of a new block
597 */
598 unsigned int target = curOffset;
599
600 /*
601 * If findBlockBoundary returns true, it means the current instruction
602 * is terminating the current block. If it is a branch, the target
603 * address will be recorded in target.
604 */
605 if (findBlockBoundary(method, insn, curOffset, &target, &isInvoke,
606 &callee)) {
607 dvmSetBit(bbStartAddr, curOffset + width);
608 if (target != curOffset) {
609 dvmSetBit(bbStartAddr, target);
610 }
611 }
612
613 codePtr += width;
614 /* each bit represents 16-bit quantity */
615 curOffset += width;
616 }
617
618 /*
619 * The number of blocks will be equal to the number of bits set to 1 in the
620 * bit vector minus 1, because the bit representing the location after the
621 * last instruction is set to one.
622 */
623 int numBlocks = dvmCountSetBits(bbStartAddr);
624 if (dvmIsBitSet(bbStartAddr, dexCode->insnsSize)) {
625 numBlocks--;
626 }
627
628 CompilationUnit cUnit;
629 BasicBlock **blockList;
630
631 memset(&cUnit, 0, sizeof(CompilationUnit));
632 cUnit.method = method;
633 blockList = cUnit.blockList =
634 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
635
636 /*
637 * Register the first block onto the list and start split it into block
638 * boundaries from there.
639 */
640 blockList[0] = firstBlock;
641 cUnit.numBlocks = 1;
642
643 int i;
644 for (i = 0; i < numBlocks; i++) {
645 MIR *insn;
646 BasicBlock *curBB = blockList[i];
647 curOffset = curBB->lastMIRInsn->offset;
648
649 for (insn = curBB->firstMIRInsn->next; insn; insn = insn->next) {
650 /* Found the beginning of a new block, see if it is created yet */
651 if (dvmIsBitSet(bbStartAddr, insn->offset)) {
652 int j;
653 for (j = 0; j < cUnit.numBlocks; j++) {
654 if (blockList[j]->firstMIRInsn->offset == insn->offset)
655 break;
656 }
657
658 /* Block not split yet - do it now */
659 if (j == cUnit.numBlocks) {
660 BasicBlock *newBB = dvmCompilerNewBB(DALVIK_BYTECODE);
661 newBB->id = blockID++;
662 newBB->firstMIRInsn = insn;
Ben Cheng8b258bf2009-06-24 17:27:07 -0700663 newBB->startOffset = insn->offset;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700664 newBB->lastMIRInsn = curBB->lastMIRInsn;
665 curBB->lastMIRInsn = insn->prev;
666 insn->prev->next = NULL;
667 insn->prev = NULL;
668
669 /*
670 * If the insn is not an unconditional branch, set up the
671 * fallthrough link.
672 */
673 if (!isUnconditionalBranch(curBB->lastMIRInsn)) {
674 curBB->fallThrough = newBB;
675 }
676
677 /* enqueue the new block */
678 blockList[cUnit.numBlocks++] = newBB;
679 break;
680 }
681 }
682 }
683 }
684
685 if (numBlocks != cUnit.numBlocks) {
686 LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit.numBlocks);
687 dvmAbort();
688 }
689
690 dvmFreeBitVector(bbStartAddr);
691
692 /* Connect the basic blocks through the taken links */
693 for (i = 0; i < numBlocks; i++) {
694 BasicBlock *curBB = blockList[i];
695 MIR *insn = curBB->lastMIRInsn;
696 unsigned int target = insn->offset;
697 bool isInvoke;
698 const Method *callee;
699
700 findBlockBoundary(method, insn, target, &target, &isInvoke, &callee);
701
702 /* Found a block ended on a branch */
703 if (target != insn->offset) {
704 int j;
705 /* Forward branch */
706 if (target > insn->offset) {
707 j = i + 1;
708 } else {
709 /* Backward branch */
710 j = 0;
711 }
712 for (; j < numBlocks; j++) {
713 if (blockList[j]->firstMIRInsn->offset == target) {
714 curBB->taken = blockList[j];
715 break;
716 }
717 }
718
Ben Cheng8b258bf2009-06-24 17:27:07 -0700719 /* Don't create dummy block for the callee yet */
720 if (j == numBlocks && !isInvoke) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700721 LOGE("Target not found for insn %x: expect target %x\n",
722 curBB->lastMIRInsn->offset, target);
723 dvmAbort();
724 }
725 }
726 }
727
728 dvmCompilerMIR2LIR(&cUnit);
729
730 dvmCompilerAssembleLIR(&cUnit);
731
732 dvmCompilerDumpCompilationUnit(&cUnit);
733
734 dvmCompilerArenaReset();
735
Ben Cheng1efc9c52009-06-08 18:25:27 -0700736 return cUnit.baseAddr + cUnit.headerSize;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700737}