1 %****************************************************************************
3 \section[SMmark.lhc]{Pointer-Reversing Mark code}
5 % (c) P. Sansom, K. Hammond, OBFUSCATION-THROUGH-GRATUITOUS-PREPROCESSOR-ABUSE
6 % Project, Glasgow University, January 26th 1993.
8 %****************************************************************************
10 This module contains the specialised and generic code to perform
11 pointer reversal marking. These routines are placed in the info
12 tables of the appropriate closures.
14 Some of the dirt is hidden in macros defined in SMmarkDefs.lh.
16 %****************************************************************************
18 \subsection[mark-overview]{Overview of Marking}
20 %****************************************************************************
22 This module uses a pointer-reversal algorithm to mark a closure.
23 To mark a closure, first set a bit indicating that the closure
24 has been marked, then mark each pointer in the closure. The mark
25 bit is used to determine whether a node has already been
26 marked before we mark it. Because we set the bit before marking
27 the children of a node, this avoids cycles.
29 Given a closure containing a number of pointers, $n$, $n > 0$ the mark
30 code for that closure can be divided into three parts:
33 The mark (or ``start'') code for the closure. Called when an attempt is made
34 to mark the closure, it initialises the mark position in the
35 closure, then jumps to the mark code for the first pointer.
37 The return (or ``in'') code for the closure. Called when a closure is
38 returned to after a child is marked, it increments the mark position
39 and jumps to the mark entry for the next pointer
41 The last (or ``in-last'') code for the closure. Called when all children
42 have been marked, it just returns to its parent through the appropriate
46 For non-\tr{SPEC} closures, the return and last codes are merged in most
47 cases, so the return code checks explicitly whether all pointers have
48 been marked, and returns if so.
50 %****************************************************************************
52 \subsubsection[mark-registers]{Registers used when marking}
54 %****************************************************************************
56 Two registers are used:
59 Points to the closure being marked.
61 Points to the closure on the top of the marking stack.
62 The first closure on the stack contains the continuation to
63 enter when marking is complete.
66 The following registers are used by Pointer Reversal Marking:
70 The top of the mark stack.
72 The node being processed.
74 The bit array (what's that? KH) to mark.
76 The base of the heap (to calculate bit to mark).
78 The limit of the heap. For generational garbage collection,
79 only closures whose address is $<$ @HeapLim@ will be marked
82 To answer KH's question, the @BitArray@ is used to store marks. This
83 avoids the need to include space for a mark bit in the closure itself.
84 The array consists of one bit per word of heap memory that is handled
85 by the compacting collector or the old generation in the generational
88 %****************************************************************************
90 \subsubsection[mark-conventions]{Calling and Return Conventions}
92 %****************************************************************************
94 When a child closure is returned from, the registers have the following
99 points to the closure just marked (this may be updated with a new
100 address to short-circuit indirections).
102 points to the closure whose return code has been entered
103 (this closure is now at the top of the pointer-reversal marking stack).
106 The macros @JUMP_MARK@ and @JUMP_MARK_RETURN@ jump to the start code
107 pointed to by the @Mark@ register, or the return code pointed to by
108 the @MStack@ register respectively.
111 %%%% GOT THIS FAR -- KH %%%%
116 Retrieved using PRMARK_CODE(infoptr)
118 Uses pointer reversal marking to mark a closure which contains N ptrs.
119 If the closure has 0 pointers it sets it to a marked state and returns
120 to the closure on top of the PR mark stack (_PRStart_0).
122 If Not (@_PRStart_N@ ($N > 0$))
123 sets to a state of marking the first pointer
124 pushes this closure on the PR marking stack (in the first ptr location)
125 marks the first child -- enters its marking code
127 A closure that is already marked just indicates this by returning to the
128 closure on the top of the PR mark stack.
131 Mark -- points to the closure to mark
132 MStack -- points to the closure on the top of the PR marking stack
133 If the stack is empty it points to a closure which contains
134 the continuation to enter when marking is complete.
138 MStack set to a closure containing the continuation to be called when
139 the root has been marked.
140 Mark pointing to the closure
142 Entering MStack Continuation:
143 Mark points to new value of the closure (indirection short circut)
144 *** Update root being marked with this value.
147 Returning To A Closure Being Marked:
151 Retrieved using PRRETURN_CODE(infoptr)
153 Starts marking the next pointer (_PRIn_I).
154 updates the current poointer being marked with new Mark
155 sets state to next pointer
157 If not, (_PRInLast_N), it returns to the closure on the top of the PR
161 Mark -- points to the closure just marked (may be updated with new
162 address to short indirections)
163 MStack -- points to it -- the closure on the top of the PR marking stack
167 The following registers are used by Pointer Reversal Marking:
169 MStack -- The MarkStack register
170 Mark -- Points to the Node being processed
171 BitArray -- The bit array to mark
172 HeapBase -- The base of the heap (to calculate bit to mark)
173 HeapLim -- The limit of the heap
174 -- For gen gc: only closures < HeapLim will be marked
175 -- OldRoots pointing < HeapLim
177 \input{SMmarkDefs.lh}
179 %****************************************************************************
181 \subsection[mark-code]{The actual Marking Code}
183 %****************************************************************************
185 This code is only used if @_INFO_MARKING@ is defined.
188 #if defined(_INFO_MARKING)
191 First the necessary forward declarations.
194 /* #define MARK_REG_MAP -- Must be done on command line for threaded code */
195 #include "SMinternal.h"
196 #include "SMmarkDefs.h"
199 extern P_ ret_MRoot, ret_Mark;
203 Define appropriate variables as potential register variables.
204 Assume GC code saves and restores any global registers used.
207 RegisterTable MarkRegTable;
210 @_startMarkWorld@ restores registers if necessary, then marks the
211 root pointed to by @Mark@.
214 STGFUN(_startMarkWorld)
217 #if defined(__STG_GCC_REGS__) && defined(__GNUC__)
218 /* If using registers load from _SAVE (see SMmarking.lc) */
220 /* I deeply suspect this should be RESTORE_REGS(...) [WDP 95/02] */
222 MarkBaseReg = &MarkRegTable;
226 MStack = SAVE_MStack;
227 BitArray = SAVE_BitArray;
228 HeapBase = SAVE_HeapBase;
229 HeapLim = SAVE_HeapLim;
237 This is the pointer reversal start code for \tr{SPEC} closures with 0
244 if (IS_MARK_BIT_SET(Mark)) {
247 INIT_MARK_NODE("SPEC",0);
255 This macro defines the format of the pointer reversal start code for a
256 number of pointers \tr{ptrs}, $>$ 0.
260 #define SPEC_PRStart_N_CODE(ptrs) \
261 STGFUN(CAT2(_PRStart_,ptrs)) \
264 if (IS_MARK_BIT_SET(Mark)) { \
268 INIT_MARK_NODE("SPEC",ptrs); \
269 INIT_MSTACK(SPEC_CLOSURE_PTR); \
276 The definitions of the start code for \tr{SPEC} closures with 1-12
280 SPEC_PRStart_N_CODE(1)
281 SPEC_PRStart_N_CODE(2)
282 SPEC_PRStart_N_CODE(3)
283 SPEC_PRStart_N_CODE(4)
284 SPEC_PRStart_N_CODE(5)
285 SPEC_PRStart_N_CODE(6)
286 SPEC_PRStart_N_CODE(7)
287 SPEC_PRStart_N_CODE(8)
288 SPEC_PRStart_N_CODE(9)
289 SPEC_PRStart_N_CODE(10)
290 SPEC_PRStart_N_CODE(11)
291 SPEC_PRStart_N_CODE(12)
295 Start code for revertible black holes with underlying @SPEC@ types.
299 #if defined(PAR) || defined(GRAN)
300 #define SPEC_RBH_PRStart_N_CODE(ptrs) \
301 STGFUN(CAT2(_PRStart_RBH_,ptrs)) \
304 if (IS_MARK_BIT_SET(Mark)) { \
308 INIT_MARK_NODE("SRBH",ptrs-1); \
309 INIT_MSTACK(SPEC_RBH_CLOSURE_PTR); \
314 SPEC_RBH_PRStart_N_CODE(2)
315 SPEC_RBH_PRStart_N_CODE(3)
316 SPEC_RBH_PRStart_N_CODE(4)
317 SPEC_RBH_PRStart_N_CODE(5)
318 SPEC_RBH_PRStart_N_CODE(6)
319 SPEC_RBH_PRStart_N_CODE(7)
320 SPEC_RBH_PRStart_N_CODE(8)
321 SPEC_RBH_PRStart_N_CODE(9)
322 SPEC_RBH_PRStart_N_CODE(10)
323 SPEC_RBH_PRStart_N_CODE(11)
324 SPEC_RBH_PRStart_N_CODE(12)
330 @SPEC_PRIn_N_CODE@ has two different meanings, depending on the world
334 In the commoned-info-table world, it
335 defines the ``in'' code for a particular number
336 of pointers, and subsumes the functionality of @SPEC_PRInLast_N_NODE@ below.
338 Otherwise, it defines the ``in'' code for a particular pointer in a
344 #define SPEC_PRIn_N_CODE(ptrs) \
345 STGFUN(CAT2(_PRIn_,ptrs)) \
349 GET_MARKED_PTRS(mbw,MStack,ptrs); \
350 if (++mbw < ptrs) { \
351 SET_MARKED_PTRS(MStack,ptrs,mbw); \
352 CONTINUE_MARKING_NODE("SPEC",mbw); \
353 MOVE_TO_NEXT_PTR(SPEC_CLOSURE_PTR,mbw); \
355 SET_MARKED_PTRS(MStack,ptrs,0L); \
356 POP_MSTACK("SPEC",SPEC_CLOSURE_PTR,ptrs); \
363 Now @SPEC_PRIn_N_CODE@ is used to define the individual entries for \tr{SPEC} closures
370 fprintf(stderr,"Called _PRIn_0\nShould never occur!\n");
377 POP_MSTACK("SPEC",SPEC_CLOSURE_PTR,1);
393 In code for revertible black holes with underlying @SPEC@ types.
396 #if defined(PAR) || defined(GRAN)
397 #define SPEC_RBH_PRIn_N_CODE(ptrs) \
398 STGFUN(CAT2(_PRIn_RBH_,ptrs)) \
402 GET_MARKED_PTRS(mbw,MStack,ptrs-1); \
403 if (++mbw < ptrs-1) { \
404 SET_MARKED_PTRS(MStack,ptrs-1,mbw); \
405 CONTINUE_MARKING_NODE("SRBH",mbw); \
406 MOVE_TO_NEXT_PTR(SPEC_RBH_CLOSURE_PTR,mbw); \
408 SET_MARKED_PTRS(MStack,ptrs-1,0L); \
409 POP_MSTACK("SRBH",SPEC_RBH_CLOSURE_PTR,ptrs-1); \
417 POP_MSTACK("SRBH",SPEC_RBH_CLOSURE_PTR,1);
421 SPEC_RBH_PRIn_N_CODE(3)
422 SPEC_RBH_PRIn_N_CODE(4)
423 SPEC_RBH_PRIn_N_CODE(5)
424 SPEC_RBH_PRIn_N_CODE(6)
425 SPEC_RBH_PRIn_N_CODE(7)
426 SPEC_RBH_PRIn_N_CODE(8)
427 SPEC_RBH_PRIn_N_CODE(9)
428 SPEC_RBH_PRIn_N_CODE(10)
429 SPEC_RBH_PRIn_N_CODE(11)
430 SPEC_RBH_PRIn_N_CODE(12)
435 Foreign Objs are in the non-parallel world only.
441 STGFUN(_PRStart_ForeignObj)
444 if (IS_MARK_BIT_SET(Mark)) {
447 INIT_MARK_NODE("ForeignObj ",0);
454 This defines the start code for generic (\tr{GEN}) closures.
463 if (IS_MARK_BIT_SET(Mark)) {
467 ptrs = GEN_CLOSURE_NoPTRS(Mark);
468 INIT_MARK_NODE("GEN ",ptrs);
472 INIT_MSTACK(GEN_CLOSURE_PTR);
478 Now the ``in'' code for \tr{GEN} closures.
488 ptrs = GEN_CLOSURE_NoPTRS(MStack);
489 GET_GEN_MARKED_PTRS(pos,MStack,ptrs);
492 SET_GEN_MARKED_PTRS(MStack,ptrs,pos);
493 CONTINUE_MARKING_NODE("GEN",pos);
494 MOVE_TO_NEXT_PTR(GEN_CLOSURE_PTR,pos);
496 SET_GEN_MARKED_PTRS(MStack,ptrs,0L);
497 POP_MSTACK("GEN ",GEN_CLOSURE_PTR,ptrs);
503 And the start/in code for a revertible black hole with an underlying @GEN@ closure.
507 #if defined(PAR) || defined(GRAN)
509 STGFUN(_PRStart_RBH_N)
515 if (IS_MARK_BIT_SET(Mark)) {
521 * Get pointer count from original closure and adjust for one pointer
522 * in the first two words of the RBH.
524 ptrs = GEN_RBH_CLOSURE_NoPTRS(Mark);
530 INIT_MARK_NODE("GRBH", ptrs);
531 INIT_MSTACK(GEN_RBH_CLOSURE_PTR);
543 * Get pointer count from original closure and adjust for one pointer
544 * in the first two words of the RBH.
546 ptrs = GEN_RBH_CLOSURE_NoPTRS(MStack);
552 GET_GEN_MARKED_PTRS(pos, MStack, ptrs);
555 SET_GEN_MARKED_PTRS(MStack, ptrs, pos);
556 CONTINUE_MARKING_NODE("GRBH", pos);
557 MOVE_TO_NEXT_PTR(GEN_RBH_CLOSURE_PTR, pos);
559 SET_GEN_MARKED_PTRS(MStack, ptrs, 0L);
560 POP_MSTACK("GRBH", GEN_RBH_CLOSURE_PTR, ptrs);
569 Start code for dynamic (\tr{DYN}) closures. There is no \tr{DYN}
570 closure with 0 pointers -- \tr{DATA} is used instead.
576 if (IS_MARK_BIT_SET(Mark)) {
580 INIT_MARK_NODE("DYN ", DYN_CLOSURE_NoPTRS(Mark));
581 INIT_MSTACK(DYN_CLOSURE_PTR);
587 and the corresponding ``in'' code.
596 ptrs = DYN_CLOSURE_NoPTRS(MStack);
597 GET_GEN_MARKED_PTRS(pos,MStack,ptrs);
600 SET_GEN_MARKED_PTRS(MStack,ptrs,pos);
601 CONTINUE_MARKING_NODE("DYN",pos);
602 MOVE_TO_NEXT_PTR(DYN_CLOSURE_PTR,pos);
604 SET_GEN_MARKED_PTRS(MStack,ptrs,0L);
605 POP_MSTACK("DYN ",DYN_CLOSURE_PTR,ptrs);
612 The start code for \tr{TUPLE} (all-pointer) objects. There can be no
613 such object without any pointers, so we don't check for this case.
616 STGFUN(_PRStart_Tuple)
619 if (IS_MARK_BIT_SET(Mark)) {
623 INIT_MARK_NODE("TUPL", TUPLE_CLOSURE_NoPTRS(Mark));
624 INIT_MSTACK(TUPLE_CLOSURE_PTR);
633 STGFUN(_PRIn_I_Tuple)
639 ptrs = TUPLE_CLOSURE_NoPTRS(MStack);
640 GET_GEN_MARKED_PTRS(pos,MStack,ptrs);
643 SET_GEN_MARKED_PTRS(MStack,ptrs,pos);
644 CONTINUE_MARKING_NODE("TUPL",pos);
645 MOVE_TO_NEXT_PTR(TUPLE_CLOSURE_PTR,pos);
647 SET_GEN_MARKED_PTRS(MStack,ptrs,0L);
648 POP_MSTACK("TUPL",TUPLE_CLOSURE_PTR,ptrs);
656 /*** MUTUPLE CLOSURE -- NO PTRS STORED IN CLOSURE -- NO DATA ***/
657 /* Only if special GC treatment required */
659 #ifdef GC_MUT_REQUIRED
661 STGFUN(_PRStart_MuTuple)
664 if (IS_MARK_BIT_SET(Mark)) {
668 INIT_MARK_NODE("MUT ", MUTUPLE_CLOSURE_NoPTRS(Mark));
669 if (MUTUPLE_CLOSURE_NoPTRS(Mark) > 0) {
670 INIT_MSTACK(MUTUPLE_CLOSURE_PTR);
678 STGFUN(_PRIn_I_MuTuple)
684 ptrs = MUTUPLE_CLOSURE_NoPTRS(MStack);
685 GET_GEN_MARKED_PTRS(pos,MStack,ptrs);
688 SET_GEN_MARKED_PTRS(MStack,ptrs,pos);
689 CONTINUE_MARKING_NODE("MUT",pos);
690 MOVE_TO_NEXT_PTR(MUTUPLE_CLOSURE_PTR,pos);
692 SET_GEN_MARKED_PTRS(MStack,ptrs,0L);
693 POP_MSTACK("MUT ",MUTUPLE_CLOSURE_PTR,ptrs);
698 #endif /* GCap || GCgn */
701 There are no pointers in a \tr{DATA} closure, so just mark the
705 STGFUN(_PRStart_Data)
708 if (IS_MARK_BIT_SET(Mark)) {
711 INIT_MARK_NODE("DATA", 0);
717 %****************************************************************************
719 \subsubsection[mark-specials]{Special cases}
721 %****************************************************************************
723 Black hole closures simply mark themselves and return.
729 if (IS_MARK_BIT_SET(Mark)) {
732 INIT_MARK_NODE("BH ", 0);
738 Marking a Static Closure -- Just return as if Marked
741 STGFUN(_PRStart_Static)
750 Marking an Indirection -- Set Mark to ind addr and mark this.
751 Updating of reference when we return will short indirection.
758 GC_SHORT_IND(); /* ticky: record that we shorted an indirection */
760 Mark = (P_) IND_CLOSURE_PTR(Mark);
766 ``Permanent indirection''---used in profiling. Works basically
767 like @_PRStart_1@ (one pointer).
769 #if defined(PROFILING) || defined(TICKY_TICKY)
775 if (IS_MARK_BIT_SET(Mark)) {
779 INIT_MARK_NODE("PI ",1);
780 /* the "1" above is dodgy (i.e. wrong), but it is never
781 used except in debugging info. ToDo??? WDP 95/07
783 INIT_MSTACK(PERM_IND_CLOSURE_PTR);
791 POP_MSTACK("PI ",PERM_IND_CLOSURE_PTR,1);
792 /* the "1" above is dodgy (i.e. wrong), but it is never
793 used except in debugging info. ToDo??? WDP 95/07
798 #endif /* PROFILING or TICKY */
801 Marking a ``selector closure'': This is a size-2 SPEC thunk that
802 selects word $n$; if the thunk's pointee is evaluated, then we short
803 out the selection, {\em just like an indirection}. If it is still
804 unevaluated, then we behave {\em exactly as for a SPEC-2 thunk}.
806 {\em Should we select ``on the way down'' (in \tr{_PRStart_Selector})
807 or ``on the way back up'' (\tr{_PRIn_Selector})?} Answer: probably on
808 the way down. Downside: we are flummoxed by indirections, so we'll
809 have to wait until the {\em next} major GC to do the selections (after
810 the indirections are shorted out in this GC). But the downside of
811 doing selections on the way back up is that we are then in a world of
812 reversed pointers, and selecting a reversed pointer---we've see this
813 on selectors for very recursive structures---is a total disaster.
818 #define IF_GC_DEBUG(x) x
820 #define IF_GC_DEBUG(x) /*nothing*/
823 #if !defined(CONCURRENT)
824 # define NOT_BLACKHOLING (! RTSflags.GcFlags.lazyBlackHoling)
826 # define NOT_BLACKHOLING 0
829 /* _PRStartSelector_<n> is a (very) glorified _PRStart_1 */
831 #define MARK_SELECTOR(n) \
832 STGFUN(CAT2(_PRStartSelector_,n)) \
837 /* must be a SPEC 2 1 closure */ \
838 ASSERT(INFO_SIZE(INFO_PTR(Mark)) == 2); \
839 ASSERT(INFO_NoPTRS(INFO_PTR(Mark)) == 1); \
840 ASSERT(MIN_UPD_SIZE == 2); /* otherwise you are hosed */ \
842 if (IS_MARK_BIT_SET(Mark)) { /* already marked */ \
847 maybe_con = (P_) *(Mark + _FHS); \
850 if (RTSflags.GcFlags.trace & DEBUG_TRACE_MARKING) { \
851 fprintf(stderr, "Start Selector %d: 0x%lx, info 0x%lx, size %ld, ptrs %ld, maybe_con 0x%lx, info 0x%lx", \
852 (n), Mark, INFO_PTR(Mark), INFO_SIZE(INFO_PTR(Mark)), \
853 INFO_NoPTRS(INFO_PTR(Mark)), \
854 maybe_con, /*danger:IS_MARK_BIT_SET(maybe_con),*/ \
855 INFO_PTR(maybe_con)); \
856 fprintf(stderr, ", tag %ld, size %ld, ptrs %ld", \
857 INFO_TAG(INFO_PTR(maybe_con)), \
858 INFO_SIZE(INFO_PTR(maybe_con)), \
859 INFO_NoPTRS(INFO_PTR(maybe_con))); \
860 if (INFO_TAG(INFO_PTR(maybe_con)) >=0) { \
861 fprintf(stderr, "=> 0x%lx", maybe_con[_FHS + (n)]); \
863 fprintf(stderr, "\n"); \
866 if (IS_STATIC(INFO_PTR(maybe_con)) /* static: cannot chk mark bit */\
867 || IS_MARK_BIT_SET(maybe_con) /* been here: may be mangled */ \
868 || INFO_TAG(INFO_PTR(maybe_con)) < 0 /* not in WHNF */ \
869 || NOT_BLACKHOLING /* see "price of laziness" paper */ \
870 || (! RTSflags.GcFlags.doSelectorsAtGC )) \
871 /* see below for OLD test we used here (WDP 95/04) */ \
872 /* ToDo: decide WHNFness another way? */ \
875 /* some things should be true about the pointee */ \
876 ASSERT(INFO_TAG(INFO_PTR(maybe_con)) == 0); \
877 /* ASSERT((n) < INFO_SIZE(INFO_PTR(maybe_con))); not true if static */ \
879 /* OK, it is evaluated: behave just like an indirection */ \
880 GC_SEL_MAJOR(); /* ticky-ticky */ \
882 Mark = (P_) (maybe_con[_FHS + (n)]); \
883 /* Mark now has the result of the selection */ \
891 the IS_STATIC test was to protect the IS_MARK_BIT_SET check;
892 but the IS_MARK_BIT_SET test was only there to avoid
893 mangled pointers, but we cannot have mangled pointers anymore
894 (after RTBLs came our way).
895 SUMMARY: we toss both of the "guard" tests.
897 if (IS_STATIC(INFO_PTR(maybe_con)) /* static: cannot chk mark bit */
898 || IS_MARK_BIT_SET(maybe_con) /* been here: may be mangled */
899 || INFO_TAG(INFO_PTR(maybe_con)) < 0) /* not in WHNF */
916 #undef IF_GC_DEBUG /* get rid of it */
919 Marking a Constant Closure -- Set Mark to corresponding static
920 closure. Updating of reference will redirect reference to the static
924 STGFUN(_PRStart_Const)
931 Mark = (P_) CONST_STATIC_CLOSURE(INFO_PTR(Mark));
934 if (IS_MARK_BIT_SET(Mark)) {
937 if (!AllFlags.doUpdEntryCounts) {
939 GC_COMMON_CONST(); /* ticky */
941 Mark = (P_) CONST_STATIC_CLOSURE(INFO_PTR(Mark));
943 } else { /* no commoning */
944 INIT_MARK_NODE("CONST ",0);
954 Marking a CharLike Closure -- Set Mark to corresponding static
955 closure. Updating of reference will redirect reference to the static
959 STGFUN(_PRStart_CharLike)
972 Mark = (P_) CHARLIKE_CLOSURE(CHARLIKE_VALUE(Mark));
976 if (IS_MARK_BIT_SET(Mark)) {
979 val = CHARLIKE_VALUE(Mark);
981 if (!AllFlags.doUpdEntryCounts) {
982 GC_COMMON_CHARLIKE(); /* ticky */
984 INFO_PTR(Mark) = (W_) Ind_info;
985 IND_CLOSURE_PTR(Mark) = (W_) CHARLIKE_CLOSURE(val);
986 Mark = (P_) IND_CLOSURE_PTR(Mark);
988 } else { /* no commoning */
989 INIT_MARK_NODE("CHAR ",0);
999 Marking an IntLike Closure -- Set Mark to corresponding static closure
1000 if in range. Updating of reference to this will redirect reference to
1004 STGFUN(_PRStart_IntLike)
1009 if (IS_MARK_BIT_SET(Mark)) {
1012 val = INTLIKE_VALUE(Mark);
1014 if (val >= MIN_INTLIKE
1015 && val <= MAX_INTLIKE
1017 && !AllFlags.doUpdEntryCounts
1020 DEBUG_PR_INTLIKE_TO_STATIC;
1021 GC_COMMON_INTLIKE(); /* ticky */
1023 INFO_PTR(Mark) = (W_) Ind_info;
1024 IND_CLOSURE_PTR(Mark) = (W_) INTLIKE_CLOSURE(val);
1025 Mark = (P_) IND_CLOSURE_PTR(Mark);
1027 } else { /* out of range of static closures */
1028 DEBUG_PR_INTLIKE_IN_HEAP;
1030 if (!AllFlags.doUpdEntryCounts) GC_COMMON_INTLIKE_FAIL();
1032 INIT_MARK_NODE("INT ",0);
1040 Special error routine, used for closures which should never call their
1047 fprintf(stderr,"Called _PRIn_Error\nShould never occur!\n");
1053 %****************************************************************************
1055 \subsubsection[mark-fetchme]{Marking FetchMe Objects (parallel only)}
1057 %****************************************************************************
1063 FetchMe's present a unique problem during global GC. Since the IMU short-circuits
1064 indirections during its evacuation, it may return a PLC as the new global address
1065 for a @FetchMe@ node. This has the effect of turning the @FetchMe@ into an
1066 indirection during local garbage collection. Of course, we'd like to short-circuit
1067 this indirection immediately.
1070 STGFUN(_PRStart_FetchMe)
1073 if (IS_MARK_BIT_SET(Mark)) {
1076 INIT_MARK_NODE("FME ", 0);
1085 if (IS_MARK_BIT_SET(Mark)) {
1089 INIT_MARK_NODE("BF ", BF_CLOSURE_NoPTRS(dummy));
1090 INIT_MSTACK(BF_CLOSURE_PTR);
1100 GET_MARKED_PTRS(mbw, MStack, BF_CLOSURE_NoPTRS(dummy));
1101 if (++mbw < BF_CLOSURE_NoPTRS(dummy)) {
1102 SET_MARKED_PTRS(MStack, BF_CLOSURE_NoPTRS(dummy), mbw);
1103 CONTINUE_MARKING_NODE("BF ", mbw);
1104 MOVE_TO_NEXT_PTR(BF_CLOSURE_PTR, mbw);
1106 SET_MARKED_PTRS(MStack, BF_CLOSURE_NoPTRS(dummy), 0L);
1107 POP_MSTACK("BF ", BF_CLOSURE_PTR, BF_CLOSURE_NoPTRS(dummy));
1115 %****************************************************************************
1117 \subsubsection[mark-tso]{Marking Thread State Objects (threaded only)}
1119 %****************************************************************************
1121 First mark the link, then mark all live registers (StkO plus the VanillaRegs
1122 indicated by Liveness).
1124 CHANGE THIS FOR THE @COMMON_ITBLS@ WORLD!
1133 if (IS_MARK_BIT_SET(Mark)) {
1137 INIT_MARK_NODE("BQ ", BQ_CLOSURE_NoPTRS(Mark));
1138 INIT_MSTACK(BQ_CLOSURE_PTR);
1146 POP_MSTACK("BQ ",BQ_CLOSURE_PTR,1);
1150 STGFUN(_PRStart_TSO)
1154 if (IS_MARK_BIT_SET(Mark)) {
1158 INIT_MARK_NODE("TSO ", 0);
1159 temp = TSO_LINK(Mark);
1160 TSO_LINK(Mark) = MStack;
1169 When we're in the TSO, pos 0 is the link, 1 is the StkO, and 2-10 correspond to
1170 the vanilla registers r[pos-2].
1176 BitWord oldpos, newpos;
1177 STGRegisterTable *r;
1181 GET_MARKED_PTRS(oldpos,MStack,TSO_PTRS);
1182 r = TSO_INTERNAL_PTR(MStack);
1186 /* Just did the link; now do the StkO */
1187 SET_MARKED_PTRS(MStack,TSO_PTRS,1L);
1189 r->rStkO = TSO_LINK(MStack);
1190 TSO_LINK(MStack) = Mark;
1192 DEBUG_PRIN("TSO ", 1);
1196 /* Just did the StkO; just update it, saving the old mstack */
1201 /* update the register we just did; save the old mstack */
1202 mstack = r->rR[oldpos - 2].p;
1203 r->rR[oldpos - 2] = Mark;
1207 /* liveness of the remaining registers */
1208 liveness = r->rLiveness >> (oldpos - 1);
1210 if (liveness == 0) {
1211 /* Restore MStack and return */
1212 SET_MARKED_PTRS(MStack,TSO_PTRS,0L);
1213 DEBUG_PRLAST("TSO ", oldpos);
1219 /* More to do in this TSO */
1221 /* Shift past non-ptr registers */
1222 for(newpos = oldpos + 1; (liveness & 1) == 0; liveness >>= 1) {
1226 /* Mark the next one */
1227 SET_MARKED_PTRS(MStack,TSO_PTRS,newpos);
1228 Mark = r->rR[newpos - 2].p;
1229 r->rR[newpos - 2].p = mstack;
1230 DEBUG_PRIN("TSO ", oldpos);
1238 %****************************************************************************
1240 \subsubsection[mark-stko]{Marking Stack Objects (threaded only)}
1242 %****************************************************************************
1244 First mark the A stack, then mark all updatees in the B stack.
1248 STGFUN(_PRStart_StkO)
1256 /* ToDo: ASSERT(sanityChk_StkO(Mark)); ??? */
1258 if (IS_MARK_BIT_SET(Mark)) {
1262 INIT_MARK_NODE("STKO", 0);
1263 size = STKO_CLOSURE_SIZE(Mark);
1264 cts_size = STKO_CLOSURE_CTS_SIZE(Mark);
1265 SET_GEN_MARKED_PTRS(Mark,size,(BitWord)(cts_size + 1));
1266 temp = STKO_LINK(Mark);
1267 STKO_LINK(Mark) = MStack;
1276 Now the ``in'' code for \tr{STKO} closures. First the A stack is flushed,
1277 then we chain down the update frames in the B stack, marking the update
1278 nodes. When all have been marked we pop the stack and return.
1283 BitWord oldpos, newpos;
1289 size = STKO_CLOSURE_SIZE(MStack);
1290 GET_GEN_MARKED_PTRS(oldpos, MStack, size);
1292 if (oldpos > STKO_CLOSURE_CTS_SIZE(MStack)) {
1293 /* Update the link, saving the old mstack */
1294 mstack = STKO_LINK(MStack);
1295 STKO_LINK(MStack) = Mark;
1297 /* Update the pointer, saving the old mstack */
1298 mstack = (P_) STKO_CLOSURE_PTR(MStack, oldpos);
1299 STKO_CLOSURE_PTR(MStack, oldpos) = (W_) Mark;
1302 /* Calculate the next position to mark */
1303 if (oldpos > STKO_SpA_OFFSET(MStack)) {
1304 /* Just walk backwards down the A stack */
1305 newpos = oldpos - 1;
1306 SET_GEN_MARKED_PTRS(MStack,size,newpos);
1307 Mark = (P_) STKO_CLOSURE_PTR(MStack, newpos);
1308 STKO_CLOSURE_PTR(MStack, newpos) = (W_) mstack;
1309 DEBUG_PRIN("STKA", oldpos);
1311 } else if (oldpos <= STKO_SuB_OFFSET(MStack)) {
1312 /* We're looking at an updatee in the B stack; find the next SuB up the chain */
1315 subptr = GRAB_SuB(STKO_CLOSURE_ADDR(MStack, oldpos - BREL(UF_UPDATEE)));
1316 newpos = STKO_CLOSURE_OFFSET(MStack,subptr);
1318 /* Just fell off the end of the A stack; grab the first SuB */
1319 newpos = STKO_SuB_OFFSET(MStack);
1322 if (newpos == 0) { /* Grrr... newpos is 1-based */
1323 /* Restore MStack and return */
1324 SET_GEN_MARKED_PTRS(MStack,size,0L);
1325 DEBUG_PRLAST("STKO", oldpos);
1331 /* newpos is actually the SuB; we want the corresponding updatee */
1332 SET_GEN_MARKED_PTRS(MStack,size,newpos + BREL(UF_UPDATEE));
1333 Mark = (P_) STKO_CLOSURE_PTR(MStack, newpos + BREL(UF_UPDATEE));
1334 STKO_CLOSURE_PTR(MStack, newpos + BREL(UF_UPDATEE)) = (W_) mstack;
1335 DEBUG_PRIN("STKB", oldpos);
1340 #endif /* CONCURRENT */
1343 %****************************************************************************
1345 \subsubsection[mark-caf]{Marking CAFs}
1347 %****************************************************************************
1349 A CAF is shorted out as if it were an indirection.
1350 The CAF reference is explicitly updated by the garbage collector.
1353 STGFUN(_PRStart_Caf)
1357 GC_SHORT_CAF(); /* ticky */
1359 Mark = (P_) IND_CLOSURE_PTR(Mark);
1365 %****************************************************************************
1367 \subsection[mark-root]{Root Marking Code}
1369 %****************************************************************************
1371 Used by \tr{SMmarking.lc} -- but needs to be in \tr{.lhc} file.
1373 These are routines placed in closures at the bottom of the marking stack
1376 STGFUN(_Dummy_PRReturn_entry)
1379 fprintf(stderr,"Called _Dummy_PRReturn_entry\nShould never occur!\n");
1384 /* various ways to call _Dummy_PRReturn_entry: */
1386 INTFUN(_PRMarking_MarkNextRoot_entry) { FB_; JMP_(_Dummy_PRReturn_entry); FE_; }
1388 INTFUN(_PRMarking_MarkNextSpark_entry) { FB_; JMP_(_Dummy_PRReturn_entry); FE_; }
1391 INTFUN(_PRMarking_MarkNextGA_entry) { FB_; JMP_(_Dummy_PRReturn_entry); FE_; }
1393 # if 1 /* !defined(CONCURRENT) */ /* HWL */
1394 INTFUN(_PRMarking_MarkNextAStack_entry) { FB_; JMP_(_Dummy_PRReturn_entry); FE_; }
1395 INTFUN(_PRMarking_MarkNextBStack_entry) { FB_; JMP_(_Dummy_PRReturn_entry); FE_; }
1397 INTFUN(_PRMarking_MarkNextCAF_entry) { FB_; JMP_(_Dummy_PRReturn_entry); FE_; }
1400 INTFUN(_PRMarking_MarkNextEvent_entry) { FB_; JMP_(_Dummy_PRReturn_entry); FE_; }
1401 INTFUN(_PRMarking_MarkNextClosureInFetchBuffer_entry) { FB_; JMP_(_Dummy_PRReturn_entry); FE_; }
1404 /* end of various ways to call _Dummy_PRReturn_entry */
1406 EXTFUN(_PRMarking_MarkNextRoot);
1407 EXTFUN(_PRMarking_MarkNextCAF);
1410 EXTFUN(_PRMarking_MarkNextSpark);
1414 EXTFUN(_PRMarking_MarkNextGA);
1416 # if 1 /* !defined(CONCURRENT) */ /* HWL */
1417 EXTFUN(_PRMarking_MarkNextAStack);
1418 EXTFUN(_PRMarking_MarkNextBStack);
1420 #endif /* not parallel */
1422 CAT_DECLARE(Dummy_PrReturn,INTERNAL_KIND,"DUMMY_PRRETURN","DUMMY_PRRETURN")
1423 /* just one, shared */
1425 DUMMY_PRRETURN_CLOSURE(_PRMarking_MarkNextRoot_closure,
1426 _PRMarking_MarkNextRoot_info,
1427 _PRMarking_MarkNextRoot,
1428 _PRMarking_MarkNextRoot_entry);
1431 DUMMY_PRRETURN_CLOSURE(_PRMarking_MarkNextSpark_closure,
1432 _PRMarking_MarkNextSpark_info,
1433 _PRMarking_MarkNextSpark,
1434 _PRMarking_MarkNextSpark_entry);
1438 DUMMY_PRRETURN_CLOSURE(_PRMarking_MarkNextEvent_closure,
1439 _PRMarking_MarkNextEvent_info,
1440 _PRMarking_MarkNextEvent,
1441 _PRMarking_MarkNextEvent_entry);
1442 DUMMY_PRRETURN_CLOSURE(_PRMarking_MarkNextClosureInFetchBuffer_closure,
1443 _PRMarking_MarkNextClosureInFetchBuffer_info,
1444 _PRMarking_MarkNextClosureInFetchBuffer,
1445 _PRMarking_MarkNextClosureInFetchBuffer_entry);
1449 DUMMY_PRRETURN_CLOSURE(_PRMarking_MarkNextGA_closure,
1450 _PRMarking_MarkNextGA_info,
1451 _PRMarking_MarkNextGA,
1452 _PRMarking_MarkNextGA_entry);
1454 # if 1 /* !defined(CONCURRENT) */ /* HWL */
1455 DUMMY_PRRETURN_CLOSURE(_PRMarking_MarkNextAStack_closure,
1456 _PRMarking_MarkNextAStack_info,
1457 _PRMarking_MarkNextAStack,
1458 _PRMarking_MarkNextAStack_entry);
1460 DUMMY_PRRETURN_CLOSURE(_PRMarking_MarkNextBStack_closure,
1461 _PRMarking_MarkNextBStack_info,
1462 _PRMarking_MarkNextBStack,
1463 _PRMarking_MarkNextBStack_entry);
1467 DUMMY_PRRETURN_CLOSURE(_PRMarking_MarkNextCAF_closure,
1468 _PRMarking_MarkNextCAF_info,
1469 _PRMarking_MarkNextCAF,
1470 _PRMarking_MarkNextCAF_entry);
1472 extern P_ sm_roots_end; /* &roots[rootno] -- one beyond the end */
1474 STGFUN(_PRMarking_MarkNextRoot)
1477 /* Update root -- may have short circuited Ind */
1480 /* Is the next off the end */
1481 if (++MRoot >= sm_roots_end)
1482 RESUME_(miniInterpretEnd);
1489 #if defined(CONCURRENT)
1491 extern P_ sm_roots_end; /* PendingSparksTl[pool] */
1493 STGFUN(_PRMarking_MarkNextSpark)
1496 /* Update root -- may have short circuited Ind */
1499 /* Is the next off the end */
1500 if (++MRoot >= sm_roots_end)
1501 RESUME_(miniInterpretEnd);
1508 STGFUN(_PRMarking_MarkNextSpark)
1510 /* This is more similar to MarkNextGA than to the MarkNextSpark in
1511 concurrent-but-not-gran land
1512 NB: MRoot is a spark (with an embedded pointer to a closure) */
1514 /* Update root -- may have short circuited Ind */
1515 SPARK_NODE( ((sparkq) MRoot) ) = Mark;
1516 MRoot = (P_) SPARK_NEXT( ((sparkq) MRoot) );
1518 /* Is the next off the end */
1520 RESUME_(miniInterpretEnd);
1522 Mark = (P_) SPARK_NODE( ((sparkq) MRoot) );
1527 #endif /* CONCURRENT */
1530 Note: Events are GranSim-only.
1531 Marking events is similar to marking GALA entries in parallel-land.
1532 The major difference is that depending on the type of the event we have
1533 to mark different field of the event (possibly several fields).
1534 Even worse, in the case of bulk fetching
1535 (@RTSflags.GranFlags.DoGUMMFetching@) we find a buffer of pointers to
1536 closures we have to mark (similar to sparks in concurrent-but-not-gransim
1541 STGFUN(_PRMarking_MarkNextEvent)
1543 rtsBool found = rtsFalse;
1547 /* First update the right component of the old event */
1548 switch (EVENT_TYPE( ((eventq) MRoot) )) {
1549 case CONTINUETHREAD:
1553 EVENT_TSO( ((eventq) MRoot) ) = (P_) Mark;
1556 SPARK_NODE(EVENT_SPARK( ((eventq) MRoot) )) = (P_) Mark;
1559 switch (EVENT_GC_INFO( ((eventq) MRoot) )) {
1561 EVENT_TSO( ((eventq) MRoot) ) = (P_) Mark;
1562 EVENT_GC_INFO( ((eventq) MRoot) ) = 1;
1563 Mark = (P_) EVENT_NODE( ((eventq) MRoot) );
1567 EVENT_NODE( ((eventq) MRoot) ) = (P_) Mark;
1568 EVENT_GC_INFO( ((eventq) MRoot) ) = 0; /* reset flag */
1571 fprintf(stderr,"PRMarking_MarkNextEvent: Illegal gc_info field of FETCHNODE event @ %#x\n",
1577 switch (EVENT_GC_INFO( ((eventq) MRoot) )) {
1579 EVENT_TSO( ((eventq) MRoot) ) = (P_) Mark;
1580 EVENT_GC_INFO( ((eventq) MRoot) ) = 1;
1581 /* In the case of packet fetching, EVENT_NODE(event) points to */
1582 /* the packet (currently, malloced). The packet is just a list of */
1583 /* closure addresses, with the length of the list at index 1 (the */
1584 /* structure of the packet is defined in Pack.lc). */
1585 if ( RTSflags.GranFlags.DoGUMMFetching ) {
1586 P_ buffer = (P_) EVENT_NODE( ((eventq) MRoot) );
1587 int size = (int) buffer[PACK_SIZE_LOCN];
1589 /* was: for (i = PACK_HDR_SIZE; i <= size-1; i++) ... */
1590 sm_roots_end = buffer + PACK_HDR_SIZE + size;
1591 MRoot = (P_) buffer + PACK_HDR_SIZE;
1595 MStack = (P_) _PRMarking_MarkNextClosureInFetchBuffer_closure;
1598 Mark = (P_) EVENT_NODE( ((eventq) MRoot) );
1603 if ( RTSflags.GranFlags.DoGUMMFetching ) {
1604 /* no update necessary; fetch buffers are malloced */
1606 EVENT_NODE( ((eventq) MRoot) ) = (P_) Mark;
1608 EVENT_GC_INFO( ((eventq) MRoot) ) = 0; /* reset flag */
1611 fprintf(stderr,"PRMarking_MarkNextEvent: Illegal gc_info field of FETCHREPLY event @ %#x\n",
1618 switch (EVENT_GC_INFO( ((eventq) MRoot) )) {
1620 EVENT_TSO( ((eventq) MRoot) ) = (P_) Mark;
1621 EVENT_GC_INFO( ((eventq) MRoot) ) = 1;
1622 Mark = (P_) EVENT_NODE( ((eventq) MRoot) );
1627 EVENT_NODE( ((eventq) MRoot) ) = (P_) Mark;
1628 EVENT_GC_INFO( ((eventq) MRoot) ) = 0; /* reset flag */
1631 fprintf(stderr,"PRMarking_MarkNextEvent: Illegal gc_info field of GLOBALBLOCK event @ %#x\n",
1637 EVENT_TSO( ((eventq) MRoot) ) = (P_) Mark;
1642 fprintf(stderr,"PRMarking_MarkNextEvent: Illegal gc_info field of FETCHNODE event @ %#x\n",
1648 MRoot = (P_) EVENT_NEXT( ((eventq) MRoot) );
1649 /* Is the next off the end */
1651 RESUME_(miniInterpretEnd);
1653 switch (EVENT_TYPE( ((eventq) MRoot) )) {
1654 case CONTINUETHREAD:
1658 EVENT_GC_INFO( ((eventq) MRoot) ) = 0;
1659 Mark = (P_) EVENT_TSO( ((eventq) MRoot) );
1663 EVENT_GC_INFO( ((eventq) MRoot) ) = 0;
1664 Mark = (P_) SPARK_NODE(EVENT_SPARK( ((eventq) MRoot) ));
1668 EVENT_GC_INFO( ((eventq) MRoot) ) = 0;
1669 Mark = (P_) EVENT_TSO( ((eventq) MRoot) );
1673 EVENT_GC_INFO( ((eventq) MRoot) ) = 0;
1674 Mark = (P_) EVENT_TSO( ((eventq) MRoot) );
1678 EVENT_GC_INFO( ((eventq) MRoot) ) = 0;
1679 Mark = (P_) EVENT_TSO( ((eventq) MRoot) );
1683 Mark = (P_) EVENT_TSO( ((eventq) MRoot) );
1690 fprintf(stderr,"Unknown event type %d (event @ %#x) in SMmarking_NextEvent\n",
1691 EVENT_TYPE( ((eventq) MRoot) ), MRoot);
1694 } while (!found && MRoot!=NULL);
1701 STGFUN(_PRMarking_MarkNextClosureInFetchBuffer)
1704 /* Update root -- may have short circuited Ind */
1707 /* Is the next off the end */
1708 if (++MRoot >= sm_roots_end) {
1709 /* We know that marking a fetch buffer is only called from within
1710 marking a FETCHREPLY event; we have saved the important
1711 registers before that */
1714 MStack = (P_) _PRMarking_MarkNextEvent_closure;
1725 STGFUN(_PRMarking_MarkNextGA)
1728 /* Update root -- may have short circuited Ind */
1729 ((GALA *)MRoot)->la = Mark;
1732 MRoot = (P_) ((GALA *) MRoot)->next;
1733 } while (MRoot != NULL && ((GALA *)MRoot)->ga.weight == MAX_GA_WEIGHT);
1735 /* Is the next off the end */
1737 RESUME_(miniInterpretEnd);
1739 Mark = ((GALA *)MRoot)->la;
1745 STGFUN(_PRMarking_MarkNextAStack)
1748 /* Update root -- may have short circuited Ind */
1751 /* Is the next off the end */
1752 if (SUBTRACT_A_STK( (PP_) ++MRoot, stackInfo.botA) < 0)
1753 RESUME_(miniInterpretEnd);
1761 STGFUN(_PRMarking_MarkNextBStack)
1764 /* Update root -- may have short circuited Ind */
1765 PUSH_UPDATEE(MRoot, Mark);
1767 MRoot = GRAB_SuB(MRoot);
1769 /* Is the next off the end */
1770 if (SUBTRACT_B_STK(MRoot, stackInfo.botB) < 0)
1771 RESUME_(miniInterpretEnd);
1773 Mark = GRAB_UPDATEE(MRoot);
1780 Mark the next CAF in the CAF list.
1783 STGFUN(_PRMarking_MarkNextCAF)
1787 /* Update root -- may have short circuited Ind */
1788 IND_CLOSURE_PTR(MRoot) = (W_) Mark;
1790 MRoot = (P_) IND_CLOSURE_LINK(MRoot);
1792 /* Is the next CAF the end of the list */
1794 RESUME_(miniInterpretEnd);
1796 GC_SHORT_CAF(); /* ticky (ToDo: wrong?) */
1798 Mark = (P_) IND_CLOSURE_PTR(MRoot);
1804 Multi-slurp protection.
1807 #endif /* _INFO_MARKING */