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