/*
* Copyright (C) 2012 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.
*/
#include "Lower.h"
#include "NcgAot.h"
#include "NcgHelper.h"
//returns # of ops generated by this function
//entries relocatable: eip + relativePC
int get_eip_API() {
call("ncgGetEIP");//%edx //will push eip to stack
return 1;
}
#define NEW_EXPORT_PC
//!update current PC in the stack frame with %eip
//!
int export_pc() {
/* for trace-based JIT, pc points to bytecode
for NCG, pc points to native code */
move_imm_to_mem(OpndSize_32, (int)rPC,
-sizeofStackSaveArea+offStackSaveArea_localRefTop, PhysicalReg_FP, true);
return 1; //return number of ops
}
/* jump from JIT'ed code to interpreter without chaining */
int jumpToInterpNoChain() {
typedef void (*vmHelper)(int);
vmHelper funcPtr = dvmJitToInterpNoChain;
move_imm_to_reg(OpndSize_32, (int)funcPtr, C_SCRATCH_1, isScratchPhysical);
unconditional_jump_reg(C_SCRATCH_1, isScratchPhysical);
if(gDvm.executionMode == kExecutionModeNcgO1) touchEax();
return 0;
}
/* jump from JIT'ed code to interpreter becaues of exception */
int jumpToInterpPunt() {
typedef void (*vmHelper)(int);
vmHelper funcPtr = dvmJitToInterpPunt;
move_imm_to_reg(OpndSize_32, (int)funcPtr, C_SCRATCH_1, isScratchPhysical);
unconditional_jump_reg(C_SCRATCH_1, isScratchPhysical);
//if(gDvm.executionMode == kExecutionModeNcgO1) touchEax();
return 0;
}
/* jump to common_exceptionThrown from JIT'ed code */
int jumpToExceptionThrown(int exceptionNum) {
if(gDvm.executionMode == kExecutionModeNcgO1) {
rememberState(exceptionNum);
export_pc();
constVREndOfBB();
beforeCall("exception"); //dump GG, GL VRs
}
typedef void (*vmHelper)(int);
vmHelper funcPtr = dvmJitToExceptionThrown;
move_imm_to_reg(OpndSize_32, (int)funcPtr, C_SCRATCH_1, isScratchPhysical);
unconditional_jump_reg(C_SCRATCH_1, isScratchPhysical);
if(gDvm.executionMode == kExecutionModeNcgO1) {
goToState(exceptionNum);
}
return 0;
}
//! generate native code to call dvmNcgInvokeInterpreter
//!the interpreter will start execution from %eax
int invokeInterpreter(bool fromApp)
{
typedef void (*vmHelper)(int);
vmHelper funcPtr = dvmNcgInvokeInterpreter;
move_imm_to_reg(OpndSize_32, (int)funcPtr, C_SCRATCH_1, isScratchPhysical);
unconditional_jump_reg(C_SCRATCH_1, isScratchPhysical);
if(gDvm.executionMode == kExecutionModeNcgO1) touchEax();
return 0;
}
//!work to do before calling a function pointer with code cache enabled
//!
void callFuncPtr(int funcPtr, const char* funcName) {
move_imm_to_reg(OpndSize_32, (int)funcPtr, C_SCRATCH_1, isScratchPhysical);
call_reg(C_SCRATCH_1, isScratchPhysical);
}
//.const_string_resolve: input in %eax, output in %eax
//.const_string_helper:
//.class_resolve: input in %eax, output in %eax
int call_helper_API(const char* helperName) {
call(helperName);
return 1;
}
/* check whether we are throwing an exception */
bool jumpToException(const char* target) {
bool isException = false;
if(!strncmp(target, "common_err", 10)) isException = true;
if(!strncmp(target, "common_throw", 12)) isException = true;
if(!strncmp(target, "common_exception", 16)) isException = true;
return isException;
}
int conditional_jump_global_API(
ConditionCode cc, const char* target,
bool isShortTerm) {
if(jumpToException(target) && currentExceptionBlockIdx >= 0) { //jump to the exceptionThrow block
condJumpToBasicBlock(stream, cc, currentExceptionBlockIdx);
return 1; //return number of ops
}
conditional_jump(cc, target, isShortTerm);
return 1;
}
int unconditional_jump_global_API(
const char* target, bool isShortTerm) {
if(jumpToException(target) && currentExceptionBlockIdx >= 0) { //jump to the exceptionThrow block
jumpToBasicBlock(stream, currentExceptionBlockIdx);
return 1; //return number of ops
}
unconditional_jump(target, isShortTerm);
return 1;
}
int getGlobalDataAddr(const char* dataName) {
int dataAddr = -1;
if(!strcmp(dataName, "doubNeg")) dataAddr = LdoubNeg;
else if(!strcmp(dataName, "intMax")) dataAddr = LintMax;
else if(!strcmp(dataName, "intMin")) dataAddr = LintMin;
else if(!strcmp(dataName, "valueNanLong")) dataAddr = LvalueNanLong;
else if(!strcmp(dataName, "valuePosInfLong")) dataAddr = LvaluePosInfLong;
else if(!strcmp(dataName, "valueNegInfLong")) dataAddr = LvalueNegInfLong;
else if(!strcmp(dataName, "shiftMask")) dataAddr = LshiftMask;
else if(!strcmp(dataName, "value64")) dataAddr = Lvalue64;
else if(!strcmp(dataName, "64bits")) dataAddr = L64bits;
else if(!strcmp(dataName, "strClassCastExceptionPtr")) dataAddr = LstrClassCastExceptionPtr;
else if(!strcmp(dataName, "strInstantiationError")) dataAddr = LstrInstantiationErrorPtr;
else if(!strcmp(dataName, "gDvmInlineOpsTable")) dataAddr = (int)gDvmInlineOpsTable;
else ALOGE("global data %s not supported", dataName);
return dataAddr;
}
//for shared code cache, we use scratchRegs[0] & [1]
int load_imm_global_data_API(const char* dataName,
OpndSize size,
int reg, bool isPhysical) {
//find the address from name
int dataAddr = getGlobalDataAddr(dataName);
move_imm_to_reg(size, dataAddr, reg, isPhysical);
return 0;
}
//for shared code cache, we use scratchRegs[0] & [1] & [2]
//FIXME: [2] is assumed to be hard-coded register
int load_global_data_API(const char* dataName,
OpndSize size,
int reg, bool isPhysical) {
//find the address from name
int dataAddr = getGlobalDataAddr(dataName);
move_mem_to_reg(size, dataAddr, PhysicalReg_Null, true, reg, isPhysical);
return 0;
}
int load_sd_global_data_API(const char* dataName,
int reg, bool isPhysical) {
//find the address from name
int dataAddr = getGlobalDataAddr(dataName);
move_sd_mem_to_reg(dataAddr, PhysicalReg_Null, true, reg, isPhysical);
return 0;
}
int load_fp_stack_global_data_API(const char* dataName,
OpndSize size) {
int dataAddr = getGlobalDataAddr(dataName);
load_int_fp_stack_imm(size, dataAddr); //fildl
return 0;
}