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