[project @ 2003-12-15 16:23:54 by simonmar]
[ghc-hetmet.git] / ghc / rts / Storage.h
index 6a7c738..fb84740 100644 (file)
@@ -1,7 +1,7 @@
 /* -----------------------------------------------------------------------------
- * $Id: Storage.h,v 1.45 2002/10/21 11:38:54 simonmar Exp $
+ * $Id: Storage.h,v 1.53 2003/11/12 17:49:11 sof Exp $
  *
- * (c) The GHC Team, 1998-1999
+ * (c) The GHC Team, 1998-2002
  *
  * External Storage Manger Interface
  *
@@ -53,7 +53,7 @@ extern void exitStorage(void);
 
    lnat  allocated_bytes(void)  Returns the number of bytes allocated
                                 via allocate() since the last GC.
-                               Used in the reoprting of statistics.
+                               Used in the reporting of statistics.
 
    SMP: allocate and doYouWantToGC can be used from STG code, they are
    surrounded by a mutex.
@@ -63,7 +63,7 @@ extern StgPtr  allocate        ( nat n );
 extern StgPtr  allocatePinned  ( nat n );
 extern lnat    allocated_bytes ( void );
 
-static inline rtsBool
+INLINE_HEADER rtsBool
 doYouWantToGC( void )
 {
   return (alloc_blocks >= alloc_blocks_lim);
@@ -78,14 +78,12 @@ doYouWantToGC( void )
   -------------------------------------------------------------------------- */
 
 #define ExtendNursery(hp,hplim)                        \
-  (CurrentNursery->free = (P_)(hp)+1,          \
+  (CloseNursery(hp),                            \
    CurrentNursery->link == NULL ? rtsFalse :   \
    (CurrentNursery = CurrentNursery->link,     \
     OpenNursery(hp,hplim),                     \
     rtsTrue))
 
-extern void PleaseStopAllocating(void);
-
 /* -----------------------------------------------------------------------------
    Performing Garbage Collection
 
@@ -131,7 +129,7 @@ extern Mutex sm_mutex;
 /* ToDo: shouldn't recordMutable and recordOldToNewPtrs acquire some
  * kind of lock in the SMP case?
  */
-static inline void
+INLINE_HEADER void
 recordMutable(StgMutClosure *p)
 {
   bdescr *bd;
@@ -149,7 +147,7 @@ recordMutable(StgMutClosure *p)
   }
 }
 
