Make globals use sharedCAF
[ghc.git] / rts / Updates.cmm
index a9f25b7..b3b6b20 100644 (file)
 
 
 #include "Cmm.h"
 
 
 #include "Cmm.h"
+#include "rts/prof/LDV.h"
+
 #include "Updates.h"
 #include "Updates.h"
-#include "StgLdvProf.h"
 
 
-/* on entry to the update code
-   (1) R1 points to the closure being returned
-   (2) Sp points to the update frame
-*/
+/*
+ * The update code is PERFORMANCE CRITICAL, if you make any changes
+ * here make sure you eyeball the assembly and check that the fast
+ * path (update in generation 0) is optimal.
+ *
+ * The return(ret) bit is passed down and pinned on the end of each
+ * branch (there end up being two major branches in the code), since
+ * we don't mind duplicating this jump.
+ */
+INFO_TABLE_RET ( stg_upd_frame, UPDATE_FRAME,
+                 UPDATE_FRAME_FIELDS(W_,P_,info_ptr,_ccs,_unused,updatee) )
+    return (P_ ret) /* the closure being returned */
+{
+    ASSERT(HpAlloc == 0); // Note [HpAlloc]
+
+    /* ToDo: it might be a PAP, so we should check... */
+    TICK_UPD_CON_IN_NEW(sizeW_fromITBL(%GET_STD_INFO(updatee)));
 
 
-/* The update fragment has been tuned so as to generate good
-   code with gcc, which accounts for some of the strangeness in the
-   way it is written.  
+    updateWithIndirection(updatee, ret, return (ret));
+}
 
 
-   In particular, the JMP_(ret) bit is passed down and pinned on the
-   end of each branch (there end up being two major branches in the
-   code), since we don't mind duplicating this jump.
-*/
+/*
+ * An update frame where the updatee has been replaced by a BLACKHOLE
+ * closure by threadPaused.  We may have threads to wake up, and we
+ * also have to check whether the blackhole has been updated by
+ * another thread in the meantime.
+ */
+INFO_TABLE_RET ( stg_marked_upd_frame, UPDATE_FRAME,
+                 UPDATE_FRAME_FIELDS(W_,P_,info_ptr,_ccs,_unused,updatee) )
+    return (P_ ret) /* the closure being returned */
+{
+    W_ v;
 
 
-#define UPD_FRAME_ENTRY_TEMPLATE                                       \
-       {                                                               \
-          W_ updatee;                                                  \
-                                                                       \
-          updatee = StgUpdateFrame_updatee(Sp);                                \
-                                                                       \
-         /* remove the update frame from the stack */                  \
-         Sp = Sp + SIZEOF_StgUpdateFrame;                              \
-                                                                       \
-         /* ToDo: it might be a PAP, so we should check... */          \
-         TICK_UPD_CON_IN_NEW(sizeW_fromITBL(%GET_STD_INFO(updatee)));  \
-                                                                       \
-         UPD_SPEC_IND(updatee, stg_IND_direct_info, R1, jump %ENTRY_CODE(Sp(0))); \
-       }
+    ASSERT(HpAlloc == 0); // Note [HpAlloc]
 
 
-#if defined(PROFILING)
-#define UPD_FRAME_BITMAP 3
-#define UPD_FRAME_WORDS  3
-#else
-#define UPD_FRAME_BITMAP 0
-#define UPD_FRAME_WORDS  1
-#endif
+    // we know the closure is a BLACKHOLE
+    v = StgInd_indirectee(updatee);
 
 
-/* this bitmap indicates that the first word of an update frame is a
- * non-pointer - this is the update frame link.  (for profiling,
- * there's a cost-centre-stack in there too).
- */
+    if (GETTAG(v) != 0) {
+        // updated by someone else: discard our value and use the
+        // other one to increase sharing, but check the blocking
+        // queues to see if any threads were waiting on this BLACKHOLE.
+        ccall checkBlockingQueues(MyCapability() "ptr", CurrentTSO "ptr");
+        return (v);
+    }
 
 
-INFO_TABLE_RET( stg_upd_frame, 
-           UPD_FRAME_WORDS, UPD_FRAME_BITMAP, UPDATE_FRAME)
-UPD_FRAME_ENTRY_TEMPLATE
+    // common case: it is still our BLACKHOLE
+    if (v == CurrentTSO) {
+        updateWithIndirection(updatee, ret, return (ret));
+    }
 
 
+    // The other cases are all handled by the generic code
+    ccall updateThunk (MyCapability() "ptr", CurrentTSO "ptr",
+                       updatee "ptr", ret "ptr");
 
 
-INFO_TABLE_RET( stg_marked_upd_frame, 
-           UPD_FRAME_WORDS, UPD_FRAME_BITMAP, UPDATE_FRAME)
-UPD_FRAME_ENTRY_TEMPLATE
+    return (ret);
+}
+
+/*
+ * Special update frame code for CAFs and eager-blackholed thunks: it
+ * knows how to update blackholes, but is distinct from
+ * stg_marked_upd_frame so that lazy blackholing won't treat it as the
+ * high watermark.
+ */
+INFO_TABLE_RET ( stg_bh_upd_frame, UPDATE_FRAME,
+                 UPDATE_FRAME_FIELDS(W_,P_,info_ptr,ccs,_unused,updatee) )
+    return (P_ ret) /* the closure being returned */
+{
+    // This all compiles away to a single jump instruction (sigh)
+    jump RET_LBL(stg_marked_upd_frame)
+        ( UPDATE_FRAME_FIELDS(,,info_ptr,ccs,_unused,updatee) )
+        (ret);
+}
+
+/* Note [HpAlloc]
+ *
+ * HpAlloc is required to be zero unless we just bumped Hp and failed
+ * the heap check: see HeapStackCheck.cmm.  Failures that result from
+ * HpAlloc being non-zero are very hard to track down, because they
+ * manifest as spurious heap corruption that happens only with +RTS
+ * -N2 or greater (because then we have a lot more
+ * interruptCapability() calls happening).  Hence, we assert
+ * HpAlloc==0 as often as possible, and in the update code is a good
+ * place to do that.
+ */