1 2/* 3 * =========================================================================== 4 * Common subroutines and data 5 * =========================================================================== 6 */ 7 8 9 10 .text 11 .align 2 12 13#if defined(WITH_JIT) 14/* 15 * Return from the translation cache to the interpreter when the compiler is 16 * having issues translating/executing a Dalvik instruction. We have to skip 17 * the code cache lookup otherwise it is possible to indefinitely bouce 18 * between the interpreter and the code cache if the instruction that fails 19 * to be compiled happens to be at a trace start. 20 */ 21 .global dvmJitToInterpPunt 22dvmJitToInterpPunt: 23 mov rPC, r0 24#ifdef EXIT_STATS 25 mov r0,lr 26 bl dvmBumpPunt; 27#endif 28 EXPORT_PC() 29 adrl rIBASE, dvmAsmInstructionStart 30 FETCH_INST() 31 GET_INST_OPCODE(ip) 32 GOTO_OPCODE(ip) 33 34/* 35 * Return to the interpreter to handle a single instruction. 36 * On entry: 37 * r0 <= PC 38 * r1 <= PC of resume instruction 39 * lr <= resume point in translation 40 */ 41 .global dvmJitToInterpSingleStep 42dvmJitToInterpSingleStep: 43 str lr,[rGLUE,#offGlue_jitResume] 44 str r1,[rGLUE,#offGlue_jitResumePC] 45 mov r1,#kInterpEntryInstr 46 @ enum is 4 byte in aapcs-EABI 47 str r1, [rGLUE, #offGlue_entryPoint] 48 mov rPC,r0 49 EXPORT_PC() 50 adrl rIBASE, dvmAsmInstructionStart 51 mov r2,#kJitSingleStep @ Ask for single step and then revert 52 str r2,[rGLUE,#offGlue_jitState] 53 mov r1,#1 @ set changeInterp to bail to debug interp 54 b common_gotoBail 55 56 57/* 58 * Return from the translation cache and immediately request 59 * a translation for the exit target. Commonly used following 60 * invokes. 61 */ 62 .global dvmJitToTraceSelect 63dvmJitToTraceSelect: 64 ldr rPC,[r14, #-1] @ get our target PC 65 add rINST,r14,#-5 @ save start of chain branch 66 mov r0,rPC 67 bl dvmJitGetCodeAddr @ Is there a translation? 68 cmp r0,#0 69 beq 2f 70 mov r1,rINST 71 bl dvmJitChain @ r0<- dvmJitChain(codeAddr,chainAddr) 72 cmp r0,#0 @ successful chain? 73 bxne r0 @ continue native execution 74 b toInterpreter @ didn't chain - resume with interpreter 75 76/* No translation, so request one if profiling isn't disabled*/ 772: 78 adrl rIBASE, dvmAsmInstructionStart 79 GET_JIT_PROF_TABLE(r0) 80 FETCH_INST() 81 cmp r0, #0 82 bne common_selectTrace 83 GET_INST_OPCODE(ip) 84 GOTO_OPCODE(ip) 85 86/* 87 * Return from the translation cache to the interpreter. 88 * The return was done with a BLX from thumb mode, and 89 * the following 32-bit word contains the target rPC value. 90 * Note that lr (r14) will have its low-order bit set to denote 91 * its thumb-mode origin. 92 * 93 * We'll need to stash our lr origin away, recover the new 94 * target and then check to see if there is a translation available 95 * for our new target. If so, we do a translation chain and 96 * go back to native execution. Otherwise, it's back to the 97 * interpreter (after treating this entry as a potential 98 * trace start). 99 */ 100 .global dvmJitToInterpNormal 101dvmJitToInterpNormal: 102 ldr rPC,[r14, #-1] @ get our target PC 103 add rINST,r14,#-5 @ save start of chain branch 104#ifdef EXIT_STATS 105 bl dvmBumpNormal 106#endif 107 mov r0,rPC 108 bl dvmJitGetCodeAddr @ Is there a translation? 109 cmp r0,#0 110 beq toInterpreter @ go if not, otherwise do chain 111 mov r1,rINST 112 bl dvmJitChain @ r0<- dvmJitChain(codeAddr,chainAddr) 113 cmp r0,#0 @ successful chain? 114 bxne r0 @ continue native execution 115 b toInterpreter @ didn't chain - resume with interpreter 116 117/* 118 * Return from the translation cache to the interpreter to do method invocation. 119 * Check if translation exists for the callee, but don't chain to it. 120 */ 121 .global dvmJitToInterpNoChain 122dvmJitToInterpNoChain: 123#ifdef EXIT_STATS 124 bl dvmBumpNoChain 125#endif 126 mov r0,rPC 127 bl dvmJitGetCodeAddr @ Is there a translation? 128 cmp r0,#0 129 bxne r0 @ continue native execution if so 130 131/* 132 * No translation, restore interpreter regs and start interpreting. 133 * rGLUE & rFP were preserved in the translated code, and rPC has 134 * already been restored by the time we get here. We'll need to set 135 * up rIBASE & rINST, and load the address of the JitTable into r0. 136 */ 137toInterpreter: 138 EXPORT_PC() 139 adrl rIBASE, dvmAsmInstructionStart 140 FETCH_INST() 141 GET_JIT_PROF_TABLE(r0) 142 @ NOTE: intended fallthrough 143/* 144 * Common code to update potential trace start counter, and initiate 145 * a trace-build if appropriate. On entry, rPC should point to the 146 * next instruction to execute, and rINST should be already loaded with 147 * the next opcode word, and r0 holds a pointer to the jit profile 148 * table (pJitProfTable). 149 */ 150common_testUpdateProfile: 151 cmp r0,#0 152 GET_INST_OPCODE(ip) 153 GOTO_OPCODE_IFEQ(ip) @ if not profiling, fallthrough otherwise */ 154 155common_updateProfile: 156 eor r3,rPC,rPC,lsr #12 @ cheap, but fast hash function 157 lsl r3,r3,#23 @ shift out excess 511 158 ldrb r1,[r0,r3,lsr #23] @ get counter 159 GET_INST_OPCODE(ip) 160 subs r1,r1,#1 @ decrement counter 161 strb r1,[r0,r3,lsr #23] @ and store it 162 GOTO_OPCODE_IFNE(ip) @ if not threshold, fallthrough otherwise */ 163 164/* 165 * Here, we switch to the debug interpreter to request 166 * trace selection. First, though, check to see if there 167 * is already a native translation in place (and, if so, 168 * jump to it now). 169 */ 170 mov r1,#255 171 strb r1,[r0,r3,lsr #23] @ reset counter 172 EXPORT_PC() 173 mov r0,rPC 174 bl dvmJitGetCodeAddr @ r0<- dvmJitGetCodeAddr(rPC) 175 cmp r0,#0 176 beq common_selectTrace 177 bxne r0 @ jump to the translation 178common_selectTrace: 179 mov r2,#kJitTSelectRequest @ ask for trace selection 180 str r2,[rGLUE,#offGlue_jitState] 181 mov r1,#1 @ set changeInterp 182 b common_gotoBail 183 184#endif 185 186/* 187 * Common code when a backward branch is taken. 188 * 189 * On entry: 190 * r9 is PC adjustment *in bytes* 191 */ 192common_backwardBranch: 193 mov r0, #kInterpEntryInstr 194 bl common_periodicChecks 195#if defined(WITH_JIT) 196 GET_JIT_PROF_TABLE(r0) 197 FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST 198 cmp r0,#0 199 bne common_updateProfile 200 GET_INST_OPCODE(ip) 201 GOTO_OPCODE(ip) 202#else 203 FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST 204 GET_INST_OPCODE(ip) @ extract opcode from rINST 205 GOTO_OPCODE(ip) @ jump to next instruction 206#endif 207 208 209/* 210 * Need to see if the thread needs to be suspended or debugger/profiler 211 * activity has begun. 212 * 213 * TODO: if JDWP isn't running, zero out pDebuggerActive pointer so we don't 214 * have to do the second ldr. 215 * 216 * TODO: reduce this so we're just checking a single location. 217 * 218 * On entry: 219 * r0 is reentry type, e.g. kInterpEntryInstr 220 * r9 is trampoline PC adjustment *in bytes* 221 */ 222common_periodicChecks: 223 ldr r3, [rGLUE, #offGlue_pSelfSuspendCount] @ r3<- &suspendCount 224 225#if defined(WITH_DEBUGGER) 226 ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive 227#endif 228#if defined(WITH_PROFILER) 229 ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers 230#endif 231 232 ldr r3, [r3] @ r3<- suspendCount (int) 233 234#if defined(WITH_DEBUGGER) 235 ldrb r1, [r1] @ r1<- debuggerActive (boolean) 236#endif 237#if defined (WITH_PROFILER) 238 ldr r2, [r2] @ r2<- activeProfilers (int) 239#endif 240 241 cmp r3, #0 @ suspend pending? 242 bne 2f @ yes, do full suspension check 243 244#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER) 245# if defined(WITH_DEBUGGER) && defined(WITH_PROFILER) 246 orrs r1, r1, r2 @ r1<- r1 | r2 247 cmp r1, #0 @ debugger attached or profiler started? 248# elif defined(WITH_DEBUGGER) 249 cmp r1, #0 @ debugger attached? 250# elif defined(WITH_PROFILER) 251 cmp r2, #0 @ profiler started? 252# endif 253 bne 3f @ debugger/profiler, switch interp 254#endif 255 256 bx lr @ nothing to do, return 257 2582: @ check suspend 259 ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self 260 EXPORT_PC() @ need for precise GC 261 b dvmCheckSuspendPending @ suspend if necessary, then return 262 2633: @ debugger/profiler enabled, bail out 264 add rPC, rPC, r9 @ update rPC 265 str r0, [rGLUE, #offGlue_entryPoint] 266 mov r1, #1 @ "want switch" = true 267 b common_gotoBail 268 269 270/* 271 * The equivalent of "goto bail", this calls through the "bail handler". 272 * 273 * State registers will be saved to the "glue" area before bailing. 274 * 275 * On entry: 276 * r1 is "bool changeInterp", indicating if we want to switch to the 277 * other interpreter or just bail all the way out 278 */ 279common_gotoBail: 280 SAVE_PC_FP_TO_GLUE() @ export state to "glue" 281 mov r0, rGLUE @ r0<- glue ptr 282 b dvmMterpStdBail @ call(glue, changeInterp) 283 284 @add r1, r1, #1 @ using (boolean+1) 285 @add r0, rGLUE, #offGlue_jmpBuf @ r0<- &glue->jmpBuf 286 @bl _longjmp @ does not return 287 @bl common_abort 288 289 290/* 291 * Common code for method invocation with range. 292 * 293 * On entry: 294 * r0 is "Method* methodToCall", the method we're trying to call 295 */ 296common_invokeMethodRange: 297.LinvokeNewRange: 298 @ prepare to copy args to "outs" area of current frame 299 movs r2, rINST, lsr #8 @ r2<- AA (arg count) -- test for zero 300 SAVEAREA_FROM_FP(r10, rFP) @ r10<- stack save area 301 beq .LinvokeArgsDone @ if no args, skip the rest 302 FETCH(r1, 2) @ r1<- CCCC 303 304 @ r0=methodToCall, r1=CCCC, r2=count, r10=outs 305 @ (very few methods have > 10 args; could unroll for common cases) 306 add r3, rFP, r1, lsl #2 @ r3<- &fp[CCCC] 307 sub r10, r10, r2, lsl #2 @ r10<- "outs" area, for call args 308 ldrh r9, [r0, #offMethod_registersSize] @ r9<- methodToCall->regsSize 3091: ldr r1, [r3], #4 @ val = *fp++ 310 subs r2, r2, #1 @ count-- 311 str r1, [r10], #4 @ *outs++ = val 312 bne 1b @ ...while count != 0 313 ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize 314 b .LinvokeArgsDone 315 316/* 317 * Common code for method invocation without range. 318 * 319 * On entry: 320 * r0 is "Method* methodToCall", the method we're trying to call 321 */ 322common_invokeMethodNoRange: 323.LinvokeNewNoRange: 324 @ prepare to copy args to "outs" area of current frame 325 movs r2, rINST, lsr #12 @ r2<- B (arg count) -- test for zero 326 SAVEAREA_FROM_FP(r10, rFP) @ r10<- stack save area 327 FETCH(r1, 2) @ r1<- GFED (load here to hide latency) 328 ldrh r9, [r0, #offMethod_registersSize] @ r9<- methodToCall->regsSize 329 ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize 330 beq .LinvokeArgsDone 331 332 @ r0=methodToCall, r1=GFED, r3=outSize, r2=count, r9=regSize, r10=outs 333.LinvokeNonRange: 334 rsb r2, r2, #5 @ r2<- 5-r2 335 add pc, pc, r2, lsl #4 @ computed goto, 4 instrs each 336 bl common_abort @ (skipped due to ARM prefetch) 3375: and ip, rINST, #0x0f00 @ isolate A 338 ldr r2, [rFP, ip, lsr #6] @ r2<- vA (shift right 8, left 2) 339 mov r0, r0 @ nop 340 str r2, [r10, #-4]! @ *--outs = vA 3414: and ip, r1, #0xf000 @ isolate G 342 ldr r2, [rFP, ip, lsr #10] @ r2<- vG (shift right 12, left 2) 343 mov r0, r0 @ nop 344 str r2, [r10, #-4]! @ *--outs = vG 3453: and ip, r1, #0x0f00 @ isolate F 346 ldr r2, [rFP, ip, lsr #6] @ r2<- vF 347 mov r0, r0 @ nop 348 str r2, [r10, #-4]! @ *--outs = vF 3492: and ip, r1, #0x00f0 @ isolate E 350 ldr r2, [rFP, ip, lsr #2] @ r2<- vE 351 mov r0, r0 @ nop 352 str r2, [r10, #-4]! @ *--outs = vE 3531: and ip, r1, #0x000f @ isolate D 354 ldr r2, [rFP, ip, lsl #2] @ r2<- vD 355 mov r0, r0 @ nop 356 str r2, [r10, #-4]! @ *--outs = vD 3570: @ fall through to .LinvokeArgsDone 358 359.LinvokeArgsDone: @ r0=methodToCall, r3=outSize, r9=regSize 360 ldr r2, [r0, #offMethod_insns] @ r2<- method->insns 361 ldr rINST, [r0, #offMethod_clazz] @ rINST<- method->clazz 362 @ find space for the new stack frame, check for overflow 363 SAVEAREA_FROM_FP(r1, rFP) @ r1<- stack save area 364 sub r1, r1, r9, lsl #2 @ r1<- newFp (old savearea - regsSize) 365 SAVEAREA_FROM_FP(r10, r1) @ r10<- newSaveArea 366@ bl common_dumpRegs 367 ldr r9, [rGLUE, #offGlue_interpStackEnd] @ r9<- interpStackEnd 368 sub r3, r10, r3, lsl #2 @ r3<- bottom (newsave - outsSize) 369 cmp r3, r9 @ bottom < interpStackEnd? 370 ldr r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags 371 blt .LstackOverflow @ yes, this frame will overflow stack 372 373 @ set up newSaveArea 374#ifdef EASY_GDB 375 SAVEAREA_FROM_FP(ip, rFP) @ ip<- stack save area 376 str ip, [r10, #offStackSaveArea_prevSave] 377#endif 378 str rFP, [r10, #offStackSaveArea_prevFrame] 379 str rPC, [r10, #offStackSaveArea_savedPc] 380#if defined(WITH_JIT) 381 mov r9, #0 382 str r9, [r10, #offStackSaveArea_returnAddr] 383#endif 384 str r0, [r10, #offStackSaveArea_method] 385 tst r3, #ACC_NATIVE 386 bne .LinvokeNative 387 388 /* 389 stmfd sp!, {r0-r3} 390 bl common_printNewline 391 mov r0, rFP 392 mov r1, #0 393 bl dvmDumpFp 394 ldmfd sp!, {r0-r3} 395 stmfd sp!, {r0-r3} 396 mov r0, r1 397 mov r1, r10 398 bl dvmDumpFp 399 bl common_printNewline 400 ldmfd sp!, {r0-r3} 401 */ 402 403 ldrh r9, [r2] @ r9 <- load INST from new PC 404 ldr r3, [rINST, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex 405 mov rPC, r2 @ publish new rPC 406 ldr r2, [rGLUE, #offGlue_self] @ r2<- glue->self 407 408 @ Update "glue" values for the new method 409 @ r0=methodToCall, r1=newFp, r2=self, r3=newMethodClass, r9=newINST 410 str r0, [rGLUE, #offGlue_method] @ glue->method = methodToCall 411 str r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ... 412#if defined(WITH_JIT) 413 GET_JIT_PROF_TABLE(r0) 414 mov rFP, r1 @ fp = newFp 415 GET_PREFETCHED_OPCODE(ip, r9) @ extract prefetched opcode from r9 416 mov rINST, r9 @ publish new rINST 417 str r1, [r2, #offThread_curFrame] @ self->curFrame = newFp 418 cmp r0,#0 419 bne common_updateProfile 420 GOTO_OPCODE(ip) @ jump to next instruction 421#else 422 mov rFP, r1 @ fp = newFp 423 GET_PREFETCHED_OPCODE(ip, r9) @ extract prefetched opcode from r9 424 mov rINST, r9 @ publish new rINST 425 str r1, [r2, #offThread_curFrame] @ self->curFrame = newFp 426 GOTO_OPCODE(ip) @ jump to next instruction 427#endif 428 429.LinvokeNative: 430 @ Prep for the native call 431 @ r0=methodToCall, r1=newFp, r10=newSaveArea 432 ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self 433 ldr r9, [r3, #offThread_jniLocal_topCookie] @ r9<- thread->localRef->... 434 str r1, [r3, #offThread_curFrame] @ self->curFrame = newFp 435 str r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top 436 mov r9, r3 @ r9<- glue->self (preserve) 437 438 mov r2, r0 @ r2<- methodToCall 439 mov r0, r1 @ r0<- newFp (points to args) 440 add r1, rGLUE, #offGlue_retval @ r1<- &retval 441 442#ifdef ASSIST_DEBUGGER 443 /* insert fake function header to help gdb find the stack frame */ 444 b .Lskip 445 .type dalvik_mterp, %function 446dalvik_mterp: 447 .fnstart 448 MTERP_ENTRY1 449 MTERP_ENTRY2 450.Lskip: 451#endif 452 453 @mov lr, pc @ set return addr 454 @ldr pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc 455 LDR_PC_LR "[r2, #offMethod_nativeFunc]" 456 457 @ native return; r9=self, r10=newSaveArea 458 @ equivalent to dvmPopJniLocals 459 ldr r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top 460 ldr r1, [r9, #offThread_exception] @ check for exception 461 str rFP, [r9, #offThread_curFrame] @ self->curFrame = fp 462 cmp r1, #0 @ null? 463 str r0, [r9, #offThread_jniLocal_topCookie] @ new top <- old top 464 bne common_exceptionThrown @ no, handle exception 465 466 FETCH_ADVANCE_INST(3) @ advance rPC, load rINST 467 GET_INST_OPCODE(ip) @ extract opcode from rINST 468 GOTO_OPCODE(ip) @ jump to next instruction 469 470.LstackOverflow: 471 ldr r0, [rGLUE, #offGlue_self] @ r0<- self 472 bl dvmHandleStackOverflow 473 b common_exceptionThrown 474#ifdef ASSIST_DEBUGGER 475 .fnend 476#endif 477 478 479 /* 480 * Common code for method invocation, calling through "glue code". 481 * 482 * TODO: now that we have range and non-range invoke handlers, this 483 * needs to be split into two. Maybe just create entry points 484 * that set r9 and jump here? 485 * 486 * On entry: 487 * r0 is "Method* methodToCall", the method we're trying to call 488 * r9 is "bool methodCallRange", indicating if this is a /range variant 489 */ 490 .if 0 491.LinvokeOld: 492 sub sp, sp, #8 @ space for args + pad 493 FETCH(ip, 2) @ ip<- FEDC or CCCC 494 mov r2, r0 @ A2<- methodToCall 495 mov r0, rGLUE @ A0<- glue 496 SAVE_PC_FP_TO_GLUE() @ export state to "glue" 497 mov r1, r9 @ A1<- methodCallRange 498 mov r3, rINST, lsr #8 @ A3<- AA 499 str ip, [sp, #0] @ A4<- ip 500 bl dvmMterp_invokeMethod @ call the C invokeMethod 501 add sp, sp, #8 @ remove arg area 502 b common_resumeAfterGlueCall @ continue to next instruction 503 .endif 504 505 506 507/* 508 * Common code for handling a return instruction. 509 * 510 * This does not return. 511 */ 512common_returnFromMethod: 513.LreturnNew: 514 mov r0, #kInterpEntryReturn 515 mov r9, #0 516 bl common_periodicChecks 517 518 SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old) 519 ldr rFP, [r0, #offStackSaveArea_prevFrame] @ fp = saveArea->prevFrame 520 ldr r9, [r0, #offStackSaveArea_savedPc] @ r9 = saveArea->savedPc 521 ldr r2, [rFP, #(offStackSaveArea_method - sizeofStackSaveArea)] 522 @ r2<- method we're returning to 523 ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self 524 cmp r2, #0 @ is this a break frame? 525 ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz 526 mov r1, #0 @ "want switch" = false 527 beq common_gotoBail @ break frame, bail out completely 528 529 PREFETCH_ADVANCE_INST(rINST, r9, 3) @ advance r9, update new rINST 530 str r2, [rGLUE, #offGlue_method]@ glue->method = newSave->method 531 ldr r1, [r10, #offClassObject_pDvmDex] @ r1<- method->clazz->pDvmDex 532 str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp 533#if defined(WITH_JIT) 534 ldr r3, [r0, #offStackSaveArea_returnAddr] @ r3 = saveArea->returnAddr 535 GET_JIT_PROF_TABLE(r0) 536 mov rPC, r9 @ publish new rPC 537 str r1, [rGLUE, #offGlue_methodClassDex] 538 cmp r3, #0 @ caller is compiled code 539 blxne r3 540 GET_INST_OPCODE(ip) @ extract opcode from rINST 541 cmp r0,#0 542 bne common_updateProfile 543 GOTO_OPCODE(ip) @ jump to next instruction 544#else 545 GET_INST_OPCODE(ip) @ extract opcode from rINST 546 mov rPC, r9 @ publish new rPC 547 str r1, [rGLUE, #offGlue_methodClassDex] 548 GOTO_OPCODE(ip) @ jump to next instruction 549#endif 550 551 /* 552 * Return handling, calls through "glue code". 553 */ 554 .if 0 555.LreturnOld: 556 SAVE_PC_FP_TO_GLUE() @ export state 557 mov r0, rGLUE @ arg to function 558 bl dvmMterp_returnFromMethod 559 b common_resumeAfterGlueCall 560 .endif 561 562 563/* 564 * Somebody has thrown an exception. Handle it. 565 * 566 * If the exception processing code returns to us (instead of falling 567 * out of the interpreter), continue with whatever the next instruction 568 * now happens to be. 569 * 570 * This does not return. 571 */ 572 .global dvmMterpCommonExceptionThrown 573dvmMterpCommonExceptionThrown: 574common_exceptionThrown: 575.LexceptionNew: 576 mov r0, #kInterpEntryThrow 577 mov r9, #0 578 bl common_periodicChecks 579 580#if defined(WITH_JIT) 581 mov r2,#kJitTSelectAbort @ abandon trace selection in progress 582 str r2,[rGLUE,#offGlue_jitState] 583#endif 584 585 ldr r10, [rGLUE, #offGlue_self] @ r10<- glue->self 586 ldr r9, [r10, #offThread_exception] @ r9<- self->exception 587 mov r1, r10 @ r1<- self 588 mov r0, r9 @ r0<- exception 589 bl dvmAddTrackedAlloc @ don't let the exception be GCed 590 mov r3, #0 @ r3<- NULL 591 str r3, [r10, #offThread_exception] @ self->exception = NULL 592 593 /* set up args and a local for "&fp" */ 594 /* (str sp, [sp, #-4]! would be perfect here, but is discouraged) */ 595 str rFP, [sp, #-4]! @ *--sp = fp 596 mov ip, sp @ ip<- &fp 597 mov r3, #0 @ r3<- false 598 str ip, [sp, #-4]! @ *--sp = &fp 599 ldr r1, [rGLUE, #offGlue_method] @ r1<- glue->method 600 mov r0, r10 @ r0<- self 601 ldr r1, [r1, #offMethod_insns] @ r1<- method->insns 602 mov r2, r9 @ r2<- exception 603 sub r1, rPC, r1 @ r1<- pc - method->insns 604 mov r1, r1, asr #1 @ r1<- offset in code units 605 606 /* call, r0 gets catchRelPc (a code-unit offset) */ 607 bl dvmFindCatchBlock @ call(self, relPc, exc, scan?, &fp) 608 609 /* fix earlier stack overflow if necessary; may trash rFP */ 610 ldrb r1, [r10, #offThread_stackOverflowed] 611 cmp r1, #0 @ did we overflow earlier? 612 beq 1f @ no, skip ahead 613 mov rFP, r0 @ save relPc result in rFP 614 mov r0, r10 @ r0<- self 615 bl dvmCleanupStackOverflow @ call(self) 616 mov r0, rFP @ restore result 6171: 618 619 /* update frame pointer and check result from dvmFindCatchBlock */ 620 ldr rFP, [sp, #4] @ retrieve the updated rFP 621 cmp r0, #0 @ is catchRelPc < 0? 622 add sp, sp, #8 @ restore stack 623 bmi .LnotCaughtLocally 624 625 /* adjust locals to match self->curFrame and updated PC */ 626 SAVEAREA_FROM_FP(r1, rFP) @ r1<- new save area 627 ldr r1, [r1, #offStackSaveArea_method] @ r1<- new method 628 str r1, [rGLUE, #offGlue_method] @ glue->method = new method 629 ldr r2, [r1, #offMethod_clazz] @ r2<- method->clazz 630 ldr r3, [r1, #offMethod_insns] @ r3<- method->insns 631 ldr r2, [r2, #offClassObject_pDvmDex] @ r2<- method->clazz->pDvmDex 632 add rPC, r3, r0, asl #1 @ rPC<- method->insns + catchRelPc 633 str r2, [rGLUE, #offGlue_methodClassDex] @ glue->pDvmDex = meth... 634 635 /* release the tracked alloc on the exception */ 636 mov r0, r9 @ r0<- exception 637 mov r1, r10 @ r1<- self 638 bl dvmReleaseTrackedAlloc @ release the exception 639 640 /* restore the exception if the handler wants it */ 641 FETCH_INST() @ load rINST from rPC 642 GET_INST_OPCODE(ip) @ extract opcode from rINST 643 cmp ip, #OP_MOVE_EXCEPTION @ is it "move-exception"? 644 streq r9, [r10, #offThread_exception] @ yes, restore the exception 645 GOTO_OPCODE(ip) @ jump to next instruction 646 647.LnotCaughtLocally: @ r9=exception, r10=self 648 /* fix stack overflow if necessary */ 649 ldrb r1, [r10, #offThread_stackOverflowed] 650 cmp r1, #0 @ did we overflow earlier? 651 movne r0, r10 @ if yes: r0<- self 652 blne dvmCleanupStackOverflow @ if yes: call(self) 653 654 @ may want to show "not caught locally" debug messages here 655#if DVM_SHOW_EXCEPTION >= 2 656 /* call __android_log_print(prio, tag, format, ...) */ 657 /* "Exception %s from %s:%d not caught locally" */ 658 @ dvmLineNumFromPC(method, pc - method->insns) 659 ldr r0, [rGLUE, #offGlue_method] 660 ldr r1, [r0, #offMethod_insns] 661 sub r1, rPC, r1 662 asr r1, r1, #1 663 bl dvmLineNumFromPC 664 str r0, [sp, #-4]! 665 @ dvmGetMethodSourceFile(method) 666 ldr r0, [rGLUE, #offGlue_method] 667 bl dvmGetMethodSourceFile 668 str r0, [sp, #-4]! 669 @ exception->clazz->descriptor 670 ldr r3, [r9, #offObject_clazz] 671 ldr r3, [r3, #offClassObject_descriptor] 672 @ 673 ldr r2, strExceptionNotCaughtLocally 674 ldr r1, strLogTag 675 mov r0, #3 @ LOG_DEBUG 676 bl __android_log_print 677#endif 678 str r9, [r10, #offThread_exception] @ restore exception 679 mov r0, r9 @ r0<- exception 680 mov r1, r10 @ r1<- self 681 bl dvmReleaseTrackedAlloc @ release the exception 682 mov r1, #0 @ "want switch" = false 683 b common_gotoBail @ bail out 684 685 686 /* 687 * Exception handling, calls through "glue code". 688 */ 689 .if 0 690.LexceptionOld: 691 SAVE_PC_FP_TO_GLUE() @ export state 692 mov r0, rGLUE @ arg to function 693 bl dvmMterp_exceptionThrown 694 b common_resumeAfterGlueCall 695 .endif 696 697 698/* 699 * After returning from a "glued" function, pull out the updated 700 * values and start executing at the next instruction. 701 */ 702common_resumeAfterGlueCall: 703 LOAD_PC_FP_FROM_GLUE() @ pull rPC and rFP out of glue 704 FETCH_INST() @ load rINST from rPC 705 GET_INST_OPCODE(ip) @ extract opcode from rINST 706 GOTO_OPCODE(ip) @ jump to next instruction 707 708/* 709 * Invalid array index. 710 */ 711common_errArrayIndex: 712 EXPORT_PC() 713 ldr r0, strArrayIndexException 714 mov r1, #0 715 bl dvmThrowException 716 b common_exceptionThrown 717 718/* 719 * Invalid array value. 720 */ 721common_errArrayStore: 722 EXPORT_PC() 723 ldr r0, strArrayStoreException 724 mov r1, #0 725 bl dvmThrowException 726 b common_exceptionThrown 727 728/* 729 * Integer divide or mod by zero. 730 */ 731common_errDivideByZero: 732 EXPORT_PC() 733 ldr r0, strArithmeticException 734 ldr r1, strDivideByZero 735 bl dvmThrowException 736 b common_exceptionThrown 737 738/* 739 * Attempt to allocate an array with a negative size. 740 */ 741common_errNegativeArraySize: 742 EXPORT_PC() 743 ldr r0, strNegativeArraySizeException 744 mov r1, #0 745 bl dvmThrowException 746 b common_exceptionThrown 747 748/* 749 * Invocation of a non-existent method. 750 */ 751common_errNoSuchMethod: 752 EXPORT_PC() 753 ldr r0, strNoSuchMethodError 754 mov r1, #0 755 bl dvmThrowException 756 b common_exceptionThrown 757 758/* 759 * We encountered a null object when we weren't expecting one. We 760 * export the PC, throw a NullPointerException, and goto the exception 761 * processing code. 762 */ 763common_errNullObject: 764 EXPORT_PC() 765 ldr r0, strNullPointerException 766 mov r1, #0 767 bl dvmThrowException 768 b common_exceptionThrown 769 770/* 771 * For debugging, cause an immediate fault. The source address will 772 * be in lr (use a bl instruction to jump here). 773 */ 774common_abort: 775 ldr pc, .LdeadFood 776.LdeadFood: 777 .word 0xdeadf00d 778 779/* 780 * Spit out a "we were here", preserving all registers. (The attempt 781 * to save ip won't work, but we need to save an even number of 782 * registers for EABI 64-bit stack alignment.) 783 */ 784 .macro SQUEAK num 785common_squeak\num: 786 stmfd sp!, {r0, r1, r2, r3, ip, lr} 787 ldr r0, strSqueak 788 mov r1, #\num 789 bl printf 790 ldmfd sp!, {r0, r1, r2, r3, ip, lr} 791 bx lr 792 .endm 793 794 SQUEAK 0 795 SQUEAK 1 796 SQUEAK 2 797 SQUEAK 3 798 SQUEAK 4 799 SQUEAK 5 800 801/* 802 * Spit out the number in r0, preserving registers. 803 */ 804common_printNum: 805 stmfd sp!, {r0, r1, r2, r3, ip, lr} 806 mov r1, r0 807 ldr r0, strSqueak 808 bl printf 809 ldmfd sp!, {r0, r1, r2, r3, ip, lr} 810 bx lr 811 812/* 813 * Print a newline, preserving registers. 814 */ 815common_printNewline: 816 stmfd sp!, {r0, r1, r2, r3, ip, lr} 817 ldr r0, strNewline 818 bl printf 819 ldmfd sp!, {r0, r1, r2, r3, ip, lr} 820 bx lr 821 822 /* 823 * Print the 32-bit quantity in r0 as a hex value, preserving registers. 824 */ 825common_printHex: 826 stmfd sp!, {r0, r1, r2, r3, ip, lr} 827 mov r1, r0 828 ldr r0, strPrintHex 829 bl printf 830 ldmfd sp!, {r0, r1, r2, r3, ip, lr} 831 bx lr 832 833/* 834 * Print the 64-bit quantity in r0-r1, preserving registers. 835 */ 836common_printLong: 837 stmfd sp!, {r0, r1, r2, r3, ip, lr} 838 mov r3, r1 839 mov r2, r0 840 ldr r0, strPrintLong 841 bl printf 842 ldmfd sp!, {r0, r1, r2, r3, ip, lr} 843 bx lr 844 845/* 846 * Print full method info. Pass the Method* in r0. Preserves regs. 847 */ 848common_printMethod: 849 stmfd sp!, {r0, r1, r2, r3, ip, lr} 850 bl dvmMterpPrintMethod 851 ldmfd sp!, {r0, r1, r2, r3, ip, lr} 852 bx lr 853 854/* 855 * Call a C helper function that dumps regs and possibly some 856 * additional info. Requires the C function to be compiled in. 857 */ 858 .if 0 859common_dumpRegs: 860 stmfd sp!, {r0, r1, r2, r3, ip, lr} 861 bl dvmMterpDumpArmRegs 862 ldmfd sp!, {r0, r1, r2, r3, ip, lr} 863 bx lr 864 .endif 865 866#if 0 867/* 868 * Experiment on VFP mode. 869 * 870 * uint32_t setFPSCR(uint32_t val, uint32_t mask) 871 * 872 * Updates the bits specified by "mask", setting them to the values in "val". 873 */ 874setFPSCR: 875 and r0, r0, r1 @ make sure no stray bits are set 876 fmrx r2, fpscr @ get VFP reg 877 mvn r1, r1 @ bit-invert mask 878 and r2, r2, r1 @ clear masked bits 879 orr r2, r2, r0 @ set specified bits 880 fmxr fpscr, r2 @ set VFP reg 881 mov r0, r2 @ return new value 882 bx lr 883 884 .align 2 885 .global dvmConfigureFP 886 .type dvmConfigureFP, %function 887dvmConfigureFP: 888 stmfd sp!, {ip, lr} 889 /* 0x03000000 sets DN/FZ */ 890 /* 0x00009f00 clears the six exception enable flags */ 891 bl common_squeak0 892 mov r0, #0x03000000 @ r0<- 0x03000000 893 add r1, r0, #0x9f00 @ r1<- 0x03009f00 894 bl setFPSCR 895 ldmfd sp!, {ip, pc} 896#endif 897 898 899/* 900 * String references, must be close to the code that uses them. 901 */ 902 .align 2 903strArithmeticException: 904 .word .LstrArithmeticException 905strArrayIndexException: 906 .word .LstrArrayIndexException 907strArrayStoreException: 908 .word .LstrArrayStoreException 909strDivideByZero: 910 .word .LstrDivideByZero 911strNegativeArraySizeException: 912 .word .LstrNegativeArraySizeException 913strNoSuchMethodError: 914 .word .LstrNoSuchMethodError 915strNullPointerException: 916 .word .LstrNullPointerException 917 918strLogTag: 919 .word .LstrLogTag 920strExceptionNotCaughtLocally: 921 .word .LstrExceptionNotCaughtLocally 922 923strNewline: 924 .word .LstrNewline 925strSqueak: 926 .word .LstrSqueak 927strPrintHex: 928 .word .LstrPrintHex 929strPrintLong: 930 .word .LstrPrintLong 931 932/* 933 * Zero-terminated ASCII string data. 934 * 935 * On ARM we have two choices: do like gcc does, and LDR from a .word 936 * with the address, or use an ADR pseudo-op to get the address 937 * directly. ADR saves 4 bytes and an indirection, but it's using a 938 * PC-relative addressing mode and hence has a limited range, which 939 * makes it not work well with mergeable string sections. 940 */ 941 .section .rodata.str1.4,"aMS",%progbits,1 942 943.LstrBadEntryPoint: 944 .asciz "Bad entry point %d\n" 945.LstrArithmeticException: 946 .asciz "Ljava/lang/ArithmeticException;" 947.LstrArrayIndexException: 948 .asciz "Ljava/lang/ArrayIndexOutOfBoundsException;" 949.LstrArrayStoreException: 950 .asciz "Ljava/lang/ArrayStoreException;" 951.LstrClassCastException: 952 .asciz "Ljava/lang/ClassCastException;" 953.LstrDivideByZero: 954 .asciz "divide by zero" 955.LstrFilledNewArrayNotImpl: 956 .asciz "filled-new-array only implemented for objects and 'int'" 957.LstrInternalError: 958 .asciz "Ljava/lang/InternalError;" 959.LstrInstantiationError: 960 .asciz "Ljava/lang/InstantiationError;" 961.LstrNegativeArraySizeException: 962 .asciz "Ljava/lang/NegativeArraySizeException;" 963.LstrNoSuchMethodError: 964 .asciz "Ljava/lang/NoSuchMethodError;" 965.LstrNullPointerException: 966 .asciz "Ljava/lang/NullPointerException;" 967 968.LstrLogTag: 969 .asciz "mterp" 970.LstrExceptionNotCaughtLocally: 971 .asciz "Exception %s from %s:%d not caught locally\n" 972 973.LstrNewline: 974 .asciz "\n" 975.LstrSqueak: 976 .asciz "<%d>" 977.LstrPrintHex: 978 .asciz "<0x%x>" 979.LstrPrintLong: 980 .asciz "<%lld>" 981 982