%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/ jumbo vBBBB, class #AAAAAAAA */
    FETCH(a0, 1)                        # a0<- aaaa (lo)
    FETCH(a2, 2)                        # a2<- AAAA (hi)
    FETCH(a3, 3)                        # a3<- BBBB
    sll    a2,a2,16
    or     a2, a0, a2                   # a2<- AAAAaaaa

    GET_VREG(rOBJ, a3)                          # rOBJ<- object
    LOAD_rSELF_methodClassDex(a0)   # a0<- pDvmDex
    LOAD_base_offDvmDex_pResClasses(a0, a0) # a0<- pDvmDex->pResClasses
                                                # is object null?
    beqz     rOBJ, .L${opcode}_okay             # null obj, cast always succeeds
    LOAD_eas2(a1, a0, a2)           # a1<- resolved class
    LOAD_base_offObject_clazz(a0, rOBJ)   # a0<- obj->clazz
                                                # have we resolved this before?
    beqz    a1, .L${opcode}_resolve             # not resolved, do it now
.L${opcode}_resolved:
                                                # same class (trivial success)?
    bne     a0, a1, .L${opcode}_fullcheck       # no, do full check
    b       .L${opcode}_okay                    # yes, finish up

    /*
     * Trivial test failed, need to perform full check.  This is common.
     *  a0 holds obj->clazz
     *  a1 holds class resolved from BBBB
     *  rOBJ holds object
     */
.L${opcode}_fullcheck:
    move      rBIX,a1                      #  avoid ClassObject getting clobbered
    JAL(dvmInstanceofNonTrivial)    # v0<- boolean result
                                                # failed?
    bnez    v0, .L${opcode}_okay                # no, success
    b       .L${opcode}_castfailure

%break


.L${opcode}_castfailure:
    # A cast has failed.  We need to throw a ClassCastException with the
    # class of the object that failed to be cast.
    EXPORT_PC()                                 # about to throw
    LOAD_base_offObject_clazz(a0, rOBJ)         # a0<- obj->clazz
    move      a1,rBIX                      #  r1<- desired class
    JAL(dvmThrowClassCastException)
    b       common_exceptionThrown

    /*
     * Advance PC and get next opcode
     *
     */
.L${opcode}_okay:
    FETCH_ADVANCE_INST(4)                       # advance rPC, load rINST
    GET_INST_OPCODE(t0)                         # extract opcode from rINST
    GOTO_OPCODE(t0)                             # jump to next instruction
    /*
     * Resolution required.  This is the least-likely path.
     *
     *  a2   holds AAAAAAAA
     *  rOBJ holds object
     */
.L${opcode}_resolve:
    EXPORT_PC()                                 # resolve() could throw
    LOAD_rSELF_method(a3)           # a3<- self->method
    move     a1, a2                             # a1<- AAAAAAAA
    li       a2, 0                              # a2<- false
    LOAD_base_offMethod_clazz(a0, a3)   # a0<- method->clazz
    JAL(dvmResolveClass)    # v0<- resolved ClassObject ptr
                                                # got null?
    beqz     v0, common_exceptionThrown         # yes, handle exception
    move     a1, v0                             # a1<- class resolved from AAAAAAAA
    LOAD_base_offObject_clazz(a0, rOBJ)   # a0<- obj->clazz
    b       .L${opcode}_resolved                # pick up where we left off
