/* 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;"