blob: 7b5ed9cf949902fc4acfdaf38c089e880f14bd7a [file] [log] [blame]
/* 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: footer.S
*/
.text
.align 2
/*
* Check to see if the thread needs to be suspended or debugger/profiler
* activity has begun.
*
* On entry:
* %ecx is reentry type, e.g. kInterpEntryInstr
* %edx is PC adjustment in bytes
*/
common_periodicChecks:
movl %edx, -8(%esp) # save pc adjustments
movl rGLUE, %edx # %edx<- pMterpGlue
movl %ebx, -4(%esp) # save %ebx to the stack
movl offGlue_pSelfSuspendCount(%edx), %ebx # %ebx<- pSuspendCount (int)
4:
movl offGlue_pDebuggerActive(%edx), %eax # %eax<- pDebuggerActive
testl %eax, %eax
je 5f
movzbl (%eax), %eax # %eax<- get debuggerActive (boolean)
5:
cmp $$0, (%ebx) # check if suspend is pending
jne 2f # handle suspend
movl offGlue_pActiveProfilers(%edx), %ebx # %ebx<- activeProfilers (int)
orl (%ebx), %eax # %eax<- merge activeProfilers and debuggerActive
movl -8(%esp), %edx # %edx<- restore %edx
jne 3f # debugger or profiler active; switch interp
movl -4(%esp), %ebx # %ebx<- restore %ebx
ret # return
2: # check suspended
EXPORT_PC
movl offGlue_self(%edx), %eax # %eax<- glue->self
movl %eax, -12(%esp) # push parameter boolean
lea -12(%esp), %esp
call dvmCheckSuspendPending # call: (Thread* self)
# return: bool
movl 4(%esp), %edx # %edx<- restore %edx
movl 8(%esp), %ebx # %ebx<- restore %ebx
lea 12(%esp), %esp
ret
3: # debugger/profiler enabled, bail out
leal (rPC, %edx, 2), rPC # adjust pc to show target
movl rGLUE, %ecx # %ecx<- pMterpGlue
movb $$kInterpEntryInstr, offGlue_entryPoint(%ecx)
movl $$1, %edx # switch interpreter
jmp common_gotoBail # bail
/*
* Check to see if the thread needs to be suspended or debugger/profiler
* activity has begun. With this variant, the reentry type is hard coded
* as kInterpEntryInstr.
*
* On entry:
* %edx is PC adjustment in bytes
*/
common_periodicChecks_backwardBranch:
EXPORT_PC
movl rGLUE, %ecx # %ecx<- pMterpGlue
movl offGlue_pSelfSuspendCount(%ecx), rINST # %ebx<- pSuspendCount (int)
4:
movl offGlue_pDebuggerActive(%ecx), %eax # %eax<- pDebuggerActive
testl %eax, %eax # test for NULL pointer
je 5f
movzbl (%eax), %eax # %eax<- get debuggerActive count
5:
cmp $$0, (rINST) # check if suspend is pending
jne 2f # handle suspend
movl offGlue_pActiveProfilers(%ecx), rINST # %edx<- activeProfilers (int)
orl (rINST), %eax # %eax<- merge activeProfilers and debuggerActive
jne 3f # debugger or profiler active; switch interp
FINISH_RB %edx, %ecx # jump to next instruction
2: # check suspended
movl offGlue_self(%ecx), %eax# %eax<- glue->self
movl %edx, rINST
movl %eax, -12(%esp) # push parameter boolean
lea -12(%esp), %esp
call dvmCheckSuspendPending # call: (Thread* self)
# return: bool
movl rINST, %edx # %edx<- restore %edx
lea 12(%esp), %esp
FINISH_RB %edx, %ecx
3: # debugger/profiler enabled, bail out
leal (rPC, %edx, 2), rPC # adjust pc to show target
movb $$kInterpEntryInstr, offGlue_entryPoint(%ecx)
movl $$1, %edx # switch interpreter
jmp common_gotoBail # bail
/*
* The equivalent of "goto bail", this calls through the "bail handler".
* State registers will be saved to the "glue" area before bailing.
*
* On entry:
* %edx is "bool changeInterp", indicating if we want to switch to the
* other interpreter or just bail all the way out
*/
common_gotoBail:
SAVE_PC_FP_TO_GLUE %ecx # save program counter and frame pointer
/*
* Inlined dvmMterpStdBail
*/
lea 40(%ebp), %esp
movl %edx, %eax
movl 24(%ebp), %edi
movl 28(%ebp), %esi
movl 32(%ebp), %ebx
movl 36(%ebp), %ebp
ret
/*
* Common code for method invocation with range.
*
* On entry:
* %ecx is "Method* methodToCall", the method we're trying to call
*/
common_invokeMethodRange:
.LinvokeNewRange:
/*
* prepare to copy args to "outs" area of current frame
*/
SAVEAREA_FROM_FP %eax # %eax<- &outs; &StackSaveArea
test rINST, rINST # test for no args
movl rINST, sReg0 # sReg0<- AA
jz .LinvokeArgsDone # no args; jump to args done
FETCH 2, %edx # %edx<- CCCC
/*
* %ecx=methodToCall, %edx=CCCC, sReg0=count, %eax=&outs (&stackSaveArea)
* (very few methods have > 10 args; could unroll for common cases)
*/
movl %ebx, sReg1 # sReg1<- save %ebx
lea (rFP, %edx, 4), %edx # %edx<- &vCCCC
shll $$2, sReg0 # sReg0<- offset
subl sReg0, %eax # %eax<- update &outs
shrl $$2, sReg0 # sReg0<- offset
1:
movl (%edx), %ebx # %ebx<- vCCCC
lea 4(%edx), %edx # %edx<- &vCCCC++
subl $$1, sReg0 # sReg<- sReg--
movl %ebx, (%eax) # *outs<- vCCCC
lea 4(%eax), %eax # outs++
jne 1b # loop if count (sReg0) not zero
movl sReg1, %ebx # %ebx<- restore %ebx
jmp .LinvokeArgsDone # continue
/*
* %ecx is "Method* methodToCall", the method we're trying to call
* prepare to copy args to "outs" area of current frame
*/
common_invokeMethodNoRange:
.LinvokeNewNoRange:
movl rINST, sReg0 # sReg0<- BA
shrl $$4, sReg0 # sReg0<- B
je .LinvokeArgsDone # no args; jump to args done
SAVEAREA_FROM_FP %eax # %eax<- &outs; &StackSaveArea
FETCH 2, %edx # %edx<- GFED
/*
* %ecx=methodToCall, %edx=GFED, sReg0=count, %eax=outs
*/
.LinvokeNonRange:
cmp $$2, sReg0 # compare sReg0 to 2
movl %edx, sReg1 # sReg1<- GFED
jl 1f # handle 1 arg
je 2f # handle 2 args
cmp $$4, sReg0 # compare sReg0 to 4
jl 3f # handle 3 args
je 4f # handle 4 args
5:
andl $$15, rINST # rINST<- A
lea -4(%eax), %eax # %eax<- update &outs; &outs--
movl (rFP, rINST, 4), %edx # %edx<- vA
movl %edx, (%eax) # *outs<- vA
movl sReg1, %edx # %edx<- GFED
4:
shr $$12, %edx # %edx<- G
lea -4(%eax), %eax # %eax<- update &outs; &outs--
movl (rFP, %edx, 4), %edx # %edx<- vG
movl %edx, (%eax) # *outs<- vG
movl sReg1, %edx # %edx<- GFED
3:
and $$0x0f00, %edx # %edx<- 0F00
shr $$6, %edx # %edx<- F at correct offset
lea -4(%eax), %eax # %eax<- update &outs; &outs--
movl (rFP, %edx), %edx # %edx<- vF
movl %edx, (%eax) # *outs<- vF
movl sReg1, %edx # %edx<- GFED
2:
and $$0x00f0, %edx # %edx<- 00E0
shr $$2, %edx # %edx<- E at correct offset
lea -4(%eax), %eax # %eax<- update &outs; &outs--
movl (rFP, %edx), %edx # %edx<- vE
movl %edx, (%eax) # *outs<- vE
movl sReg1, %edx # %edx<- GFED
1:
and $$0x000f, %edx # %edx<- 000D
movl (rFP, %edx, 4), %edx # %edx<- vD
movl %edx, -4(%eax) # *--outs<- vD
0:
/*
* %ecx is "Method* methodToCall", the method we're trying to call
* find space for the new stack frame, check for overflow
*/
.LinvokeArgsDone:
movzwl offMethod_registersSize(%ecx), %eax # %eax<- methodToCall->regsSize
movzwl offMethod_outsSize(%ecx), %edx # %edx<- methodToCall->outsSize
movl %ecx, sReg0 # sReg<- methodToCall
shl $$2, %eax # %eax<- update offset
SAVEAREA_FROM_FP %ecx # %ecx<- &outs; &StackSaveArea
subl %eax, %ecx # %ecx<- newFP; (old savearea - regsSize)
movl rGLUE, %eax # %eax<- pMterpGlue
movl %ecx, sReg1 # sReg1<- &outs
subl $$sizeofStackSaveArea, %ecx # %ecx<- newSaveArea (stack save area using newFP)
movl offGlue_interpStackEnd(%eax), %eax # %eax<- glue->interpStackEnd
movl %eax, sReg2 # sReg2<- glue->interpStackEnd
shl $$2, %edx # %edx<- update offset for outsSize
movl %ecx, %eax # %eax<- newSaveArea
sub %edx, %ecx # %ecx<- bottom; (newSaveArea - outsSize)
cmp sReg2, %ecx # compare interpStackEnd and bottom
movl sReg0, %ecx # %ecx<- restore methodToCall
jl .LstackOverflow # handle frame overflow
/*
* set up newSaveArea
*/
#ifdef EASY_GDB
SAVEAREA_FROM_FP %edx # %edx<- &outs; &StackSaveArea
movl %edx, offStackSaveArea_prevSave(%eax) # newSaveArea->prevSave<- &outs
#endif
movl rFP, offStackSaveArea_prevFrame(%eax) # newSaveArea->prevFrame<- rFP
movl rPC, offStackSaveArea_savedPc(%eax) # newSaveArea->savedPc<- rPC
testl $$ACC_NATIVE, offMethod_accessFlags(%ecx) # check for native call
movl %ecx, offStackSaveArea_method(%eax) # newSaveArea->method<- method to call
jne .LinvokeNative # handle native call
/*
* Update "glue" values for the new method
* %ecx=methodToCall, sReg1=newFp
*/
movl offMethod_clazz(%ecx), %edx # %edx<- method->clazz
movl rGLUE, %eax # %eax<- pMterpGlue
movl %ecx, offGlue_method(%eax) # glue->method<- methodToCall
movl offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
movl offMethod_insns(%ecx), rPC # rPC<- methodToCall->insns
movl %edx, offGlue_methodClassDex(%eax) # glue->methodClassDex<- method->clazz->pDvmDex
movl offGlue_self(%eax), %ecx # %ecx<- glue->self
movl sReg1, rFP # rFP<- newFP
movl rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- newFP
FINISH_A # jump to methodToCall->insns
/*
* Prep for the native call
* %ecx=methodToCall, sReg1=newFP, %eax=newSaveArea
*/
.LinvokeNative:
movl rGLUE, %edx # %edx<- pMterpGlue
movl %ecx, -20(%esp) # push parameter methodToCall
movl offGlue_self(%edx), %edx # %edx<- glue->self
movl offThread_jniLocal_topCookie(%edx), %ecx # %ecx<- glue->self->thread->refNext
movl %ecx, offStackSaveArea_localRefCookie(%eax) # newSaveArea->localRefCookie<- refNext
movl %eax, -4(%esp) # save newSaveArea
movl sReg1, %eax # %eax<- newFP
movl %eax, offThread_curFrame(%edx) # glue->self->curFrame<- newFP
movl %edx, -8(%esp) # save glue->self
movl %edx, -16(%esp) # push parameter glue->self
movl rGLUE, %edx # %edx<- pMterpGlue
movl -20(%esp), %ecx # %ecx<- methodToCall
lea offGlue_retval(%edx), %edx # %edx<- &retval
movl %edx, -24(%esp) # push parameter pMterpGlue
movl %eax, -28(%esp) # push parameter newFP
lea -28(%esp), %esp
#ifdef ASSIST_DEBUGGER
jmp .Lskip
.type dalvik_mterp, %function
dalvik_mterp:
MTERP_ENTRY
.Lskip:
#endif
call *offMethod_nativeFunc(%ecx) # call methodToCall->nativeFunc
lea 28(%esp), %esp
movl -4(%esp), %edx # %edx<- newSaveArea
movl -8(%esp), %ecx # %ecx<- glue->self
movl offStackSaveArea_localRefCookie(%edx), %eax # %eax<- newSaveArea->localRefCookie
FFETCH_ADV 3, %edx # %edx<- next instruction hi; fetch, advance
cmp $$0, offThread_exception(%ecx) # check for exception
movl rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- rFP
movl %eax, offThread_jniLocal_topCookie(%ecx) # glue->self<- newSaveArea->localRefCookie
jne common_exceptionThrown # handle exception
FGETOP_JMP 3, %edx # jump to next instruction; getop, jmp
.LstackOverflow:
movl %ecx, -4(%esp) # push method to call
movl rGLUE, %ecx # %ecx<- pMterpGlue
movl offGlue_self(%ecx), %ecx # %ecx<- glue->self
movl %ecx, -8(%esp) # push parameter self
lea -8(%esp), %esp
call dvmHandleStackOverflow # call: (Thread* self, Method *meth)
# return: void
lea 8(%esp), %esp
jmp common_exceptionThrown # handle exception
#ifdef ASSIST_DEBUGGER
#endif
/*
* Common code for handling a return instruction.
*
* This does not return.
*/
common_returnFromMethod:
.LreturnNew:
/*
* Inline common periodic checks
*/
movl rGLUE, rINST # %ecx<- pMterpGlue
movl offGlue_pSelfSuspendCount(rINST), %edx # %ebx<- pSuspendCount (int)
movl offGlue_pDebuggerActive(rINST), %eax # %eax<- pDebuggerActive
movl (%eax), %eax # %eax<- get debuggerActive (boolean)
and $$7, %eax # %eax<- mask for boolean (just how many bits does it take?)
cmp $$0, (%edx) # check if suspend is pending
jne 2f # handle suspend
movl offGlue_pActiveProfilers(rINST), %edx # %edx<- activeProfilers (int)
or (%edx), %eax # %eax<- merge activeProfilers and debuggerActive
cmp $$0, %eax # check for debuggerActive
jne 3f # debugger or profiler active; switch interp
jmp 4f
2: # check suspended
movl offGlue_self(rINST), %eax# %eax<- glue->self
movl %eax, -12(%esp) # push parameter boolean
lea -12(%esp), %esp
call dvmCheckSuspendPending # call: (Thread* self)
# return: bool
lea 12(%esp), %esp
jmp 4f
3: # debugger/profiler enabled, bail out
movl $$kInterpEntryInstr, offGlue_entryPoint(rINST) # glue->entryPoint<- reentry type
movl $$1, %edx # switch to interp<- true
jmp common_gotoBail # bail
/*
* Get save area; rGLUE is %ebx, rFP is %eax
*/
4:
SAVEAREA_FROM_FP %ecx # %ecx<- saveArea(old)
movl offStackSaveArea_prevFrame(%ecx), rFP # rFP<- saveArea->PrevFrame
movl (offStackSaveArea_method - sizeofStackSaveArea)(rFP), %edx # %edx<- method we are returning to
cmpl $$0, %edx # check for break frame
je common_gotoBail # bail if break frame
movl offStackSaveArea_savedPc(%ecx), rPC # rPC<- saveAreaOld->savedPc
movl offGlue_self(rINST), %ecx # %eax<- glue->self
movl %edx, offGlue_method(rINST) # glue->method<- newSave->method
movl offMethod_clazz(%edx), %edx # %edx<- method->clazz
FFETCH_ADV 3, %eax # %ecx<- next instruction hi; fetch, advance
movl rFP, offThread_curFrame(%ecx) # glue->self->curFrame<- rFP
movl offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
movl %edx, offGlue_methodClassDex(rINST) # glue->pDvmDex<- method->clazz->pDvmDex
FGETOP_JMP 3, %eax # jump to next instruction; getop, jmp
/*
* Handle thrown an exception. If the exception processing code
* returns to us (instead of falling out of the interpreter),
* continue with whatever the next instruction now happens to be.
* This does not return.
*/
common_exceptionThrown:
.LexceptionNew:
movl $$kInterpEntryThrow, %ecx # %ecx<- reentry type
movl $$0, %edx # %edx<- pc adjustment
call common_periodicChecks
movl rGLUE, %eax # %eax<- pMterpGlue
movl offGlue_self(%eax), %edx # %edx<- glue->self
movl offThread_exception(%edx), %ecx # %ecx<- pMterpGlue->self->exception
movl %edx, -4(%esp) # push parameter self
movl %ecx, -8(%esp) # push parameter obj
lea -8(%esp), %esp
call dvmAddTrackedAlloc # don't allow the exception to be GC'd
# call: (Object* obj, Thread* self)
# return: void
movl 4(%esp), %edx # %edx<- glue->self
movl $$0, offThread_exception(%edx) # glue->self->exception<- NULL
/*
* set up args and a local for &fp
*/
movl rFP, -4(%esp) # move fp to stack
lea -4(%esp), %esp # update %esp
movl %esp, -4(%esp) # push parameter 4<- &fp
movl $$0, -8(%esp) # push parameter 3<- false
movl 4(%esp), %edx
movl %edx, -12(%esp) # push parameter 2<- glue->self->exception
movl rGLUE, %eax # %eax<- pMterpGlue
movl offGlue_method(%eax), %edx # %edx<- glue->method
movl offMethod_insns(%edx), %edx # %edx<- glue->method->insns
movl rPC, %ecx # %ecx<- rPC
subl %edx, %ecx # %ecx<- pc - glue->method->insns
sar $$1, %ecx # %ecx<- adjust %ecx for offset
movl %ecx, -16(%esp) # push parameter 1<- glue->method->insns
movl 8(%esp), %edx
movl %edx, -20(%esp) # push parameter 0<- glue->self
lea -20(%esp), %esp
/*
* call dvmFindCatchBlock, %eax gets catchRelPc (a code-unit offset)
*/
call dvmFindCatchBlock # call: (Thread* self, int relPc, Object* exception,
# bool doUnroll, void** newFrame)
# return: int
lea 32(%esp), %esp
movl -12(%esp), rFP # rFP<- updated rFP
cmp $$0, %eax # check for catchRelPc < 0
jl .LnotCaughtLocally # handle not caught locally
/*
* fix stack overflow if necessary
*/
movl -4(%esp), %ecx # %ecx<- glue->self
cmp $$0, offThread_stackOverflowed(%ecx)
je 1f
movl %eax, -4(%esp) # save %eax for later
movl %ecx, -12(%esp) # push parameter 2 glue->self
lea -12(%esp), %esp
call dvmCleanupStackOverflow # call: (Thread* self, Object* exception)
# return: void
lea 12(%esp), %esp
movl -4(%esp), %eax # %eax<- restore %eax
jmp 2f
1:
movl %ecx, -12(%esp) # push parameter 2 glue->self
2:
/*
* adjust locals to match self->curFrame and updated PC
*
*/
SAVEAREA_FROM_FP %edx # %edx<- get newSaveArea
movl rGLUE, %ecx # %ecx<- pMterpGlue
movl offStackSaveArea_method(%edx), rPC # rPC<- newMethod
movl rPC, offGlue_method(%ecx) # glue->method<- newMethod
movl offMethod_clazz(rPC), %edx # %edx<- method->clazz
movl offMethod_insns(rPC), rPC # rPC<- method->insns
movl offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
lea (rPC, %eax, 2), rPC # rPC<- method->insns + catchRelPc
movl %edx, offGlue_methodClassDex(%ecx) # glue->pDvmDex<- method->clazz->pDvmDex
movl -8(%esp), %eax
movl %eax, -16(%esp) # push parameter 1 obj
lea -16(%esp), %esp
call dvmReleaseTrackedAlloc # call: (Object* obj, Thread* self)
# return: void
lea 16(%esp), %esp
FINISH_FETCH %eax
cmp $$OP_MOVE_EXCEPTION, %eax # is it a move exception
jne 1f
movl -12(%esp), %edx # %edx<- glue->self
movl -8(%esp), %ecx # %ecx<- exception
movl %ecx, offThread_exception(%edx) # restore the exception
1:
FINISH_JMP %eax
/*
* -8(%esp) = exception, -4(%esp) = self
*/
.LnotCaughtLocally:
movl -4(%esp), %edx # %edx<- glue->self
movzb offThread_stackOverflowed(%edx), %eax # %eax<- self->stackOverflowed
cmp $$0, %eax # check for stack overflow;
# maybe should use cmpb
je 1f #
movl %edx, -12(%esp) # push parameter 1 glue->self
lea -12(%esp), %esp
call dvmCleanupStackOverflow # call: (Thread* self, Object* exception)
# return: void
lea 12(%esp), %esp
/*
* Release the exception
* -8(%esp) = exception, -4(%esp) = self
*/
1:
movl -8(%esp), %ecx # %ecx<- exception
movl -4(%esp), %edx # %edx<- glue->self
movl %ecx, offThread_exception(%edx) # glue->self<- exception
lea -8(%esp), %esp
call dvmReleaseTrackedAlloc # call: (Object* obj, Thread* self)
# return: void
lea 8(%esp), %esp
movl $$0, %edx # switch to interp<- false
jmp common_gotoBail # bail
/*
* After returning from a "glued" function, pull out the updated
* values and start executing at the next instruction.
*/
common_resumeAfterGlueCall:
LOAD_PC_FP_FROM_GLUE # pull rPC and rFP out of glue
FINISH_A # jump to next instruction
/*
* For debugging, cause an immediate fault.
*/
common_abort:
jmp .LdeadFood
.LdeadFood:
.int 0xdeadf00d
/*
* Invalid array index.
*/
common_errArrayIndex:
EXPORT_PC
movl $$.LstrArrayIndexException, -8(%esp) # push parameter description
movl $$0, -4(%esp) # push parameter msg paramter
lea -8(%esp), %esp
call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
# return: void
lea 8(%esp), %esp
jmp common_exceptionThrown # handle exception
/*
* Invalid array value.
*/
common_errArrayStore:
EXPORT_PC
movl $$.LstrArrayStoreException, -8(%esp) # push parameter description
movl $$0, -4(%esp) # push parameter msg paramter
lea -8(%esp), %esp
call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
# return: void
lea 8(%esp), %esp
jmp common_exceptionThrown # handle exception
/*
* Integer divide or mod by zero.
*/
common_errDivideByZero:
EXPORT_PC
movl $$.LstrArithmeticException, -8(%esp) # push parameter description
movl $$.LstrDivideByZero, -4(%esp) # push parameter msg paramter
lea -8(%esp), %esp
call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
# return: void
lea 8(%esp), %esp
jmp common_exceptionThrown # handle exception
/*
* Attempt to allocate an array with a negative size.
*/
common_errNegativeArraySize:
EXPORT_PC
movl $$.LstrNegativeArraySizeException, -8(%esp) # push parameter description
movl $$0, -4(%esp) # push parameter msg paramter
lea -8(%esp), %esp
call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
# return: void
lea 8(%esp), %esp
jmp common_exceptionThrown # handle exception
/*
* Invocation of a non-existent method.
*/
common_errNoSuchMethod:
EXPORT_PC
movl $$.LstrNoSuchMethodError, -8(%esp) # push parameter description
movl $$0, -4(%esp) # push parameter msg paramter
lea -8(%esp), %esp
call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
# return: void
lea 8(%esp), %esp
jmp common_exceptionThrown # handle exception
/*
* Unexpected null object.
*/
common_errNullObject:
EXPORT_PC
movl $$.LstrNullPointerException, -8(%esp) # push parameter description
movl $$0, -4(%esp) # push parameter msg paramter
lea -8(%esp), %esp
call dvmThrowException # call: (const char* exceptionDescriptor, const char* msg)
# return: void
lea 8(%esp), %esp
jmp common_exceptionThrown # handle exception
/*
* String references
*/
.align 4
.section .rodata
.LstrArithmeticException:
.asciz "Ljava/lang/ArithmeticException;"
.LstrArrayIndexException:
.asciz "Ljava/lang/ArrayIndexOutOfBoundsException;"
.LstrArrayStoreException:
.asciz "Ljava/lang/ArrayStoreException;"
.LstrDivideByZero:
.asciz "divide by zero"
.LstrInstantiationError:
.asciz "Ljava/lang/InstantiationError;"
.LstrNegativeArraySizeException:
.asciz "Ljava/lang/NegativeArraySizeException;"
.LstrNoSuchMethodError:
.asciz "Ljava/lang/NoSuchMethodError;"
.LstrNullPointerException:
.asciz "Ljava/lang/NullPointerException;"
.LstrExceptionNotCaughtLocally:
.asciz "Exception %s from %s:%d not caught locally\n"