// ============================================================ // NOTE: We only use this file for GHC < 7.8. // ============================================================ #include "Cmm.h" #warning "Duplicating functionality from the GHC RTS..." #define WHICH_CAS DUP_cas #define WHICH_SLBARRIER DUP_store_load_barrier #define WHICH_LLBARRIER DUP_load_load_barrier #define WHICH_WBARRIER DUP_write_barrier // These versions are linked directly from the RTS: /* #define WHICH_CAS cas */ /* #define WHICH_SLBARRIER store_load_barrier */ /* #define WHICH_LLBARRIER load_load_barrier */ /* #define WHICH_WBARRIER write_barrier */ // ================================================================================ add1Op /* Int# -> Int# */ { W_ num; num = R1 + 1; RET_P(num); } stg_casArrayzh /* MutableArray# s a -> Int# -> a -> a -> State# s -> (# State# s, Int#, a #) */ { W_ arr, p, ind, old, new, h, len; arr = R1; // anything else? ind = R2; old = R3; new = R4; p = arr + SIZEOF_StgMutArrPtrs + WDS(ind); (h) = foreign "C" WHICH_CAS(p, old, new) []; if (h != old) { // Failure, return what was there instead of 'old': RET_NP(1,h); } else { // Compare and Swap Succeeded: SET_HDR(arr, stg_MUT_ARR_PTRS_DIRTY_info, CCCS); len = StgMutArrPtrs_ptrs(arr); // The write barrier. We must write a byte into the mark table: I8[arr + SIZEOF_StgMutArrPtrs + WDS(len) + (ind >> MUT_ARR_PTRS_CARD_BITS )] = 1; RET_NP(0,new); } } stg_casByteArrayIntzh /* MutableByteArray# s -> Int# -> Int# -> Int# -> State# s -> (# State# s, Int# #) */ { W_ arr, p, ind, old, new, h, len; arr = R1; ind = R2; old = R3; new = R4; p = arr + SIZEOF_StgArrWords + WDS(ind); (h) = foreign "C" WHICH_CAS(p, old, new) []; RET_N(h); } stg_fetchAddByteArrayIntzh /* MutableByteArray# s -> Int# -> Int# -> State# s -> (# State# s, Int# #) */ { W_ arr, p, ind, incr, h, len; arr = R1; ind = R2; incr = R3; p = arr + SIZEOF_StgArrWords + WDS(ind); (h) = foreign "C" atomic_inc_with(incr, p) []; RET_N(h); } // One difference from casMutVar# is that this version returns the NEW // pointer in the case of success, NOT the old one. stg_casMutVar2zh /* MutVar# s a -> Word# -> a -> State# s -> (# State#, Int#, a #) */ { W_ mv, old, new, h, addr; // Calling convention: Up to 8 registers contain arguments. mv = R1; old = R2; new = R3; addr = mv + SIZEOF_StgHeader + OFFSET_StgMutVar_var; // The "cas" function from the C runtime abstracts over // platform/architecture differences. It returns the old value. (h) = foreign "C" WHICH_CAS(addr, old, new) []; if (h != old) { // Failure: RET_NP(1, h); } else { // Success means a mutation and thus GC write barrier: if (GET_INFO(mv) == stg_MUT_VAR_CLEAN_info) { foreign "C" dirty_MUT_VAR(BaseReg "ptr", mv "ptr") []; } // Return the NEW value as the ticket for next time. RET_NP(0,new); } } // Takes a single input argument in R1: stg_readMutVar2zh /* MutVar# RealWorld a -> State# RealWorld -> (# State# RealWorld, Word#, a #) */ { W_ mv, res; mv = R1; // Do the actual read: res = W_[mv + SIZEOF_StgHeader + OFFSET_StgMutVar_var]; RET_NP(res, res); } /* emitPrimOp [res] ReadMutVarOp [mutv] _ */ /* = stmtC (CmmAssign (CmmLocal res) (cmmLoadIndexW mutv fixedHdrSize gcWord)) */