/*
* 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)
{
}