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