📄 ccmglue_cpu.s
字号:
#endif /* Do fastTryLock(): */#define TEMP r0#define EXPECTED_BITS r1#define OBJ r2#define EE r3#define OWNEDREC r12 ; Make sure that the object is not NULL: ldr EE, [sp, #OFFSET_CVMCCExecEnv_ee] cmp OBJ, #0 beq SYM_NAME(CVMCCMruntimeThrowNullPointerExceptionGlue) /* 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 _monenterRecordNotAvailable ; 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 ; } /* Save some values that we need later: NOTE: We don't save EE and EXPECTED_BITS, because EE can always be fetched from the CCEE, and EXPECTED_BITS was already saved in the OWNEDREC. */ str OBJ, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+0] str OWNEDREC, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+4] str lr, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+8] add r0, OBJ, #OFFSET_CVMObjectHeader_various32 mov r1, EXPECTED_BITS mov r2, NEW_BITS CALL_VM_FUNCTION(InterlockedTestExchange) /* Restore the needed values: */ ldr OBJ, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+0] ldr OWNEDREC, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+4] ldr lr, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+8] ldr EXPECTED_BITS, [OWNEDREC, #OFFSET_CVMOwnedMonitor_u_fast_bits] ldr EE, [sp, #OFFSET_CVMCCExecEnv_ee] /* Restore EE. */ cmp ACTUAL_BITS, EXPECTED_BITS /* ACTUAL_BITS is in r0. */ bne _monenterFastFailed /* 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 = lockrec: str OWNEDREC, [EE, #OFFSET_CVMExecEnv_objLocksOwned] mov pc, lr /* Return to the caller */_monenterFastFailed#ifdef CVM_DEBUG /* NOTE: EXPECTED_BITS is no longer needed here. We can't use TEMP because TEMP is r0 which is currently needed to retain the value of ACTUAL_BITS. */#define TEMP2 EXPECTED_BITS ; ownedRec->state = CONSTANT_CVM_OWNEDMON_FREE: mov TEMP2, #0 str TEMP2, [OWNEDREC, #OFFSET_CVMOwnedMonitor_count] mov TEMP2, #CONSTANT_CVM_OWNEDMON_FREE str TEMP2, [OWNEDREC, #OFFSET_CVMOwnedMonitor_state]#undef TEMP2#endif ; If object is not in LOCKED state, then fail: tst ACTUAL_BITS, #0x3 /* check for CVM_LOCKSTATE_LOCKED */ bne _monenterFastRetryFailed ; If not associated with an ownedRec, then fail: bics OWNEDREC, ACTUAL_BITS, #3 beq _monenterFastReentryFailed#undef ACTUAL_BITS ; If (ownedRec->owner != ee), then fail: ldr TEMP, [OWNEDREC, #OFFSET_CVMOwnedMonitor_owner] cmp TEMP, EE bne _monenterFastReentryFailed#define EXPECTED_CNT EXPECTED_BITS#define ACTUAL_CNT r0#define NEW_COUNT r2 ; 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 _monenterFastReentryFailed add NEW_COUNT, EXPECTED_CNT, #1 /* Save some values that we need later: NOTE: We only need OBJ, EXPECTED_CNT, and lr after this call. OBJ and lr was already saved before the first call to InterlockedTestExchange() and is invariant during that call. Hence, we only need to save the EXPECTED_CNT. */ str EXPECTED_CNT, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+4] add r0, OWNEDREC, #OFFSET_CVMOwnedMonitor_count mov r1, EXPECTED_CNT ; r2 already contains NEW_CNT. CALL_VM_FUNCTION(InterlockedTestExchange) /* Restore the needed values: */ ldr OBJ, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+0] ldr EXPECTED_CNT, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+4] ldr lr, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+8] cmp ACTUAL_CNT, EXPECTED_CNT /* ACTUAL_CNT is in r0. */ bne _monenterFastReentryFailed /* Fail if not as expected. */#undef EXPECTED_CNT#undef ACTUAL_CNT#undef NEW_COUNT ; If the old count is as expected, then we're successful: mov pc, lr /* Return to the caller */_monenterFastRetryFailed_monenterFastReentryFailed_monenterRecordNotAvailable /* Let C helper do the hard stuff: */ /* NOTE: It is expected that the OBJ pointer is already in r2. */ CALL_HELPER_AND_PASS_EE(CVMCCMruntimeMonitorEnter)#undef TEMP#undef EXPECTED_BITS#undef OBJ#undef EE#undef OWNEDREC ENTRY_END/* * Entry point for monitorexit. */ ; ; Arguments: ; r2 = a3 = 'obj' ; ; Also incoming: ; r4 = v1 = jfp ; r5 = v2 = jsp ; sp = ccee ; LEAF_ENTRY CVMCCMruntimeMonitorExitGlue#if 0 ; ; If you just want to call the C helper and write very little ; assembler code, then just the following line is needed. ; CALL_HELPER_AND_PASS_EE(CVMCCMruntimeMonitorExit)#endif /* Do fastTryUnlock(): */#define TEMP r0#define EXPECTED_CNT r1#define OBJ r2#define EE r3#define OWNEDREC r12 ; Make sure that the object is not NULL: ldr EE, [sp, #OFFSET_CVMCCExecEnv_ee] cmp OBJ, #0 beq SYM_NAME(CVMCCMruntimeThrowNullPointerExceptionGlue) /* Check to see if the object is locked with a fastlock: */ ldr OWNEDREC, [OBJ, #OFFSET_CVMObjectHeader_various32] /* obits */ tst OWNEDREC, #0x3 /* (obits & 0x3) == CVM_LOCKSTATE_LOCKED? */ bne _monexitFastTryUnlockFailed /* If not, we failed. */ /* If the LOCKREC is NULL, is is currently being inflated */ cmp OWNEDREC, #0 beq _monexitFastTryUnlockFailed /* If we get here, then the object is locked with a fastlock: */ /* Make sure that the current thread owns the monitor: */ ldr TEMP, [OWNEDREC, #OFFSET_CVMOwnedMonitor_owner] cmp TEMP, EE bne _monexitFastTryUnlockFailed /* If not owner, we failed. */ /* If we get here, then the current thread does own the monitor, and all is well. Proceed with unlocking: */ ldr EXPECTED_CNT, [OWNEDREC, #OFFSET_CVMOwnedMonitor_count] cmp EXPECTED_CNT, #CONSTANT_CVM_INVALID_REENTRY_COUNT beq _monexitFastTryUnlockFailed#define ACTUAL_CNT r0#define NEW_COUNT OBJ /* r2 */ str OBJ, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+0] subs NEW_COUNT, EXPECTED_CNT, #1 beq _monexitDoUnlock /* If zero, then unlock */ ; new monitor count > 0, so just update it and we're done: str lr, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+8] add r0, OWNEDREC, #OFFSET_CVMOwnedMonitor_count str EXPECTED_CNT, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+4] ; r1 already has EXPECTED_CNT. ; r2 already has NEW_COUNT. CALL_VM_FUNCTION(InterlockedTestExchange) ldr OBJ, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+0] ldr EXPECTED_CNT, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+4] ldr lr, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+8] cmp ACTUAL_CNT, EXPECTED_CNT /* ACTUAL_CNT is in r0. */ bne _monexitFastTryUnlockFailed /* Go slow way. */#undef ACTUAL_CNT#undef NEW_COUNT ; we're done! monitor count was successfully decrement: mov pc, lr /* return to caller */_monexitDoUnlock#define ACTUAL_BITS r0#define EXPECTED_BITS OWNEDREC#define NEW_BITS r2 /* If we get here, then the re-entry count has reached 0. */ ; Restore the obits to the object header: ldr OBJ, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+0] add r0, OBJ, #OFFSET_CVMObjectHeader_various32 ; NEW_BITS is r2. ldr NEW_BITS, [OWNEDREC, #OFFSET_CVMOwnedMonitor_u_fast_bits] mov r1, EXPECTED_BITS str EXPECTED_BITS, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+4] str lr, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+8] CALL_VM_FUNCTION(InterlockedTestExchange) /* NOTE: EXPECTED_BITS is defined to be OWNEDREC. By restoring EXPECTED_BITS, we're also restoring OWNEDREC. */ ldr OBJ, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+0] ldr EXPECTED_BITS, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+4] ldr lr, [sp, #OFFSET_CVMCCExecEnv_ccmStorage+8] cmp ACTUAL_BITS, EXPECTED_BITS /* ACTUAL_BITS is in r0. */ bne _monexitFastTryUnlockFailed /* Go slow way. */#undef ACTUAL_BITS#undef EXPECTED_BITS#undef NEW_BITS#ifdef CVM_DEBUG ; Make the lockrec play nice with the debug assertions: mov TEMP, #CONSTANT_CVM_OWNEDMON_FREE str TEMP, [OWNEDREC, #OFFSET_CVMOwnedMonitor_state] mov TEMP, #0 str TEMP, [OWNEDREC, #OFFSET_CVMOwnedMonitor_u_fast_bits] str TEMP, [OWNEDREC, #OFFSET_CVMOwnedMonitor_object] str TEMP, [OWNEDREC, #OFFSET_CVMOwnedMonitor_count]#endif ldr EE, [sp, #OFFSET_CVMCCExecEnv_ee] ; Check if the lockrec is the first one on the thread's owned list: ldr TEMP, [EE, #OFFSET_CVMExecEnv_objLocksOwned] cmp TEMP, OWNEDREC bne _monexitFastTryUnlockFindPrevLockRecord ; Remove the lockrec from the ee's owned list: ldr TEMP, [OWNEDREC, #OFFSET_CVMOwnedMonitor_next] str TEMP, [EE, #OFFSET_CVMExecEnv_objLocksOwned]_monexitFastTryUnlockAddLockRecordToFreeList ; Add the lockrec to the ee's free list: ldr TEMP, [EE, #OFFSET_CVMExecEnv_objLocksFreeOwned] str TEMP, [OWNEDREC, #OFFSET_CVMOwnedMonitor_next] str OWNEDREC, [EE, #OFFSET_CVMExecEnv_objLocksFreeOwned] mov pc, lr /* Return to the caller. *//* It is safe to reuse NBITS at this point *//* NOTE: PREV_REC must be defined to be TEMP because it depends on the value that TEMP is set to above (as its initial value) before coming here.*/#define PREV_REC TEMP#define TEMP2 EXPECTED_CNT_monexitFastTryUnlockFindPrevLockRecord ldr TEMP2, [PREV_REC, #OFFSET_CVMOwnedMonitor_next] cmp TEMP2, OWNEDREC beq _monexitFastTryUnlockFoundPrevLockRecord mov PREV_REC, TEMP2 b _monexitFastTryUnlockFindPrevLockRecord_monexitFastTryUnlockFoundPrevLockRecord ; Remove the lockrec from the ee's owned list: ldr TEMP2, [OWNEDREC, #OFFSET_CVMOwnedMonitor_next] str TEMP2, [PREV_REC, #OFFSET_CVMOwnedMonitor_next] b _monexitFastTryUnlockAddLockRecordToFreeList#undef PREV_REC#undef TEMP2_monexitFastTryUnlockFailed /* Let C helper do the hard stuff: */ /* NOTE: It is expected that the OBJ pointer is already in r2. */ CALL_HELPER_AND_PASS_EE(CVMCCMruntimeMonitorExit)#undef TEMP#undef EXPECTED_CNT#undef OBJ#undef EE#undef OWNEDREC ENTRY_END#else#error unsupported CVM_FASTLOCK_TYPE or CVM_MICROLOCK_TYPE#endif POOL
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -