Remove old GUM/GranSim code
[ghc-hetmet.git] / rts / Updates.h
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 1998-2004
4  *
5  * Performing updates.
6  *
7  * ---------------------------------------------------------------------------*/
8
9 #ifndef UPDATES_H
10 #define UPDATES_H
11
12 /* -----------------------------------------------------------------------------
13    Updates
14
15    We have two layers of update macros.  The top layer, UPD_IND() and
16    friends perform all the work of an update.  In detail:
17
18       - if the closure being updated is a blocking queue, then all the
19         threads waiting on the blocking queue are updated.
20
21       - then the lower level updateWithIndirection() macro is invoked 
22         to actually replace the closure with an indirection (see below).
23
24    -------------------------------------------------------------------------- */
25
26 #  define SEMI ;
27 # define UPD_IND(updclosure, heapptr) \
28    UPD_REAL_IND(updclosure,INFO_PTR(stg_IND_info),heapptr,SEMI)
29 # define UPD_SPEC_IND(updclosure, ind_info, heapptr, and_then) \
30    UPD_REAL_IND(updclosure,ind_info,heapptr,and_then)
31
32 /* These macros have to work in both C and C--, so here's the
33  * impedance matching:
34  */
35 #ifdef CMINUSMINUS
36 #define BLOCK_BEGIN
37 #define BLOCK_END
38 #define INFO_PTR(info)      info
39 #else
40 #define BLOCK_BEGIN         {
41 #define BLOCK_END           }
42 #define INFO_PTR(info)      &info
43 #define StgBlockingQueue_blocking_queue(closure) \
44     (((StgBlockingQueue *)closure)->blocking_queue)
45 #endif
46
47 /* krc: there used to be an UPD_REAL_IND and an
48    UPD_PERM_IND, the latter of which was used for
49    ticky and cost-centre profiling.
50    for now, we just have UPD_REAL_IND. */
51 #define UPD_REAL_IND(updclosure, ind_info, heapptr, and_then)   \
52         BLOCK_BEGIN                                             \
53         updateWithIndirection(ind_info,                         \
54                               updclosure,                       \
55                               heapptr,                          \
56                               and_then);                        \
57         BLOCK_END
58
59 /* -----------------------------------------------------------------------------
60    Awaken any threads waiting on a blocking queue (BLACKHOLE_BQ).
61    -------------------------------------------------------------------------- */
62
63 /* -----------------------------------------------------------------------------
64    Updates: lower-level macros which update a closure with an
65    indirection to another closure.
66
67    There are several variants of this code.
68
69        PROFILING:
70    -------------------------------------------------------------------------- */
71
72 /* LDV profiling:
73  * We call LDV_recordDead_FILL_SLOP_DYNAMIC(p1) regardless of the generation in 
74  * which p1 resides.
75  *
76  * Note: 
77  *   After all, we do *NOT* need to call LDV_RECORD_CREATE() for both IND and 
78  *   IND_OLDGEN closures because they are inherently used. But, it corrupts
79  *   the invariants that every closure keeps its creation time in the profiling
80  *  field. So, we call LDV_RECORD_CREATE().
81  */
82
83 /* In the DEBUG case, we also zero out the slop of the old closure,
84  * so that the sanity checker can tell where the next closure is.
85  *
86  * Two important invariants: we should never try to update a closure
87  * to point to itself, and the closure being updated should not
88  * already have been updated (the mutable list will get messed up
89  * otherwise).
90  *
91  * NB. We do *not* do this in THREADED_RTS mode, because when we have the
92  * possibility of multiple threads entering the same closure, zeroing
93  * the slop in one of the threads would have a disastrous effect on
94  * the other (seen in the wild!).
95  */
96 #ifdef CMINUSMINUS
97
98 #define FILL_SLOP(p)                                                    \
99   W_ inf;                                                               \
100   W_ sz;                                                                \
101   W_ i;                                                                 \
102   inf = %GET_STD_INFO(p);                                               \
103   if (%INFO_TYPE(inf) != HALF_W_(BLACKHOLE)                             \
104         && %INFO_TYPE(inf) != HALF_W_(CAF_BLACKHOLE)) {                 \
105       if (%INFO_TYPE(inf) == HALF_W_(THUNK_SELECTOR)) {                 \
106           sz = BYTES_TO_WDS(SIZEOF_StgSelector_NoThunkHdr);             \
107      } else {                                                           \
108           if (%INFO_TYPE(inf) == HALF_W_(AP_STACK)) {                   \
109               sz = StgAP_STACK_size(p) + BYTES_TO_WDS(SIZEOF_StgAP_STACK_NoThunkHdr); \
110           } else {                                                      \
111               if (%INFO_TYPE(inf) == HALF_W_(AP)) {                     \
112                   sz = TO_W_(StgAP_n_args(p)) +  BYTES_TO_WDS(SIZEOF_StgAP_NoThunkHdr); \
113               } else {                                                  \
114                   sz = TO_W_(%INFO_PTRS(inf)) + TO_W_(%INFO_NPTRS(inf)); \
115               }                                                         \
116           }                                                             \
117       }                                                                 \
118       i = 0;                                                            \
119       for:                                                              \
120         if (i < sz) {                                                   \
121           StgThunk_payload(p,i) = 0;                                    \
122           i = i + 1;                                                    \
123           goto for;                                                     \
124         }                                                               \
125   }
126
127 #else /* !CMINUSMINUS */
128
129 INLINE_HEADER void
130 FILL_SLOP(StgClosure *p)
131 {                                               
132     StgInfoTable *inf = get_itbl(p);            
133     nat i, sz;
134
135     switch (inf->type) {
136     case BLACKHOLE:
137     case CAF_BLACKHOLE:
138         goto no_slop;
139         // we already filled in the slop when we overwrote the thunk
140         // with BLACKHOLE, and also an evacuated BLACKHOLE is only the
141         // size of an IND.
142     case THUNK_SELECTOR:
143         sz = sizeofW(StgSelector) - sizeofW(StgThunkHeader);
144         break;
145     case AP:
146         sz = ((StgAP *)p)->n_args + sizeofW(StgAP) - sizeofW(StgThunkHeader);
147         break;
148     case AP_STACK:
149         sz = ((StgAP_STACK *)p)->size + sizeofW(StgAP_STACK) - sizeofW(StgThunkHeader);
150         break;
151     default:
152         sz = inf->layout.payload.ptrs + inf->layout.payload.nptrs;
153         break;
154     }
155     for (i = 0; i < sz; i++) {
156         ((StgThunk *)p)->payload[i] = 0;
157     }
158 no_slop:
159     ;
160 }
161
162 #endif /* CMINUSMINUS */
163
164 #if !defined(DEBUG) || defined(THREADED_RTS)
165 #define DEBUG_FILL_SLOP(p) /* do nothing */
166 #else
167 #define DEBUG_FILL_SLOP(p) FILL_SLOP(p)
168 #endif
169
170 /* We have two versions of this macro (sadly), one for use in C-- code,
171  * and the other for C.
172  *
173  * The and_then argument is a performance hack so that we can paste in
174  * the continuation code directly.  It helps shave a couple of
175  * instructions off the common case in the update code, which is
176  * worthwhile (the update code is often part of the inner loop).
177  * (except that gcc now appears to common up this code again and
178  * invert the optimisation.  Grrrr --SDM).
179  */
180 #ifdef CMINUSMINUS
181 #define generation(n) (W_[generations] + n*SIZEOF_generation)
182 #define updateWithIndirection(ind_info, p1, p2, and_then)       \
183     W_ bd;                                                      \
184                                                                 \
185     DEBUG_FILL_SLOP(p1);                                        \
186     LDV_RECORD_DEAD_FILL_SLOP_DYNAMIC(p1);                      \
187     StgInd_indirectee(p1) = p2;                                 \
188     prim %write_barrier() [];                                   \
189     bd = Bdescr(p1);                                            \
190     if (bdescr_gen_no(bd) != 0 :: CInt) {                       \
191       recordMutableCap(p1, TO_W_(bdescr_gen_no(bd)), R1);       \
192       SET_INFO(p1, stg_IND_OLDGEN_info);                        \
193       LDV_RECORD_CREATE(p1);                                    \
194       TICK_UPD_OLD_IND();                                       \
195       and_then;                                                 \
196     } else {                                                    \
197       SET_INFO(p1, ind_info);                                   \
198       LDV_RECORD_CREATE(p1);                                    \
199       TICK_UPD_NEW_IND();                                       \
200       and_then;                                                 \
201   }
202 #else
203 #define updateWithIndirection(ind_info, p1, p2, and_then)       \
204   {                                                             \
205     bdescr *bd;                                                 \
206                                                                 \
207     ASSERT( (P_)p1 != (P_)p2 );                                 \
208     /* not necessarily true: ASSERT( !closure_IND(p1) ); */     \
209     /* occurs in RaiseAsync.c:raiseAsync() */                   \
210     DEBUG_FILL_SLOP(p1);                                        \
211     LDV_RECORD_DEAD_FILL_SLOP_DYNAMIC(p1);                      \
212     ((StgInd *)p1)->indirectee = p2;                            \
213     write_barrier();                                            \
214     bd = Bdescr((P_)p1);                                        \
215     if (bd->gen_no != 0) {                                      \
216       recordMutableGenLock(p1, bd->gen_no);                     \
217       SET_INFO(p1, &stg_IND_OLDGEN_info);                       \
218       TICK_UPD_OLD_IND();                                       \
219       and_then;                                                 \
220     } else {                                                    \
221       SET_INFO(p1, ind_info);                                   \
222       LDV_RECORD_CREATE(p1);                                    \
223       TICK_UPD_NEW_IND();                                       \
224       and_then;                                                 \
225     }                                                           \
226   }
227 #endif /* CMINUSMINUS */
228 #endif /* UPDATES_H */