Fold testsuite.git into ghc.git (re #8545)
[ghc.git] / rts / Updates.cmm
1 /* -----------------------------------------------------------------------------
2  *
3  * (c) The GHC Team, 1998-2004
4  *
5  * Code to perform updates.
6  *
7  * This file is written in a subset of C--, extended with various
8  * features specific to GHC.  It is compiled by GHC directly.  For the
9  * syntax of .cmm files, see the parser in ghc/compiler/cmm/CmmParse.y.
10  *
11  * ---------------------------------------------------------------------------*/
12
13
14 #include "Cmm.h"
15 #include "rts/prof/LDV.h"
16
17 #include "Updates.h"
18
19 /*
20  * The update code is PERFORMANCE CRITICAL, if you make any changes
21  * here make sure you eyeball the assembly and check that the fast
22  * path (update in generation 0) is optimal.
23  *
24  * The return(ret) bit is passed down and pinned on the end of each
25  * branch (there end up being two major branches in the code), since
26  * we don't mind duplicating this jump.
27  */
28 INFO_TABLE_RET ( stg_upd_frame, UPDATE_FRAME,
29                  UPDATE_FRAME_FIELDS(W_,P_,info_ptr,_ccs,_unused,updatee) )
30     return (P_ ret) /* the closure being returned */
31 {
32     ASSERT(HpAlloc == 0); // Note [HpAlloc]
33
34     /* ToDo: it might be a PAP, so we should check... */
35     TICK_UPD_CON_IN_NEW(sizeW_fromITBL(%GET_STD_INFO(updatee)));
36
37     updateWithIndirection(updatee, ret, return (ret));
38 }
39
40 /*
41  * An update frame where the updatee has been replaced by a BLACKHOLE
42  * closure by threadPaused.  We may have threads to wake up, and we
43  * also have to check whether the blackhole has been updated by
44  * another thread in the meantime.
45  */
46 INFO_TABLE_RET ( stg_marked_upd_frame, UPDATE_FRAME,
47                  UPDATE_FRAME_FIELDS(W_,P_,info_ptr,_ccs,_unused,updatee) )
48     return (P_ ret) /* the closure being returned */
49 {
50     W_ v;
51
52     ASSERT(HpAlloc == 0); // Note [HpAlloc]
53
54     // we know the closure is a BLACKHOLE
55     v = StgInd_indirectee(updatee);
56
57     if (GETTAG(v) != 0) {
58         // updated by someone else: discard our value and use the
59         // other one to increase sharing, but check the blocking
60         // queues to see if any threads were waiting on this BLACKHOLE.
61         ccall checkBlockingQueues(MyCapability() "ptr", CurrentTSO "ptr");
62         return (v);
63     }
64
65     // common case: it is still our BLACKHOLE
66     if (v == CurrentTSO) {
67         updateWithIndirection(updatee, ret, return (ret));
68     }
69
70     // The other cases are all handled by the generic code
71     ccall updateThunk (MyCapability() "ptr", CurrentTSO "ptr",
72                        updatee "ptr", ret "ptr");
73
74     return (ret);
75 }
76
77 /*
78  * Special update frame code for CAFs and eager-blackholed thunks: it
79  * knows how to update blackholes, but is distinct from
80  * stg_marked_upd_frame so that lazy blackholing won't treat it as the
81  * high watermark.
82  */
83 INFO_TABLE_RET ( stg_bh_upd_frame, UPDATE_FRAME,
84                  UPDATE_FRAME_FIELDS(W_,P_,info_ptr,ccs,_unused,updatee) )
85     return (P_ ret) /* the closure being returned */
86 {
87     // This all compiles away to a single jump instruction (sigh)
88     jump RET_LBL(stg_marked_upd_frame)
89         ( UPDATE_FRAME_FIELDS(,,info_ptr,ccs,_unused,updatee) )
90         (ret);
91 }
92
93 /* Note [HpAlloc]
94  *
95  * HpAlloc is required to be zero unless we just bumped Hp and failed
96  * the heap check: see HeapStackCheck.cmm.  Failures that result from
97  * HpAlloc being non-zero are very hard to track down, because they
98  * manifest as spurious heap corruption that happens only with +RTS
99  * -N2 or greater (because then we have a lot more
100  * interruptCapability() calls happening).  Hence, we assert
101  * HpAlloc==0 as often as possible, and in the update code is a good
102  * place to do that.
103  */