github.com/hbdrawn/golang@v0.0.0-20141214014649-6b835209aba2/src/runtime/malloc.go (about) 1 // Copyright 2014 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package runtime 6 7 import "unsafe" 8 9 const ( 10 debugMalloc = false 11 12 flagNoScan = _FlagNoScan 13 flagNoZero = _FlagNoZero 14 15 maxTinySize = _TinySize 16 tinySizeClass = _TinySizeClass 17 maxSmallSize = _MaxSmallSize 18 19 pageShift = _PageShift 20 pageSize = _PageSize 21 pageMask = _PageMask 22 23 bitsPerPointer = _BitsPerPointer 24 bitsMask = _BitsMask 25 pointersPerByte = _PointersPerByte 26 maxGCMask = _MaxGCMask 27 bitsDead = _BitsDead 28 bitsPointer = _BitsPointer 29 bitsScalar = _BitsScalar 30 31 mSpanInUse = _MSpanInUse 32 33 concurrentSweep = _ConcurrentSweep 34 ) 35 36 // Page number (address>>pageShift) 37 type pageID uintptr 38 39 // base address for all 0-byte allocations 40 var zerobase uintptr 41 42 // Allocate an object of size bytes. 43 // Small objects are allocated from the per-P cache's free lists. 44 // Large objects (> 32 kB) are allocated straight from the heap. 45 func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer { 46 if size == 0 { 47 return unsafe.Pointer(&zerobase) 48 } 49 size0 := size 50 51 if flags&flagNoScan == 0 && typ == nil { 52 gothrow("malloc missing type") 53 } 54 55 // This function must be atomic wrt GC, but for performance reasons 56 // we don't acquirem/releasem on fast path. The code below does not have 57 // split stack checks, so it can't be preempted by GC. 58 // Functions like roundup/add are inlined. And systemstack/racemalloc are nosplit. 59 // If debugMalloc = true, these assumptions are checked below. 60 if debugMalloc { 61 mp := acquirem() 62 if mp.mallocing != 0 { 63 gothrow("malloc deadlock") 64 } 65 mp.mallocing = 1 66 if mp.curg != nil { 67 mp.curg.stackguard0 = ^uintptr(0xfff) | 0xbad 68 } 69 } 70 71 c := gomcache() 72 var s *mspan 73 var x unsafe.Pointer 74 if size <= maxSmallSize { 75 if flags&flagNoScan != 0 && size < maxTinySize { 76 // Tiny allocator. 77 // 78 // Tiny allocator combines several tiny allocation requests 79 // into a single memory block. The resulting memory block 80 // is freed when all subobjects are unreachable. The subobjects 81 // must be FlagNoScan (don't have pointers), this ensures that 82 // the amount of potentially wasted memory is bounded. 83 // 84 // Size of the memory block used for combining (maxTinySize) is tunable. 85 // Current setting is 16 bytes, which relates to 2x worst case memory 86 // wastage (when all but one subobjects are unreachable). 87 // 8 bytes would result in no wastage at all, but provides less 88 // opportunities for combining. 89 // 32 bytes provides more opportunities for combining, 90 // but can lead to 4x worst case wastage. 91 // The best case winning is 8x regardless of block size. 92 // 93 // Objects obtained from tiny allocator must not be freed explicitly. 94 // So when an object will be freed explicitly, we ensure that 95 // its size >= maxTinySize. 96 // 97 // SetFinalizer has a special case for objects potentially coming 98 // from tiny allocator, it such case it allows to set finalizers 99 // for an inner byte of a memory block. 100 // 101 // The main targets of tiny allocator are small strings and 102 // standalone escaping variables. On a json benchmark 103 // the allocator reduces number of allocations by ~12% and 104 // reduces heap size by ~20%. 105 tinysize := uintptr(c.tinysize) 106 if size <= tinysize { 107 tiny := unsafe.Pointer(c.tiny) 108 // Align tiny pointer for required (conservative) alignment. 109 if size&7 == 0 { 110 tiny = roundup(tiny, 8) 111 } else if size&3 == 0 { 112 tiny = roundup(tiny, 4) 113 } else if size&1 == 0 { 114 tiny = roundup(tiny, 2) 115 } 116 size1 := size + (uintptr(tiny) - uintptr(unsafe.Pointer(c.tiny))) 117 if size1 <= tinysize { 118 // The object fits into existing tiny block. 119 x = tiny 120 c.tiny = (*byte)(add(x, size)) 121 c.tinysize -= uintptr(size1) 122 c.local_tinyallocs++ 123 if debugMalloc { 124 mp := acquirem() 125 if mp.mallocing == 0 { 126 gothrow("bad malloc") 127 } 128 mp.mallocing = 0 129 if mp.curg != nil { 130 mp.curg.stackguard0 = mp.curg.stack.lo + _StackGuard 131 } 132 // Note: one releasem for the acquirem just above. 133 // The other for the acquirem at start of malloc. 134 releasem(mp) 135 releasem(mp) 136 } 137 return x 138 } 139 } 140 // Allocate a new maxTinySize block. 141 s = c.alloc[tinySizeClass] 142 v := s.freelist 143 if v.ptr() == nil { 144 systemstack(func() { 145 mCache_Refill(c, tinySizeClass) 146 }) 147 s = c.alloc[tinySizeClass] 148 v = s.freelist 149 } 150 s.freelist = v.ptr().next 151 s.ref++ 152 //TODO: prefetch v.next 153 x = unsafe.Pointer(v) 154 (*[2]uint64)(x)[0] = 0 155 (*[2]uint64)(x)[1] = 0 156 // See if we need to replace the existing tiny block with the new one 157 // based on amount of remaining free space. 158 if maxTinySize-size > tinysize { 159 c.tiny = (*byte)(add(x, size)) 160 c.tinysize = uintptr(maxTinySize - size) 161 } 162 size = maxTinySize 163 } else { 164 var sizeclass int8 165 if size <= 1024-8 { 166 sizeclass = size_to_class8[(size+7)>>3] 167 } else { 168 sizeclass = size_to_class128[(size-1024+127)>>7] 169 } 170 size = uintptr(class_to_size[sizeclass]) 171 s = c.alloc[sizeclass] 172 v := s.freelist 173 if v.ptr() == nil { 174 systemstack(func() { 175 mCache_Refill(c, int32(sizeclass)) 176 }) 177 s = c.alloc[sizeclass] 178 v = s.freelist 179 } 180 s.freelist = v.ptr().next 181 s.ref++ 182 //TODO: prefetch 183 x = unsafe.Pointer(v) 184 if flags&flagNoZero == 0 { 185 v.ptr().next = 0 186 if size > 2*ptrSize && ((*[2]uintptr)(x))[1] != 0 { 187 memclr(unsafe.Pointer(v), size) 188 } 189 } 190 } 191 c.local_cachealloc += intptr(size) 192 } else { 193 var s *mspan 194 systemstack(func() { 195 s = largeAlloc(size, uint32(flags)) 196 }) 197 x = unsafe.Pointer(uintptr(s.start << pageShift)) 198 size = uintptr(s.elemsize) 199 } 200 201 if flags&flagNoScan != 0 { 202 // All objects are pre-marked as noscan. 203 goto marked 204 } 205 206 // If allocating a defer+arg block, now that we've picked a malloc size 207 // large enough to hold everything, cut the "asked for" size down to 208 // just the defer header, so that the GC bitmap will record the arg block 209 // as containing nothing at all (as if it were unused space at the end of 210 // a malloc block caused by size rounding). 211 // The defer arg areas are scanned as part of scanstack. 212 if typ == deferType { 213 size0 = unsafe.Sizeof(_defer{}) 214 } 215 216 // From here till marked label marking the object as allocated 217 // and storing type info in the GC bitmap. 218 { 219 arena_start := uintptr(unsafe.Pointer(mheap_.arena_start)) 220 off := (uintptr(x) - arena_start) / ptrSize 221 xbits := (*uint8)(unsafe.Pointer(arena_start - off/wordsPerBitmapByte - 1)) 222 shift := (off % wordsPerBitmapByte) * gcBits 223 if debugMalloc && ((*xbits>>shift)&(bitMask|bitPtrMask)) != bitBoundary { 224 println("runtime: bits =", (*xbits>>shift)&(bitMask|bitPtrMask)) 225 gothrow("bad bits in markallocated") 226 } 227 228 var ti, te uintptr 229 var ptrmask *uint8 230 if size == ptrSize { 231 // It's one word and it has pointers, it must be a pointer. 232 *xbits |= (bitsPointer << 2) << shift 233 goto marked 234 } 235 if typ.kind&kindGCProg != 0 { 236 nptr := (uintptr(typ.size) + ptrSize - 1) / ptrSize 237 masksize := nptr 238 if masksize%2 != 0 { 239 masksize *= 2 // repeated 240 } 241 masksize = masksize * pointersPerByte / 8 // 4 bits per word 242 masksize++ // unroll flag in the beginning 243 if masksize > maxGCMask && typ.gc[1] != 0 { 244 // write barriers have not been updated to deal with this case yet. 245 gothrow("maxGCMask too small for now") 246 // If the mask is too large, unroll the program directly 247 // into the GC bitmap. It's 7 times slower than copying 248 // from the pre-unrolled mask, but saves 1/16 of type size 249 // memory for the mask. 250 systemstack(func() { 251 unrollgcproginplace_m(x, typ, size, size0) 252 }) 253 goto marked 254 } 255 ptrmask = (*uint8)(unsafe.Pointer(uintptr(typ.gc[0]))) 256 // Check whether the program is already unrolled 257 // by checking if the unroll flag byte is set 258 maskword := uintptr(atomicloadp(unsafe.Pointer(ptrmask))) 259 if *(*uint8)(unsafe.Pointer(&maskword)) == 0 { 260 systemstack(func() { 261 unrollgcprog_m(typ) 262 }) 263 } 264 ptrmask = (*uint8)(add(unsafe.Pointer(ptrmask), 1)) // skip the unroll flag byte 265 } else { 266 ptrmask = (*uint8)(unsafe.Pointer(typ.gc[0])) // pointer to unrolled mask 267 } 268 if size == 2*ptrSize { 269 *xbits = *ptrmask | bitBoundary 270 goto marked 271 } 272 te = uintptr(typ.size) / ptrSize 273 // If the type occupies odd number of words, its mask is repeated. 274 if te%2 == 0 { 275 te /= 2 276 } 277 // Copy pointer bitmask into the bitmap. 278 for i := uintptr(0); i < size0; i += 2 * ptrSize { 279 v := *(*uint8)(add(unsafe.Pointer(ptrmask), ti)) 280 ti++ 281 if ti == te { 282 ti = 0 283 } 284 if i == 0 { 285 v |= bitBoundary 286 } 287 if i+ptrSize == size0 { 288 v &^= uint8(bitPtrMask << 4) 289 } 290 291 *xbits = v 292 xbits = (*byte)(add(unsafe.Pointer(xbits), ^uintptr(0))) 293 } 294 if size0%(2*ptrSize) == 0 && size0 < size { 295 // Mark the word after last object's word as bitsDead. 296 *xbits = bitsDead << 2 297 } 298 } 299 marked: 300 301 // GCmarkterminate allocates black 302 // All slots hold nil so no scanning is needed. 303 // This may be racing with GC so do it atomically if there can be 304 // a race marking the bit. 305 if gcphase == _GCmarktermination { 306 systemstack(func() { 307 gcmarknewobject_m(uintptr(x)) 308 }) 309 } 310 311 if raceenabled { 312 racemalloc(x, size) 313 } 314 315 if debugMalloc { 316 mp := acquirem() 317 if mp.mallocing == 0 { 318 gothrow("bad malloc") 319 } 320 mp.mallocing = 0 321 if mp.curg != nil { 322 mp.curg.stackguard0 = mp.curg.stack.lo + _StackGuard 323 } 324 // Note: one releasem for the acquirem just above. 325 // The other for the acquirem at start of malloc. 326 releasem(mp) 327 releasem(mp) 328 } 329 330 if debug.allocfreetrace != 0 { 331 tracealloc(x, size, typ) 332 } 333 334 if rate := MemProfileRate; rate > 0 { 335 if size < uintptr(rate) && int32(size) < c.next_sample { 336 c.next_sample -= int32(size) 337 } else { 338 mp := acquirem() 339 profilealloc(mp, x, size) 340 releasem(mp) 341 } 342 } 343 344 if memstats.heap_alloc >= memstats.next_gc/2 { 345 gogc(0) 346 } 347 348 return x 349 } 350 351 func loadPtrMask(typ *_type) []uint8 { 352 var ptrmask *uint8 353 nptr := (uintptr(typ.size) + ptrSize - 1) / ptrSize 354 if typ.kind&kindGCProg != 0 { 355 masksize := nptr 356 if masksize%2 != 0 { 357 masksize *= 2 // repeated 358 } 359 masksize = masksize * pointersPerByte / 8 // 4 bits per word 360 masksize++ // unroll flag in the beginning 361 if masksize > maxGCMask && typ.gc[1] != 0 { 362 // write barriers have not been updated to deal with this case yet. 363 gothrow("maxGCMask too small for now") 364 } 365 ptrmask = (*uint8)(unsafe.Pointer(uintptr(typ.gc[0]))) 366 // Check whether the program is already unrolled 367 // by checking if the unroll flag byte is set 368 maskword := uintptr(atomicloadp(unsafe.Pointer(ptrmask))) 369 if *(*uint8)(unsafe.Pointer(&maskword)) == 0 { 370 systemstack(func() { 371 unrollgcprog_m(typ) 372 }) 373 } 374 ptrmask = (*uint8)(add(unsafe.Pointer(ptrmask), 1)) // skip the unroll flag byte 375 } else { 376 ptrmask = (*uint8)(unsafe.Pointer(typ.gc[0])) // pointer to unrolled mask 377 } 378 return (*[1 << 30]byte)(unsafe.Pointer(ptrmask))[:(nptr+1)/2] 379 } 380 381 // implementation of new builtin 382 func newobject(typ *_type) unsafe.Pointer { 383 flags := uint32(0) 384 if typ.kind&kindNoPointers != 0 { 385 flags |= flagNoScan 386 } 387 return mallocgc(uintptr(typ.size), typ, flags) 388 } 389 390 // implementation of make builtin for slices 391 func newarray(typ *_type, n uintptr) unsafe.Pointer { 392 flags := uint32(0) 393 if typ.kind&kindNoPointers != 0 { 394 flags |= flagNoScan 395 } 396 if int(n) < 0 || (typ.size > 0 && n > _MaxMem/uintptr(typ.size)) { 397 panic("runtime: allocation size out of range") 398 } 399 return mallocgc(uintptr(typ.size)*n, typ, flags) 400 } 401 402 // rawmem returns a chunk of pointerless memory. It is 403 // not zeroed. 404 func rawmem(size uintptr) unsafe.Pointer { 405 return mallocgc(size, nil, flagNoScan|flagNoZero) 406 } 407 408 // round size up to next size class 409 func goroundupsize(size uintptr) uintptr { 410 if size < maxSmallSize { 411 if size <= 1024-8 { 412 return uintptr(class_to_size[size_to_class8[(size+7)>>3]]) 413 } 414 return uintptr(class_to_size[size_to_class128[(size-1024+127)>>7]]) 415 } 416 if size+pageSize < size { 417 return size 418 } 419 return (size + pageSize - 1) &^ pageMask 420 } 421 422 func profilealloc(mp *m, x unsafe.Pointer, size uintptr) { 423 c := mp.mcache 424 rate := MemProfileRate 425 if size < uintptr(rate) { 426 // pick next profile time 427 // If you change this, also change allocmcache. 428 if rate > 0x3fffffff { // make 2*rate not overflow 429 rate = 0x3fffffff 430 } 431 next := int32(fastrand1()) % (2 * int32(rate)) 432 // Subtract the "remainder" of the current allocation. 433 // Otherwise objects that are close in size to sampling rate 434 // will be under-sampled, because we consistently discard this remainder. 435 next -= (int32(size) - c.next_sample) 436 if next < 0 { 437 next = 0 438 } 439 c.next_sample = next 440 } 441 442 mProf_Malloc(x, size) 443 } 444 445 // force = 1 - do GC regardless of current heap usage 446 // force = 2 - go GC and eager sweep 447 func gogc(force int32) { 448 // The gc is turned off (via enablegc) until the bootstrap has completed. 449 // Also, malloc gets called in the guts of a number of libraries that might be 450 // holding locks. To avoid deadlocks during stoptheworld, don't bother 451 // trying to run gc while holding a lock. The next mallocgc without a lock 452 // will do the gc instead. 453 mp := acquirem() 454 if gp := getg(); gp == mp.g0 || mp.locks > 1 || !memstats.enablegc || panicking != 0 || gcpercent < 0 { 455 releasem(mp) 456 return 457 } 458 releasem(mp) 459 mp = nil 460 461 semacquire(&worldsema, false) 462 463 if force == 0 && memstats.heap_alloc < memstats.next_gc { 464 // typically threads which lost the race to grab 465 // worldsema exit here when gc is done. 466 semrelease(&worldsema) 467 return 468 } 469 470 // Ok, we're doing it! Stop everybody else 471 startTime := nanotime() 472 mp = acquirem() 473 mp.gcing = 1 474 releasem(mp) 475 476 systemstack(stoptheworld) 477 systemstack(finishsweep_m) // finish sweep before we start concurrent scan. 478 if true { // To turn on concurrent scan and mark set to true... 479 systemstack(starttheworld) 480 // Do a concurrent heap scan before we stop the world. 481 systemstack(gcscan_m) 482 systemstack(stoptheworld) 483 systemstack(gcinstallmarkwb_m) 484 systemstack(starttheworld) 485 systemstack(gcmark_m) 486 systemstack(stoptheworld) 487 systemstack(gcinstalloffwb_m) 488 } 489 490 if mp != acquirem() { 491 gothrow("gogc: rescheduled") 492 } 493 494 clearpools() 495 496 // Run gc on the g0 stack. We do this so that the g stack 497 // we're currently running on will no longer change. Cuts 498 // the root set down a bit (g0 stacks are not scanned, and 499 // we don't need to scan gc's internal state). We also 500 // need to switch to g0 so we can shrink the stack. 501 n := 1 502 if debug.gctrace > 1 { 503 n = 2 504 } 505 eagersweep := force >= 2 506 for i := 0; i < n; i++ { 507 if i > 0 { 508 startTime = nanotime() 509 } 510 // switch to g0, call gc, then switch back 511 systemstack(func() { 512 gc_m(startTime, eagersweep) 513 }) 514 } 515 516 systemstack(func() { 517 gccheckmark_m(startTime, eagersweep) 518 }) 519 520 // all done 521 mp.gcing = 0 522 semrelease(&worldsema) 523 systemstack(starttheworld) 524 releasem(mp) 525 mp = nil 526 527 // now that gc is done, kick off finalizer thread if needed 528 if !concurrentSweep { 529 // give the queued finalizers, if any, a chance to run 530 Gosched() 531 } 532 } 533 534 func GCcheckmarkenable() { 535 systemstack(gccheckmarkenable_m) 536 } 537 538 func GCcheckmarkdisable() { 539 systemstack(gccheckmarkdisable_m) 540 } 541 542 // GC runs a garbage collection. 543 func GC() { 544 gogc(2) 545 } 546 547 // linker-provided 548 var noptrdata struct{} 549 var enoptrdata struct{} 550 var noptrbss struct{} 551 var enoptrbss struct{} 552 553 // SetFinalizer sets the finalizer associated with x to f. 554 // When the garbage collector finds an unreachable block 555 // with an associated finalizer, it clears the association and runs 556 // f(x) in a separate goroutine. This makes x reachable again, but 557 // now without an associated finalizer. Assuming that SetFinalizer 558 // is not called again, the next time the garbage collector sees 559 // that x is unreachable, it will free x. 560 // 561 // SetFinalizer(x, nil) clears any finalizer associated with x. 562 // 563 // The argument x must be a pointer to an object allocated by 564 // calling new or by taking the address of a composite literal. 565 // The argument f must be a function that takes a single argument 566 // to which x's type can be assigned, and can have arbitrary ignored return 567 // values. If either of these is not true, SetFinalizer aborts the 568 // program. 569 // 570 // Finalizers are run in dependency order: if A points at B, both have 571 // finalizers, and they are otherwise unreachable, only the finalizer 572 // for A runs; once A is freed, the finalizer for B can run. 573 // If a cyclic structure includes a block with a finalizer, that 574 // cycle is not guaranteed to be garbage collected and the finalizer 575 // is not guaranteed to run, because there is no ordering that 576 // respects the dependencies. 577 // 578 // The finalizer for x is scheduled to run at some arbitrary time after 579 // x becomes unreachable. 580 // There is no guarantee that finalizers will run before a program exits, 581 // so typically they are useful only for releasing non-memory resources 582 // associated with an object during a long-running program. 583 // For example, an os.File object could use a finalizer to close the 584 // associated operating system file descriptor when a program discards 585 // an os.File without calling Close, but it would be a mistake 586 // to depend on a finalizer to flush an in-memory I/O buffer such as a 587 // bufio.Writer, because the buffer would not be flushed at program exit. 588 // 589 // It is not guaranteed that a finalizer will run if the size of *x is 590 // zero bytes. 591 // 592 // It is not guaranteed that a finalizer will run for objects allocated 593 // in initializers for package-level variables. Such objects may be 594 // linker-allocated, not heap-allocated. 595 // 596 // A single goroutine runs all finalizers for a program, sequentially. 597 // If a finalizer must run for a long time, it should do so by starting 598 // a new goroutine. 599 func SetFinalizer(obj interface{}, finalizer interface{}) { 600 e := (*eface)(unsafe.Pointer(&obj)) 601 etyp := e._type 602 if etyp == nil { 603 gothrow("runtime.SetFinalizer: first argument is nil") 604 } 605 if etyp.kind&kindMask != kindPtr { 606 gothrow("runtime.SetFinalizer: first argument is " + *etyp._string + ", not pointer") 607 } 608 ot := (*ptrtype)(unsafe.Pointer(etyp)) 609 if ot.elem == nil { 610 gothrow("nil elem type!") 611 } 612 613 // find the containing object 614 _, base, _ := findObject(e.data) 615 616 if base == nil { 617 // 0-length objects are okay. 618 if e.data == unsafe.Pointer(&zerobase) { 619 return 620 } 621 622 // Global initializers might be linker-allocated. 623 // var Foo = &Object{} 624 // func main() { 625 // runtime.SetFinalizer(Foo, nil) 626 // } 627 // The relevant segments are: noptrdata, data, bss, noptrbss. 628 // We cannot assume they are in any order or even contiguous, 629 // due to external linking. 630 if uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrdata)) || 631 uintptr(unsafe.Pointer(&data)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&edata)) || 632 uintptr(unsafe.Pointer(&bss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&ebss)) || 633 uintptr(unsafe.Pointer(&noptrbss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrbss)) { 634 return 635 } 636 gothrow("runtime.SetFinalizer: pointer not in allocated block") 637 } 638 639 if e.data != base { 640 // As an implementation detail we allow to set finalizers for an inner byte 641 // of an object if it could come from tiny alloc (see mallocgc for details). 642 if ot.elem == nil || ot.elem.kind&kindNoPointers == 0 || ot.elem.size >= maxTinySize { 643 gothrow("runtime.SetFinalizer: pointer not at beginning of allocated block") 644 } 645 } 646 647 f := (*eface)(unsafe.Pointer(&finalizer)) 648 ftyp := f._type 649 if ftyp == nil { 650 // switch to system stack and remove finalizer 651 systemstack(func() { 652 removefinalizer(e.data) 653 }) 654 return 655 } 656 657 if ftyp.kind&kindMask != kindFunc { 658 gothrow("runtime.SetFinalizer: second argument is " + *ftyp._string + ", not a function") 659 } 660 ft := (*functype)(unsafe.Pointer(ftyp)) 661 ins := *(*[]*_type)(unsafe.Pointer(&ft.in)) 662 if ft.dotdotdot || len(ins) != 1 { 663 gothrow("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string) 664 } 665 fint := ins[0] 666 switch { 667 case fint == etyp: 668 // ok - same type 669 goto okarg 670 case fint.kind&kindMask == kindPtr: 671 if (fint.x == nil || fint.x.name == nil || etyp.x == nil || etyp.x.name == nil) && (*ptrtype)(unsafe.Pointer(fint)).elem == ot.elem { 672 // ok - not same type, but both pointers, 673 // one or the other is unnamed, and same element type, so assignable. 674 goto okarg 675 } 676 case fint.kind&kindMask == kindInterface: 677 ityp := (*interfacetype)(unsafe.Pointer(fint)) 678 if len(ityp.mhdr) == 0 { 679 // ok - satisfies empty interface 680 goto okarg 681 } 682 if _, ok := assertE2I2(ityp, obj); ok { 683 goto okarg 684 } 685 } 686 gothrow("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string) 687 okarg: 688 // compute size needed for return parameters 689 nret := uintptr(0) 690 for _, t := range *(*[]*_type)(unsafe.Pointer(&ft.out)) { 691 nret = round(nret, uintptr(t.align)) + uintptr(t.size) 692 } 693 nret = round(nret, ptrSize) 694 695 // make sure we have a finalizer goroutine 696 createfing() 697 698 systemstack(func() { 699 if !addfinalizer(e.data, (*funcval)(f.data), nret, fint, ot) { 700 gothrow("runtime.SetFinalizer: finalizer already set") 701 } 702 }) 703 } 704 705 // round n up to a multiple of a. a must be a power of 2. 706 func round(n, a uintptr) uintptr { 707 return (n + a - 1) &^ (a - 1) 708 } 709 710 // Look up pointer v in heap. Return the span containing the object, 711 // the start of the object, and the size of the object. If the object 712 // does not exist, return nil, nil, 0. 713 func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) { 714 c := gomcache() 715 c.local_nlookup++ 716 if ptrSize == 4 && c.local_nlookup >= 1<<30 { 717 // purge cache stats to prevent overflow 718 lock(&mheap_.lock) 719 purgecachedstats(c) 720 unlock(&mheap_.lock) 721 } 722 723 // find span 724 arena_start := uintptr(unsafe.Pointer(mheap_.arena_start)) 725 arena_used := uintptr(unsafe.Pointer(mheap_.arena_used)) 726 if uintptr(v) < arena_start || uintptr(v) >= arena_used { 727 return 728 } 729 p := uintptr(v) >> pageShift 730 q := p - arena_start>>pageShift 731 s = *(**mspan)(add(unsafe.Pointer(mheap_.spans), q*ptrSize)) 732 if s == nil { 733 return 734 } 735 x = unsafe.Pointer(uintptr(s.start) << pageShift) 736 737 if uintptr(v) < uintptr(x) || uintptr(v) >= uintptr(unsafe.Pointer(s.limit)) || s.state != mSpanInUse { 738 s = nil 739 x = nil 740 return 741 } 742 743 n = uintptr(s.elemsize) 744 if s.sizeclass != 0 { 745 x = add(x, (uintptr(v)-uintptr(x))/n*n) 746 } 747 return 748 } 749 750 var fingCreate uint32 751 752 func createfing() { 753 // start the finalizer goroutine exactly once 754 if fingCreate == 0 && cas(&fingCreate, 0, 1) { 755 go runfinq() 756 } 757 } 758 759 // This is the goroutine that runs all of the finalizers 760 func runfinq() { 761 var ( 762 frame unsafe.Pointer 763 framecap uintptr 764 ) 765 766 for { 767 lock(&finlock) 768 fb := finq 769 finq = nil 770 if fb == nil { 771 gp := getg() 772 fing = gp 773 fingwait = true 774 gp.issystem = true 775 goparkunlock(&finlock, "finalizer wait") 776 gp.issystem = false 777 continue 778 } 779 unlock(&finlock) 780 if raceenabled { 781 racefingo() 782 } 783 for fb != nil { 784 for i := int32(0); i < fb.cnt; i++ { 785 f := (*finalizer)(add(unsafe.Pointer(&fb.fin), uintptr(i)*unsafe.Sizeof(finalizer{}))) 786 787 framesz := unsafe.Sizeof((interface{})(nil)) + uintptr(f.nret) 788 if framecap < framesz { 789 // The frame does not contain pointers interesting for GC, 790 // all not yet finalized objects are stored in finq. 791 // If we do not mark it as FlagNoScan, 792 // the last finalized object is not collected. 793 frame = mallocgc(framesz, nil, flagNoScan) 794 framecap = framesz 795 } 796 797 if f.fint == nil { 798 gothrow("missing type in runfinq") 799 } 800 switch f.fint.kind & kindMask { 801 case kindPtr: 802 // direct use of pointer 803 *(*unsafe.Pointer)(frame) = f.arg 804 case kindInterface: 805 ityp := (*interfacetype)(unsafe.Pointer(f.fint)) 806 // set up with empty interface 807 (*eface)(frame)._type = &f.ot.typ 808 (*eface)(frame).data = f.arg 809 if len(ityp.mhdr) != 0 { 810 // convert to interface with methods 811 // this conversion is guaranteed to succeed - we checked in SetFinalizer 812 *(*fInterface)(frame) = assertE2I(ityp, *(*interface{})(frame)) 813 } 814 default: 815 gothrow("bad kind in runfinq") 816 } 817 reflectcall(unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz)) 818 819 // drop finalizer queue references to finalized object 820 f.fn = nil 821 f.arg = nil 822 f.ot = nil 823 } 824 fb.cnt = 0 825 next := fb.next 826 lock(&finlock) 827 fb.next = finc 828 finc = fb 829 unlock(&finlock) 830 fb = next 831 } 832 } 833 } 834 835 var persistent struct { 836 lock mutex 837 pos unsafe.Pointer 838 end unsafe.Pointer 839 } 840 841 // Wrapper around sysAlloc that can allocate small chunks. 842 // There is no associated free operation. 843 // Intended for things like function/type/debug-related persistent data. 844 // If align is 0, uses default align (currently 8). 845 func persistentalloc(size, align uintptr, stat *uint64) unsafe.Pointer { 846 const ( 847 chunk = 256 << 10 848 maxBlock = 64 << 10 // VM reservation granularity is 64K on windows 849 ) 850 851 if align != 0 { 852 if align&(align-1) != 0 { 853 gothrow("persistentalloc: align is not a power of 2") 854 } 855 if align > _PageSize { 856 gothrow("persistentalloc: align is too large") 857 } 858 } else { 859 align = 8 860 } 861 862 if size >= maxBlock { 863 return sysAlloc(size, stat) 864 } 865 866 lock(&persistent.lock) 867 persistent.pos = roundup(persistent.pos, align) 868 if uintptr(persistent.pos)+size > uintptr(persistent.end) { 869 persistent.pos = sysAlloc(chunk, &memstats.other_sys) 870 if persistent.pos == nil { 871 unlock(&persistent.lock) 872 gothrow("runtime: cannot allocate memory") 873 } 874 persistent.end = add(persistent.pos, chunk) 875 } 876 p := persistent.pos 877 persistent.pos = add(persistent.pos, size) 878 unlock(&persistent.lock) 879 880 if stat != &memstats.other_sys { 881 xadd64(stat, int64(size)) 882 xadd64(&memstats.other_sys, -int64(size)) 883 } 884 return p 885 }