/* ----------------------------------------------------------------------------
- * $Id: Closures.h,v 1.13 1999/05/11 16:47:40 keithw Exp $
+ * $Id: Closures.h,v 1.33 2003/03/24 14:46:53 simonmar Exp $
*
* (c) The GHC Team, 1998-1999
*
The profiling header
-------------------------------------------------------------------------- */
-#ifdef PROFILING
-
typedef struct {
- CostCentreStack *ccs;
+ CostCentreStack *ccs;
+ union {
+ struct _RetainerSet *rs; // Retainer Set
+ StgWord ldvw; // Lag/Drag/Void Word
+ } hp;
} StgProfHeader;
-#else /* !PROFILING */
-
-typedef struct {
- /* empty */
-} StgProfHeader;
-
-#endif /* PROFILING */
-
/* -----------------------------------------------------------------------------
- The parallel header
+ The GranSim header
-------------------------------------------------------------------------- */
-#ifdef GRAN
-
typedef struct {
- W_ procs;
+ StgWord procs; /* bitmask indicating on which PEs this closure resides */
} StgGranHeader;
-#else /* !PAR */
-
-typedef struct {
- /* empty */
-} StgGranHeader;
-
-#endif /* PAR */
-
-/* -----------------------------------------------------------------------------
- The ticky-ticky header
-
- Comment from old Ticky.h:
-
- This is used to record if a closure has been updated but not yet
- entered. It is set when the closure is updated and cleared when
- subsequently entered.
-
- NB: It is {\em not} an ``entry count'', it is an
- ``entries-after-update count.''
-
- The commoning up of @CONST@, @CHARLIKE@ and @INTLIKE@ closures is
- turned off(?) if this is required. This has only been done for 2s
- collection. It is done using a nasty hack which defines the
- @_Evacuate@ and @_Scavenge@ code for @CONST@, @CHARLIKE@ and @INTLIKE@
- info tables to be @_Evacuate_1@ and @_Scavenge_1_0@.
- -------------------------------------------------------------------------- */
-
-#ifdef TICKY_TICKY
-
-typedef struct {
- /* old: W_ updated; */
-} StgTickyHeader;
-
-#else /* !TICKY_TICKY */
-
-typedef struct {
- /* empty */
-} StgTickyHeader;
-
-#endif /* TICKY_TICKY */
-
/* -----------------------------------------------------------------------------
The full fixed-size closure header
StgProfHeader prof;
#endif
#ifdef GRAN
- StgGranHeader par;
-#endif
-#ifdef TICKY_TICKY
- StgTickyHeader ticky;
+ StgGranHeader gran;
#endif
} StgHeader;
/* All closures follow the generic format */
-typedef struct StgClosure_ {
+struct StgClosure_ {
StgHeader header;
- struct StgClosure_ *payload[0];
-} StgClosure;
+ struct StgClosure_ *payload[FLEXIBLE_ARRAY];
+};
/* What a stroke of luck - all our mutable closures follow the same
* basic layout, with the mutable link field as the second field after
typedef struct StgMutClosure_ {
StgHeader header;
- StgPtr *padding;
+ StgWord padding;
struct StgMutClosure_ *mut_link;
- struct StgClosure_ *payload[0];
+ struct StgClosure_ *payload[FLEXIBLE_ARRAY];
} StgMutClosure;
typedef struct {
typedef struct {
StgHeader header;
- StgWord n_args;
- StgClosure *fun;
- StgPtr payload[0];
+ StgHalfWord arity; /* zero if it is an AP */
+ StgHalfWord n_args;
+ StgClosure *fun; /* really points to a fun */
+ StgClosure *payload[FLEXIBLE_ARRAY];
} StgPAP;
+// AP closures have the same layout, for convenience
+typedef StgPAP StgAP;
+
typedef struct {
StgHeader header;
- StgWord n_args;
+ StgWord size; // number of words in payload
StgClosure *fun;
- StgPtr payload[0];
-} StgAP_UPD;
-
-typedef struct {
- StgHeader header;
- StgWord n_ptrs;
- StgWord n_words;
- StgWord n_instrs;
- StgWord stgexpr;
- StgPtr payload[0];
-} StgBCO;
+ StgClosure *payload[FLEXIBLE_ARRAY]; // contains a chunk of *stack*
+} StgAP_STACK;
typedef struct {
StgHeader header;
} StgIndOldGen;
typedef struct {
- StgHeader header;
- StgClosure *indirectee;
- StgClosure *static_link;
-} StgIndStatic;
-
-typedef struct StgCAF_ {
StgHeader header;
- StgClosure *body;
- StgMutClosure *mut_link;
- StgClosure *value;
- struct StgCAF_ *link;
-} StgCAF;
-
-typedef struct {
- StgHeader header;
- struct StgTSO_ *blocking_queue;
- StgMutClosure *mut_link;
-} StgBlockingQueue;
+ StgClosure *indirectee;
+ StgClosure *static_link;
+ struct _StgInfoTable *saved_info;
+} StgIndStatic;
typedef struct {
StgHeader header;
StgWord words;
- StgWord payload[0];
+ StgWord payload[FLEXIBLE_ARRAY];
} StgArrWords;
typedef struct {
StgHeader header;
StgWord ptrs;
StgMutClosure *mut_link; /* mutable list */
- StgClosure *payload[0];
+ StgClosure *payload[FLEXIBLE_ARRAY];
} StgMutArrPtrs;
typedef struct {
typedef struct _StgUpdateFrame {
StgHeader header;
- struct _StgUpdateFrame *link;
StgClosure *updatee;
} StgUpdateFrame;
typedef struct {
StgHeader header;
- struct _StgUpdateFrame *link;
-} StgSeqFrame;
-
-typedef struct {
- StgHeader header;
- struct _StgUpdateFrame *link;
+ StgInt exceptions_blocked;
StgClosure *handler;
} StgCatchFrame;
StgHeader header;
StgWord sn;
} StgStableName;
-
+
typedef struct _StgWeak { /* Weak v */
StgHeader header;
StgClosure *key;
struct _StgWeak *link;
} StgDeadWeak;
+/* Byte code objects. These are fixed size objects with pointers to
+ * four arrays, designed so that a BCO can be easily "re-linked" to
+ * other BCOs, to facilitate GHC's intelligent recompilation. The
+ * array of instructions is static and not re-generated when the BCO
+ * is re-linked, but the other 3 arrays will be regenerated.
+ *
+ * A BCO represents either a function or a stack frame. In each case,
+ * it needs a bitmap to describe to the garbage collector the
+ * pointerhood of its arguments/free variables respectively, and in
+ * the case of a function it also needs an arity. These are stored
+ * directly in the BCO, rather than in the instrs array, for two
+ * reasons:
+ * (a) speed: we need to get at the bitmap info quickly when
+ * the GC is examining APs and PAPs that point to this BCO
+ * (b) a subtle interaction with the compacting GC. In compacting
+ * GC, the info that describes the size/layout of a closure
+ * cannot be in an object more than one level of indirection
+ * away from the current object, because of the order in
+ * which pointers are updated to point to their new locations.
+ */
+
+typedef struct {
+ StgHeader header;
+ StgArrWords *instrs; // a pointer to an ArrWords
+ StgArrWords *literals; // a pointer to an ArrWords
+ StgMutArrPtrs *ptrs; // a pointer to a MutArrPtrs
+ StgArrWords *itbls; // a pointer to an ArrWords
+ StgHalfWord arity; // arity of this BCO
+ StgHalfWord size; // size of this BCO (in words)
+ StgWord bitmap[FLEXIBLE_ARRAY]; // an StgLargeBitmap
+} StgBCO;
+
+#define BCO_BITMAP(bco) ((StgLargeBitmap *)((StgBCO *)(bco))->bitmap)
+#define BCO_BITMAP_SIZE(bco) (BCO_BITMAP(bco)->size)
+#define BCO_BITMAP_BITS(bco) (BCO_BITMAP(bco)->bitmap)
+#define BCO_BITMAP_SIZEW(bco) ((BCO_BITMAP_SIZE(bco) + BITS_IN(StgWord) - 1) \
+ / BITS_IN(StgWord))
+
/* Dynamic stack frames - these have a liveness mask in the object
* itself, rather than in the info table. Useful for generic heap
- * check code.
+ * check code. See StgMacros.h, HEAP_CHK_GEN().
*/
typedef struct {
- const struct _StgInfoTable* info;
- StgWord liveness;
- StgWord ret_addr;
- StgWord payload[0];
+ const struct _StgInfoTable* info;
+ StgWord liveness;
+ StgWord ret_addr;
+ StgClosure * payload[FLEXIBLE_ARRAY];
} StgRetDyn;
+/* A function return stack frame: used when saving the state for a
+ * garbage collection at a function entry point. The function
+ * arguments are on the stack, and we also save the function (its
+ * info table describes the pointerhood of the arguments).
+ *
+ * The stack frame size is also cached in the frame for convenience.
+ */
+typedef struct {
+ const struct _StgInfoTable* info;
+ StgWord size;
+ StgClosure * fun;
+ StgClosure * payload[FLEXIBLE_ARRAY];
+} StgRetFun;
+
/* Concurrent communication objects */
typedef struct {
StgClosure* value;
} StgMVar;
-/* Parallel FETCH_ME closures */
-#ifdef PAR
-typedef struct {
+#if defined(PAR) || defined(GRAN)
+/*
+ StgBlockingQueueElement is a ``collective type'' representing the types
+ of closures that can be found on a blocking queue: StgTSO, StgRBHSave,
+ StgBlockedFetch. (StgRBHSave can only appear at the end of a blocking
+ queue). Logically, this is a union type, but defining another struct
+ with a common layout is easier to handle in the code (same as for
+ StgMutClosures).
+ Note that in the standard setup only StgTSOs can be on a blocking queue.
+ This is one of the main reasons for slightly different code in files
+ such as Schedule.c.
+*/
+typedef struct StgBlockingQueueElement_ {
+ StgHeader header;
+ struct StgBlockingQueueElement_ *link; /* next elem in BQ */
+ StgMutClosure *mut_link; /* next elem in mutable list */
+ struct StgClosure_ *payload[FLEXIBLE_ARRAY];/* contents of the closure */
+} StgBlockingQueueElement;
+
+/* only difference to std code is type of the elem in the BQ */
+typedef struct StgBlockingQueue_ {
+ StgHeader header;
+ struct StgBlockingQueueElement_ *blocking_queue; /* start of the BQ */
+ StgMutClosure *mut_link; /* next elem in mutable list */
+} StgBlockingQueue;
+
+/* this closure is hanging at the end of a blocking queue in (see RBH.c) */
+typedef struct StgRBHSave_ {
StgHeader header;
- void *ga; /* type globalAddr is abstract here */
+ StgClosure *payload[FLEXIBLE_ARRAY]; /* 2 words ripped out of the guts of the */
+} StgRBHSave; /* closure holding the blocking queue */
+
+typedef struct StgRBH_ {
+ StgHeader header;
+ struct StgBlockingQueueElement_ *blocking_queue; /* start of the BQ */
+ StgMutClosure *mut_link; /* next elem in mutable list */
+} StgRBH;
+
+#else
+
+typedef struct StgBlockingQueue_ {
+ StgHeader header;
+ struct StgTSO_ *blocking_queue;
+ StgMutClosure *mut_link;
+} StgBlockingQueue;
+
+#endif
+
+#if defined(PAR)
+/* global indirections aka FETCH_ME closures */
+typedef struct StgFetchMe_ {
+ StgHeader header;
+ globalAddr *ga; /* ptr to unique id for a closure */
+ StgMutClosure *mut_link; /* next elem in mutable list */
} StgFetchMe;
+
+/* same contents as an ordinary StgBlockingQueue */
+typedef struct StgFetchMeBlockingQueue_ {
+ StgHeader header;
+ struct StgBlockingQueueElement_ *blocking_queue; /* start of the BQ */
+ StgMutClosure *mut_link; /* next elem in mutable list */
+} StgFetchMeBlockingQueue;
+
+/* This is an entry in a blocking queue. It indicates a fetch request from a
+ TSO on another PE demanding the value of this closur. Note that a
+ StgBlockedFetch can only occur in a BQ. Once the node is evaluated and
+ updated with the result, the result will be sent back (the PE is encoded
+ in the globalAddr) and the StgBlockedFetch closure will be nuked.
+*/
+typedef struct StgBlockedFetch_ {
+ StgHeader header;
+ struct StgBlockingQueueElement_ *link; /* next elem in the BQ */
+ StgMutClosure *mut_link; /* next elem in mutable list */
+ StgClosure *node; /* node to fetch */
+ globalAddr ga; /* where to send the result to */
+} StgBlockedFetch; /* NB: not just a ptr to a GA */
#endif
#endif /* CLOSURES_H */