LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Garbage collector. | 5 // Garbage collector. |
6 | 6 |
7 #include "runtime.h" | 7 #include "runtime.h" |
8 #include "arch_GOARCH.h" | 8 #include "arch_GOARCH.h" |
9 #include "malloc.h" | 9 #include "malloc.h" |
10 #include "stack.h" | 10 #include "stack.h" |
11 #include "mgc0.h" | 11 #include "mgc0.h" |
12 #include "race.h" | 12 #include "race.h" |
13 #include "type.h" | 13 #include "type.h" |
14 #include "typekind.h" | 14 #include "typekind.h" |
15 #include "funcdata.h" | 15 #include "funcdata.h" |
16 #include "../../cmd/ld/textflag.h" | 16 #include "../../cmd/ld/textflag.h" |
17 | 17 |
18 enum { | 18 enum { |
19 Debug = 0, | 19 Debug = 0, |
20 DebugMark = 0, // run second pass to check mark | |
21 CollectStats = 0, | 20 CollectStats = 0, |
22 ScanStackByFrames = 1, | 21 ScanStackByFrames = 1, |
23 IgnorePreciseGC = 0, | 22 IgnorePreciseGC = 0, |
24 | 23 |
25 // Four bits per word (see #defines below). | 24 // Four bits per word (see #defines below). |
26 wordsPerBitmapWord = sizeof(void*)*8/4, | 25 wordsPerBitmapWord = sizeof(void*)*8/4, |
27 bitShift = sizeof(void*)*8/4, | 26 bitShift = sizeof(void*)*8/4, |
28 | 27 |
29 WorkbufSize = 16*1024, | 28 WorkbufSize = 16*1024, |
30 RootBlockSize = 4*1024, | 29 RootBlockSize = 4*1024, |
31 FinBlockSize = 4*1024, | 30 FinBlockSize = 4*1024, |
32 | 31 |
33 handoffThreshold = 4, | 32 handoffThreshold = 4, |
34 IntermediateBufferCapacity = 64, | 33 IntermediateBufferCapacity = 64, |
35 | 34 |
36 // Bits in type information | 35 // Bits in type information |
37 PRECISE = 1, | 36 PRECISE = 1, |
38 LOOP = 2, | 37 LOOP = 2, |
39 PC_BITS = PRECISE | LOOP, | 38 PC_BITS = PRECISE | LOOP, |
40 | 39 |
41 // Pointer map | 40 // Pointer map |
42 BitsPerPointer = 2, | 41 BitsPerPointer = 2, |
43 BitsNoPointer = 0, | 42 BitsNoPointer = 0, |
44 BitsPointer = 1, | 43 BitsPointer = 1, |
45 BitsIface = 2, | 44 BitsIface = 2, |
46 BitsEface = 3, | 45 BitsEface = 3, |
| 46 |
| 47 RootData = 0, |
| 48 RootBss = 1, |
| 49 RootFinalizers = 2, |
| 50 RootSpanTypes = 3, |
| 51 RootFlushCaches = 4, |
| 52 RootCount = 5, |
47 }; | 53 }; |
48 | 54 |
49 static struct | 55 static struct |
50 { | 56 { |
51 Lock;·· | 57 Lock;·· |
52 void* head; | 58 void* head; |
53 } pools; | 59 } pools; |
54 | 60 |
55 void | 61 void |
56 sync·runtime_registerPool(void **p) | 62 sync·runtime_registerPool(void **p) |
57 { | 63 { |
58 runtime·lock(&pools); | 64 runtime·lock(&pools); |
59 p[0] = pools.head; | 65 p[0] = pools.head; |
60 pools.head = p; | 66 pools.head = p; |
61 runtime·unlock(&pools); | 67 runtime·unlock(&pools); |
62 } | 68 } |
63 | 69 |
64 static void | 70 static void |
65 clearpools(void) | 71 clearpools(void) |
66 { | 72 { |
67 » void **p, **next; | 73 » void **pool, **next; |
68 | 74 » P *p, **pp; |
69 » for(p = pools.head; p != nil; p = next) { | 75 » int32 i; |
70 » » next = p[0]; | 76 |
71 » » p[0] = nil; // next | 77 » // clear sync.Pool's |
72 » » p[1] = nil; // slice | 78 » for(pool = pools.head; pool != nil; pool = next) { |
73 » » p[2] = nil; | 79 » » next = pool[0]; |
74 » » p[3] = nil; | 80 » » pool[0] = nil; // next |
| 81 » » pool[1] = nil; // slice |
| 82 » » pool[2] = nil; |
| 83 » » pool[3] = nil; |
75 } | 84 } |
76 pools.head = nil; | 85 pools.head = nil; |
| 86 |
| 87 // clear defer pools |
| 88 for(pp=runtime·allp; p=*pp; pp++) { |
| 89 for(i=0; i<nelem(p->deferpool); i++) |
| 90 p->deferpool[i] = nil; |
| 91 } |
77 } | 92 } |
78 | 93 |
79 // Bits in per-word bitmap. | 94 // Bits in per-word bitmap. |
80 // #defines because enum might not be able to hold the values. | 95 // #defines because enum might not be able to hold the values. |
81 // | 96 // |
82 // Each word in the bitmap describes wordsPerBitmapWord words | 97 // Each word in the bitmap describes wordsPerBitmapWord words |
83 // of heap memory. There are 4 bitmap bits dedicated to each heap word, | 98 // of heap memory. There are 4 bitmap bits dedicated to each heap word, |
84 // so on a 64-bit system there is one bitmap word per 16 heap words. | 99 // so on a 64-bit system there is one bitmap word per 16 heap words. |
85 // The bits in the word are packed together by type first, then by | 100 // The bits in the word are packed together by type first, then by |
86 // heap location, so each 64-bit bitmap word consists of, from top to bottom, | 101 // heap location, so each 64-bit bitmap word consists of, from top to bottom, |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
177 static FinBlock *allfin; // list of all blocks | 192 static FinBlock *allfin; // list of all blocks |
178 static Lock finlock; | 193 static Lock finlock; |
179 static int32 fingwait; | 194 static int32 fingwait; |
180 | 195 |
181 static void runfinq(void); | 196 static void runfinq(void); |
182 static Workbuf* getempty(Workbuf*); | 197 static Workbuf* getempty(Workbuf*); |
183 static Workbuf* getfull(Workbuf*); | 198 static Workbuf* getfull(Workbuf*); |
184 static void putempty(Workbuf*); | 199 static void putempty(Workbuf*); |
185 static Workbuf* handoff(Workbuf*); | 200 static Workbuf* handoff(Workbuf*); |
186 static void gchelperstart(void); | 201 static void gchelperstart(void); |
187 static void» scanstack(G* gp, void *scanbuf); | 202 static void» addfinroots(void *wbufp, void *v); |
| 203 static void» flushallmcaches(void); |
| 204 static void» scanframe(Stkframe *frame, void *wbufp); |
| 205 static void» addstackroots(G *gp, Workbuf **wbufp); |
188 | 206 |
189 static struct { | 207 static struct { |
190 uint64 full; // lock-free list of full blocks | 208 uint64 full; // lock-free list of full blocks |
191 uint64 empty; // lock-free list of empty blocks | 209 uint64 empty; // lock-free list of empty blocks |
192 byte pad0[CacheLineSize]; // prevents false-sharing between full/empt
y and nproc/nwait | 210 byte pad0[CacheLineSize]; // prevents false-sharing between full/empt
y and nproc/nwait |
193 uint32 nproc; | 211 uint32 nproc; |
| 212 int64 tstart; |
194 volatile uint32 nwait; | 213 volatile uint32 nwait; |
195 volatile uint32 ndone; | 214 volatile uint32 ndone; |
196 volatile uint32 debugmarkdone; | |
197 Note alldone; | 215 Note alldone; |
198 ParFor *markfor; | 216 ParFor *markfor; |
199 ParFor *sweepfor; | 217 ParFor *sweepfor; |
200 | 218 |
201 Lock; | 219 Lock; |
202 byte *chunk; | 220 byte *chunk; |
203 uintptr nchunk; | 221 uintptr nchunk; |
204 | |
205 Obj *roots; | |
206 uint32 nroot; | |
207 uint32 rootcap; | |
208 } work; | 222 } work; |
209 | 223 |
210 enum { | 224 enum { |
211 GC_DEFAULT_PTR = GC_NUM_INSTR, | 225 GC_DEFAULT_PTR = GC_NUM_INSTR, |
212 GC_CHAN, | 226 GC_CHAN, |
213 GC_G_PTR, | |
214 | 227 |
215 GC_NUM_INSTR2 | 228 GC_NUM_INSTR2 |
216 }; | 229 }; |
217 | 230 |
218 static struct { | 231 static struct { |
219 struct { | 232 struct { |
220 uint64 sum; | 233 uint64 sum; |
221 uint64 cnt; | 234 uint64 cnt; |
222 } ptr; | 235 } ptr; |
223 uint64 nbytes; | 236 uint64 nbytes; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
288 if(CollectStats) | 301 if(CollectStats) |
289 runtime·xadd64(&gcstats.markonly.foundword, 1); | 302 runtime·xadd64(&gcstats.markonly.foundword, 1); |
290 goto found; | 303 goto found; |
291 } | 304 } |
292 } | 305 } |
293 | 306 |
294 // Otherwise consult span table to find beginning. | 307 // Otherwise consult span table to find beginning. |
295 // (Manually inlined copy of MHeap_LookupMaybe.) | 308 // (Manually inlined copy of MHeap_LookupMaybe.) |
296 k = (uintptr)obj>>PageShift; | 309 k = (uintptr)obj>>PageShift; |
297 x = k; | 310 x = k; |
298 » if(sizeof(void*) == 8) | 311 » x -= (uintptr)runtime·mheap.arena_start>>PageShift; |
299 » » x -= (uintptr)runtime·mheap.arena_start>>PageShift; | |
300 s = runtime·mheap.spans[x]; | 312 s = runtime·mheap.spans[x]; |
301 if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse
) | 313 if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse
) |
302 return false; | 314 return false; |
303 p = (byte*)((uintptr)s->start<<PageShift); | 315 p = (byte*)((uintptr)s->start<<PageShift); |
304 if(s->sizeclass == 0) { | 316 if(s->sizeclass == 0) { |
305 obj = p; | 317 obj = p; |
306 } else { | 318 } else { |
307 uintptr size = s->elemsize; | 319 uintptr size = s->elemsize; |
308 int32 i = ((byte*)obj - p)/size; | 320 int32 i = ((byte*)obj - p)/size; |
309 obj = p+i*size; | 321 obj = p+i*size; |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
488 if(CollectStats) | 500 if(CollectStats) |
489 runtime·xadd64(&gcstats.flushptrbuf.foun
dword, 1); | 501 runtime·xadd64(&gcstats.flushptrbuf.foun
dword, 1); |
490 goto found; | 502 goto found; |
491 } | 503 } |
492 } | 504 } |
493 | 505 |
494 // Otherwise consult span table to find beginning. | 506 // Otherwise consult span table to find beginning. |
495 // (Manually inlined copy of MHeap_LookupMaybe.) | 507 // (Manually inlined copy of MHeap_LookupMaybe.) |
496 k = (uintptr)obj>>PageShift; | 508 k = (uintptr)obj>>PageShift; |
497 x = k; | 509 x = k; |
498 » » if(sizeof(void*) == 8) | 510 » » x -= (uintptr)arena_start>>PageShift; |
499 » » » x -= (uintptr)arena_start>>PageShift; | |
500 s = runtime·mheap.spans[x]; | 511 s = runtime·mheap.spans[x]; |
501 if(s == nil || k < s->start || obj >= s->limit || s->state != MS
panInUse) | 512 if(s == nil || k < s->start || obj >= s->limit || s->state != MS
panInUse) |
502 continue; | 513 continue; |
503 p = (byte*)((uintptr)s->start<<PageShift); | 514 p = (byte*)((uintptr)s->start<<PageShift); |
504 if(s->sizeclass == 0) { | 515 if(s->sizeclass == 0) { |
505 obj = p; | 516 obj = p; |
506 } else { | 517 } else { |
507 size = s->elemsize; | 518 size = s->elemsize; |
508 int32 i = ((byte*)obj - p)/size; | 519 int32 i = ((byte*)obj - p)/size; |
509 obj = p+i*size; | 520 obj = p+i*size; |
(...skipping 26 matching lines...) Expand all Loading... |
536 } | 547 } |
537 } | 548 } |
538 | 549 |
539 // If object has no pointers, don't need to scan further. | 550 // If object has no pointers, don't need to scan further. |
540 if((bits & bitScan) == 0) | 551 if((bits & bitScan) == 0) |
541 continue; | 552 continue; |
542 | 553 |
543 // Ask span about size class. | 554 // Ask span about size class. |
544 // (Manually inlined copy of MHeap_Lookup.) | 555 // (Manually inlined copy of MHeap_Lookup.) |
545 x = (uintptr)obj >> PageShift; | 556 x = (uintptr)obj >> PageShift; |
546 » » if(sizeof(void*) == 8) | 557 » » x -= (uintptr)arena_start>>PageShift; |
547 » » » x -= (uintptr)arena_start>>PageShift; | |
548 s = runtime·mheap.spans[x]; | 558 s = runtime·mheap.spans[x]; |
549 | 559 |
550 PREFETCH(obj); | 560 PREFETCH(obj); |
551 | 561 |
552 *wp = (Obj){obj, s->elemsize, ti}; | 562 *wp = (Obj){obj, s->elemsize, ti}; |
553 wp++; | 563 wp++; |
554 nobj++; | 564 nobj++; |
555 continue_obj:; | 565 continue_obj:; |
556 } | 566 } |
557 | 567 |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
625 sbuf->wbuf = wbuf; | 635 sbuf->wbuf = wbuf; |
626 sbuf->nobj = nobj; | 636 sbuf->nobj = nobj; |
627 } | 637 } |
628 | 638 |
629 // Program that scans the whole block and treats every block element as a potent
ial pointer | 639 // Program that scans the whole block and treats every block element as a potent
ial pointer |
630 static uintptr defaultProg[2] = {PtrSize, GC_DEFAULT_PTR}; | 640 static uintptr defaultProg[2] = {PtrSize, GC_DEFAULT_PTR}; |
631 | 641 |
632 // Hchan program | 642 // Hchan program |
633 static uintptr chanProg[2] = {0, GC_CHAN}; | 643 static uintptr chanProg[2] = {0, GC_CHAN}; |
634 | 644 |
635 // G* program | |
636 static uintptr gptrProg[2] = {0, GC_G_PTR}; | |
637 | |
638 // Local variables of a program fragment or loop | 645 // Local variables of a program fragment or loop |
639 typedef struct Frame Frame; | 646 typedef struct Frame Frame; |
640 struct Frame { | 647 struct Frame { |
641 uintptr count, elemsize, b; | 648 uintptr count, elemsize, b; |
642 uintptr *loop_or_ret; | 649 uintptr *loop_or_ret; |
643 }; | 650 }; |
644 | 651 |
645 // Sanity check for the derived type info objti. | 652 // Sanity check for the derived type info objti. |
646 static void | 653 static void |
647 checkptr(void *obj, uintptr objti) | 654 checkptr(void *obj, uintptr objti) |
648 { | 655 { |
649 uintptr *pc1, *pc2, type, tisize, i, j, x; | 656 uintptr *pc1, *pc2, type, tisize, i, j, x; |
650 byte *objstart; | 657 byte *objstart; |
651 Type *t; | 658 Type *t; |
652 MSpan *s; | 659 MSpan *s; |
653 | 660 |
654 if(!Debug) | 661 if(!Debug) |
655 runtime·throw("checkptr is debug only"); | 662 runtime·throw("checkptr is debug only"); |
656 | 663 |
657 if(obj < runtime·mheap.arena_start || obj >= runtime·mheap.arena_used) | 664 if(obj < runtime·mheap.arena_start || obj >= runtime·mheap.arena_used) |
658 return; | 665 return; |
659 type = runtime·gettype(obj); | 666 type = runtime·gettype(obj); |
660 t = (Type*)(type & ~(uintptr)(PtrSize-1)); | 667 t = (Type*)(type & ~(uintptr)(PtrSize-1)); |
661 if(t == nil) | 668 if(t == nil) |
662 return; | 669 return; |
663 x = (uintptr)obj >> PageShift; | 670 x = (uintptr)obj >> PageShift; |
664 » if(sizeof(void*) == 8) | 671 » x -= (uintptr)(runtime·mheap.arena_start)>>PageShift; |
665 » » x -= (uintptr)(runtime·mheap.arena_start)>>PageShift; | |
666 s = runtime·mheap.spans[x]; | 672 s = runtime·mheap.spans[x]; |
667 objstart = (byte*)((uintptr)s->start<<PageShift); | 673 objstart = (byte*)((uintptr)s->start<<PageShift); |
668 if(s->sizeclass != 0) { | 674 if(s->sizeclass != 0) { |
669 i = ((byte*)obj - objstart)/s->elemsize; | 675 i = ((byte*)obj - objstart)/s->elemsize; |
670 objstart += i*s->elemsize; | 676 objstart += i*s->elemsize; |
671 } | 677 } |
672 tisize = *(uintptr*)objti; | 678 tisize = *(uintptr*)objti; |
673 // Sanity check for object size: it should fit into the memory block. | 679 // Sanity check for object size: it should fit into the memory block. |
674 if((byte*)obj + tisize > objstart + s->elemsize) { | 680 if((byte*)obj + tisize > objstart + s->elemsize) { |
675 runtime·printf("object of type '%S' at %p/%p does not fit in blo
ck %p/%p\n", | 681 runtime·printf("object of type '%S' at %p/%p does not fit in blo
ck %p/%p\n", |
(...skipping 21 matching lines...) Expand all Loading... |
697 } | 703 } |
698 } | 704 } |
699 }······································· | 705 }······································· |
700 | 706 |
701 // scanblock scans a block of n bytes starting at pointer b for references | 707 // scanblock scans a block of n bytes starting at pointer b for references |
702 // to other objects, scanning any it finds recursively until there are no | 708 // to other objects, scanning any it finds recursively until there are no |
703 // unscanned objects left. Instead of using an explicit recursion, it keeps | 709 // unscanned objects left. Instead of using an explicit recursion, it keeps |
704 // a work list in the Workbuf* structures and loops in the main function | 710 // a work list in the Workbuf* structures and loops in the main function |
705 // body. Keeping an explicit work list is easier on the stack allocator and | 711 // body. Keeping an explicit work list is easier on the stack allocator and |
706 // more efficient. | 712 // more efficient. |
707 // | |
708 // wbuf: current work buffer | |
709 // wp: storage for next queued pointer (write pointer) | |
710 // nobj: number of queued objects | |
711 static void | 713 static void |
712 scanblock(Workbuf *wbuf, Obj *wp, uintptr nobj, bool keepworking) | 714 scanblock(Workbuf *wbuf, bool keepworking) |
713 { | 715 { |
714 byte *b, *arena_start, *arena_used; | 716 byte *b, *arena_start, *arena_used; |
715 » uintptr n, i, end_b, elemsize, size, ti, objti, count, type; | 717 » uintptr n, i, end_b, elemsize, size, ti, objti, count, type, nobj; |
716 uintptr *pc, precise_type, nominal_size; | 718 uintptr *pc, precise_type, nominal_size; |
717 uintptr *chan_ret, chancap; | 719 uintptr *chan_ret, chancap; |
718 void *obj; | 720 void *obj; |
719 Type *t; | 721 Type *t; |
720 Slice *sliceptr; | 722 Slice *sliceptr; |
721 Frame *stack_ptr, stack_top, stack[GC_STACK_CAPACITY+4]; | 723 Frame *stack_ptr, stack_top, stack[GC_STACK_CAPACITY+4]; |
722 BufferList *scanbuffers; | 724 BufferList *scanbuffers; |
723 Scanbuf sbuf; | 725 Scanbuf sbuf; |
724 Eface *eface; | 726 Eface *eface; |
725 Iface *iface; | 727 Iface *iface; |
726 Hchan *chan; | 728 Hchan *chan; |
727 ChanType *chantype; | 729 ChanType *chantype; |
| 730 Obj *wp; |
728 | 731 |
729 if(sizeof(Workbuf) % WorkbufSize != 0) | 732 if(sizeof(Workbuf) % WorkbufSize != 0) |
730 runtime·throw("scanblock: size of Workbuf is suboptimal"); | 733 runtime·throw("scanblock: size of Workbuf is suboptimal"); |
731 | 734 |
732 // Memory arena parameters. | 735 // Memory arena parameters. |
733 arena_start = runtime·mheap.arena_start; | 736 arena_start = runtime·mheap.arena_start; |
734 arena_used = runtime·mheap.arena_used; | 737 arena_used = runtime·mheap.arena_used; |
735 | 738 |
736 stack_ptr = stack+nelem(stack)-1; | 739 stack_ptr = stack+nelem(stack)-1; |
737 | 740 |
738 precise_type = false; | 741 precise_type = false; |
739 nominal_size = 0; | 742 nominal_size = 0; |
| 743 |
| 744 if(wbuf) { |
| 745 nobj = wbuf->nobj; |
| 746 wp = &wbuf->obj[nobj]; |
| 747 } else { |
| 748 nobj = 0; |
| 749 wp = nil; |
| 750 } |
740 | 751 |
741 // Initialize sbuf | 752 // Initialize sbuf |
742 scanbuffers = &bufferList[m->helpgc]; | 753 scanbuffers = &bufferList[m->helpgc]; |
743 | 754 |
744 sbuf.ptr.begin = sbuf.ptr.pos = &scanbuffers->ptrtarget[0]; | 755 sbuf.ptr.begin = sbuf.ptr.pos = &scanbuffers->ptrtarget[0]; |
745 sbuf.ptr.end = sbuf.ptr.begin + nelem(scanbuffers->ptrtarget); | 756 sbuf.ptr.end = sbuf.ptr.begin + nelem(scanbuffers->ptrtarget); |
746 | 757 |
747 sbuf.obj.begin = sbuf.obj.pos = &scanbuffers->obj[0]; | 758 sbuf.obj.begin = sbuf.obj.pos = &scanbuffers->obj[0]; |
748 sbuf.obj.end = sbuf.obj.begin + nelem(scanbuffers->obj); | 759 sbuf.obj.end = sbuf.obj.begin + nelem(scanbuffers->obj); |
749 | 760 |
(...skipping 315 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1065 (uintptr)chantype->elem->gc | PR
ECISE | LOOP}; | 1076 (uintptr)chantype->elem->gc | PR
ECISE | LOOP}; |
1066 if(sbuf.obj.pos == sbuf.obj.end) | 1077 if(sbuf.obj.pos == sbuf.obj.end) |
1067 flushobjbuf(&sbuf); | 1078 flushobjbuf(&sbuf); |
1068 } | 1079 } |
1069 } | 1080 } |
1070 if(chan_ret == nil) | 1081 if(chan_ret == nil) |
1071 goto next_block; | 1082 goto next_block; |
1072 pc = chan_ret; | 1083 pc = chan_ret; |
1073 continue; | 1084 continue; |
1074 | 1085 |
1075 case GC_G_PTR: | |
1076 obj = (void*)stack_top.b; | |
1077 scanstack(obj, &sbuf); | |
1078 goto next_block; | |
1079 | |
1080 default: | 1086 default: |
1081 runtime·throw("scanblock: invalid GC instruction"); | 1087 runtime·throw("scanblock: invalid GC instruction"); |
1082 return; | 1088 return; |
1083 } | 1089 } |
1084 | 1090 |
1085 if(obj >= arena_start && obj < arena_used) { | 1091 if(obj >= arena_start && obj < arena_used) { |
1086 *sbuf.ptr.pos++ = (PtrTarget){obj, objti}; | 1092 *sbuf.ptr.pos++ = (PtrTarget){obj, objti}; |
1087 if(sbuf.ptr.pos == sbuf.ptr.end) | 1093 if(sbuf.ptr.pos == sbuf.ptr.end) |
1088 flushptrbuf(&sbuf); | 1094 flushptrbuf(&sbuf); |
1089 } | 1095 } |
(...skipping 24 matching lines...) Expand all Loading... |
1114 | 1120 |
1115 // Fetch b from the work buffer. | 1121 // Fetch b from the work buffer. |
1116 --sbuf.wp; | 1122 --sbuf.wp; |
1117 b = sbuf.wp->p; | 1123 b = sbuf.wp->p; |
1118 n = sbuf.wp->n; | 1124 n = sbuf.wp->n; |
1119 ti = sbuf.wp->ti; | 1125 ti = sbuf.wp->ti; |
1120 sbuf.nobj--; | 1126 sbuf.nobj--; |
1121 } | 1127 } |
1122 } | 1128 } |
1123 | 1129 |
1124 // debug_scanblock is the debug copy of scanblock. | |
1125 // it is simpler, slower, single-threaded, recursive, | |
1126 // and uses bitSpecial as the mark bit. | |
1127 static void | |
1128 debug_scanblock(byte *b, uintptr n) | |
1129 { | |
1130 byte *obj, *p; | |
1131 void **vp; | |
1132 uintptr size, *bitp, bits, shift, i, xbits, off; | |
1133 MSpan *s; | |
1134 | |
1135 if(!DebugMark) | |
1136 runtime·throw("debug_scanblock without DebugMark"); | |
1137 | |
1138 if((intptr)n < 0) { | |
1139 runtime·printf("debug_scanblock %p %D\n", b, (int64)n); | |
1140 runtime·throw("debug_scanblock"); | |
1141 } | |
1142 | |
1143 // Align b to a word boundary. | |
1144 off = (uintptr)b & (PtrSize-1); | |
1145 if(off != 0) { | |
1146 b += PtrSize - off; | |
1147 n -= PtrSize - off; | |
1148 } | |
1149 | |
1150 vp = (void**)b; | |
1151 n /= PtrSize; | |
1152 for(i=0; i<n; i++) { | |
1153 obj = (byte*)vp[i]; | |
1154 | |
1155 // Words outside the arena cannot be pointers. | |
1156 if((byte*)obj < runtime·mheap.arena_start || (byte*)obj >= runti
me·mheap.arena_used) | |
1157 continue; | |
1158 | |
1159 // Round down to word boundary. | |
1160 obj = (void*)((uintptr)obj & ~((uintptr)PtrSize-1)); | |
1161 | |
1162 // Consult span table to find beginning. | |
1163 s = runtime·MHeap_LookupMaybe(&runtime·mheap, obj); | |
1164 if(s == nil) | |
1165 continue; | |
1166 | |
1167 p = (byte*)((uintptr)s->start<<PageShift); | |
1168 size = s->elemsize; | |
1169 if(s->sizeclass == 0) { | |
1170 obj = p; | |
1171 } else { | |
1172 int32 i = ((byte*)obj - p)/size; | |
1173 obj = p+i*size; | |
1174 } | |
1175 | |
1176 // Now that we know the object header, reload bits. | |
1177 off = (uintptr*)obj - (uintptr*)runtime·mheap.arena_start; | |
1178 bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapW
ord - 1; | |
1179 shift = off % wordsPerBitmapWord; | |
1180 xbits = *bitp; | |
1181 bits = xbits >> shift; | |
1182 | |
1183 // Now we have bits, bitp, and shift correct for | |
1184 // obj pointing at the base of the object. | |
1185 // If not allocated or already marked, done. | |
1186 if((bits & bitAllocated) == 0 || (bits & bitSpecial) != 0) // N
OTE: bitSpecial not bitMarked | |
1187 continue; | |
1188 *bitp |= bitSpecial<<shift; | |
1189 if(!(bits & bitMarked)) | |
1190 runtime·printf("found unmarked block %p in %p\n", obj, v
p+i); | |
1191 | |
1192 // If object has no pointers, don't need to scan further. | |
1193 if((bits & bitScan) == 0) | |
1194 continue; | |
1195 | |
1196 debug_scanblock(obj, size); | |
1197 } | |
1198 } | |
1199 | |
1200 // Append obj to the work buffer. | 1130 // Append obj to the work buffer. |
1201 // _wbuf, _wp, _nobj are input/output parameters and are specifying the work buf
fer. | 1131 // _wbuf, _wp, _nobj are input/output parameters and are specifying the work buf
fer. |
1202 static void | 1132 static void |
1203 enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj) | 1133 enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj) |
1204 { | 1134 { |
1205 uintptr nobj, off; | 1135 uintptr nobj, off; |
1206 Obj *wp; | 1136 Obj *wp; |
1207 Workbuf *wbuf; | 1137 Workbuf *wbuf; |
1208 | 1138 |
1209 if(Debug > 1) | 1139 if(Debug > 1) |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1246 wp++; | 1176 wp++; |
1247 nobj++; | 1177 nobj++; |
1248 | 1178 |
1249 // Save work buffer state | 1179 // Save work buffer state |
1250 *_wp = wp; | 1180 *_wp = wp; |
1251 *_wbuf = wbuf; | 1181 *_wbuf = wbuf; |
1252 *_nobj = nobj; | 1182 *_nobj = nobj; |
1253 } | 1183 } |
1254 | 1184 |
1255 static void | 1185 static void |
| 1186 enqueue1(Workbuf **wbufp, Obj obj) |
| 1187 { |
| 1188 Workbuf *wbuf; |
| 1189 |
| 1190 wbuf = *wbufp; |
| 1191 if(wbuf->nobj >= nelem(wbuf->obj)) |
| 1192 *wbufp = wbuf = getempty(wbuf); |
| 1193 wbuf->obj[wbuf->nobj++] = obj; |
| 1194 } |
| 1195 |
| 1196 static void |
1256 markroot(ParFor *desc, uint32 i) | 1197 markroot(ParFor *desc, uint32 i) |
1257 { | 1198 { |
1258 Obj *wp; | |
1259 Workbuf *wbuf; | 1199 Workbuf *wbuf; |
1260 » uintptr nobj; | 1200 » FinBlock *fb; |
| 1201 » MSpan **allspans, *s; |
| 1202 » uint32 spanidx; |
| 1203 » G *gp; |
1261 | 1204 |
1262 USED(&desc); | 1205 USED(&desc); |
1263 » wp = nil; | 1206 » wbuf = getempty(nil); |
1264 » wbuf = nil; | 1207 » switch(i) { |
1265 » nobj = 0; | 1208 » case RootData: |
1266 » enqueue(work.roots[i], &wbuf, &wp, &nobj); | 1209 » » enqueue1(&wbuf, (Obj){data, edata - data, (uintptr)gcdata}); |
1267 » scanblock(wbuf, wp, nobj, false); | 1210 » » break; |
| 1211 |
| 1212 » case RootBss: |
| 1213 » » enqueue1(&wbuf, (Obj){bss, ebss - bss, (uintptr)gcbss}); |
| 1214 » » break; |
| 1215 |
| 1216 » case RootFinalizers: |
| 1217 » » for(fb=allfin; fb; fb=fb->alllink) |
| 1218 » » » enqueue1(&wbuf, (Obj){(byte*)fb->fin, fb->cnt*sizeof(fb-
>fin[0]), 0}); |
| 1219 » » break; |
| 1220 |
| 1221 » case RootSpanTypes: |
| 1222 » » // mark span types and MSpan.specials (to walk spans only once) |
| 1223 » » allspans = runtime·mheap.allspans; |
| 1224 » » for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) { |
| 1225 » » » Special *sp; |
| 1226 » » » SpecialFinalizer *spf; |
| 1227 |
| 1228 » » » s = allspans[spanidx]; |
| 1229 » » » if(s->state != MSpanInUse) |
| 1230 » » » » continue; |
| 1231 » » » // The garbage collector ignores type pointers stored in
MSpan.types: |
| 1232 » » » // - Compiler-generated types are stored outside of hea
p. |
| 1233 » » » // - The reflect package has runtime-generated types ca
ched in its data structures. |
| 1234 » » » // The garbage collector relies on finding the refere
nces via that cache. |
| 1235 » » » if(s->types.compression == MTypes_Words || s->types.comp
ression == MTypes_Bytes) |
| 1236 » » » » markonly((byte*)s->types.data); |
| 1237 » » » for(sp = s->specials; sp != nil; sp = sp->next) { |
| 1238 » » » » if(sp->kind != KindSpecialFinalizer) |
| 1239 » » » » » continue; |
| 1240 » » » » // don't mark finalized object, but scan it so w
e |
| 1241 » » » » // retain everything it points to. |
| 1242 » » » » spf = (SpecialFinalizer*)sp; |
| 1243 » » » » enqueue1(&wbuf, (Obj){(void*)((s->start << PageS
hift) + spf->offset), s->elemsize, 0}); |
| 1244 » » » » enqueue1(&wbuf, (Obj){(void*)&spf->fn, PtrSize,
0}); |
| 1245 » » » » enqueue1(&wbuf, (Obj){(void*)&spf->fint, PtrSize
, 0}); |
| 1246 » » » » enqueue1(&wbuf, (Obj){(void*)&spf->ot, PtrSize,
0}); |
| 1247 » » » } |
| 1248 » » } |
| 1249 » » break; |
| 1250 |
| 1251 » case RootFlushCaches: |
| 1252 » » flushallmcaches(); |
| 1253 » » break; |
| 1254 |
| 1255 » default: |
| 1256 » » // the rest is scanning goroutine stacks |
| 1257 » » if(i - RootCount >= runtime·allglen) |
| 1258 » » » runtime·throw("markroot: bad index"); |
| 1259 » » gp = runtime·allg[i - RootCount]; |
| 1260 » » // remember when we've first observed the G blocked |
| 1261 » » // needed only to output in traceback |
| 1262 » » if((gp->status == Gwaiting || gp->status == Gsyscall) && gp->wai
tsince == 0) |
| 1263 » » » gp->waitsince = work.tstart; |
| 1264 » » addstackroots(gp, &wbuf); |
| 1265 » » break; |
| 1266 » »······· |
| 1267 » } |
| 1268 |
| 1269 » if(wbuf) |
| 1270 » » scanblock(wbuf, false); |
1268 } | 1271 } |
1269 | 1272 |
1270 // Get an empty work buffer off the work.empty list, | 1273 // Get an empty work buffer off the work.empty list, |
1271 // allocating new buffers as needed. | 1274 // allocating new buffers as needed. |
1272 static Workbuf* | 1275 static Workbuf* |
1273 getempty(Workbuf *b) | 1276 getempty(Workbuf *b) |
1274 { | 1277 { |
1275 if(b != nil) | 1278 if(b != nil) |
1276 runtime·lfstackpush(&work.full, &b->node); | 1279 runtime·lfstackpush(&work.full, &b->node); |
1277 b = (Workbuf*)runtime·lfstackpop(&work.empty); | 1280 b = (Workbuf*)runtime·lfstackpop(&work.empty); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1354 b1->nobj = n; | 1357 b1->nobj = n; |
1355 runtime·memmove(b1->obj, b->obj+b->nobj, n*sizeof b1->obj[0]); | 1358 runtime·memmove(b1->obj, b->obj+b->nobj, n*sizeof b1->obj[0]); |
1356 m->gcstats.nhandoff++; | 1359 m->gcstats.nhandoff++; |
1357 m->gcstats.nhandoffcnt += n; | 1360 m->gcstats.nhandoffcnt += n; |
1358 | 1361 |
1359 // Put b on full list - let first half of b get stolen. | 1362 // Put b on full list - let first half of b get stolen. |
1360 runtime·lfstackpush(&work.full, &b->node); | 1363 runtime·lfstackpush(&work.full, &b->node); |
1361 return b1; | 1364 return b1; |
1362 } | 1365 } |
1363 | 1366 |
1364 static void | |
1365 addroot(Obj obj) | |
1366 { | |
1367 uint32 cap; | |
1368 Obj *new; | |
1369 | |
1370 if(work.nroot >= work.rootcap) { | |
1371 cap = RootBlockSize/sizeof(Obj); | |
1372 if(cap < 2*work.rootcap) | |
1373 cap = 2*work.rootcap; | |
1374 new = (Obj*)runtime·SysAlloc(cap*sizeof(Obj), &mstats.gc_sys); | |
1375 if(new == nil) | |
1376 runtime·throw("runtime: cannot allocate memory"); | |
1377 if(work.roots != nil) { | |
1378 runtime·memmove(new, work.roots, work.rootcap*sizeof(Obj
)); | |
1379 runtime·SysFree(work.roots, work.rootcap*sizeof(Obj), &m
stats.gc_sys); | |
1380 } | |
1381 work.roots = new; | |
1382 work.rootcap = cap; | |
1383 } | |
1384 work.roots[work.nroot] = obj; | |
1385 work.nroot++; | |
1386 } | |
1387 | |
1388 extern byte pclntab[]; // base for f->ptrsoff | 1367 extern byte pclntab[]; // base for f->ptrsoff |
1389 | 1368 |
1390 typedef struct BitVector BitVector; | 1369 typedef struct BitVector BitVector; |
1391 struct BitVector | 1370 struct BitVector |
1392 { | 1371 { |
1393 int32 n; | 1372 int32 n; |
1394 uint32 data[]; | 1373 uint32 data[]; |
1395 }; | 1374 }; |
1396 | 1375 |
1397 typedef struct StackMap StackMap; | 1376 typedef struct StackMap StackMap; |
(...skipping 19 matching lines...) Expand all Loading... |
1417 bv = (BitVector*)ptr; | 1396 bv = (BitVector*)ptr; |
1418 words = ((bv->n + 31) / 32) + 1; | 1397 words = ((bv->n + 31) / 32) + 1; |
1419 ptr += words; | 1398 ptr += words; |
1420 } | 1399 } |
1421 return (BitVector*)ptr; | 1400 return (BitVector*)ptr; |
1422 } | 1401 } |
1423 | 1402 |
1424 // Scans an interface data value when the interface type indicates | 1403 // Scans an interface data value when the interface type indicates |
1425 // that it is a pointer. | 1404 // that it is a pointer. |
1426 static void | 1405 static void |
1427 scaninterfacedata(uintptr bits, byte *scanp, bool afterprologue, Scanbuf *sbuf) | 1406 scaninterfacedata(uintptr bits, byte *scanp, bool afterprologue, void *wbufp) |
1428 { | 1407 { |
1429 Itab *tab; | 1408 Itab *tab; |
1430 Type *type; | 1409 Type *type; |
1431 | 1410 |
1432 if(runtime·precisestack && afterprologue) { | 1411 if(runtime·precisestack && afterprologue) { |
1433 if(bits == BitsIface) { | 1412 if(bits == BitsIface) { |
1434 tab = *(Itab**)scanp; | 1413 tab = *(Itab**)scanp; |
1435 if(tab->type->size <= sizeof(void*) && (tab->type->kind
& KindNoPointers)) | 1414 if(tab->type->size <= sizeof(void*) && (tab->type->kind
& KindNoPointers)) |
1436 return; | 1415 return; |
1437 } else { // bits == BitsEface | 1416 } else { // bits == BitsEface |
1438 type = *(Type**)scanp; | 1417 type = *(Type**)scanp; |
1439 if(type->size <= sizeof(void*) && (type->kind & KindNoPo
inters)) | 1418 if(type->size <= sizeof(void*) && (type->kind & KindNoPo
inters)) |
1440 return; | 1419 return; |
1441 } | 1420 } |
1442 } | 1421 } |
1443 » *sbuf->obj.pos++ = (Obj){scanp+PtrSize, PtrSize, 0}; | 1422 » enqueue1(wbufp, (Obj){scanp+PtrSize, PtrSize, 0}); |
1444 » if(sbuf->obj.pos == sbuf->obj.end) | |
1445 » » flushobjbuf(sbuf); | |
1446 } | 1423 } |
1447 | 1424 |
1448 // Starting from scanp, scans words corresponding to set bits. | 1425 // Starting from scanp, scans words corresponding to set bits. |
1449 static void | 1426 static void |
1450 scanbitvector(byte *scanp, BitVector *bv, bool afterprologue, Scanbuf *sbuf) | 1427 scanbitvector(byte *scanp, BitVector *bv, bool afterprologue, void *wbufp) |
1451 { | 1428 { |
1452 uintptr word, bits; | 1429 uintptr word, bits; |
1453 uint32 *wordp; | 1430 uint32 *wordp; |
1454 int32 i, remptrs; | 1431 int32 i, remptrs; |
1455 | 1432 |
1456 wordp = bv->data; | 1433 wordp = bv->data; |
1457 for(remptrs = bv->n; remptrs > 0; remptrs -= 32) { | 1434 for(remptrs = bv->n; remptrs > 0; remptrs -= 32) { |
1458 word = *wordp++; | 1435 word = *wordp++; |
1459 if(remptrs < 32) | 1436 if(remptrs < 32) |
1460 i = remptrs; | 1437 i = remptrs; |
1461 else | 1438 else |
1462 i = 32; | 1439 i = 32; |
1463 i /= BitsPerPointer; | 1440 i /= BitsPerPointer; |
1464 for(; i > 0; i--) { | 1441 for(; i > 0; i--) { |
1465 bits = word & 3; | 1442 bits = word & 3; |
1466 if(bits != BitsNoPointer && *(void**)scanp != nil) | 1443 if(bits != BitsNoPointer && *(void**)scanp != nil) |
1467 » » » » if(bits == BitsPointer) { | 1444 » » » » if(bits == BitsPointer) |
1468 » » » » » *sbuf->obj.pos++ = (Obj){scanp, PtrSize,
0}; | 1445 » » » » » enqueue1(wbufp, (Obj){scanp, PtrSize, 0}
); |
1469 » » » » » if(sbuf->obj.pos == sbuf->obj.end) | 1446 » » » » else |
1470 » » » » » » flushobjbuf(sbuf); | 1447 » » » » » scaninterfacedata(bits, scanp, afterprol
ogue, wbufp); |
1471 » » » » } else | |
1472 » » » » » scaninterfacedata(bits, scanp, afterprol
ogue, sbuf); | |
1473 word >>= BitsPerPointer; | 1448 word >>= BitsPerPointer; |
1474 scanp += PtrSize; | 1449 scanp += PtrSize; |
1475 } | 1450 } |
1476 } | 1451 } |
1477 } | 1452 } |
1478 | 1453 |
1479 // Scan a stack frame: local variables and function arguments/results. | 1454 // Scan a stack frame: local variables and function arguments/results. |
1480 static void | 1455 static void |
1481 scanframe(Stkframe *frame, void *arg) | 1456 scanframe(Stkframe *frame, void *wbufp) |
1482 { | 1457 { |
1483 Func *f; | 1458 Func *f; |
1484 Scanbuf *sbuf; | |
1485 StackMap *stackmap; | 1459 StackMap *stackmap; |
1486 BitVector *bv; | 1460 BitVector *bv; |
1487 uintptr size; | 1461 uintptr size; |
1488 uintptr targetpc; | 1462 uintptr targetpc; |
1489 int32 pcdata; | 1463 int32 pcdata; |
1490 bool afterprologue; | 1464 bool afterprologue; |
1491 | 1465 |
1492 f = frame->fn; | 1466 f = frame->fn; |
1493 targetpc = frame->pc; | 1467 targetpc = frame->pc; |
1494 if(targetpc != f->entry) | 1468 if(targetpc != f->entry) |
1495 targetpc--; | 1469 targetpc--; |
1496 pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc); | 1470 pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc); |
1497 if(pcdata == -1) { | 1471 if(pcdata == -1) { |
1498 // We do not have a valid pcdata value but there might be a | 1472 // We do not have a valid pcdata value but there might be a |
1499 // stackmap for this function. It is likely that we are looking | 1473 // stackmap for this function. It is likely that we are looking |
1500 // at the function prologue, assume so and hope for the best. | 1474 // at the function prologue, assume so and hope for the best. |
1501 pcdata = 0; | 1475 pcdata = 0; |
1502 } | 1476 } |
1503 | 1477 |
1504 sbuf = arg; | |
1505 // Scan local variables if stack frame has been allocated. | 1478 // Scan local variables if stack frame has been allocated. |
1506 // Use pointer information if known. | 1479 // Use pointer information if known. |
1507 afterprologue = (frame->varp > (byte*)frame->sp); | 1480 afterprologue = (frame->varp > (byte*)frame->sp); |
1508 if(afterprologue) { | 1481 if(afterprologue) { |
1509 stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); | 1482 stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps); |
1510 if(stackmap == nil) { | 1483 if(stackmap == nil) { |
1511 // No locals information, scan everything. | 1484 // No locals information, scan everything. |
1512 size = frame->varp - (byte*)frame->sp; | 1485 size = frame->varp - (byte*)frame->sp; |
1513 » » » *sbuf->obj.pos++ = (Obj){frame->varp - size, size, 0}; | 1486 » » » enqueue1(wbufp, (Obj){frame->varp - size, size, 0}); |
1514 » » » if(sbuf->obj.pos == sbuf->obj.end) | |
1515 » » » » flushobjbuf(sbuf); | |
1516 } else if(stackmap->n < 0) { | 1487 } else if(stackmap->n < 0) { |
1517 // Locals size information, scan just the locals. | 1488 // Locals size information, scan just the locals. |
1518 size = -stackmap->n; | 1489 size = -stackmap->n; |
1519 » » » *sbuf->obj.pos++ = (Obj){frame->varp - size, size, 0}; | 1490 » » » enqueue1(wbufp, (Obj){frame->varp - size, size, 0}); |
1520 » » » if(sbuf->obj.pos == sbuf->obj.end) | 1491 » » } else if(stackmap->n > 0) { |
1521 » » » » flushobjbuf(sbuf);» » } else if(stackm
ap->n > 0) { | |
1522 // Locals bitmap information, scan just the pointers in | 1492 // Locals bitmap information, scan just the pointers in |
1523 // locals. | 1493 // locals. |
1524 if(pcdata < 0 || pcdata >= stackmap->n) { | 1494 if(pcdata < 0 || pcdata >= stackmap->n) { |
1525 // don't know where we are | 1495 // don't know where we are |
1526 » » » » runtime·printf("pcdata is %d and %d stack map en
tries\n", pcdata, stackmap->n); | 1496 » » » » runtime·printf("pcdata is %d and %d stack map en
tries for %s (targetpc=%p)\n", |
1527 » » » » runtime·throw("addframeroots: bad symbol table")
; | 1497 » » » » » pcdata, stackmap->n, runtime·funcname(f)
, targetpc); |
| 1498 » » » » runtime·throw("scanframe: bad symbol table"); |
1528 } | 1499 } |
1529 bv = stackmapdata(stackmap, pcdata); | 1500 bv = stackmapdata(stackmap, pcdata); |
1530 size = (bv->n * PtrSize) / BitsPerPointer; | 1501 size = (bv->n * PtrSize) / BitsPerPointer; |
1531 » » » scanbitvector(frame->varp - size, bv, afterprologue, sbu
f); | 1502 » » » scanbitvector(frame->varp - size, bv, afterprologue, wbu
fp); |
1532 } | 1503 } |
1533 } | 1504 } |
1534 | 1505 |
1535 // Scan arguments. | 1506 // Scan arguments. |
1536 // Use pointer information if known. | 1507 // Use pointer information if known. |
1537 stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); | 1508 stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps); |
1538 if(stackmap != nil) { | 1509 if(stackmap != nil) { |
1539 bv = stackmapdata(stackmap, pcdata); | 1510 bv = stackmapdata(stackmap, pcdata); |
1540 » » scanbitvector(frame->argp, bv, false, sbuf); | 1511 » » scanbitvector(frame->argp, bv, false, wbufp); |
1541 » } else { | 1512 » } else |
1542 » » *sbuf->obj.pos++ = (Obj){frame->argp, frame->arglen, 0}; | 1513 » » enqueue1(wbufp, (Obj){frame->argp, frame->arglen, 0}); |
1543 » » if(sbuf->obj.pos == sbuf->obj.end) | |
1544 » » » flushobjbuf(sbuf); | |
1545 » } | |
1546 } | 1514 } |
1547 | 1515 |
1548 static void | 1516 static void |
1549 scanstack(G* gp, void *scanbuf) | 1517 addstackroots(G *gp, Workbuf **wbufp) |
1550 { | |
1551 » runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff
, scanframe, scanbuf, false); | |
1552 } | |
1553 | |
1554 static void | |
1555 addstackroots(G *gp) | |
1556 { | 1518 { |
1557 M *mp; | 1519 M *mp; |
1558 int32 n; | 1520 int32 n; |
1559 Stktop *stk; | 1521 Stktop *stk; |
1560 uintptr sp, guard; | 1522 uintptr sp, guard; |
1561 void *base; | 1523 void *base; |
1562 uintptr size; | 1524 uintptr size; |
| 1525 |
| 1526 switch(gp->status){ |
| 1527 default: |
| 1528 runtime·printf("unexpected G.status %d (goroutine %p %D)\n", gp-
>status, gp, gp->goid); |
| 1529 runtime·throw("mark - bad status"); |
| 1530 case Gdead: |
| 1531 return; |
| 1532 case Grunning: |
| 1533 runtime·throw("mark - world not stopped"); |
| 1534 case Grunnable: |
| 1535 case Gsyscall: |
| 1536 case Gwaiting: |
| 1537 break; |
| 1538 } |
1563 | 1539 |
1564 if(gp == g) | 1540 if(gp == g) |
1565 runtime·throw("can't scan our own stack"); | 1541 runtime·throw("can't scan our own stack"); |
1566 if((mp = gp->m) != nil && mp->helpgc) | 1542 if((mp = gp->m) != nil && mp->helpgc) |
1567 runtime·throw("can't scan gchelper stack"); | 1543 runtime·throw("can't scan gchelper stack"); |
1568 if(gp->syscallstack != (uintptr)nil) { | 1544 if(gp->syscallstack != (uintptr)nil) { |
1569 // Scanning another goroutine that is about to enter or might | 1545 // Scanning another goroutine that is about to enter or might |
1570 // have just exited a system call. It may be executing code such | 1546 // have just exited a system call. It may be executing code such |
1571 // as schedlock and may have needed to start a new stack segment
. | 1547 // as schedlock and may have needed to start a new stack segment
. |
1572 // Use the stack segment and stack pointer at the time of | 1548 // Use the stack segment and stack pointer at the time of |
1573 // the system call instead, since that won't change underfoot. | 1549 // the system call instead, since that won't change underfoot. |
1574 sp = gp->syscallsp; | 1550 sp = gp->syscallsp; |
1575 stk = (Stktop*)gp->syscallstack; | 1551 stk = (Stktop*)gp->syscallstack; |
1576 guard = gp->syscallguard; | 1552 guard = gp->syscallguard; |
1577 } else { | 1553 } else { |
1578 // Scanning another goroutine's stack. | 1554 // Scanning another goroutine's stack. |
1579 // The goroutine is usually asleep (the world is stopped). | 1555 // The goroutine is usually asleep (the world is stopped). |
1580 sp = gp->sched.sp; | 1556 sp = gp->sched.sp; |
1581 stk = (Stktop*)gp->stackbase; | 1557 stk = (Stktop*)gp->stackbase; |
1582 guard = gp->stackguard; | 1558 guard = gp->stackguard; |
1583 // For function about to start, context argument is a root too. | 1559 // For function about to start, context argument is a root too. |
1584 if(gp->sched.ctxt != 0 && runtime·mlookup(gp->sched.ctxt, &base,
&size, nil)) | 1560 if(gp->sched.ctxt != 0 && runtime·mlookup(gp->sched.ctxt, &base,
&size, nil)) |
1585 » » » addroot((Obj){base, size, 0}); | 1561 » » » enqueue1(wbufp, (Obj){base, size, 0}); |
1586 } | 1562 } |
1587 if(ScanStackByFrames) { | 1563 if(ScanStackByFrames) { |
1588 USED(sp); | 1564 USED(sp); |
1589 USED(stk); | 1565 USED(stk); |
1590 USED(guard); | 1566 USED(guard); |
1591 » » addroot((Obj){(byte*)gp, PtrSize, (uintptr)gptrProg}); | 1567 » » runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x
7fffffff, scanframe, wbufp, false); |
1592 } else { | 1568 } else { |
1593 n = 0; | 1569 n = 0; |
1594 while(stk) { | 1570 while(stk) { |
1595 if(sp < guard-StackGuard || (uintptr)stk < sp) { | 1571 if(sp < guard-StackGuard || (uintptr)stk < sp) { |
1596 runtime·printf("scanstack inconsistent: g%D#%d s
p=%p not in [%p,%p]\n", gp->goid, n, sp, guard-StackGuard, stk); | 1572 runtime·printf("scanstack inconsistent: g%D#%d s
p=%p not in [%p,%p]\n", gp->goid, n, sp, guard-StackGuard, stk); |
1597 runtime·throw("scanstack"); | 1573 runtime·throw("scanstack"); |
1598 } | 1574 } |
1599 » » » addroot((Obj){(byte*)sp, (uintptr)stk - sp, (uintptr)def
aultProg | PRECISE | LOOP}); | 1575 » » » enqueue1(wbufp, (Obj){(byte*)sp, (uintptr)stk - sp, (uin
tptr)defaultProg | PRECISE | LOOP}); |
1600 sp = stk->gobuf.sp; | 1576 sp = stk->gobuf.sp; |
1601 guard = stk->stackguard; | 1577 guard = stk->stackguard; |
1602 stk = (Stktop*)stk->stackbase; | 1578 stk = (Stktop*)stk->stackbase; |
1603 n++; | 1579 n++; |
1604 } | 1580 } |
1605 } | 1581 } |
1606 } | 1582 } |
1607 | 1583 |
1608 static void | 1584 void |
1609 addfinroots(void *v) | 1585 runtime·queuefinalizer(byte *p, FuncVal *fn, uintptr nret, Type *fint, PtrType *
ot) |
1610 { | 1586 { |
1611 » uintptr size; | |
1612 » void *base; | |
1613 | |
1614 » size = 0; | |
1615 » if(!runtime·mlookup(v, &base, &size, nil) || !runtime·blockspecial(base)
) | |
1616 » » runtime·throw("mark - finalizer inconsistency"); | |
1617 | |
1618 » // do not mark the finalizer block itself. just mark the things it poin
ts at. | |
1619 » addroot((Obj){base, size, 0}); | |
1620 } | |
1621 | |
1622 static void | |
1623 addroots(void) | |
1624 { | |
1625 » G *gp; | |
1626 » FinBlock *fb; | |
1627 » MSpan *s, **allspans; | |
1628 » uint32 spanidx; | |
1629 | |
1630 » work.nroot = 0; | |
1631 | |
1632 » // data & bss | |
1633 » // TODO(atom): load balancing | |
1634 » addroot((Obj){data, edata - data, (uintptr)gcdata}); | |
1635 » addroot((Obj){bss, ebss - bss, (uintptr)gcbss}); | |
1636 | |
1637 » // MSpan.types | |
1638 » allspans = runtime·mheap.allspans; | |
1639 » for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) { | |
1640 » » s = allspans[spanidx]; | |
1641 » » if(s->state == MSpanInUse) { | |
1642 » » » // The garbage collector ignores type pointers stored in
MSpan.types: | |
1643 » » » // - Compiler-generated types are stored outside of hea
p. | |
1644 » » » // - The reflect package has runtime-generated types ca
ched in its data structures. | |
1645 » » » // The garbage collector relies on finding the refere
nces via that cache. | |
1646 » » » switch(s->types.compression) { | |
1647 » » » case MTypes_Empty: | |
1648 » » » case MTypes_Single: | |
1649 » » » » break; | |
1650 » » » case MTypes_Words: | |
1651 » » » case MTypes_Bytes: | |
1652 » » » » markonly((byte*)s->types.data); | |
1653 » » » » break; | |
1654 » » » } | |
1655 » » } | |
1656 » } | |
1657 | |
1658 » // stacks | |
1659 » for(gp=runtime·allg; gp!=nil; gp=gp->alllink) { | |
1660 » » switch(gp->status){ | |
1661 » » default: | |
1662 » » » runtime·printf("unexpected G.status %d\n", gp->status); | |
1663 » » » runtime·throw("mark - bad status"); | |
1664 » » case Gdead: | |
1665 » » » break; | |
1666 » » case Grunning: | |
1667 » » » runtime·throw("mark - world not stopped"); | |
1668 » » case Grunnable: | |
1669 » » case Gsyscall: | |
1670 » » case Gwaiting: | |
1671 » » » addstackroots(gp); | |
1672 » » » break; | |
1673 » » } | |
1674 » } | |
1675 | |
1676 » runtime·walkfintab(addfinroots); | |
1677 | |
1678 » for(fb=allfin; fb; fb=fb->alllink) | |
1679 » » addroot((Obj){(byte*)fb->fin, fb->cnt*sizeof(fb->fin[0]), 0}); | |
1680 } | |
1681 | |
1682 static void | |
1683 addfreelists(void) | |
1684 { | |
1685 » int32 i; | |
1686 » P *p, **pp; | |
1687 » MCache *c; | |
1688 » MLink *m; | |
1689 | |
1690 » // Mark objects in the MCache of each P so we don't collect them. | |
1691 » for(pp=runtime·allp; p=*pp; pp++) { | |
1692 » » c = p->mcache; | |
1693 » » if(c==nil) | |
1694 » » » continue; | |
1695 » » for(i = 0; i < NumSizeClasses; i++) { | |
1696 » » » for(m = c->list[i].list; m != nil; m = m->next) { | |
1697 » » » » markonly(m); | |
1698 » » » } | |
1699 » » } | |
1700 » } | |
1701 » // Note: the sweeper will mark objects in each span's freelist. | |
1702 } | |
1703 | |
1704 static bool | |
1705 handlespecial(byte *p, uintptr size) | |
1706 { | |
1707 » FuncVal *fn; | |
1708 » uintptr nret; | |
1709 » PtrType *ot; | |
1710 » Type *fint; | |
1711 FinBlock *block; | 1587 FinBlock *block; |
1712 Finalizer *f; | 1588 Finalizer *f; |
1713 | |
1714 if(!runtime·getfinalizer(p, true, &fn, &nret, &fint, &ot)) { | |
1715 runtime·setblockspecial(p, false); | |
1716 runtime·MProf_Free(p, size); | |
1717 return false; | |
1718 } | |
1719 | 1589 |
1720 runtime·lock(&finlock); | 1590 runtime·lock(&finlock); |
1721 if(finq == nil || finq->cnt == finq->cap) { | 1591 if(finq == nil || finq->cnt == finq->cap) { |
1722 if(finc == nil) { | 1592 if(finc == nil) { |
1723 finc = runtime·persistentalloc(FinBlockSize, 0, &mstats.
gc_sys); | 1593 finc = runtime·persistentalloc(FinBlockSize, 0, &mstats.
gc_sys); |
1724 finc->cap = (FinBlockSize - sizeof(FinBlock)) / sizeof(F
inalizer) + 1; | 1594 finc->cap = (FinBlockSize - sizeof(FinBlock)) / sizeof(F
inalizer) + 1; |
1725 finc->alllink = allfin; | 1595 finc->alllink = allfin; |
1726 allfin = finc; | 1596 allfin = finc; |
1727 } | 1597 } |
1728 block = finc; | 1598 block = finc; |
1729 finc = block->next; | 1599 finc = block->next; |
1730 block->next = finq; | 1600 block->next = finq; |
1731 finq = block; | 1601 finq = block; |
1732 } | 1602 } |
1733 f = &finq->fin[finq->cnt]; | 1603 f = &finq->fin[finq->cnt]; |
1734 finq->cnt++; | 1604 finq->cnt++; |
1735 f->fn = fn; | 1605 f->fn = fn; |
1736 f->nret = nret; | 1606 f->nret = nret; |
1737 f->fint = fint; | 1607 f->fint = fint; |
1738 f->ot = ot; | 1608 f->ot = ot; |
1739 f->arg = p; | 1609 f->arg = p; |
1740 runtime·unlock(&finlock); | 1610 runtime·unlock(&finlock); |
1741 return true; | |
1742 } | 1611 } |
1743 | 1612 |
1744 // Sweep frees or collects finalizers for blocks not marked in the mark phase. | 1613 // Sweep frees or collects finalizers for blocks not marked in the mark phase. |
1745 // It clears the mark bits in preparation for the next GC round. | 1614 // It clears the mark bits in preparation for the next GC round. |
1746 static void | 1615 static void |
1747 sweepspan(ParFor *desc, uint32 idx) | 1616 sweepspan(ParFor *desc, uint32 idx) |
1748 { | 1617 { |
1749 int32 cl, n, npages; | 1618 int32 cl, n, npages; |
1750 » uintptr size, off, *bitp, shift; | 1619 » uintptr size, off, *bitp, shift, bits; |
1751 byte *p; | 1620 byte *p; |
1752 MCache *c; | 1621 MCache *c; |
1753 byte *arena_start; | 1622 byte *arena_start; |
1754 MLink head, *end; | 1623 MLink head, *end; |
1755 int32 nfree; | 1624 int32 nfree; |
1756 byte *type_data; | 1625 byte *type_data; |
1757 byte compression; | 1626 byte compression; |
1758 uintptr type_data_inc; | 1627 uintptr type_data_inc; |
1759 MSpan *s; | 1628 MSpan *s; |
1760 MLink *x; | 1629 MLink *x; |
| 1630 Special *special, **specialp, *y; |
1761 | 1631 |
1762 USED(&desc); | 1632 USED(&desc); |
1763 s = runtime·mheap.allspans[idx]; | 1633 s = runtime·mheap.allspans[idx]; |
1764 if(s->state != MSpanInUse) | 1634 if(s->state != MSpanInUse) |
1765 return; | 1635 return; |
1766 arena_start = runtime·mheap.arena_start; | 1636 arena_start = runtime·mheap.arena_start; |
1767 p = (byte*)(s->start << PageShift); | |
1768 cl = s->sizeclass; | 1637 cl = s->sizeclass; |
1769 size = s->elemsize; | 1638 size = s->elemsize; |
1770 if(cl == 0) { | 1639 if(cl == 0) { |
1771 n = 1; | 1640 n = 1; |
1772 } else { | 1641 } else { |
1773 // Chunk full of small blocks. | 1642 // Chunk full of small blocks. |
1774 npages = runtime·class_to_allocnpages[cl]; | 1643 npages = runtime·class_to_allocnpages[cl]; |
1775 n = (npages << PageShift) / size; | 1644 n = (npages << PageShift) / size; |
1776 } | 1645 } |
1777 nfree = 0; | 1646 nfree = 0; |
1778 end = &head; | 1647 end = &head; |
1779 c = m->mcache; | 1648 c = m->mcache; |
1780 | 1649 |
1781 // mark any free objects in this span so we don't collect them | 1650 // mark any free objects in this span so we don't collect them |
1782 for(x = s->freelist; x != nil; x = x->next) { | 1651 for(x = s->freelist; x != nil; x = x->next) { |
1783 // This is markonly(x) but faster because we don't need | 1652 // This is markonly(x) but faster because we don't need |
1784 // atomic access and we're guaranteed to be pointing at | 1653 // atomic access and we're guaranteed to be pointing at |
1785 // the head of a valid object. | 1654 // the head of a valid object. |
1786 off = (uintptr*)x - (uintptr*)runtime·mheap.arena_start; | 1655 off = (uintptr*)x - (uintptr*)runtime·mheap.arena_start; |
1787 bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapW
ord - 1; | 1656 bitp = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapW
ord - 1; |
1788 shift = off % wordsPerBitmapWord; | 1657 shift = off % wordsPerBitmapWord; |
1789 *bitp |= bitMarked<<shift; | 1658 *bitp |= bitMarked<<shift; |
1790 } | 1659 } |
1791 ········ | 1660 ········ |
| 1661 // Unlink & free special records for any objects we're about to free. |
| 1662 specialp = &s->specials; |
| 1663 special = *specialp; |
| 1664 while(special != nil) { |
| 1665 p = (byte*)(s->start << PageShift) + special->offset; |
| 1666 off = (uintptr*)p - (uintptr*)arena_start; |
| 1667 bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1; |
| 1668 shift = off % wordsPerBitmapWord; |
| 1669 bits = *bitp>>shift; |
| 1670 if((bits & (bitAllocated|bitMarked)) == bitAllocated) { |
| 1671 // about to free object: splice out special record |
| 1672 y = special; |
| 1673 special = special->next; |
| 1674 *specialp = special; |
| 1675 if(!runtime·freespecial(y, p, size)) { |
| 1676 // stop freeing of object if it has a finalizer |
| 1677 *bitp |= bitMarked << shift; |
| 1678 } |
| 1679 } else { |
| 1680 // object is still live: keep special record |
| 1681 specialp = &special->next; |
| 1682 special = *specialp; |
| 1683 } |
| 1684 } |
| 1685 |
1792 type_data = (byte*)s->types.data; | 1686 type_data = (byte*)s->types.data; |
1793 type_data_inc = sizeof(uintptr); | 1687 type_data_inc = sizeof(uintptr); |
1794 compression = s->types.compression; | 1688 compression = s->types.compression; |
1795 switch(compression) { | 1689 switch(compression) { |
1796 case MTypes_Bytes: | 1690 case MTypes_Bytes: |
1797 type_data += 8*sizeof(uintptr); | 1691 type_data += 8*sizeof(uintptr); |
1798 type_data_inc = 1; | 1692 type_data_inc = 1; |
1799 break; | 1693 break; |
1800 } | 1694 } |
1801 | 1695 |
1802 // Sweep through n objects of given size starting at p. | 1696 // Sweep through n objects of given size starting at p. |
1803 // This thread owns the span now, so it can manipulate | 1697 // This thread owns the span now, so it can manipulate |
1804 // the block bitmap without atomic operations. | 1698 // the block bitmap without atomic operations. |
| 1699 p = (byte*)(s->start << PageShift); |
1805 for(; n > 0; n--, p += size, type_data+=type_data_inc) { | 1700 for(; n > 0; n--, p += size, type_data+=type_data_inc) { |
1806 uintptr off, *bitp, shift, bits; | |
1807 | |
1808 off = (uintptr*)p - (uintptr*)arena_start; | 1701 off = (uintptr*)p - (uintptr*)arena_start; |
1809 bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1; | 1702 bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1; |
1810 shift = off % wordsPerBitmapWord; | 1703 shift = off % wordsPerBitmapWord; |
1811 bits = *bitp>>shift; | 1704 bits = *bitp>>shift; |
1812 | 1705 |
1813 if((bits & bitAllocated) == 0) | 1706 if((bits & bitAllocated) == 0) |
1814 continue; | 1707 continue; |
1815 | 1708 |
1816 if((bits & bitMarked) != 0) { | 1709 if((bits & bitMarked) != 0) { |
1817 if(DebugMark) { | |
1818 if(!(bits & bitSpecial)) | |
1819 runtime·printf("found spurious mark on %
p\n", p); | |
1820 *bitp &= ~(bitSpecial<<shift); | |
1821 } | |
1822 *bitp &= ~(bitMarked<<shift); | 1710 *bitp &= ~(bitMarked<<shift); |
1823 continue; | 1711 continue; |
1824 } | |
1825 | |
1826 // Special means it has a finalizer or is being profiled. | |
1827 // In DebugMark mode, the bit has been coopted so | |
1828 // we have to assume all blocks are special. | |
1829 if(DebugMark || (bits & bitSpecial) != 0) { | |
1830 if(handlespecial(p, size)) | |
1831 continue; | |
1832 } | 1712 } |
1833 | 1713 |
1834 // Clear mark, scan, and special bits. | 1714 // Clear mark, scan, and special bits. |
1835 *bitp &= ~((bitScan|bitMarked|bitSpecial)<<shift); | 1715 *bitp &= ~((bitScan|bitMarked|bitSpecial)<<shift); |
1836 | 1716 |
1837 if(cl == 0) { | 1717 if(cl == 0) { |
1838 // Free large span. | 1718 // Free large span. |
1839 runtime·unmarkspan(p, 1<<PageShift); | 1719 runtime·unmarkspan(p, 1<<PageShift); |
1840 *(uintptr*)p = (uintptr)0xdeaddeaddeaddeadll; // needs
zeroing | 1720 *(uintptr*)p = (uintptr)0xdeaddeaddeaddeadll; // needs
zeroing |
1841 if(runtime·debug.efence) | 1721 if(runtime·debug.efence) |
1842 runtime·SysFree(p, size, &mstats.gc_sys); | 1722 runtime·SysFree(p, size, &mstats.gc_sys); |
1843 else | 1723 else |
1844 runtime·MHeap_Free(&runtime·mheap, s, 1); | 1724 runtime·MHeap_Free(&runtime·mheap, s, 1); |
1845 c->local_nlargefree++; | 1725 c->local_nlargefree++; |
1846 c->local_largefree += size; | 1726 c->local_largefree += size; |
1847 } else { | 1727 } else { |
1848 // Free small object. | 1728 // Free small object. |
1849 switch(compression) { | 1729 switch(compression) { |
1850 case MTypes_Words: | 1730 case MTypes_Words: |
1851 *(uintptr*)type_data = 0; | 1731 *(uintptr*)type_data = 0; |
1852 break; | 1732 break; |
1853 case MTypes_Bytes: | 1733 case MTypes_Bytes: |
1854 *(byte*)type_data = 0; | 1734 *(byte*)type_data = 0; |
1855 break; | 1735 break; |
1856 } | 1736 } |
1857 » » » if(size > sizeof(uintptr)) | 1737 » » » if(size > 2*sizeof(uintptr)) |
1858 ((uintptr*)p)[1] = (uintptr)0xdeaddeaddeaddeadll
; // mark as "needs to be zeroed" | 1738 ((uintptr*)p)[1] = (uintptr)0xdeaddeaddeaddeadll
; // mark as "needs to be zeroed" |
1859 » » »······· | 1739 » » » else if(size > sizeof(uintptr)) |
| 1740 » » » » ((uintptr*)p)[1] = 0; |
| 1741 |
1860 end->next = (MLink*)p; | 1742 end->next = (MLink*)p; |
1861 end = (MLink*)p; | 1743 end = (MLink*)p; |
1862 nfree++; | 1744 nfree++; |
1863 } | 1745 } |
1864 } | 1746 } |
1865 | 1747 |
1866 if(nfree) { | 1748 if(nfree) { |
1867 c->local_nsmallfree[cl] += nfree; | 1749 c->local_nsmallfree[cl] += nfree; |
1868 c->local_cachealloc -= nfree * size; | 1750 c->local_cachealloc -= nfree * size; |
1869 runtime·MCentral_FreeSpan(&runtime·mheap.central[cl], s, nfree,
head.next, end); | 1751 runtime·MCentral_FreeSpan(&runtime·mheap.central[cl], s, nfree,
head.next, end); |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1942 uint32 spanidx; | 1824 uint32 spanidx; |
1943 | 1825 |
1944 for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) { | 1826 for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) { |
1945 dumpspan(spanidx); | 1827 dumpspan(spanidx); |
1946 } | 1828 } |
1947 } | 1829 } |
1948 | 1830 |
1949 void | 1831 void |
1950 runtime·gchelper(void) | 1832 runtime·gchelper(void) |
1951 { | 1833 { |
| 1834 int32 nproc; |
| 1835 |
1952 gchelperstart(); | 1836 gchelperstart(); |
1953 | 1837 |
1954 // parallel mark for over gc roots | 1838 // parallel mark for over gc roots |
1955 runtime·parfordo(work.markfor); | 1839 runtime·parfordo(work.markfor); |
1956 | 1840 |
1957 // help other threads scan secondary blocks | 1841 // help other threads scan secondary blocks |
1958 » scanblock(nil, nil, 0, true); | 1842 » scanblock(nil, true); |
1959 | |
1960 » if(DebugMark) { | |
1961 » » // wait while the main thread executes mark(debug_scanblock) | |
1962 » » while(runtime·atomicload(&work.debugmarkdone) == 0) | |
1963 » » » runtime·usleep(10); | |
1964 » } | |
1965 | 1843 |
1966 runtime·parfordo(work.sweepfor); | 1844 runtime·parfordo(work.sweepfor); |
1967 bufferList[m->helpgc].busy = 0; | 1845 bufferList[m->helpgc].busy = 0; |
1968 » if(runtime·xadd(&work.ndone, +1) == work.nproc-1) | 1846 » nproc = work.nproc; // work.nproc can change right after we increment w
ork.ndone |
| 1847 » if(runtime·xadd(&work.ndone, +1) == nproc-1) |
1969 runtime·notewakeup(&work.alldone); | 1848 runtime·notewakeup(&work.alldone); |
1970 } | 1849 } |
1971 | 1850 |
1972 #define GcpercentUnknown (-2) | 1851 #define GcpercentUnknown (-2) |
1973 | 1852 |
1974 // Initialized from $GOGC. GOGC=off means no gc. | 1853 // Initialized from $GOGC. GOGC=off means no gc. |
1975 // | 1854 // |
1976 // Next gc is after we've allocated an extra amount of | 1855 // Next gc is after we've allocated an extra amount of |
1977 // memory proportional to the amount already in use. | 1856 // memory proportional to the amount already in use. |
1978 // If gcpercent=100 and we're using 4M, we'll gc again | 1857 // If gcpercent=100 and we're using 4M, we'll gc again |
(...skipping 11 matching lines...) Expand all Loading... |
1990 | 1869 |
1991 for(pp=runtime·allp; p=*pp; pp++) { | 1870 for(pp=runtime·allp; p=*pp; pp++) { |
1992 c = p->mcache; | 1871 c = p->mcache; |
1993 if(c==nil) | 1872 if(c==nil) |
1994 continue; | 1873 continue; |
1995 runtime·purgecachedstats(c); | 1874 runtime·purgecachedstats(c); |
1996 } | 1875 } |
1997 } | 1876 } |
1998 | 1877 |
1999 static void | 1878 static void |
| 1879 flushallmcaches(void) |
| 1880 { |
| 1881 P *p, **pp; |
| 1882 MCache *c; |
| 1883 |
| 1884 // Flush MCache's to MCentral. |
| 1885 for(pp=runtime·allp; p=*pp; pp++) { |
| 1886 c = p->mcache; |
| 1887 if(c==nil) |
| 1888 continue; |
| 1889 runtime·MCache_ReleaseAll(c); |
| 1890 } |
| 1891 } |
| 1892 |
| 1893 static void |
2000 updatememstats(GCStats *stats) | 1894 updatememstats(GCStats *stats) |
2001 { | 1895 { |
2002 M *mp; | 1896 M *mp; |
2003 MSpan *s; | 1897 MSpan *s; |
2004 MCache *c; | |
2005 P *p, **pp; | |
2006 int32 i; | 1898 int32 i; |
2007 uint64 stacks_inuse, smallfree; | 1899 uint64 stacks_inuse, smallfree; |
2008 uint64 *src, *dst; | 1900 uint64 *src, *dst; |
2009 | 1901 |
2010 if(stats) | 1902 if(stats) |
2011 runtime·memclr((byte*)stats, sizeof(*stats)); | 1903 runtime·memclr((byte*)stats, sizeof(*stats)); |
2012 stacks_inuse = 0; | 1904 stacks_inuse = 0; |
2013 for(mp=runtime·allm; mp; mp=mp->alllink) { | 1905 for(mp=runtime·allm; mp; mp=mp->alllink) { |
2014 stacks_inuse += mp->stackinuse*FixedStack; | 1906 stacks_inuse += mp->stackinuse*FixedStack; |
2015 if(stats) { | 1907 if(stats) { |
(...skipping 20 matching lines...) Expand all Loading... |
2036 mstats.alloc = 0; | 1928 mstats.alloc = 0; |
2037 mstats.total_alloc = 0; | 1929 mstats.total_alloc = 0; |
2038 mstats.nmalloc = 0; | 1930 mstats.nmalloc = 0; |
2039 mstats.nfree = 0; | 1931 mstats.nfree = 0; |
2040 for(i = 0; i < nelem(mstats.by_size); i++) { | 1932 for(i = 0; i < nelem(mstats.by_size); i++) { |
2041 mstats.by_size[i].nmalloc = 0; | 1933 mstats.by_size[i].nmalloc = 0; |
2042 mstats.by_size[i].nfree = 0; | 1934 mstats.by_size[i].nfree = 0; |
2043 } | 1935 } |
2044 | 1936 |
2045 // Flush MCache's to MCentral. | 1937 // Flush MCache's to MCentral. |
2046 » for(pp=runtime·allp; p=*pp; pp++) { | 1938 » flushallmcaches(); |
2047 » » c = p->mcache; | |
2048 » » if(c==nil) | |
2049 » » » continue; | |
2050 » » runtime·MCache_ReleaseAll(c); | |
2051 » } | |
2052 | 1939 |
2053 // Aggregate local stats. | 1940 // Aggregate local stats. |
2054 cachestats(); | 1941 cachestats(); |
2055 | 1942 |
2056 // Scan all spans and count number of alive objects. | 1943 // Scan all spans and count number of alive objects. |
2057 for(i = 0; i < runtime·mheap.nspan; i++) { | 1944 for(i = 0; i < runtime·mheap.nspan; i++) { |
2058 s = runtime·mheap.allspans[i]; | 1945 s = runtime·mheap.allspans[i]; |
2059 if(s->state != MSpanInUse) | 1946 if(s->state != MSpanInUse) |
2060 continue; | 1947 continue; |
2061 if(s->sizeclass == 0) { | 1948 if(s->sizeclass == 0) { |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2149 // typically threads which lost the race to grab | 2036 // typically threads which lost the race to grab |
2150 // worldsema exit here when gc is done. | 2037 // worldsema exit here when gc is done. |
2151 runtime·semrelease(&runtime·worldsema); | 2038 runtime·semrelease(&runtime·worldsema); |
2152 return; | 2039 return; |
2153 } | 2040 } |
2154 | 2041 |
2155 // Ok, we're doing it! Stop everybody else | 2042 // Ok, we're doing it! Stop everybody else |
2156 a.start_time = runtime·nanotime(); | 2043 a.start_time = runtime·nanotime(); |
2157 m->gcing = 1; | 2044 m->gcing = 1; |
2158 runtime·stoptheworld(); | 2045 runtime·stoptheworld(); |
| 2046 ········ |
| 2047 if(runtime·debug.allocfreetrace) |
| 2048 runtime·MProf_TraceGC(); |
2159 | 2049 |
2160 clearpools(); | 2050 clearpools(); |
2161 | 2051 |
2162 // Run gc on the g0 stack. We do this so that the g stack | 2052 // Run gc on the g0 stack. We do this so that the g stack |
2163 // we're currently running on will no longer change. Cuts | 2053 // we're currently running on will no longer change. Cuts |
2164 // the root set down a bit (g0 stacks are not scanned, and | 2054 // the root set down a bit (g0 stacks are not scanned, and |
2165 // we don't need to scan gc's internal state). Also an | 2055 // we don't need to scan gc's internal state). Also an |
2166 // enabler for copyable stacks. | 2056 // enabler for copyable stacks. |
2167 for(i = 0; i < (runtime·debug.gctrace > 1 ? 2 : 1); i++) { | 2057 for(i = 0; i < (runtime·debug.gctrace > 1 ? 2 : 1); i++) { |
2168 // switch to g0, call gc(&a), then switch back | 2058 // switch to g0, call gc(&a), then switch back |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2210 gc(struct gc_args *args) | 2100 gc(struct gc_args *args) |
2211 { | 2101 { |
2212 int64 t0, t1, t2, t3, t4; | 2102 int64 t0, t1, t2, t3, t4; |
2213 uint64 heap0, heap1, obj0, obj1, ninstr; | 2103 uint64 heap0, heap1, obj0, obj1, ninstr; |
2214 GCStats stats; | 2104 GCStats stats; |
2215 M *mp; | 2105 M *mp; |
2216 uint32 i; | 2106 uint32 i; |
2217 Eface eface; | 2107 Eface eface; |
2218 | 2108 |
2219 t0 = args->start_time; | 2109 t0 = args->start_time; |
| 2110 work.tstart = args->start_time;· |
2220 | 2111 |
2221 if(CollectStats) | 2112 if(CollectStats) |
2222 runtime·memclr((byte*)&gcstats, sizeof(gcstats)); | 2113 runtime·memclr((byte*)&gcstats, sizeof(gcstats)); |
2223 | 2114 |
2224 for(mp=runtime·allm; mp; mp=mp->alllink) | 2115 for(mp=runtime·allm; mp; mp=mp->alllink) |
2225 runtime·settype_flush(mp); | 2116 runtime·settype_flush(mp); |
2226 | 2117 |
2227 heap0 = 0; | 2118 heap0 = 0; |
2228 obj0 = 0; | 2119 obj0 = 0; |
2229 if(runtime·debug.gctrace) { | 2120 if(runtime·debug.gctrace) { |
(...skipping 10 matching lines...) Expand all Loading... |
2240 m->locks--; | 2131 m->locks--; |
2241 | 2132 |
2242 if(itabtype == nil) { | 2133 if(itabtype == nil) { |
2243 // get C pointer to the Go type "itab" | 2134 // get C pointer to the Go type "itab" |
2244 runtime·gc_itab_ptr(&eface); | 2135 runtime·gc_itab_ptr(&eface); |
2245 itabtype = ((PtrType*)eface.type)->elem; | 2136 itabtype = ((PtrType*)eface.type)->elem; |
2246 } | 2137 } |
2247 | 2138 |
2248 work.nwait = 0; | 2139 work.nwait = 0; |
2249 work.ndone = 0; | 2140 work.ndone = 0; |
2250 work.debugmarkdone = 0; | |
2251 work.nproc = runtime·gcprocs(); | 2141 work.nproc = runtime·gcprocs(); |
2252 » addroots(); | 2142 » runtime·parforsetup(work.markfor, work.nproc, RootCount + runtime·allgle
n, nil, false, markroot); |
2253 » addfreelists(); | |
2254 » runtime·parforsetup(work.markfor, work.nproc, work.nroot, nil, false, ma
rkroot); | |
2255 runtime·parforsetup(work.sweepfor, work.nproc, runtime·mheap.nspan, nil,
true, sweepspan); | 2143 runtime·parforsetup(work.sweepfor, work.nproc, runtime·mheap.nspan, nil,
true, sweepspan); |
2256 if(work.nproc > 1) { | 2144 if(work.nproc > 1) { |
2257 runtime·noteclear(&work.alldone); | 2145 runtime·noteclear(&work.alldone); |
2258 runtime·helpgc(work.nproc); | 2146 runtime·helpgc(work.nproc); |
2259 } | 2147 } |
2260 | 2148 |
2261 t1 = runtime·nanotime(); | 2149 t1 = runtime·nanotime(); |
2262 | 2150 |
2263 gchelperstart(); | 2151 gchelperstart(); |
2264 runtime·parfordo(work.markfor); | 2152 runtime·parfordo(work.markfor); |
2265 » scanblock(nil, nil, 0, true); | 2153 » scanblock(nil, true); |
2266 | 2154 |
2267 » if(DebugMark) { | |
2268 » » for(i=0; i<work.nroot; i++) | |
2269 » » » debug_scanblock(work.roots[i].p, work.roots[i].n); | |
2270 » » runtime·atomicstore(&work.debugmarkdone, 1); | |
2271 » } | |
2272 t2 = runtime·nanotime(); | 2155 t2 = runtime·nanotime(); |
2273 | 2156 |
2274 runtime·parfordo(work.sweepfor); | 2157 runtime·parfordo(work.sweepfor); |
2275 bufferList[m->helpgc].busy = 0; | 2158 bufferList[m->helpgc].busy = 0; |
2276 t3 = runtime·nanotime(); | 2159 t3 = runtime·nanotime(); |
2277 | 2160 |
2278 if(work.nproc > 1) | 2161 if(work.nproc > 1) |
2279 runtime·notesleep(&work.alldone); | 2162 runtime·notesleep(&work.alldone); |
2280 | 2163 |
2281 cachestats(); | 2164 cachestats(); |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2424 Eface *ef, ef1; | 2307 Eface *ef, ef1; |
2425 | 2308 |
2426 frame = nil; | 2309 frame = nil; |
2427 framecap = 0; | 2310 framecap = 0; |
2428 for(;;) { | 2311 for(;;) { |
2429 runtime·lock(&finlock); | 2312 runtime·lock(&finlock); |
2430 fb = finq; | 2313 fb = finq; |
2431 finq = nil; | 2314 finq = nil; |
2432 if(fb == nil) { | 2315 if(fb == nil) { |
2433 fingwait = 1; | 2316 fingwait = 1; |
2434 » » » runtime·park(runtime·unlock, &finlock, "finalizer wait")
; | 2317 » » » runtime·parkunlock(&finlock, "finalizer wait"); |
2435 continue; | 2318 continue; |
2436 } | 2319 } |
2437 runtime·unlock(&finlock); | 2320 runtime·unlock(&finlock); |
2438 if(raceenabled) | 2321 if(raceenabled) |
2439 runtime·racefingo(); | 2322 runtime·racefingo(); |
2440 for(; fb; fb=next) { | 2323 for(; fb; fb=next) { |
2441 next = fb->next; | 2324 next = fb->next; |
2442 for(i=0; i<fb->cnt; i++) { | 2325 for(i=0; i<fb->cnt; i++) { |
2443 f = &fb->fin[i]; | 2326 f = &fb->fin[i]; |
2444 framesz = sizeof(Eface) + f->nret; | 2327 framesz = sizeof(Eface) + f->nret; |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2643 runtime·throw("unmarkspan: unaligned length"); | 2526 runtime·throw("unmarkspan: unaligned length"); |
2644 // Okay to use non-atomic ops here, because we control | 2527 // Okay to use non-atomic ops here, because we control |
2645 // the entire span, and each bitmap word has bits for only | 2528 // the entire span, and each bitmap word has bits for only |
2646 // one span, so no other goroutines are changing these | 2529 // one span, so no other goroutines are changing these |
2647 // bitmap words. | 2530 // bitmap words. |
2648 n /= wordsPerBitmapWord; | 2531 n /= wordsPerBitmapWord; |
2649 while(n-- > 0) | 2532 while(n-- > 0) |
2650 *b-- = 0; | 2533 *b-- = 0; |
2651 } | 2534 } |
2652 | 2535 |
2653 bool | |
2654 runtime·blockspecial(void *v) | |
2655 { | |
2656 uintptr *b, off, shift; | |
2657 | |
2658 if(DebugMark) | |
2659 return true; | |
2660 | |
2661 off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; | |
2662 b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; | |
2663 shift = off % wordsPerBitmapWord; | |
2664 | |
2665 return (*b & (bitSpecial<<shift)) != 0; | |
2666 } | |
2667 | |
2668 void | |
2669 runtime·setblockspecial(void *v, bool s) | |
2670 { | |
2671 uintptr *b, off, shift, bits, obits; | |
2672 | |
2673 if(DebugMark) | |
2674 return; | |
2675 | |
2676 off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; | |
2677 b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; | |
2678 shift = off % wordsPerBitmapWord; | |
2679 | |
2680 for(;;) { | |
2681 obits = *b; | |
2682 if(s) | |
2683 bits = obits | (bitSpecial<<shift); | |
2684 else | |
2685 bits = obits & ~(bitSpecial<<shift); | |
2686 if(runtime·gomaxprocs == 1) { | |
2687 *b = bits; | |
2688 break; | |
2689 } else { | |
2690 // more than one goroutine is potentially running: use a
tomic op | |
2691 if(runtime·casp((void**)b, (void*)obits, (void*)bits)) | |
2692 break; | |
2693 } | |
2694 } | |
2695 } | |
2696 | |
2697 void | 2536 void |
2698 runtime·MHeap_MapBits(MHeap *h) | 2537 runtime·MHeap_MapBits(MHeap *h) |
2699 { | 2538 { |
2700 // Caller has added extra mappings to the arena. | 2539 // Caller has added extra mappings to the arena. |
2701 // Add extra mappings of bitmap words as needed. | 2540 // Add extra mappings of bitmap words as needed. |
2702 // We allocate extra bitmap pieces in chunks of bitmapChunk. | 2541 // We allocate extra bitmap pieces in chunks of bitmapChunk. |
2703 enum { | 2542 enum { |
2704 bitmapChunk = 8192 | 2543 bitmapChunk = 8192 |
2705 }; | 2544 }; |
2706 uintptr n; | 2545 uintptr n; |
2707 | 2546 |
2708 n = (h->arena_used - h->arena_start) / wordsPerBitmapWord; | 2547 n = (h->arena_used - h->arena_start) / wordsPerBitmapWord; |
2709 n = ROUND(n, bitmapChunk); | 2548 n = ROUND(n, bitmapChunk); |
2710 if(h->bitmap_mapped >= n) | 2549 if(h->bitmap_mapped >= n) |
2711 return; | 2550 return; |
2712 | 2551 |
2713 runtime·SysMap(h->arena_start - n, n - h->bitmap_mapped, &mstats.gc_sys)
; | 2552 runtime·SysMap(h->arena_start - n, n - h->bitmap_mapped, &mstats.gc_sys)
; |
2714 h->bitmap_mapped = n; | 2553 h->bitmap_mapped = n; |
2715 } | 2554 } |
LEFT | RIGHT |