summaryrefslogtreecommitdiff
path: root/rts/PrimOps.cmm
diff options
context:
space:
mode:
Diffstat (limited to 'rts/PrimOps.cmm')
-rw-r--r--rts/PrimOps.cmm399
1 files changed, 191 insertions, 208 deletions
diff --git a/rts/PrimOps.cmm b/rts/PrimOps.cmm
index 3d4bea433d..a5d8553e94 100644
--- a/rts/PrimOps.cmm
+++ b/rts/PrimOps.cmm
@@ -30,6 +30,7 @@ import pthread_mutex_lock;
import pthread_mutex_unlock;
#endif
import CLOSURE base_ControlziExceptionziBase_nestedAtomically_closure;
+import CLOSURE base_GHCziIOziException_heapOverflow_closure;
import EnterCriticalSection;
import LeaveCriticalSection;
import CLOSURE ghczmprim_GHCziTypes_False_closure;
@@ -62,7 +63,10 @@ stg_newByteArrayzh ( W_ n )
payload_words = ROUNDUP_BYTES_TO_WDS(n);
words = BYTES_TO_WDS(SIZEOF_StgArrBytes) + payload_words;
- ("ptr" p) = ccall allocate(MyCapability() "ptr",words);
+ ("ptr" p) = ccall allocateMightFail(MyCapability() "ptr", words);
+ if (p == NULL) {
+ jump stg_raisezh(base_GHCziIOziException_heapOverflow_closure);
+ }
TICK_ALLOC_PRIM(SIZEOF_StgArrBytes,WDS(payload_words),0);
SET_HDR(p, stg_ARR_WORDS_info, CCCS);
StgArrBytes_bytes(p) = n;
@@ -92,6 +96,9 @@ stg_newPinnedByteArrayzh ( W_ n )
words = ROUNDUP_BYTES_TO_WDS(bytes);
("ptr" p) = ccall allocatePinned(MyCapability() "ptr", words);
+ if (p == NULL) {
+ jump stg_raisezh(base_GHCziIOziException_heapOverflow_closure);
+ }
TICK_ALLOC_PRIM(SIZEOF_StgArrBytes,WDS(payload_words),0);
/* Now we need to move p forward so that the payload is aligned
@@ -130,6 +137,9 @@ stg_newAlignedPinnedByteArrayzh ( W_ n, W_ alignment )
words = ROUNDUP_BYTES_TO_WDS(bytes);
("ptr" p) = ccall allocatePinned(MyCapability() "ptr", words);
+ if (p == NULL) {
+ jump stg_raisezh(base_GHCziIOziException_heapOverflow_closure);
+ }
TICK_ALLOC_PRIM(SIZEOF_StgArrBytes,WDS(payload_words),0);
/* Now we need to move p forward so that the payload is aligned
@@ -150,8 +160,9 @@ stg_isByteArrayPinnedzh ( gcptr ba )
// Pinned byte arrays live in blocks with the BF_PINNED flag set.
// We also consider BF_LARGE objects to be immovable. See #13894.
// See the comment in Storage.c:allocatePinned.
+ // We also consider BF_COMPACT objects to be immovable. See #14900.
flags = TO_W_(bdescr_flags(bd));
- return (flags & (BF_PINNED | BF_LARGE) != 0);
+ return (flags & (BF_PINNED | BF_LARGE | BF_COMPACT) != 0);
}
stg_isMutableByteArrayPinnedzh ( gcptr mba )
@@ -240,17 +251,20 @@ stg_newArrayzh ( W_ n /* words */, gcptr init )
// number of words.
size = n + mutArrPtrsCardWords(n);
words = BYTES_TO_WDS(SIZEOF_StgMutArrPtrs) + size;
- ("ptr" arr) = ccall allocate(MyCapability() "ptr",words);
+ ("ptr" arr) = ccall allocateMightFail(MyCapability() "ptr",words);
+ if (arr == NULL) {
+ jump stg_raisezh(base_GHCziIOziException_heapOverflow_closure);
+ }
TICK_ALLOC_PRIM(SIZEOF_StgMutArrPtrs, WDS(size), 0);
SET_HDR(arr, stg_MUT_ARR_PTRS_DIRTY_info, CCCS);
StgMutArrPtrs_ptrs(arr) = n;
StgMutArrPtrs_size(arr) = size;
- // Initialise all elements of the the array with the value in R2
+ // Initialise all elements of the array with the value in R2
p = arr + SIZEOF_StgMutArrPtrs;
for:
- if (p < arr + SIZEOF_StgMutArrPtrs + WDS(n)) {
+ if (p < arr + SIZEOF_StgMutArrPtrs + WDS(n)) (likely: True) {
W_[p] = init;
p = p + WDS(1);
goto for;
@@ -261,28 +275,15 @@ stg_newArrayzh ( W_ n /* words */, gcptr init )
stg_unsafeThawArrayzh ( gcptr arr )
{
- // SUBTLETY TO DO WITH THE OLD GEN MUTABLE LIST
- //
- // A MUT_ARR_PTRS lives on the mutable list, but a MUT_ARR_PTRS_FROZEN
- // normally doesn't. However, when we freeze a MUT_ARR_PTRS, we leave
- // it on the mutable list for the GC to remove (removing something from
- // the mutable list is not easy).
- //
- // So that we can tell whether a MUT_ARR_PTRS_FROZEN is on the mutable list,
- // when we freeze it we set the info ptr to be MUT_ARR_PTRS_FROZEN0
- // to indicate that it is still on the mutable list.
- //
- // So, when we thaw a MUT_ARR_PTRS_FROZEN, we must cope with two cases:
- // either it is on a mut_list, or it isn't. We adopt the convention that
- // the closure type is MUT_ARR_PTRS_FROZEN0 if it is on the mutable list,
- // and MUT_ARR_PTRS_FROZEN otherwise. In fact it wouldn't matter if
- // we put it on the mutable list more than once, but it would get scavenged
- // multiple times during GC, which would be unnecessarily slow.
- //
- if (StgHeader_info(arr) != stg_MUT_ARR_PTRS_FROZEN0_info) {
+ // A MUT_ARR_PTRS always lives on a mut_list, but a MUT_ARR_PTRS_FROZEN
+ // doesn't. To decide whether to add the thawed array to a mut_list we check
+ // the info table. MUT_ARR_PTRS_FROZEN_DIRTY means it's already on a
+ // mut_list so no need to add it again. MUT_ARR_PTRS_FROZEN_CLEAN means it's
+ // not and we should add it to a mut_list.
+ if (StgHeader_info(arr) != stg_MUT_ARR_PTRS_FROZEN_DIRTY_info) {
SET_INFO(arr,stg_MUT_ARR_PTRS_DIRTY_info);
+ // must be done after SET_INFO, because it ASSERTs closure_MUTABLE():
recordMutable(arr);
- // must be done after SET_INFO, because it ASSERTs closure_MUTABLE()
return (arr);
} else {
SET_INFO(arr,stg_MUT_ARR_PTRS_DIRTY_info);
@@ -312,7 +313,7 @@ stg_copyMutableArrayArrayzh ( gcptr src, W_ src_off, gcptr dst, W_ dst_off, W_ n
stg_cloneArrayzh ( gcptr src, W_ offset, W_ n )
{
- cloneArray(stg_MUT_ARR_PTRS_FROZEN_info, src, offset, n)
+ cloneArray(stg_MUT_ARR_PTRS_FROZEN_CLEAN_info, src, offset, n)
}
stg_cloneMutableArrayzh ( gcptr src, W_ offset, W_ n )
@@ -323,7 +324,7 @@ stg_cloneMutableArrayzh ( gcptr src, W_ offset, W_ n )
// We have to escape the "z" in the name.
stg_freezzeArrayzh ( gcptr src, W_ offset, W_ n )
{
- cloneArray(stg_MUT_ARR_PTRS_FROZEN_info, src, offset, n)
+ cloneArray(stg_MUT_ARR_PTRS_FROZEN_CLEAN_info, src, offset, n)
}
stg_thawArrayzh ( gcptr src, W_ offset, W_ n )
@@ -366,7 +367,10 @@ stg_newArrayArrayzh ( W_ n /* words */ )
// number of words.
size = n + mutArrPtrsCardWords(n);
words = BYTES_TO_WDS(SIZEOF_StgMutArrPtrs) + size;
- ("ptr" arr) = ccall allocate(MyCapability() "ptr",words);
+ ("ptr" arr) = ccall allocateMightFail(MyCapability() "ptr",words);
+ if (arr == NULL) {
+ jump stg_raisezh(base_GHCziIOziException_heapOverflow_closure);
+ }
TICK_ALLOC_PRIM(SIZEOF_StgMutArrPtrs, WDS(size), 0);
SET_HDR(arr, stg_MUT_ARR_PTRS_DIRTY_info, W_[CCCS]);
@@ -376,7 +380,7 @@ stg_newArrayArrayzh ( W_ n /* words */ )
// Initialise all elements of the array with a pointer to the new array
p = arr + SIZEOF_StgMutArrPtrs;
for:
- if (p < arr + SIZEOF_StgMutArrPtrs + WDS(n)) {
+ if (p < arr + SIZEOF_StgMutArrPtrs + WDS(n)) (likely: True) {
W_[p] = arr;
p = p + WDS(1);
goto for;
@@ -398,16 +402,19 @@ stg_newSmallArrayzh ( W_ n /* words */, gcptr init )
again: MAYBE_GC(again);
words = BYTES_TO_WDS(SIZEOF_StgSmallMutArrPtrs) + n;
- ("ptr" arr) = ccall allocate(MyCapability() "ptr",words);
+ ("ptr" arr) = ccall allocateMightFail(MyCapability() "ptr",words);
+ if (arr == NULL) {
+ jump stg_raisezh(base_GHCziIOziException_heapOverflow_closure);
+ }
TICK_ALLOC_PRIM(SIZEOF_StgSmallMutArrPtrs, WDS(n), 0);
SET_HDR(arr, stg_SMALL_MUT_ARR_PTRS_DIRTY_info, CCCS);
StgSmallMutArrPtrs_ptrs(arr) = n;
- // Initialise all elements of the the array with the value in R2
+ // Initialise all elements of the array with the value in R2
p = arr + SIZEOF_StgSmallMutArrPtrs;
for:
- if (p < arr + SIZEOF_StgSmallMutArrPtrs + WDS(n)) {
+ if (p < arr + SIZEOF_StgSmallMutArrPtrs + WDS(n)) (likely: True) {
W_[p] = init;
p = p + WDS(1);
goto for;
@@ -419,7 +426,7 @@ stg_newSmallArrayzh ( W_ n /* words */, gcptr init )
stg_unsafeThawSmallArrayzh ( gcptr arr )
{
// See stg_unsafeThawArrayzh
- if (StgHeader_info(arr) != stg_SMALL_MUT_ARR_PTRS_FROZEN0_info) {
+ if (StgHeader_info(arr) != stg_SMALL_MUT_ARR_PTRS_FROZEN_DIRTY_info) {
SET_INFO(arr, stg_SMALL_MUT_ARR_PTRS_DIRTY_info);
recordMutable(arr);
// must be done after SET_INFO, because it ASSERTs closure_MUTABLE()
@@ -432,7 +439,7 @@ stg_unsafeThawSmallArrayzh ( gcptr arr )
stg_cloneSmallArrayzh ( gcptr src, W_ offset, W_ n )
{
- cloneSmallArray(stg_SMALL_MUT_ARR_PTRS_FROZEN_info, src, offset, n)
+ cloneSmallArray(stg_SMALL_MUT_ARR_PTRS_FROZEN_CLEAN_info, src, offset, n)
}
stg_cloneSmallMutableArrayzh ( gcptr src, W_ offset, W_ n )
@@ -443,7 +450,7 @@ stg_cloneSmallMutableArrayzh ( gcptr src, W_ offset, W_ n )
// We have to escape the "z" in the name.
stg_freezzeSmallArrayzh ( gcptr src, W_ offset, W_ n )
{
- cloneSmallArray(stg_SMALL_MUT_ARR_PTRS_FROZEN_info, src, offset, n)
+ cloneSmallArray(stg_SMALL_MUT_ARR_PTRS_FROZEN_CLEAN_info, src, offset, n)
}
stg_thawSmallArrayzh ( gcptr src, W_ offset, W_ n )
@@ -557,9 +564,9 @@ stg_casMutVarzh ( gcptr mv, gcptr old, gcptr new )
#endif
}
-stg_atomicModifyMutVarzh ( gcptr mv, gcptr f )
+stg_atomicModifyMutVar2zh ( gcptr mv, gcptr f )
{
- W_ z, x, y, r, h;
+ W_ z, x, y, h;
/* If x is the current contents of the MutVar#, then
We want to make the new contents point to
@@ -568,13 +575,12 @@ stg_atomicModifyMutVarzh ( gcptr mv, gcptr f )
and the return value is
- (sel_1 (f x))
+ (# x, (f x) #)
obviously we can share (f x).
z = [stg_ap_2 f x] (max (HS + 2) MIN_UPD_SIZE)
y = [stg_sel_0 z] (max (HS + 1) MIN_UPD_SIZE)
- r = [stg_sel_1 z] (max (HS + 1) MIN_UPD_SIZE)
*/
#if defined(MIN_UPD_SIZE) && MIN_UPD_SIZE > 1
@@ -593,7 +599,7 @@ stg_atomicModifyMutVarzh ( gcptr mv, gcptr f )
#define TICK_ALLOC_THUNK_2() TICK_ALLOC_UP_THK(WDS(2),0)
#endif
-#define SIZE (THUNK_2_SIZE + THUNK_1_SIZE + THUNK_1_SIZE)
+#define SIZE (THUNK_2_SIZE + THUNK_1_SIZE)
HP_CHK_GEN_TICKY(SIZE);
@@ -611,13 +617,6 @@ stg_atomicModifyMutVarzh ( gcptr mv, gcptr f )
LDV_RECORD_CREATE(y);
StgThunk_payload(y,0) = z;
- TICK_ALLOC_THUNK_1();
- CCCS_ALLOC(THUNK_1_SIZE);
- r = y - THUNK_1_SIZE;
- SET_HDR(r, stg_sel_1_upd_info, CCCS);
- LDV_RECORD_CREATE(r);
- StgThunk_payload(r,0) = z;
-
retry:
x = StgMutVar_var(mv);
StgThunk_payload(z,1) = x;
@@ -632,15 +631,66 @@ stg_atomicModifyMutVarzh ( gcptr mv, gcptr f )
ccall dirty_MUT_VAR(BaseReg "ptr", mv "ptr");
}
- return (r);
+ return (x,z);
+}
+
+stg_atomicModifyMutVarzuzh ( gcptr mv, gcptr f )
+{
+ W_ z, x, h;
+
+ /* If x is the current contents of the MutVar#, then
+ We want to make the new contents point to
+
+ (f x)
+
+ and the return value is
+
+ (# x, (f x) #)
+
+ obviously we can share (f x).
+
+ z = [stg_ap_2 f x] (max (HS + 2) MIN_UPD_SIZE)
+ */
+
+#if defined(MIN_UPD_SIZE) && MIN_UPD_SIZE > 2
+#define THUNK_SIZE (SIZEOF_StgThunkHeader + WDS(MIN_UPD_SIZE))
+#define TICK_ALLOC_THUNK() TICK_ALLOC_UP_THK(WDS(2),WDS(MIN_UPD_SIZE-2))
+#else
+#define THUNK_SIZE (SIZEOF_StgThunkHeader + WDS(2))
+#define TICK_ALLOC_THUNK() TICK_ALLOC_UP_THK(WDS(2),0)
+#endif
+
+ HP_CHK_GEN_TICKY(THUNK_SIZE);
+
+ TICK_ALLOC_THUNK();
+ CCCS_ALLOC(THUNK_SIZE);
+ z = Hp - THUNK_SIZE + WDS(1);
+ SET_HDR(z, stg_ap_2_upd_info, CCCS);
+ LDV_RECORD_CREATE(z);
+ StgThunk_payload(z,0) = f;
+
+ retry:
+ x = StgMutVar_var(mv);
+ StgThunk_payload(z,1) = x;
+#if defined(THREADED_RTS)
+ (h) = prim %cmpxchgW(mv + SIZEOF_StgHeader + OFFSET_StgMutVar_var, x, z);
+ if (h != x) { goto retry; }
+#else
+ StgMutVar_var(mv) = z;
+#endif
+
+ if (GET_INFO(mv) == stg_MUT_VAR_CLEAN_info) {
+ ccall dirty_MUT_VAR(BaseReg "ptr", mv "ptr");
+ }
+
+ return (x,z);
}
+
/* -----------------------------------------------------------------------------
Weak Pointer Primitives
-------------------------------------------------------------------------- */
-STRING(stg_weak_msg,"New weak pointer at %p\n")
-
stg_mkWeakzh ( gcptr key,
gcptr value,
gcptr finalizer /* or stg_NO_FINALIZER_closure */ )
@@ -663,7 +713,7 @@ stg_mkWeakzh ( gcptr key,
Capability_weak_ptr_list_tl(MyCapability()) = w;
}
- IF_DEBUG(weak, ccall debugBelch(stg_weak_msg,w));
+ IF_DEBUG(weak, ccall debugBelch("New weak pointer at %p\n",w));
return (w);
}
@@ -673,8 +723,6 @@ stg_mkWeakNoFinalizzerzh ( gcptr key, gcptr value )
jump stg_mkWeakzh (key, value, stg_NO_FINALIZER_closure);
}
-STRING(stg_cfinalizer_msg,"Adding a finalizer to %p\n")
-
stg_addCFinalizzerToWeakzh ( W_ fptr, // finalizer
W_ ptr,
W_ flag, // has environment (0 or 1)
@@ -708,7 +756,7 @@ stg_addCFinalizzerToWeakzh ( W_ fptr, // finalizer
recordMutable(w);
- IF_DEBUG(weak, ccall debugBelch(stg_cfinalizer_msg,w));
+ IF_DEBUG(weak, ccall debugBelch("Adding a finalizer to %p\n",w));
return (1);
}
@@ -924,11 +972,6 @@ stg_yieldzh ()
jump stg_yield_noregs();
}
-stg_myThreadIdzh ()
-{
- return (CurrentTSO);
-}
-
stg_labelThreadzh ( gcptr threadid, W_ addr )
{
#if defined(DEBUG) || defined(TRACING) || defined(DTRACE)
@@ -1004,6 +1047,7 @@ INFO_TABLE_RET(stg_catch_retry_frame, CATCH_RETRY_FRAME,
alt_code))
return (P_ ret)
{
+ unwind Sp = Sp + SIZEOF_StgCatchRetryFrame;
W_ r;
gcptr trec, outer, arg;
@@ -1041,11 +1085,10 @@ INFO_TABLE_RET(stg_catch_retry_frame, CATCH_RETRY_FRAME,
// Atomically frame ------------------------------------------------------------
// This must match StgAtomicallyFrame in Closures.h
-#define ATOMICALLY_FRAME_FIELDS(w_,p_,info_ptr,p1,p2,code,next,result) \
+#define ATOMICALLY_FRAME_FIELDS(w_,p_,info_ptr,p1,p2,code,result) \
w_ info_ptr, \
PROF_HDR_FIELDS(w_,p1,p2) \
p_ code, \
- p_ next, \
p_ result
@@ -1054,67 +1097,36 @@ INFO_TABLE_RET(stg_atomically_frame, ATOMICALLY_FRAME,
ATOMICALLY_FRAME_FIELDS(W_,P_,
info_ptr, p1, p2,
code,
- next_invariant,
frame_result))
return (P_ result) // value returned to the frame
{
W_ valid;
- gcptr trec, outer, next_invariant, q;
+ gcptr trec, outer, q;
trec = StgTSO_trec(CurrentTSO);
outer = StgTRecHeader_enclosing_trec(trec);
- if (outer == NO_TREC) {
- /* First time back at the atomically frame -- pick up invariants */
- ("ptr" next_invariant) =
- ccall stmGetInvariantsToCheck(MyCapability() "ptr", trec "ptr");
- frame_result = result;
+ /* Back at the atomically frame */
+ frame_result = result;
+ /* try to commit */
+ (valid) = ccall stmCommitTransaction(MyCapability() "ptr", trec "ptr");
+ if (valid != 0) {
+ /* Transaction was valid: commit succeeded */
+ StgTSO_trec(CurrentTSO) = NO_TREC;
+ return (frame_result);
} else {
- /* Second/subsequent time back at the atomically frame -- abort the
- * tx that's checking the invariant and move on to the next one */
- StgTSO_trec(CurrentTSO) = outer;
- StgInvariantCheckQueue_my_execution(next_invariant) = trec;
- ccall stmAbortTransaction(MyCapability() "ptr", trec "ptr");
- /* Don't free trec -- it's linked from q and will be stashed in the
- * invariant if we eventually commit. */
- next_invariant =
- StgInvariantCheckQueue_next_queue_entry(next_invariant);
- trec = outer;
- }
-
- if (next_invariant != END_INVARIANT_CHECK_QUEUE) {
- /* We can't commit yet: another invariant to check */
- ("ptr" trec) = ccall stmStartTransaction(MyCapability() "ptr", trec "ptr");
+ /* Transaction was not valid: try again */
+ ("ptr" trec) = ccall stmStartTransaction(MyCapability() "ptr",
+ NO_TREC "ptr");
StgTSO_trec(CurrentTSO) = trec;
- q = StgInvariantCheckQueue_invariant(next_invariant);
+
jump stg_ap_v_fast
+ // push the StgAtomicallyFrame again: the code generator is
+ // clever enough to only assign the fields that have changed.
(ATOMICALLY_FRAME_FIELDS(,,info_ptr,p1,p2,
- code,next_invariant,frame_result))
- (StgAtomicInvariant_code(q));
-
- } else {
-
- /* We've got no more invariants to check, try to commit */
- (valid) = ccall stmCommitTransaction(MyCapability() "ptr", trec "ptr");
- if (valid != 0) {
- /* Transaction was valid: commit succeeded */
- StgTSO_trec(CurrentTSO) = NO_TREC;
- return (frame_result);
- } else {
- /* Transaction was not valid: try again */
- ("ptr" trec) = ccall stmStartTransaction(MyCapability() "ptr",
- NO_TREC "ptr");
- StgTSO_trec(CurrentTSO) = trec;
- next_invariant = END_INVARIANT_CHECK_QUEUE;
-
- jump stg_ap_v_fast
- // push the StgAtomicallyFrame again: the code generator is
- // clever enough to only assign the fields that have changed.
- (ATOMICALLY_FRAME_FIELDS(,,info_ptr,p1,p2,
- code,next_invariant,frame_result))
- (code);
- }
+ code,frame_result))
+ (code);
}
}
@@ -1124,7 +1136,6 @@ INFO_TABLE_RET(stg_atomically_waiting_frame, ATOMICALLY_FRAME,
ATOMICALLY_FRAME_FIELDS(W_,P_,
info_ptr, p1, p2,
code,
- next_invariant,
frame_result))
return (/* no return values */)
{
@@ -1136,7 +1147,7 @@ INFO_TABLE_RET(stg_atomically_waiting_frame, ATOMICALLY_FRAME,
/* Previous attempt is still valid: no point trying again yet */
jump stg_block_noregs
(ATOMICALLY_FRAME_FIELDS(,,info_ptr, p1, p2,
- code,next_invariant,frame_result))
+ code,frame_result))
();
} else {
/* Previous attempt is no longer valid: try again */
@@ -1146,7 +1157,7 @@ INFO_TABLE_RET(stg_atomically_waiting_frame, ATOMICALLY_FRAME,
// change the frame header to stg_atomically_frame_info
jump stg_ap_v_fast
(ATOMICALLY_FRAME_FIELDS(,,stg_atomically_frame_info, p1, p2,
- code,next_invariant,frame_result))
+ code,frame_result))
(code);
}
}
@@ -1197,7 +1208,7 @@ stg_atomicallyzh (P_ stm)
{
P_ old_trec;
P_ new_trec;
- P_ code, next_invariant, frame_result;
+ P_ code, frame_result;
// stmStartTransaction may allocate
MAYBE_GC_P(stg_atomicallyzh, stm);
@@ -1212,7 +1223,6 @@ stg_atomicallyzh (P_ stm)
}
code = stm;
- next_invariant = END_INVARIANT_CHECK_QUEUE;
frame_result = NO_TREC;
/* Start the memory transcation */
@@ -1221,7 +1231,7 @@ stg_atomicallyzh (P_ stm)
jump stg_ap_v_fast
(ATOMICALLY_FRAME_FIELDS(,,stg_atomically_frame_info, CCCS, 0,
- code,next_invariant,frame_result))
+ code,frame_result))
(stm);
}
@@ -1324,16 +1334,6 @@ retry_pop_stack:
// We've reached the ATOMICALLY_FRAME: attempt to wait
ASSERT(frame_type == ATOMICALLY_FRAME);
- if (outer != NO_TREC) {
- // We called retry while checking invariants, so abort the current
- // invariant check (merging its TVar accesses into the parents read
- // set so we'll wait on them)
- ccall stmAbortTransaction(MyCapability() "ptr", trec "ptr");
- ccall stmFreeAbortedTRec(MyCapability() "ptr", trec "ptr");
- trec = outer;
- StgTSO_trec(CurrentTSO) = trec;
- outer = StgTRecHeader_enclosing_trec(trec);
- }
ASSERT(outer == NO_TREC);
(r) = ccall stmWait(MyCapability() "ptr", CurrentTSO "ptr", trec "ptr");
@@ -1353,20 +1353,6 @@ retry_pop_stack:
}
}
-stg_checkzh (P_ closure /* STM a */)
-{
- W_ trec;
-
- MAYBE_GC_P (stg_checkzh, closure);
-
- trec = StgTSO_trec(CurrentTSO);
- ccall stmAddInvariantToCheck(MyCapability() "ptr",
- trec "ptr",
- closure "ptr");
- return ();
-}
-
-
stg_newTVarzh (P_ init)
{
W_ tv;
@@ -1741,7 +1727,7 @@ loop:
ccall tryWakeupThread(MyCapability() "ptr", tso);
- // If it was an readMVar, then we can still do work,
+ // If it was a readMVar, then we can still do work,
// so loop back. (XXX: This could take a while)
if (why_blocked == BlockedOnMVarRead) {
q = StgMVarTSOQueue_link(q);
@@ -1822,7 +1808,7 @@ loop:
ccall tryWakeupThread(MyCapability() "ptr", tso);
- // If it was an readMVar, then we can still do work,
+ // If it was a readMVar, then we can still do work,
// so loop back. (XXX: This could take a while)
if (why_blocked == BlockedOnMVarRead) {
q = StgMVarTSOQueue_link(q);
@@ -2004,70 +1990,44 @@ stg_mkApUpd0zh ( P_ bco )
stg_unpackClosurezh ( P_ closure )
{
- W_ clos, info, ptrs, nptrs, p, ptrs_arr, nptrs_arr;
- clos = UNTAG(closure);
- info = %GET_STD_INFO(clos);
-
- // Some closures have non-standard layout, so we omit those here.
- W_ type;
- type = TO_W_(%INFO_TYPE(info));
- switch [0 .. N_CLOSURE_TYPES] type {
- case THUNK_SELECTOR : {
- ptrs = 1;
- nptrs = 0;
- goto out;
- }
- case THUNK, THUNK_1_0, THUNK_0_1, THUNK_2_0, THUNK_1_1,
- THUNK_0_2, THUNK_STATIC, AP, PAP, AP_STACK, BCO : {
- ptrs = 0;
- nptrs = 0;
- goto out;
- }
- default: {
- ptrs = TO_W_(%INFO_PTRS(info));
- nptrs = TO_W_(%INFO_NPTRS(info));
- goto out;
- }}
-
-out:
- W_ ptrs_arr_sz, ptrs_arr_cards, nptrs_arr_sz;
- nptrs_arr_sz = SIZEOF_StgArrBytes + WDS(nptrs);
- ptrs_arr_cards = mutArrPtrsCardWords(ptrs);
- ptrs_arr_sz = SIZEOF_StgMutArrPtrs + WDS(ptrs) + WDS(ptrs_arr_cards);
-
- ALLOC_PRIM_P (ptrs_arr_sz + nptrs_arr_sz, stg_unpackClosurezh, closure);
-
- ptrs_arr = Hp - nptrs_arr_sz - ptrs_arr_sz + WDS(1);
- nptrs_arr = Hp - nptrs_arr_sz + WDS(1);
-
- SET_HDR(ptrs_arr, stg_MUT_ARR_PTRS_FROZEN_info, CCCS);
- StgMutArrPtrs_ptrs(ptrs_arr) = ptrs;
- StgMutArrPtrs_size(ptrs_arr) = ptrs + ptrs_arr_cards;
+ W_ info, ptrs, nptrs, p, ptrs_arr, dat_arr;
+ info = %GET_STD_INFO(UNTAG(closure));
- p = 0;
+ ptrs = TO_W_(%INFO_PTRS(info));
+ nptrs = TO_W_(%INFO_NPTRS(info));
-write_ptrs:
- if(p < ptrs) {
- W_[ptrs_arr + SIZEOF_StgMutArrPtrs + WDS(p)] = StgClosure_payload(clos,p);
- p = p + 1;
- goto write_ptrs;
- }
- /* We can leave the card table uninitialised, since the array is
- allocated in the nursery. The GC will fill it in if/when the array
- is promoted. */
+ W_ clos;
+ clos = UNTAG(closure);
- SET_HDR(nptrs_arr, stg_ARR_WORDS_info, CCCS);
- StgArrBytes_bytes(nptrs_arr) = WDS(nptrs);
- p = 0;
+ W_ len;
+ // The array returned is the raw data for the entire closure.
+ // The length is variable based upon the closure type, ptrs, and non-ptrs
+ (len) = foreign "C" heap_view_closureSize(clos "ptr");
+
+ W_ ptrs_arr_sz, ptrs_arr_cards, dat_arr_sz;
+ dat_arr_sz = SIZEOF_StgArrBytes + WDS(len);
-write_nptrs:
- if(p < nptrs) {
- W_[BYTE_ARR_CTS(nptrs_arr) + WDS(p)] = StgClosure_payload(clos, p+ptrs);
+ ALLOC_PRIM_P (dat_arr_sz, stg_unpackClosurezh, closure);
+
+ dat_arr = Hp - dat_arr_sz + WDS(1);
+
+
+ SET_HDR(dat_arr, stg_ARR_WORDS_info, CCCS);
+ StgArrBytes_bytes(dat_arr) = WDS(len);
+ p = 0;
+for:
+ if(p < len) {
+ W_[BYTE_ARR_CTS(dat_arr) + WDS(p)] = W_[clos + WDS(p)];
p = p + 1;
- goto write_nptrs;
+ goto for;
}
- return (info, ptrs_arr, nptrs_arr);
+ W_ ptrArray;
+
+ // Follow the pointers
+ ("ptr" ptrArray) = foreign "C" heap_view_closurePtrs(MyCapability() "ptr", clos "ptr");
+
+ return (info, dat_arr, ptrArray);
}
/* -----------------------------------------------------------------------------
@@ -2118,8 +2078,6 @@ stg_waitWritezh ( W_ fd )
#endif
}
-
-STRING(stg_delayzh_malloc_str, "stg_delayzh")
stg_delayzh ( W_ us_delay )
{
#if defined(mingw32_HOST_OS)
@@ -2140,7 +2098,7 @@ stg_delayzh ( W_ us_delay )
/* could probably allocate this on the heap instead */
("ptr" ares) = ccall stgMallocBytes(SIZEOF_StgAsyncIOResult,
- stg_delayzh_malloc_str);
+ "stg_delayzh");
(reqID) = ccall addDelayRequest(us_delay);
StgAsyncIOResult_reqID(ares) = reqID;
StgAsyncIOResult_len(ares) = 0;
@@ -2185,7 +2143,6 @@ while:
#if defined(mingw32_HOST_OS)
-STRING(stg_asyncReadzh_malloc_str, "stg_asyncReadzh")
stg_asyncReadzh ( W_ fd, W_ is_sock, W_ len, W_ buf )
{
W_ ares;
@@ -2200,7 +2157,7 @@ stg_asyncReadzh ( W_ fd, W_ is_sock, W_ len, W_ buf )
/* could probably allocate this on the heap instead */
("ptr" ares) = ccall stgMallocBytes(SIZEOF_StgAsyncIOResult,
- stg_asyncReadzh_malloc_str);
+ "stg_asyncReadzh");
(reqID) = ccall addIORequest(fd, 0/*FALSE*/,is_sock,len,buf "ptr");
StgAsyncIOResult_reqID(ares) = reqID;
StgAsyncIOResult_len(ares) = 0;
@@ -2211,7 +2168,6 @@ stg_asyncReadzh ( W_ fd, W_ is_sock, W_ len, W_ buf )
#endif
}
-STRING(stg_asyncWritezh_malloc_str, "stg_asyncWritezh")
stg_asyncWritezh ( W_ fd, W_ is_sock, W_ len, W_ buf )
{
W_ ares;
@@ -2225,7 +2181,7 @@ stg_asyncWritezh ( W_ fd, W_ is_sock, W_ len, W_ buf )
StgTSO_why_blocked(CurrentTSO) = BlockedOnWrite::I16;
("ptr" ares) = ccall stgMallocBytes(SIZEOF_StgAsyncIOResult,
- stg_asyncWritezh_malloc_str);
+ "stg_asyncWritezh");
(reqID) = ccall addIORequest(fd, 1/*TRUE*/,is_sock,len,buf "ptr");
StgAsyncIOResult_reqID(ares) = reqID;
@@ -2237,7 +2193,6 @@ stg_asyncWritezh ( W_ fd, W_ is_sock, W_ len, W_ buf )
#endif
}
-STRING(stg_asyncDoProczh_malloc_str, "stg_asyncDoProczh")
stg_asyncDoProczh ( W_ proc, W_ param )
{
W_ ares;
@@ -2252,7 +2207,7 @@ stg_asyncDoProczh ( W_ proc, W_ param )
/* could probably allocate this on the heap instead */
("ptr" ares) = ccall stgMallocBytes(SIZEOF_StgAsyncIOResult,
- stg_asyncDoProczh_malloc_str);
+ "stg_asyncDoProczh");
(reqID) = ccall addDoProcRequest(proc "ptr",param "ptr");
StgAsyncIOResult_reqID(ares) = reqID;
StgAsyncIOResult_len(ares) = 0;
@@ -2358,7 +2313,7 @@ stg_noDuplicatezh /* no arg list: explicit stack layout */
stg_getApStackValzh ( P_ ap_stack, W_ offset )
{
- if (%INFO_PTR(ap_stack) == stg_AP_STACK_info) {
+ if (%INFO_PTR(UNTAG(ap_stack)) == stg_AP_STACK_info) {
return (1,StgAP_STACK_payload(ap_stack,offset));
} else {
return (0,ap_stack);
@@ -2450,6 +2405,14 @@ stg_traceEventzh ( W_ msg )
return ();
}
+stg_traceBinaryEventzh ( W_ msg, W_ len )
+{
+#if defined(TRACING) || defined(DEBUG)
+ ccall traceUserBinaryMsg(MyCapability() "ptr", msg "ptr", len);
+#endif
+ return ();
+}
+
// Same code as stg_traceEventzh above but a different kind of event
// Before changing this code, read the comments in the impl above
stg_traceMarkerzh ( W_ msg )
@@ -2475,3 +2438,23 @@ stg_traceMarkerzh ( W_ msg )
return ();
}
+
+stg_getThreadAllocationCounterzh ()
+{
+ // Account for the allocation in the current block
+ W_ offset;
+ offset = Hp - bdescr_start(CurrentNursery);
+ return (StgTSO_alloc_limit(CurrentTSO) - TO_I64(offset));
+}
+
+stg_setThreadAllocationCounterzh ( I64 counter )
+{
+ // Allocation in the current block will be subtracted by
+ // getThreadAllocationCounter#, so we have to offset any existing
+ // allocation here. See also openNursery/closeNursery in
+ // compiler/codeGen/StgCmmForeign.hs.
+ W_ offset;
+ offset = Hp - bdescr_start(CurrentNursery);
+ StgTSO_alloc_limit(CurrentTSO) = counter + TO_I64(offset);
+ return ();
+}