1/* 2 * =========================================================================== 3 * Common subroutines and data 4 * =========================================================================== 5 */ 6 7 .text 8 .align 2 9 10#if defined(WITH_JIT) 11 12#if defined(WITH_SELF_VERIFICATION) 13/* 14 * "longjmp" to a translation after single-stepping. Before returning 15 * to translation, must save state for self-verification. 16 */ 17 .global dvmJitResumeTranslation @ (Thread* self, u4* dFP) 18dvmJitResumeTranslation: 19 mov rSELF, r0 @ restore self 20 mov rPC, r1 @ restore Dalvik pc 21 mov rFP, r2 @ restore Dalvik fp 22 ldr r10, [rSELF,#offThread_jitResumeNPC] @ resume address 23 mov r2, #0 24 str r2, [rSELF,#offThread_jitResumeNPC] @ reset resume address 25 ldr sp, [rSELF,#offThread_jitResumeNSP] @ cut back native stack 26 b jitSVShadowRunStart @ resume as if cache hit 27 @ expects resume addr in r10 28 29 .global dvmJitToInterpPunt 30dvmJitToInterpPunt: 31 mov r2,#kSVSPunt @ r2<- interpreter entry point 32 mov r3, #0 33 str r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land 34 b jitSVShadowRunEnd @ doesn't return 35 36 .global dvmJitToInterpSingleStep 37dvmJitToInterpSingleStep: 38 mov rPC, r0 @ set up dalvik pc 39 EXPORT_PC() 40 str lr, [rSELF,#offThread_jitResumeNPC] 41 str sp, [rSELF,#offThread_jitResumeNSP] 42 str r1, [rSELF,#offThread_jitResumeDPC] 43 mov r2,#kSVSSingleStep @ r2<- interpreter entry point 44 b jitSVShadowRunEnd @ doesn't return 45 46 47 .global dvmJitToInterpNoChainNoProfile 48dvmJitToInterpNoChainNoProfile: 49 mov r0,rPC @ pass our target PC 50 mov r2,#kSVSNoProfile @ r2<- interpreter entry point 51 mov r3, #0 @ 0 means !inJitCodeCache 52 str r3, [rSELF, #offThread_inJitCodeCache] @ back to the interp land 53 b jitSVShadowRunEnd @ doesn't return 54 55 .global dvmJitToInterpTraceSelectNoChain 56dvmJitToInterpTraceSelectNoChain: 57 mov r0,rPC @ pass our target PC 58 mov r2,#kSVSTraceSelect @ r2<- interpreter entry point 59 mov r3, #0 @ 0 means !inJitCodeCache 60 str r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land 61 b jitSVShadowRunEnd @ doesn't return 62 63 .global dvmJitToInterpTraceSelect 64dvmJitToInterpTraceSelect: 65 ldr r0,[lr, #-1] @ pass our target PC 66 mov r2,#kSVSTraceSelect @ r2<- interpreter entry point 67 mov r3, #0 @ 0 means !inJitCodeCache 68 str r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land 69 b jitSVShadowRunEnd @ doesn't return 70 71 .global dvmJitToInterpBackwardBranch 72dvmJitToInterpBackwardBranch: 73 ldr r0,[lr, #-1] @ pass our target PC 74 mov r2,#kSVSBackwardBranch @ r2<- interpreter entry point 75 mov r3, #0 @ 0 means !inJitCodeCache 76 str r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land 77 b jitSVShadowRunEnd @ doesn't return 78 79 .global dvmJitToInterpNormal 80dvmJitToInterpNormal: 81 ldr r0,[lr, #-1] @ pass our target PC 82 mov r2,#kSVSNormal @ r2<- interpreter entry point 83 mov r3, #0 @ 0 means !inJitCodeCache 84 str r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land 85 b jitSVShadowRunEnd @ doesn't return 86 87 .global dvmJitToInterpNoChain 88dvmJitToInterpNoChain: 89 mov r0,rPC @ pass our target PC 90 mov r2,#kSVSNoChain @ r2<- interpreter entry point 91 mov r3, #0 @ 0 means !inJitCodeCache 92 str r3, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land 93 b jitSVShadowRunEnd @ doesn't return 94#else 95 96/* 97 * "longjmp" to a translation after single-stepping. 98 */ 99 .global dvmJitResumeTranslation @ (Thread* self, u4* dFP) 100dvmJitResumeTranslation: 101 mov rSELF, r0 @ restore self 102 mov rPC, r1 @ restore Dalvik pc 103 mov rFP, r2 @ restore Dalvik fp 104 ldr r0, [rSELF,#offThread_jitResumeNPC] 105 mov r2, #0 106 str r2, [rSELF,#offThread_jitResumeNPC] @ reset resume address 107 ldr sp, [rSELF,#offThread_jitResumeNSP] @ cut back native stack 108 bx r0 @ resume translation 109 110/* 111 * Return from the translation cache to the interpreter when the compiler is 112 * having issues translating/executing a Dalvik instruction. We have to skip 113 * the code cache lookup otherwise it is possible to indefinitely bouce 114 * between the interpreter and the code cache if the instruction that fails 115 * to be compiled happens to be at a trace start. 116 */ 117 .global dvmJitToInterpPunt 118dvmJitToInterpPunt: 119 mov rPC, r0 120#if defined(WITH_JIT_TUNING) 121 mov r0,lr 122 bl dvmBumpPunt; 123#endif 124 EXPORT_PC() 125 mov r0, #0 126 str r0, [rSELF, #offThread_inJitCodeCache] @ Back to the interp land 127 ldr rIBASE, [rSELF, #offThread_curHandlerTable] 128 FETCH_INST() 129 GET_INST_OPCODE(ip) 130 GOTO_OPCODE(ip) 131 132/* 133 * Return to the interpreter to handle a single instruction. 134 * We'll use the normal single-stepping mechanism via interpBreak, 135 * but also save the native pc of the resume point in the translation 136 * and the native sp so that we can later do the equivalent of a 137 * longjmp() to resume. 138 * On entry: 139 * dPC <= Dalvik PC of instrucion to interpret 140 * lr <= resume point in translation 141 * r1 <= Dalvik PC of next instruction 142 */ 143 .global dvmJitToInterpSingleStep 144dvmJitToInterpSingleStep: 145 mov rPC, r0 @ set up dalvik pc 146 EXPORT_PC() 147 str lr, [rSELF,#offThread_jitResumeNPC] 148 str sp, [rSELF,#offThread_jitResumeNSP] 149 str r1, [rSELF,#offThread_jitResumeDPC] 150 mov r1, #1 151 str r1, [rSELF,#offThread_singleStepCount] @ just step once 152 mov r0, rSELF 153 mov r1, #kSubModeCountedStep 154 bl dvmEnableSubMode @ (self, newMode) 155 ldr rIBASE, [rSELF,#offThread_curHandlerTable] 156 FETCH_INST() 157 GET_INST_OPCODE(ip) 158 GOTO_OPCODE(ip) 159 160/* 161 * Return from the translation cache and immediately request 162 * a translation for the exit target. Commonly used for callees. 163 */ 164 .global dvmJitToInterpTraceSelectNoChain 165dvmJitToInterpTraceSelectNoChain: 166#if defined(WITH_JIT_TUNING) 167 bl dvmBumpNoChain 168#endif 169 mov r0,rPC 170 mov r1,rSELF 171 bl dvmJitGetTraceAddrThread @ (pc, self) 172 str r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag 173 mov r1, rPC @ arg1 of translation may need this 174 mov lr, #0 @ in case target is HANDLER_INTERPRET 175 cmp r0,#0 @ !0 means translation exists 176 bxne r0 @ continue native execution if so 177 b 2f @ branch over to use the interpreter 178 179/* 180 * Return from the translation cache and immediately request 181 * a translation for the exit target. Commonly used following 182 * invokes. 183 */ 184 .global dvmJitToInterpTraceSelect 185dvmJitToInterpTraceSelect: 186 ldr rPC,[lr, #-1] @ get our target PC 187 add rINST,lr,#-5 @ save start of chain branch 188 add rINST, #-4 @ .. which is 9 bytes back 189 mov r0,rPC 190 mov r1,rSELF 191 bl dvmJitGetTraceAddrThread @ (pc, self) 192 str r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag 193 cmp r0,#0 194 beq 2f 195 mov r1,rINST 196 bl dvmJitChain @ r0<- dvmJitChain(codeAddr,chainAddr) 197 mov r1, rPC @ arg1 of translation may need this 198 mov lr, #0 @ in case target is HANDLER_INTERPRET 199 cmp r0,#0 @ successful chain? 200 bxne r0 @ continue native execution 201 b toInterpreter @ didn't chain - resume with interpreter 202 203/* No translation, so request one if profiling isn't disabled*/ 2042: 205 ldr rIBASE, [rSELF, #offThread_curHandlerTable] 206 ldr r0, [rSELF, #offThread_pJitProfTable] 207 FETCH_INST() 208 cmp r0, #0 209 movne r2,#kJitTSelectRequestHot @ ask for trace selection 210 bne common_selectTrace 211 GET_INST_OPCODE(ip) 212 GOTO_OPCODE(ip) 213 214/* 215 * Return from the translation cache to the interpreter. 216 * The return was done with a BLX from thumb mode, and 217 * the following 32-bit word contains the target rPC value. 218 * Note that lr (r14) will have its low-order bit set to denote 219 * its thumb-mode origin. 220 * 221 * We'll need to stash our lr origin away, recover the new 222 * target and then check to see if there is a translation available 223 * for our new target. If so, we do a translation chain and 224 * go back to native execution. Otherwise, it's back to the 225 * interpreter (after treating this entry as a potential 226 * trace start). 227 */ 228 .global dvmJitToInterpNormal 229dvmJitToInterpNormal: 230 ldr rPC,[lr, #-1] @ get our target PC 231 add rINST,lr,#-5 @ save start of chain branch 232 add rINST,#-4 @ .. which is 9 bytes back 233#if defined(WITH_JIT_TUNING) 234 bl dvmBumpNormal 235#endif 236 mov r0,rPC 237 mov r1,rSELF 238 bl dvmJitGetTraceAddrThread @ (pc, self) 239 str r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag 240 cmp r0,#0 241 beq toInterpreter @ go if not, otherwise do chain 242 mov r1,rINST 243 bl dvmJitChain @ r0<- dvmJitChain(codeAddr,chainAddr) 244 mov r1, rPC @ arg1 of translation may need this 245 mov lr, #0 @ in case target is HANDLER_INTERPRET 246 cmp r0,#0 @ successful chain? 247 bxne r0 @ continue native execution 248 b toInterpreter @ didn't chain - resume with interpreter 249 250/* 251 * Return from the translation cache to the interpreter to do method invocation. 252 * Check if translation exists for the callee, but don't chain to it. 253 */ 254 .global dvmJitToInterpNoChainNoProfile 255dvmJitToInterpNoChainNoProfile: 256#if defined(WITH_JIT_TUNING) 257 bl dvmBumpNoChain 258#endif 259 mov r0,rPC 260 mov r1,rSELF 261 bl dvmJitGetTraceAddrThread @ (pc, self) 262 str r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag 263 mov r1, rPC @ arg1 of translation may need this 264 mov lr, #0 @ in case target is HANDLER_INTERPRET 265 cmp r0,#0 266 bxne r0 @ continue native execution if so 267 EXPORT_PC() 268 ldr rIBASE, [rSELF, #offThread_curHandlerTable] 269 FETCH_INST() 270 GET_INST_OPCODE(ip) @ extract opcode from rINST 271 GOTO_OPCODE(ip) @ jump to next instruction 272 273/* 274 * Return from the translation cache to the interpreter to do method invocation. 275 * Check if translation exists for the callee, but don't chain to it. 276 */ 277 .global dvmJitToInterpNoChain 278dvmJitToInterpNoChain: 279#if defined(WITH_JIT_TUNING) 280 bl dvmBumpNoChain 281#endif 282 mov r0,rPC 283 mov r1,rSELF 284 bl dvmJitGetTraceAddrThread @ (pc, self) 285 str r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag 286 mov r1, rPC @ arg1 of translation may need this 287 mov lr, #0 @ in case target is HANDLER_INTERPRET 288 cmp r0,#0 289 bxne r0 @ continue native execution if so 290#endif 291 292/* 293 * No translation, restore interpreter regs and start interpreting. 294 * rSELF & rFP were preserved in the translated code, and rPC has 295 * already been restored by the time we get here. We'll need to set 296 * up rIBASE & rINST, and load the address of the JitTable into r0. 297 */ 298toInterpreter: 299 EXPORT_PC() 300 ldr rIBASE, [rSELF, #offThread_curHandlerTable] 301 FETCH_INST() 302 ldr r0, [rSELF, #offThread_pJitProfTable] 303 ldr rIBASE, [rSELF, #offThread_curHandlerTable] 304 @ NOTE: intended fallthrough 305 306/* 307 * Similar to common_updateProfile, but tests for null pJitProfTable 308 * r0 holds pJifProfTAble, rINST is loaded, rPC is current and 309 * rIBASE has been recently refreshed. 310 */ 311common_testUpdateProfile: 312 cmp r0, #0 @ JIT switched off? 313 beq 4f @ return to interp if so 314 315/* 316 * Common code to update potential trace start counter, and initiate 317 * a trace-build if appropriate. 318 * On entry here: 319 * r0 <= pJitProfTable (verified non-NULL) 320 * rPC <= Dalvik PC 321 * rINST <= next instruction 322 */ 323common_updateProfile: 324 eor r3,rPC,rPC,lsr #12 @ cheap, but fast hash function 325 lsl r3,r3,#(32 - JIT_PROF_SIZE_LOG_2) @ shift out excess bits 326 ldrb r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ get counter 327 GET_INST_OPCODE(ip) 328 subs r1,r1,#1 @ decrement counter 329 strb r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ and store it 330 GOTO_OPCODE_IFNE(ip) @ if not threshold, fallthrough otherwise */ 331 332 /* Looks good, reset the counter */ 333 ldr r1, [rSELF, #offThread_jitThreshold] 334 strb r1,[r0,r3,lsr #(32 - JIT_PROF_SIZE_LOG_2)] @ reset counter 335 EXPORT_PC() 336 mov r0,rPC 337 mov r1,rSELF 338 bl dvmJitGetTraceAddrThread @ (pc, self) 339 str r0, [rSELF, #offThread_inJitCodeCache] @ set the inJitCodeCache flag 340 mov r1, rPC @ arg1 of translation may need this 341 mov lr, #0 @ in case target is HANDLER_INTERPRET 342 cmp r0,#0 343#if !defined(WITH_SELF_VERIFICATION) 344 bxne r0 @ jump to the translation 345 mov r2,#kJitTSelectRequest @ ask for trace selection 346 @ fall-through to common_selectTrace 347#else 348 moveq r2,#kJitTSelectRequest @ ask for trace selection 349 beq common_selectTrace 350 /* 351 * At this point, we have a target translation. However, if 352 * that translation is actually the interpret-only pseudo-translation 353 * we want to treat it the same as no translation. 354 */ 355 mov r10, r0 @ save target 356 bl dvmCompilerGetInterpretTemplate 357 cmp r0, r10 @ special case? 358 bne jitSVShadowRunStart @ set up self verification shadow space 359 @ Need to clear the inJitCodeCache flag 360 mov r3, #0 @ 0 means not in the JIT code cache 361 str r3, [rSELF, #offThread_inJitCodeCache] @ back to the interp land 362 GET_INST_OPCODE(ip) 363 GOTO_OPCODE(ip) 364 /* no return */ 365#endif 366 367/* 368 * On entry: 369 * r2 is jit state. 370 */ 371common_selectTrace: 372 ldrh r0,[rSELF,#offThread_subMode] 373 ands r0, #(kSubModeJitTraceBuild | kSubModeJitSV) 374 bne 3f @ already doing JIT work, continue 375 str r2,[rSELF,#offThread_jitState] 376 mov r0, rSELF 377/* 378 * Call out to validate trace-building request. If successful, 379 * rIBASE will be swapped to to send us into single-stepping trace 380 * building mode, so we need to refresh before we continue. 381 */ 382 EXPORT_PC() 383 SAVE_PC_FP_TO_SELF() @ copy of pc/fp to Thread 384 bl dvmJitCheckTraceRequest 3853: 386 FETCH_INST() 387 ldr rIBASE, [rSELF, #offThread_curHandlerTable] 3884: 389 GET_INST_OPCODE(ip) @ extract opcode from rINST 390 GOTO_OPCODE(ip) 391 /* no return */ 392#endif 393 394#if defined(WITH_SELF_VERIFICATION) 395/* 396 * Save PC and registers to shadow memory for self verification mode 397 * before jumping to native translation. 398 * On entry: 399 * rPC, rFP, rSELF: the values that they should contain 400 * r10: the address of the target translation. 401 */ 402jitSVShadowRunStart: 403 mov r0,rPC @ r0<- program counter 404 mov r1,rFP @ r1<- frame pointer 405 mov r2,rSELF @ r2<- self (Thread) pointer 406 mov r3,r10 @ r3<- target translation 407 bl dvmSelfVerificationSaveState @ save registers to shadow space 408 ldr rFP,[r0,#offShadowSpace_shadowFP] @ rFP<- fp in shadow space 409 bx r10 @ jump to the translation 410 411/* 412 * Restore PC, registers, and interpreter state to original values 413 * before jumping back to the interpreter. 414 * On entry: 415 * r0: dPC 416 * r2: self verification state 417 */ 418jitSVShadowRunEnd: 419 mov r1,rFP @ pass ending fp 420 mov r3,rSELF @ pass self ptr for convenience 421 bl dvmSelfVerificationRestoreState @ restore pc and fp values 422 LOAD_PC_FP_FROM_SELF() @ restore pc, fp 423 ldr r1,[r0,#offShadowSpace_svState] @ get self verification state 424 cmp r1,#0 @ check for punt condition 425 beq 1f 426 @ Set up SV single-stepping 427 mov r0, rSELF 428 mov r1, #kSubModeJitSV 429 bl dvmEnableSubMode @ (self, subMode) 430 mov r2,#kJitSelfVerification @ ask for self verification 431 str r2,[rSELF,#offThread_jitState] 432 @ intentional fallthrough 4331: @ exit to interpreter without check 434 EXPORT_PC() 435 ldr rIBASE, [rSELF, #offThread_curHandlerTable] 436 FETCH_INST() 437 GET_INST_OPCODE(ip) 438 GOTO_OPCODE(ip) 439#endif 440 441/* 442 * The equivalent of "goto bail", this calls through the "bail handler". 443 * It will end this interpreter activation, and return to the caller 444 * of dvmMterpStdRun. 445 * 446 * State registers will be saved to the "thread" area before bailing 447 * debugging purposes 448 */ 449common_gotoBail: 450 SAVE_PC_FP_TO_SELF() @ export state to "thread" 451 mov r0, rSELF @ r0<- self ptr 452 b dvmMterpStdBail @ call(self, changeInterp) 453 454/* 455 * The JIT's invoke method needs to remember the callsite class and 456 * target pair. Save them here so that they are available to 457 * dvmCheckJit following the interpretation of this invoke. 458 */ 459#if defined(WITH_JIT) 460save_callsiteinfo: 461 cmp r9, #0 462 ldrne r9, [r9, #offObject_clazz] 463 str r0, [rSELF, #offThread_methodToCall] 464 str r9, [rSELF, #offThread_callsiteClass] 465 bx lr 466#endif 467 468/* 469 * Common code for method invocation with range. 470 * 471 * On entry: 472 * r0 is "Method* methodToCall", r9 is "this" 473 */ 474common_invokeMethodRange: 475.LinvokeNewRange: 476#if defined(WITH_JIT) 477 ldrh r1, [rSELF, #offThread_subMode] 478 ands r1, #kSubModeJitTraceBuild 479 blne save_callsiteinfo 480#endif 481 @ prepare to copy args to "outs" area of current frame 482 movs r2, rINST, lsr #8 @ r2<- AA (arg count) -- test for zero 483 SAVEAREA_FROM_FP(r10, rFP) @ r10<- stack save area 484 beq .LinvokeArgsDone @ if no args, skip the rest 485 FETCH(r1, 2) @ r1<- CCCC 486 487.LinvokeRangeArgs: 488 @ r0=methodToCall, r1=CCCC, r2=count, r10=outs 489 @ (very few methods have > 10 args; could unroll for common cases) 490 add r3, rFP, r1, lsl #2 @ r3<- &fp[CCCC] 491 sub r10, r10, r2, lsl #2 @ r10<- "outs" area, for call args 4921: ldr r1, [r3], #4 @ val = *fp++ 493 subs r2, r2, #1 @ count-- 494 str r1, [r10], #4 @ *outs++ = val 495 bne 1b @ ...while count != 0 496 b .LinvokeArgsDone 497 498/* 499 * Common code for method invocation without range. 500 * 501 * On entry: 502 * r0 is "Method* methodToCall", r9 is "this" 503 */ 504common_invokeMethodNoRange: 505.LinvokeNewNoRange: 506#if defined(WITH_JIT) 507 ldrh r1, [rSELF, #offThread_subMode] 508 ands r1, #kSubModeJitTraceBuild 509 blne save_callsiteinfo 510#endif 511 @ prepare to copy args to "outs" area of current frame 512 movs r2, rINST, lsr #12 @ r2<- B (arg count) -- test for zero 513 SAVEAREA_FROM_FP(r10, rFP) @ r10<- stack save area 514 FETCH(r1, 2) @ r1<- GFED (load here to hide latency) 515 beq .LinvokeArgsDone 516 517 @ r0=methodToCall, r1=GFED, r2=count, r10=outs 518.LinvokeNonRange: 519 rsb r2, r2, #5 @ r2<- 5-r2 520 add pc, pc, r2, lsl #4 @ computed goto, 4 instrs each 521 bl common_abort @ (skipped due to ARM prefetch) 5225: and ip, rINST, #0x0f00 @ isolate A 523 ldr r2, [rFP, ip, lsr #6] @ r2<- vA (shift right 8, left 2) 524 mov r0, r0 @ nop 525 str r2, [r10, #-4]! @ *--outs = vA 5264: and ip, r1, #0xf000 @ isolate G 527 ldr r2, [rFP, ip, lsr #10] @ r2<- vG (shift right 12, left 2) 528 mov r0, r0 @ nop 529 str r2, [r10, #-4]! @ *--outs = vG 5303: and ip, r1, #0x0f00 @ isolate F 531 ldr r2, [rFP, ip, lsr #6] @ r2<- vF 532 mov r0, r0 @ nop 533 str r2, [r10, #-4]! @ *--outs = vF 5342: and ip, r1, #0x00f0 @ isolate E 535 ldr r2, [rFP, ip, lsr #2] @ r2<- vE 536 mov r0, r0 @ nop 537 str r2, [r10, #-4]! @ *--outs = vE 5381: and ip, r1, #0x000f @ isolate D 539 ldr r2, [rFP, ip, lsl #2] @ r2<- vD 540 mov r0, r0 @ nop 541 str r2, [r10, #-4]! @ *--outs = vD 5420: @ fall through to .LinvokeArgsDone 543 544.LinvokeArgsDone: @ r0=methodToCall 545 ldrh r9, [r0, #offMethod_registersSize] @ r9<- methodToCall->regsSize 546 ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize 547 ldr r2, [r0, #offMethod_insns] @ r2<- method->insns 548 ldr rINST, [r0, #offMethod_clazz] @ rINST<- method->clazz 549 @ find space for the new stack frame, check for overflow 550 SAVEAREA_FROM_FP(r1, rFP) @ r1<- stack save area 551 sub r1, r1, r9, lsl #2 @ r1<- newFp (old savearea - regsSize) 552 SAVEAREA_FROM_FP(r10, r1) @ r10<- newSaveArea 553@ bl common_dumpRegs 554 ldr r9, [rSELF, #offThread_interpStackEnd] @ r9<- interpStackEnd 555 sub r3, r10, r3, lsl #2 @ r3<- bottom (newsave - outsSize) 556 cmp r3, r9 @ bottom < interpStackEnd? 557 ldrh lr, [rSELF, #offThread_subMode] 558 ldr r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags 559 blo .LstackOverflow @ yes, this frame will overflow stack 560 561 @ set up newSaveArea 562#ifdef EASY_GDB 563 SAVEAREA_FROM_FP(ip, rFP) @ ip<- stack save area 564 str ip, [r10, #offStackSaveArea_prevSave] 565#endif 566 str rFP, [r10, #offStackSaveArea_prevFrame] 567 str rPC, [r10, #offStackSaveArea_savedPc] 568#if defined(WITH_JIT) 569 mov r9, #0 570 str r9, [r10, #offStackSaveArea_returnAddr] 571#endif 572 str r0, [r10, #offStackSaveArea_method] 573 574 @ Profiling? 575 cmp lr, #0 @ any special modes happening? 576 bne 2f @ go if so 5771: 578 tst r3, #ACC_NATIVE 579 bne .LinvokeNative 580 581 /* 582 stmfd sp!, {r0-r3} 583 bl common_printNewline 584 mov r0, rFP 585 mov r1, #0 586 bl dvmDumpFp 587 ldmfd sp!, {r0-r3} 588 stmfd sp!, {r0-r3} 589 mov r0, r1 590 mov r1, r10 591 bl dvmDumpFp 592 bl common_printNewline 593 ldmfd sp!, {r0-r3} 594 */ 595 596 ldrh r9, [r2] @ r9 <- load INST from new PC 597 ldr r3, [rINST, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex 598 mov rPC, r2 @ publish new rPC 599 600 @ Update state values for the new method 601 @ r0=methodToCall, r1=newFp, r3=newMethodClass, r9=newINST 602 str r0, [rSELF, #offThread_method] @ self->method = methodToCall 603 str r3, [rSELF, #offThread_methodClassDex] @ self->methodClassDex = ... 604 mov r2, #1 605 str r2, [rSELF, #offThread_debugIsMethodEntry] 606#if defined(WITH_JIT) 607 ldr r0, [rSELF, #offThread_pJitProfTable] 608 mov rFP, r1 @ fp = newFp 609 GET_PREFETCHED_OPCODE(ip, r9) @ extract prefetched opcode from r9 610 mov rINST, r9 @ publish new rINST 611 str r1, [rSELF, #offThread_curFrame] @ curFrame = newFp 612 cmp r0,#0 613 bne common_updateProfile 614 GOTO_OPCODE(ip) @ jump to next instruction 615#else 616 mov rFP, r1 @ fp = newFp 617 GET_PREFETCHED_OPCODE(ip, r9) @ extract prefetched opcode from r9 618 mov rINST, r9 @ publish new rINST 619 str r1, [rSELF, #offThread_curFrame] @ curFrame = newFp 620 GOTO_OPCODE(ip) @ jump to next instruction 621#endif 622 6232: 624 @ Profiling - record method entry. r0: methodToCall 625 stmfd sp!, {r0-r3} @ preserve r0-r3 626 str rPC, [rSELF, #offThread_pc] @ update interpSave.pc 627 mov r1, r0 628 mov r0, rSELF 629 bl dvmReportInvoke @ (self, method) 630 ldmfd sp!, {r0-r3} @ restore r0-r3 631 b 1b 632 633.LinvokeNative: 634 @ Prep for the native call 635 @ r0=methodToCall, r1=newFp, r10=newSaveArea 636 ldrh lr, [rSELF, #offThread_subMode] 637 ldr r9, [rSELF, #offThread_jniLocal_topCookie]@r9<-thread->localRef->... 638 str r1, [rSELF, #offThread_curFrame] @ curFrame = newFp 639 str r9, [r10, #offStackSaveArea_localRefCookie] @newFp->localRefCookie=top 640 mov r2, r0 @ r2<- methodToCall 641 mov r0, r1 @ r0<- newFp (points to args) 642 add r1, rSELF, #offThread_retval @ r1<- &retval 643 mov r3, rSELF @ arg3<- self 644 645#ifdef ASSIST_DEBUGGER 646 /* insert fake function header to help gdb find the stack frame */ 647 b .Lskip 648 .type dalvik_mterp, %function 649dalvik_mterp: 650 .fnstart 651 MTERP_ENTRY1 652 MTERP_ENTRY2 653.Lskip: 654#endif 655 656 cmp lr, #0 @ any special SubModes active? 657 bne 11f @ go handle them if so 658 ldr ip, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc 659 blx ip 6607: 661 662 @ native return; r10=newSaveArea 663 @ equivalent to dvmPopJniLocals 664 ldr r0, [r10, #offStackSaveArea_localRefCookie] @ r0<- saved top 665 ldr r1, [rSELF, #offThread_exception] @ check for exception 666 str rFP, [rSELF, #offThread_curFrame] @ curFrame = fp 667 cmp r1, #0 @ null? 668 str r0, [rSELF, #offThread_jniLocal_topCookie] @ new top <- old top 669 bne common_exceptionThrown @ no, handle exception 670 671 FETCH_ADVANCE_INST(3) @ advance rPC, load rINST 672 GET_INST_OPCODE(ip) @ extract opcode from rINST 673 GOTO_OPCODE(ip) @ jump to next instruction 674 67511: 676 @ r0=newFp, r1=&retval, r2=methodToCall, r3=self, lr=subModes 677 stmfd sp!, {r0-r3} @ save all but subModes 678 mov r0, r2 @ r0<- methodToCall 679 mov r1, rSELF 680 mov r2, rFP 681 bl dvmReportPreNativeInvoke @ (methodToCall, self, fp) 682 ldmfd sp, {r0-r3} @ refresh. NOTE: no sp autoincrement 683 684 @ Call the native method 685 ldr ip, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc 686 blx ip 687 688 @ Restore the pre-call arguments 689 ldmfd sp!, {r0-r3} @ r2<- methodToCall (others unneeded) 690 691 @ Finish up any post-invoke subMode requirements 692 mov r0, r2 @ r0<- methodToCall 693 mov r1, rSELF 694 mov r2, rFP 695 bl dvmReportPostNativeInvoke @ (methodToCall, self, fp) 696 b 7b @ resume 697 698.LstackOverflow: @ r0=methodToCall 699 mov r1, r0 @ r1<- methodToCall 700 mov r0, rSELF @ r0<- self 701 bl dvmHandleStackOverflow 702 b common_exceptionThrown 703#ifdef ASSIST_DEBUGGER 704 .fnend 705 .size dalvik_mterp, .-dalvik_mterp 706#endif 707 708 709 /* 710 * Common code for method invocation, calling through "glue code". 711 * 712 * TODO: now that we have range and non-range invoke handlers, this 713 * needs to be split into two. Maybe just create entry points 714 * that set r9 and jump here? 715 * 716 * On entry: 717 * r0 is "Method* methodToCall", the method we're trying to call 718 * r9 is "bool methodCallRange", indicating if this is a /range variant 719 */ 720 .if 0 721.LinvokeOld: 722 sub sp, sp, #8 @ space for args + pad 723 FETCH(ip, 2) @ ip<- FEDC or CCCC 724 mov r2, r0 @ A2<- methodToCall 725 mov r0, rSELF @ A0<- self 726 SAVE_PC_FP_TO_SELF() @ export state to "self" 727 mov r1, r9 @ A1<- methodCallRange 728 mov r3, rINST, lsr #8 @ A3<- AA 729 str ip, [sp, #0] @ A4<- ip 730 bl dvmMterp_invokeMethod @ call the C invokeMethod 731 add sp, sp, #8 @ remove arg area 732 b common_resumeAfterGlueCall @ continue to next instruction 733 .endif 734 735 736 737/* 738 * Common code for handling a return instruction. 739 * 740 * This does not return. 741 */ 742common_returnFromMethod: 743.LreturnNew: 744 ldrh lr, [rSELF, #offThread_subMode] 745 SAVEAREA_FROM_FP(r0, rFP) 746 ldr r9, [r0, #offStackSaveArea_savedPc] @ r9 = saveArea->savedPc 747 cmp lr, #0 @ any special subMode handling needed? 748 bne 19f 74914: 750 ldr rFP, [r0, #offStackSaveArea_prevFrame] @ fp = saveArea->prevFrame 751 ldr r2, [rFP, #(offStackSaveArea_method - sizeofStackSaveArea)] 752 @ r2<- method we're returning to 753 cmp r2, #0 @ is this a break frame? 754#if defined(WORKAROUND_CORTEX_A9_745320) 755 /* Don't use conditional loads if the HW defect exists */ 756 beq 15f 757 ldr r10, [r2, #offMethod_clazz] @ r10<- method->clazz 75815: 759#else 760 ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz 761#endif 762 beq common_gotoBail @ break frame, bail out completely 763 764 ldr rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh rIBASE 765 PREFETCH_ADVANCE_INST(rINST, r9, 3) @ advance r9, update new rINST 766 str r2, [rSELF, #offThread_method]@ self->method = newSave->method 767 ldr r1, [r10, #offClassObject_pDvmDex] @ r1<- method->clazz->pDvmDex 768 str rFP, [rSELF, #offThread_curFrame] @ curFrame = fp 769#if defined(WITH_JIT) 770 ldr r10, [r0, #offStackSaveArea_returnAddr] @ r10 = saveArea->returnAddr 771 mov rPC, r9 @ publish new rPC 772 str r1, [rSELF, #offThread_methodClassDex] 773 str r10, [rSELF, #offThread_inJitCodeCache] @ may return to JIT'ed land 774 cmp r10, #0 @ caller is compiled code 775 blxne r10 776 GET_INST_OPCODE(ip) @ extract opcode from rINST 777 GOTO_OPCODE(ip) @ jump to next instruction 778#else 779 GET_INST_OPCODE(ip) @ extract opcode from rINST 780 mov rPC, r9 @ publish new rPC 781 str r1, [rSELF, #offThread_methodClassDex] 782 GOTO_OPCODE(ip) @ jump to next instruction 783#endif 784 78519: 786 @ Handle special actions 787 @ On entry, r0: StackSaveArea 788 ldr r1, [r0, #offStackSaveArea_prevFrame] @ r2<- prevFP 789 str rPC, [rSELF, #offThread_pc] @ update interpSave.pc 790 str r1, [rSELF, #offThread_curFrame] @ update interpSave.curFrame 791 mov r0, rSELF 792 bl dvmReportReturn @ (self) 793 SAVEAREA_FROM_FP(r0, rFP) @ restore StackSaveArea 794 b 14b @ continue 795 796 /* 797 * Return handling, calls through "glue code". 798 */ 799 .if 0 800.LreturnOld: 801 SAVE_PC_FP_TO_SELF() @ export state 802 mov r0, rSELF @ arg to function 803 bl dvmMterp_returnFromMethod 804 b common_resumeAfterGlueCall 805 .endif 806 807 808/* 809 * Somebody has thrown an exception. Handle it. 810 * 811 * If the exception processing code returns to us (instead of falling 812 * out of the interpreter), continue with whatever the next instruction 813 * now happens to be. 814 * 815 * This does not return. 816 */ 817 .global dvmMterpCommonExceptionThrown 818dvmMterpCommonExceptionThrown: 819common_exceptionThrown: 820.LexceptionNew: 821 822 EXPORT_PC() 823 824 mov r0, rSELF 825 bl dvmCheckSuspendPending 826 827 ldr r9, [rSELF, #offThread_exception] @ r9<- self->exception 828 mov r1, rSELF @ r1<- self 829 mov r0, r9 @ r0<- exception 830 bl dvmAddTrackedAlloc @ don't let the exception be GCed 831 ldrh r2, [rSELF, #offThread_subMode] @ get subMode flags 832 mov r3, #0 @ r3<- NULL 833 str r3, [rSELF, #offThread_exception] @ self->exception = NULL 834 835 @ Special subMode? 836 cmp r2, #0 @ any special subMode handling needed? 837 bne 7f @ go if so 8388: 839 /* set up args and a local for "&fp" */ 840 /* (str sp, [sp, #-4]! would be perfect here, but is discouraged) */ 841 str rFP, [sp, #-4]! @ *--sp = fp 842 mov ip, sp @ ip<- &fp 843 mov r3, #0 @ r3<- false 844 str ip, [sp, #-4]! @ *--sp = &fp 845 ldr r1, [rSELF, #offThread_method] @ r1<- self->method 846 mov r0, rSELF @ r0<- self 847 ldr r1, [r1, #offMethod_insns] @ r1<- method->insns 848 mov r2, r9 @ r2<- exception 849 sub r1, rPC, r1 @ r1<- pc - method->insns 850 mov r1, r1, asr #1 @ r1<- offset in code units 851 852 /* call, r0 gets catchRelPc (a code-unit offset) */ 853 bl dvmFindCatchBlock @ call(self, relPc, exc, scan?, &fp) 854 855 /* fix earlier stack overflow if necessary; may trash rFP */ 856 ldrb r1, [rSELF, #offThread_stackOverflowed] 857 cmp r1, #0 @ did we overflow earlier? 858 beq 1f @ no, skip ahead 859 mov rFP, r0 @ save relPc result in rFP 860 mov r0, rSELF @ r0<- self 861 mov r1, r9 @ r1<- exception 862 bl dvmCleanupStackOverflow @ call(self) 863 mov r0, rFP @ restore result 8641: 865 866 /* update frame pointer and check result from dvmFindCatchBlock */ 867 ldr rFP, [sp, #4] @ retrieve the updated rFP 868 cmp r0, #0 @ is catchRelPc < 0? 869 add sp, sp, #8 @ restore stack 870 bmi .LnotCaughtLocally 871 872 /* adjust locals to match self->interpSave.curFrame and updated PC */ 873 SAVEAREA_FROM_FP(r1, rFP) @ r1<- new save area 874 ldr r1, [r1, #offStackSaveArea_method] @ r1<- new method 875 str r1, [rSELF, #offThread_method] @ self->method = new method 876 ldr r2, [r1, #offMethod_clazz] @ r2<- method->clazz 877 ldr r3, [r1, #offMethod_insns] @ r3<- method->insns 878 ldr r2, [r2, #offClassObject_pDvmDex] @ r2<- method->clazz->pDvmDex 879 add rPC, r3, r0, asl #1 @ rPC<- method->insns + catchRelPc 880 str r2, [rSELF, #offThread_methodClassDex] @ self->pDvmDex = meth... 881 882 /* release the tracked alloc on the exception */ 883 mov r0, r9 @ r0<- exception 884 mov r1, rSELF @ r1<- self 885 bl dvmReleaseTrackedAlloc @ release the exception 886 887 /* restore the exception if the handler wants it */ 888 ldr rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh rIBASE 889 FETCH_INST() @ load rINST from rPC 890 GET_INST_OPCODE(ip) @ extract opcode from rINST 891 cmp ip, #OP_MOVE_EXCEPTION @ is it "move-exception"? 892 streq r9, [rSELF, #offThread_exception] @ yes, restore the exception 893 GOTO_OPCODE(ip) @ jump to next instruction 894 895 @ Manage debugger bookkeeping 8967: 897 str rPC, [rSELF, #offThread_pc] @ update interpSave.pc 898 str rFP, [rSELF, #offThread_curFrame] @ update interpSave.curFrame 899 mov r0, rSELF @ arg0<- self 900 mov r1, r9 @ arg1<- exception 901 bl dvmReportExceptionThrow @ (self, exception) 902 b 8b @ resume with normal handling 903 904.LnotCaughtLocally: @ r9=exception 905 /* fix stack overflow if necessary */ 906 ldrb r1, [rSELF, #offThread_stackOverflowed] 907 cmp r1, #0 @ did we overflow earlier? 908 movne r0, rSELF @ if yes: r0<- self 909 movne r1, r9 @ if yes: r1<- exception 910 blne dvmCleanupStackOverflow @ if yes: call(self) 911 912 @ may want to show "not caught locally" debug messages here 913#if DVM_SHOW_EXCEPTION >= 2 914 /* call __android_log_print(prio, tag, format, ...) */ 915 /* "Exception %s from %s:%d not caught locally" */ 916 @ dvmLineNumFromPC(method, pc - method->insns) 917 ldr r0, [rSELF, #offThread_method] 918 ldr r1, [r0, #offMethod_insns] 919 sub r1, rPC, r1 920 asr r1, r1, #1 921 bl dvmLineNumFromPC 922 str r0, [sp, #-4]! 923 @ dvmGetMethodSourceFile(method) 924 ldr r0, [rSELF, #offThread_method] 925 bl dvmGetMethodSourceFile 926 str r0, [sp, #-4]! 927 @ exception->clazz->descriptor 928 ldr r3, [r9, #offObject_clazz] 929 ldr r3, [r3, #offClassObject_descriptor] 930 @ 931 ldr r2, strExceptionNotCaughtLocally 9320: add r2, pc 933 ldr r1, strLogTag 9341: add r1, pc 935 mov r0, #3 @ LOG_DEBUG 936 bl __android_log_print 937#endif 938 str r9, [rSELF, #offThread_exception] @ restore exception 939 mov r0, r9 @ r0<- exception 940 mov r1, rSELF @ r1<- self 941 bl dvmReleaseTrackedAlloc @ release the exception 942 b common_gotoBail @ bail out 943 944strExceptionNotCaughtLocally: 945 .word PCREL_REF(.LstrExceptionNotCaughtLocally,0b) 946strLogTag: 947 .word PCREL_REF(.LstrLogTag,1b) 948 949 /* 950 * Exception handling, calls through "glue code". 951 */ 952 .if 0 953.LexceptionOld: 954 SAVE_PC_FP_TO_SELF() @ export state 955 mov r0, rSELF @ arg to function 956 bl dvmMterp_exceptionThrown 957 b common_resumeAfterGlueCall 958 .endif 959 960#if defined(WITH_JIT) 961 /* 962 * If the JIT is actively building a trace we need to make sure 963 * that the field is fully resolved before including the current 964 * instruction. 965 * 966 * On entry: 967 * r10: &dvmDex->pResFields[field] 968 * r0: field pointer (must preserve) 969 */ 970common_verifyField: 971 ldrh r3, [rSELF, #offThread_subMode] @ r3 <- submode byte 972 ands r3, #kSubModeJitTraceBuild 973 bxeq lr @ Not building trace, continue 974 ldr r1, [r10] @ r1<- reload resolved StaticField ptr 975 cmp r1, #0 @ resolution complete? 976 bxne lr @ yes, continue 977 stmfd sp!, {r0-r2,lr} @ save regs 978 mov r0, rSELF 979 mov r1, rPC 980 bl dvmJitEndTraceSelect @ (self,pc) end trace before this inst 981 ldmfd sp!, {r0-r2, lr} 982 bx lr @ return 983#endif 984 985/* 986 * After returning from a "glued" function, pull out the updated 987 * values and start executing at the next instruction. 988 */ 989common_resumeAfterGlueCall: 990 LOAD_PC_FP_FROM_SELF() @ pull rPC and rFP out of thread 991 ldr rIBASE, [rSELF, #offThread_curHandlerTable] @ refresh 992 FETCH_INST() @ load rINST from rPC 993 GET_INST_OPCODE(ip) @ extract opcode from rINST 994 GOTO_OPCODE(ip) @ jump to next instruction 995 996/* 997 * Invalid array index. Note that our calling convention is strange; we use r1 998 * and r3 because those just happen to be the registers all our callers are 999 * using. We move r3 before calling the C function, but r1 happens to match. 1000 * r1: index 1001 * r3: size 1002 */ 1003common_errArrayIndex: 1004 EXPORT_PC() 1005 mov r0, r3 1006 bl dvmThrowArrayIndexOutOfBoundsException 1007 b common_exceptionThrown 1008 1009/* 1010 * Integer divide or mod by zero. 1011 */ 1012common_errDivideByZero: 1013 EXPORT_PC() 1014 ldr r0, strDivideByZero 10150: add r0, pc 1016 bl dvmThrowArithmeticException 1017 b common_exceptionThrown 1018 1019strDivideByZero: 1020 .word PCREL_REF(.LstrDivideByZero,0b) 1021 1022/* 1023 * Attempt to allocate an array with a negative size. 1024 * On entry: length in r1 1025 */ 1026common_errNegativeArraySize: 1027 EXPORT_PC() 1028 mov r0, r1 @ arg0 <- len 1029 bl dvmThrowNegativeArraySizeException @ (len) 1030 b common_exceptionThrown 1031 1032/* 1033 * Invocation of a non-existent method. 1034 * On entry: method name in r1 1035 */ 1036common_errNoSuchMethod: 1037 EXPORT_PC() 1038 mov r0, r1 1039 bl dvmThrowNoSuchMethodError 1040 b common_exceptionThrown 1041 1042/* 1043 * We encountered a null object when we weren't expecting one. We 1044 * export the PC, throw a NullPointerException, and goto the exception 1045 * processing code. 1046 */ 1047common_errNullObject: 1048 EXPORT_PC() 1049 mov r0, #0 1050 bl dvmThrowNullPointerException 1051 b common_exceptionThrown 1052 1053/* 1054 * For debugging, cause an immediate fault. The source address will 1055 * be in lr (use a bl instruction to jump here). 1056 */ 1057common_abort: 1058 ldr pc, .LdeadFood 1059.LdeadFood: 1060 .word 0xdeadf00d 1061 1062/* 1063 * Spit out a "we were here", preserving all registers. (The attempt 1064 * to save ip won't work, but we need to save an even number of 1065 * registers for EABI 64-bit stack alignment.) 1066 */ 1067 .macro SQUEAK num 1068common_squeak\num: 1069 stmfd sp!, {r0, r1, r2, r3, ip, lr} 1070 ldr r0, strSqueak\num 10710: add r0, pc 1072 mov r1, #\num 1073 bl printf 1074 ldmfd sp!, {r0, r1, r2, r3, ip, lr} 1075 bx lr 1076 1077strSqueak\num: 1078 .word PCREL_REF(.LstrSqueak,0b) 1079 .endm 1080 1081 SQUEAK 0 1082 SQUEAK 1 1083 SQUEAK 2 1084 SQUEAK 3 1085 SQUEAK 4 1086 SQUEAK 5 1087 1088/* 1089 * Spit out the number in r0, preserving registers. 1090 */ 1091common_printNum: 1092 stmfd sp!, {r0, r1, r2, r3, ip, lr} 1093 mov r1, r0 1094 ldr r0, strSqueak 10950: add r0, pc 1096 bl printf 1097 ldmfd sp!, {r0, r1, r2, r3, ip, lr} 1098 bx lr 1099 1100strSqueak: 1101 .word PCREL_REF(.LstrSqueak,0b) 1102 1103/* 1104 * Print a newline, preserving registers. 1105 */ 1106common_printNewline: 1107 stmfd sp!, {r0, r1, r2, r3, ip, lr} 1108 ldr r0, strNewline 11090: add r0, pc 1110 bl printf 1111 ldmfd sp!, {r0, r1, r2, r3, ip, lr} 1112 bx lr 1113 1114strNewline: 1115 .word PCREL_REF(.LstrNewline,0b) 1116 1117 /* 1118 * Print the 32-bit quantity in r0 as a hex value, preserving registers. 1119 */ 1120common_printHex: 1121 stmfd sp!, {r0, r1, r2, r3, ip, lr} 1122 mov r1, r0 1123 ldr r0, strPrintHex 11240: add r0, pc 1125 bl printf 1126 ldmfd sp!, {r0, r1, r2, r3, ip, lr} 1127 bx lr 1128 1129strPrintHex: 1130 .word PCREL_REF(.LstrPrintHex,0b) 1131 1132/* 1133 * Print the 64-bit quantity in r0-r1, preserving registers. 1134 */ 1135common_printLong: 1136 stmfd sp!, {r0, r1, r2, r3, ip, lr} 1137 mov r3, r1 1138 mov r2, r0 1139 ldr r0, strPrintLong 11400: add r0, pc 1141 bl printf 1142 ldmfd sp!, {r0, r1, r2, r3, ip, lr} 1143 bx lr 1144 1145strPrintLong: 1146 .word PCREL_REF(.LstrPrintLong,0b) 1147 1148/* 1149 * Print full method info. Pass the Method* in r0. Preserves regs. 1150 */ 1151common_printMethod: 1152 stmfd sp!, {r0, r1, r2, r3, ip, lr} 1153 bl dvmMterpPrintMethod 1154 ldmfd sp!, {r0, r1, r2, r3, ip, lr} 1155 bx lr 1156 1157/* 1158 * Call a C helper function that dumps regs and possibly some 1159 * additional info. Requires the C function to be compiled in. 1160 */ 1161 .if 0 1162common_dumpRegs: 1163 stmfd sp!, {r0, r1, r2, r3, ip, lr} 1164 bl dvmMterpDumpArmRegs 1165 ldmfd sp!, {r0, r1, r2, r3, ip, lr} 1166 bx lr 1167 .endif 1168 1169#if 0 1170/* 1171 * Experiment on VFP mode. 1172 * 1173 * uint32_t setFPSCR(uint32_t val, uint32_t mask) 1174 * 1175 * Updates the bits specified by "mask", setting them to the values in "val". 1176 */ 1177setFPSCR: 1178 and r0, r0, r1 @ make sure no stray bits are set 1179 fmrx r2, fpscr @ get VFP reg 1180 mvn r1, r1 @ bit-invert mask 1181 and r2, r2, r1 @ clear masked bits 1182 orr r2, r2, r0 @ set specified bits 1183 fmxr fpscr, r2 @ set VFP reg 1184 mov r0, r2 @ return new value 1185 bx lr 1186 1187 .align 2 1188 .global dvmConfigureFP 1189 .type dvmConfigureFP, %function 1190dvmConfigureFP: 1191 stmfd sp!, {ip, lr} 1192 /* 0x03000000 sets DN/FZ */ 1193 /* 0x00009f00 clears the six exception enable flags */ 1194 bl common_squeak0 1195 mov r0, #0x03000000 @ r0<- 0x03000000 1196 add r1, r0, #0x9f00 @ r1<- 0x03009f00 1197 bl setFPSCR 1198 ldmfd sp!, {ip, pc} 1199#endif 1200 1201 1202 1203/* 1204 * Zero-terminated ASCII string data. 1205 * 1206 * On ARM we have two choices: do like gcc does, and LDR from a .word 1207 * with the address, or use an ADR pseudo-op to get the address 1208 * directly. ADR saves 4 bytes and an indirection, but it's using a 1209 * PC-relative addressing mode and hence has a limited range, which 1210 * makes it not work well with mergeable string sections. 1211 */ 1212 .section .rodata.str1.4,"aMS",%progbits,1 1213 1214.LstrBadEntryPoint: 1215 .asciz "Bad entry point %d\n" 1216.LstrFilledNewArrayNotImpl: 1217 .asciz "filled-new-array only implemented for objects and 'int'" 1218.LstrDivideByZero: 1219 .asciz "divide by zero" 1220.LstrLogTag: 1221 .asciz "mterp" 1222.LstrExceptionNotCaughtLocally: 1223 .asciz "Exception %s from %s:%d not caught locally\n" 1224 1225.LstrNewline: 1226 .asciz "\n" 1227.LstrSqueak: 1228 .asciz "<%d>" 1229.LstrPrintHex: 1230 .asciz "<%#x>" 1231.LstrPrintLong: 1232 .asciz "<%lld>" 1233