-static inline void
+INLINE_HEADER void
 recordOldToNewPtrs(StgMutClosure *p)
 {
   bdescr *bd;
@@ -165,15 +163,16 @@ recordOldToNewPtrs(StgMutClosure *p)
 // We zero out the slop when PROFILING is on.
 // #ifndef DEBUG
 #if !defined(DEBUG) && !defined(PROFILING)
-#define updateWithIndirection(info, p1, p2)                            \
+#define updateWithIndirection(info, ind_info, p1, p2, and_then)                \
   {                                                                    \
     bdescr *bd;                                                                \
                                                                        \
     bd = Bdescr((P_)p1);                                               \
     if (bd->gen_no == 0) {                                             \
       ((StgInd *)p1)->indirectee = p2;                                 \
-      SET_INFO(p1,&stg_IND_info);                                      \
+      SET_INFO(p1,ind_info);                                           \
       TICK_UPD_NEW_IND();                                              \
+      and_then;                                                                \
     } else {                                                           \
       ((StgIndOldGen *)p1)->indirectee = p2;                           \
       if (info != &stg_BLACKHOLE_BQ_info) {                            \
@@ -184,6 +183,7 @@ recordOldToNewPtrs(StgMutClosure *p)
       }                                                                        \
       SET_INFO(p1,&stg_IND_OLDGEN_info);                               \
       TICK_UPD_OLD_IND();                                              \
+      and_then;                                                                \
     }                                                                  \
   }
 #elif defined(PROFILING)
@@ -197,7 +197,7 @@ recordOldToNewPtrs(StgMutClosure *p)
 //   the invariants that every closure keeps its creation time in the profiling
 //   field. So, we call LDV_recordCreate().
 
-#define updateWithIndirection(info, p1, p2)                            \
+#define updateWithIndirection(info, ind_info, p1, p2, and_then)                \
   {                                                                    \
     bdescr *bd;                                                                \
                                                                        \
@@ -205,9 +205,10 @@ recordOldToNewPtrs(StgMutClosure *p)
     bd = Bdescr((P_)p1);                                               \
     if (bd->gen_no == 0) {                                             \
       ((StgInd *)p1)->indirectee = p2;                                 \
-      SET_INFO(p1,&stg_IND_info);                                      \
+      SET_INFO(p1,ind_info);                                           \
       LDV_recordCreate((p1));                                           \
       TICK_UPD_NEW_IND();                                              \
+      and_then;                                                                \
     } else {                                                           \
       ((StgIndOldGen *)p1)->indirectee = p2;                           \
       if (info != &stg_BLACKHOLE_BQ_info) {                            \
@@ -218,6 +219,7 @@ recordOldToNewPtrs(StgMutClosure *p)
       }                                                                        \
       SET_INFO(p1,&stg_IND_OLDGEN_info);                               \
       LDV_recordCreate((p1));                                           \
+      and_then;                                                                \
     }                                                                  \
   }
 
@@ -231,7 +233,7 @@ recordOldToNewPtrs(StgMutClosure *p)
  * already have been updated (the mutable list will get messed up
  * otherwise).
  */
-#define updateWithIndirection(info, p1, p2)                            \
+#define updateWithIndirection(info, ind_info, p1, p2, and_then)                \
   {                                                                    \
     bdescr *bd;                                                                \
                                                                        \
@@ -239,8 +241,9 @@ recordOldToNewPtrs(StgMutClosure *p)
     bd = Bdescr((P_)p1);                                               \
     if (bd->gen_no == 0) {                                             \
       ((StgInd *)p1)->indirectee = p2;                                 \
-      SET_INFO(p1,&stg_IND_info);                                      \
+      SET_INFO(p1,ind_info);                                           \
       TICK_UPD_NEW_IND();                                              \
+      and_then;                                                                \
     } else {                                                           \
       if (info != &stg_BLACKHOLE_BQ_info) {                            \
        {                                                               \
@@ -248,7 +251,7 @@ recordOldToNewPtrs(StgMutClosure *p)
          nat np = inf->layout.payload.ptrs,                            \
              nw = inf->layout.payload.nptrs, i;                        \
           if (inf->type != THUNK_SELECTOR) {                           \
-             for (i = np; i < np + nw; i++) {                          \
+             for (i = 0; i < np + nw; i++) {                           \
                ((StgClosure *)p1)->payload[i] = 0;                     \
              }                                                         \
           }                                                            \
@@ -261,6 +264,7 @@ recordOldToNewPtrs(StgMutClosure *p)
       ((StgIndOldGen *)p1)->indirectee = p2;                           \
       SET_INFO(p1,&stg_IND_OLDGEN_info);                               \
       TICK_UPD_OLD_IND();                                              \
+      and_then;                                                                \
     }                                                                  \
   }
 #endif
@@ -283,7 +287,7 @@ recordOldToNewPtrs(StgMutClosure *p)
   }
 
 #if defined(TICKY_TICKY) || defined(PROFILING)
-static inline void
+INLINE_HEADER void
 updateWithPermIndirection(const StgInfoTable *info, StgClosure *p1, StgClosure *p2) 
 {
   bdescr *bd;
@@ -326,294 +330,122 @@ updateWithPermIndirection(const StgInfoTable *info, StgClosure *p1, StgClosure *
 #endif
 
 /* -----------------------------------------------------------------------------
-   The CAF table - used to let us revert CAFs
+   The CAF table - used to let us revert CAFs in GHCi
    -------------------------------------------------------------------------- */
 
 void revertCAFs( void );
 
-#if defined(DEBUG)
-void printMutOnceList(generation *gen);
-void printMutableList(generation *gen);
-#endif /* DEBUG */
-
-/* --------------------------------------------------------------------------
-                      Address space layout macros
-   --------------------------------------------------------------------------
-
-   Here are the assumptions GHC makes about address space layout.
-   Broadly, it thinks there are three sections:
-
-     CODE    Read-only.  Contains code and read-only data (such as
-                info tables)
-             Also called "text"
-
-     DATA    Read-write data.  Contains static closures (and on some
-                architectures, info tables too)
-
-     HEAP    Dynamically-allocated closures
-
-     USER    None of the above.  The only way USER things arise right 
-             now is when GHCi allocates a constructor info table, which
-            it does by mallocing them.
-
-   Three macros identify these three areas:
-     IS_DATA(p), HEAP_ALLOCED(p)
-
-   HEAP_ALLOCED is called FOR EVERY SINGLE CLOSURE during GC.
-   It needs to be FAST.
-
-   Implementation of HEAP_ALLOCED
-   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-   Concerning HEAP, most of the time (certainly under [Static] and [GHCi],
-   we ensure that the heap is allocated above some fixed address HEAP_BASE
-   (defined in MBlock.h).  In this case we set TEXT_BEFORE_HEAP, and we
-   get a nice fast test.
-
-   Sometimes we can't be quite sure.  For example in Windows, we can't 
-   fix where our heap address space comes from.  In this case we un-set 
-   TEXT_BEFORE_HEAP. That makes it more expensive to test whether a pointer
-   comes from the HEAP section, because we need to look at the allocator's
-   address maps (see HEAP_ALLOCED macro)
-
-   Implementation of CODE and DATA
-   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-   Concerning CODE and DATA, there are three main regimes:
-
-     [Static] Totally      The segments are contiguous, and laid out 
-     statically linked     exactly as above
-
-     [GHCi] Static,        GHCi may load new modules, but it knows the
-     except for GHCi       address map, so for any given address it can
-                           still tell which section it belongs to
-
-     [DLL] OS-supported    Chunks of CODE and DATA may be mixed in 
-     dynamic loading       the address space, and we can't tell how
-
-
-   For the [Static] case, we assume memory is laid out like this
-   (in order of increasing addresses)
-
-       Start of memory
-           CODE section
-       TEXT_SECTION_END_MARKER   (usually _etext)
-           DATA section
-       DATA_SECTION_END_MARKER   (usually _end)
-           USER section
-       HEAP_BASE
-           HEAP section
-
-   For the [GHCi] case, we have to consult GHCi's dynamic linker's
-   address maps, which is done by macros
-         is_dynamically_loaded_code_or_rodata_ptr
-         is_dynamically_loaded_code_or_rwdata_ptr
-
-   For the [DLL] case, IS_DATA is really not usable at all.
- */
-
-
-#undef TEXT_BEFORE_HEAP
-#if !defined(mingw32_TARGET_OS) && !defined(cygwin32_TARGET_OS)
-#define TEXT_BEFORE_HEAP 1
-#endif
-
-extern void* TEXT_SECTION_END_MARKER_DECL;
-extern void* DATA_SECTION_END_MARKER_DECL;
-
-#ifdef darwin_TARGET_OS
-extern unsigned long macho_etext;
-extern unsigned long macho_edata;
-#define IS_CODE_PTR(p) (  ((P_)(p) < (P_)macho_etext) \
-                       || is_dynamically_loaded_code_or_rodata_ptr((char *)p) )
-#define IS_DATA_PTR(p) ( ((P_)(p) >= (P_)macho_etext && \
-                          (P_)(p) < (P_)macho_edata) \
-                       || is_dynamically_loaded_rwdata_ptr((char *)p) )
-#define IS_USER_PTR(p) ( ((P_)(p) >= (P_)macho_edata) \
-                       && is_not_dynamically_loaded_ptr((char *)p) )
-#else
-/* Take into account code sections in dynamically loaded object files. */
-#define IS_DATA_PTR(p) ( ((P_)(p) >= (P_)&TEXT_SECTION_END_MARKER && \
-                          (P_)(p) < (P_)&DATA_SECTION_END_MARKER) \
-                       || is_dynamically_loaded_rwdata_ptr((char *)p) )
-#define IS_USER_PTR(p) ( ((P_)(p) >= (P_)&DATA_SECTION_END_MARKER) \
-                       && is_not_dynamically_loaded_ptr((char *)p) )
-#endif
-
-/* --------------------------------------------------------------------------
-   Macros for distinguishing data pointers from code pointers
-   --------------------------------------------------------------------------
-
-  Specification
-  ~~~~~~~~~~~~~
-  The garbage collector needs to make some critical distinctions between pointers.
-  In particular we need
-     LOOKS_LIKE_GHC_INFO(p)          p points to an info table
-
-  For both of these macros, p is
-      *either* a pointer to a closure (static or heap allocated)
-      *or* a return address on the (Haskell) stack
-
-  (Return addresses are in fact info-pointers, so that the Haskell stack
-  looks very like a chunk of heap.)
-
-  The garbage collector uses LOOKS_LIKE_GHC_INFO when walking the stack, as it
-  walks over the "pending arguments" on its way to the next return address.
-  It is called moderately often, but not as often as HEAP_ALLOCED
-
-  ToDo: LOOKS_LIKE_GHC_INFO(p) does not return True when p points to a
-  constructor info table allocated by GHCi.  We should really rename 
-  LOOKS_LIKE_GHC_INFO to LOOKS_LIKE_GHC_RETURN_INFO.
-
-  Implementation
-  ~~~~~~~~~~~~~~
-  LOOKS_LIKE_GHC_INFO is more complicated because of the need to distinguish 
-  between static closures and info tables.  It's a known portability problem.
-  We have three approaches:
-
-  Plan A: Address-space partitioning.  
-    keep static closures in the (single, contiguous) data segment: IS_DATA_PTR(p)
-
-  Plan A can fail for two reasons:
-    * In many environments (eg. dynamic loading),
-      text and data aren't in a single contiguous range.  
-    * When we compile through vanilla C (no mangling) we sometimes
-      can't guaranteee to put info tables in the text section.  This
-      happens eg. on MacOS where the C compiler refuses to put const
-      data in the text section if it has any code pointers in it
-      (which info tables do *only* when we're compiling without
-      TABLES_NEXT_TO_CODE).
-    
-  Hence, Plan B: (compile-via-C-with-mangling, or native code generation)
-    Put a zero word before each static closure.
-    When compiling to native code, or via C-with-mangling, info tables
-    are laid out "backwards" from the address specified in the info pointer
-    (the entry code goes forward from the info pointer).  Hence, the word
-    before the one referenced the info pointer is part of the info table,
-    and is guaranteed non-zero.
-
-    For reasons nobody seems to fully understand, the statically-allocated tables
-    of INTLIKE and CHARLIKE closures can't have this zero word, so we
-    have to test separately for them.
-
-    Plan B fails altogether for the compile-through-vanilla-C route, because
-    info tables aren't laid out backwards.
-
-
-  Hence, Plan C: (unregisterised, compile-through-vanilla-C route only)
-    If we didn't manage to get info tables into the text section, then
-    we can distinguish between a static closure pointer and an info
-    pointer as follows:  the first word of an info table is a code pointer,
-    and therefore in text space, whereas the first word of a closure pointer
-    is an info pointer, and therefore not.  Shazam!
-*/
-
-
-/* When working with Win32 DLLs, static closures are identified by
-   being prefixed with a zero word. This is needed so that we can
-   distinguish between pointers to static closures and (reversed!)
-   info tables.
-
-   This 'scheme' breaks down for closure tables such as CHARLIKE,
-   so we catch these separately.
-  
-   LOOKS_LIKE_STATIC_CLOSURE() 
-       - discriminates between static closures and info tbls
-         (needed by LOOKS_LIKE_GHC_INFO() below - [Win32 DLLs only.])
-   LOOKS_LIKE_STATIC() 
-       - distinguishes between static and heap allocated data.
- */
-#if defined(ENABLE_WIN32_DLL_SUPPORT)
-            /* definitely do not enable for mingw DietHEP */
-#define LOOKS_LIKE_STATIC(r) (!(HEAP_ALLOCED(r)))
-
-/* Tiresome predicates needed to check for pointers into the closure tables */
-#define IS_CHARLIKE_CLOSURE(p) \
-    ( (P_)(p) >= (P_)stg_CHARLIKE_closure && \
-      (char*)(p) <= ((char*)stg_CHARLIKE_closure + \
-                     (MAX_CHARLIKE-MIN_CHARLIKE) * sizeof(StgIntCharlikeClosure)) )
-#define IS_INTLIKE_CLOSURE(p) \
-    ( (P_)(p) >= (P_)stg_INTLIKE_closure && \
-      (char*)(p) <= ((char*)stg_INTLIKE_closure + \
-                     (MAX_INTLIKE-MIN_INTLIKE) * sizeof(StgIntCharlikeClosure)) )
-
-#define LOOKS_LIKE_STATIC_CLOSURE(r) (((*(((unsigned long *)(r))-1)) == 0) || IS_CHARLIKE_CLOSURE(r) || IS_INTLIKE_CLOSURE(r))
-
-#elif defined(darwin_TARGET_OS) && !defined(TABLES_NEXT_TO_CODE)
-
-#define LOOKS_LIKE_STATIC(r) (!(HEAP_ALLOCED(r)))
-#define LOOKS_LIKE_STATIC_CLOSURE(r) (IS_DATA_PTR(r) && !LOOKS_LIKE_GHC_INFO(r))
-
-#else
-
-#define LOOKS_LIKE_STATIC(r) IS_DATA_PTR(r)
-#define LOOKS_LIKE_STATIC_CLOSURE(r) IS_DATA_PTR(r)
+/* -----------------------------------------------------------------------------
+   DEBUGGING predicates for pointers
 
-#endif
+   LOOKS_LIKE_INFO_PTR(p)    returns False if p is definitely not an info ptr
+   LOOKS_LIKE_CLOSURE_PTR(p) returns False if p is definitely not a closure ptr
 
+   These macros are complete but not sound.  That is, they might
+   return false positives.  Do not rely on them to distinguish info
+   pointers from closure pointers, for example.
 
-/* -----------------------------------------------------------------------------
-   Macros for distinguishing infotables from closures.
-   
-   You'd think it'd be easy to tell an info pointer from a closure pointer:
-   closures live on the heap and infotables are in read only memory.  Right?
-   Wrong!  Static closures live in read only memory and Hugs allocates
-   infotables for constructors on the (writable) C heap.
+   We don't use address-space predicates these days, for portability
+   reasons, and the fact that code/data can be scattered about the
+   address space in a dynamically-linked environment.  Our best option
+   is to look at the alleged info table and see whether it seems to
+   make sense...
    -------------------------------------------------------------------------- */
 
