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_DEX_INSTRUCTIONS(rFP) 99 lw a1, OFF_FP_DEX_PC(rFP) 100 lw rIBASE, THREAD_CURRENT_IBASE_OFFSET(rSELF) 101 EAS1(rPC, a0, a1) # generate new dex_pc_ptr 102 /* Do we need to switch interpreters? */ 103 JAL(MterpShouldSwitchInterpreters) 104 bnez v0, MterpFallback 105 /* resume execution at catch block */ 106 EXPORT_PC() 107 FETCH_INST() 108 GET_INST_OPCODE(t0) 109 GOTO_OPCODE(t0) 110 /* NOTE: no fallthrough */ 111 112/* 113 * Common handling for branches with support for Jit profiling. 114 * On entry: 115 * rINST <= signed offset 116 * rPROFILE <= signed hotness countdown (expanded to 32 bits) 117 * 118 * We have quite a few different cases for branch profiling, OSR detection and 119 * suspend check support here. 120 * 121 * Taken backward branches: 122 * If profiling active, do hotness countdown and report if we hit zero. 123 * If in osr check mode, see if our target is a compiled loop header entry and do OSR if so. 124 * Is there a pending suspend request? If so, suspend. 125 * 126 * Taken forward branches and not-taken backward branches: 127 * If in osr check mode, see if our target is a compiled loop header entry and do OSR if so. 128 * 129 * Our most common case is expected to be a taken backward branch with active jit profiling, 130 * but no full OSR check and no pending suspend request. 131 * Next most common case is not-taken branch with no full OSR check. 132 */ 133MterpCommonTakenBranchNoFlags: 134 bgtz rINST, .L_forward_branch # don't add forward branches to hotness 135/* 136 * We need to subtract 1 from positive values and we should not see 0 here, 137 * so we may use the result of the comparison with -1. 138 */ 139#if JIT_CHECK_OSR != -1 140# error "JIT_CHECK_OSR must be -1." 141#endif 142 li t0, JIT_CHECK_OSR 143 beq rPROFILE, t0, .L_osr_check 144 blt rPROFILE, t0, .L_resume_backward_branch 145 subu rPROFILE, 1 146 beqz rPROFILE, .L_add_batch # counted down to zero - report 147.L_resume_backward_branch: 148 lw ra, THREAD_FLAGS_OFFSET(rSELF) 149 REFRESH_IBASE() 150 addu a2, rINST, rINST # a2<- byte offset 151 FETCH_ADVANCE_INST_RB(a2) # update rPC, load rINST 152 and ra, THREAD_SUSPEND_OR_CHECKPOINT_REQUEST 153 bnez ra, .L_suspend_request_pending 154 GET_INST_OPCODE(t0) # extract opcode from rINST 155 GOTO_OPCODE(t0) # jump to next instruction 156 157.L_suspend_request_pending: 158 EXPORT_PC() 159 move a0, rSELF 160 JAL(MterpSuspendCheck) # (self) 161 bnez v0, MterpFallback 162 REFRESH_IBASE() # might have changed during suspend 163 GET_INST_OPCODE(t0) # extract opcode from rINST 164 GOTO_OPCODE(t0) # jump to next instruction 165 166.L_no_count_backwards: 167 li t0, JIT_CHECK_OSR # check for possible OSR re-entry 168 bne rPROFILE, t0, .L_resume_backward_branch 169.L_osr_check: 170 move a0, rSELF 171 addu a1, rFP, OFF_FP_SHADOWFRAME 172 move a2, rINST 173 EXPORT_PC() 174 JAL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset) 175 bnez v0, MterpOnStackReplacement 176 b .L_resume_backward_branch 177 178.L_forward_branch: 179 li t0, JIT_CHECK_OSR # check for possible OSR re-entry 180 beq rPROFILE, t0, .L_check_osr_forward 181.L_resume_forward_branch: 182 add a2, rINST, rINST # a2<- byte offset 183 FETCH_ADVANCE_INST_RB(a2) # update rPC, load rINST 184 GET_INST_OPCODE(t0) # extract opcode from rINST 185 GOTO_OPCODE(t0) # jump to next instruction 186 187.L_check_osr_forward: 188 move a0, rSELF 189 addu a1, rFP, OFF_FP_SHADOWFRAME 190 move a2, rINST 191 EXPORT_PC() 192 JAL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset) 193 bnez v0, MterpOnStackReplacement 194 b .L_resume_forward_branch 195 196.L_add_batch: 197 addu a1, rFP, OFF_FP_SHADOWFRAME 198 sh rPROFILE, SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET(a1) 199 lw a0, OFF_FP_METHOD(rFP) 200 move a2, rSELF 201 JAL(MterpAddHotnessBatch) # (method, shadow_frame, self) 202 move rPROFILE, v0 # restore new hotness countdown to rPROFILE 203 b .L_no_count_backwards 204 205/* 206 * Entered from the conditional branch handlers when OSR check request active on 207 * not-taken path. All Dalvik not-taken conditional branch offsets are 2. 208 */ 209.L_check_not_taken_osr: 210 move a0, rSELF 211 addu a1, rFP, OFF_FP_SHADOWFRAME 212 li a2, 2 213 EXPORT_PC() 214 JAL(MterpMaybeDoOnStackReplacement) # (self, shadow_frame, offset) 215 bnez v0, MterpOnStackReplacement 216 FETCH_ADVANCE_INST(2) 217 GET_INST_OPCODE(t0) # extract opcode from rINST 218 GOTO_OPCODE(t0) # jump to next instruction 219 220/* 221 * On-stack replacement has happened, and now we've returned from the compiled method. 222 */ 223MterpOnStackReplacement: 224#if MTERP_LOGGING 225 move a0, rSELF 226 addu a1, rFP, OFF_FP_SHADOWFRAME 227 move a2, rINST 228 JAL(MterpLogOSR) 229#endif 230 li v0, 1 # Signal normal return 231 b MterpDone 232 233/* 234 * Bail out to reference interpreter. 235 */ 236MterpFallback: 237 EXPORT_PC() 238#if MTERP_LOGGING 239 move a0, rSELF 240 addu a1, rFP, OFF_FP_SHADOWFRAME 241 JAL(MterpLogFallback) 242#endif 243MterpCommonFallback: 244 move v0, zero # signal retry with reference interpreter. 245 b MterpDone 246/* 247 * We pushed some registers on the stack in ExecuteMterpImpl, then saved 248 * SP and LR. Here we restore SP, restore the registers, and then restore 249 * LR to PC. 250 * 251 * On entry: 252 * uint32_t* rFP (should still be live, pointer to base of vregs) 253 */ 254MterpExceptionReturn: 255 li v0, 1 # signal return to caller. 256 b MterpDone 257MterpReturn: 258 lw a2, OFF_FP_RESULT_REGISTER(rFP) 259 sw v0, 0(a2) 260 sw v1, 4(a2) 261 li v0, 1 # signal return to caller. 262MterpDone: 263/* 264 * At this point, we expect rPROFILE to be non-zero. If negative, hotness is disabled or we're 265 * checking for OSR. If greater than zero, we might have unreported hotness to register 266 * (the difference between the ending rPROFILE and the cached hotness counter). rPROFILE 267 * should only reach zero immediately after a hotness decrement, and is then reset to either 268 * a negative special state or the new non-zero countdown value. 269 */ 270 blez rPROFILE, .L_pop_and_return # if > 0, we may have some counts to report. 271 272MterpProfileActive: 273 move rINST, v0 # stash return value 274 /* Report cached hotness counts */ 275 lw a0, OFF_FP_METHOD(rFP) 276 addu a1, rFP, OFF_FP_SHADOWFRAME 277 move a2, rSELF 278 sh rPROFILE, SHADOWFRAME_HOTNESS_COUNTDOWN_OFFSET(a1) 279 JAL(MterpAddHotnessBatch) # (method, shadow_frame, self) 280 move v0, rINST # restore return value 281 282.L_pop_and_return: 283/* Restore from the stack and return. Frame size = STACK_SIZE */ 284 STACK_LOAD_FULL() 285 jalr zero, ra 286 287 .cfi_endproc 288 .end ExecuteMterpImpl 289