footer.S revision 0c2dc522d0e120f346cf0a40c8cf0c93346131c2
1/* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16/* 17 * Common subroutines and data. 18 */ 19 20#if defined(WITH_JIT) 21/* 22 * JIT-related re-entries into the interpreter. In general, if the 23 * exit from a translation can at some point be chained, the entry 24 * here requires that control arrived via a call, and that the "rp" 25 * on TOS is actually a pointer to a 32-bit cell containing the Dalvik PC 26 * of the next insn to handle. If no chaining will happen, the entry 27 * should be reached via a direct jump and rPC set beforehand. 28 */ 29 30 .global dvmJitToInterpPunt 31/* 32 * The compiler will generate a jump to this entry point when it is 33 * having difficulty translating a Dalvik instruction. We must skip 34 * the code cache lookup & prevent chaining to avoid bouncing between 35 * the interpreter and code cache. rPC must be set on entry. 36 */ 37dvmJitToInterpPunt: 38 GET_PC 39#if defined(WITH_JIT_TUNING) 40 movl rPC, OUT_ARG0(%esp) 41 call dvmBumpPunt 42#endif 43 movl rSELF, %ecx 44 movl offThread_curHandlerTable(%ecx),rIBASE 45 movl $$0, offThread_inJitCodeCache(%ecx) 46 FETCH_INST_R %ecx 47 GOTO_NEXT_R %ecx 48 49 .global dvmJitToInterpSingleStep 50/* 51 * Return to the interpreter to handle a single instruction. 52 * Should be reached via a call. 53 * On entry: 54 * 0(%esp) <= native return address within trace 55 * rPC <= Dalvik PC of this instruction 56 * OUT_ARG0+4(%esp) <= Dalvik PC of next instruction 57 */ 58dvmJitToInterpSingleStep: 59/* TODO */ 60 call dvmAbort 61#if 0 62 pop %eax 63 movl rSELF, %ecx 64 movl OUT_ARG0(%esp), %edx 65 movl %eax,offThread_jitResumeNPC(%ecx) 66 movl %edx,offThread_jitResumeDPC(%ecx) 67 movl $$kInterpEntryInstr,offThread_entryPoint(%ecx) 68 movl $$1,rINST # changeInterp <= true 69 jmp common_gotoBail 70#endif 71 72 .global dvmJitToInterpNoChainNoProfile 73/* 74 * Return from the translation cache to the interpreter to do method 75 * invocation. Check if the translation exists for the callee, but don't 76 * chain to it. rPC must be set on entry. 77 */ 78dvmJitToInterpNoChainNoProfile: 79#if defined(WITH_JIT_TUNING) 80 call dvmBumpNoChain 81#endif 82 movl %eax, rPC 83 movl rSELF, %eax 84 movl rPC,OUT_ARG0(%esp) 85 movl %eax,OUT_ARG1(%esp) 86 call dvmJitGetTraceAddrThread # (pc, self) 87 movl rSELF,%ecx # ecx <- self 88 movl %eax,offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag 89 cmpl $$0, %eax 90 jz 1f 91 jmp *%eax # exec translation if we've got one 92 # won't return 931: 94 EXPORT_PC 95 movl rSELF, %ecx 96 movl offThread_curHandlerTable(%ecx),rIBASE 97 FETCH_INST_R %ecx 98 GOTO_NEXT_R %ecx 99 100/* 101 * Return from the translation cache and immediately request a 102 * translation from the exit target, but don't attempt to chain. 103 * rPC set on entry. 104 */ 105 .global dvmJitToInterpTraceSelectNoChain 106dvmJitToInterpTraceSelectNoChain: 107#if defined(WITH_JIT_TUNING) 108 call dvmBumpNoChain 109#endif 110 movl %ebx, rPC 111 lea 4(%esp), %esp #to recover the esp update due to function call 112 movl rSELF, %eax 113 movl rPC,OUT_ARG0(%esp) 114 movl %eax,OUT_ARG1(%esp) 115 call dvmJitGetTraceAddrThread # (pc, self) 116 movl rSELF,%ecx 117 cmpl $$0,%eax 118 movl %eax,offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag 119 jz 1f 120 jmp *%eax # jump to tranlation 121 # won't return 122 123/* No Translation - request one */ 1241: 125 GET_JIT_PROF_TABLE %ecx %eax 126 cmpl $$0, %eax # JIT enabled? 127 jnz 2f # Request one if so 128 movl rSELF, %ecx 129 movl offThread_curHandlerTable(%ecx),rIBASE 130 FETCH_INST_R %ecx # Continue interpreting if not 131 GOTO_NEXT_R %ecx 1322: 133 ## Looks like an EXPORT_PC is needed here. Now jmp to common_selectTrace2 134 movl $$kJitTSelectRequestHot,%eax # ask for trace select 135 jmp common_selectTrace 136 137/* 138 * Return from the translation cache and immediately request a 139 * translation for the exit target. Reached via a call, and 140 * (TOS)->rPC. 141 */ 142 .global dvmJitToInterpTraceSelect 143dvmJitToInterpTraceSelect: 144 movl 0(%esp), %eax # get return address 145 movl %ebx, rPC # get first argument (target rPC) 146 147 ## TODO, need to clean up stack manipulation ... this isn't signal safe and 148 ## doesn't use the calling conventions of header.S 149 lea 4(%esp), %esp #to recover the esp update due to function call 150 151 ## An additional 5B instruction "jump 0" was added for a thread-safe 152 ## chaining cell update in JIT code cache. So the offset is now -17=-12-5. 153 lea -17(%eax), %ebx #$$JIT_OFFSET_CHAIN_START(%eax), %ebx 154 lea -4(%esp), %esp 155 movl rSELF, %eax 156 movl rPC,OUT_ARG0(%esp) 157 movl %eax,OUT_ARG1(%esp) 158 call dvmJitGetTraceAddrThread # (pc, self) 159 lea 4(%esp), %esp 160 cmpl $$0,%eax 161 movl rSELF, %ecx 162 movl %eax,offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag 163 jz 1b # no - ask for one 164 movl %eax,OUT_ARG0(%esp) 165 movl rINST,OUT_ARG1(%esp) 166 call dvmJitChain # Attempt dvmJitChain(codeAddr,chainAddr) 167 cmpl $$0,%eax # Success? 168 jz toInterpreter # didn't chain - interpret 169 jmp *%eax 170 # won't return 171 172/* 173 * Placeholder entries for x86 JIT 174 */ 175 .global dvmJitToInterpBackwardBranch 176dvmJitToInterpBackwardBranch: 177 178 .global dvmJitToExceptionThrown 179dvmJitToExceptionThrown: //rPC in 180 movl rSELF, %edx 181 GET_PC 182 movl $$0, offThread_inJitCodeCache(%edx) 183 jmp common_exceptionThrown 184 185 .global dvmJitToInterpNormal 186dvmJitToInterpNormal: 187/* one input: the target rPC value */ 188 movl 0(%esp), %eax # get return address 189 movl %ebx, rPC # get first argument (target rPC) 190 191 ## TODO, need to clean up stack manipulation ... this isn't signal safe and 192 ## doesn't use the calling conventions of header.S 193 194 ## An additional 5B instruction "jump 0" was added for a thread-safe 195 ## chaining cell update in JIT code cache. So the offset is now -17=-12-5. 196 lea -17(%eax), %ebx #$$JIT_OFFSET_CHAIN_START(%eax), %ebx 197 lea 4(%esp), %esp 198 movl rPC, OUT_ARG0(%esp) 199 movl rSELF, %ecx 200 movl %ecx, OUT_ARG1(%esp) 201 call dvmJitGetTraceAddrThread 202 ## Here is the change from using rGLUE to rSELF for accessing the 203 ## JIT code cache flag 204 movl rSELF, %ecx 205 movl %eax, offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag 206 #lea 4(%esp), %esp 207 cmp $$0, %eax 208 je toInterpreter 209 #lea -8(%esp), %esp 210 movl %ebx, OUT_ARG1(%esp) # %ebx live thorugh dvmJitGetTraceAddrThread 211 movl %eax, OUT_ARG0(%esp) # first argument 212 call dvmJitChain 213 #lea 8(%esp), %esp 214 cmp $$0, %eax 215 je toInterpreter 216 jmp *%eax #to native address 217 218 .global dvmJitToInterpNoChain 219dvmJitToInterpNoChain: 220dvmJitToInterpNoChain: #rPC in eax 221 ## TODO, need to clean up stack manipulation ... this isn't signal safe and 222 ## doesn't use the calling conventions of header.S 223 movl %eax, rPC 224 movl rPC, OUT_ARG0(%esp) 225 movl rSELF, %ecx 226 movl %ecx, OUT_ARG1(%esp) 227 call dvmJitGetTraceAddrThread 228 ## Here is the change from using rGLUE to rSELF for accessing the 229 ## JIT code cache flag 230 movl rSELF, %ecx 231 movl %eax, offThread_inJitCodeCache(%ecx) # set inJitCodeCache flag 232 cmp $$0, %eax 233 je toInterpreter 234 jmp *%eax #to native address 235 236toInterpreter: 237 EXPORT_PC 238 movl rSELF, %ecx 239 movl offThread_curHandlerTable(%ecx), rIBASE 240 FETCH_INST 241 movl offThread_pJitProfTable(%ecx), %eax 242 #Fallthrough 243 244/* ebx holds the pointer to the jit profile table 245 edx has the opCode */ 246common_testUpdateProfile: 247 cmp $$0, %eax 248 je 4f 249/* eax holds the pointer to the jit profile table 250 edx has the opCode 251 rPC points to the next bytecode */ 252 253common_updateProfile: 254 # quick & dirty hash 255 movl rPC, %ecx 256 shrl $$12, %ecx 257 xorl rPC, %ecx 258 andl $$((1<<JIT_PROF_SIZE_LOG_2)-1), %ecx 259 decb (%ecx,%eax) 260 #jmp 1f # remove 261 jz 2f 2621: 263 GOTO_NEXT 2642: 265common_Profile: 266/* 267 * Here, we switch to the debug interpreter to request 268 * trace selection. First, though, check to see if there 269 * is already a native translation in place (and, if so, 270 * jump to it now. 271 */ 272 SPILL(rIBASE) 273 SPILL_TMP1(rINST) 274 movl rSELF, rIBASE 275 GET_JIT_THRESHOLD rIBASE rINST # leaves rSELF in %ecx 276 EXPORT_PC 277 movb rINSTbl,(%ecx,%eax) # reset counter 278 movl rIBASE,rINST # preserve rSELF 279 movl rSELF, %eax 280 movl rPC,OUT_ARG0(%esp) 281 movl rIBASE,OUT_ARG1(%esp) 282 call dvmJitGetTraceAddrThread # (pc, self) 283 UNSPILL(rIBASE) 284 movl %eax,offThread_inJitCodeCache(rINST) # set the inJitCodeCache flag 285 UNSPILL_TMP1(rINST) 286 cmpl $$0,%eax 287 #jmp 1f # remove 288 jz 1f 289 jmp *%eax # TODO: decide call vs/ jmp!. No return either way 2901: 291 movl $$kJitTSelectRequest,%eax 292 # On entry, eax<- jitState, rPC valid 293common_selectTrace: 294 mov %ebx, EBX_SPILL(%ebp) 295 movl rSELF, %ebx 296 movzwl offThread_subMode(%ebx), %ecx 297 and $$(kSubModeJitTraceBuild | kSubModeJitSV), %ecx 298 jne 3f # already doing JIT work, continue 299 movl %eax, offThread_jitState(%ebx) 300 movl rSELF, %eax 301 movl %eax, OUT_ARG0(%esp) 302 303/* 304 * Call out to validate trace-building request. If successful, rIBASE will be swapped 305 * to send us into single-steppign trace building mode, so we need to refresh before 306 * we continue. 307 */ 308 309 EXPORT_PC 310 SAVE_PC_FP_TO_SELF %ecx 311 call dvmJitCheckTraceRequest 3123: 313 mov EBX_SPILL(%ebp), %ebx 314 FETCH_INST 315 movl rSELF, %ecx 316 movl offThread_curHandlerTable(%ecx), rIBASE 3174: 318 GOTO_NEXT 319 320common_selectTrace2: 321 mov %ebx, EBX_SPILL(%ebp) 322 movl rSELF, %ebx 323 movl %ebx, OUT_ARG0(%esp) 324 movl %eax, offThread_jitState(%ebx) 325 movzwl offThread_subMode(%ebx), %ecx 326 mov EBX_SPILL(%ebp), %ebx 327 and (kSubModeJitTraceBuild | kSubModeJitSV), %ecx 328 jne 3f # already doing JIT work, continue 329 330 331 332/* 333 * Call out to validate trace-building request. If successful, rIBASE will be swapped 334 * to send us into single-steppign trace building mode, so we need to refresh before 335 * we continue. 336 */ 337 338 EXPORT_PC 339 SAVE_PC_FP_TO_SELF %ecx 340 call dvmJitCheckTraceRequest 3413: 342 FETCH_INST 343 movl rSELF, %ecx 344 movl offThread_curHandlerTable(%ecx), rIBASE 3454: 346 GOTO_NEXT 347 348#endif 349 350/* 351 * For the invoke codes we need to know what register holds the "this" pointer. However 352 * it seems the this pointer is assigned consistently most times it is in %ecx but other 353 * times it is in OP_INVOKE_INTERFACE_JUMBO OP_INVOKE_INTERFACE OP_INVOKE_SUPER_QUICK and 354 * OP_INVOKE_VIRTUAL_QUICK 355*/ 356 357/* 358 * Common code for method invocation with range. 359 * 360 * On entry: 361 * eax = Method* methodToCall 362 * ecx = "this" 363 * rINSTw trashed, must reload 364 * rIBASE trashed, must reload before resuming interpreter 365 */ 366 367common_invokeMethodRange: 368.LinvokeNewRange: 369#if defined(WITH_JIT) 370 SPILL_TMP1(%edx) 371 SPILL_TMP2(%ebx) 372 movl rSELF, %edx 373 movzwl offThread_subMode(%edx), %ebx 374 and $$kSubModeJitTraceBuild, %ebx 375 jz 6f 376 call save_callsiteinfo 3776: 378 UNSPILL_TMP2(%ebx) 379 UNSPILL_TMP1(%edx) 380#endif 381 /* 382 * prepare to copy args to "outs" area of current frame 383 */ 384 385 movzbl 1(rPC),rINST # rINST<- AA 386 movzwl 4(rPC), %ecx # %ecx<- CCCC 387 SAVEAREA_FROM_FP %edx # %edx<- &StackSaveArea 388 test rINST, rINST 389 movl rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- AA 390 jz .LinvokeArgsDone # no args; jump to args done 391 392 393 /* 394 * %eax=methodToCall, %ecx=CCCC, LOCAL0_OFFSET(%ebp)=count, 395 * %edx=&outs (&stackSaveArea). (very few methods have > 10 args; 396 * could unroll for common cases) 397 */ 398 399.LinvokeRangeArgs: 400 movl %ebx, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- save %ebx 401 lea (rFP, %ecx, 4), %ecx # %ecx<- &vCCCC 402 shll $$2, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- offset 403 subl LOCAL0_OFFSET(%ebp), %edx # %edx<- update &outs 404 shrl $$2, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- offset 4051: 406 movl (%ecx), %ebx # %ebx<- vCCCC 407 lea 4(%ecx), %ecx # %ecx<- &vCCCC++ 408 subl $$1, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET<- LOCAL0_OFFSET-- 409 movl %ebx, (%edx) # *outs<- vCCCC 410 lea 4(%edx), %edx # outs++ 411 jne 1b # loop if count (LOCAL0_OFFSET(%ebp)) not zero 412 movl LOCAL1_OFFSET(%ebp), %ebx # %ebx<- restore %ebx 413 jmp .LinvokeArgsDone # continue 414 415 /* 416 * %eax is "Method* methodToCall", the method we're trying to call 417 * prepare to copy args to "outs" area of current frame 418 * rIBASE trashed, must reload before resuming interpreter 419 */ 420 421common_invokeMethodNoRange: 422#if defined(WITH_JIT) 423 SPILL_TMP1(%edx) 424 SPILL_TMP2(%ebx) 425 movl rSELF, %edx 426 movzwl offThread_subMode(%edx), %ebx 427 and $$kSubModeJitTraceBuild, %ebx 428 jz 6f 429 call save_callsiteinfo 4306: 431 UNSPILL_TMP2(%ebx) 432 UNSPILL_TMP1(%edx) 433#endif 434.LinvokeNewNoRange: 435 movzbl 1(rPC),rINST # rINST<- BA 436 movl rINST, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BA 437 shrl $$4, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- B 438 je .LinvokeArgsDone # no args; jump to args done 439 movzwl 4(rPC), %ecx # %ecx<- GFED 440 SAVEAREA_FROM_FP %edx # %edx<- &StackSaveArea 441 442 /* 443 * %eax=methodToCall, %ecx=GFED, LOCAL0_OFFSET(%ebp)=count, %edx=outs 444 */ 445 446.LinvokeNonRange: 447 cmp $$2, LOCAL0_OFFSET(%ebp) # compare LOCAL0_OFFSET(%ebp) to 2 448 movl %ecx, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- GFED 449 jl 1f # handle 1 arg 450 je 2f # handle 2 args 451 cmp $$4, LOCAL0_OFFSET(%ebp) # compare LOCAL0_OFFSET(%ebp) to 4 452 jl 3f # handle 3 args 453 je 4f # handle 4 args 4545: 455 andl $$15, rINST # rINSTw<- A 456 lea -4(%edx), %edx # %edx<- update &outs; &outs-- 457 movl (rFP, rINST, 4), %ecx # %ecx<- vA 458 movl %ecx, (%edx) # *outs<- vA 459 movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED 4604: 461 shr $$12, %ecx # %ecx<- G 462 lea -4(%edx), %edx # %edx<- update &outs; &outs-- 463 movl (rFP, %ecx, 4), %ecx # %ecx<- vG 464 movl %ecx, (%edx) # *outs<- vG 465 movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED 4663: 467 and $$0x0f00, %ecx # %ecx<- 0F00 468 shr $$8, %ecx # %ecx<- F 469 lea -4(%edx), %edx # %edx<- update &outs; &outs-- 470 movl (rFP, %ecx, 4), %ecx # %ecx<- vF 471 movl %ecx, (%edx) # *outs<- vF 472 movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED 4732: 474 and $$0x00f0, %ecx # %ecx<- 00E0 475 shr $$4, %ecx # %ecx<- E 476 lea -4(%edx), %edx # %edx<- update &outs; &outs-- 477 movl (rFP, %ecx, 4), %ecx # %ecx<- vE 478 movl %ecx, (%edx) # *outs<- vE 479 movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED 4801: 481 and $$0x000f, %ecx # %ecx<- 000D 482 movl (rFP, %ecx, 4), %ecx # %ecx<- vD 483 movl %ecx, -4(%edx) # *--outs<- vD 4840: 485 486 /* 487 * %eax is "Method* methodToCall", the method we're trying to call 488 * find space for the new stack frame, check for overflow 489 */ 490 491.LinvokeArgsDone: 492 movzwl offMethod_registersSize(%eax), %edx # %edx<- methodToCall->regsSize 493 movzwl offMethod_outsSize(%eax), %ecx # %ecx<- methodToCall->outsSize 494 movl %eax, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET<- methodToCall 495 shl $$2, %edx # %edx<- update offset 496 SAVEAREA_FROM_FP %eax # %eax<- &StackSaveArea 497 subl %edx, %eax # %eax<- newFP; (old savearea - regsSize) 498 movl rSELF,%edx # %edx<- pthread 499 movl %eax, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- &outs 500 subl $$sizeofStackSaveArea, %eax # %eax<- newSaveArea (stack save area using newFP) 501 movl offThread_interpStackEnd(%edx), %edx # %edx<- self->interpStackEnd 502 movl %edx, TMP_SPILL1(%ebp) # spill self->interpStackEnd 503 shl $$2, %ecx # %ecx<- update offset for outsSize 504 movl %eax, %edx # %edx<- newSaveArea 505 sub %ecx, %eax # %eax<- bottom; (newSaveArea - outsSize) 506 cmp TMP_SPILL1(%ebp), %eax # compare interpStackEnd and bottom 507 movl LOCAL0_OFFSET(%ebp), %eax # %eax<- restore methodToCall 508 jl .LstackOverflow # handle frame overflow 509 510 /* 511 * set up newSaveArea 512 */ 513 514#ifdef EASY_GDB 515 SAVEAREA_FROM_FP %ecx # %ecx<- &StackSaveArea 516 movl %ecx, offStackSaveArea_prevSave(%edx) # newSaveArea->prevSave<- &outs 517#endif 518 movl rSELF,%ecx # %ecx<- pthread 519 movl rFP, offStackSaveArea_prevFrame(%edx) # newSaveArea->prevFrame<- rFP 520 movl rPC, offStackSaveArea_savedPc(%edx) # newSaveArea->savedPc<- rPC 521#if defined(WITH_JIT) 522 movl $$0, offStackSaveArea_returnAddr(%edx) 523#endif 524 525 /* Any special actions to take? */ 526 cmpw $$0, offThread_subMode(%ecx) 527 jne 2f # Yes - handle them 5281: 529 testl $$ACC_NATIVE, offMethod_accessFlags(%eax) # check for native call 530 movl %eax, offStackSaveArea_method(%edx) # newSaveArea->method<- method to call 531 jne .LinvokeNative # handle native call 532 533 /* 534 * Update "self" values for the new method 535 * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFp 536 */ 537 movl offMethod_clazz(%eax), %edx # %edx<- method->clazz 538 movl offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex 539 movl %eax, offThread_method(%ecx) # self->method<- methodToCall 540 movl %edx, offThread_methodClassDex(%ecx) # self->methodClassDex<- method->clazz->pDvmDex 541 movl offMethod_insns(%eax), rPC # rPC<- methodToCall->insns 542 movl $$1, offThread_debugIsMethodEntry(%ecx) 543 movl LOCAL1_OFFSET(%ebp), rFP # rFP<- newFP 544 movl rFP, offThread_curFrame(%ecx) # curFrame<-newFP 545 movl offThread_curHandlerTable(%ecx),rIBASE 546 FETCH_INST 547#if defined(WITH_JIT) 548 /* rPC is already updated */ 549 GET_JIT_PROF_TABLE %ecx %eax 550 cmp $$0, %eax 551 jne common_updateProfile # set up %ebx & %edx & rPC 552#endif 553 GOTO_NEXT # jump to methodToCall->insns 554 5552: 556 /* 557 * On entry, preserve all: 558 * %eax: method 559 * %ecx: self 560 * %edx: new save area 561 */ 562 SPILL_TMP1(%eax) # preserve methodToCall 563 SPILL_TMP2(%edx) # preserve newSaveArea 564 movl rPC, offThread_pc(%ecx) # update interpSave.pc 565 movl %ecx, OUT_ARG0(%esp) 566 movl %eax, OUT_ARG1(%esp) 567 call dvmReportInvoke # (self, method) 568 UNSPILL_TMP1(%eax) 569 UNSPILL_TMP2(%edx) 570 movl rSELF,%ecx # restore rSELF 571 jmp 1b 572 573 /* 574 * Prep for the native call 575 * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFP, %edx=newSaveArea, %ecx=self 576 */ 577 578.LinvokeNative: 579 movl offThread_jniLocal_topCookie(%ecx), rINST # rINST<- self->localRef->... 580 movl rINST, offStackSaveArea_localRefCookie(%edx) # newSaveArea->localRefCookie<- top 581 movl %edx, LOCAL2_OFFSET(%ebp) # save newSaveArea 582 movl LOCAL1_OFFSET(%ebp), rINST # rINST<- newFP 583 movl rINST, offThread_curFrame(%ecx) # curFrame<- newFP 584 cmpw $$0, offThread_subMode(%ecx) # Anything special going on? 585 jne 11f # yes - handle it 586 movl %ecx, OUT_ARG3(%esp) # push parameter self 587 movl %eax, OUT_ARG2(%esp) # push parameter methodToCall 588 lea offThread_retval(%ecx), %ecx # %ecx<- &retval 589 movl %ecx, OUT_ARG1(%esp) # push parameter &retval 590 movl rINST, OUT_ARG0(%esp) # push parameter newFP 591 call *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc 5927: 593 movl LOCAL2_OFFSET(%ebp), %ecx # %ecx<- newSaveArea 594 movl rSELF, %eax # %eax<- self 595 movl offStackSaveArea_localRefCookie(%ecx), %edx # %edx<- old top 596 cmp $$0, offThread_exception(%eax) # check for exception 597 movl rFP, offThread_curFrame(%eax) # curFrame<- rFP 598 movl %edx, offThread_jniLocal_topCookie(%eax) # new top <- old top 599 jne common_exceptionThrown # handle exception 600 movl offThread_curHandlerTable(%eax),rIBASE 601 FETCH_INST_OPCODE 3 %ecx 602 ADVANCE_PC 3 603 GOTO_NEXT_R %ecx # jump to next instruction 604 60511: 606 /* 607 * Handle any special subMode actions 608 * %eax=methodToCall, rINST=newFP, %ecx=self 609 */ 610 SPILL_TMP1(%eax) # save methodTocall 611 movl rPC, offThread_pc(%ecx) 612 movl %ecx, OUT_ARG1(%esp) 613 movl %eax, OUT_ARG0(%esp) 614 movl rFP, OUT_ARG2(%esp) 615 call dvmReportPreNativeInvoke # (methodToCall, self, fp) 616 UNSPILL_TMP1(%eax) # restore methodToCall 617 movl rSELF,%ecx # restore self 618 619 /* Do the native call */ 620 movl %ecx, OUT_ARG3(%esp) # push parameter self 621 lea offThread_retval(%ecx), %ecx # %ecx<- &retval 622 movl %eax, OUT_ARG2(%esp) # push parameter methodToCall 623 movl %ecx, OUT_ARG1(%esp) # push parameter &retval 624 movl rINST, OUT_ARG0(%esp) # push parameter newFP 625 call *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc 626 627 UNSPILL_TMP1(%eax) # restore methodToCall 628 movl rSELF, %ecx 629 movl %ecx, OUT_ARG1(%esp) 630 movl %eax, OUT_ARG0(%esp) 631 movl rFP, OUT_ARG2(%esp) 632 call dvmReportPostNativeInvoke # (methodToCall, self, fp) 633 jmp 7b # rejoin 634 635.LstackOverflow: # eax=methodToCall 636 movl %eax, OUT_ARG1(%esp) # push parameter methodToCall 637 movl rSELF,%eax # %eax<- self 638 movl %eax, OUT_ARG0(%esp) # push parameter self 639 call dvmHandleStackOverflow # call: (Thread* self, Method* meth) 640 jmp common_exceptionThrown # handle exception 641 642 643/* 644 * Common code for handling a return instruction 645 */ 646common_returnFromMethod: 647 movl rSELF, %ecx 648 SAVEAREA_FROM_FP %eax # %eax<- saveArea(old) 649 cmpw $$0, offThread_subMode(%ecx) # special action needed? 650 jne 19f # go if so 65114: 652 653 movl offStackSaveArea_prevFrame(%eax), rFP # rFP<- saveArea->PrevFrame 654 movl (offStackSaveArea_method - sizeofStackSaveArea)(rFP), rINST # rINST<- method we are returning to 655 cmpl $$0, rINST # check for break frame 656 je common_gotoBail # bail if break frame 657 movl offThread_curHandlerTable(%ecx),rIBASE 658 movl offStackSaveArea_savedPc(%eax), rPC # rPC<- saveAreaOld->savedPc 659#if defined(WITH_JIT) 660 movl offStackSaveArea_returnAddr(%eax), %ecx 661#endif 662 movl rSELF, %eax 663 movl rINST, offThread_method(%eax) # glue->method<- newSave->method 664 movl offMethod_clazz(rINST), rINST # rINST<- method->clazz 665 movl rFP, offThread_curFrame(%eax) # glue->self->curFrame<- rFP 666#if defined(WITH_JIT) 667 //update self->offThread_inJitCodeCache 668 movl %ecx, offThread_inJitCodeCache(%eax) 669#endif 670 movl offClassObject_pDvmDex(rINST), rINST # rINST<- method->clazz->pDvmDex 671 movl rINST, offThread_methodClassDex(%eax) # glue->pDvmDex<- method->clazz->pDvmDex 672#if defined(WITH_JIT) 673 cmp $$0, %ecx 674 je .returnToBC 675 movl %ecx, %eax 676 jmp *%eax 677#endif 678 679.returnToBC: 680 681#if defined(WITH_JIT) 682 FETCH_INST_OPCODE 3, %ecx # %eax<- next instruction hi; fetch, advance 683 // %ecx has the opcode 684 addl $$6, rPC # 3*2 = 6 685 SPILL_TMP1 (%ecx) 686 movl rSELF, %ecx 687 FETCH_INST 688 UNSPILL_TMP1 (%ecx) 689 movzbl 1(rPC), rINST 690 jmp *(rIBASE,%ecx,4) 691#else 692 FETCH_INST_WORD 3 693 ADVANCE_PC 3 694 GOTO_NEXT 695#endif 696 69719: 698 /* 699 * Handle special subMode actions 700 * On entry, rFP: prevFP, %ecx: self, %eax: saveArea 701 */ 702 SPILL_TMP1(%ebx) 703 movl offStackSaveArea_prevFrame(%eax), %ebx # %ebx<- saveArea->PrevFrame 704 movl rPC, offThread_pc(%ecx) # update interpSave.pc 705 movl %ebx, offThread_curFrame(%ecx) # update interpSave.curFrame 706 movl %ecx, OUT_ARG0(%esp) # parameter self 707 call dvmReportReturn # (self) 708 UNSPILL_TMP1(%ebx) 709 movl rSELF, %ecx # restore self 710 SAVEAREA_FROM_FP %eax # restore saveArea 711 jmp 14b 712 713 714/* 715 * Prepare to strip the current frame and "longjump" back to caller of 716 * dvmMterpStdRun. 717 * 718 * on entry: 719 * rINST holds changeInterp 720 * ecx holds self pointer 721 * 722 * expected profile: dvmMterpStdBail(Thread *self, bool changeInterp) 723 */ 724common_gotoBail: 725 movl rPC,offThread_pc(%ecx) # export state to self 726 movl rFP,offThread_curFrame(%ecx) 727 movl %ecx,OUT_ARG0(%esp) # self in arg0 728 movl rINST,OUT_ARG1(%esp) # changeInterp in arg1 729 call dvmMterpStdBail # bail out.... 730 731/* 732 * The JIT's invoke method needs to remember the callsite class and 733 * target pair. Save them here so that they are available to 734 * dvmCheckJit following the interpretation of this invoke. 735 * 736 * eax = Method* methodToCall 737 * ecx = "this" 738 * edx = rSELF 739 * ebx = free to use 740 */ 741#if defined(WITH_JIT) 742save_callsiteinfo: 743 cmp $$0, %ecx 744 je 2f 745 movl offObject_clazz(%ecx), %ecx 7462: 747 movl rSELF, %ebx 748 movl %eax, offThread_methodToCall(%ebx) 749 movl %ecx, offThread_callsiteClass(%ebx) 750 ret 751#endif 752 753#if defined(WITH_JIT) 754 755 /* 756 * If the JIT is actively building a trace we need to make sure 757 * that the field is fully resolved before including the current 758 * instruction. 759 * 760 * On entry: 761 * %ecx: &dvmDex->pResFields[field] 762 * %eax: field pointer (must preserve) 763 */ 764common_verifyField: 765 movl %ebx, TMP_SPILL1(%ebp) 766 movl rSELF, %ebx 767 movzwl offThread_subMode(%ebx), %ebx 768 andl $$kSubModeJitTraceBuild, %ebx 769 movl TMP_SPILL1(%ebp), %ebx 770 jne 1f 771 ret 7721: 773 movl (%ecx), %ecx 774 cmp $$0, %ecx 775 je 1f 776 ret 7771: 778 SPILL_TMP1(%eax) 779 SPILL_TMP2(%edx) 780 movl rSELF, %ecx 781 # Because we call into this helper from a bytecode, we have 782 # to be careful not to write over the return address when using 783 # the OUT_ARG macros 784 lea -8(%esp), %esp 785 movl %ecx, OUT_ARG0(%esp) 786 movl rPC, OUT_ARG1(%esp) 787 call dvmJitEndTraceSelect 788 lea 8(%esp), %esp 789 UNSPILL_TMP2(%edx) 790 UNSPILL_TMP1(%eax) 791 ret 792#endif 793 794/* 795 * After returning from a "selfd" function, pull out the updated values 796 * and start executing at the next instruction. 797 */ 798common_resumeAfterGlueCall: 799 movl rSELF, %eax 800 movl offThread_pc(%eax),rPC 801 movl offThread_curFrame(%eax),rFP 802 movl offThread_curHandlerTable(%eax),rIBASE 803 FETCH_INST 804 GOTO_NEXT 805 806/* 807 * Integer divide or mod by zero 808 */ 809common_errDivideByZero: 810 EXPORT_PC 811 movl $$.LstrDivideByZero,%eax 812 movl %eax,OUT_ARG0(%esp) 813 call dvmThrowArithmeticException 814 jmp common_exceptionThrown 815 816/* 817 * Attempt to allocate an array with a negative size. 818 * On entry, len in eax 819 */ 820common_errNegativeArraySize: 821 EXPORT_PC 822 movl %eax,OUT_ARG0(%esp) # arg0<- len 823 call dvmThrowNegativeArraySizeException # (len) 824 jmp common_exceptionThrown 825 826/* 827 * Attempt to allocate an array with a negative size. 828 * On entry, method name in eax 829 */ 830common_errNoSuchMethod: 831 EXPORT_PC 832 movl %eax,OUT_ARG0(%esp) 833 call dvmThrowNoSuchMethodError 834 jmp common_exceptionThrown 835 836/* 837 * Hit a null object when we weren't expecting one. Export the PC, throw a 838 * NullPointerException and goto the exception processing code. 839 */ 840common_errNullObject: 841 EXPORT_PC 842 xorl %eax,%eax 843 movl %eax,OUT_ARG0(%esp) 844 call dvmThrowNullPointerException 845 jmp common_exceptionThrown 846 847/* 848 * Array index exceeds max. 849 * On entry: 850 * eax <- array object 851 * ecx <- index 852 */ 853common_errArrayIndex: 854 EXPORT_PC 855 movl offArrayObject_length(%eax), %eax 856 movl %eax,OUT_ARG0(%esp) 857 movl %ecx,OUT_ARG1(%esp) 858 call dvmThrowArrayIndexOutOfBoundsException # args (length, index) 859 jmp common_exceptionThrown 860 861/* 862 * Somebody has thrown an exception. Handle it. 863 * 864 * If the exception processing code returns to us (instead of falling 865 * out of the interpreter), continue with whatever the next instruction 866 * now happens to be. 867 * 868 * NOTE: special subMode handling done in dvmMterp_exceptionThrown 869 * 870 * This does not return. 871 */ 872common_exceptionThrown: 873.LexceptionNew: 874 875 EXPORT_PC 876 movl rSELF, %ecx 877 movl %ecx, OUT_ARG0(%esp) 878 call dvmCheckSuspendPending 879 880 movl rSELF, %ecx 881 movl offThread_exception(%ecx), %edx # %edx <- self->exception 882 movl %edx, OUT_ARG0(%esp) 883 movl %ecx, OUT_ARG1(%esp) 884 SPILL_TMP1(%edx) 885 call dvmAddTrackedAlloc # don't let the exception be GCed 886 UNSPILL_TMP1(%edx) 887 movl rSELF, %ecx 888 movl offThread_subMode(%ecx), %eax # get subMode flags 889 movl $$0, offThread_exception(%ecx) 890 891 # Special subMode? 892 cmpl $$0, %eax # any special subMode handling needed? 893 je 8f # go if so 894 895 # Manage debugger bookkeeping 896 movl rPC, offThread_pc(%ecx) # update interpSave.pc 897 movl rFP, offThread_curFrame(%ecx) # update interpSave.curFrame 898 movl %ecx, OUT_ARG0(%esp) 899 movl %edx, OUT_ARG1(%esp) 900 SPILL_TMP1(%edx) 901 call dvmReportExceptionThrow # (self, exception) 902 UNSPILL_TMP1(%edx) 903 movl rSELF, %ecx 904 9058: 906 /* 907 * set up args and a local for &fp 908 */ 909 lea 20(%esp), %esp # raise %esp 910 movl rFP, (%esp) # save fp 911 movl %esp, %eax # %eax = &fp 912 lea -20(%esp), %esp # reset %esp 913 movl %eax, OUT_ARG4(%esp) # Arg 4 = &fp 914 movl $$0, OUT_ARG3(%esp) # Arg 3 = false 915 movl %edx, OUT_ARG2(%esp) # Arg 2 = exception 916 movl %ecx, OUT_ARG0(%esp) # Arg 0 = self 917 918 movl offThread_method(%ecx), %eax # %eax = self->method 919 movl offMethod_insns(%eax), %eax # %eax = self->method->insn 920 # ldrh lr, [rSELF, #offThread_subMode] @ lr<- subMode flags # TODO 921 movl rPC, %ecx 922 subl %eax, %ecx # %ecx = pc - self->method->insn 923 sar $$1, %ecx # adjust %ecx for code offset 924 movl %ecx, OUT_ARG1(%esp) # Arg 1 = %ecx 925 926 /* call, %eax gets catchRelPc (a code-unit offset) */ 927 SPILL_TMP1(%edx) # save exception 928 call dvmFindCatchBlock # call(self, relPc, exc, scan?, &fp) 929 UNSPILL_TMP1(%edx) # restore exception 930 931 /* fix earlier stack overflow if necessary; may trash rFP */ 932 movl rSELF, %ecx 933 cmpl $$0, offThread_stackOverflowed(%ecx) # did we overflow? 934 je 1f # no, skip ahead 935 movl %eax, rFP # save relPc result in rFP 936 movl %ecx, OUT_ARG0(%esp) # Arg 0 = self 937 movl %edx, OUT_ARG1(%esp) # Arg 1 = exception 938 SPILL_TMP1(%edx) 939 call dvmCleanupStackOverflow # call(self, exception) 940 UNSPILL_TMP1(%edx) 941 movl rFP, %eax # restore result 942 movl rSELF, %ecx 9431: 944 945 /* update frame pointer and check result from dvmFindCatchBlock */ 946 movl 20(%esp), rFP # retrieve the updated rFP 947 cmpl $$0, %eax # is catchRelPc < 0? 948 jl .LnotCaughtLocally 949 950 /* adjust locals to match self->interpSave.curFrame and updated PC */ 951 SAVEAREA_FROM_FP rINST # rINST<- new save area 952 movl offStackSaveArea_method(rINST), rINST # rINST<- new method 953 movl rINST, offThread_method(%ecx) # self->method = new method 954 movl offMethod_clazz(rINST), %ecx # %ecx = method->clazz 955 movl offMethod_insns(rINST), rINST # rINST = method->insn 956 movl offClassObject_pDvmDex(%ecx), %ecx # %ecx = method->clazz->pDvmDex 957 lea (rINST, %eax, 2), rPC # rPC<- method->insns + catchRelPc 958 movl rSELF, rINST 959 movl %ecx, offThread_methodClassDex(rINST) # self->pDvmDex = method->clazz->pDvmDex 960 961 /* release the tracked alloc on the exception */ 962 movl %edx, OUT_ARG0(%esp) # Arg 0 = exception 963 movl rINST, OUT_ARG1(%esp) # Arg 1 = self 964 SPILL_TMP1(%edx) 965 call dvmReleaseTrackedAlloc # release the exception 966 UNSPILL_TMP1(%edx) 967 968 /* restore the exception if the handler wants it */ 969 movl rSELF, %ecx 970 FETCH_INST 971 movzbl rINSTbl, %eax 972 cmpl $$OP_MOVE_EXCEPTION, %eax # is it "move-exception"? 973 jne 1f 974 movl %edx, offThread_exception(%ecx) # restore exception 9751: 976 movl offThread_curHandlerTable(%ecx), rIBASE # refresh rIBASE 977 GOTO_NEXT 978 979.LnotCaughtLocally: # %edx = exception 980 /* fix stack overflow if necessary */ 981 movl rSELF, %ecx 982 movl offThread_stackOverflowed(%ecx), %eax 983 cmpl $$0, %eax # did we overflow earlier? 984 je 1f 985 movl %ecx, OUT_ARG0(%esp) 986 movl %edx, OUT_ARG1(%esp) 987 SPILL_TMP1(%edx) 988 call dvmCleanupStackOverflow 989 UNSPILL_TMP1(%edx) 990 9911: 992 movl rSELF, %ecx 993 movl %edx, offThread_exception(%ecx) #restore exception 994 movl %edx, OUT_ARG0(%esp) 995 movl %ecx, OUT_ARG1(%esp) 996 call dvmReleaseTrackedAlloc # release the exception 997 movl rSELF, %ecx 998 jmp common_gotoBail # bail out 999 1000common_abort: 1001 movl $$0xdeadf00d,%eax 1002 call *%eax 1003 1004 1005/* 1006 * Strings 1007 */ 1008 1009 .section .rodata 1010.LstrDivideByZero: 1011 .asciz "divide by zero" 1012.LstrFilledNewArrayNotImplA: 1013 .asciz "filled-new-array only implemented for 'int'" 1014