-/* not accurate by any means, but stops the assertions failing... */
-/* TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO */
-#define IS_HUGS_CONSTR_INFO(info)  IS_USER_PTR(info)
+#define LOOKS_LIKE_INFO_PTR(p) \
+   (p && ((StgInfoTable *)(INFO_PTR_TO_STRUCT(p)))->type != INVALID_OBJECT && \
+    ((StgInfoTable *)(INFO_PTR_TO_STRUCT(p)))->type < N_CLOSURE_TYPES)
 
-/* LOOKS_LIKE_GHC_INFO is called moderately often during GC, but
- * Certainly not as often as HEAP_ALLOCED.
- */
-#if defined(darwin_TARGET_OS) && !defined(TABLES_NEXT_TO_CODE)
-       /* Plan C, see above */
-#define LOOKS_LIKE_GHC_INFO(info) IS_CODE_PTR(((StgInfoTable *)info).entry)
-#else
-#define LOOKS_LIKE_GHC_INFO(info) (!HEAP_ALLOCED(info) \
-                                   && !LOOKS_LIKE_STATIC_CLOSURE(info))
-#endif
+#define LOOKS_LIKE_CLOSURE_PTR(p) \
+   (LOOKS_LIKE_INFO_PTR(((StgClosure *)(p))->header.info))
 
 /* -----------------------------------------------------------------------------
    Macros for calculating how big a closure will be (used during allocation)
    -------------------------------------------------------------------------- */
 
