blob: 5e75d15f085cd50c516c2f60fc465e0ba960cf42 [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
209 /* Identify traces that we don't want to compile */
210 if (gDvmJit.methodTable) {
211 int len = strlen(desc->method->clazz->descriptor) +
212 strlen(desc->method->name) + 1;
213 char *fullSignature = dvmCompilerNew(len, true);
214 strcpy(fullSignature, desc->method->clazz->descriptor);
215 strcat(fullSignature, desc->method->name);
216
217 int hashValue = dvmComputeUtf8Hash(fullSignature);
218
219 /*
220 * Doing three levels of screening to see whether we want to skip
221 * compiling this method
222 */
223
224 /* First, check the full "class;method" signature */
225 bool methodFound =
226 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
227 fullSignature, (HashCompareFunc) strcmp,
228 false) !=
229 NULL;
230
231 /* Full signature not found - check the enclosing class */
232 if (methodFound == false) {
233 int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
234 methodFound =
235 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
236 (char *) desc->method->clazz->descriptor,
237 (HashCompareFunc) strcmp, false) !=
238 NULL;
239 /* Enclosing class not found - check the method name */
240 if (methodFound == false) {
241 int hashValue = dvmComputeUtf8Hash(desc->method->name);
242 methodFound =
243 dvmHashTableLookup(gDvmJit.methodTable, hashValue,
244 (char *) desc->method->name,
245 (HashCompareFunc) strcmp, false) !=
246 NULL;
247 }
248 }
249
250 /*
251 * Under the following conditions, the trace will be *conservatively*
252 * compiled by only containing single-step instructions to and from the
253 * interpreter.
254 * 1) If includeSelectedMethod == false, the method matches the full or
255 * partial signature stored in the hash table.
256 *
257 * 2) If includeSelectedMethod == true, the method does not match the
258 * full and partial signature stored in the hash table.
259 */
260 if (gDvmJit.includeSelectedMethod != methodFound) {
261 cUnit.allSingleStep = true;
262 } else {
263 /* Compile the trace as normal */
264
265 /* Print the method we cherry picked */
266 if (gDvmJit.includeSelectedMethod == true) {
267 cUnit.printMe = true;
268 }
269 }
270 }
271
272 /* Allocate the first basic block */
273 lastBB = startBB = curBB = dvmCompilerNewBB(DALVIK_BYTECODE);
274 curBB->startOffset = curOffset;
275 curBB->id = numBlocks++;
276
277 if (cUnit.printMe) {
278 LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n",
279 desc->method->name, curOffset);
280 }
281
Ben Cheng1efc9c52009-06-08 18:25:27 -0700282 /*
283 * Analyze the trace descriptor and include up to the maximal number
284 * of Dalvik instructions into the IR.
285 */
286 while (1) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700287 MIR *insn;
288 int width;
289 insn = dvmCompilerNew(sizeof(MIR),false);
290 insn->offset = curOffset;
291 width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
292 insn->width = width;
293 traceSize += width;
294 dvmCompilerAppendMIR(curBB, insn);
Ben Cheng1efc9c52009-06-08 18:25:27 -0700295 cUnit.numInsts++;
296 /* Instruction limit reached - terminate the trace here */
297 if (cUnit.numInsts >= numMaxInsts) {
298 break;
299 }
300 if (--numInsts == 0) {
Ben Chengba4fc8b2009-06-01 13:00:29 -0700301 if (currRun->frag.runEnd) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700302 break;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700303 } else {
304 curBB = dvmCompilerNewBB(DALVIK_BYTECODE);
305 lastBB->next = curBB;
306 lastBB = curBB;
307 curBB->id = numBlocks++;
308 currRun++;
309 curOffset = currRun->frag.startOffset;
310 numInsts = currRun->frag.numInsts;
311 curBB->startOffset = curOffset;
312 codePtr = dexCode->insns + curOffset;
313 }
314 } else {
315 curOffset += width;
316 codePtr += width;
317 }
318 }
319
320 /*
321 * Now scan basic blocks containing real code to connect the
322 * taken/fallthrough links. Also create chaining cells for code not included
323 * in the trace.
324 */
325 for (curBB = startBB; curBB; curBB = curBB->next) {
326 MIR *lastInsn = curBB->lastMIRInsn;
327 /* Hit a pseudo block - exit the search now */
328 if (lastInsn == NULL) {
329 break;
330 }
331 curOffset = lastInsn->offset;
332 unsigned int targetOffset = curOffset;
333 unsigned int fallThroughOffset = curOffset + lastInsn->width;
334 bool isInvoke = false;
335 const Method *callee = NULL;
336
337 findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
338 &targetOffset, &isInvoke, &callee);
339
340 /* Link the taken and fallthrough blocks */
341 BasicBlock *searchBB;
342
343 /* No backward branch in the trace - start searching the next BB */
344 for (searchBB = curBB->next; searchBB; searchBB = searchBB->next) {
345 if (targetOffset == searchBB->startOffset) {
346 curBB->taken = searchBB;
347 }
348 if (fallThroughOffset == searchBB->startOffset) {
349 curBB->fallThrough = searchBB;
350 }
351 }
352
Ben Cheng1efc9c52009-06-08 18:25:27 -0700353 int flags = dexGetInstrFlags(gDvm.instrFlags,
354 lastInsn->dalvikInsn.opCode);
355
356 /*
357 * Some blocks are ended by non-control-flow-change instructions,
358 * currently only due to trace length constraint. In this case we need
359 * to generate an explicit branch at the end of the block to jump to
360 * the chaining cell.
361 */
362 curBB->needFallThroughBranch =
363 (flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
364 kInstrInvoke)) == 0;
365
Ben Chengba4fc8b2009-06-01 13:00:29 -0700366 /* Target block not included in the trace */
367 if (targetOffset != curOffset && curBB->taken == NULL) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700368 if (isInvoke) {
369 lastBB->next = dvmCompilerNewBB(CHAINING_CELL_INVOKE);
370 /* For unconditional branches, request a hot chaining cell */
371 } else {
372 lastBB->next = dvmCompilerNewBB(flags & kInstrUnconditional ?
373 CHAINING_CELL_HOT :
374 CHAINING_CELL_NORMAL);
375 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700376 lastBB = lastBB->next;
377 lastBB->id = numBlocks++;
378 if (isInvoke) {
379 lastBB->startOffset = 0;
380 lastBB->containingMethod = callee;
381 } else {
382 lastBB->startOffset = targetOffset;
383 }
384 curBB->taken = lastBB;
385 }
386
387 /* Fallthrough block not included in the trace */
388 if (!isUnconditionalBranch(lastInsn) && curBB->fallThrough == NULL) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700389 /*
390 * If the chaining cell is after an invoke or
391 * instruction that cannot change the control flow, request a hot
392 * chaining cell.
393 */
394 if (isInvoke || curBB->needFallThroughBranch) {
395 lastBB->next = dvmCompilerNewBB(CHAINING_CELL_HOT);
396 } else {
397 lastBB->next = dvmCompilerNewBB(CHAINING_CELL_NORMAL);
398 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700399 lastBB = lastBB->next;
400 lastBB->id = numBlocks++;
401 lastBB->startOffset = fallThroughOffset;
402 curBB->fallThrough = lastBB;
403 }
404 }
405
406 /* Now create a special block to host PC reconstruction code */
407 lastBB->next = dvmCompilerNewBB(PC_RECONSTRUCTION);
408 lastBB = lastBB->next;
409 lastBB->id = numBlocks++;
410
411 /* And one final block that publishes the PC and raise the exception */
412 lastBB->next = dvmCompilerNewBB(EXCEPTION_HANDLING);
413 lastBB = lastBB->next;
414 lastBB->id = numBlocks++;
415
416 if (cUnit.printMe) {
417 LOGD("TRACEINFO (%d): 0x%08x %s%s 0x%x %d of %d, %d blocks",
Ben Chenge9695e52009-06-16 16:11:47 -0700418 compilationId,
Ben Chengba4fc8b2009-06-01 13:00:29 -0700419 (intptr_t) desc->method->insns,
420 desc->method->clazz->descriptor,
421 desc->method->name,
422 desc->trace[0].frag.startOffset,
423 traceSize,
424 dexCode->insnsSize,
425 numBlocks);
426 }
427
428 BasicBlock **blockList;
429
430 cUnit.method = desc->method;
431 cUnit.traceDesc = desc;
432 cUnit.numBlocks = numBlocks;
433 dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
434 blockList = cUnit.blockList =
435 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
436
437 int i;
438
439 for (i = 0, curBB = startBB; i < numBlocks; i++) {
440 blockList[i] = curBB;
441 curBB = curBB->next;
442 }
443 /* Make sure all blocks are added to the cUnit */
444 assert(curBB == NULL);
445
446 if (cUnit.printMe) {
447 dvmCompilerDumpCompilationUnit(&cUnit);
448 }
449
450 /* Convert MIR to LIR, etc. */
451 dvmCompilerMIR2LIR(&cUnit);
452
Ben Cheng1efc9c52009-06-08 18:25:27 -0700453 /* Convert LIR into machine code. */
Ben Chengba4fc8b2009-06-01 13:00:29 -0700454 dvmCompilerAssembleLIR(&cUnit);
455
456 if (cUnit.printMe) {
Ben Cheng1efc9c52009-06-08 18:25:27 -0700457 if (cUnit.halveInstCount) {
458 LOGD("Assembler aborted");
459 } else {
460 dvmCompilerCodegenDump(&cUnit);
461 }
462 LOGD("End %s%s, %d Dalvik instructions",
463 desc->method->clazz->descriptor, desc->method->name,
464 cUnit.numInsts);
Ben Chengba4fc8b2009-06-01 13:00:29 -0700465 }
466
467 /* Reset the compiler resource pool */
468 dvmCompilerArenaReset();
469
Ben Chenge9695e52009-06-16 16:11:47 -0700470 /* Free the bit vector tracking null-checked registers */
471 dvmFreeBitVector(cUnit.registerScoreboard.nullCheckedRegs);
472
Ben Cheng1efc9c52009-06-08 18:25:27 -0700473 /*
474 * Things have gone smoothly - publish the starting address of
475 * translation's entry point.
476 */
477 if (!cUnit.halveInstCount) {
478 return cUnit.baseAddr + cUnit.headerSize;
479
480 /* Halve the instruction count and retry again */
481 } else {
482 return dvmCompileTrace(desc, cUnit.numInsts / 2);
483 }
Ben Chengba4fc8b2009-06-01 13:00:29 -0700484}
485
486/*
487 * Similar to dvmCompileTrace, but the entity processed here is the whole
488 * method.
489 *
490 * TODO: implementation will be revisited when the trace builder can provide
491 * whole-method traces.
492 */
493void *dvmCompileMethod(Method *method)
494{
495 const DexCode *dexCode = dvmGetMethodCode(method);
496 const u2 *codePtr = dexCode->insns;
497 const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
498 int blockID = 0;
499 unsigned int curOffset = 0;
500
501 BasicBlock *firstBlock = dvmCompilerNewBB(DALVIK_BYTECODE);
502 firstBlock->id = blockID++;
503
504 /* Allocate the bit-vector to track the beginning of basic blocks */
505 BitVector *bbStartAddr = dvmAllocBitVector(dexCode->insnsSize+1, false);
506 dvmSetBit(bbStartAddr, 0);
507
508 /*
509 * Sequentially go through every instruction first and put them in a single
510 * basic block. Identify block boundaries at the mean time.
511 */
512 while (codePtr < codeEnd) {
513 MIR *insn = dvmCompilerNew(sizeof(MIR), false);
514 insn->offset = curOffset;
515 int width = parseInsn(codePtr, &insn->dalvikInsn, false);
516 bool isInvoke = false;
517 const Method *callee;
518 insn->width = width;
519
520 dvmCompilerAppendMIR(firstBlock, insn);
521 /*
522 * Check whether this is a block ending instruction and whether it
523 * suggests the start of a new block
524 */
525 unsigned int target = curOffset;
526
527 /*
528 * If findBlockBoundary returns true, it means the current instruction
529 * is terminating the current block. If it is a branch, the target
530 * address will be recorded in target.
531 */
532 if (findBlockBoundary(method, insn, curOffset, &target, &isInvoke,
533 &callee)) {
534 dvmSetBit(bbStartAddr, curOffset + width);
535 if (target != curOffset) {
536 dvmSetBit(bbStartAddr, target);
537 }
538 }
539
540 codePtr += width;
541 /* each bit represents 16-bit quantity */
542 curOffset += width;
543 }
544
545 /*
546 * The number of blocks will be equal to the number of bits set to 1 in the
547 * bit vector minus 1, because the bit representing the location after the
548 * last instruction is set to one.
549 */
550 int numBlocks = dvmCountSetBits(bbStartAddr);
551 if (dvmIsBitSet(bbStartAddr, dexCode->insnsSize)) {
552 numBlocks--;
553 }
554
555 CompilationUnit cUnit;
556 BasicBlock **blockList;
557
558 memset(&cUnit, 0, sizeof(CompilationUnit));
559 cUnit.method = method;
560 blockList = cUnit.blockList =
561 dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
562
563 /*
564 * Register the first block onto the list and start split it into block
565 * boundaries from there.
566 */
567 blockList[0] = firstBlock;
568 cUnit.numBlocks = 1;
569
570 int i;
571 for (i = 0; i < numBlocks; i++) {
572 MIR *insn;
573 BasicBlock *curBB = blockList[i];
574 curOffset = curBB->lastMIRInsn->offset;
575
576 for (insn = curBB->firstMIRInsn->next; insn; insn = insn->next) {
577 /* Found the beginning of a new block, see if it is created yet */
578 if (dvmIsBitSet(bbStartAddr, insn->offset)) {
579 int j;
580 for (j = 0; j < cUnit.numBlocks; j++) {
581 if (blockList[j]->firstMIRInsn->offset == insn->offset)
582 break;
583 }
584
585 /* Block not split yet - do it now */
586 if (j == cUnit.numBlocks) {
587 BasicBlock *newBB = dvmCompilerNewBB(DALVIK_BYTECODE);
588 newBB->id = blockID++;
589 newBB->firstMIRInsn = insn;
590 newBB->lastMIRInsn = curBB->lastMIRInsn;
591 curBB->lastMIRInsn = insn->prev;
592 insn->prev->next = NULL;
593 insn->prev = NULL;
594
595 /*
596 * If the insn is not an unconditional branch, set up the
597 * fallthrough link.
598 */
599 if (!isUnconditionalBranch(curBB->lastMIRInsn)) {
600 curBB->fallThrough = newBB;
601 }
602
603 /* enqueue the new block */
604 blockList[cUnit.numBlocks++] = newBB;
605 break;
606 }
607 }
608 }
609 }
610
611 if (numBlocks != cUnit.numBlocks) {
612 LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit.numBlocks);
613 dvmAbort();
614 }
615
616 dvmFreeBitVector(bbStartAddr);
617
618 /* Connect the basic blocks through the taken links */
619 for (i = 0; i < numBlocks; i++) {
620 BasicBlock *curBB = blockList[i];
621 MIR *insn = curBB->lastMIRInsn;
622 unsigned int target = insn->offset;
623 bool isInvoke;
624 const Method *callee;
625
626 findBlockBoundary(method, insn, target, &target, &isInvoke, &callee);
627
628 /* Found a block ended on a branch */
629 if (target != insn->offset) {
630 int j;
631 /* Forward branch */
632 if (target > insn->offset) {
633 j = i + 1;
634 } else {
635 /* Backward branch */
636 j = 0;
637 }
638 for (; j < numBlocks; j++) {
639 if (blockList[j]->firstMIRInsn->offset == target) {
640 curBB->taken = blockList[j];
641 break;
642 }
643 }
644
645 if (j == numBlocks) {
646 LOGE("Target not found for insn %x: expect target %x\n",
647 curBB->lastMIRInsn->offset, target);
648 dvmAbort();
649 }
650 }
651 }
652
653 dvmCompilerMIR2LIR(&cUnit);
654
655 dvmCompilerAssembleLIR(&cUnit);
656
657 dvmCompilerDumpCompilationUnit(&cUnit);
658
659 dvmCompilerArenaReset();
660
Ben Cheng1efc9c52009-06-08 18:25:27 -0700661 return cUnit.baseAddr + cUnit.headerSize;
Ben Chengba4fc8b2009-06-01 13:00:29 -0700662}