#ifndef __REGION #define __REGION /* This implementation assumes 32 bit pointers in the use of private region addresses as RegionId's and in calls to DEREF_GLOBAL to read remote pointers (Split-C backend) */ #include "ti_config.h" #include "backend.h" #include "runtime-options.h" #include "static-global.h" #include #include #include "region-struct.h" #include "ti-memory.h" #include "primitives.h" #include "gasnet_tools.h" #if SIZEOF_VOID_P == 8 # define LARGE_ADDRESSES #endif typedef struct T6Region4lang2ti *Region; typedef struct T6Region4lang2ti RegionStruct; struct T12SharedRegion4lang2ti; struct T13PrivateRegion4lang2ti; /* We use configure to detect the page size (should match that used by the Boehm-Weiser GC) */ #ifdef _CRAYT3E /* Cray T3E is an oddball - no fixed page size, so use 8KB */ #define RPAGESIZE 8192 #define RPAGELOG 13 #else #define RPAGESIZE GASNETT_PAGESIZE #define RPAGELOG GASNETT_PAGESHIFT #endif #ifdef WIDE_POINTERS typedef GP_type(RegionStruct) GRegion; typedef GP_type(jIntPointer) GP_jIntPointer; #else typedef Region GRegion; #endif #define FREEPAGE ((RegionId) -1L) /* Id of a free page */ #if !BOUNDS_CHECKING #define NMEMDEBUG #endif #ifdef NMEMDEBUG #define ASSERT_FREE(p) 0 #define ASSERT_INUSE(p, r) 0 #else #define ASSERT_FREE(p) assert(PL2RegionId(p) == FREEPAGE) #define ASSERT_INUSE(p, r) assert(PL2RegionId(p) == Region2RegionId((r))) #endif void region_init(void); struct T12SharedRegion4lang2ti *newsregion(void); struct T13PrivateRegion4lang2ti *newpregion(void); Region newregion(void); void initregion(Region r); void *_ralloc(Region r, size_t size); const void *_ralloc_atomic(Region r, size_t size); #define ralloc(region,sz) \ (ti_trace_alloc(ralloc,0,sz), _ralloc(region, sz)) #define ralloc_atomic(region,sz) \ (ti_trace_alloc(ralloc_atomic,0,sz), _ralloc_atomic(region, sz)) int deleteregion(Region r); void ti_get_region_stats(jlong *regionTotalHeapSize, jlong *regionHeapInUse); /* all the thread-specific region state */ typedef struct { int rstart; Region allregions; unsigned long nextSharedId; #ifndef BACKEND_UNIPROC #define MAXSREGIONS 1024 Region sregionidmap[MAXSREGIONS >> 1]; #endif } ti_region_threadinfo_t; #ifdef MEMORY_SHARED extern ti_region_threadinfo_t *_ti_region_threadinfo; #define ti_myregioninfo() (&(_ti_region_threadinfo[MYBOXPROC])) #define ti_hisregioninfo(boxthread) (&(_ti_region_threadinfo[boxthread])) #define ti_initregioninfo() do { \ assert(_ti_region_threadinfo == NULL); \ _ti_region_threadinfo = (ti_region_threadinfo_t *) \ ti_malloc(MYBOXPROCS*sizeof(ti_region_threadinfo_t)); \ } while (0) #else extern ti_region_threadinfo_t _ti_region_threadinfo; #define ti_myregioninfo() (&_ti_region_threadinfo) #define ti_hisregioninfo(boxthread) (assert(boxthread==0),&_ti_region_threadinfo) #define ti_initregioninfo() #endif #ifndef BACKEND_UNIPROC /* On all backends but the uniprocessor one, region id's for private regions are just the address of the region, region id's of shared regions are odd numbers. The local representative of a shared region can be found (given the shared region id) by consulting the sregionidmap table. Shared region id 1 is actually garbage collected memory. */ typedef jIntPointer RegionId; #define UNK_REGIONID ((RegionId) 1) #define SHARED_REGIONID(rid) ((rid) & 1) TI_INLINE(RegionId2Region) Region RegionId2Region(RegionId rid) { if (rid & 1) return ti_myregioninfo()->sregionidmap[rid >> 1]; else return (Region)rid; } #define Region2RegionId(r) ((r)->id) TI_INLINE(MyRegion) Region MyRegion(Region r) { if (!r) return NULL; /* Returns our representative for region r */ return RegionId2Region(r->id); } #else /* BACKEND_UNIPROC */ /* regions and region ids are the same thing */ typedef Region RegionId; extern struct T6Region4lang2ti zeroregion; #define UNK_REGIONID &zeroregion #define SHARED_REGIONID(rid) ((rid)->id & 1) #define Region2RegionId(r) (r) #define RegionId2Region(r) (r) /* uniproc backend */ #define MyRegion(r) (r) #endif /* BACKEND_UNIPROC */ typedef jUIntPointer PageId, IntPtr; #ifndef LARGE_ADDRESSES #define MAXMEMBITS 32 #define MAXPAGE (1 << (MAXMEMBITS - RPAGELOG)) extern RegionId __regionmap[]; TI_INLINE(SetRegionId) void SetRegionId(PageId pagenb, RegionId rid) { __regionmap[pagenb] = rid; } TI_INLINE(Page2RegionId) RegionId Page2RegionId(PageId pnb) { return __regionmap[pnb]; } #ifdef MEMORY_DISTRIBUTED typedef GP_type(RegionId) GP_RegionId; TI_INLINE(GPage2RegionId) RegionId GPage2RegionId(int box, int proc, PageId pnb) { RegionId rv; GP_RegionId ga; TO_GLOBALB_STATIC(ga, box, __regionmap + pnb); DEREF_GLOBAL_lp(rv, ga); return rv; } #endif #else /* We use a two-level "page table". The upper MEMSLICE1 bits are assumed to be all 0 or all 1 (and are ignored). */ #define MAXMEMBITS 64 #define MEMSLICE1 15 #define MEMSLICE2 18 #define MEMSLICE3 (MAXMEMBITS - RPAGELOG - MEMSLICE1 - MEMSLICE2) #ifdef NMEMDEBUG #define CHECK_VALID_PAGE(pid) 0 #define CHECK_VALID_PTR(p) 0 #else #if 1 /* don't assume top bits are all zero - that assumption is invalid on Itanium-linux */ extern PageId large_page_top_bits; extern int large_page_top_bits_set; #define CHECK_VALID_PAGE(pid) \ /*printf("%08x %08x\n",(int)(pid>>32),(int)(pid&0x0FFFFFFFF));*/\ assert(pid == 0 || (large_page_top_bits_set ? \ (((pid) >> (MEMSLICE2 + MEMSLICE3)) == large_page_top_bits) :\ (large_page_top_bits = ((pid) >> (MEMSLICE2+MEMSLICE3)), (large_page_top_bits_set = 1)))); #else #define CHECK_VALID_PAGE(pid) \ assert((pid) >> (MEMSLICE2 + MEMSLICE3) == 0 || \ (pid) >> (MEMSLICE2 + MEMSLICE3) == (1 << MEMSLICE1) - 1); #endif #define CHECK_VALID_PTR(p) CHECK_VALID_PAGE((p) >> RPAGELOG) #endif extern RegionId *__regiontable[]; void SetRegionId(PageId pagenb, RegionId rid); TI_INLINE(Page2RegionId) RegionId Page2RegionId(PageId pnb) { IntPtr offset2 = (pnb >> MEMSLICE3) & ((1 << MEMSLICE2) - 1); IntPtr offset3 = pnb & ((1 << MEMSLICE3) - 1); CHECK_VALID_PAGE(pnb); /* Check if indirect table is present */ if (__regiontable[offset2]) { return __regiontable[offset2][offset3]; } else { /* If the indirect table is not there, the value is assumed to be ... */ return UNK_REGIONID; } } #ifdef MEMORY_DISTRIBUTED /* This is slow. Things should be done differently (this probably involves moving the checking into the active message handler anyway, so will do this when I implement reference counting) */ typedef GP_type(RegionId) GP_RegionId; typedef RegionId* RegionIdPtr; typedef GP_type(RegionIdPtr) GP_RegionIdPtr; TI_INLINE(GPage2RegionId) RegionId GPage2RegionId(int box, int proc, PageId pnb) { IntPtr offset2 = (pnb >> MEMSLICE3) & ((1 << MEMSLICE2) - 1); IntPtr offset3 = pnb & ((1 << MEMSLICE3) - 1); RegionId *level2; RegionId rv; GP_RegionId ga; GP_RegionIdPtr gap; CHECK_VALID_PAGE(pnb); TO_GLOBALB_STATIC(gap, box, __regiontable + offset2); DEREF_GLOBAL_lp(level2, gap); /* Check if indirect table is present */ if (level2) { TO_GLOBALB(ga, box, level2 + offset3); DEREF_GLOBAL_lp(rv, ga); return rv; } else { /* If the indirect table is not there, the value is assumed to be ... */ return UNK_REGIONID; } } #endif #endif #define PAGENB(x) ((PageId)(x) >> RPAGELOG) #define PAGEADDR(n) ((void *)((n) << RPAGELOG)) void set_region(struct page *p, int npages, Region r); /* Mark the memory range from 'from' (inclusive) to 'to' (exclusive) as belonging to region with id 'rid' */ void set_region_range(void *from, void *to, RegionId rid); TI_INLINE(PL2RegionId) RegionId PL2RegionId(const void *p) { return Page2RegionId(PAGENB(p)); } TI_INLINE(PL2Region) Region PL2Region(const void *p) { return RegionId2Region(PL2RegionId(p)); } #ifdef MEMORY_DISTRIBUTED TI_INLINE(GRegion2RegionId) jIntPointer GRegion2RegionId(GRegion r) { jIntPointer id; GP_jIntPointer idAddr; FIELD_ADDR_GLOBAL(idAddr, r, id); DEREF_GLOBAL_lp(id, idAddr); return id; } # define PG2RegionId(p) split2RegionId(TO_BOX(p), TO_PROC(p), TO_LOCAL(p)) TI_INLINE(split2RegionId) RegionId split2RegionId(int box, int proc, const void *addr) { if (box == MYBOX || !addr) return PL2RegionId(addr); else return GPage2RegionId(box, proc, PAGENB(addr)); } # define PG2Region(p) split2Region(TO_BOX(p), TO_PROC(p), TO_LOCAL(p)) TI_INLINE(split2Region) Region split2Region(int box, int proc, const void *addr) { return RegionId2Region(split2RegionId(box, proc, addr)); } # define MyGRegion(x) MyGRegionHandler(TO_BOX(x), TO_PROC(x), (Region) (TO_LOCAL(x))) TI_INLINE(MyGRegionHandler) Region MyGRegionHandler(int box, int proc, Region r) { if (box == MYBOX) return MyRegion(r); /* Must be a shared region (otherwise we wouldn't be seeing it) */ { GRegion gp_r; TO_GLOBALB(gp_r, box, r); return ti_myregioninfo()->sregionidmap[GRegion2RegionId(gp_r) >> 1]; } } #else /* !MEMORY_DISTRIBUTED */ /* uniproc, smp-narrow, smp-wide, and pthread backends */ # ifdef WIDE_POINTERS # define GRegion2RegionId(x) Region2RegionId((Region)TO_LOCAL(x)) # define PG2RegionId(x) PL2RegionId((Region)TO_LOCAL(x)) # define PG2Region(x) PL2Region((Region)TO_LOCAL(x)) # define MyGRegion(x) MyRegion((Region)TO_LOCAL(x)) # else /* !WIDE_POINTERS */ # define GRegion2RegionId Region2RegionId # define PG2RegionId PL2RegionId # define PG2Region PL2Region # define MyGRegion(x) MyRegion((GRegion)(x)) # endif/* !WIDE_POINTERS */ #endif /* !MEMORY_DISTRIBUTED */ void sharingViolation(const char *where); #endif /* !__REGION */