| %verify "executed" |
| %verify "exception handled" |
| /* |
| * Execute a "native inline" instruction, using "/range" semantics. |
| * Same idea as execute-inline, but we get the args differently. |
| * |
| * We need to call an InlineOp4Func: |
| * bool (func)(u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult) |
| * |
| * The first four args are in a0-a3, pointer to return value storage |
| * is on the stack. The function's return value is a flag that tells |
| * us if an exception was thrown. |
| */ |
| /* [opt] execute-inline/range {vCCCC..v(CCCC+AA-1)}, inline@BBBB */ |
| lhu a2, offThread_subMode(rSELF) |
| FETCH(rBIX, 1) # rBIX<- BBBB |
| EXPORT_PC() # can throw |
| and a2, kSubModeDebugProfile # Any going on? |
| bnez a2, .L${opcode}_debugmode # yes - take slow path |
| .L${opcode}_resume: |
| addu a1, rSELF, offThread_retval # a1<- &self->retval |
| GET_OPA(a0) |
| sw a1, STACK_OFFSET_ARG04(sp) # push &self->retval |
| BAL(.L${opcode}_continue) # make call; will return after |
| lw gp, STACK_OFFSET_GP(sp) # restore gp |
| beqz v0, common_exceptionThrown # returned false, handle exception |
| FETCH_ADVANCE_INST(3) # advance rPC, load rINST |
| GET_INST_OPCODE(t0) # extract opcode from rINST |
| GOTO_OPCODE(t0) # jump to next instruction |
| |
| %break |
| |
| /* |
| * Extract args, call function. |
| * a0 = #of args (0-4) |
| * rBIX = call index |
| * ra = return addr, above [DO NOT JAL out of here w/o preserving ra] |
| */ |
| .L${opcode}_continue: |
| FETCH(rOBJ, 2) # rOBJ <- CCCC |
| beq a0, 0, 0f |
| beq a0, 1, 1f |
| beq a0, 2, 2f |
| beq a0, 3, 3f |
| beq a0, 4, 4f |
| JAL(common_abort) # too many arguments |
| |
| 4: |
| add t0, rOBJ, 3 |
| GET_VREG(a3, t0) |
| 3: |
| add t0, rOBJ, 2 |
| GET_VREG(a2, t0) |
| 2: |
| add t0, rOBJ, 1 |
| GET_VREG(a1, t0) |
| 1: |
| GET_VREG(a0, rOBJ) |
| 0: |
| la rOBJ, gDvmInlineOpsTable # table of InlineOperation |
| EAS4(t1, rOBJ, rBIX) # t1 <- rINST + rBIX<<4 |
| lw t9, 0(t1) |
| jr t9 # sizeof=16, "func" is first entry |
| # not reached |
| |
| /* |
| * We're debugging or profiling. |
| * rBIX: opIndex |
| */ |
| .L${opcode}_debugmode: |
| move a0, rBIX |
| JAL(dvmResolveInlineNative) |
| beqz v0, .L${opcode}_resume # did it resolve? no, just move on |
| move rOBJ, v0 # remember method |
| move a0, v0 |
| move a1, rSELF |
| JAL(dvmFastMethodTraceEnter) # (method, self) |
| addu a1, rSELF, offThread_retval # a1<- &self->retval |
| GET_OPA(a0) # a0 <- A |
| # Stack should have 16/20 available |
| sw a1, STACK_OFFSET_ARG04(sp) # push &self->retval |
| move rINST, rOBJ # rINST<- method |
| BAL(.L${opcode}_continue) # make call; will return after |
| lw gp, STACK_OFFSET_GP(sp) # restore gp |
| move rOBJ, v0 # save result of inline |
| move a0, rINST # a0<- method |
| move a1, rSELF # a1<- self |
| JAL(dvmFastNativeMethodTraceExit) # (method, self) |
| beqz rOBJ, common_exceptionThrown # returned false, handle exception |
| FETCH_ADVANCE_INST(3) # advance rPC, load rINST |
| GET_INST_OPCODE(t0) # extract opcode from rINST |
| GOTO_OPCODE(t0) # jump to next instruction |