#ifndef TITANIUM_GC_H #define TITANIUM_GC_H #include "config.h" #include "backend.h" #if defined(USE_DISTRIBUTED_GC) && !defined(USE_GC_NONE) /* DOB: * The distributed collector has 3 entry points for marking escaping pointers: * * GC_PTR_ESC() is used only to mark a contiguous block of global pointers (only) * that is about to be transferred to a remote processor * GC_PTR_ESC_ALL() is used to scan a region of bytes about to be transferred to a * remote processor and conservatively treat the entire contents as potential local pointers * (which may also include some global pointers). * This entry point is the safest and most conservative option, but should be used sparingly * and only when better type information is not available, as it can burden the hash table unnecessarily * GC_PTR_ESC_ALL_GPS() is used to scan a region of bytes about to be transferred to a * remote processor, where it is statically known that any embedded pointers must be in the form * of global pointers (jGPointers) and there are NO LOCAL POINTERS contained in the region * which need to be considered live after the transfer. This option allows the scanning a * region with imprecise type info while using some intelligence to discern the pointers. */ # define GC_PTR_ESC(addrblock, num_gps) dgc_ptr_esc((void *)(addrblock),(num_gps),0) # define GC_PTR_ESC_ALL(addrblock, num_bytes) dgc_ptr_esc_all((void *)(addrblock),(num_bytes),0) # define GC_PTR_ESC_ALL_GPS(addrblock, num_bytes) dgc_ptr_esc_all_gps((void *)(addrblock),(num_bytes),0) /* AM_handler_context should be set to 1 if called from the context of an AM handler, or 0 otherwise */ extern void dgc_ptr_esc(void *addrblock, int num_gps, int AM_handler_context); extern void dgc_ptr_esc_all(void *mem, int num_bytes, int AM_handler_context); extern void dgc_ptr_esc_all_gps(void *mem, int num_bytes, int AM_handler_context); extern void dgc_init(void); int dgc_numhashed(void); #else # define GC_PTR_ESC(addrblock, num_gps) # define GC_PTR_ESC_ALL(addrblock, num_bytes) # define GC_PTR_ESC_ALL_GPS(addrblock, num_bytes) #endif /* IF_DISTGC(safeStmt, optStmt) provides a succinct way to choose the appropriate command based on whether the distributed GC is in use */ #if defined(USE_DISTRIBUTED_GC) && !defined(USE_GC_NONE) extern int GC_dont_gc; #define IF_DISTGC(safeStmt, optStmt) do { \ if (GC_dont_gc) { optStmt; } \ else { safeStmt; } \ } while (0) #else #define IF_DISTGC(safeStmt, optStmt) do { optStmt; } while (0) #endif extern void print_mem_stats(int gcstats, int regionstats); extern void print_outofmem(int sz) __attribute__ ((noreturn)); #ifdef NOMEMCHECKS #define ti_alloccheck(p,s) (p) #else INLINE_MODIFIER void *ti_alloccheck(void *p, int sz) { if (PREDICT_FALSE(p == NULL)) print_outofmem(sz); return p; } #endif #ifdef USE_GC_NONE # define ti_malloc(s) ti_alloccheck(calloc(1, s),s) # define ti_malloc_atomic(s) ti_alloccheck(calloc(1, s),s) # define ti_malloc_huge(s) ti_alloccheck(calloc(1, s),s) # define ti_malloc_atomic_huge(s) ti_alloccheck(calloc(1, s),s) # define ti_gc_stack_init(x) ((void) 0) # define ti_gc_mem_init() ((void) 0) # define ti_region_push_all(x,y) ((void) 0) # define ti_free free # define ti_region_get_mem(s) ti_alloccheck(nogc_region_get_mem, s) #define ti_gc_usedheapsize() (-1) #define ti_gc_totalheapsize() (-1) #define ti_gc_freeheapsize() (-1) #include /* in runtime/pages.c */ extern void *nogc_region_get_mem(size_t s); #else /* USE_GC_NONE */ /* Use Boehm-Weiser GC, at the very least to manage memory */ extern void (*ti_gc_other_roots_pusher)(); extern void GC_push_region_roots(); /* This is the call the Boehm-Weiser GC uses to request memory from us. Size is a multiple of GC_page_size, and we must return something that is at an address that is a multiple of GC_page_size */ char *get_memory_from_titanium(unsigned long size); char *GC_unix_get_mem(unsigned long size); #define ti_region_get_mem(s) ti_alloccheck(GC_unix_get_mem(s),s) # if defined(MEMORY_DISTRIBUTED) && !defined(USE_DISTRIBUTED_GC) /* The following lives in runtime/pages.c */ extern void *ti_dist_malloc(size_t); # define ti_malloc(s) ti_alloccheck(ti_dist_malloc(s), s) # define ti_malloc_atomic(s) ti_alloccheck(GC_malloc_atomic_uncollectable(s), s) # define ti_malloc_huge(s) ti_alloccheck(ti_dist_malloc(s), s) # define ti_malloc_atomic_huge(s) ti_alloccheck(GC_malloc_atomic_uncollectable(s), s) # define ti_region_push_all(b,t) GC_push_all_stack((void*)(b),(void*)(t)) # define ti_free GC_free # else /* MEMORY_DISTRIBUTED */ /* * Note: when allocating memory using the "huge" allocators, you must * ensure that there will be a live pointer to within the first 256 * bytes of the block of memory for the duration of its lifetime. */ # define ti_malloc(s) ti_alloccheck(GC_malloc(s), s) # define ti_malloc_atomic(s) ti_alloccheck(GC_malloc_atomic(s), s) # define ti_malloc_huge(s) ti_alloccheck(GC_malloc_ignore_off_page(s), s) # define ti_malloc_atomic_huge(s) ti_alloccheck(GC_malloc_atomic_ignore_off_page(s), s) # define ti_region_push_all(b,t) GC_push_all_stack((void*)(b),(void*)(t)) # define ti_free GC_free # endif /* MEMORY_DISTRIBUTED */ # define ti_gc_stack_init(x) (GC_stackbottom = (ptr_t)(x)) # define ti_gc_mem_init() \ do { \ if (getenvMaster("TI_NOGC")) { \ if (!getenvMaster("TI_BACKEND_SILENT")) \ printf("Disabling GC.\n"); \ GC_dont_gc = 1; \ } \ ti_gc_other_roots_pusher = GC_push_other_roots; \ GC_push_other_roots = GC_push_region_roots; \ GC_malloc(1); \ } while(0) #define ti_gc_usedheapsize() (GC_get_heap_size() - GC_get_free_bytes()) #define ti_gc_totalheapsize() (GC_get_heap_size()) #define ti_gc_freeheapsize() (GC_get_free_bytes()) # undef TRUE # undef FALSE # include # include /* This is the call the Boehm-Weiser GC uses to request memory from us. Size is a multiple of GC_page_size, and we must return something that is at an address that is a multiple of GC_page_size */ /* In runtime/pages.c */ char *get_titanium_memory(GC_word bytes); ptr_t GC_unix_get_mem(word); #endif /* USE_GC_NONE */ #endif /* !TITANIUM_GC_H */