blob: d0e7f92fc07464d98239e67edea59ebc7cfabe76 [file] [log] [blame]
/*
* 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.
*/
/*! \file Lower.cpp
\brief This file implements the high-level wrapper for lowering
*/
//#include "uthash.h"
#include "libdex/DexOpcodes.h"
#include "libdex/DexFile.h"
#include <math.h>
#include <sys/mman.h>
#include "Translator.h"
#include "Lower.h"
#include "enc_wrapper.h"
#include "vm/mterp/Mterp.h"
#include "NcgHelper.h"
#include "libdex/DexCatch.h"
#include "compiler/CompilerIR.h"
//statistics for optimization
int num_removed_nullCheck;
PhysicalReg scratchRegs[4];
LowOp* ops[BUFFER_SIZE];
LowOp* op;
u2* rPC; //PC pointer to bytecode
u2 inst; //current bytecode
int offsetPC/*offset in bytecode*/, offsetNCG/*byte offset in native code*/;
int ncg_rPC;
//! map from PC in bytecode to PC in native code
int mapFromBCtoNCG[BYTECODE_SIZE_PER_METHOD]; //initially mapped to -1
char* streamStart = NULL; //start of the Pure CodeItem?, not include the global symbols
char* streamCode = NULL; //start of the Pure CodeItem?, not include the global symbols
char* streamMethodStart; //start of the method
char* stream; //current stream pointer
int lowOpTimeStamp = 0;
Method* currentMethod = NULL;
int currentExceptionBlockIdx = -1;
LowOpBlockLabel* traceLabelList = NULL;
BasicBlock* traceCurrentBB = NULL;
MIR* traceCurrentMIR = NULL;
bool scheduling_is_on = false;
int common_invokeMethodNoRange();
int common_invokeMethodRange();
int common_invokeArgsDone(ArgsDoneType, bool);
//data section of .ia32:
char globalData[128];
char strClassCastException[] = "Ljava/lang/ClassCastException;";
char strInstantiationError[] = "Ljava/lang/InstantiationError;";
char strInternalError[] = "Ljava/lang/InternalError;";
char strFilledNewArrayNotImpl[] = "filled-new-array only implemented for 'int'";
char strArithmeticException[] = "Ljava/lang/ArithmeticException;";
char strArrayIndexException[] = "Ljava/lang/ArrayIndexOutOfBoundsException;";
char strArrayStoreException[] = "Ljava/lang/ArrayStoreException;";
char strDivideByZero[] = "divide by zero";
char strNegativeArraySizeException[] = "Ljava/lang/NegativeArraySizeException;";
char strNoSuchMethodError[] = "Ljava/lang/NoSuchMethodError;";
char strNullPointerException[] = "Ljava/lang/NullPointerException;";
char strStringIndexOutOfBoundsException[] = "Ljava/lang/StringIndexOutOfBoundsException;";
int LstrClassCastExceptionPtr, LstrInstantiationErrorPtr, LstrInternalError, LstrFilledNewArrayNotImpl;
int LstrArithmeticException, LstrArrayIndexException, LstrArrayStoreException, LstrStringIndexOutOfBoundsException;
int LstrDivideByZero, LstrNegativeArraySizeException, LstrNoSuchMethodError, LstrNullPointerException;
int LdoubNeg, LvaluePosInfLong, LvalueNegInfLong, LvalueNanLong, LshiftMask, Lvalue64, L64bits, LintMax, LintMin;
void initConstDataSec() {
char* tmpPtr = globalData;
LdoubNeg = (int)tmpPtr;
*((u4*)tmpPtr) = 0x00000000;
tmpPtr += sizeof(u4);
*((u4*)tmpPtr) = 0x80000000;
tmpPtr += sizeof(u4);
LvaluePosInfLong = (int)tmpPtr;
*((u4*)tmpPtr) = 0xFFFFFFFF;
tmpPtr += sizeof(u4);
*((u4*)tmpPtr) = 0x7FFFFFFF;
tmpPtr += sizeof(u4);
LvalueNegInfLong = (int)tmpPtr;
*((u4*)tmpPtr) = 0x00000000;
tmpPtr += sizeof(u4);
*((u4*)tmpPtr) = 0x80000000;
tmpPtr += sizeof(u4);
LvalueNanLong = (int)tmpPtr;
*((u4*)tmpPtr) = 0;
tmpPtr += sizeof(u4);
*((u4*)tmpPtr) = 0;
tmpPtr += sizeof(u4);
LshiftMask = (int)tmpPtr;
*((u4*)tmpPtr) = 0x3f;
tmpPtr += sizeof(u4);
*((u4*)tmpPtr) = 0;
tmpPtr += sizeof(u4);
Lvalue64 = (int)tmpPtr;
*((u4*)tmpPtr) = 0x40;
tmpPtr += sizeof(u4);
*((u4*)tmpPtr) = 0;
tmpPtr += sizeof(u4);
L64bits = (int)tmpPtr;
*((u4*)tmpPtr) = 0xFFFFFFFF;
tmpPtr += sizeof(u4);
*((u4*)tmpPtr) = 0xFFFFFFFF;
tmpPtr += sizeof(u4);
LintMin = (int)tmpPtr;
*((u4*)tmpPtr) = 0x80000000;
tmpPtr += sizeof(u4);
LintMax = (int)tmpPtr;
*((u4*)tmpPtr) = 0x7FFFFFFF;
tmpPtr += sizeof(u4);
LstrClassCastExceptionPtr = (int)strClassCastException;
LstrInstantiationErrorPtr = (int)strInstantiationError;
LstrInternalError = (int)strInternalError;
LstrFilledNewArrayNotImpl = (int)strFilledNewArrayNotImpl;
LstrArithmeticException = (int)strArithmeticException;
LstrArrayIndexException = (int)strArrayIndexException;
LstrArrayStoreException = (int)strArrayStoreException;
LstrDivideByZero = (int)strDivideByZero;
LstrNegativeArraySizeException = (int)strNegativeArraySizeException;
LstrNoSuchMethodError = (int)strNoSuchMethodError;
LstrNullPointerException = (int)strNullPointerException;
LstrStringIndexOutOfBoundsException = (int)strStringIndexOutOfBoundsException;
}
//declarations of functions used in this file
int spill_reg(int reg, bool isPhysical);
int unspill_reg(int reg, bool isPhysical);
int const_string_resolve();
int sget_sput_resolve();
int new_instance_needinit();
int new_instance_abstract();
int invoke_virtual_resolve();
int invoke_direct_resolve();
int invoke_static_resolve();
int filled_new_array_notimpl();
int resolve_class2(
int startLR/*logical register index*/, bool isPhysical, int indexReg/*const pool index*/,
bool indexPhysical,
int thirdArg);
int resolve_method2(
int startLR/*logical register index*/, bool isPhysical, int indexReg/*const pool index*/,
bool indexPhysical,
int thirdArg/*VIRTUAL*/);
int resolve_inst_field2(
int startLR/*logical register index*/, bool isPhysical,
int indexReg/*const pool index*/,
bool indexPhysical);
int resolve_static_field2(
int startLR/*logical register index*/, bool isPhysical,
int indexReg/*const pool index*/,
bool indexPhysical);
int invokeMethodNoRange_1_helper();
int invokeMethodNoRange_2_helper();
int invokeMethodNoRange_3_helper();
int invokeMethodNoRange_4_helper();
int invokeMethodNoRange_5_helper();
int invokeMethodRange_helper();
int invoke_virtual_helper();
int invoke_virtual_quick_helper();
int invoke_static_helper();
int invoke_direct_helper();
int new_instance_helper();
int sget_sput_helper(int flag);
int aput_obj_helper();
int aget_helper(int flag);
int aput_helper(int flag);
int monitor_enter_helper();
int monitor_exit_helper();
int throw_helper();
int const_string_helper();
int array_length_helper();
int invoke_super_helper();
int invoke_interface_helper();
int iget_iput_helper(int flag);
int check_cast_helper(bool instance);
int new_array_helper();
int common_returnFromMethod();
/*!
\brief dump helper functions
*/
int performCGWorklist() {
filled_new_array_notimpl();
freeShortMap();
const_string_resolve();
freeShortMap();
resolve_class2(PhysicalReg_EAX, true, PhysicalReg_EAX, true, 0);
freeShortMap();
resolve_method2(PhysicalReg_EAX, true, PhysicalReg_EAX, true, METHOD_VIRTUAL);
freeShortMap();
resolve_method2(PhysicalReg_EAX, true, PhysicalReg_EAX, true, METHOD_DIRECT);
freeShortMap();
resolve_method2(PhysicalReg_EAX, true, PhysicalReg_EAX, true, METHOD_STATIC);
freeShortMap();
resolve_inst_field2(PhysicalReg_EAX, true, PhysicalReg_EAX, true);
freeShortMap();
resolve_static_field2(PhysicalReg_EAX, true, PhysicalReg_EAX, true);
freeShortMap();
throw_exception_message(PhysicalReg_ECX, PhysicalReg_EAX, true, PhysicalReg_Null, true);
freeShortMap();
throw_exception(PhysicalReg_ECX, PhysicalReg_EAX, PhysicalReg_Null, true);
freeShortMap();
new_instance_needinit();
freeShortMap();
return 0;
}
int aput_object_count;
int common_periodicChecks_entry();
int common_periodicChecks4();
/*!
\brief for debugging purpose, dump the sequence of native code for each bytecode
*/
int ncgMethodFake(Method* method) {
//to measure code size expansion, no need to patch up labels
methodDataWorklist = NULL;
globalShortWorklist = NULL;
globalNCGWorklist = NULL;
streamMethodStart = stream;
//initialize mapFromBCtoNCG
memset(&mapFromBCtoNCG[0], -1, BYTECODE_SIZE_PER_METHOD * sizeof(mapFromBCtoNCG[0]));
unsigned int i;
u2* rStart = (u2*)malloc(5*sizeof(u2));
if(rStart == NULL) {
ALOGE("Memory allocation failed");
return -1;
}
rPC = rStart;
method->insns = rStart;
for(i = 0; i < 5; i++) *rPC++ = 0;
for(i = 0; i < 256; i++) {
rPC = rStart;
//modify the opcode
char* tmp = (char*)rStart;
*tmp++ = i;
*tmp = i;
inst = FETCH(0);
char* tmpStart = stream;
lowerByteCode(method); //use inst, rPC, method, modify rPC
int size_in_u2 = rPC - rStart;
if(stream - tmpStart > 0)
ALOGI("LOWER bytecode %x size in u2: %d ncg size in byte: %d", i, size_in_u2, stream - tmpStart);
}
exit(0);
}
bool existATryBlock(Method* method, int startPC, int endPC) {
const DexCode* pCode = dvmGetMethodCode(method);
u4 triesSize = pCode->triesSize;
const DexTry* pTries = dexGetTries(pCode);
unsigned int i;
for (i = 0; i < triesSize; i++) {
const DexTry* pTry = &pTries[i];
u4 start = pTry->startAddr; //offsetPC
u4 end = start + pTry->insnCount;
//if [start, end] overlaps with [startPC, endPC] returns true
if((int)end < startPC || (int)start > endPC) { //no overlap
} else {
return true;
}
}
return false;
}
int mm_bytecode_size = 0;
int mm_ncg_size = 0;
int mm_relocation_size = 0;
int mm_map_size = 0;
void resetCodeSize() {
mm_bytecode_size = 0;
mm_ncg_size = 0;
mm_relocation_size = 0;
mm_map_size = 0;
}
bool bytecodeIsRemoved(const Method* method, u4 bytecodeOffset) {
if(gDvm.executionMode == kExecutionModeNcgO0) return false;
u4 ncgOff = mapFromBCtoNCG[bytecodeOffset];
int k = bytecodeOffset+1;
u2 insnsSize = dvmGetMethodInsnsSize(method);
while(k < insnsSize) {
if(mapFromBCtoNCG[k] < 0) {
k++;
continue;
}
if(mapFromBCtoNCG[k] == (int)ncgOff) return true;
return false;
}
return false;
}
int invoke_super_nsm();
void init_common(const char* curFileName, DvmDex *pDvmDex, bool forNCG); //forward declaration
void initGlobalMethods(); //forward declaration
//called once when compiler thread starts up
void initJIT(const char* curFileName, DvmDex *pDvmDex) {
init_common(curFileName, pDvmDex, false);
}
void init_common(const char* curFileName, DvmDex *pDvmDex, bool forNCG) {
if(!gDvm.constInit) {
globalMapNum = 0;
globalMap = NULL;
initConstDataSec();
gDvm.constInit = true;
}
//for initJIT: stream is already set
if(!gDvm.commonInit) {
initGlobalMethods();
gDvm.commonInit = true;
}
}
void initGlobalMethods() {
dump_x86_inst = false; /* DEBUG */
// generate native code for function ncgGetEIP
insertLabel("ncgGetEIP", false);
move_mem_to_reg(OpndSize_32, 0, PhysicalReg_ESP, true, PhysicalReg_EDX, true);
x86_return();
//generate code for common labels
//jumps within a helper function is treated as short labels
globalShortMap = NULL;
common_periodicChecks_entry();
freeShortMap();
common_periodicChecks4();
freeShortMap();
//common_invokeMethodNoRange();
//common_invokeMethodRange();
if(dump_x86_inst) ALOGI("ArgsDone_Normal start");
common_invokeArgsDone(ArgsDone_Normal, false);
freeShortMap();
if(dump_x86_inst) ALOGI("ArgsDone_Native start");
common_invokeArgsDone(ArgsDone_Native, false);
freeShortMap();
if(dump_x86_inst) ALOGI("ArgsDone_Full start");
common_invokeArgsDone(ArgsDone_Full, true/*isJitFull*/);
if(dump_x86_inst) ALOGI("ArgsDone_Full end");
freeShortMap();
common_backwardBranch();
freeShortMap();
common_exceptionThrown();
freeShortMap();
common_errNullObject();
freeShortMap();
common_errArrayIndex();
freeShortMap();
common_errArrayStore();
freeShortMap();
common_errNegArraySize();
freeShortMap();
common_errNoSuchMethod();
freeShortMap();
common_errDivideByZero();
freeShortMap();
common_gotoBail();
freeShortMap();
common_gotoBail_0();
freeShortMap();
invoke_super_nsm();
freeShortMap();
performCGWorklist(); //generate code for helper functions
performLabelWorklist(); //it is likely that the common labels will jump to other common labels
dump_x86_inst = false;
}
ExecutionMode origMode;
//when to update streamMethodStart
bool lowerByteCodeJit(const Method* method, const u2* codePtr, MIR* mir) {
rPC = (u2*)codePtr;
inst = FETCH(0);
traceCurrentMIR = mir;
int retCode = lowerByteCode(method);
traceCurrentMIR = NULL;
freeShortMap();
if(retCode >= 0) return false; //handled
return true; //not handled
}
void startOfBasicBlock(BasicBlock* bb) {
traceCurrentBB = bb;
if(gDvm.executionMode == kExecutionModeNcgO0) {
isScratchPhysical = true;
} else {
isScratchPhysical = false;
}
}
void startOfTrace(const Method* method, LowOpBlockLabel* labelList, int exceptionBlockId,
CompilationUnit *cUnit) {
origMode = gDvm.executionMode;
gDvm.executionMode = kExecutionModeNcgO1;
if(gDvm.executionMode == kExecutionModeNcgO0) {
isScratchPhysical = true;
} else {
isScratchPhysical = false;
}
currentMethod = (Method*)method;
currentExceptionBlockIdx = exceptionBlockId;
methodDataWorklist = NULL;
globalShortWorklist = NULL;
globalNCGWorklist = NULL;
streamMethodStart = stream;
//initialize mapFromBCtoNCG
memset(&mapFromBCtoNCG[0], -1, BYTECODE_SIZE_PER_METHOD * sizeof(mapFromBCtoNCG[0]));
traceLabelList = labelList;
if(gDvm.executionMode == kExecutionModeNcgO1)
startOfTraceO1(method, labelList, exceptionBlockId, cUnit);
}
void endOfTrace(bool freeOnly) {
if(freeOnly) {
freeLabelWorklist();
freeNCGWorklist();
freeDataWorklist();
freeChainingWorklist();
}
else {
performLabelWorklist();
performNCGWorklist(); //handle forward jump (GOTO, IF)
performDataWorklist(); //handle SWITCH & FILL_ARRAY_DATA
performChainingWorklist();
}
if(gDvm.executionMode == kExecutionModeNcgO1) {
endOfTraceO1();
}
gDvm.executionMode = origMode;
}
///////////////////////////////////////////////////////////////////
//!
//! each bytecode is translated to a sequence of machine codes
int lowerByteCode(const Method* method) { //inputs: rPC & inst & stream & streamMethodStart
/* offsetPC is used in O1 code generator, where it is defined as the sequence number
use a local version to avoid overwriting */
int offsetPC = rPC - (u2*)method->insns;
if(dump_x86_inst)
ALOGI("LOWER bytecode %x at offsetPC %x offsetNCG %x @%p",
INST_INST(inst), offsetPC, stream - streamMethodStart, stream);
//update mapFromBCtoNCG
offsetNCG = stream - streamMethodStart;
if(offsetPC >= BYTECODE_SIZE_PER_METHOD) ALOGE("offsetPC %d exceeds BYTECODE_SIZE_PER_METHOD", offsetPC);
mapFromBCtoNCG[offsetPC] = offsetNCG;
#if defined(ENABLE_TRACING) && defined(TRACING_OPTION2)
insertMapWorklist(offsetPC, mapFromBCtoNCG[offsetPC], 1);
#endif
//return number of LowOps generated
switch (INST_INST(inst)) {
case OP_NOP:
return op_nop();
case OP_MOVE:
case OP_MOVE_OBJECT:
return op_move();
case OP_MOVE_FROM16:
case OP_MOVE_OBJECT_FROM16:
return op_move_from16();
case OP_MOVE_16:
case OP_MOVE_OBJECT_16:
return op_move_16();
case OP_MOVE_WIDE:
return op_move_wide();
case OP_MOVE_WIDE_FROM16:
return op_move_wide_from16();
case OP_MOVE_WIDE_16:
return op_move_wide_16();
case OP_MOVE_RESULT:
case OP_MOVE_RESULT_OBJECT:
return op_move_result();
case OP_MOVE_RESULT_WIDE:
return op_move_result_wide();
case OP_MOVE_EXCEPTION:
return op_move_exception();
case OP_RETURN_VOID:
case OP_RETURN_VOID_BARRIER:
return op_return_void();
case OP_RETURN:
case OP_RETURN_OBJECT:
return op_return();
case OP_RETURN_WIDE:
return op_return_wide();
case OP_CONST_4:
return op_const_4();
case OP_CONST_16:
return op_const_16();
case OP_CONST:
return op_const();
case OP_CONST_HIGH16:
return op_const_high16();
case OP_CONST_WIDE_16:
return op_const_wide_16();
case OP_CONST_WIDE_32:
return op_const_wide_32();
case OP_CONST_WIDE:
return op_const_wide();
case OP_CONST_WIDE_HIGH16:
return op_const_wide_high16();
case OP_CONST_STRING:
return op_const_string();
case OP_CONST_STRING_JUMBO:
return op_const_string_jumbo();
case OP_CONST_CLASS:
return op_const_class();
case OP_MONITOR_ENTER:
return op_monitor_enter();
case OP_MONITOR_EXIT:
return op_monitor_exit();
case OP_CHECK_CAST:
return op_check_cast();
case OP_INSTANCE_OF:
return op_instance_of();
case OP_ARRAY_LENGTH:
return op_array_length();
case OP_NEW_INSTANCE:
return op_new_instance();
case OP_NEW_ARRAY:
return op_new_array();
case OP_FILLED_NEW_ARRAY:
return op_filled_new_array();
case OP_FILLED_NEW_ARRAY_RANGE:
return op_filled_new_array_range();
case OP_FILL_ARRAY_DATA:
return op_fill_array_data();
case OP_THROW:
return op_throw();
case OP_THROW_VERIFICATION_ERROR:
return op_throw_verification_error();
case OP_GOTO:
return op_goto();
case OP_GOTO_16:
return op_goto_16();
case OP_GOTO_32:
return op_goto_32();
case OP_PACKED_SWITCH:
return op_packed_switch();
case OP_SPARSE_SWITCH:
return op_sparse_switch();
case OP_CMPL_FLOAT:
return op_cmpl_float();
case OP_CMPG_FLOAT:
return op_cmpg_float();
case OP_CMPL_DOUBLE:
return op_cmpl_double();
case OP_CMPG_DOUBLE:
return op_cmpg_double();
case OP_CMP_LONG:
return op_cmp_long();
case OP_IF_EQ:
return op_if_eq();
case OP_IF_NE:
return op_if_ne();
case OP_IF_LT:
return op_if_lt();
case OP_IF_GE:
return op_if_ge();
case OP_IF_GT:
return op_if_gt();
case OP_IF_LE:
return op_if_le();
case OP_IF_EQZ:
return op_if_eqz();
case OP_IF_NEZ:
return op_if_nez();
case OP_IF_LTZ:
return op_if_ltz();
case OP_IF_GEZ:
return op_if_gez();
case OP_IF_GTZ:
return op_if_gtz();
case OP_IF_LEZ:
return op_if_lez();
case OP_AGET:
return op_aget();
case OP_AGET_WIDE:
return op_aget_wide();
case OP_AGET_OBJECT:
return op_aget_object();
case OP_AGET_BOOLEAN:
return op_aget_boolean();
case OP_AGET_BYTE:
return op_aget_byte();
case OP_AGET_CHAR:
return op_aget_char();
case OP_AGET_SHORT:
return op_aget_short();
case OP_APUT:
return op_aput();
case OP_APUT_WIDE:
return op_aput_wide();
case OP_APUT_OBJECT:
return op_aput_object();
case OP_APUT_BOOLEAN:
return op_aput_boolean();
case OP_APUT_BYTE:
return op_aput_byte();
case OP_APUT_CHAR:
return op_aput_char();
case OP_APUT_SHORT:
return op_aput_short();
case OP_IGET:
case OP_IGET_VOLATILE:
return op_iget();
case OP_IGET_WIDE:
return op_iget_wide(false); // isVolatile==false
case OP_IGET_WIDE_VOLATILE:
return op_iget_wide(true); // isVolatile==true
case OP_IGET_OBJECT:
case OP_IGET_OBJECT_VOLATILE:
return op_iget_object();
case OP_IGET_BOOLEAN:
return op_iget_boolean();
case OP_IGET_BYTE:
return op_iget_byte();
case OP_IGET_CHAR:
return op_iget_char();
case OP_IGET_SHORT:
return op_iget_short();
case OP_IPUT:
case OP_IPUT_VOLATILE:
return op_iput();
case OP_IPUT_WIDE:
return op_iput_wide(false); // isVolatile==false
case OP_IPUT_WIDE_VOLATILE:
return op_iput_wide(true); // isVolatile==true
case OP_IPUT_OBJECT:
case OP_IPUT_OBJECT_VOLATILE:
return op_iput_object();
case OP_IPUT_BOOLEAN:
return op_iput_boolean();
case OP_IPUT_BYTE:
return op_iput_byte();
case OP_IPUT_CHAR:
return op_iput_char();
case OP_IPUT_SHORT:
return op_iput_short();
case OP_SGET:
case OP_SGET_VOLATILE:
return op_sget();
case OP_SGET_WIDE:
return op_sget_wide(false); // isVolatile==false
case OP_SGET_WIDE_VOLATILE:
return op_sget_wide(true); // isVolatile==true
case OP_SGET_OBJECT:
case OP_SGET_OBJECT_VOLATILE:
return op_sget_object();
case OP_SGET_BOOLEAN:
return op_sget_boolean();
case OP_SGET_BYTE:
return op_sget_byte();
case OP_SGET_CHAR:
return op_sget_char();
case OP_SGET_SHORT:
return op_sget_short();
case OP_SPUT:
case OP_SPUT_VOLATILE:
return op_sput(false);
case OP_SPUT_WIDE:
return op_sput_wide(false); // isVolatile==false
case OP_SPUT_WIDE_VOLATILE:
return op_sput_wide(true); // isVolatile==true
case OP_SPUT_OBJECT:
case OP_SPUT_OBJECT_VOLATILE:
return op_sput_object();
case OP_SPUT_BOOLEAN:
return op_sput_boolean();
case OP_SPUT_BYTE:
return op_sput_byte();
case OP_SPUT_CHAR:
return op_sput_char();
case OP_SPUT_SHORT:
return op_sput_short();
case OP_INVOKE_VIRTUAL:
return op_invoke_virtual();
case OP_INVOKE_SUPER:
return op_invoke_super();
case OP_INVOKE_DIRECT:
return op_invoke_direct();
case OP_INVOKE_STATIC:
return op_invoke_static();
case OP_INVOKE_INTERFACE:
return op_invoke_interface();
case OP_INVOKE_VIRTUAL_RANGE:
return op_invoke_virtual_range();
case OP_INVOKE_SUPER_RANGE:
return op_invoke_super_range();
case OP_INVOKE_DIRECT_RANGE:
return op_invoke_direct_range();
case OP_INVOKE_STATIC_RANGE:
return op_invoke_static_range();
case OP_INVOKE_INTERFACE_RANGE:
return op_invoke_interface_range();
case OP_NEG_INT:
return op_neg_int();
case OP_NOT_INT:
return op_not_int();
case OP_NEG_LONG:
return op_neg_long();
case OP_NOT_LONG:
return op_not_long();
case OP_NEG_FLOAT:
return op_neg_float();
case OP_NEG_DOUBLE:
return op_neg_double();
case OP_INT_TO_LONG:
return op_int_to_long();
case OP_INT_TO_FLOAT:
return op_int_to_float();
case OP_INT_TO_DOUBLE:
return op_int_to_double();
case OP_LONG_TO_INT:
return op_long_to_int();
case OP_LONG_TO_FLOAT:
return op_long_to_float();
case OP_LONG_TO_DOUBLE:
return op_long_to_double();
case OP_FLOAT_TO_INT:
return op_float_to_int();
case OP_FLOAT_TO_LONG:
return op_float_to_long();
case OP_FLOAT_TO_DOUBLE:
return op_float_to_double();
case OP_DOUBLE_TO_INT:
return op_double_to_int();
case OP_DOUBLE_TO_LONG:
return op_double_to_long();
case OP_DOUBLE_TO_FLOAT:
return op_double_to_float();
case OP_INT_TO_BYTE:
return op_int_to_byte();
case OP_INT_TO_CHAR:
return op_int_to_char();
case OP_INT_TO_SHORT:
return op_int_to_short();
case OP_ADD_INT:
return op_add_int();
case OP_SUB_INT:
return op_sub_int();
case OP_MUL_INT:
return op_mul_int();
case OP_DIV_INT:
return op_div_int();
case OP_REM_INT:
return op_rem_int();
case OP_AND_INT:
return op_and_int();
case OP_OR_INT:
return op_or_int();
case OP_XOR_INT:
return op_xor_int();
case OP_SHL_INT:
return op_shl_int();
case OP_SHR_INT:
return op_shr_int();
case OP_USHR_INT:
return op_ushr_int();
case OP_ADD_LONG:
return op_add_long();
case OP_SUB_LONG:
return op_sub_long();
case OP_MUL_LONG:
return op_mul_long();
case OP_DIV_LONG:
return op_div_long();
case OP_REM_LONG:
return op_rem_long();
case OP_AND_LONG:
return op_and_long();
case OP_OR_LONG:
return op_or_long();
case OP_XOR_LONG:
return op_xor_long();
case OP_SHL_LONG:
return op_shl_long();
case OP_SHR_LONG:
return op_shr_long();
case OP_USHR_LONG:
return op_ushr_long();
case OP_ADD_FLOAT:
return op_add_float();
case OP_SUB_FLOAT:
return op_sub_float();
case OP_MUL_FLOAT:
return op_mul_float();
case OP_DIV_FLOAT:
return op_div_float();
case OP_REM_FLOAT:
return op_rem_float();
case OP_ADD_DOUBLE:
return op_add_double();
case OP_SUB_DOUBLE:
return op_sub_double();
case OP_MUL_DOUBLE:
return op_mul_double();
case OP_DIV_DOUBLE:
return op_div_double();
case OP_REM_DOUBLE:
return op_rem_double();
case OP_ADD_INT_2ADDR:
return op_add_int_2addr();
case OP_SUB_INT_2ADDR:
return op_sub_int_2addr();
case OP_MUL_INT_2ADDR:
return op_mul_int_2addr();
case OP_DIV_INT_2ADDR:
return op_div_int_2addr();
case OP_REM_INT_2ADDR:
return op_rem_int_2addr();
case OP_AND_INT_2ADDR:
return op_and_int_2addr();
case OP_OR_INT_2ADDR:
return op_or_int_2addr();
case OP_XOR_INT_2ADDR:
return op_xor_int_2addr();
case OP_SHL_INT_2ADDR:
return op_shl_int_2addr();
case OP_SHR_INT_2ADDR:
return op_shr_int_2addr();
case OP_USHR_INT_2ADDR:
return op_ushr_int_2addr();
case OP_ADD_LONG_2ADDR:
return op_add_long_2addr();
case OP_SUB_LONG_2ADDR:
return op_sub_long_2addr();
case OP_MUL_LONG_2ADDR:
return op_mul_long_2addr();
case OP_DIV_LONG_2ADDR:
return op_div_long_2addr();
case OP_REM_LONG_2ADDR:
return op_rem_long_2addr();
case OP_AND_LONG_2ADDR:
return op_and_long_2addr();
case OP_OR_LONG_2ADDR:
return op_or_long_2addr();
case OP_XOR_LONG_2ADDR:
return op_xor_long_2addr();
case OP_SHL_LONG_2ADDR:
return op_shl_long_2addr();
case OP_SHR_LONG_2ADDR:
return op_shr_long_2addr();
case OP_USHR_LONG_2ADDR:
return op_ushr_long_2addr();
case OP_ADD_FLOAT_2ADDR:
return op_add_float_2addr();
case OP_SUB_FLOAT_2ADDR:
return op_sub_float_2addr();
case OP_MUL_FLOAT_2ADDR:
return op_mul_float_2addr();
case OP_DIV_FLOAT_2ADDR:
return op_div_float_2addr();
case OP_REM_FLOAT_2ADDR:
return op_rem_float_2addr();
case OP_ADD_DOUBLE_2ADDR:
return op_add_double_2addr();
case OP_SUB_DOUBLE_2ADDR:
return op_sub_double_2addr();
case OP_MUL_DOUBLE_2ADDR:
return op_mul_double_2addr();
case OP_DIV_DOUBLE_2ADDR:
return op_div_double_2addr();
case OP_REM_DOUBLE_2ADDR:
return op_rem_double_2addr();
case OP_ADD_INT_LIT16:
return op_add_int_lit16();
case OP_RSUB_INT:
return op_rsub_int();
case OP_MUL_INT_LIT16:
return op_mul_int_lit16();
case OP_DIV_INT_LIT16:
return op_div_int_lit16();
case OP_REM_INT_LIT16:
return op_rem_int_lit16();
case OP_AND_INT_LIT16:
return op_and_int_lit16();
case OP_OR_INT_LIT16:
return op_or_int_lit16();
case OP_XOR_INT_LIT16:
return op_xor_int_lit16();
case OP_ADD_INT_LIT8:
return op_add_int_lit8();
case OP_RSUB_INT_LIT8:
return op_rsub_int_lit8();
case OP_MUL_INT_LIT8:
return op_mul_int_lit8();
case OP_DIV_INT_LIT8:
return op_div_int_lit8();
case OP_REM_INT_LIT8:
return op_rem_int_lit8();
case OP_AND_INT_LIT8:
return op_and_int_lit8();
case OP_OR_INT_LIT8:
return op_or_int_lit8();
case OP_XOR_INT_LIT8:
return op_xor_int_lit8();
case OP_SHL_INT_LIT8:
return op_shl_int_lit8();
case OP_SHR_INT_LIT8:
return op_shr_int_lit8();
case OP_USHR_INT_LIT8:
return op_ushr_int_lit8();
case OP_EXECUTE_INLINE:
return op_execute_inline(false);
case OP_EXECUTE_INLINE_RANGE:
return op_execute_inline(true);
case OP_BREAKPOINT:
ALOGE("found bytecode OP_BREAKPOINT");
dvmAbort();
case OP_INVOKE_OBJECT_INIT_RANGE:
return op_invoke_object_init_range();
case OP_IGET_QUICK:
return op_iget_quick();
case OP_IGET_WIDE_QUICK:
return op_iget_wide_quick();
case OP_IGET_OBJECT_QUICK:
return op_iget_object_quick();
case OP_IPUT_QUICK:
return op_iput_quick();
case OP_IPUT_WIDE_QUICK:
return op_iput_wide_quick();
case OP_IPUT_OBJECT_QUICK:
return op_iput_object_quick();
case OP_INVOKE_VIRTUAL_QUICK:
return op_invoke_virtual_quick();
case OP_INVOKE_VIRTUAL_QUICK_RANGE:
return op_invoke_virtual_quick_range();
case OP_INVOKE_SUPER_QUICK:
return op_invoke_super_quick();
case OP_INVOKE_SUPER_QUICK_RANGE:
return op_invoke_super_quick_range();
}
ALOGE("No JIT support for bytecode %x at offsetPC %x",
INST_INST(inst), offsetPC);
return -1;
}
int op_nop() {
rPC++;
return 0;
}