1/* 2 * =========================================================================== 3 * Common subroutines and data 4 * =========================================================================== 5 */ 6 7 .text 8 .align 2 9 10/* 11 * We've detected a condition that will result in an exception, but the exception 12 * has not yet been thrown. Just bail out to the reference interpreter to deal with it. 13 * TUNING: for consistency, we may want to just go ahead and handle these here. 14 */ 15common_errDivideByZero: 16 EXPORT_PC() 17#if MTERP_LOGGING 18 move a0, rSELF 19 addu a1, rFP, OFF_FP_SHADOWFRAME 20 JAL(MterpLogDivideByZeroException) 21#endif 22 b MterpCommonFallback 23 24common_errArrayIndex: 25 EXPORT_PC() 26#if MTERP_LOGGING 27 move a0, rSELF 28 addu a1, rFP, OFF_FP_SHADOWFRAME 29 JAL(MterpLogArrayIndexException) 30#endif 31 b MterpCommonFallback 32 33common_errNegativeArraySize: 34 EXPORT_PC() 35#if MTERP_LOGGING 36 move a0, rSELF 37 addu a1, rFP, OFF_FP_SHADOWFRAME 38 JAL(MterpLogNegativeArraySizeException) 39#endif 40 b MterpCommonFallback 41 42common_errNoSuchMethod: 43 EXPORT_PC() 44#if MTERP_LOGGING 45 move a0, rSELF 46 addu a1, rFP, OFF_FP_SHADOWFRAME 47 JAL(MterpLogNoSuchMethodException) 48#endif 49 b MterpCommonFallback 50 51common_errNullObject: 52 EXPORT_PC() 53#if MTERP_LOGGING 54 move a0, rSELF 55 addu a1, rFP, OFF_FP_SHADOWFRAME 56 JAL(MterpLogNullObjectException) 57#endif 58 b MterpCommonFallback 59 60common_exceptionThrown: 61 EXPORT_PC() 62#if MTERP_LOGGING 63 move a0, rSELF 64 addu a1, rFP, OFF_FP_SHADOWFRAME 65 JAL(MterpLogExceptionThrownException) 66#endif 67 b MterpCommonFallback 68 69MterpSuspendFallback: 70 EXPORT_PC() 71#if MTERP_LOGGING 72 move a0, rSELF 73 addu a1, rFP, OFF_FP_SHADOWFRAME 74 lw a2, THREAD_FLAGS_OFFSET(rSELF) 75 JAL(MterpLogSuspendFallback) 76#endif 77 b MterpCommonFallback 78 79/* 80 * If we're here, something is out of the ordinary. If there is a pending 81 * exception, handle it. Otherwise, roll back and retry with the reference 82 * interpreter. 83 */ 84MterpPossibleException: 85 lw a0, THREAD_EXCEPTION_OFFSET(rSELF) 86 beqz a0, MterpFallback # If exception, fall back to reference interpreter. 87 /* intentional fallthrough - handle pending exception. */ 88/* 89 * On return from a runtime helper routine, we've found a pending exception. 90 * Can we handle it here - or need to bail out to caller? 91 * 92 */ 93MterpException: 94 move a0, rSELF 95 addu a1, rFP, OFF_FP_SHADOWFRAME 96 JAL(MterpHandleException) # (self, shadow_frame) 97 beqz v0, MterpExceptionReturn # no local catch, back to caller. 98 lw a0, OFF_FP_CODE_ITEM(rFP) 99 lw a1, OFF_FP_DEX_PC(rFP) 100 lw rIBASE, THREAD_CURRENT_IBASE_OFFSET(rSELF) 101 addu rPC, a0, CODEITEM_INSNS_OFFSET 102 sll a1, a1, 1 103 addu rPC, rPC, a1 # generate new dex_pc_ptr 104 /* Do we need to switch interpreters? */ 105 JAL(MterpShouldSwitchInterpreters) 106 bnez v0, MterpFallback 107 /* resume execution at catch block */ 108 EXPORT_PC() 109 FETCH_INST() 110 GET_INST_OPCODE(t0) 111 GOTO_OPCODE(t0) 112 /* NOTE: no fallthrough */ 113 114/* 115 * Common handling for branches with support for Jit profiling. 116 * On entry: 117 * rINST <= signed offset 118 * rPROFILE <= signed hotness countdown (expanded to 32 bits) 119 * 120 * We have quite a few different cases for branch profiling, OSR detection and 121 * suspend check support here. 122 * 123 * Taken backward branches: 124 * If profiling active, do hotness countdown and report if we hit zero. 125 * If in osr check mode, see if our target is a compiled loop header entry and do OSR if so. 126 * Is there a pending suspend request? If so, suspend. 127 * 128 * Taken forward branches and not-taken backward branches: 129 * If in osr check mode, see if our target is a compiled loop header entry and do OSR if so. 130 * 131 * Our most common case is expected to be a taken backward branch with active jit profiling, 132 * but no full OSR check and no pending suspend request. 133 * Next most common case is not-taken branch with no full OSR check. 134 */ 135MterpCommonTakenBranchNoFlags: 136 bgtz rINST, .L_forward_branch # don't add forward branches to hotness 137/* 138 * We need to subtract 1 from positive values and we should not see 0 here, 139 * so we may use the result of the comparison with -1. 140 */ 141#if JIT_CHECK_OSR != -1 142# error "JIT_CHECK_OSR must be -1." 143#endif 144 li t0, JIT_CHECK_OSR 145 beq rPROFILE, t0, .L_osr_check 146 blt rPROFILE, t0, .L_resume_backward_branch 147 subu rPROFILE, 1 148 beqz rPROFILE, .L_add_batch # counted down to zero - report 149.L_resume_backward_branch: 150 lw ra, THREAD_FLAGS_OFFSET(rSELF) 151 REFRESH_IBASE() 152 addu a2, rINST, rINST # a2<- byte offset 153 FETCH_ADVANCE_INST_RB(a2) # update rPC, load rINST 154 and ra, THREAD_SUSPEND_OR_CHECKPOINT_REQUEST 155 bnez ra, .L_suspend_request_pending 156 GET_INST_OPCODE(t0) # extract opcode from rINST 157 GOTO_OPCODE(t0) # jump to next instruction 158 159.L_suspend_request_pending: 160 EXPORT_PC() 161 move a0, rSELF 162 JAL(MterpSuspendCheck) # (self) 163 bnez v0, MterpFallback 164 REFRESH_IBASE() # might have changed during suspend 165 GET_INST_OPCODE(t0) # extract opcode from rINST 166 GOTO_OPCODE(t0) # jump to next instruction 167 168.L_no_count_backwards: 169 li t0, JIT_CHECK_OSR # check for possible OSR re-entry 170 bne rPROFILE, t0, .L_resume_backward_branch 171.L_osr_check: 172 move a0, rSELF 173 addu a1, rFP, OFF_FP_SHADOWFRAME 174 move a2, rINST 175 EXPORT_PC() 176 JAL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset) 177 bnez v0, MterpOnStackReplacement 178 b .L_resume_backward_branch 179 180.L_forward_branch: 181 li t0, JIT_CHECK_OSR # check for possible OSR re-entry 182 beq rPROFILE, t0, .L_check_osr_forward 183.L_resume_forward_branch: 184 add a2, rINST, rINST # a2<- byte offset 185 FETCH_ADVANCE_INST_RB(a2) # update rPC, load rINST 186 GET_INST_OPCODE(t0) # extract opcode from rINST 187 GOTO_OPCODE(t0) # jump to next instruction 188 189.L_check_osr_forward: 190 move a0, rSELF 191 addu a1, rFP, OFF_FP_SHADOWFRAME 192 move a2, rINST 193 EXPORT_PC() 194 JAL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset) 195 bnez v0, MterpOnStackReplacement 196 b .L_resume_forward_branch 197 198.L_add_batch: 199 addu a1, rFP, OFF_FP_SHADOWFRAME 200 sh rPROFILE, SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET(a1) 201 lw a0, OFF_FP_METHOD(rFP) 202 move a2, rSELF 203 JAL(MterpAddHotnessBatch) # (method, shadow_frame, self) 204 move rPROFILE, v0 # restore new hotness countdown to rPROFILE 205 b .L_no_count_backwards 206 207/* 208 * Entered from the conditional branch handlers when OSR check request active on 209 * not-taken path. All Dalvik not-taken conditional branch offsets are 2. 210 */ 211.L_check_not_taken_osr: 212 move a0, rSELF 213 addu a1, rFP, OFF_FP_SHADOWFRAME 214 li a2, 2 215 EXPORT_PC() 216 JAL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset) 217 bnez v0, MterpOnStackReplacement 218 FETCH_ADVANCE_INST(2) 219 GET_INST_OPCODE(t0) # extract opcode from rINST 220 GOTO_OPCODE(t0) # jump to next instruction 221 222/* 223 * On-stack replacement has happened, and now we've returned from the compiled method. 224 */ 225MterpOnStackReplacement: 226#if MTERP_LOGGING 227 move a0, rSELF 228 addu a1, rFP, OFF_FP_SHADOWFRAME 229 move a2, rINST 230 JAL(MterpLogOSR) 231#endif 232 li v0, 1 # Signal normal return 233 b MterpDone 234 235/* 236 * Bail out to reference interpreter. 237 */ 238MterpFallback: 239 EXPORT_PC() 240#if MTERP_LOGGING 241 move a0, rSELF 242 addu a1, rFP, OFF_FP_SHADOWFRAME 243 JAL(MterpLogFallback) 244#endif 245MterpCommonFallback: 246 move v0, zero # signal retry with reference interpreter. 247 b MterpDone 248/* 249 * We pushed some registers on the stack in ExecuteMterpImpl, then saved 250 * SP and LR. Here we restore SP, restore the registers, and then restore 251 * LR to PC. 252 * 253 * On entry: 254 * uint32_t* rFP (should still be live, pointer to base of vregs) 255 */ 256MterpExceptionReturn: 257 li v0, 1 # signal return to caller. 258 b MterpDone 259MterpReturn: 260 lw a2, OFF_FP_RESULT_REGISTER(rFP) 261 sw v0, 0(a2) 262 sw v1, 4(a2) 263 li v0, 1 # signal return to caller. 264MterpDone: 265/* 266 * At this point, we expect rPROFILE to be non-zero. If negative, hotness is disabled or we're 267 * checking for OSR. If greater than zero, we might have unreported hotness to register 268 * (the difference between the ending rPROFILE and the cached hotness counter). rPROFILE 269 * should only reach zero immediately after a hotness decrement, and is then reset to either 270 * a negative special state or the new non-zero countdown value. 271 */ 272 blez rPROFILE, .L_pop_and_return # if > 0, we may have some counts to report. 273 274MterpProfileActive: 275 move rINST, v0 # stash return value 276 /* Report cached hotness counts */ 277 lw a0, OFF_FP_METHOD(rFP) 278 addu a1, rFP, OFF_FP_SHADOWFRAME 279 move a2, rSELF 280 sh rPROFILE, SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET(a1) 281 JAL(MterpAddHotnessBatch) # (method, shadow_frame, self) 282 move v0, rINST # restore return value 283 284.L_pop_and_return: 285/* Restore from the stack and return. Frame size = STACK_SIZE */ 286 STACK_LOAD_FULL() 287 jalr zero, ra 288 289 .end ExecuteMterpImpl 290