/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * This file contains codegen and support common to all supported * X86 variants. It is included by: * * Codegen-$(TARGET_ARCH_VARIANT).c * * which combines this common code with specific support found in the * applicable directory below this one. */ extern X86LIR *loadConstant(CompilationUnit *cUnit, int rDest, int value); extern X86LIR *loadWordDisp(CompilationUnit *cUnit, int rBase, int displacement, int rDest); extern void dvmCompilerFlushAllRegs(CompilationUnit *cUnit); extern void storeWordDisp(CompilationUnit *cUnit, int rBase, int displacement, int rSrc); extern X86LIR *opReg(CompilationUnit *cUnit, OpKind op, int rDestSrc); static int opcodeCoverage[kNumPackedOpcodes]; static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK]; #if 0 // Avoid compiler warnings when x86 disabled during development /* * Bail to the interpreter. Will not return to this trace. * On entry, rPC must be set correctly. */ static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset) { dvmCompilerFlushAllRegs(cUnit); loadConstant(cUnit, rPC, (int)(cUnit->method->insns + offset)); loadWordDisp(cUnit, rEBP, 0, rECX); // Get glue loadWordDisp(cUnit, rECX, offsetof(Thread, jitToInterpEntries.dvmJitToInterpPunt), rEAX); opReg(cUnit, kOpUncondBr, rEAX); } static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir) { int flags = dexGetFlagsFromOpcode(mir->dalvikInsn.opcode); int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn | kInstrCanThrow; //If already optimized out, just ignore if (mir->dalvikInsn.opcode == OP_NOP) return; //Ugly, but necessary. Flush all Dalvik regs so Interp can find them dvmCompilerFlushAllRegs(cUnit); if ((mir->next == NULL) || (flags & flagsToCheck)) { genPuntToInterp(cUnit, mir->offset); return; } int entryAddr = offsetof(Thread, jitToInterpEntries.dvmJitToInterpSingleStep); loadWordDisp(cUnit, rEBP, 0, rECX); // Get glue loadWordDisp(cUnit, rECX, entryAddr, rEAX); // rEAX<- entry address /* rPC = dalvik pc */ loadConstant(cUnit, rPC, (int) (cUnit->method->insns + mir->offset)); /* rECX = dalvik pc of following instruction */ loadConstant(cUnit, rECX, (int) (cUnit->method->insns + mir->next->offset)); /* Pass on the stack */ storeWordDisp(cUnit, rESP, OUT_ARG0, rECX); opReg(cUnit, kOpCall, rEAX); } #endif /* * The following are the first-level codegen routines that analyze the format * of each bytecode then either dispatch special purpose codegen routines * or produce corresponding Thumb instructions directly. */ #if 0 static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, X86LIR *labelList) { /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */ return true; } static bool handleFmt10x(CompilationUnit *cUnit, MIR *mir) { return true; } static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir) { return true; } static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir) { return true; } static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir) { return true; } static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir) { return true; } static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir) { return true; } static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir) { return true; } static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir) { return true; } static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, X86LIR *labelList) { return true; } static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir) { return true; } static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir) { return true; } static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir) { return true; } static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, X86LIR *labelList) { return true; } static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir) { return true; } static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir) { return true; } static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir) { return true; } static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, X86LIR *labelList) { return true; } static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb, X86LIR *labelList) { return true; } /* * NOTE: Handles both range and non-range versions (arguments * have already been normalized by this point). */ static bool handleExecuteInline(CompilationUnit *cUnit, MIR *mir) { return true; } static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir) { return true; } #endif void dvmCompilerMIR2LIR(CompilationUnit *cUnit) { } /* Accept the work and start compiling */ bool dvmCompilerDoWork(CompilerWorkOrder *work) { JitTraceDescription *desc; bool res; if (gDvmJit.codeCacheFull) { return false; } switch (work->kind) { case kWorkOrderTrace: /* Start compilation with maximally allowed trace length */ desc = (JitTraceDescription *)work->info; res = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result, work->bailPtr, 0 /* no hints */); break; case kWorkOrderTraceDebug: { bool oldPrintMe = gDvmJit.printMe; gDvmJit.printMe = true; /* Start compilation with maximally allowed trace length */ desc = (JitTraceDescription *)work->info; res = dvmCompileTrace(desc, JIT_MAX_TRACE_LEN, &work->result, work->bailPtr, 0 /* no hints */); gDvmJit.printMe = oldPrintMe; break; } default: res = false; ALOGE("Jit: unknown work order type"); assert(0); // Bail if debug build, discard otherwise } return res; } /* Architectural-specific debugging helpers go here */ void dvmCompilerArchDump(void) { /* Print compiled opcode in this VM instance */ int i, start, streak; char buf[1024]; streak = i = 0; buf[0] = 0; while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) { i++; } if (i == kNumPackedOpcodes) { return; } for (start = i++, streak = 1; i < kNumPackedOpcodes; i++) { if (opcodeCoverage[i]) { streak++; } else { if (streak == 1) { sprintf(buf+strlen(buf), "%x,", start); } else { sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1); } streak = 0; while (opcodeCoverage[i] == 0 && i < kNumPackedOpcodes) { i++; } if (i < kNumPackedOpcodes) { streak = 1; start = i; } } } if (streak) { if (streak == 1) { sprintf(buf+strlen(buf), "%x", start); } else { sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1); } } if (strlen(buf)) { ALOGD("dalvik.vm.jit.op = %s", buf); } } /* Common initialization routine for an architecture family */ bool dvmCompilerArchInit() { return dvmCompilerArchVariantInit(); } void *dvmCompilerGetInterpretTemplate() { return (void*) ((int)gDvmJit.codeCache + templateEntryOffsets[TEMPLATE_INTERPRET]); } JitInstructionSetType dvmCompilerGetInterpretTemplateSet() { return DALVIK_JIT_X86; } void dvmCompilerInitializeRegAlloc(CompilationUnit *cUnit) { }