1 /* -----------------------------------------------------------------------------
2 *
3 * (c) The GHC Team, 1998-2013
4 *
5 * Performing updates.
6 *
7 * ---------------------------------------------------------------------------*/
8
9 #pragma once
10
11 #if !defined(CMINUSMINUS)
12 #include "BeginPrivate.h"
13 #endif
14
15 /* -----------------------------------------------------------------------------
16 Updates
17 -------------------------------------------------------------------------- */
18
19 /* LDV profiling:
20 * After all, we do *NOT* need to call LDV_RECORD_CREATE() for IND
21 * closures because they are inherently used. But, it corrupts
22 * the invariants that every closure keeps its creation time in the profiling
23 * field. So, we call LDV_RECORD_CREATE().
24 */
25
26 /*
27 * We have two versions of this macro (sadly), one for use in C-- code,
28 * and the other for C.
29 *
30 * The and_then argument is a performance hack so that we can paste in
31 * the continuation code directly. It helps shave a couple of
32 * instructions off the common case in the update code, which is
33 * worthwhile (the update code is often part of the inner loop).
34 */
35 #if defined(CMINUSMINUS)
36
37 #define UPDATE_FRAME_FIELDS(w_,p_,info_ptr,ccs,p2,updatee) \
38 w_ info_ptr, \
39 PROF_HDR_FIELDS(w_,ccs,p2) \
40 p_ updatee
41
42 /*
43 * Getting the memory barriers correct here is quite tricky. Essentially
44 * the write barrier ensures that any writes to the new indirectee are visible
45 * before we introduce the indirection.
46 * See Note [Heap memory barriers] in SMP.h.
47 */
48 #define updateWithIndirection(p1, p2, and_then) \
49 W_ bd; \
50 \
51 prim_write_barrier; \
52 bd = Bdescr(p1); \
53 if (bdescr_gen_no(bd) != 0 :: bits16) { \
54 IF_NONMOVING_WRITE_BARRIER_ENABLED { \
55 ccall updateRemembSetPushThunk_(BaseReg, p1 "ptr"); \
56 } \
57 recordMutableCap(p1, TO_W_(bdescr_gen_no(bd))); \
58 TICK_UPD_OLD_IND(); \
59 } else { \
60 TICK_UPD_NEW_IND(); \
61 } \
62 OVERWRITING_CLOSURE(p1); \
63 StgInd_indirectee(p1) = p2; \
64 prim_write_barrier; \
65 SET_INFO(p1, stg_BLACKHOLE_info); \
66 LDV_RECORD_CREATE(p1); \
67 and_then;
68
69 #else /* !CMINUSMINUS */
70
updateWithIndirection(Capability * cap,StgClosure * p1,StgClosure * p2)71 INLINE_HEADER void updateWithIndirection (Capability *cap,
72 StgClosure *p1,
73 StgClosure *p2)
74 {
75 ASSERT( (P_)p1 != (P_)p2 );
76 /* not necessarily true: ASSERT( !closure_IND(p1) ); */
77 /* occurs in RaiseAsync.c:raiseAsync() */
78 /* See Note [Heap memory barriers] in SMP.h */
79 bdescr *bd = Bdescr((StgPtr)p1);
80 if (bd->gen_no != 0) {
81 IF_NONMOVING_WRITE_BARRIER_ENABLED {
82 updateRemembSetPushThunk(cap, (StgThunk*)p1);
83 }
84 recordMutableCap(p1, cap, bd->gen_no);
85 TICK_UPD_OLD_IND();
86 } else {
87 TICK_UPD_NEW_IND();
88 }
89 OVERWRITING_CLOSURE(p1);
90 RELEASE_STORE(&((StgInd *)p1)->indirectee, p2);
91 SET_INFO_RELEASE(p1, &stg_BLACKHOLE_info);
92 LDV_RECORD_CREATE(p1);
93 }
94
95 #endif /* CMINUSMINUS */
96
97 #if !defined(CMINUSMINUS)
98 #include "EndPrivate.h"
99 #endif
100