/* * 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; }