* - Hp += n ==> Hp_adj(n)
* - R1.i ==> R1 (similarly for R1.w, R1.cl etc.)
* - You need to explicitly dereference variables; eg.
- * context_switch ==> CInt[context_switch]
+ * alloc_blocks ==> CInt[alloc_blocks]
* - convert all word offsets into byte offsets:
* - e ==> WDS(e)
* - sizeofW(StgFoo) ==> SIZEOF_StgFoo
#define CMINUSMINUS 1
#include "ghcconfig.h"
-#include "RtsConfig.h"
/* -----------------------------------------------------------------------------
Types
#define I16 bits16
#define I32 bits32
#define I64 bits64
+#define P_ gcptr
#if SIZEOF_VOID_P == 4
#define W_ bits32
#endif
/*
- * The RTS must UNTAG a pointer before dereferencing it.
- * The use of UNTAG follows the following rules of thumb:
- *
- * - Any pointer might be tagged.
- * - Except the pointers that are passed in R1 to RTS functions.
- * - R1 is also untagged when entering constructor code.
- *
- * TODO:
- *
- * - Remove redundancies of tagging and untagging in code generation.
- * - Optimize getTag or dataToTag# ?
- *
+ * The RTS must sometimes UNTAG a pointer before dereferencing it.
+ * See the wiki page Commentary/Rts/HaskellExecution/PointerTagging
*/
#define TAG_MASK ((1 << TAG_BITS) - 1)
#define UNTAG(p) (p & ~TAG_MASK)
name : bits8[] str; \
} \
+#ifdef TABLES_NEXT_TO_CODE
+#define RET_LBL(f) f##_info
+#else
+#define RET_LBL(f) f##_ret
+#endif
+
+#ifdef TABLES_NEXT_TO_CODE
+#define ENTRY_LBL(f) f##_info
+#else
+#define ENTRY_LBL(f) f##_entry
+#endif
+
/* -----------------------------------------------------------------------------
Byte/word macros
Indirections can contain tagged pointers, so their tag is checked.
-------------------------------------------------------------------------- */
+#ifdef PROFILING
+
+// When profiling, we cannot shortcut ENTER() by checking the tag,
+// because LDV profiling relies on entering closures to mark them as
+// "used".
+
+#define LOAD_INFO \
+ info = %INFO_PTR(UNTAG(P1));
+
+#define UNTAG_R1 \
+ P1 = UNTAG(P1);
+
+#else
+
+#define LOAD_INFO \
+ if (GETTAG(P1) != 0) { \
+ jump %ENTRY_CODE(Sp(0)); \
+ } \
+ info = %INFO_PTR(P1);
+
+#define UNTAG_R1 /* nothing */
+
+#endif
+
#define ENTER() \
again: \
W_ info; \
- if (GETTAG(R1) != 0) { \
- jump %ENTRY_CODE(Sp(0)); \
- } \
- info = %INFO_PTR(R1); \
+ LOAD_INFO \
switch [INVALID_OBJECT .. N_CLOSURE_TYPES] \
(TO_W_( %INFO_TYPE(%STD_INFO(info)) )) { \
case \
IND_OLDGEN_PERM, \
IND_STATIC: \
{ \
- R1 = StgInd_indirectee(R1); \
+ P1 = StgInd_indirectee(P1); \
goto again; \
} \
case \
FUN_0_1, \
FUN_2_0, \
FUN_1_1, \
+ FUN_0_2, \
FUN_STATIC, \
BCO, \
PAP: \
} \
default: \
{ \
+ UNTAG_R1 \
jump %ENTRY_CODE(info); \
} \
}
Constants.
-------------------------------------------------------------------------- */
-#include "Constants.h"
+#include "rts/Constants.h"
#include "DerivedConstants.h"
-#include "ClosureTypes.h"
-#include "StgFun.h"
-#include "OSThreads.h"
-#include "SMP.h"
+#include "rts/storage/ClosureTypes.h"
+#include "rts/storage/FunTypes.h"
+#include "rts/storage/SMPClosureOps.h"
+#include "rts/OSThreads.h"
/*
* Need MachRegs, because some of the RTS code is conditionally
* compiled based on REG_R1, REG_R2, etc.
*/
#define STOLEN_X86_REGS 4
-#include "MachRegs.h"
+#include "stg/MachRegs.h"
-#include "Liveness.h"
-#include "StgLdvProf.h"
+#include "rts/storage/Liveness.h"
+#include "rts/prof/LDV.h"
#undef BLOCK_SIZE
#undef MBLOCK_SIZE
-#include "Block.h" /* For Bdescr() */
+#include "rts/storage/Block.h" /* For Bdescr() */
-/* Can't think of a better place to put this. */
-#if SIZEOF_mp_limb_t != SIZEOF_VOID_P
-#error mp_limb_t != StgWord: assumptions in PrimOps.cmm are now false
-#endif
-
#define MyCapability() (BaseReg - OFFSET_Capability_r)
/* -------------------------------------------------------------------------
HP_CHK_GEN(alloc,liveness,reentry); \
TICK_ALLOC_HEAP_NOCTR(alloc);
-// allocateLocal() allocates from the nursery, so we check to see
+// allocate() allocates from the nursery, so we check to see
// whether the nursery is nearly empty in any function that uses
-// allocateLocal() - this includes many of the primops.
+// allocate() - this includes many of the primops.
#define MAYBE_GC(liveness,reentry) \
- if (bdescr_link(CurrentNursery) == NULL || CInt[alloc_blocks] >= CInt[alloc_blocks_lim]) { \
+ if (bdescr_link(CurrentNursery) == NULL || \
+ generation_n_new_large_blocks(W_[g0]) >= CInt[alloc_blocks_lim]) { \
R9 = liveness; \
R10 = reentry; \
HpAlloc = 0; \
#define BITMAP_BITS(bitmap) ((bitmap) >> BITMAP_BITS_SHIFT)
/* Debugging macros */
-#define LOOKS_LIKE_INFO_PTR(p) \
- ((p) != NULL && \
- (TO_W_(%INFO_TYPE(%STD_INFO(p))) != INVALID_OBJECT) && \
+#define LOOKS_LIKE_INFO_PTR(p) \
+ ((p) != NULL && \
+ LOOKS_LIKE_INFO_PTR_NOT_NULL(p))
+
+#define LOOKS_LIKE_INFO_PTR_NOT_NULL(p) \
+ ( (TO_W_(%INFO_TYPE(%STD_INFO(p))) != INVALID_OBJECT) && \
(TO_W_(%INFO_TYPE(%STD_INFO(p))) < N_CLOSURE_TYPES))
#define LOOKS_LIKE_CLOSURE_PTR(p) (LOOKS_LIKE_INFO_PTR(GET_INFO(UNTAG(p))))
#define StgFunInfoExtra_bitmap(i) StgFunInfoExtraFwd_bitmap(i)
#endif
+#define mutArrPtrsCardWords(n) \
+ ROUNDUP_BYTES_TO_WDS(((n) + (1 << MUT_ARR_PTRS_CARD_BITS) - 1) >> MUT_ARR_PTRS_CARD_BITS)
+
/* -----------------------------------------------------------------------------
Voluntary Yields/Blocks
#define END_TSO_QUEUE stg_END_TSO_QUEUE_closure
#define END_INVARIANT_CHECK_QUEUE stg_END_INVARIANT_CHECK_QUEUE_closure
-#define dirtyTSO(tso) \
- StgTSO_flags(tso) = StgTSO_flags(tso) | TSO_DIRTY::I32;
-
#define recordMutableCap(p, gen, regs) \
W_ __bd; \
W_ mut_list; \
W_[free] = p; \
bdescr_free(__bd) = free + WDS(1);
-#define recordMutable(p, regs) \
- W_ __p; \
- __p = p; \
- recordMutableCap(__p, TO_W_(bdescr_gen_no(Bdescr(__p))), regs)
+#define recordMutable(p, regs) \
+ P_ __p; \
+ W_ __bd; \
+ W_ __gen; \
+ __p = p; \
+ __bd = Bdescr(__p); \
+ __gen = TO_W_(bdescr_gen_no(__bd)); \
+ if (__gen > 0) { recordMutableCap(__p, __gen, regs); }
#endif /* CMM_H */