blob: c8f3abc0142220bf782f94dba7caa4f7f05a0f08 [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
33 // Need to check if this is a real NOP or a pseudo opcode
34 if (opcode == OP_NOP && instr != 0) {
35 if (instr == kPackedSwitchSignature) {
36 insnWidth = 4 + codePtr[1] * 2;
37 } else if (instr == kSparseSwitchSignature) {
38 insnWidth = 2 + codePtr[1] * 4;
39 } else if (instr == kArrayDataSignature) {
40 int width = codePtr[1];
41 int size = codePtr[2] | (codePtr[3] << 16);
42 // The plus 1 is to round up for odd size and width
43 insnWidth = 4 + ((size * width) + 1) / 2;
44 }
45 insnWidth = 0;
46 } else {
47 insnWidth = gDvm.instrWidth[opcode];
48 if (insnWidth < 0) {
49 insnWidth = -insnWidth;
50 }
51 }
52
53 dexDecodeInstruction(gDvm.instrFormat, codePtr, decInsn);
54 if (printMe) {
55 LOGD("%p: %#06x %s\n", codePtr, opcode, getOpcodeName(opcode));
56 }
57 return insnWidth;
58}
59
60/*
61 * Identify block-ending instructions and collect supplemental information
62 * regarding the following instructions.
63 */
64static inline bool findBlockBoundary(const Method *caller, MIR *insn,
65 unsigned int curOffset,
66 unsigned int *target, bool *isInvoke,
67 const Method **callee)
68{
69 switch (insn->dalvikInsn.opCode) {
70 /* Target is not compile-time constant */
71 case OP_RETURN_VOID:
72 case OP_RETURN:
73 case OP_RETURN_WIDE:
74 case OP_RETURN_OBJECT:
75 case OP_THROW:
76 case OP_INVOKE_VIRTUAL:
77 case OP_INVOKE_VIRTUAL_RANGE:
78 case OP_INVOKE_INTERFACE:
79 case OP_INVOKE_INTERFACE_RANGE:
80 case OP_INVOKE_VIRTUAL_QUICK:
81 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
82 *isInvoke = true;
83 break;
84 case OP_INVOKE_SUPER:
85 case OP_INVOKE_SUPER_RANGE: {
86 int mIndex = caller->clazz->pDvmDex->
87 pResMethods[insn->dalvikInsn.vB]->methodIndex;
88 const Method *calleeMethod =
89 caller->clazz->super->vtable[mIndex];
90
91 if (!dvmIsNativeMethod(calleeMethod)) {
92 *target = (unsigned int) calleeMethod->insns;
93 }
94 *isInvoke = true;
95 *callee = calleeMethod;
96 break;
97 }
98 case OP_INVOKE_STATIC:
99 case OP_INVOKE_STATIC_RANGE: {
100 const Method *calleeMethod =
101 caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
102
103 if (!dvmIsNativeMethod(calleeMethod)) {
104 *target = (unsigned int) calleeMethod->insns;
105 }
106 *isInvoke = true;
107 *callee = calleeMethod;
108 break;
109 }
110 case OP_INVOKE_SUPER_QUICK:
111 case OP_INVOKE_SUPER_QUICK_RANGE: {
112 const Method *calleeMethod =
113 caller->clazz->super->vtable[insn->dalvikInsn.vB];
114
115 if (!dvmIsNativeMethod(calleeMethod)) {
116 *target = (unsigned int) calleeMethod->insns;
117 }
118 *isInvoke = true;
119 *callee = calleeMethod;
120 break;
121 }
122 case OP_INVOKE_DIRECT:
123 case OP_INVOKE_DIRECT_RANGE: {
124 const Method *calleeMethod =
125 caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
126 if (!dvmIsNativeMethod(calleeMethod)) {
127 *target = (unsigned int) calleeMethod->insns;
128 }
129 *isInvoke = true;
130 *callee = calleeMethod;
131 break;
132 }
133 case OP_GOTO:
134 case OP_GOTO_16:
135 case OP_GOTO_32:
136 *target = curOffset + (int) insn->dalvikInsn.vA;
137 break;
138
139 case OP_IF_EQ:
140 case OP_IF_NE:
141 case OP_IF_LT:
142 case OP_IF_GE:
143 case OP_IF_GT:
144 case OP_IF_LE:
145 *target = curOffset + (int) insn->dalvikInsn.vC;
146 break;
147
148 case OP_IF_EQZ:
149 case OP_IF_NEZ:
150 case OP_IF_LTZ:
151 case OP_IF_GEZ:
152 case OP_IF_GTZ:
153 case OP_IF_LEZ:
154 *target = curOffset + (int) insn->dalvikInsn.vB;
155 break;
156
157 default:
158 return false;
159 } return true;
160}
161
162/*
163 * Identify conditional branch instructions
164 */
165static inline bool isUnconditionalBranch(MIR *insn)
166{
167 switch (insn->dalvikInsn.opCode) {
168 case OP_RETURN_VOID:
169 case OP_RETURN:
170 case OP_RETURN_WIDE:
171 case OP_RETURN_OBJECT:
172 case OP_GOTO:
173 case OP_GOTO_16:
174 case OP_GOTO_32:
175 return true;
176 default:
177 return false;
178 }
179}
180
181/*
182 * Main entry point to start trace compilation. Basic blocks are constructed
183 * first and they will be passed to the codegen routines to convert Dalvik
184 * bytecode into machine code.
185 */
Ben Cheng1efc9c52009-06-08 18:25:27 -0700186void *dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts)
Ben Chengba4fc8b2009-06-01 13:00:29 -0700187{
188 const DexCode *dexCode = dvmGetMethodCode(desc->method);
189 const JitTraceRun* currRun = &desc->trace[0];
Ben Chengba4fc8b2009-06-01 13:00:29 -0700190 unsigned int curOffset = currRun->frag.startOffset;
191 unsigned int numInsts = currRun->frag.numInsts;
192 const u2 *codePtr = dexCode->insns + curOffset;
193 int traceSize = 0;
194 const u2 *startCodePtr = codePtr;
195 BasicBlock *startBB, *curBB, *lastBB;
196 int numBlocks = 0;
197 static int compilationId;
198 CompilationUnit cUnit;
199 memset(&cUnit, 0, sizeof(CompilationUnit));
200
Ben Chenge9695e52009-06-16 16:11:47 -0700201 compilationId++;
202
203 cUnit.registerScoreboard.nullCheckedRegs =
204 dvmAllocBitVector(desc->method->registersSize, false);
205
Ben Chengba4fc8b2009-06-01 13:00:29 -0700206 /* Initialize the printMe flag */
207 cUnit.printMe = gDvmJit.printMe;
208
Bill Buzbee6e963e12009-06-17 16:56:19 -0700209 /* Initialize the profile flag */
210 cUnit.executionCount = gDvmJit.profile;
211
Ben Chengba4fc8b2009-06-01 13:00:29 -0700212 /* Identify traces that we don't want to compile */
213 if (gDvmJit.methodTable) {
214 int len = strlen(desc->method->clazz->descriptor) +
215 strlen(desc->method->name) + 1;
216 char *fullSignature = dvmCompilerNew(len, true);
217 strcpy(fullSignature, desc->method->clazz->descriptor);
218 strcat(fullSignature, desc->method->name);
219
220 int hashValue = dvmComputeUtf8Hash(fullSignature);
221
222 /*
223 * Doing three levels of screening to see whether we want to skip
224 * compiling this method
225 */
226
227 /* First, check the full "class;method" signature */
228 bool methodFound =
229 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
230 fullSignature, (HashCompareFunc) strcmp,
231 false) !=
232 NULL;
233
234 /* Full signature not found - check the enclosing class */
235 if (methodFound == false) {
236 int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
237 methodFound =
238 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
239 (char *) desc->method->clazz->descriptor,
240 (HashCompareFunc) strcmp, false) !=
241 NULL;
242 /* Enclosing class not found - check the method name */
243 if (methodFound == false) {
244 int hashValue = dvmComputeUtf8Hash(desc->method->name);
245 methodFound =
246 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
247 (char *) desc->method->name,
248 (HashCompareFunc) strcmp, false) !=
249 NULL;
250 }
251 }
252
253 /*
254 * Under the following conditions, the trace will be *conservatively*
255 * compiled by only containing single-step instructions to and from the
256 * interpreter.
257 * 1) If includeSelectedMethod == false, the method matches the full or
258 * partial signature stored in the hash table.
259 *
260 * 2) If includeSelectedMethod == true, the method does not match the
261 * full and partial signature stored in the hash table.
262 */
263 if (gDvmJit.includeSelectedMethod != methodFound) {
264 cUnit.allSingleStep = true;
265 } else {
266 /* Compile the trace as normal */
267
268 /* Print the method we cherry picked */
269 if (gDvmJit.includeSelectedMethod == true) {
270 cUnit.printMe = true;
271 }
272 }
273 }
274
275 /* Allocate the first basic block */
276 lastBB = startBB = curBB = dvmCompilerNewBB(DALVIK_BYTECODE);
277 curBB->startOffset = curOffset;
278 curBB->id = numBlocks++;
279
280 if (cUnit.printMe) {
281 LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n",
282 desc->method->name, curOffset);
283 }
284
Ben Cheng1efc9c52009-06-08 18:25:27 -0700285 /*
286 * Analyze the trace descriptor and include up to the maximal number
287 * of Dalvik instructions into the IR.
288 */
289 while (1) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700290 MIR *insn;
291 int width;
292 insn = dvmCompilerNew(sizeof(MIR),false);
293 insn->offset = curOffset;
294 width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
295 insn->width = width;
296 traceSize += width;
297 dvmCompilerAppendMIR(curBB, insn);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700298 cUnit.numInsts++;
299 /* Instruction limit reached - terminate the trace here */
300 if (cUnit.numInsts >= numMaxInsts) {
301 break;
302 }
303 if (--numInsts == 0) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700304 if (currRun->frag.runEnd) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700305 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700306 } else {
307 curBB = dvmCompilerNewBB(DALVIK_BYTECODE);
308 lastBB->next = curBB;
309 lastBB = curBB;
310 curBB->id = numBlocks++;
311 currRun++;
312 curOffset = currRun->frag.startOffset;
313 numInsts = currRun->frag.numInsts;
314 curBB->startOffset = curOffset;
315 codePtr = dexCode->insns + curOffset;
316 }
317 } else {
318 curOffset += width;
319 codePtr += width;
320 }
321 }
322
323 /*
324 * Now scan basic blocks containing real code to connect the
325 * taken/fallthrough links. Also create chaining cells for code not included
326 * in the trace.
327 */
328 for (curBB = startBB; curBB; curBB = curBB->next) {
329 MIR *lastInsn = curBB->lastMIRInsn;
330 /* Hit a pseudo block - exit the search now */
331 if (lastInsn == NULL) {
332 break;
333 }
334 curOffset = lastInsn->offset;
335 unsigned int targetOffset = curOffset;
336 unsigned int fallThroughOffset = curOffset + lastInsn->width;
337 bool isInvoke = false;
338 const Method *callee = NULL;
339
340 findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
341 &targetOffset, &isInvoke, &callee);
342
343 /* Link the taken and fallthrough blocks */
344 BasicBlock *searchBB;
345
346 /* No backward branch in the trace - start searching the next BB */
347 for (searchBB = curBB->next; searchBB; searchBB = searchBB->next) {
348 if (targetOffset == searchBB->startOffset) {
349 curBB->taken = searchBB;
350 }
351 if (fallThroughOffset == searchBB->startOffset) {
352 curBB->fallThrough = searchBB;
353 }
354 }
355
Ben Cheng1efc9c52009-06-08 18:25:27 -0700356 int flags = dexGetInstrFlags(gDvm.instrFlags,
357 lastInsn->dalvikInsn.opCode);
358
359 /*
360 * Some blocks are ended by non-control-flow-change instructions,
361 * currently only due to trace length constraint. In this case we need
362 * to generate an explicit branch at the end of the block to jump to
363 * the chaining cell.
364 */
365 curBB->needFallThroughBranch =
366 (flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
367 kInstrInvoke)) == 0;
368
Ben Chengba4fc8b2009-06-01 13:00:29 -0700369 /* Target block not included in the trace */
370 if (targetOffset != curOffset && curBB->taken == NULL) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700371 if (isInvoke) {
372 lastBB->next = dvmCompilerNewBB(CHAINING_CELL_INVOKE);
373 /* For unconditional branches, request a hot chaining cell */
374 } else {
375 lastBB->next = dvmCompilerNewBB(flags & kInstrUnconditional ?
376 CHAINING_CELL_HOT :
377 CHAINING_CELL_NORMAL);
378 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700379 lastBB = lastBB->next;
380 lastBB->id = numBlocks++;
381 if (isInvoke) {
382 lastBB->startOffset = 0;
383 lastBB->containingMethod = callee;
384 } else {
385 lastBB->startOffset = targetOffset;
386 }
387 curBB->taken = lastBB;
388 }
389
390 /* Fallthrough block not included in the trace */
391 if (!isUnconditionalBranch(lastInsn) && curBB->fallThrough == NULL) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700392 /*
393 * If the chaining cell is after an invoke or
394 * instruction that cannot change the control flow, request a hot
395 * chaining cell.
396 */
397 if (isInvoke || curBB->needFallThroughBranch) {
398 lastBB->next = dvmCompilerNewBB(CHAINING_CELL_HOT);
399 } else {
400 lastBB->next = dvmCompilerNewBB(CHAINING_CELL_NORMAL);
401 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700402 lastBB = lastBB->next;
403 lastBB->id = numBlocks++;
404 lastBB->startOffset = fallThroughOffset;
405 curBB->fallThrough = lastBB;
406 }
407 }
408
409 /* Now create a special block to host PC reconstruction code */
410 lastBB->next = dvmCompilerNewBB(PC_RECONSTRUCTION);
411 lastBB = lastBB->next;
412 lastBB->id = numBlocks++;
413
414 /* And one final block that publishes the PC and raise the exception */
415 lastBB->next = dvmCompilerNewBB(EXCEPTION_HANDLING);
416 lastBB = lastBB->next;
417 lastBB->id = numBlocks++;
418
419 if (cUnit.printMe) {
420 LOGD("TRACEINFO (%d): 0x%08x %s%s 0x%x %d of %d, %d blocks",
Ben Chenge9695e52009-06-16 16:11:47 -0700421 compilationId,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700422 (intptr_t) desc->method->insns,
423 desc->method->clazz->descriptor,
424 desc->method->name,
425 desc->trace[0].frag.startOffset,
426 traceSize,
427 dexCode->insnsSize,
428 numBlocks);
429 }
430
431 BasicBlock **blockList;
432
433 cUnit.method = desc->method;
434 cUnit.traceDesc = desc;
435 cUnit.numBlocks = numBlocks;
436 dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
437 blockList = cUnit.blockList =
438 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
439
440 int i;
441
442 for (i = 0, curBB = startBB; i < numBlocks; i++) {
443 blockList[i] = curBB;
444 curBB = curBB->next;
445 }
446 /* Make sure all blocks are added to the cUnit */
447 assert(curBB == NULL);
448
449 if (cUnit.printMe) {
450 dvmCompilerDumpCompilationUnit(&cUnit);
451 }
452
453 /* Convert MIR to LIR, etc. */
454 dvmCompilerMIR2LIR(&cUnit);
455
Ben Cheng1efc9c52009-06-08 18:25:27 -0700456 /* Convert LIR into machine code. */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700457 dvmCompilerAssembleLIR(&cUnit);
458
459 if (cUnit.printMe) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700460 if (cUnit.halveInstCount) {
461 LOGD("Assembler aborted");
462 } else {
463 dvmCompilerCodegenDump(&cUnit);
464 }
465 LOGD("End %s%s, %d Dalvik instructions",
466 desc->method->clazz->descriptor, desc->method->name,
467 cUnit.numInsts);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700468 }
469
470 /* Reset the compiler resource pool */
471 dvmCompilerArenaReset();
472
Ben Chenge9695e52009-06-16 16:11:47 -0700473 /* Free the bit vector tracking null-checked registers */
474 dvmFreeBitVector(cUnit.registerScoreboard.nullCheckedRegs);
475
Ben Cheng1efc9c52009-06-08 18:25:27 -0700476 /*
477 * Things have gone smoothly - publish the starting address of
478 * translation's entry point.
479 */
480 if (!cUnit.halveInstCount) {
481 return cUnit.baseAddr + cUnit.headerSize;
482
483 /* Halve the instruction count and retry again */
484 } else {
485 return dvmCompileTrace(desc, cUnit.numInsts / 2);
486 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700487}
488
489/*
490 * Similar to dvmCompileTrace, but the entity processed here is the whole
491 * method.
492 *
493 * TODO: implementation will be revisited when the trace builder can provide
494 * whole-method traces.
495 */
496void *dvmCompileMethod(Method *method)
497{
498 const DexCode *dexCode = dvmGetMethodCode(method);
499 const u2 *codePtr = dexCode->insns;
500 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
501 int blockID = 0;
502 unsigned int curOffset = 0;
503
504 BasicBlock *firstBlock = dvmCompilerNewBB(DALVIK_BYTECODE);
505 firstBlock->id = blockID++;
506
507 /* Allocate the bit-vector to track the beginning of basic blocks */
508 BitVector *bbStartAddr = dvmAllocBitVector(dexCode->insnsSize+1, false);
509 dvmSetBit(bbStartAddr, 0);
510
511 /*
512 * Sequentially go through every instruction first and put them in a single
513 * basic block. Identify block boundaries at the mean time.
514 */
515 while (codePtr < codeEnd) {
516 MIR *insn = dvmCompilerNew(sizeof(MIR), false);
517 insn->offset = curOffset;
518 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
519 bool isInvoke = false;
520 const Method *callee;
521 insn->width = width;
522
523 dvmCompilerAppendMIR(firstBlock, insn);
524 /*
525 * Check whether this is a block ending instruction and whether it
526 * suggests the start of a new block
527 */
528 unsigned int target = curOffset;
529
530 /*
531 * If findBlockBoundary returns true, it means the current instruction
532 * is terminating the current block. If it is a branch, the target
533 * address will be recorded in target.
534 */
535 if (findBlockBoundary(method, insn, curOffset, &target, &isInvoke,
536 &callee)) {
537 dvmSetBit(bbStartAddr, curOffset + width);
538 if (target != curOffset) {
539 dvmSetBit(bbStartAddr, target);
540 }
541 }
542
543 codePtr += width;
544 /* each bit represents 16-bit quantity */
545 curOffset += width;
546 }
547
548 /*
549 * The number of blocks will be equal to the number of bits set to 1 in the
550 * bit vector minus 1, because the bit representing the location after the
551 * last instruction is set to one.
552 */
553 int numBlocks = dvmCountSetBits(bbStartAddr);
554 if (dvmIsBitSet(bbStartAddr, dexCode->insnsSize)) {
555 numBlocks--;
556 }
557
558 CompilationUnit cUnit;
559 BasicBlock **blockList;
560
561 memset(&cUnit, 0, sizeof(CompilationUnit));
562 cUnit.method = method;
563 blockList = cUnit.blockList =
564 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
565
566 /*
567 * Register the first block onto the list and start split it into block
568 * boundaries from there.
569 */
570 blockList[0] = firstBlock;
571 cUnit.numBlocks = 1;
572
573 int i;
574 for (i = 0; i < numBlocks; i++) {
575 MIR *insn;
576 BasicBlock *curBB = blockList[i];
577 curOffset = curBB->lastMIRInsn->offset;
578
579 for (insn = curBB->firstMIRInsn->next; insn; insn = insn->next) {
580 /* Found the beginning of a new block, see if it is created yet */
581 if (dvmIsBitSet(bbStartAddr, insn->offset)) {
582 int j;
583 for (j = 0; j < cUnit.numBlocks; j++) {
584 if (blockList[j]->firstMIRInsn->offset == insn->offset)
585 break;
586 }
587
588 /* Block not split yet - do it now */
589 if (j == cUnit.numBlocks) {
590 BasicBlock *newBB = dvmCompilerNewBB(DALVIK_BYTECODE);
591 newBB->id = blockID++;
592 newBB->firstMIRInsn = insn;
593 newBB->lastMIRInsn = curBB->lastMIRInsn;
594 curBB->lastMIRInsn = insn->prev;
595 insn->prev->next = NULL;
596 insn->prev = NULL;
597
598 /*
599 * If the insn is not an unconditional branch, set up the
600 * fallthrough link.
601 */
602 if (!isUnconditionalBranch(curBB->lastMIRInsn)) {
603 curBB->fallThrough = newBB;
604 }
605
606 /* enqueue the new block */
607 blockList[cUnit.numBlocks++] = newBB;
608 break;
609 }
610 }
611 }
612 }
613
614 if (numBlocks != cUnit.numBlocks) {
615 LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit.numBlocks);
616 dvmAbort();
617 }
618
619 dvmFreeBitVector(bbStartAddr);
620
621 /* Connect the basic blocks through the taken links */
622 for (i = 0; i < numBlocks; i++) {
623 BasicBlock *curBB = blockList[i];
624 MIR *insn = curBB->lastMIRInsn;
625 unsigned int target = insn->offset;
626 bool isInvoke;
627 const Method *callee;
628
629 findBlockBoundary(method, insn, target, &target, &isInvoke, &callee);
630
631 /* Found a block ended on a branch */
632 if (target != insn->offset) {
633 int j;
634 /* Forward branch */
635 if (target > insn->offset) {
636 j = i + 1;
637 } else {
638 /* Backward branch */
639 j = 0;
640 }
641 for (; j < numBlocks; j++) {
642 if (blockList[j]->firstMIRInsn->offset == target) {
643 curBB->taken = blockList[j];
644 break;
645 }
646 }
647
648 if (j == numBlocks) {
649 LOGE("Target not found for insn %x: expect target %x\n",
650 curBB->lastMIRInsn->offset, target);
651 dvmAbort();
652 }
653 }
654 }
655
656 dvmCompilerMIR2LIR(&cUnit);
657
658 dvmCompilerAssembleLIR(&cUnit);
659
660 dvmCompilerDumpCompilationUnit(&cUnit);
661
662 dvmCompilerArenaReset();
663
Ben Cheng1efc9c52009-06-08 18:25:27 -0700664 return cUnit.baseAddr + cUnit.headerSize;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700665}