/* 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_INSTANCE_OF.S
    *
    * Code: Checks if object is instance of a class. Uses no substitutions.
    *
    * For: instance-of
    *
    * Description: Store in the given destination register 1 if the indicated
    *              reference is an instance of the given type, or 0 if not.
    *              The type must be a reference type (not a primitive type).
    *
    * Format: B|A|op CCCC (22c)
    *
    * Syntax: op vA, vB, type@CCCC
    *         op vA, vB, field@CCCC
    */

    movl        rINST, %edx             # %edx<- BA
    shr         $$4, %edx               # %edx<- B
    GET_VREG    %edx                    # %edx<- vB
    cmp         $$0, %edx               # check for null object
    je          .L${opcode}_store       # null object
    jmp         .L${opcode}_break
%break

.L${opcode}_break:
    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
    movl        offGlue_methodClassDex(%ecx), %ecx # %ecx<- pDvmDex
    FETCH       1, %eax                 # %eax<- CCCC
    movl        offDvmDex_pResClasses(%ecx), %ecx # %ecx<- pDvmDex->pResClasses
    movl        (%ecx, %eax, 4), %ecx   # %ecx<- resolved class
    movl        offObject_clazz(%edx), %edx # %edx<- obj->clazz
    cmp         $$0, %ecx               # check if already resovled
    je          .L${opcode}_resolve     # not resolved before, so resolve now

.L${opcode}_resolved:
    cmp         %ecx, %edx              # check if same class
    je          .L${opcode}_trivial     # yes, finish
    jmp         .L${opcode}_fullcheck   # no, do full check

   /*
    * The trivial test failed, we need to perform a full check.
    * %edx holds obj->clazz
    * %ecx holds class resolved from BBBB
    */

.L${opcode}_fullcheck:
    movl        %edx, -8(%esp)          # push parameter obj->clazz
    movl        %ecx, -4(%esp)          # push parameter resolved class
    lea         -8(%esp), %esp
    call        dvmInstanceofNonTrivial # perform full check
                                        # call: (ClassObject* instance, ClassObject* clazz)
                                        # return: int
    andl        $$15, rINST             # rINST<- A
    FFETCH_ADV  2, %edx                 # %edx<- next instruction hi; fetch, advance
    lea         8(%esp), %esp
    SET_VREG    %eax, rINST             # vA<- r0
    FGETOP_JMP  2, %edx                 # jump to next instruction; getop, jmp

   /*
    * %edx holds boolean result
    */

.L${opcode}_store:
    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
    andl        $$15, rINST             # rINST<- A
    SET_VREG    %edx, rINST             # vA<- r0
    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp

   /*
    * Trivial test succeeded, save and bail.
    */

.L${opcode}_trivial:
    FFETCH_ADV  2, %eax                 # %eax<- next instruction hi; fetch, advance
    andl        $$15, rINST             # rINST<- A
    SET_VREG    $$1, rINST              # vA<- r0
    FGETOP_JMP  2, %eax                 # jump to next instruction; getop, jmp

   /*
    * Resolution required.  This is the least-likely path.
    * %eax holds BBBB
    */

.L${opcode}_resolve:

    movl        rGLUE, %ecx             # %ecx<- pMterpGlue
    EXPORT_PC
    movl        offGlue_method(%ecx), %ecx # %ecx<- glue->method
    movl        offMethod_clazz(%ecx), %ecx # %ecx<- glue->method->clazz
    movl        %ecx, -12(%esp)         # push parameter glue->method->clazz
    movl        %eax, -8(%esp)          # push parameter CCCC; type index
    movl        $$1, -4(%esp)           # push parameter true
    lea         -12(%esp), %esp
    call        dvmResolveClass         # call: (const ClassObject* referrer, u4 classIdx,
                                        #        bool fromUnverifiedConstant)
                                        # return: ClassObject*
    lea         12(%esp), %esp
    cmp         $$0, %eax               # check for null
    je          common_exceptionThrown  # handle exception
    movl        rINST, %edx             # %edx<- BA+
    shr         $$4, %edx               # %edx<- B
    movl        %eax, %ecx              # need class in %ecx
    GET_VREG    %edx                    # %edx<- vB
    movl        offObject_clazz(%edx), %edx # %edx<- obj->clazz
    jmp         .L${opcode}_resolved    # clazz resolved, continue