-static __inline__ StgOffset AP_sizeW    ( nat n_args )              
-{ return sizeofW(StgAP_UPD) + n_args; }
+INLINE_HEADER StgOffset PAP_sizeW   ( nat n_args )
+{ return sizeofW(StgPAP) + n_args; }
 
-static __inline__ StgOffset PAP_sizeW   ( nat n_args )              
-{ return sizeofW(StgPAP)    + n_args; }
+INLINE_HEADER StgOffset AP_STACK_sizeW ( nat size )
+{ return sizeofW(StgAP_STACK) + size; }
 
-static __inline__ StgOffset CONSTR_sizeW( nat p, nat np )  
+INLINE_HEADER StgOffset CONSTR_sizeW( nat p, nat np )
 { return sizeofW(StgHeader) + p + np; }
 
-static __inline__ StgOffset THUNK_SELECTOR_sizeW ( void )                    
+INLINE_HEADER StgOffset THUNK_SELECTOR_sizeW ( void )
 { return sizeofW(StgHeader) + MIN_UPD_SIZE; }
 
-static __inline__ StgOffset BLACKHOLE_sizeW ( void )                    
+INLINE_HEADER StgOffset BLACKHOLE_sizeW ( void )
 { return sizeofW(StgHeader) + MIN_UPD_SIZE; }
 
 /* --------------------------------------------------------------------------
- * Sizes of closures
- * ------------------------------------------------------------------------*/
+   Sizes of closures
+   ------------------------------------------------------------------------*/
 
