#ifndef TITANIUM_GC_H #define TITANIUM_GC_H #include "ti_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) #define IF_DISTGC(safeStmt, optStmt) do { \ if (ti_never_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)); void ti_get_region_stats(jlong *regionTotalHeapSize, jlong *regionHeapInUse); TI_INLINE(_ti_regionTotalSize) jlong _ti_regionTotalSize() { jlong totalSize; ti_get_region_stats(&totalSize, NULL); return totalSize; } #ifdef NOMEMCHECKS #define ti_alloccheck_notrace(p,s) ((void *)(p)) #else TI_INLINE(_ti_alloccheck) void *_ti_alloccheck(void *p, int sz) { if (PREDICT_FALSE(p == NULL)) print_outofmem(sz); return p; } #define ti_alloccheck_notrace(p,s) (_ti_alloccheck(p,s)) #endif #define ti_alloccheck(opname,p,s) (ti_trace_alloc(opname,1,s),ti_alloccheck_notrace(p,s)) #ifdef USE_GC_NONE /* atomic allocators do NOT clear the memory, * non-atomic allocators DO clear the memory */ # define ti_malloc(s) ti_alloccheck(ti_malloc, calloc(1, s),s) # define ti_malloc_atomic(s) ti_alloccheck(ti_malloc_atomic, malloc(s),s) # define ti_malloc_huge(s) ti_alloccheck(ti_malloc_huge, calloc(1, s),s) # define ti_malloc_atomic_huge(s) ti_alloccheck(ti_malloc_atomic_huge, malloc(s),s) # define ti_malloc_atomic_uncollectable(s) ti_alloccheck(ti_malloc_atomic_uncollectable, malloc(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(p) (ti_trace_free(ti_free), free(p)) # define ti_region_get_mem(s) ti_alloccheck_notrace(nogc_region_get_mem(s), s) # define ti_gc() ((void) 0) #define ti_gc_usedheapsize() (-1) #define ti_gc_totalheapsize() (-1) #define ti_gc_freeheapsize() (-1) jlong _ti_timalloc_sz; #define ti_trace_free(opname) \ (ti_trace_printf(("HEAPOP %s GC Heap size: %10llu total " \ "Region Heap Size: %10llu total", \ #opname, \ (long long unsigned)_ti_timalloc_sz, \ (long long unsigned)_ti_regionTotalSize())), \ ((void)0)) #define ti_trace_alloc(opname,isgc,sz) \ (ti_trace_printf(("HEAPOP %s(%i) GC Heap size: %10llu total " \ "Region Heap Size: %10llu total", \ #opname,(int)(sz), \ (long long unsigned)_ti_timalloc_sz, \ (long long unsigned)_ti_regionTotalSize())), \ (isgc?_ti_timalloc_sz+=sz:0),((void)0)) #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 int ti_never_gc; /* set true iff all collections are disabled using TI_NOGC */ /* ------------- Internal GC stuff we rely on -------------- */ extern int GC_dont_gc; /* switch to disable all collections */ extern void ti_push_region_roots(); /* our routine that pushes region roots on demand */ extern void (*GC_push_other_roots)(void); /* callback ptr we set in GC to get a callback to push regions */ extern void (*ti_gc_other_roots_pusher)(); /* stores old value of the other roots pusher */ /* This is the call we make to the Boehm-Weiser GC to request memory Size is a multiple of GC_page_size, and must return something that is at an address that is a multiple of GC_page_size */ char *GC_unix_get_mem(unsigned long size); #define ti_region_get_mem(s) ti_alloccheck_notrace(GC_unix_get_mem(s),s) extern void GC_push_all_stack (char * b, char * t); # define ti_region_push_all(b,t) GC_push_all_stack((void*)(b),(void*)(t)) # define ti_free(p) (ti_trace_free(ti_free),GC_free(p)) # define ti_gc() if (!ti_never_gc) { ti_trace_free(ti_gc); GC_gcollect(); } /* -------------------------------------------------------- */ # 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_malloc, ti_dist_malloc(s), s) # define ti_malloc_atomic(s) ti_alloccheck(ti_malloc_atomic, GC_malloc_atomic_uncollectable(s), s) # define ti_malloc_huge(s) ti_alloccheck(ti_malloc_huge, ti_dist_malloc(s), s) # define ti_malloc_atomic_huge(s) ti_alloccheck(ti_malloc_atomic_huge, GC_malloc_atomic_uncollectable(s), s) # define ti_malloc_atomic_uncollectable(s) ti_alloccheck(ti_malloc_atomic_uncollectable, GC_malloc_atomic_uncollectable(s), s) # 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(ti_malloc, GC_malloc(s), s) # define ti_malloc_atomic(s) ti_alloccheck(ti_malloc_atomic, GC_malloc_atomic(s), s) # define ti_malloc_huge(s) ti_alloccheck(ti_malloc_huge, GC_malloc_ignore_off_page(s), s) # define ti_malloc_atomic_huge(s) ti_alloccheck(ti_malloc_atomic_huge, GC_malloc_atomic_ignore_off_page(s), s) # define ti_malloc_atomic_uncollectable(s) ti_alloccheck(ti_malloc_atomic_uncollectable, GC_malloc_atomic_uncollectable(s), s) # endif /* MEMORY_DISTRIBUTED */ #ifdef __ia64__ #define ti_gc_stack_init(x) ((void)0) /* avoid warnings about Itanium reg stack */ #else #define ti_gc_stack_init(x) (GC_stackbottom = (void *)(x)) #endif # define ti_gc_mem_init() \ do { \ if (getenvMaster("TI_NOGC")) { \ if (!getenvMaster("TI_BACKEND_SILENT")) \ printf("Disabling GC.\n"); \ ti_never_gc = 1; \ GC_dont_gc = 1; \ } \ GC_INIT(); \ GC_malloc(1); \ ti_gc_other_roots_pusher = GC_push_other_roots; \ GC_push_other_roots = ti_push_region_roots; \ } 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()) #define ti_trace_free(opname) \ (ti_trace_printf(("HEAPOP %s GC Heap size: %10llu total, %10llu free " \ "Region Heap Size: %10llu total", \ #opname, \ (long long unsigned)ti_gc_totalheapsize(), \ (long long unsigned)ti_gc_freeheapsize(), \ (long long unsigned)_ti_regionTotalSize())), \ ((void)0)) #define ti_trace_alloc(opname,isgc,sz) \ (ti_trace_printf(("HEAPOP %s(%i) GC Heap size: %10llu total, %10llu free" \ " Region heap size: %10llu total", \ #opname, (int)(sz), \ (long long unsigned)ti_gc_totalheapsize(), \ (long long unsigned)ti_gc_freeheapsize(), \ (long long unsigned)_ti_regionTotalSize())), \ ((void)0)) # include #if 0 /* currently do not need or install this */ # include #endif #endif /* USE_GC_NONE */ #endif /* !TITANIUM_GC_H */