/* Copyright (C) 2008 The Android Open Source Project
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * http://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License.
    */

   /*
    * File: OP_CHECK_CAST.S
    *
    * Code: Checks to see if a cast is allowed. Uses no substitutions.
    *
    * For: check-cast
    *
    * Description: Throw if the reference in the given register cannot be
    *              cast to the indicated type. The type must be a reference
    *              type (not a primitive type).
    *
    * Format: AA|op BBBB (21c)
    *
    * Syntax: op vAA, type@BBBB
    */

    movl        rGLUE, %edx             # get MterpGlue pointer
    movl        offGlue_methodClassDex(%edx), %eax # %eax<- pDvmDex
    GET_VREG    rINST                   # rINST<- vAA
    movl        offDvmDex_pResClasses(%eax), %eax # %eax<- pDvmDex->pResClasses
    cmp         $$0, rINST              # check for null reference object
    je          .L${opcode}_okay        # can always cast null object
    FETCH       1, %ecx                 # %ecx<- BBBB
    movl        (%eax, %ecx, 4), %ecx   # %ecx<- resolved class
    cmp         $$0, %ecx               # check if classes is resolved before?
    je          .L${opcode}_resolve     # resolve class
    jmp         .L${opcode}_resolved    # continue
%break

.L${opcode}_resolved:
    cmp         %ecx, offObject_clazz(rINST) # check for same class
    jne         .L${opcode}_fullcheck   # not same class; do full check

.L${opcode}_okay:
    FINISH      2                       # jump to next instruction

   /*
    *  Trivial test failed, need to perform full check.
    *  offObject_clazz(rINST) holds obj->clazz
    *  %ecx holds class resolved from BBBB
    *  rINST holds object
    */

.L${opcode}_fullcheck:
    movl        offObject_clazz(rINST), %eax  # %eax<- obj->clazz
    movl        %eax, -12(%esp)         # push parameter obj->clazz
    movl        %ecx, -8(%esp)          # push parameter # push parameter resolved class
    lea         -12(%esp), %esp
    call        dvmInstanceofNonTrivial # call: (ClassObject* instance, ClassObject* clazz)
                                        # return: int
    lea         12(%esp), %esp
    cmp         $$0, %eax               # failed?
    jne         .L${opcode}_okay        # success

   /*
    * A cast has failed.  We need to throw a ClassCastException with the
    * class of the object that failed to be cast.
    */

    EXPORT_PC                           # we will throw an exception
    movl        $$.LstrClassCastExceptionPtr, -8(%esp) # push parameter message
    movl        offObject_clazz(rINST), rINST # rINST<- obj->clazz
    movl        offClassObject_descriptor(rINST), rINST # rINST<- obj->clazz->descriptor
    movl        rINST, -4(%esp)         # push parameter obj->clazz->descriptor
    lea         -8(%esp), %esp
    call        dvmThrowExceptionWithClassMessage # call: (const char* exceptionDescriptor,
                                                  #       const char* messageDescriptor, Object* cause)
                                                  # return: void
    lea         8(%esp), %esp
    jmp         common_exceptionThrown

   /*
    * Resolution required.  This is the least-likely path.
    *
    *  rINST holds object
    */

.L${opcode}_resolve:
    movl        offGlue_method(%edx), %eax # %eax<- glue->method
    FETCH       1, %ecx                 # %ecx holds BBBB
    EXPORT_PC                           # in case we throw an exception
    movl        $$0, -8(%esp)           # push parameter false
    movl        offMethod_clazz(%eax), %eax # %eax<- glue->method->clazz
    movl        %ecx, -12(%esp)         # push parameter BBBB
    movl        %eax, -16(%esp)         # push parameter glue->method>clazz
    lea         -16(%esp), %esp
    call        dvmResolveClass         # resolve ClassObject pointer
                                        # call: (const ClassObject* referrer, u4 classIdx,
                                        #        bool fromUnverifiedConstant)
                                        # return ClassObject*
    lea         16(%esp), %esp
    cmp         $$0, %eax               # check for null pointer
    je          common_exceptionThrown  # handle excpetion
    movl        %eax, %ecx              # %ecx<- resolved class
    jmp         .L${opcode}_resolved

.LstrClassCastExceptionPtr:
.asciz      "Ljava/lang/ClassCastException;"