Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(175)

Delta Between Two Patch Sets: src/pkg/runtime/mgc0.c

Issue 45770044: code review 45770044: runtime: increase page size to 8K (Closed)
Left Patch Set: diff -r 9fd412c6b156 https://dvyukov%40google.com@code.google.com/p/go/ Created 11 years, 2 months ago
Right Patch Set: diff -r 7abe32ccffb1 https://dvyukov%40google.com@code.google.com/p/go/ Created 11 years, 1 month ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « src/pkg/runtime/mem.go ('k') | src/pkg/runtime/netpoll.goc » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b