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