| %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 a cast from one class to another is allowed. |
| */ |
| /* check-cast vAA, class@BBBB */ |
| movl rSELF,%ecx |
| GET_VREG_R rINST,rINST # rINST<- vAA (object) |
| movzwl 2(rPC),%eax # eax<- BBBB |
| movl offThread_methodClassDex(%ecx),%ecx # ecx<- pDvmDex |
| testl rINST,rINST # is oject null? |
| movl offDvmDex_pResClasses(%ecx),%ecx # ecx<- pDvmDex->pResClasses |
| je .L${opcode}_okay # null obj, cast always succeeds |
| movl (%ecx,%eax,4),%eax # eax<- resolved class |
| movl offObject_clazz(rINST),%ecx # ecx<- obj->clazz |
| testl %eax,%eax # have we resolved this before? |
| je .L${opcode}_resolve # no, go do it now |
| .L${opcode}_resolved: |
| cmpl %eax,%ecx # same class (trivial success)? |
| jne .L${opcode}_fullcheck # no, do full check |
| .L${opcode}_okay: |
| FETCH_INST_OPCODE 2 %ecx |
| ADVANCE_PC 2 |
| GOTO_NEXT_R %ecx |
| |
| /* |
| * Trivial test failed, need to perform full check. This is common. |
| * ecx holds obj->clazz |
| * eax holds class resolved from BBBB |
| * rINST holds object |
| */ |
| .L${opcode}_fullcheck: |
| movl %eax,sReg0 # we'll need the desired class on failure |
| movl %eax,OUT_ARG1(%esp) |
| movl %ecx,OUT_ARG0(%esp) |
| SPILL(rIBASE) |
| call dvmInstanceofNonTrivial # eax<- boolean result |
| UNSPILL(rIBASE) |
| testl %eax,%eax # failed? |
| jne .L${opcode}_okay # no, success |
| |
| # A cast has failed. We need to throw a ClassCastException. |
| EXPORT_PC |
| movl offObject_clazz(rINST),%eax |
| movl %eax,OUT_ARG0(%esp) # arg0<- obj->clazz |
| movl sReg0,%ecx |
| movl %ecx,OUT_ARG1(%esp) # arg1<- desired class |
| call dvmThrowClassCastException |
| jmp common_exceptionThrown |
| |
| /* |
| * Resolution required. This is the least-likely path, and we're |
| * going to have to recreate some data. |
| * |
| * rINST holds object |
| */ |
| .L${opcode}_resolve: |
| movl rSELF,%ecx |
| EXPORT_PC |
| movzwl 2(rPC),%eax # eax<- BBBB |
| movl offThread_method(%ecx),%ecx # ecx<- self->method |
| movl %eax,OUT_ARG1(%esp) # arg1<- BBBB |
| movl offMethod_clazz(%ecx),%ecx # ecx<- metho->clazz |
| movl $$0,OUT_ARG2(%esp) # arg2<- false |
| movl %ecx,OUT_ARG0(%esp) # arg0<- method->clazz |
| SPILL(rIBASE) |
| call dvmResolveClass # eax<- resolved ClassObject ptr |
| UNSPILL(rIBASE) |
| testl %eax,%eax # got null? |
| je common_exceptionThrown # yes, handle exception |
| movl offObject_clazz(rINST),%ecx # ecx<- obj->clazz |
| jmp .L${opcode}_resolved # pick up where we left off |