X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2FStorage.h;h=838248dfea8bd4ca5ac0fabb85686ec3e8551b47;hb=557bca7326077b67324b87e4042be83638ff6581;hp=adf420754950e1ff6cff75f409a6132611d2394b;hpb=d182db3a49ecb720293666fb278c1acd54c5b31d;p=ghc-hetmet.git diff --git a/ghc/rts/Storage.h b/ghc/rts/Storage.h index adf4207..838248d 100644 --- a/ghc/rts/Storage.h +++ b/ghc/rts/Storage.h @@ -1,7 +1,7 @@ /* ----------------------------------------------------------------------------- - * $Id: Storage.h,v 1.42 2002/03/21 11:24:00 sebc Exp $ + * $Id: Storage.h,v 1.48 2003/03/21 16:18:39 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. @@ -248,7 +248,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; \ } \ } \ @@ -326,293 +326,66 @@ 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 -#ifndef mingw32_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 - -/* The HEAP_ALLOCED test below is called FOR EVERY SINGLE CLOSURE - * during GC. It needs to be FAST. - * - * BEWARE: when we're dynamically loading code (for GHCi), make sure - * that we don't load any code above HEAP_BASE, or this test won't work. - */ -#ifdef TEXT_BEFORE_HEAP -# define HEAP_ALLOCED(x) ((StgPtr)(x) >= (StgPtr)(HEAP_BASE)) -#else -/* mingw, really */ -# define HEAP_ALLOCED(x) (is_heap_alloced(x)) -#endif +/* ----------------------------------------------------------------------------- + DEBUGGING predicates for pointers + 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 -/* -------------------------------------------------------------------------- - 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(USE_MINIINTERPRETER) -#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) -#endif + 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(USE_MINIINTERPRETER) - /* Plan C, see above */ -# define LOOKS_LIKE_GHC_INFO(info) IS_CODE_PTR(((P_*)(info))[0]) -#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; } +static __inline__ StgOffset PAP_sizeW ( nat n_args ) +{ return sizeofW(StgPAP) + n_args; } -static __inline__ StgOffset PAP_sizeW ( nat n_args ) -{ return sizeofW(StgPAP) + n_args; } +static __inline__ StgOffset AP_STACK_sizeW ( nat size ) +{ return sizeofW(StgAP_STACK) + size; } -static __inline__ StgOffset CONSTR_sizeW( nat p, nat np ) +static __inline__ StgOffset CONSTR_sizeW( nat p, nat np ) { return sizeofW(StgHeader) + p + np; } -static __inline__ StgOffset THUNK_SELECTOR_sizeW ( void ) +static __inline__ StgOffset THUNK_SELECTOR_sizeW ( void ) { return sizeofW(StgHeader) + MIN_UPD_SIZE; } -static __inline__ StgOffset BLACKHOLE_sizeW ( void ) +static __inline__ StgOffset BLACKHOLE_sizeW ( void ) { return sizeofW(StgHeader) + MIN_UPD_SIZE; } /* -------------------------------------------------------------------------- - * Sizes of closures - * ------------------------------------------------------------------------*/ + Sizes of closures + ------------------------------------------------------------------------*/ static __inline__ StgOffset sizeW_fromITBL( const StgInfoTable* itbl ) { return sizeofW(StgClosure) + sizeofW(StgPtr) * itbl->layout.payload.ptrs + sizeofW(StgWord) * itbl->layout.payload.nptrs; } +static __inline__ StgOffset ap_stack_sizeW( StgAP_STACK* x ) +{ return AP_STACK_sizeW(x->size); } + static __inline__ StgOffset pap_sizeW( StgPAP* x ) { return PAP_sizeW(x->n_args); } @@ -625,5 +398,46 @@ static __inline__ StgOffset mut_arr_ptrs_sizeW( StgMutArrPtrs* x ) static __inline__ StgWord tso_sizeW ( StgTSO *tso ) { return TSO_STRUCT_SIZEW + tso->stack_size; } -#endif /* STORAGE_H */ +/* ----------------------------------------------------------------------------- + Sizes of stack frames + -------------------------------------------------------------------------- */ + +static inline 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_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