-static __inline__ StgOffset sizeW_fromITBL( const StgInfoTable* itbl ) 
+INLINE_HEADER StgOffset sizeW_fromITBL( const StgInfoTable* itbl ) 
 { return sizeofW(StgClosure) 
        + sizeofW(StgPtr)  * itbl->layout.payload.ptrs 
        + sizeofW(StgWord) * itbl->layout.payload.nptrs; }
 
-static __inline__ StgOffset pap_sizeW( StgPAP* x )
+INLINE_HEADER StgOffset ap_stack_sizeW( StgAP_STACK* x )
+{ return AP_STACK_sizeW(x->size); }
+
+INLINE_HEADER StgOffset pap_sizeW( StgPAP* x )
 { return PAP_sizeW(x->n_args); }
 
-static __inline__ StgOffset arr_words_sizeW( StgArrWords* x )
+INLINE_HEADER StgOffset arr_words_sizeW( StgArrWords* x )
 { return sizeofW(StgArrWords) + x->words; }
 
-static __inline__ StgOffset mut_arr_ptrs_sizeW( StgMutArrPtrs* x )
+INLINE_HEADER StgOffset mut_arr_ptrs_sizeW( StgMutArrPtrs* x )
 { return sizeofW(StgMutArrPtrs) + x->ptrs; }
 
