-This directory contains the Dalvik virtual machine and associated
-class library.
+This directory contains the Dalvik virtual machine and core class library,
+as well as related tools, libraries, and tests.
A note about the licenses and header comments
---------------------------------------------
void dumpInstruction(DexFile* pDexFile, const DexCode* pCode, int insnIdx,
int insnWidth, const DecodedInstruction* pDecInsn)
{
- static const float gSpecialTab[16] = {
- -2.0f, -1.0f, -0.5f, -0.25f, -0.1f, 0.1f, 0.25f, 0.5f,
- 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 10.0f, 100.0f, 1000.0f
- };
const u2* insns = pCode->insns;
int i;
Home of Dalvik eXchange, the thing that takes in class files and
-reformulates them for consumption in the VM.
+reformulates them for consumption in the VM. It also does a few other
+things; use "dx --help" to see a modicum of self-documentation.
intCurrencySymbol = env->NewStringUTF("XXX");
}
if(currencySymbol == NULL) {
- currencySymbol = env->NewStringUTF("\u00a4");
+ // creating a new string explicitly with the UTF-8 encoding of "\u00a4"
+ currencySymbol = env->NewStringUTF("\xc2\xa4");
}
counter += 2;
public class PlatformAddressFactory {
- public static PlatformAddress on(int value) {
- return PlatformAddressFactory.on(value, PlatformAddress.UNKNOWN);
+ // BEGIN android-added
+ /**
+ * Defines the number of PlatformAddress objects to be cached. Must be a
+ * power of two. Caching PlatformAddress objects minimizes the creation
+ * of garbage and reduces the number of GC-hiccups in OpenGL animations.
+ */
+ private final static int CACHE_SIZE = 1<<8;
+
+ /**
+ * A mask with all bits set, matching the size of the cache.
+ */
+ private final static int CACHE_MASK = CACHE_SIZE - 1;
+
+ /**
+ * Defines the maximum number of probes taken per hash, used for looking
+ * up an empty cache slot or a previously stored PlatformAddress.
+ */
+ private final static int MAX_PROBES = 5;
+
+ /**
+ * A cycling index (0 to MAX_PROBES-1) used to replace elements in the cache.
+ */
+ private static int replacementIndex = 0;
+
+ /**
+ * Array of PlatformAddress references kept from garbage collection.
+ */
+ private static PlatformAddress[] cache = new PlatformAddress[CACHE_SIZE];
+ // END android-added
+
+
+ // BEGIN android-changed
+ public synchronized static PlatformAddress on(int value, long size) {
+ if (value == 0) {
+ return PlatformAddress.NULL;
+ }
+ int idx = value >> 5;
+ for (int probe = 0; probe < MAX_PROBES; probe++) {
+ PlatformAddress cachedObj = cache[(idx + probe) & CACHE_MASK];
+ if (cachedObj == null) {
+ return cache[(idx + probe) & CACHE_MASK] =
+ new PlatformAddress(value, size);
+ }
+ if (cachedObj.osaddr == value && cachedObj.size == size) {
+ return cachedObj;
+ }
+ }
+ replacementIndex = (replacementIndex + 1) % MAX_PROBES;
+ return cache[(idx + replacementIndex) & CACHE_MASK] =
+ new PlatformAddress(value, size);
}
+ // END android-changed
- public static PlatformAddress on(int value, long size) {
- PlatformAddress addr = (value == 0) ? PlatformAddress.NULL : new PlatformAddress(value, size);
- return addr;
+ public static PlatformAddress on(int value) {
+ return PlatformAddressFactory.on(value, PlatformAddress.UNKNOWN);
}
public static MappedPlatformAddress mapOn(int value, long size) {
arch/arm/CallOldABI.S \
arch/arm/CallEABI.S \
arch/arm/HintsEABI.c
- # TODO: select sources for ARMv4 vs. ARMv5TE
- LOCAL_SRC_FILES += \
- mterp/out/InterpC-armv5te.c.arm \
- mterp/out/InterpAsm-armv5te.S
+ #
+ # The armv4 configation in mterp is actually armv4t, it's just
+ # wrongly named
+ #
+ # TODO: Rename mterp/config-armv4 and mterp/armv4 (to armv4t)
+ # then remove this ifeq.
+ #
+ ifeq ($(TARGET_ARCH_VERSION),armv4t)
+ LOCAL_SRC_FILES += \
+ mterp/out/InterpC-armv4.c.arm \
+ mterp/out/InterpAsm-armv4.S
+ else
+ # Select architecture specific sources (armv4,armv5te etc)
+ LOCAL_SRC_FILES += \
+ mterp/out/InterpC-$(TARGET_ARCH_VERSION).c.arm \
+ mterp/out/InterpAsm-$(TARGET_ARCH_VERSION).S
+ endif
LOCAL_SHARED_LIBRARIES += libdl
else
ifeq ($(TARGET_ARCH),x86)
}
#endif
+#if WITH_OBJECT_HEADERS
+ if (ptr2chunk(obj)->scanGeneration == gGeneration) {
+ LOGE("object 0x%08x was already scanned this generation\n",
+ (uintptr_t)obj);
+ dvmAbort();
+ }
+ ptr2chunk(obj)->oldScanGeneration = ptr2chunk(obj)->scanGeneration;
+ ptr2chunk(obj)->scanGeneration = gGeneration;
+ ptr2chunk(obj)->scanCount++;
+#endif
+
/* Get and mark the class object for this particular instance.
*/
clazz = obj->clazz;
*/
return;
}
+
#if WITH_OBJECT_HEADERS
gMarkParent = obj;
- if (ptr2chunk(obj)->scanGeneration == gGeneration) {
- LOGE("object 0x%08x was already scanned this generation\n",
- (uintptr_t)obj);
- dvmAbort();
- }
- ptr2chunk(obj)->oldScanGeneration = ptr2chunk(obj)->scanGeneration;
- ptr2chunk(obj)->scanGeneration = gGeneration;
- ptr2chunk(obj)->scanCount++;
#endif
assert(dvmIsValidObject((Object *)clazz));
}
/*
- * Initialize some things we need for verification.
+ * Free up some things we needed for verification.
*/
void dvmVerificationShutdown(void)
{
@ call the method
ldr ip, [r4, #8] @ func
+#ifdef __ARM_HAVE_BLX
blx ip
+#else
+ mov lr, pc
+ bx ip
+#endif
@ We're back, result is in r0 or (for long/double) r0-r1.
@
static inline s4 s4FromSwitchData(const void* switchData) {
u2* data = switchData;
return data[0] | (((s4) data[1]) << 16);
+}
#endif
/*
.LOP_INVOKE_DIRECT_finish:
UNSPILL(rPC)
testl %ecx,%ecx # null "this"?
- movl $0,%ecx
- #jne common_invokeMethodNoRange # no, continue on
- jne common_invokeOld # no, continue on, eax<- method, ecx<- methodCallRange
+ jne common_invokeMethodNoRange # no, continue on
jmp common_errNullObject
/* ------------------------------ */
EXPORT_PC()
movl offDvmDex_pResMethods(%ecx),%ecx # ecx<- pDvmDex->pResMethods
movl (%ecx,%eax,4),%eax # eax<- resolved methodToCall
- movl $0,%ecx # needed by common_invokeOld - revisit
testl %eax,%eax
- #jne common_invokeMethodNoRange
- jne common_invokeOld
+ jne common_invokeMethodNoRange
GET_GLUE(%ecx)
movl offGlue_method(%ecx),%ecx # ecx<- glue->method
movzwl 2(rPC),%eax
.LOP_INVOKE_DIRECT_RANGE_finish:
UNSPILL(rPC)
testl %ecx,%ecx # null "this"?
- movl $1,%ecx
- #jne common_invokeMethodRange # no, continue on
- jne common_invokeOld # no, continue on, eax<- method, ecx<- methodCallRange
+ jne common_invokeMethodRange # no, continue on
jmp common_errNullObject
EXPORT_PC()
movl offDvmDex_pResMethods(%ecx),%ecx # ecx<- pDvmDex->pResMethods
movl (%ecx,%eax,4),%eax # eax<- resolved methodToCall
- movl $1,%ecx # needed by common_invokeOld - revisit
testl %eax,%eax
- #jne common_invokeMethodRange
- jne common_invokeOld
+ jne common_invokeMethodRange
GET_GLUE(%ecx)
movl offGlue_method(%ecx),%ecx # ecx<- glue->method
movzwl 2(rPC),%eax
movl offClassObject_vtable(%eax),%eax # eax<- thisPtr->clazz->vtable
EXPORT_PC() # might throw later - get ready
movl (%eax,%ecx,4),%eax # eax<- vtable[BBBB]
- movl $0,%ecx # pass range flag
- #jmp common_invokeMethodNoRange
- jmp common_invokeOld
+ jmp common_invokeMethodNoRange
+
/* ------------------------------ */
movl offClassObject_vtable(%eax),%eax # eax<- thisPtr->clazz->vtable
EXPORT_PC() # might throw later - get ready
movl (%eax,%ecx,4),%eax # eax<- vtable[BBBB]
- movl $1,%ecx # pass range flag
- #jmp common_invokeMethodRange
- jmp common_invokeOld
+ jmp common_invokeMethodRange
+
movl offClassObject_vtable(%ecx),%ecx # ecx<- vtable
EXPORT_PC()
movl (%ecx,%eax,4),%eax # eax<- super->vtable[BBBB]
- movl $0,%ecx # ecx<- range flag
- #jmp common_invokeMethodNoRange
- jmp common_invokeOld
+ jmp common_invokeMethodNoRange
/* ------------------------------ */
movl offClassObject_vtable(%ecx),%ecx # ecx<- vtable
EXPORT_PC()
movl (%ecx,%eax,4),%eax # eax<- super->vtable[BBBB]
- movl $1,%ecx # ecx<- range flag
- #jmp common_invokeMethodRange
- jmp common_invokeOld
+ jmp common_invokeMethodRange
movl offObject_clazz(%ecx),%ecx # ecx<- thisPtr->clazz
movl offClassObject_vtable(%ecx),%ecx # ecx<- thisPtr->clazz->vtable
movl (%ecx,%eax,4),%eax # eax<- vtable[methodIndex]
- movl $0,%ecx # needed for common_invokeOld
- #jmp common_invokeMethodNoRange
- jmp common_invokeOld
+ jmp common_invokeMethodNoRange
/* continuation for OP_INVOKE_SUPER */
jae .LOP_INVOKE_SUPER_nsm # method not present in superclass
movl offClassObject_vtable(%eax),%eax # eax<- ...clazz->super->vtable
movl (%eax,%ecx,4),%eax # eax<- vtable[methodIndex]
- movl $0,%ecx
- #jmp common_invokeMethodNoRange
- jmp common_invokeOld
+ jmp common_invokeMethodNoRange
+
/* At this point:
* ecx = null (needs to be resolved base method)
SPILL(rPC)
call dvmResolveMethod # call(clazz,ref,flags)
UNSPILL(rPC)
- movl $0,%ecx
testl %eax,%eax # got null?
- #jne common_invokeMethodNoRange
- jne common_invokeOld
+ jne common_invokeMethodNoRange
jmp common_exceptionThrown
UNSPILL(rPC)
testl %eax,%eax
je common_exceptionThrown
- movl $0,%ecx
- #jmp common_invokeMethodNoRange
- jmp common_invokeOld
+ jmp common_invokeMethodNoRange
/* continuation for OP_INVOKE_VIRTUAL_RANGE */
movl offObject_clazz(%ecx),%ecx # ecx<- thisPtr->clazz
movl offClassObject_vtable(%ecx),%ecx # ecx<- thisPtr->clazz->vtable
movl (%ecx,%eax,4),%eax # eax<- vtable[methodIndex]
- movl $1,%ecx # needed for common_invokeOld
- #jmp common_invokeMethodRange
- jmp common_invokeOld
+ jmp common_invokeMethodRange
/* continuation for OP_INVOKE_SUPER_RANGE */
jae .LOP_INVOKE_SUPER_RANGE_nsm # method not present in superclass
movl offClassObject_vtable(%eax),%eax # eax<- ...clazz->super->vtable
movl (%eax,%ecx,4),%eax # eax<- vtable[methodIndex]
- movl $1,%ecx
- #jmp common_invokeMethodRange
- jmp common_invokeOld
+ jmp common_invokeMethodRange
+
/* At this point:
* ecx = null (needs to be resolved base method)
SPILL(rPC)
call dvmResolveMethod # call(clazz,ref,flags)
UNSPILL(rPC)
- movl $1,%ecx
testl %eax,%eax # got null?
- #jne common_invokeMethodRange
- jne common_invokeOld
+ jne common_invokeMethodRange
jmp common_exceptionThrown
UNSPILL(rPC)
testl %eax,%eax
je common_exceptionThrown
- movl $1,%ecx
- #jmp common_invokeMethodRange
- jmp common_invokeOld
+ jmp common_invokeMethodRange
/* continuation for OP_FLOAT_TO_INT */
*/
common_backwardBranch:
GET_GLUE(%ecx)
- call common_periodicChecks # Note: expects rPC to be preserved
+ call common_periodicChecks # Note: expects rPC to be preserved
ADVANCE_PC_INDEXED(rINST_FULL)
FETCH_INST()
GOTO_NEXT
+
+
+/*
+ * Common code for method invocation with range.
+ *
+ * On entry:
+ * eax = Method* methodToCall
+ * rINST trashed, must reload
+ */
+
+common_invokeMethodRange:
+.LinvokeNewRange:
+
+ /*
+ * prepare to copy args to "outs" area of current frame
+ */
+
+ movzbl 1(rPC),rINST_FULL # rINST_FULL<- AA
+ movzwl 4(rPC), %ecx # %ecx<- CCCC
+ SPILL(rPC)
+ SAVEAREA_FROM_FP(%edx,rFP) # %edx<- &StackSaveArea
+ test rINST_FULL, rINST_FULL
+ movl rINST_FULL, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- AA
+ jz .LinvokeArgsDone # no args; jump to args done
+
+
+ /*
+ * %eax=methodToCall, %ecx=CCCC, LOCAL0_OFFSET(%ebp)=count, %edx=&outs (&stackSaveArea)
+ * (very few methods have > 10 args; could unroll for common cases)
+ */
+
+ movl %ebx, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- save %ebx
+ lea (rFP, %ecx, 4), %ecx # %ecx<- &vCCCC
+ shll $2, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- offset
+ subl LOCAL0_OFFSET(%ebp), %edx # %edx<- update &outs
+ shrl $2, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- offset
+1:
+ movl (%ecx), %ebx # %ebx<- vCCCC
+ lea 4(%ecx), %ecx # %ecx<- &vCCCC++
+ subl $1, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET<- LOCAL0_OFFSET--
+ movl %ebx, (%edx) # *outs<- vCCCC
+ lea 4(%edx), %edx # outs++
+ jne 1b # loop if count (LOCAL0_OFFSET(%ebp)) not zero
+ movl LOCAL1_OFFSET(%ebp), %ebx # %ebx<- restore %ebx
+ jmp .LinvokeArgsDone # continue
+
+ /*
+ * %eax is "Method* methodToCall", the method we're trying to call
+ * prepare to copy args to "outs" area of current frame
+ */
+
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+ movzbl 1(rPC),rINST_FULL # rINST_FULL<- BA
+ SPILL(rPC)
+ movl rINST_FULL, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BA
+ shrl $4, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- B
+ je .LinvokeArgsDone # no args; jump to args done
+ movzwl 4(rPC), %ecx # %ecx<- GFED
+ SAVEAREA_FROM_FP(%edx,rFP) # %edx<- &StackSaveArea
+
+ /*
+ * %eax=methodToCall, %ecx=GFED, LOCAL0_OFFSET(%ebp)=count, %edx=outs
+ */
+
+.LinvokeNonRange:
+ cmp $2, LOCAL0_OFFSET(%ebp) # compare LOCAL0_OFFSET(%ebp) to 2
+ movl %ecx, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- GFED
+ jl 1f # handle 1 arg
+ je 2f # handle 2 args
+ cmp $4, LOCAL0_OFFSET(%ebp) # compare LOCAL0_OFFSET(%ebp) to 4
+ jl 3f # handle 3 args
+ je 4f # handle 4 args
+5:
+ andl $15, rINST_FULL # rINST<- A
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, rINST_FULL, 4), %ecx # %ecx<- vA
+ movl %ecx, (%edx) # *outs<- vA
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+4:
+ shr $12, %ecx # %ecx<- G
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vG
+ movl %ecx, (%edx) # *outs<- vG
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+3:
+ and $0x0f00, %ecx # %ecx<- 0F00
+ shr $8, %ecx # %ecx<- F
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vF
+ movl %ecx, (%edx) # *outs<- vF
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+2:
+ and $0x00f0, %ecx # %ecx<- 00E0
+ shr $4, %ecx # %ecx<- E
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vE
+ movl %ecx, (%edx) # *outs<- vE
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+1:
+ and $0x000f, %ecx # %ecx<- 000D
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vD
+ movl %ecx, -4(%edx) # *--outs<- vD
+0:
+
+ /*
+ * %eax is "Method* methodToCall", the method we're trying to call
+ * find space for the new stack frame, check for overflow
+ */
+
+.LinvokeArgsDone:
+ movzwl offMethod_registersSize(%eax), %edx # %edx<- methodToCall->regsSize
+ movzwl offMethod_outsSize(%eax), %ecx # %ecx<- methodToCall->outsSize
+ movl %eax, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET<- methodToCall
+ shl $2, %edx # %edx<- update offset
+ SAVEAREA_FROM_FP(%eax,rFP) # %eax<- &StackSaveArea
+ subl %edx, %eax # %eax<- newFP; (old savearea - regsSize)
+ GET_GLUE(%edx) # %edx<- pMterpGlue
+ movl %eax, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- &outs
+ subl $sizeofStackSaveArea, %eax # %eax<- newSaveArea (stack save area using newFP)
+ movl offGlue_interpStackEnd(%edx), %edx # %edx<- glue->interpStackEnd
+ movl %edx, LOCAL2_OFFSET(%ebp) # LOCAL2_OFFSET<- glue->interpStackEnd
+ shl $2, %ecx # %ecx<- update offset for outsSize
+ movl %eax, %edx # %edx<- newSaveArea
+ sub %ecx, %eax # %eax<- bottom; (newSaveArea - outsSize)
+ cmp LOCAL2_OFFSET(%ebp), %eax # compare interpStackEnd and bottom
+ movl LOCAL0_OFFSET(%ebp), %eax # %eax<- restore methodToCall
+ jl .LstackOverflow # handle frame overflow
+
+ /*
+ * set up newSaveArea
+ */
+
+#ifdef EASY_GDB
+ SAVEAREA_FROM_FP(%ecx,rFP) # %ecx<- &StackSaveArea
+ movl %ecx, offStackSaveArea_prevSave(%edx) # newSaveArea->prevSave<- &outs
+#endif
+ movl rFP, offStackSaveArea_prevFrame(%edx) # newSaveArea->prevFrame<- rFP
+ movl rPC_SPILL(%ebp), %ecx
+ movl %ecx, offStackSaveArea_savedPc(%edx) # newSaveArea->savedPc<- rPC
+ testl $ACC_NATIVE, offMethod_accessFlags(%eax) # check for native call
+ movl %eax, offStackSaveArea_method(%edx) # newSaveArea->method<- method to call
+ jne .LinvokeNative # handle native call
+
+ /*
+ * Update "glue" values for the new method
+ * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFp
+ */
+
+ movl offMethod_clazz(%eax), %edx # %edx<- method->clazz
+ GET_GLUE(%ecx) # %ecx<- pMterpGlue
+ movl offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
+ movl %eax, offGlue_method(%ecx) # glue->method<- methodToCall
+ movl %edx, offGlue_methodClassDex(%ecx) # glue->methodClassDex<- method->clazz->pDvmDex
+ movl offMethod_insns(%eax), rPC # rPC<- methodToCall->insns
+ movl offGlue_self(%ecx), %eax # %eax<- glue->self
+ movl LOCAL1_OFFSET(%ebp), rFP # rFP<- newFP
+ movl rFP, offThread_curFrame(%eax) # glue->self->curFrame<- newFP
+ FETCH_INST()
+ GOTO_NEXT # jump to methodToCall->insns
+
+ /*
+ * Prep for the native call
+ * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFP, %edx=newSaveArea
+ */
+
+.LinvokeNative:
+ GET_GLUE(%ecx) # %ecx<- pMterpGlue
+ movl %eax, OUT_ARG1(%esp) # push parameter methodToCall
+ movl offGlue_self(%ecx), %ecx # %ecx<- glue->self
+ movl offThread_jniLocal_nextEntry(%ecx), %eax # %eax<- glue->self->thread->refNext
+ movl %eax, offStackSaveArea_localRefTop(%edx) # newSaveArea->localRefTop<- refNext
+ movl %edx, OUT_ARG4(%esp) # save newSaveArea
+ movl LOCAL1_OFFSET(%ebp), %edx # %edx<- newFP
+ movl %edx, offThread_curFrame(%ecx) # glue->self->curFrame<- newFP
+ movl %ecx, OUT_ARG3(%esp) # save glue->self
+ movl %ecx, OUT_ARG2(%esp) # push parameter glue->self
+ GET_GLUE(%ecx) # %ecx<- pMterpGlue
+ movl OUT_ARG1(%esp), %eax # %eax<- methodToCall
+ lea offGlue_retval(%ecx), %ecx # %ecx<- &retval
+ movl %ecx, OUT_ARG0(%esp) # push parameter pMterpGlue
+ push %edx # push parameter newFP
+
+ call *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
+ lea 4(%esp), %esp
+ movl OUT_ARG4(%esp), %ecx # %ecx<- newSaveArea
+ movl OUT_ARG3(%esp), %eax # %eax<- glue->self
+ movl offStackSaveArea_localRefTop(%ecx), %edx # %edx<- newSaveArea->localRefTop
+ cmp $0, offThread_exception(%eax) # check for exception
+ movl rFP, offThread_curFrame(%eax) # glue->self->curFrame<- rFP
+ movl %edx, offThread_jniLocal_nextEntry(%eax) # glue->self<- newSaveArea->localRefTop
+ UNSPILL(rPC)
+ jne common_exceptionThrown # handle exception
+ FETCH_INST_WORD(3)
+ ADVANCE_PC(3)
+ GOTO_NEXT # jump to next instruction
+
+.LstackOverflow:
+ GET_GLUE(%eax) # %eax<- pMterpGlue
+ movl offGlue_self(%eax), %eax # %eax<- glue->self
+ movl %eax, OUT_ARG0(%esp) # push parameter self
+ call dvmHandleStackOverflow # call: (Thread* self)
+ UNSPILL(rPC) # return: void
+ jmp common_exceptionThrown # handle exception
+
+
/*
* Common invoke code (old-style).
* TUNING: Rewrite along lines of new armv5 code?
.L${opcode}_finish:
UNSPILL(rPC)
testl %ecx,%ecx # null "this"?
- movl $$$isrange,%ecx
- #jne common_invokeMethod${routine} # no, continue on
- jne common_invokeOld # no, continue on, eax<- method, ecx<- methodCallRange
+ jne common_invokeMethod${routine} # no, continue on
jmp common_errNullObject
%break
UNSPILL(rPC)
testl %eax,%eax
je common_exceptionThrown
- movl $$$isrange,%ecx
- #jmp common_invokeMethod${routine}
- jmp common_invokeOld
+ jmp common_invokeMethod${routine}
EXPORT_PC()
movl offDvmDex_pResMethods(%ecx),%ecx # ecx<- pDvmDex->pResMethods
movl (%ecx,%eax,4),%eax # eax<- resolved methodToCall
- movl $$$isrange,%ecx # needed by common_invokeOld - revisit
testl %eax,%eax
- #jne common_invokeMethod${routine}
- jne common_invokeOld
+ jne common_invokeMethod${routine}
GET_GLUE(%ecx)
movl offGlue_method(%ecx),%ecx # ecx<- glue->method
movzwl 2(rPC),%eax
SPILL(rPC)
call dvmResolveMethod # call(clazz,ref,flags)
UNSPILL(rPC)
- movl $$$isrange,%ecx
testl %eax,%eax # got null?
- #jne common_invokeMethod${routine}
- jne common_invokeOld
+ jne common_invokeMethod${routine}
jmp common_exceptionThrown
jae .L${opcode}_nsm # method not present in superclass
movl offClassObject_vtable(%eax),%eax # eax<- ...clazz->super->vtable
movl (%eax,%ecx,4),%eax # eax<- vtable[methodIndex]
- movl $$$isrange,%ecx
- #jmp common_invokeMethod${routine}
- jmp common_invokeOld
+ jmp common_invokeMethod${routine}
+
/* At this point:
* ecx = null (needs to be resolved base method)
movl offClassObject_vtable(%ecx),%ecx # ecx<- vtable
EXPORT_PC()
movl (%ecx,%eax,4),%eax # eax<- super->vtable[BBBB]
- movl $$$isrange,%ecx # ecx<- range flag
- #jmp common_invokeMethod${routine}
- jmp common_invokeOld
+ jmp common_invokeMethod${routine}
movl offObject_clazz(%ecx),%ecx # ecx<- thisPtr->clazz
movl offClassObject_vtable(%ecx),%ecx # ecx<- thisPtr->clazz->vtable
movl (%ecx,%eax,4),%eax # eax<- vtable[methodIndex]
- movl $$$isrange,%ecx # needed for common_invokeOld
- #jmp common_invokeMethod${routine}
- jmp common_invokeOld
+ jmp common_invokeMethod${routine}
movl offClassObject_vtable(%eax),%eax # eax<- thisPtr->clazz->vtable
EXPORT_PC() # might throw later - get ready
movl (%eax,%ecx,4),%eax # eax<- vtable[BBBB]
- movl $$$isrange,%ecx # pass range flag
- #jmp common_invokeMethod${routine}
- jmp common_invokeOld
+ jmp common_invokeMethod${routine}
+
*/
common_backwardBranch:
GET_GLUE(%ecx)
- call common_periodicChecks # Note: expects rPC to be preserved
+ call common_periodicChecks # Note: expects rPC to be preserved
ADVANCE_PC_INDEXED(rINST_FULL)
FETCH_INST()
GOTO_NEXT
+
+
+/*
+ * Common code for method invocation with range.
+ *
+ * On entry:
+ * eax = Method* methodToCall
+ * rINST trashed, must reload
+ */
+
+common_invokeMethodRange:
+.LinvokeNewRange:
+
+ /*
+ * prepare to copy args to "outs" area of current frame
+ */
+
+ movzbl 1(rPC),rINST_FULL # rINST_FULL<- AA
+ movzwl 4(rPC), %ecx # %ecx<- CCCC
+ SPILL(rPC)
+ SAVEAREA_FROM_FP(%edx,rFP) # %edx<- &StackSaveArea
+ test rINST_FULL, rINST_FULL
+ movl rINST_FULL, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- AA
+ jz .LinvokeArgsDone # no args; jump to args done
+
+
+ /*
+ * %eax=methodToCall, %ecx=CCCC, LOCAL0_OFFSET(%ebp)=count, %edx=&outs (&stackSaveArea)
+ * (very few methods have > 10 args; could unroll for common cases)
+ */
+
+ movl %ebx, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- save %ebx
+ lea (rFP, %ecx, 4), %ecx # %ecx<- &vCCCC
+ shll $$2, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- offset
+ subl LOCAL0_OFFSET(%ebp), %edx # %edx<- update &outs
+ shrl $$2, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- offset
+1:
+ movl (%ecx), %ebx # %ebx<- vCCCC
+ lea 4(%ecx), %ecx # %ecx<- &vCCCC++
+ subl $$1, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET<- LOCAL0_OFFSET--
+ movl %ebx, (%edx) # *outs<- vCCCC
+ lea 4(%edx), %edx # outs++
+ jne 1b # loop if count (LOCAL0_OFFSET(%ebp)) not zero
+ movl LOCAL1_OFFSET(%ebp), %ebx # %ebx<- restore %ebx
+ jmp .LinvokeArgsDone # continue
+
+ /*
+ * %eax is "Method* methodToCall", the method we're trying to call
+ * prepare to copy args to "outs" area of current frame
+ */
+
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+ movzbl 1(rPC),rINST_FULL # rINST_FULL<- BA
+ SPILL(rPC)
+ movl rINST_FULL, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BA
+ shrl $$4, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- B
+ je .LinvokeArgsDone # no args; jump to args done
+ movzwl 4(rPC), %ecx # %ecx<- GFED
+ SAVEAREA_FROM_FP(%edx,rFP) # %edx<- &StackSaveArea
+
+ /*
+ * %eax=methodToCall, %ecx=GFED, LOCAL0_OFFSET(%ebp)=count, %edx=outs
+ */
+
+.LinvokeNonRange:
+ cmp $$2, LOCAL0_OFFSET(%ebp) # compare LOCAL0_OFFSET(%ebp) to 2
+ movl %ecx, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- GFED
+ jl 1f # handle 1 arg
+ je 2f # handle 2 args
+ cmp $$4, LOCAL0_OFFSET(%ebp) # compare LOCAL0_OFFSET(%ebp) to 4
+ jl 3f # handle 3 args
+ je 4f # handle 4 args
+5:
+ andl $$15, rINST_FULL # rINST<- A
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, rINST_FULL, 4), %ecx # %ecx<- vA
+ movl %ecx, (%edx) # *outs<- vA
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+4:
+ shr $$12, %ecx # %ecx<- G
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vG
+ movl %ecx, (%edx) # *outs<- vG
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+3:
+ and $$0x0f00, %ecx # %ecx<- 0F00
+ shr $$8, %ecx # %ecx<- F
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vF
+ movl %ecx, (%edx) # *outs<- vF
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+2:
+ and $$0x00f0, %ecx # %ecx<- 00E0
+ shr $$4, %ecx # %ecx<- E
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vE
+ movl %ecx, (%edx) # *outs<- vE
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+1:
+ and $$0x000f, %ecx # %ecx<- 000D
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vD
+ movl %ecx, -4(%edx) # *--outs<- vD
+0:
+
+ /*
+ * %eax is "Method* methodToCall", the method we're trying to call
+ * find space for the new stack frame, check for overflow
+ */
+
+.LinvokeArgsDone:
+ movzwl offMethod_registersSize(%eax), %edx # %edx<- methodToCall->regsSize
+ movzwl offMethod_outsSize(%eax), %ecx # %ecx<- methodToCall->outsSize
+ movl %eax, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET<- methodToCall
+ shl $$2, %edx # %edx<- update offset
+ SAVEAREA_FROM_FP(%eax,rFP) # %eax<- &StackSaveArea
+ subl %edx, %eax # %eax<- newFP; (old savearea - regsSize)
+ GET_GLUE(%edx) # %edx<- pMterpGlue
+ movl %eax, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- &outs
+ subl $$sizeofStackSaveArea, %eax # %eax<- newSaveArea (stack save area using newFP)
+ movl offGlue_interpStackEnd(%edx), %edx # %edx<- glue->interpStackEnd
+ movl %edx, LOCAL2_OFFSET(%ebp) # LOCAL2_OFFSET<- glue->interpStackEnd
+ shl $$2, %ecx # %ecx<- update offset for outsSize
+ movl %eax, %edx # %edx<- newSaveArea
+ sub %ecx, %eax # %eax<- bottom; (newSaveArea - outsSize)
+ cmp LOCAL2_OFFSET(%ebp), %eax # compare interpStackEnd and bottom
+ movl LOCAL0_OFFSET(%ebp), %eax # %eax<- restore methodToCall
+ jl .LstackOverflow # handle frame overflow
+
+ /*
+ * set up newSaveArea
+ */
+
+#ifdef EASY_GDB
+ SAVEAREA_FROM_FP(%ecx,rFP) # %ecx<- &StackSaveArea
+ movl %ecx, offStackSaveArea_prevSave(%edx) # newSaveArea->prevSave<- &outs
+#endif
+ movl rFP, offStackSaveArea_prevFrame(%edx) # newSaveArea->prevFrame<- rFP
+ movl rPC_SPILL(%ebp), %ecx
+ movl %ecx, offStackSaveArea_savedPc(%edx) # newSaveArea->savedPc<- rPC
+ testl $$ACC_NATIVE, offMethod_accessFlags(%eax) # check for native call
+ movl %eax, offStackSaveArea_method(%edx) # newSaveArea->method<- method to call
+ jne .LinvokeNative # handle native call
+
+ /*
+ * Update "glue" values for the new method
+ * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFp
+ */
+
+ movl offMethod_clazz(%eax), %edx # %edx<- method->clazz
+ GET_GLUE(%ecx) # %ecx<- pMterpGlue
+ movl offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
+ movl %eax, offGlue_method(%ecx) # glue->method<- methodToCall
+ movl %edx, offGlue_methodClassDex(%ecx) # glue->methodClassDex<- method->clazz->pDvmDex
+ movl offMethod_insns(%eax), rPC # rPC<- methodToCall->insns
+ movl offGlue_self(%ecx), %eax # %eax<- glue->self
+ movl LOCAL1_OFFSET(%ebp), rFP # rFP<- newFP
+ movl rFP, offThread_curFrame(%eax) # glue->self->curFrame<- newFP
+ FETCH_INST()
+ GOTO_NEXT # jump to methodToCall->insns
+
+ /*
+ * Prep for the native call
+ * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFP, %edx=newSaveArea
+ */
+
+.LinvokeNative:
+ GET_GLUE(%ecx) # %ecx<- pMterpGlue
+ movl %eax, OUT_ARG1(%esp) # push parameter methodToCall
+ movl offGlue_self(%ecx), %ecx # %ecx<- glue->self
+ movl offThread_jniLocal_nextEntry(%ecx), %eax # %eax<- glue->self->thread->refNext
+ movl %eax, offStackSaveArea_localRefTop(%edx) # newSaveArea->localRefTop<- refNext
+ movl %edx, OUT_ARG4(%esp) # save newSaveArea
+ movl LOCAL1_OFFSET(%ebp), %edx # %edx<- newFP
+ movl %edx, offThread_curFrame(%ecx) # glue->self->curFrame<- newFP
+ movl %ecx, OUT_ARG3(%esp) # save glue->self
+ movl %ecx, OUT_ARG2(%esp) # push parameter glue->self
+ GET_GLUE(%ecx) # %ecx<- pMterpGlue
+ movl OUT_ARG1(%esp), %eax # %eax<- methodToCall
+ lea offGlue_retval(%ecx), %ecx # %ecx<- &retval
+ movl %ecx, OUT_ARG0(%esp) # push parameter pMterpGlue
+ push %edx # push parameter newFP
+
+ call *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
+ lea 4(%esp), %esp
+ movl OUT_ARG4(%esp), %ecx # %ecx<- newSaveArea
+ movl OUT_ARG3(%esp), %eax # %eax<- glue->self
+ movl offStackSaveArea_localRefTop(%ecx), %edx # %edx<- newSaveArea->localRefTop
+ cmp $$0, offThread_exception(%eax) # check for exception
+ movl rFP, offThread_curFrame(%eax) # glue->self->curFrame<- rFP
+ movl %edx, offThread_jniLocal_nextEntry(%eax) # glue->self<- newSaveArea->localRefTop
+ UNSPILL(rPC)
+ jne common_exceptionThrown # handle exception
+ FETCH_INST_WORD(3)
+ ADVANCE_PC(3)
+ GOTO_NEXT # jump to next instruction
+
+.LstackOverflow:
+ GET_GLUE(%eax) # %eax<- pMterpGlue
+ movl offGlue_self(%eax), %eax # %eax<- glue->self
+ movl %eax, OUT_ARG0(%esp) # push parameter self
+ call dvmHandleStackOverflow # call: (Thread* self)
+ UNSPILL(rPC) # return: void
+ jmp common_exceptionThrown # handle exception
+
+
/*
* Common invoke code (old-style).
* TUNING: Rewrite along lines of new armv5 code?