📄 ccminvokers_cpu.s
字号:
; r4 = v1 = jfp ; r5 = v2 = jsp #define NEW_JFP CVMARM_NEWJFP_REGNAME /* r7 = v4 */ /* r0 = ee r1 = obj r4 = v1 = JFP r5 = v2 = JSP r7 = v4 = NEW_JFP *//* TODO: This CVMCCMinvokeNonstaticSyncMethodHelper code has not undergone thorough multi-threaded stress testing yet. It needs to undergo stress testing before release. */#if 0 /* If you just want to call the C helper and write very little assembler code, then just branch to (and implement) letInterpreterDoInvoke. */ b letInterpreterDoInvoke#endif#define EE ORIG_LR /* r10 */#define OBJ r1#define EXPECTED_BITS r8#define OWNEDREC r11#define TEMP ip ldr OBJ, [r1] /* get object to sync on. */ str MB, [NEW_JFP, #OFFSET_CVMFrame_mb] ; save r0 ; optimistically store receiver object str OBJ, [NEW_JFP, #OFFSET_CVMCompiledFrame_receiverObjX] ; now r0 = ee ldr EE, [sp, #OFFSET_CVMCCExecEnv_ee] /* Do fastTryLock(): */ /* Setup a lock record and assume the object has not been locked yet: */ ; ownedRec = ee->objLocksFreeOwned: ldr OWNEDREC, [EE, #OFFSET_CVMExecEnv_objLocksFreeOwned] cmp OWNEDREC, #0 beq _ownedRecordNotAvailable ; ownedRec->object = obj: str OBJ, [OWNEDREC, #OFFSET_CVMOwnedMonitor_object] ; ownedRec->count = 1: mov TEMP, #1 /* Initial lock re-entry count */ str TEMP, [OWNEDREC, #OFFSET_CVMOwnedMonitor_count]#ifdef CVM_DEBUG ; ownedRec->state = CONSTANT_CVM_OWNEDMON_OWNED: mov TEMP, #CONSTANT_CVM_OWNEDMON_OWNED str TEMP, [OWNEDREC, #OFFSET_CVMOwnedMonitor_state]#endif ; NEW_BITS = (OWNEDREC) | CVM_LOCKSTATE_LOCKED: ; Since the value of CVM_LOCKSTATE_LOCKED is 0 by design, this means ; that NEW_BITS is essentially ownedRec. Nothing need to be done to ; initialize NEW_BITS.#define ACTUAL_BITS r0#define NEW_BITS OWNEDREC ; obits = CVMhdrBitsPtr(obj->hdr.various32) | CVM_LOCKSTATE_UNLOCKED: ldr EXPECTED_BITS, [OBJ, #OFFSET_CVMObjectHeader_various32] bic EXPECTED_BITS, EXPECTED_BITS, #3 /* clear rightmost 2 bits */ orr EXPECTED_BITS, EXPECTED_BITS, #CONSTANT_CVM_LOCKSTATE_UNLOCKED ; ownedRec->u.fast.bits = obits: str EXPECTED_BITS, [OWNEDREC, #OFFSET_CVMOwnedMonitor_u_fast_bits] ; Do atomicCompareAndSwap: ; ACTUAL_BITS = [OBJ, #OFFSET_CVMObjectHeader_various32] ; if ([OBJ, #OFFSET_CVMObjectHeader_various32] == EXPECTED_BITS) { ; [OBJ, #OFFSET_CVMObjectHeader_various32] = NEW_BITS ; } add r0, OBJ, #OFFSET_CVMObjectHeader_various32 mov r1, EXPECTED_BITS mov r2, NEW_BITS mov ORIG_LR, lr /* NOTE: ORIG_LR and EE are the same registers. */ CALL_VM_FUNCTION(InterlockedTestExchange) mov lr, ORIG_LR ldr EE, [sp, #OFFSET_CVMCCExecEnv_ee] /* Restore EE. */ cmp ACTUAL_BITS, EXPECTED_BITS /* ACTUAL_BITS is in r0. */ bne _objAlreadyLocked /* already locked */#undef NEW_BITS /* Remove lockrec from the ee's free list: */ ; nextRec = ownedRec->next: ldr TEMP, [OWNEDREC, #OFFSET_CVMOwnedMonitor_next] ; ee->objLocksFreeOwned = nextRec: str TEMP, [EE, #OFFSET_CVMExecEnv_objLocksFreeOwned] /* Add the lockrec to the ee's owned list: */ ; nextRec = ee->objLocksOwned: ldr TEMP, [EE, #OFFSET_CVMExecEnv_objLocksOwned] ; ownedRec->next = nextRec: str TEMP, [OWNEDREC, #OFFSET_CVMOwnedMonitor_next] ; ee->objLocksOwned = ownedRec: str OWNEDREC, [EE, #OFFSET_CVMExecEnv_objLocksOwned] b _fastlockSuccess /* we are all done locking */_objAlreadyLocked#ifdef CVM_DEBUG ; lockrec->state = CONSTANT_CVM_OWNEDMON_FREE: mov TEMP, #0 str TEMP, [OWNEDREC, #OFFSET_CVMOwnedMonitor_count] mov TEMP, #CONSTANT_CVM_OWNEDMON_FREE str TEMP, [OWNEDREC, #OFFSET_CVMOwnedMonitor_state]#endif ; If object is not in LOCKED state, then fail: ands TEMP, ACTUAL_BITS, #0x3 /* check for CVM_LOCKSTATE_LOCKED */ bne _fastRetryFailed ; If not associated with a lock record, then fail: bics OWNEDREC, ACTUAL_BITS, #2 beq _fastReentryFailed /* Make sure ownedRec is not NULL. */#undef ACTUAL_BITS ; If (ownedRec->owner != ee), then fail: ldr TEMP, [OWNEDREC, #OFFSET_CVMOwnedMonitor_owner] cmp TEMP, EE bne _fastReentryFailed#define EXPECTED_CNT EXPECTED_BITS#define NEW_COUNT r2#define ACTUAL_CNT r0 ; If we get here, then we are re-entering the lock: ldr EXPECTED_CNT, [OWNEDREC, #OFFSET_CVMOwnedMonitor_count] cmp EXPECTED_CNT, #CONSTANT_CVM_INVALID_REENTRY_COUNT beq _fastReentryFailed add NEW_COUNT, EXPECTED_CNT, #1 add r0, OWNEDREC, #OFFSET_CVMOwnedMonitor_count mov r1, EXPECTED_CNT ; r2 already contains the NEW_CNT. mov ORIG_LR, lr /* NOTE: ORIG_LR and EE are the same registers. */ CALL_VM_FUNCTION(InterlockedTestExchange) mov lr, ORIG_LR /* NOTE: We don't need EE after this. So, no need to restore it. */ cmp ACTUAL_CNT, EXPECTED_CNT /* ACTUAL_CNT is in r0. */ beq _fastlockSuccess /* Success if as expected. */ /* Else, fall thru to _fastReentryFailed below. */#undef EXPECTED_CNT#undef NEW_COUNT#undef ACTUAL_CNT_fastRetryFailed_fastReentryFailed_ownedRecordNotAvailable /* Let interpreter do the hard stuff: */ ldr MB, [NEW_JFP, #OFFSET_CVMFrame_mb] b letInterpreterDoInvoke_fastlockSuccess ldr MB, [NEW_JFP, #OFFSET_CVMFrame_mb] ; Reload MB. mov PREV, JFP mov JFP, NEW_JFP ; compiled frame#ifdef CVM_DEBUG_ASSERTS mov TEMP, #CONSTANT_CVM_FRAMETYPE_NONE strb TEMP, [JFP, #OFFSET_CVMFrame_type] mov TEMP, #-1 strb TEMP, [JFP, #OFFSET_CVMFrame_flags]#endif str PREV, [JFP, #OFFSET_CVMFrame_prevX] ; set up registers ; see about stack frame requirements.#ifdef CVM_TRACE mov ORIG_LR, lr mov r1, JFP ldr r0, [sp, #OFFSET_CVMCCExecEnv_ee] bl SYM_NAME(CVMCCMtraceMethodCallGlue) mov lr, ORIG_LR#endif#undef EE#undef OBJ#undef EXPECTED_BITS#undef OWNEDREC#undef TEMP ENTRY(CVMARMgcPatchPointAtInvoke) LABEL(CVMARMgcPatchPointAtInvokeLocal) ; GC check - gc will patch at this location when a rendezvous is ; needed. See ccmGcPatchPoints in jitinit_cpu.c. The patch will ; be a "b CVMARMhandleGCAtInvoke" mov pc, lr ; Return to method after handling possible GC request ENTRY(CVMARMhandleGCAtInvoke) ; ; At this point a GC is requested. ; mov ORIG_LR, lr FIXUP_FRAMES_0(JFP) ldr r0, [sp, #OFFSET_CVMCCExecEnv_ee] ; r0 = ee ldr r1, [JFP, #OFFSET_CVMFrame_mb] ; r1 = mb ; We will be gc safe soon. Prevent this method from being decompiled str r1, [r0, #OFFSET_CVMExecEnv_invokeMb] ; Check if this is a synchronized invocation ; If it is, we have to stash the receiver in the ; newly pushed frame into a safe location. The new frame is not ; yet "committed" to the stack, and as such, cannot be located ; by GC. ldrh r1, [r1, #OFFSET_CVMMethodBlock_invokerAndAccessFlagsX] tst r1, #CONSTANT_METHOD_ACC_SYNCHRONIZED ; Synchronized method if result of 'tst' is 'ne'. Stash ; receiver in [ee->miscICell] ldrne r1, [JFP, #OFFSET_CVMCompiledFrame_receiverObjX] ldrne r2, [r0, #OFFSET_CVMExecEnv_miscICell] strne r1, [r2] ; stash in miscICell IMPORT CVMglobals ldr ip, SYMBOL(CVMglobals) ; At this point r0 is guaranteed to contain the ee str PREV,[r0,#OFFSET_CVMExecEnv_interpreterStack+OFFSET_CVMStack_currentFrame] mov r3, #1 add r1, ip, #OFFSET_CVMGlobalState_cstate_GCSAFE add r2, r0, #OFFSET_CVMExecEnv_tcstate_GCSAFE CALL_VM_FUNCTION(CVMcsRendezvous) ; reload the ee and mb ldr r0, [sp, #OFFSET_CVMCCExecEnv_ee] ; r0 = ee ldr r1, [JFP, #OFFSET_CVMFrame_mb] ; r1 = mb ; we no longer need to prevent the method from being decompiled mov ip, #0 str ip, [r0, #OFFSET_CVMExecEnv_invokeMb] mov lr, ORIG_LR ; ; We've returned from the GC. Check for a sync method ; again to see if we should restore 'receiverObjX' ; from miscICell. ; ldrh r2, [r1, #OFFSET_CVMMethodBlock_invokerAndAccessFlagsX] tst r2, #CONSTANT_METHOD_ACC_SYNCHRONIZED beq CVMARMgcPatchPointAtInvokeLocal ; Restore receiverObjX in new frame ldr r0, [r0, #OFFSET_CVMExecEnv_miscICell] ; r0 = &miscICell ldr ip, [r0] str ip, [JFP, #OFFSET_CVMCompiledFrame_receiverObjX] ; And clear miscICell for other uses mov ip, #0 str ip, [r0] ; reload the ee. The frame flush needs it at the return point ldr r0, [sp, #OFFSET_CVMCCExecEnv_ee] ; r0 = ee b CVMARMgcPatchPointAtInvokeLocal SET_SIZE( CVMCCMinvokeNonstaticSyncMethodHelper )#undef ORIG_LR#else#error unsupported CVM_FASTLOCK_TYPE or CVM_MICROLOCK_TYPE#endif ENTRY(CVMCCMinvokeStaticSyncMethodHelper)ENTRY1( CVMCCMinvokeStaticSyncMethodHelper ) /* r0 = a1 = target mb * r4 = v1 = jfp * r5 = v2 = jsp */#ifdef CVM_METHODBLOCK_HAS_CB ldr r1, [MB, #OFFSET_CVMMethodBlock_cbX]#else#if CONSTANT_CVMMethodBlock_size != 28#error Wrong CVMMethodBlock size#endif#ifdef OFFSET_CVMMethodBlock_cbX#error OFFSET_CVMMethodBlock_cbX defined but not CVM_METHODBLOCK_HAS_CB#endif ldrb r1, [MB, #OFFSET_CVMMethodBlock_methodIndexX] /* r1 = MB - r1*32 + r1*4 * which means * r1 = MB - r1*28 */ sub ip, MB, r1, asl #5 add r1, ip, r1, asl #2 ldr r1, [r1, #-OFFSET_CVMMethodRange_mb]#endif /* r1 needs to be set to the icell of the object to lock */ ldr r1, [r1, #OFFSET_CVMClassBlock_javaInstanceX] b CVMCCMinvokeNonstaticSyncMethodHelperLocal SET_SIZE( CVMCCMinvokeStaticSyncMethodHelper ) ENTRY(CVMCCMinvokeCNIMethod)ENTRY1( CVMCCMinvokeCNIMethod ) /* r4 = v1 = jfp * r5 = v2 = jsp * r0 = target mb */ ldrb r1, [MB,#OFFSET_CVMMethodBlock_argsSizeX] str lr, [JFP, #OFFSET_CVMCompiledFrame_PC] sub r1, JSP, r1, LSL #2 /* TOS */#undef MB#define MB r6 /* v3 */#define ARGS r7 /* v4 */ mov MB, r0 /* save MB */ mov ARGS, r1 /* save args ptr */ /* although r1 is now in ARGS, we still want to preserve it */ FIXUP_FRAMES(JFP, {r1}, 1) ldr r0, [sp, #OFFSET_CVMCCExecEnv_ee] str JSP,[JFP,#OFFSET_CVMFrame_topOfStack] str JFP,[r0 ,#OFFSET_CVMExecEnv_interpreterStack+OFFSET_CVMStack_currentFrame] #ifdef CVM_TRACE /* trace call */ mov r1, JFP mov r2, MB /* r2 = mb */ bl SYM_NAME(CCMtraceFramelessMethodCall) ldr r0, [sp, #OFFSET_CVMCCExecEnv_ee] /* r0 = ee */ mov r1, ARGS /* restore args ptr */#endif /* invoke the method - r1 is still the args pointer */ add r2, sp, #OFFSET_CVMCCExecEnv_ccmStorage /* r2 = mbPtr */ str MB, [r2] /* store MB into mbPtr */ mov lr, pc ldr pc, [MB, #OFFSET_CVMMethodBlock_codeX]#ifdef CVM_TRACE /* trace return */ str r0, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+4] /* save result */ mov r1, MB /* r1 = mb */ mov r2, JFP ldr r0, [sp, #OFFSET_CVMCCExecEnv_ee] /* r0 = ee */ bl SYM_NAME(CCMtraceFramelessMethodReturn) ldr r0, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+4] /* restore result */#endif /* if r0 >= 0, then r0 is the size in words of the method result */ cmp r0, #0 addge JSP, ARGS, r0, LSL #2 /* pop args and adjust for result */ ldrge pc, [JFP, #OFFSET_CVMCompiledFrame_PC] /* check if a new mb to execute has been returned */ cmp r0, #CONSTANT_CNI_NEW_MB bne new_transition ldr r0, [sp, #OFFSET_CVMCCExecEnv_ccmStorage] /* r0 = newMb */ /* adjust TOS. The new method may have fewer args than the CNI method */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -