// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Heap map, 64-bit version // See malloc.h and mheap.c for overview. #include "runtime.h" #include "malloc.h" #if __SIZEOF_POINTER__ == 8 // 3-level radix tree mapping page ids to Span*. void runtime_MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr)) { m->allocator = allocator; } MSpan* runtime_MHeapMap_Get(MHeapMap *m, PageID k) { int32 i1, i2, i3; i3 = k & MHeapMap_Level3Mask; k >>= MHeapMap_Level3Bits; i2 = k & MHeapMap_Level2Mask; k >>= MHeapMap_Level2Bits; i1 = k & MHeapMap_Level1Mask; k >>= MHeapMap_Level1Bits; if(k != 0) runtime_throw("MHeapMap_Get"); return m->p[i1]->p[i2]->s[i3]; } MSpan* runtime_MHeapMap_GetMaybe(MHeapMap *m, PageID k) { int32 i1, i2, i3; MHeapMapNode2 *p2; MHeapMapNode3 *p3; i3 = k & MHeapMap_Level3Mask; k >>= MHeapMap_Level3Bits; i2 = k & MHeapMap_Level2Mask; k >>= MHeapMap_Level2Bits; i1 = k & MHeapMap_Level1Mask; k >>= MHeapMap_Level1Bits; if(k != 0) runtime_throw("MHeapMap_Get"); p2 = m->p[i1]; if(p2 == nil) return nil; p3 = p2->p[i2]; if(p3 == nil) return nil; return p3->s[i3]; } void runtime_MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s) { int32 i1, i2, i3; i3 = k & MHeapMap_Level3Mask; k >>= MHeapMap_Level3Bits; i2 = k & MHeapMap_Level2Mask; k >>= MHeapMap_Level2Bits; i1 = k & MHeapMap_Level1Mask; k >>= MHeapMap_Level1Bits; if(k != 0) runtime_throw("MHeapMap_Set"); m->p[i1]->p[i2]->s[i3] = s; } // Allocate the storage required for entries [k, k+1, ..., k+len-1] // so that Get and Set calls need not check for nil pointers. bool runtime_MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len) { uintptr end; int32 i1, i2; MHeapMapNode2 *p2; MHeapMapNode3 *p3; end = k+len; while(k < end) { if((k >> MHeapMap_TotalBits) != 0) return false; i2 = (k >> MHeapMap_Level3Bits) & MHeapMap_Level2Mask; i1 = (k >> (MHeapMap_Level3Bits + MHeapMap_Level2Bits)) & MHeapMap_Level1Mask; // first-level pointer if((p2 = m->p[i1]) == nil) { p2 = m->allocator(sizeof *p2); if(p2 == nil) return false; mstats.heapmap_sys += sizeof *p2; m->p[i1] = p2; } // second-level pointer if(p2->p[i2] == nil) { p3 = m->allocator(sizeof *p3); if(p3 == nil) return false; mstats.heapmap_sys += sizeof *p3; p2->p[i2] = p3; } // advance key past this leaf node k = ((k >> MHeapMap_Level3Bits) + 1) << MHeapMap_Level3Bits; } return true; } #endif /* __SIZEOF_POINTER__ == 8 */