| %verify "executed" |
| %verify "null object" |
| %verify "class cast exception thrown, with correct class name" |
| %verify "class cast exception not thrown on same class" |
| %verify "class cast exception not thrown on subclass" |
| %verify "class not resolved" |
| %verify "class already resolved" |
| /* |
| * Check to see if an object reference is an instance of a class. |
| * |
| * Most common situation is a non-null object, being compared against |
| * an already-resolved class. |
| */ |
| /* instance-of vA, vB, class@CCCC */ |
| movzbl rINST_HI,%eax # eax<- BA |
| sarl $$4,%eax # eax<- B |
| GET_VREG(%eax,%eax) # eax<- vB (obj) |
| GET_GLUE(%ecx) |
| testl %eax,%eax # object null? |
| movl offGlue_methodClassDex(%ecx),%ecx # ecx<- pDvmDex |
| SPILL(rPC) |
| je .L${opcode}_store # null obj, not instance, store it |
| movzwl 2(rPC),rPC # rPC<- CCCC |
| movl offDvmDex_pResClasses(%ecx),%ecx # ecx<- pDvmDex->pResClasses |
| movl (%ecx,rPC,4),%ecx # ecx<- resolved class |
| movl offObject_clazz(%eax),%eax # eax<- obj->clazz |
| testl %ecx,%ecx # have we resolved this before? |
| je .L${opcode}_resolve # not resolved, do it now |
| .L${opcode}_resolved: # eax<- obj->clazz, ecx<- resolved class |
| cmpl %eax,%ecx # same class (trivial success)? |
| je .L${opcode}_trivial # yes, trivial finish |
| jmp .L${opcode}_fullcheck # no, do full check |
| %break |
| |
| /* |
| * Trivial test failed, need to perform full check. This is common. |
| * eax holds obj->clazz |
| * ecx holds class resolved from BBBB |
| * rINST_HI has BA |
| * rPC already spilled |
| */ |
| .L${opcode}_fullcheck: |
| movl %eax,OUT_ARG0(%esp) |
| movl %ecx,OUT_ARG1(%esp) |
| call dvmInstanceofNonTrivial # eax<- boolean result |
| # fall through to ${opcode}_store |
| |
| /* |
| * eax holds boolean result |
| * rINST_HI holds BA |
| */ |
| .L${opcode}_store: |
| UNSPILL(rPC) |
| movzbl rINST_HI,%ecx # ecx<- BA |
| FETCH_INST_WORD(2) |
| andb $$0xf,%cl # ecl<- A |
| ADVANCE_PC(2) |
| SET_VREG(%eax,%ecx) # vA<- eax |
| GOTO_NEXT |
| |
| /* |
| * Trivial test succeeded, save and bail. |
| * r9 holds A |
| */ |
| .L${opcode}_trivial: |
| UNSPILL(rPC) |
| movzbl rINST_HI,%ecx # ecx<- BA |
| FETCH_INST_WORD(2) |
| andb $$0xf,%cl # ecl<- A |
| ADVANCE_PC(2) |
| movl $$1,%eax |
| SET_VREG(%eax,%ecx) # vA<- true |
| GOTO_NEXT |
| |
| /* |
| * Resolution required. This is the least-likely path. |
| * |
| * rPC holds BBBB |
| * rINST_HI holds BA |
| */ |
| .L${opcode}_resolve: |
| movl rPC,OUT_ARG1(%esp) # arg1<- BBBB |
| GET_GLUE(%ecx) |
| UNSPILL(rPC) |
| movl offGlue_method(%ecx),%ecx |
| movl $$1,OUT_ARG2(%esp) # arg2<- true |
| movl offMethod_clazz(%ecx),%ecx # ecx<- method->clazz |
| EXPORT_PC() |
| movl %ecx,OUT_ARG0(%esp) # arg0<- method->clazz |
| call dvmResolveClass # eax<- resolved ClassObject ptr |
| UNSPILL(rPC) |
| testl %eax,%eax # success? |
| je common_exceptionThrown # no, handle exception |
| /* Now, we need to sync up with fast path. We need eax to |
| * hold the obj->clazz, and ecx to hold the resolved class |
| */ |
| movl %eax,%ecx # ecx<- resolved class |
| movzbl rINST_HI,%eax # eax<- BA |
| sarl $$4,%eax # eax<- B |
| GET_VREG(%eax,%eax) # eax<- vB (obj) |
| movl offObject_clazz(%eax),%eax # eax<- obj->clazz |
| jmp .L${opcode}_resolved |