/* * 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 LowerGetPut.cpp \brief This file lowers the following bytecodes: XGET|PUT_XXX */ #include "libdex/DexOpcodes.h" #include "libdex/DexFile.h" #include "Lower.h" #include "NcgAot.h" #include "enc_wrapper.h" #define P_GPR_1 PhysicalReg_EBX #define P_GPR_2 PhysicalReg_ECX #define P_GPR_3 PhysicalReg_ESI #define P_GPR_4 PhysicalReg_EDX //! LOWER bytecode AGET without usage of helper function //! It has null check and length check int aget_common_nohelper(int flag, u2 vA, u2 vref, u2 vindex) { //////////////////////////// // Request VR free delays before register allocation for the temporaries if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) requestVRFreeDelay(vref,VRDELAY_NULLCHECK); if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) { requestVRFreeDelay(vref,VRDELAY_BOUNDCHECK); requestVRFreeDelay(vindex,VRDELAY_BOUNDCHECK); } get_virtual_reg(vref, OpndSize_32, 1, false); //array get_virtual_reg(vindex, OpndSize_32, 2, false); //index if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) { //last argument is the exception number for this bytecode nullCheck(1, false, 1, vref); //maybe optimized away, if not, call cancelVRFreeDelayRequest(vref,VRDELAY_NULLCHECK); } else { updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1 } if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) { boundCheck(vref, 1, false, vindex, 2, false, 2); cancelVRFreeDelayRequest(vref,VRDELAY_BOUNDCHECK); cancelVRFreeDelayRequest(vindex,VRDELAY_BOUNDCHECK); } else { updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1 updateRefCount2(2, LowOpndRegType_gp, false); //update reference count for tmp2 } if(flag == AGET) { move_mem_disp_scale_to_reg(OpndSize_32, 1, false, offArrayObject_contents, 2, false, 4, 4, false); } else if(flag == AGET_WIDE) { move_mem_disp_scale_to_reg(OpndSize_64, 1, false, offArrayObject_contents, 2, false, 8, 1, false); } else if(flag == AGET_CHAR) { movez_mem_disp_scale_to_reg(OpndSize_16, 1, false, offArrayObject_contents, 2, false, 2, 4, false); } else if(flag == AGET_SHORT) { moves_mem_disp_scale_to_reg(OpndSize_16, 1, false, offArrayObject_contents, 2, false, 2, 4, false); } else if(flag == AGET_BOOLEAN) { movez_mem_disp_scale_to_reg(OpndSize_8, 1, false, offArrayObject_contents, 2, false, 1, 4, false); } else if(flag == AGET_BYTE) { moves_mem_disp_scale_to_reg(OpndSize_8, 1, false, offArrayObject_contents, 2, false, 1, 4, false); } if(flag == AGET_WIDE) { set_virtual_reg(vA, OpndSize_64, 1, false); } else { set_virtual_reg(vA, OpndSize_32, 4, false); } ////////////////////////////////// return 0; } //! wrapper to call either aget_common_helper or aget_common_nohelper //! int aget_common(int flag, u2 vA, u2 vref, u2 vindex) { return aget_common_nohelper(flag, vA, vref, vindex); } #undef P_GPR_1 #undef P_GPR_2 #undef P_GPR_3 #undef P_GPR_4 //! lower bytecode AGET by calling aget_common //! int op_aget() { u2 vA = INST_AA(inst); u2 vref = FETCH(1) & 0xff; u2 vindex = FETCH(1) >> 8; int retval = aget_common(AGET, vA, vref, vindex); rPC += 2; return retval; } //! lower bytecode AGET_WIDE by calling aget_common //! int op_aget_wide() { u2 vA = INST_AA(inst); u2 vref = FETCH(1) & 0xff; u2 vindex = FETCH(1) >> 8; int retval = aget_common(AGET_WIDE, vA, vref, vindex); rPC += 2; return retval; } //! lower bytecode AGET_OBJECT by calling aget_common //! int op_aget_object() { return op_aget(); } //! lower bytecode BOOLEAN by calling aget_common //! int op_aget_boolean() { u2 vA = INST_AA(inst); u2 vref = FETCH(1) & 0xff; u2 vindex = FETCH(1) >> 8; int retval = aget_common(AGET_BOOLEAN, vA, vref, vindex); rPC += 2; return retval; } //! lower bytecode AGET_BYTE by calling aget_common //! int op_aget_byte() { u2 vA = INST_AA(inst); u2 vref = FETCH(1) & 0xff; u2 vindex = FETCH(1) >> 8; int retval = aget_common(AGET_BYTE, vA, vref, vindex); rPC += 2; return retval; } //! lower bytecode AGET_CHAR by calling aget_common //! int op_aget_char() { u2 vA = INST_AA(inst); u2 vref = FETCH(1) & 0xff; u2 vindex = FETCH(1) >> 8; int retval = aget_common(AGET_CHAR, vA, vref, vindex); rPC += 2; return retval; } //! lower bytecode AGET_SHORT by calling aget_common //! int op_aget_short() { u2 vA = INST_AA(inst); u2 vref = FETCH(1) & 0xff; u2 vindex = FETCH(1) >> 8; int retval = aget_common(AGET_SHORT, vA, vref, vindex); rPC += 2; return retval; } #define P_GPR_1 PhysicalReg_EBX #define P_GPR_2 PhysicalReg_ECX #define P_GPR_3 PhysicalReg_ESI #define P_GPR_4 PhysicalReg_EDX //! LOWER bytecode APUT without usage of helper function //! It has null check and length check int aput_common_nohelper(int flag, u2 vA, u2 vref, u2 vindex) { ////////////////////////////////////// // Request VR free delays before register allocation for the temporaries. // No need to request delay for vA since it will be transferred to temporary // after the null check and bound check. if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) requestVRFreeDelay(vref,VRDELAY_NULLCHECK); if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) { requestVRFreeDelay(vref,VRDELAY_BOUNDCHECK); requestVRFreeDelay(vindex,VRDELAY_BOUNDCHECK); } get_virtual_reg(vref, OpndSize_32, 1, false); //array get_virtual_reg(vindex, OpndSize_32, 2, false); //index if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) { //last argument is the exception number for this bytecode nullCheck(1, false, 1, vref); //maybe optimized away, if not, call cancelVRFreeDelayRequest(vref,VRDELAY_NULLCHECK); } else { updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1 } if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) { boundCheck(vref, 1, false, vindex, 2, false, 2); cancelVRFreeDelayRequest(vref,VRDELAY_BOUNDCHECK); cancelVRFreeDelayRequest(vindex,VRDELAY_BOUNDCHECK); } else { updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1 updateRefCount2(2, LowOpndRegType_gp, false); //update reference count for tmp2 } if(flag == APUT_WIDE) { get_virtual_reg(vA, OpndSize_64, 1, false); } else { get_virtual_reg(vA, OpndSize_32, 4, false); } if(flag == APUT) move_reg_to_mem_disp_scale(OpndSize_32, 4, false, 1, false, offArrayObject_contents, 2, false, 4); else if(flag == APUT_WIDE) move_reg_to_mem_disp_scale(OpndSize_64, 1, false, 1, false, offArrayObject_contents, 2, false, 8); else if(flag == APUT_CHAR || flag == APUT_SHORT) move_reg_to_mem_disp_scale(OpndSize_16, 4, false, 1, false, offArrayObject_contents, 2, false, 2); else if(flag == APUT_BOOLEAN || flag == APUT_BYTE) move_reg_to_mem_disp_scale(OpndSize_8, 4, false, 1, false, offArrayObject_contents, 2, false, 1); ////////////////////////////////// return 0; } //! wrapper to call either aput_common_helper or aput_common_nohelper //! int aput_common(int flag, u2 vA, u2 vref, u2 vindex) { return aput_common_nohelper(flag, vA, vref, vindex); } #undef P_GPR_1 #undef P_GPR_2 #undef P_GPR_3 #undef P_GPR_4 //! lower bytecode APUT by calling aput_common //! int op_aput() { u2 vA = INST_AA(inst); u2 vref = FETCH(1) & 0xff; u2 vindex = FETCH(1) >> 8; int retval = aput_common(APUT, vA, vref, vindex); rPC += 2; return retval; } //! lower bytecode APUT_WIDE by calling aput_common //! int op_aput_wide() { u2 vA = INST_AA(inst); u2 vref = FETCH(1) & 0xff; u2 vindex = FETCH(1) >> 8; int retval = aput_common(APUT_WIDE, vA, vref, vindex); rPC += 2; return retval; } //! lower bytecode APUT_BOOLEAN by calling aput_common //! int op_aput_boolean() { u2 vA = INST_AA(inst); u2 vref = FETCH(1) & 0xff; u2 vindex = FETCH(1) >> 8; int retval = aput_common(APUT_BOOLEAN, vA, vref, vindex); rPC += 2; return retval; } //! lower bytecode APUT_BYTE by calling aput_common //! int op_aput_byte() { u2 vA = INST_AA(inst); u2 vref = FETCH(1) & 0xff; u2 vindex = FETCH(1) >> 8; int retval = aput_common(APUT_BYTE, vA, vref, vindex); rPC += 2; return retval; } //! lower bytecode APUT_CHAR by calling aput_common //! int op_aput_char() { u2 vA = INST_AA(inst); u2 vref = FETCH(1) & 0xff; u2 vindex = FETCH(1) >> 8; int retval = aput_common(APUT_CHAR, vA, vref, vindex); rPC += 2; return retval; } //! lower bytecode APUT_SHORT by calling aput_common //! int op_aput_short() { u2 vA = INST_AA(inst); u2 vref = FETCH(1) & 0xff; u2 vindex = FETCH(1) >> 8; int retval = aput_common(APUT_SHORT, vA, vref, vindex); rPC += 2; return retval; } #define P_GPR_1 PhysicalReg_EBX //callee-saved valid after CanPutArray #define P_GPR_2 PhysicalReg_ECX #define P_GPR_3 PhysicalReg_ESI //callee-saved #define P_SCRATCH_1 PhysicalReg_EDX #define P_SCRATCH_2 PhysicalReg_EAX #define P_SCRATCH_3 PhysicalReg_EDX void markCard_notNull(int tgtAddrReg, int scratchReg, bool isPhysical); //! lower bytecode APUT_OBJECT //! Lower the bytecode using helper function ".aput_obj_helper" if helper switch is on int op_aput_object() { //type checking u2 vA = INST_AA(inst); u2 vref = FETCH(1) & 0xff; u2 vindex = FETCH(1) >> 8; /////////////////////////// // Request VR free delays before register allocation for the temporaries // No need to request delay for vA since it will be transferred to temporary // after the null check and bound check. if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) requestVRFreeDelay(vref,VRDELAY_NULLCHECK); if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) { requestVRFreeDelay(vref,VRDELAY_BOUNDCHECK); requestVRFreeDelay(vindex,VRDELAY_BOUNDCHECK); } get_virtual_reg(vref, OpndSize_32, 1, false); //array export_pc(); //use %edx if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) { compare_imm_reg(OpndSize_32, 0, 1, false); conditional_jump_global_API(Condition_E, "common_errNullObject", false); cancelVRFreeDelayRequest(vref,VRDELAY_NULLCHECK); } else { updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1 } get_virtual_reg(vindex, OpndSize_32, 2, false); //index if(!(traceCurrentMIR->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) { compare_mem_reg(OpndSize_32, offArrayObject_length, 1, false, 2, false); conditional_jump_global_API(Condition_NC, "common_errArrayIndex", false); cancelVRFreeDelayRequest(vref,VRDELAY_BOUNDCHECK); cancelVRFreeDelayRequest(vindex,VRDELAY_BOUNDCHECK); } else { updateRefCount2(1, LowOpndRegType_gp, false); //update reference count for tmp1 updateRefCount2(2, LowOpndRegType_gp, false); //update reference count for tmp2 } get_virtual_reg(vA, OpndSize_32, 4, false); compare_imm_reg(OpndSize_32, 0, 4, false); conditional_jump(Condition_E, ".aput_object_skip_check", true); rememberState(1); move_mem_to_reg(OpndSize_32, offObject_clazz, 4, false, 5, false); load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true); move_reg_to_mem(OpndSize_32, 5, false, 0, PhysicalReg_ESP, true); move_mem_to_reg(OpndSize_32, offObject_clazz, 1, false, 6, false); move_reg_to_mem(OpndSize_32, 6, false, 4, PhysicalReg_ESP, true); scratchRegs[0] = PhysicalReg_SCRATCH_1; call_dvmCanPutArrayElement(); //scratch?? load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true); compare_imm_reg(OpndSize_32, 0, PhysicalReg_EAX, true); conditional_jump_global_API(Condition_E, "common_errArrayStore", false); //NOTE: "2, false" is live through function call move_reg_to_mem_disp_scale(OpndSize_32, 4, false, 1, false, offArrayObject_contents, 2, false, 4); markCard_notNull(1, 11, false); rememberState(2); ////TODO NCG O1 + code cache unconditional_jump(".aput_object_after_check", true); insertLabel(".aput_object_skip_check", true); goToState(1); //NOTE: "2, false" is live through function call move_reg_to_mem_disp_scale(OpndSize_32, 4, false, 1, false, offArrayObject_contents, 2, false, 4); transferToState(2); insertLabel(".aput_object_after_check", true); /////////////////////////////// rPC += 2; return 0; } #undef P_GPR_1 #undef P_GPR_2 #undef P_GPR_3 #undef P_SCRATCH_1 #undef P_SCRATCH_2 #undef P_SCRATCH_3 ////////////////////////////////////////// #define P_GPR_1 PhysicalReg_ECX #define P_GPR_2 PhysicalReg_EBX //should be callee-saved to avoid overwritten by inst_field_resolve #define P_GPR_3 PhysicalReg_ESI #define P_SCRATCH_1 PhysicalReg_EDX /* movl offThread_cardTable(self), scratchReg compare_imm_reg 0, valReg (testl valReg, valReg) je .markCard_skip shrl $GC_CARD_SHIFT, tgtAddrReg movb %, (scratchReg, tgtAddrReg) NOTE: scratchReg can be accessed with the corresponding byte tgtAddrReg will be updated for O1, update the corresponding reference count */ void markCard(int valReg, int tgtAddrReg, bool targetPhysical, int scratchReg, bool isPhysical) { get_self_pointer(PhysicalReg_SCRATCH_6, isScratchPhysical); move_mem_to_reg(OpndSize_32, offsetof(Thread, cardTable), PhysicalReg_SCRATCH_6, isScratchPhysical, scratchReg, isPhysical); compare_imm_reg(OpndSize_32, 0, valReg, isPhysical); conditional_jump(Condition_E, ".markCard_skip", true); alu_binary_imm_reg(OpndSize_32, shr_opc, GC_CARD_SHIFT, tgtAddrReg, targetPhysical); move_reg_to_mem_disp_scale(OpndSize_8, scratchReg, isPhysical, scratchReg, isPhysical, 0, tgtAddrReg, targetPhysical, 1); insertLabel(".markCard_skip", true); } void markCard_notNull(int tgtAddrReg, int scratchReg, bool isPhysical) { get_self_pointer(PhysicalReg_SCRATCH_2, isScratchPhysical); move_mem_to_reg(OpndSize_32, offsetof(Thread, cardTable), PhysicalReg_SCRATCH_2, isScratchPhysical, scratchReg, isPhysical); alu_binary_imm_reg(OpndSize_32, shr_opc, GC_CARD_SHIFT, tgtAddrReg, isPhysical); move_reg_to_mem_disp_scale(OpndSize_8, scratchReg, isPhysical, scratchReg, isPhysical, 0, tgtAddrReg, isPhysical, 1); } void markCard_filled(int tgtAddrReg, bool isTgtPhysical, int scratchReg, bool isScratchPhysical) { get_self_pointer(PhysicalReg_SCRATCH_2, false/*isPhysical*/); move_mem_to_reg(OpndSize_32, offsetof(Thread, cardTable), PhysicalReg_SCRATCH_2, isScratchPhysical, scratchReg, isScratchPhysical); alu_binary_imm_reg(OpndSize_32, shr_opc, GC_CARD_SHIFT, tgtAddrReg, isTgtPhysical); move_reg_to_mem_disp_scale(OpndSize_8, scratchReg, isScratchPhysical, scratchReg, isScratchPhysical, 0, tgtAddrReg, isTgtPhysical, 1); } //! LOWER bytecode IGET,IPUT without usage of helper function //! It has null check and calls assembly function inst_field_resolve int iget_iput_common_nohelper(int tmp, int flag, u2 vA, u2 vB, int isObj, bool isVolatile) { #ifdef WITH_JIT_INLINING const Method *method = (traceCurrentMIR->OptimizationFlags & MIR_CALLEE) ? traceCurrentMIR->meta.calleeMethod : currentMethod; InstField *pInstField = (InstField *) method->clazz->pDvmDex->pResFields[tmp]; #else InstField *pInstField = (InstField *) currentMethod->clazz->pDvmDex->pResFields[tmp]; #endif int fieldOffset; assert(pInstField != NULL); fieldOffset = pInstField->byteOffset; move_imm_to_reg(OpndSize_32, fieldOffset, 8, false); // Request VR delay before transfer to temporary. Only vB needs delay. // vA will have non-zero reference count since transfer to temporary for // it happens after null check, thus no delay is needed. requestVRFreeDelay(vB,VRDELAY_NULLCHECK); get_virtual_reg(vB, OpndSize_32, 7, false); nullCheck(7, false, 2, vB); //maybe optimized away, if not, call cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK); if(flag == IGET) { move_mem_scale_to_reg(OpndSize_32, 7, false, 8, false, 1, 9, false); set_virtual_reg(vA, OpndSize_32, 9, false); #ifdef DEBUG_IGET_OBJ if(isObj > 0) { pushAllRegs(); load_effective_addr(-16, PhysicalReg_ESP, true, PhysicalReg_ESP, true); move_reg_to_mem(OpndSize_32, 9, false, 12, PhysicalReg_ESP, true); //field move_reg_to_mem(OpndSize_32, 7, false, 8, PhysicalReg_ESP, true); //object move_imm_to_mem(OpndSize_32, tmp, 4, PhysicalReg_ESP, true); //field move_imm_to_mem(OpndSize_32, 0, 0, PhysicalReg_ESP, true); //iget call_dvmDebugIgetIput(); load_effective_addr(16, PhysicalReg_ESP, true, PhysicalReg_ESP, true); popAllRegs(); } #endif } else if(flag == IGET_WIDE) { if(isVolatile) { /* call dvmQuasiAtomicRead64(addr) */ load_effective_addr(fieldOffset, 7, false, 9, false); move_reg_to_mem(OpndSize_32, 9, false, -4, PhysicalReg_ESP, true); //1st argument load_effective_addr(-4, PhysicalReg_ESP, true, PhysicalReg_ESP, true); nextVersionOfHardReg(PhysicalReg_EAX, 2); nextVersionOfHardReg(PhysicalReg_EDX, 2); scratchRegs[0] = PhysicalReg_SCRATCH_3; call_dvmQuasiAtomicRead64(); load_effective_addr(4, PhysicalReg_ESP, true, PhysicalReg_ESP, true); //memory content in %edx, %eax set_virtual_reg(vA, OpndSize_32, PhysicalReg_EAX, true); set_virtual_reg(vA+1, OpndSize_32, PhysicalReg_EDX, true); } else { move_mem_scale_to_reg(OpndSize_64, 7, false, 8, false, 1, 1, false); //access field set_virtual_reg(vA, OpndSize_64, 1, false); } } else if(flag == IPUT) { get_virtual_reg(vA, OpndSize_32, 9, false); move_reg_to_mem_scale(OpndSize_32, 9, false, 7, false, 8, false, 1); //access field if(isObj) { markCard(9, 7, false, 11, false); } } else if(flag == IPUT_WIDE) { get_virtual_reg(vA, OpndSize_64, 1, false); if(isVolatile) { /* call dvmQuasiAtomicSwap64(val, addr) */ load_effective_addr(fieldOffset, 7, false, 9, false); move_reg_to_mem(OpndSize_32, 9, false, -4, PhysicalReg_ESP, true); //2nd argument move_reg_to_mem(OpndSize_64, 1, false, -12, PhysicalReg_ESP, true); //1st argument load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true); scratchRegs[0] = PhysicalReg_SCRATCH_3; call_dvmQuasiAtomicSwap64(); load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true); } else { move_reg_to_mem_scale(OpndSize_64, 1, false, 7, false, 8, false, 1); } } /////////////////////////// return 0; } //! wrapper to call either iget_iput_common_helper or iget_iput_common_nohelper //! int iget_iput_common(int tmp, int flag, u2 vA, u2 vB, int isObj, bool isVolatile) { return iget_iput_common_nohelper(tmp, flag, vA, vB, isObj, isVolatile); } #undef P_GPR_1 #undef P_GPR_2 #undef P_GPR_3 #undef P_SCRATCH_1 //! lower bytecode IGET by calling iget_iput_common //! int op_iget() { u2 vA = INST_A(inst); u2 vB = INST_B(inst); u2 tmp = FETCH(1); int retval = iget_iput_common(tmp, IGET, vA, vB, 0, false); rPC += 2; return retval; } //! lower bytecode IGET_WIDE by calling iget_iput_common //! int op_iget_wide(bool isVolatile) { u2 vA = INST_A(inst); u2 vB = INST_B(inst); u2 tmp = FETCH(1); int retval = iget_iput_common(tmp, IGET_WIDE, vA, vB, 0, isVolatile); rPC += 2; return retval; } //! lower bytecode IGET_OBJECT by calling iget_iput_common //! int op_iget_object() { u2 vA = INST_A(inst); u2 vB = INST_B(inst); u2 tmp = FETCH(1); int retval = iget_iput_common(tmp, IGET, vA, vB, 1, false); rPC += 2; return retval; } //! lower bytecode IGET_BOOLEAN by calling iget_iput_common //! int op_iget_boolean() { return op_iget(); } //! lower bytecode IGET_BYTE by calling iget_iput_common //! int op_iget_byte() { return op_iget(); } //! lower bytecode IGET_CHAR by calling iget_iput_common //! int op_iget_char() { return op_iget(); } //! lower bytecode IGET_SHORT by calling iget_iput_common //! int op_iget_short() { return op_iget(); } //! lower bytecode IPUT by calling iget_iput_common //! int op_iput() { u2 vA = INST_A(inst); u2 vB = INST_B(inst); u2 tmp = FETCH(1); int retval = iget_iput_common(tmp, IPUT, vA, vB, 0, false); rPC += 2; return retval; } //! lower bytecode IPUT_WIDE by calling iget_iput_common //! int op_iput_wide(bool isVolatile) { u2 vA = INST_A(inst); u2 vB = INST_B(inst); u2 tmp = FETCH(1); int retval = iget_iput_common(tmp, IPUT_WIDE, vA, vB, 0, isVolatile); rPC += 2; return retval; } //! lower bytecode IPUT_OBJECT by calling iget_iput_common //! int op_iput_object() { u2 vA = INST_A(inst); u2 vB = INST_B(inst); u2 tmp = FETCH(1); int retval = iget_iput_common(tmp, IPUT, vA, vB, 1, false); rPC += 2; return retval; } //! lower bytecode IPUT_BOOLEAN by calling iget_iput_common //! int op_iput_boolean() { return op_iput(); } //! lower bytecode IPUT_BYTE by calling iget_iput_common //! int op_iput_byte() { return op_iput(); } //! lower bytecode IPUT_CHAR by calling iget_iput_common //! int op_iput_char() { return op_iput(); } //! lower bytecode IPUT_SHORT by calling iget_iput_common //! int op_iput_short() { return op_iput(); } #define P_GPR_1 PhysicalReg_EBX #define P_GPR_2 PhysicalReg_ECX #define P_GPR_3 PhysicalReg_EDX //used by helper only //! common section to lower IGET & IPUT //! It will use helper function sget_helper if the switch is on int sget_sput_common(int flag, u2 vA, u2 tmp, bool isObj, bool isVolatile) { //call assembly static_field_resolve //no exception //glue: get_res_fields //hard-coded: eax (one version?) ////////////////////////////////////////// #ifdef WITH_JIT_INLINING const Method *method = (traceCurrentMIR->OptimizationFlags & MIR_CALLEE) ? traceCurrentMIR->meta.calleeMethod : currentMethod; void *fieldPtr = (void*) (method->clazz->pDvmDex->pResFields[tmp]); #else void *fieldPtr = (void*) (currentMethod->clazz->pDvmDex->pResFields[tmp]); #endif assert(fieldPtr != NULL); move_imm_to_reg(OpndSize_32, (int)fieldPtr, PhysicalReg_EAX, true); if(flag == SGET) { move_mem_to_reg(OpndSize_32, offStaticField_value, PhysicalReg_EAX, true, 7, false); //access field set_virtual_reg(vA, OpndSize_32, 7, false); } else if(flag == SGET_WIDE) { if(isVolatile) { /* call dvmQuasiAtomicRead64(addr) */ load_effective_addr(offStaticField_value, PhysicalReg_EAX, true, 9, false); move_reg_to_mem(OpndSize_32, 9, false, -4, PhysicalReg_ESP, true); //1st argument load_effective_addr(-4, PhysicalReg_ESP, true, PhysicalReg_ESP, true); nextVersionOfHardReg(PhysicalReg_EAX, 2); nextVersionOfHardReg(PhysicalReg_EDX, 2); scratchRegs[0] = PhysicalReg_SCRATCH_3; call_dvmQuasiAtomicRead64(); load_effective_addr(4, PhysicalReg_ESP, true, PhysicalReg_ESP, true); //memory content in %edx, %eax set_virtual_reg(vA, OpndSize_32, PhysicalReg_EAX, true); set_virtual_reg(vA+1, OpndSize_32, PhysicalReg_EDX, true); } else { move_mem_to_reg(OpndSize_64, offStaticField_value, PhysicalReg_EAX, true, 1, false); //access field set_virtual_reg(vA, OpndSize_64, 1, false); } } else if(flag == SPUT) { get_virtual_reg(vA, OpndSize_32, 7, false); move_reg_to_mem(OpndSize_32, 7, false, offStaticField_value, PhysicalReg_EAX, true); //access field if(isObj) { /* get clazz object, then use clazz object to mark card */ move_mem_to_reg(OpndSize_32, offField_clazz, PhysicalReg_EAX, true, 12, false); markCard(7/*valReg*/, 12, false, 11, false); } } else if(flag == SPUT_WIDE) { get_virtual_reg(vA, OpndSize_64, 1, false); if(isVolatile) { /* call dvmQuasiAtomicSwap64(val, addr) */ load_effective_addr(offStaticField_value, PhysicalReg_EAX, true, 9, false); move_reg_to_mem(OpndSize_32, 9, false, -4, PhysicalReg_ESP, true); //2nd argument move_reg_to_mem(OpndSize_64, 1, false, -12, PhysicalReg_ESP, true); //1st argument load_effective_addr(-12, PhysicalReg_ESP, true, PhysicalReg_ESP, true); scratchRegs[0] = PhysicalReg_SCRATCH_3; call_dvmQuasiAtomicSwap64(); load_effective_addr(12, PhysicalReg_ESP, true, PhysicalReg_ESP, true); } else { move_reg_to_mem(OpndSize_64, 1, false, offStaticField_value, PhysicalReg_EAX, true); //access field } } ////////////////////////////////////////////// return 0; } #undef P_GPR_1 #undef P_GPR_2 #undef P_GPR_3 //! lower bytecode SGET by calling sget_sput_common //! int op_sget() { u2 vA = INST_AA(inst); u2 tmp = FETCH(1); int retval = sget_sput_common(SGET, vA, tmp, false, false); rPC += 2; return retval; } //! lower bytecode SGET_WIDE by calling sget_sput_common //! int op_sget_wide(bool isVolatile) { u2 vA = INST_AA(inst); u2 tmp = FETCH(1); int retval = sget_sput_common(SGET_WIDE, vA, tmp, false, isVolatile); rPC += 2; return retval; } //! lower bytecode SGET_OBJECT by calling sget_sput_common //! int op_sget_object() { return op_sget(); } //! lower bytecode SGET_BOOLEAN by calling sget_sput_common //! int op_sget_boolean() { return op_sget(); } //! lower bytecode SGET_BYTE by calling sget_sput_common //! int op_sget_byte() { return op_sget(); } //! lower bytecode SGET_CHAR by calling sget_sput_common //! int op_sget_char() { return op_sget(); } //! lower bytecode SGET_SHORT by calling sget_sput_common //! int op_sget_short() { return op_sget(); } //! lower bytecode SPUT by calling sget_sput_common //! int op_sput(bool isObj) { u2 vA = INST_AA(inst); u2 tmp = FETCH(1); int retval = sget_sput_common(SPUT, vA, tmp, isObj, false); rPC += 2; return retval; } //! lower bytecode SPUT_WIDE by calling sget_sput_common //! int op_sput_wide(bool isVolatile) { u2 vA = INST_AA(inst); u2 tmp = FETCH(1); int retval = sget_sput_common(SPUT_WIDE, vA, tmp, false, isVolatile); rPC += 2; return retval; } //! lower bytecode SPUT_OBJECT by calling sget_sput_common //! int op_sput_object() { return op_sput(true); } //! lower bytecode SPUT_OBJECT by calling sget_sput_common //! int op_sput_boolean() { return op_sput(false); } //! lower bytecode SPUT_BOOLEAN by calling sget_sput_common //! int op_sput_byte() { return op_sput(false); } //! lower bytecode SPUT_BYTE by calling sget_sput_common //! int op_sput_char() { return op_sput(false); } //! lower bytecode SPUT_SHORT by calling sget_sput_common //! int op_sput_short() { return op_sput(false); } #define P_GPR_1 PhysicalReg_EBX #define P_GPR_2 PhysicalReg_ECX //! lower bytecode IGET_QUICK //! int op_iget_quick() { u2 vA = INST_A(inst); u2 vB = INST_B(inst); //object u2 tmp = FETCH(1); requestVRFreeDelay(vB,VRDELAY_NULLCHECK); // Request VR delay before transfer to temporary get_virtual_reg(vB, OpndSize_32, 1, false); nullCheck(1, false, 1, vB); //maybe optimized away, if not, call cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK); move_mem_to_reg(OpndSize_32, tmp, 1, false, 2, false); set_virtual_reg(vA, OpndSize_32, 2, false); rPC += 2; return 0; } #undef P_GPR_1 #undef P_GPR_2 #define P_GPR_1 PhysicalReg_EBX //! lower bytecode IGET_WIDE_QUICK //! int op_iget_wide_quick() { u2 vA = INST_A(inst); u2 vB = INST_B(inst); //object u2 tmp = FETCH(1); requestVRFreeDelay(vB,VRDELAY_NULLCHECK); // Request VR delay before transfer to temporary get_virtual_reg(vB, OpndSize_32, 1, false); nullCheck(1, false, 1, vB); //maybe optimized away, if not, call cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK); move_mem_to_reg(OpndSize_64, tmp, 1, false, 1, false); set_virtual_reg(vA, OpndSize_64, 1, false); rPC += 2; return 0; } #undef P_GPR_1 //! lower bytecode IGET_OBJECT_QUICK //! int op_iget_object_quick() { return op_iget_quick(); } #define P_GPR_1 PhysicalReg_EBX #define P_GPR_2 PhysicalReg_ECX //! lower bytecode IPUT_QUICK //! int iput_quick_common(bool isObj) { u2 vA = INST_A(inst); u2 vB = INST_B(inst); //object u2 tmp = FETCH(1); // Request VR delay before transfer to temporary. Only vB needs delay. // vA will have non-zero reference count since transfer to temporary for // it happens after null check, thus no delay is needed. requestVRFreeDelay(vB,VRDELAY_NULLCHECK); get_virtual_reg(vB, OpndSize_32, 1, false); nullCheck(1, false, 1, vB); //maybe optimized away, if not, call cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK); get_virtual_reg(vA, OpndSize_32, 2, false); move_reg_to_mem(OpndSize_32, 2, false, tmp, 1, false); if(isObj) { markCard(2/*valReg*/, 1, false, 11, false); } rPC += 2; return 0; } int op_iput_quick() { return iput_quick_common(false); } #undef P_GPR_1 #undef P_GPR_2 #define P_GPR_1 PhysicalReg_EBX //! lower bytecode IPUT_WIDE_QUICK //! int op_iput_wide_quick() { u2 vA = INST_A(inst); u2 vB = INST_B(inst); //object u2 tmp = FETCH(1); //byte offset // Request VR delay before transfer to temporary. Only vB needs delay. // vA will have non-zero reference count since transfer to temporary for // it happens after null check, thus no delay is needed. requestVRFreeDelay(vB,VRDELAY_NULLCHECK); get_virtual_reg(vB, OpndSize_32, 1, false); nullCheck(1, false, 1, vB); //maybe optimized away, if not, call cancelVRFreeDelayRequest(vB,VRDELAY_NULLCHECK); get_virtual_reg(vA, OpndSize_64, 1, false); move_reg_to_mem(OpndSize_64, 1, false, tmp, 1, false); rPC += 2; return 0; } #undef P_GPR_1 //! lower bytecode IPUT_OBJECT_QUICK //! int op_iput_object_quick() { return iput_quick_common(true); }