static void mark(void) { uintptr blsize, nobj; struct root_list *pl; // Figure out how big an object stack we need. // Get a new one if we need more than we have // or we need significantly less than we have. nobj = mstats.heap_objects; if(nobj > (uintptr)(ebl - bl) || nobj < (uintptr)(ebl-bl)/4) { if(bl != nil) runtime_SysFree(bl, (byte*)ebl - (byte*)bl); // While we're allocated a new object stack, // add 20% headroom and also round up to // the nearest page boundary, since mmap // will anyway. nobj = nobj * 12/10; blsize = nobj * sizeof *bl; blsize = (blsize + 4095) & ~4095; nobj = blsize / sizeof *bl; bl = runtime_SysAlloc(blsize); ebl = bl + nobj; } for(pl = roots; pl != nil; pl = pl->next) { struct root* pr = &pl->roots[0]; while(1) { void *decl = pr->decl; if(decl == nil) break; scanblock(decl, pr->size); pr++; } } scanblock((byte*)&m0, sizeof m0); scanblock((byte*)&finq, sizeof finq); runtime_MProf_Mark(scanblock); // mark stacks __go_scanstacks(scanblock); // mark things pointed at by objects with finalizers runtime_walkfintab(markfin, scanblock); }
static void scanblock(int32 depth, byte *b, int64 n) { int32 off; void *obj; uintptr size; uint32 *refp, ref; void **vp; int64 i; if(Debug > 1) printf("%d scanblock %p %D\n", depth, b, n); off = (uint32)(uintptr)b & (PtrSize-1); if(off) { b += PtrSize - off; n -= PtrSize - off; } vp = (void**)b; n /= PtrSize; for(i=0; i<n; i++) { obj = vp[i]; if(obj == nil) continue; if(mheap.closure_min != nil && mheap.closure_min <= (byte*)obj && (byte*)obj < mheap.closure_max) { if((((uintptr)obj) & 63) != 0) continue; // Looks like a Native Client closure. // Actual pointer is pointed at by address in first instruction. // Embedded pointer starts at byte 2. // If it is f4f4f4f4 then that space hasn't been // used for a closure yet (f4 is the HLT instruction). // See nacl/386/closure.c for more. void **pp; pp = *(void***)((byte*)obj+2); if(pp == (void**)0xf4f4f4f4) // HLT... - not a closure after all continue; obj = *pp; } if(mheap.min <= (byte*)obj && (byte*)obj < mheap.max) { if(mlookup(obj, &obj, &size, nil, &refp)) { ref = *refp; switch(ref & ~RefFlags) { case RefNone: if(Debug > 1) printf("%d found at %p: ", depth, &vp[i]); *refp = RefSome | (ref & RefFlags); if(!(ref & RefNoPointers)) scanblock(depth+1, obj, size); break; } } } } }
static void markfin(void *v) { uintptr size; uint32 *refp; size = 0; refp = nil; if(!runtime_mlookup(v, (byte**)&v, &size, nil, &refp) || !(*refp & RefHasFinalizer)) runtime_throw("mark - finalizer inconsistency"); // do not mark the finalizer block itself. just mark the things it points at. scanblock(v, size); }
static void mark(void) { G *gp; // mark data+bss. // skip mheap itself, which has no interesting pointers // and is mostly zeroed and would not otherwise be paged in. scanblock(0, data, (byte*)&mheap - data); scanblock(0, (byte*)(&mheap+1), end - (byte*)(&mheap+1)); // mark stacks for(gp=allg; gp!=nil; gp=gp->alllink) { switch(gp->status){ default: printf("unexpected G.status %d\n", gp->status); throw("mark - bad status"); case Gdead: break; case Grunning: case Grecovery: if(gp != g) throw("mark - world not stopped"); scanstack(gp); break; case Grunnable: case Gsyscall: case Gwaiting: scanstack(gp); break; } } // mark things pointed at by objects with finalizers walkfintab(markfin); }
static void scanstack(G *gp) { Stktop *stk; byte *sp; if(gp == g) sp = (byte*)&gp; else sp = gp->sched.sp; if(Debug > 1) printf("scanstack %d %p\n", gp->goid, sp); stk = (Stktop*)gp->stackbase; while(stk) { scanblock(0, sp, (byte*)stk - sp); sp = stk->gobuf.sp; stk = (Stktop*)stk->stackbase; } }