-static __inline__ StgWord tso_sizeW ( StgTSO *tso )
+INLINE_HEADER StgWord tso_sizeW ( StgTSO *tso )
 { return TSO_STRUCT_SIZEW + tso->stack_size; }
 
-#endif /* STORAGE_H */
+INLINE_HEADER StgWord bco_sizeW ( StgBCO *bco )
+{ return bco->size; }
+
+/* -----------------------------------------------------------------------------
+   Sizes of stack frames
+   -------------------------------------------------------------------------- */
+
+INLINE_HEADER StgWord stack_frame_sizeW( StgClosure *frame )
+{
+    StgRetInfoTable *info;
+
+    info = get_ret_itbl(frame);
+    switch (info->i.type) {
+
+    case RET_DYN:
+    {
+       StgRetDyn *dyn = (StgRetDyn *)frame;
+       return  sizeofW(StgRetDyn) + RET_DYN_BITMAP_SIZE + 
+           RET_DYN_NONPTR_REGS_SIZE +
+           GET_PTRS(dyn->liveness) + GET_NONPTRS(dyn->liveness);
+    }
+           
+    case RET_FUN:
+       return sizeofW(StgRetFun) + ((StgRetFun *)frame)->size;
+
+    case RET_BIG:
+    case RET_VEC_BIG:
+       return 1 + info->i.layout.large_bitmap->size;
+
+    case RET_BCO:
+       return 2 + BCO_BITMAP_SIZE((StgBCO *)((P_)frame)[1]);
+
+    default:
+       return 1 + BITMAP_SIZE(info->i.layout.bitmap);
+    }
+}
+
+/* -----------------------------------------------------------------------------
+   Debugging bits
+   -------------------------------------------------------------------------- */
+
+#if defined(DEBUG)
+void printMutOnceList(generation *gen);
+void printMutableList(generation *gen);
+#endif
 
+#endif // STORAGE_H