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" |
(...skipping 1369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1380 } | 1380 } |
1381 work.roots = new; | 1381 work.roots = new; |
1382 work.rootcap = cap; | 1382 work.rootcap = cap; |
1383 } | 1383 } |
1384 work.roots[work.nroot] = obj; | 1384 work.roots[work.nroot] = obj; |
1385 work.nroot++; | 1385 work.nroot++; |
1386 } | 1386 } |
1387 | 1387 |
1388 extern byte pclntab[]; // base for f->ptrsoff | 1388 extern byte pclntab[]; // base for f->ptrsoff |
1389 | 1389 |
| 1390 typedef struct BitVector BitVector; |
1390 struct BitVector | 1391 struct BitVector |
1391 { | 1392 { |
1392 int32 n; | 1393 int32 n; |
1393 uint32 data[]; | 1394 uint32 data[]; |
1394 }; | 1395 }; |
1395 typedef struct BitVector BitVector; | |
1396 | 1396 |
1397 // Starting from scanp, scans words corresponding to set bits. | 1397 // Starting from scanp, scans words corresponding to set bits. |
1398 static void | 1398 static void |
1399 scanbitvector(byte* scanp, BitVector *bv) | 1399 scanbitvector(byte *scanp, BitVector *bv) |
1400 { | 1400 { |
1401 » int32 i, j, remptrs; | 1401 » uint32 *wp; |
1402 » uint32 w, b; | 1402 » uint32 w; |
1403 | 1403 » int32 i, remptrs; |
1404 » for(i = 0, remptrs = bv->n; i < bv->n; i++) { | 1404 |
1405 » » w = bv->data[i]; | 1405 » wp = bv->data; |
1406 » » b = 1; | 1406 » for(remptrs = bv->n; remptrs > 0; remptrs -= 32) { |
1407 » » j = remptrs; | 1407 » » w = *wp++; |
1408 » » if(j > 32) | 1408 » » if(remptrs < 32) |
1409 » » » j = 32; | 1409 » » » i = remptrs; |
1410 » » for(; j > 0; j--) { | 1410 » » else |
1411 » » » if(w & b) { | 1411 » » » i = 32; |
| 1412 » » for(; i > 0; i--) { |
| 1413 » » » if(w & 1) |
1412 addroot((Obj){scanp, PtrSize, 0}); | 1414 addroot((Obj){scanp, PtrSize, 0}); |
1413 » » » } | 1415 » » » w >>= 1; |
1414 » » » b <<= 1; | |
1415 scanp += PtrSize; | 1416 scanp += PtrSize; |
1416 } | 1417 } |
1417 remptrs -= 32; | |
1418 } | 1418 } |
1419 } | 1419 } |
1420 | 1420 |
1421 // Scan a stack frame: local variables and function arguments/results. | 1421 // Scan a stack frame: local variables and function arguments/results. |
1422 static void | 1422 static void |
1423 addframeroots(Stkframe *frame, void*) | 1423 addframeroots(Stkframe *frame, void*) |
1424 { | 1424 { |
1425 Func *f; | 1425 Func *f; |
1426 byte *scanp; | |
1427 BitVector *args, *locals; | 1426 BitVector *args, *locals; |
1428 » intptr sz; | 1427 » uintptr size; |
1429 | 1428 |
1430 f = frame->fn; | 1429 f = frame->fn; |
1431 | 1430 |
1432 // Scan local variables if stack frame has been allocated. | 1431 // Scan local variables if stack frame has been allocated. |
1433 // Use pointer information if known. | 1432 // Use pointer information if known. |
1434 » sz = frame->varp - (byte*)frame->sp; | 1433 » if(frame->varp > (byte*)frame->sp) { |
1435 » if(sz > 0) { | 1434 » » locals = runtime·funcdata(f, FUNCDATA_GCLocals); |
1436 » » locals = runtime·funcdata(f, FUNCDATA_GCLOCALS); | |
1437 if(locals == nil) { | 1435 if(locals == nil) { |
1438 » » » addroot((Obj){frame->varp - sz, sz, 0}); | 1436 » » » // No locals information, scan everything. |
1439 » » } else if(locals->n >= 0) { | 1437 » » » size = frame->varp - (byte*)frame->sp; |
1440 » » » if(locals->n > 0) { | 1438 » » » addroot((Obj){frame->varp - size, size, 0}); |
1441 » » » » scanp = frame->varp - locals->n*PtrSize; | 1439 » » } else if(locals->n < 0) { |
1442 » » » » scanbitvector(scanp, locals); | 1440 » » » // Locals size information, scan just the |
1443 » » » } | 1441 » » » // locals. |
1444 » » } else { | 1442 » » » size = -locals->n; |
1445 » » » addroot((Obj){frame->varp - -locals->n, -locals->n, 0}); | 1443 » » » addroot((Obj){frame->varp - size, size, 0}); |
| 1444 » » } else if(locals->n > 0) { |
| 1445 » » » // Locals bitmap information, scan just the |
| 1446 » » » // pointers in locals. |
| 1447 » » » size = locals->n*PtrSize; |
| 1448 » » » scanbitvector(frame->varp - size, locals); |
1446 } | 1449 } |
1447 } | 1450 } |
1448 | 1451 |
1449 // Scan arguments. | 1452 // Scan arguments. |
1450 // Use pointer information if known. | 1453 // Use pointer information if known. |
1451 » args = runtime·funcdata(f, FUNCDATA_GCARGS); | 1454 » args = runtime·funcdata(f, FUNCDATA_GCArgs); |
1452 » if(f->args > 0 && args != nil && args->n > 0) { | 1455 » if(args != nil && args->n > 0) |
1453 » » scanp = frame->argp; | 1456 » » scanbitvector(frame->argp, args); |
1454 » » scanbitvector(scanp, args); | 1457 » else |
1455 » } else | |
1456 addroot((Obj){frame->argp, frame->arglen, 0}); | 1458 addroot((Obj){frame->argp, frame->arglen, 0}); |
1457 } | 1459 } |
1458 | 1460 |
1459 static void | 1461 static void |
1460 addstackroots(G *gp) | 1462 addstackroots(G *gp) |
1461 { | 1463 { |
1462 M *mp; | 1464 M *mp; |
1463 int32 n; | 1465 int32 n; |
1464 Stktop *stk; | 1466 Stktop *stk; |
1465 uintptr sp, guard, pc, lr; | 1467 uintptr sp, guard, pc, lr; |
1466 void *base; | 1468 void *base; |
1467 uintptr size; | 1469 uintptr size; |
1468 | 1470 |
1469 stk = (Stktop*)gp->stackbase; | 1471 stk = (Stktop*)gp->stackbase; |
1470 guard = gp->stackguard; | 1472 guard = gp->stackguard; |
1471 | 1473 |
1472 if(gp == g) | 1474 if(gp == g) |
1473 runtime·throw("can't scan our own stack"); | 1475 runtime·throw("can't scan our own stack"); |
1474 if((mp = gp->m) != nil && mp->helpgc) | 1476 if((mp = gp->m) != nil && mp->helpgc) |
1475 runtime·throw("can't scan gchelper stack"); | 1477 runtime·throw("can't scan gchelper stack"); |
1476 » if(gp->gcstack != (uintptr)nil) { | 1478 » if(gp->syscallstack != (uintptr)nil) { |
1477 // Scanning another goroutine that is about to enter or might | 1479 // Scanning another goroutine that is about to enter or might |
1478 // have just exited a system call. It may be executing code such | 1480 // have just exited a system call. It may be executing code such |
1479 // as schedlock and may have needed to start a new stack segment
. | 1481 // as schedlock and may have needed to start a new stack segment
. |
1480 // Use the stack segment and stack pointer at the time of | 1482 // Use the stack segment and stack pointer at the time of |
1481 // the system call instead, since that won't change underfoot. | 1483 // the system call instead, since that won't change underfoot. |
1482 » » sp = gp->gcsp; | 1484 » » sp = gp->syscallsp; |
1483 » » pc = gp->gcpc; | 1485 » » pc = gp->syscallpc; |
1484 lr = 0; | 1486 lr = 0; |
1485 » » stk = (Stktop*)gp->gcstack; | 1487 » » stk = (Stktop*)gp->syscallstack; |
1486 » » guard = gp->gcguard; | 1488 » » guard = gp->syscallguard; |
1487 } else { | 1489 } else { |
1488 // Scanning another goroutine's stack. | 1490 // Scanning another goroutine's stack. |
1489 // The goroutine is usually asleep (the world is stopped). | 1491 // The goroutine is usually asleep (the world is stopped). |
1490 sp = gp->sched.sp; | 1492 sp = gp->sched.sp; |
1491 pc = gp->sched.pc; | 1493 pc = gp->sched.pc; |
1492 lr = gp->sched.lr; | 1494 lr = gp->sched.lr; |
1493 | 1495 |
1494 // For function about to start, context argument is a root too. | 1496 // For function about to start, context argument is a root too. |
1495 if(gp->sched.ctxt != 0 && runtime·mlookup(gp->sched.ctxt, &base,
&size, nil)) | 1497 if(gp->sched.ctxt != 0 && runtime·mlookup(gp->sched.ctxt, &base,
&size, nil)) |
1496 addroot((Obj){base, size, 0}); | 1498 addroot((Obj){base, size, 0}); |
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2093 M *mp; | 2095 M *mp; |
2094 uint32 i; | 2096 uint32 i; |
2095 Eface eface; | 2097 Eface eface; |
2096 | 2098 |
2097 t0 = args->start_time; | 2099 t0 = args->start_time; |
2098 | 2100 |
2099 if(CollectStats) | 2101 if(CollectStats) |
2100 runtime·memclr((byte*)&gcstats, sizeof(gcstats)); | 2102 runtime·memclr((byte*)&gcstats, sizeof(gcstats)); |
2101 | 2103 |
2102 for(mp=runtime·allm; mp; mp=mp->alllink) | 2104 for(mp=runtime·allm; mp; mp=mp->alllink) |
2103 » » runtime·settype_flush(mp, false); | 2105 » » runtime·settype_flush(mp); |
2104 | 2106 |
2105 heap0 = 0; | 2107 heap0 = 0; |
2106 obj0 = 0; | 2108 obj0 = 0; |
2107 if(runtime·debug.gctrace) { | 2109 if(runtime·debug.gctrace) { |
2108 updatememstats(nil); | 2110 updatememstats(nil); |
2109 heap0 = mstats.heap_alloc; | 2111 heap0 = mstats.heap_alloc; |
2110 obj0 = mstats.nmalloc - mstats.nfree; | 2112 obj0 = mstats.nmalloc - mstats.nfree; |
2111 } | 2113 } |
2112 | 2114 |
2113 m->locks++; // disable gc during mallocs in parforalloc | 2115 m->locks++; // disable gc during mallocs in parforalloc |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2356 | 2358 |
2357 off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; // word offset | 2359 off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; // word offset |
2358 b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; | 2360 b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; |
2359 shift = off % wordsPerBitmapWord; | 2361 shift = off % wordsPerBitmapWord; |
2360 | 2362 |
2361 for(;;) { | 2363 for(;;) { |
2362 obits = *b; | 2364 obits = *b; |
2363 bits = (obits & ~(bitMask<<shift)) | (bitAllocated<<shift); | 2365 bits = (obits & ~(bitMask<<shift)) | (bitAllocated<<shift); |
2364 if(noptr) | 2366 if(noptr) |
2365 bits |= bitNoPointers<<shift; | 2367 bits |= bitNoPointers<<shift; |
2366 » » if(runtime·singleproc) { | 2368 » » if(runtime·gomaxprocs == 1) { |
2367 *b = bits; | 2369 *b = bits; |
2368 break; | 2370 break; |
2369 } else { | 2371 } else { |
2370 // more than one goroutine is potentially running: use a
tomic op | 2372 // more than one goroutine is potentially running: use a
tomic op |
2371 if(runtime·casp((void**)b, (void*)obits, (void*)bits)) | 2373 if(runtime·casp((void**)b, (void*)obits, (void*)bits)) |
2372 break; | 2374 break; |
2373 } | 2375 } |
2374 } | 2376 } |
2375 } | 2377 } |
2376 | 2378 |
2377 // mark the block at v of size n as freed. | 2379 // mark the block at v of size n as freed. |
2378 void | 2380 void |
2379 runtime·markfreed(void *v, uintptr n) | 2381 runtime·markfreed(void *v, uintptr n) |
2380 { | 2382 { |
2381 uintptr *b, obits, bits, off, shift; | 2383 uintptr *b, obits, bits, off, shift; |
2382 | 2384 |
2383 if(0) | 2385 if(0) |
2384 runtime·printf("markallocated %p+%p\n", v, n); | 2386 runtime·printf("markallocated %p+%p\n", v, n); |
2385 | 2387 |
2386 if((byte*)v+n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mh
eap.arena_start) | 2388 if((byte*)v+n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mh
eap.arena_start) |
2387 runtime·throw("markallocated: bad pointer"); | 2389 runtime·throw("markallocated: bad pointer"); |
2388 | 2390 |
2389 off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; // word offset | 2391 off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; // word offset |
2390 b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; | 2392 b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; |
2391 shift = off % wordsPerBitmapWord; | 2393 shift = off % wordsPerBitmapWord; |
2392 | 2394 |
2393 for(;;) { | 2395 for(;;) { |
2394 obits = *b; | 2396 obits = *b; |
2395 bits = (obits & ~(bitMask<<shift)) | (bitBlockBoundary<<shift); | 2397 bits = (obits & ~(bitMask<<shift)) | (bitBlockBoundary<<shift); |
2396 » » if(runtime·singleproc) { | 2398 » » if(runtime·gomaxprocs == 1) { |
2397 *b = bits; | 2399 *b = bits; |
2398 break; | 2400 break; |
2399 } else { | 2401 } else { |
2400 // more than one goroutine is potentially running: use a
tomic op | 2402 // more than one goroutine is potentially running: use a
tomic op |
2401 if(runtime·casp((void**)b, (void*)obits, (void*)bits)) | 2403 if(runtime·casp((void**)b, (void*)obits, (void*)bits)) |
2402 break; | 2404 break; |
2403 } | 2405 } |
2404 } | 2406 } |
2405 } | 2407 } |
2406 | 2408 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2506 off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; | 2508 off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start; |
2507 b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; | 2509 b = (uintptr*)runtime·mheap.arena_start - off/wordsPerBitmapWord - 1; |
2508 shift = off % wordsPerBitmapWord; | 2510 shift = off % wordsPerBitmapWord; |
2509 | 2511 |
2510 for(;;) { | 2512 for(;;) { |
2511 obits = *b; | 2513 obits = *b; |
2512 if(s) | 2514 if(s) |
2513 bits = obits | (bitSpecial<<shift); | 2515 bits = obits | (bitSpecial<<shift); |
2514 else | 2516 else |
2515 bits = obits & ~(bitSpecial<<shift); | 2517 bits = obits & ~(bitSpecial<<shift); |
2516 » » if(runtime·singleproc) { | 2518 » » if(runtime·gomaxprocs == 1) { |
2517 *b = bits; | 2519 *b = bits; |
2518 break; | 2520 break; |
2519 } else { | 2521 } else { |
2520 // more than one goroutine is potentially running: use a
tomic op | 2522 // more than one goroutine is potentially running: use a
tomic op |
2521 if(runtime·casp((void**)b, (void*)obits, (void*)bits)) | 2523 if(runtime·casp((void**)b, (void*)obits, (void*)bits)) |
2522 break; | 2524 break; |
2523 } | 2525 } |
2524 } | 2526 } |
2525 } | 2527 } |
2526 | 2528 |
2527 void | 2529 void |
2528 runtime·MHeap_MapBits(MHeap *h) | 2530 runtime·MHeap_MapBits(MHeap *h) |
2529 { | 2531 { |
2530 // Caller has added extra mappings to the arena. | 2532 // Caller has added extra mappings to the arena. |
2531 // Add extra mappings of bitmap words as needed. | 2533 // Add extra mappings of bitmap words as needed. |
2532 // We allocate extra bitmap pieces in chunks of bitmapChunk. | 2534 // We allocate extra bitmap pieces in chunks of bitmapChunk. |
2533 enum { | 2535 enum { |
2534 bitmapChunk = 8192 | 2536 bitmapChunk = 8192 |
2535 }; | 2537 }; |
2536 uintptr n; | 2538 uintptr n; |
2537 | 2539 |
2538 n = (h->arena_used - h->arena_start) / wordsPerBitmapWord; | 2540 n = (h->arena_used - h->arena_start) / wordsPerBitmapWord; |
2539 n = ROUND(n, bitmapChunk); | 2541 n = ROUND(n, bitmapChunk); |
2540 if(h->bitmap_mapped >= n) | 2542 if(h->bitmap_mapped >= n) |
2541 return; | 2543 return; |
2542 | 2544 |
2543 runtime·SysMap(h->arena_start - n, n - h->bitmap_mapped); | 2545 runtime·SysMap(h->arena_start - n, n - h->bitmap_mapped); |
2544 h->bitmap_mapped = n; | 2546 h->bitmap_mapped = n; |
2545 } | 2547 } |
LEFT | RIGHT |