2016-03-01 15:57:46 -07:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
2015-01-16 12:43:38 -07:00
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
// Garbage collector: finalizers and block profiling.
|
|
|
|
|
|
|
|
package runtime
|
|
|
|
|
2015-11-02 12:09:24 -07:00
|
|
|
import (
|
|
|
|
"runtime/internal/atomic"
|
2015-11-11 10:39:30 -07:00
|
|
|
"runtime/internal/sys"
|
2015-11-02 12:09:24 -07:00
|
|
|
"unsafe"
|
|
|
|
)
|
2015-01-16 12:43:38 -07:00
|
|
|
|
2017-01-31 09:46:36 -07:00
|
|
|
// finblock is an array of finalizers to be executed. finblocks are
|
|
|
|
// arranged in a linked list for the finalizer queue.
|
|
|
|
//
|
2016-10-11 20:58:21 -06:00
|
|
|
// finblock is allocated from non-GC'd memory, so any heap pointers
|
2017-01-31 09:46:36 -07:00
|
|
|
// must be specially handled. GC currently assumes that the finalizer
|
|
|
|
// queue does not grow during marking (but it can shrink).
|
2016-10-11 20:58:21 -06:00
|
|
|
//
|
|
|
|
//go:notinheap
|
2015-02-19 11:38:46 -07:00
|
|
|
type finblock struct {
|
|
|
|
alllink *finblock
|
|
|
|
next *finblock
|
2016-10-14 11:39:07 -06:00
|
|
|
cnt uint32
|
2015-02-19 11:38:46 -07:00
|
|
|
_ int32
|
2015-11-11 10:39:30 -07:00
|
|
|
fin [(_FinBlockSize - 2*sys.PtrSize - 2*4) / unsafe.Sizeof(finalizer{})]finalizer
|
2015-02-19 11:38:46 -07:00
|
|
|
}
|
|
|
|
|
2015-01-16 12:43:38 -07:00
|
|
|
var finlock mutex // protects the following variables
|
|
|
|
var fing *g // goroutine that runs finalizers
|
|
|
|
var finq *finblock // list of finalizers that are to be executed
|
|
|
|
var finc *finblock // cache of free blocks
|
2015-11-11 10:39:30 -07:00
|
|
|
var finptrmask [_FinBlockSize / sys.PtrSize / 8]byte
|
2015-01-16 12:43:38 -07:00
|
|
|
var fingwait bool
|
|
|
|
var fingwake bool
|
|
|
|
var allfin *finblock // list of all blocks
|
|
|
|
|
2015-02-19 11:38:46 -07:00
|
|
|
// NOTE: Layout known to queuefinalizer.
|
|
|
|
type finalizer struct {
|
2016-10-11 20:58:21 -06:00
|
|
|
fn *funcval // function to call (may be a heap pointer)
|
|
|
|
arg unsafe.Pointer // ptr to object (may be a heap pointer)
|
2015-02-19 11:38:46 -07:00
|
|
|
nret uintptr // bytes of return values from fn
|
|
|
|
fint *_type // type of first argument of fn
|
2016-10-11 20:58:21 -06:00
|
|
|
ot *ptrtype // type of ptr to object (may be a heap pointer)
|
2015-02-19 11:38:46 -07:00
|
|
|
}
|
|
|
|
|
2015-01-16 12:43:38 -07:00
|
|
|
var finalizer1 = [...]byte{
|
cmd/internal/gc, runtime: use 1-bit bitmap for stack frames, data, bss
The bitmaps were 2 bits per pointer because we needed to distinguish
scalar, pointer, multiword, and we used the leftover value to distinguish
uninitialized from scalar, even though the garbage collector (GC) didn't care.
Now that there are no multiword structures from the GC's point of view,
cut the bitmaps down to 1 bit per pointer, recording just live pointer vs not.
The GC assumes the same layout for stack frames and for the maps
describing the global data and bss sections, so change them all in one CL.
The code still refers to 4-bit heap bitmaps and 2-bit "type bitmaps", since
the 2-bit representation lives (at least for now) in some of the reflect data.
Because these stack frame bitmaps are stored directly in the rodata in
the binary, this CL reduces the size of the 6g binary by about 1.1%.
Performance change is basically a wash, but using less memory,
and smaller binaries, and enables other bitmap reductions.
name old mean new mean delta
BenchmarkBinaryTree17 13.2s × (0.97,1.03) 13.0s × (0.99,1.01) -0.93% (p=0.005)
BenchmarkBinaryTree17-2 9.69s × (0.96,1.05) 9.51s × (0.96,1.03) -1.86% (p=0.001)
BenchmarkBinaryTree17-4 10.1s × (0.97,1.05) 10.0s × (0.96,1.05) ~ (p=0.141)
BenchmarkFannkuch11 4.35s × (0.99,1.01) 4.43s × (0.98,1.04) +1.75% (p=0.001)
BenchmarkFannkuch11-2 4.31s × (0.99,1.03) 4.32s × (1.00,1.00) ~ (p=0.095)
BenchmarkFannkuch11-4 4.32s × (0.99,1.02) 4.38s × (0.98,1.04) +1.38% (p=0.008)
BenchmarkFmtFprintfEmpty 83.5ns × (0.97,1.10) 87.3ns × (0.92,1.11) +4.55% (p=0.014)
BenchmarkFmtFprintfEmpty-2 81.8ns × (0.98,1.04) 82.5ns × (0.97,1.08) ~ (p=0.364)
BenchmarkFmtFprintfEmpty-4 80.9ns × (0.99,1.01) 82.6ns × (0.97,1.08) +2.12% (p=0.010)
BenchmarkFmtFprintfString 320ns × (0.95,1.04) 322ns × (0.97,1.05) ~ (p=0.368)
BenchmarkFmtFprintfString-2 303ns × (0.97,1.04) 304ns × (0.97,1.04) ~ (p=0.484)
BenchmarkFmtFprintfString-4 305ns × (0.97,1.05) 306ns × (0.98,1.05) ~ (p=0.543)
BenchmarkFmtFprintfInt 311ns × (0.98,1.03) 319ns × (0.97,1.03) +2.63% (p=0.000)
BenchmarkFmtFprintfInt-2 297ns × (0.98,1.04) 301ns × (0.97,1.04) +1.19% (p=0.023)
BenchmarkFmtFprintfInt-4 302ns × (0.98,1.02) 304ns × (0.97,1.03) ~ (p=0.126)
BenchmarkFmtFprintfIntInt 554ns × (0.96,1.05) 554ns × (0.97,1.03) ~ (p=0.975)
BenchmarkFmtFprintfIntInt-2 520ns × (0.98,1.03) 517ns × (0.98,1.02) ~ (p=0.153)
BenchmarkFmtFprintfIntInt-4 524ns × (0.98,1.02) 525ns × (0.98,1.03) ~ (p=0.597)
BenchmarkFmtFprintfPrefixedInt 433ns × (0.97,1.06) 434ns × (0.97,1.06) ~ (p=0.804)
BenchmarkFmtFprintfPrefixedInt-2 413ns × (0.98,1.04) 413ns × (0.98,1.03) ~ (p=0.881)
BenchmarkFmtFprintfPrefixedInt-4 420ns × (0.97,1.03) 421ns × (0.97,1.03) ~ (p=0.561)
BenchmarkFmtFprintfFloat 620ns × (0.99,1.03) 636ns × (0.97,1.03) +2.57% (p=0.000)
BenchmarkFmtFprintfFloat-2 601ns × (0.98,1.02) 617ns × (0.98,1.03) +2.58% (p=0.000)
BenchmarkFmtFprintfFloat-4 613ns × (0.98,1.03) 626ns × (0.98,1.02) +2.15% (p=0.000)
BenchmarkFmtManyArgs 2.19µs × (0.96,1.04) 2.23µs × (0.97,1.02) +1.65% (p=0.000)
BenchmarkFmtManyArgs-2 2.08µs × (0.98,1.03) 2.10µs × (0.99,1.02) +0.79% (p=0.019)
BenchmarkFmtManyArgs-4 2.10µs × (0.98,1.02) 2.13µs × (0.98,1.02) +1.72% (p=0.000)
BenchmarkGobDecode 21.3ms × (0.97,1.05) 21.1ms × (0.97,1.04) -1.36% (p=0.025)
BenchmarkGobDecode-2 20.0ms × (0.97,1.03) 19.2ms × (0.97,1.03) -4.00% (p=0.000)
BenchmarkGobDecode-4 19.5ms × (0.99,1.02) 19.0ms × (0.99,1.01) -2.39% (p=0.000)
BenchmarkGobEncode 18.3ms × (0.95,1.07) 18.1ms × (0.96,1.08) ~ (p=0.305)
BenchmarkGobEncode-2 16.8ms × (0.97,1.02) 16.4ms × (0.98,1.02) -2.79% (p=0.000)
BenchmarkGobEncode-4 15.4ms × (0.98,1.02) 15.4ms × (0.98,1.02) ~ (p=0.465)
BenchmarkGzip 650ms × (0.98,1.03) 655ms × (0.97,1.04) ~ (p=0.075)
BenchmarkGzip-2 652ms × (0.98,1.03) 655ms × (0.98,1.02) ~ (p=0.337)
BenchmarkGzip-4 656ms × (0.98,1.04) 653ms × (0.98,1.03) ~ (p=0.291)
BenchmarkGunzip 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.507)
BenchmarkGunzip-2 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.313)
BenchmarkGunzip-4 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.312)
BenchmarkHTTPClientServer 110µs × (0.98,1.03) 109µs × (0.99,1.02) -1.40% (p=0.000)
BenchmarkHTTPClientServer-2 154µs × (0.90,1.08) 149µs × (0.90,1.08) -3.43% (p=0.007)
BenchmarkHTTPClientServer-4 138µs × (0.97,1.04) 138µs × (0.96,1.04) ~ (p=0.670)
BenchmarkJSONEncode 40.2ms × (0.98,1.02) 40.2ms × (0.98,1.05) ~ (p=0.828)
BenchmarkJSONEncode-2 35.1ms × (0.99,1.02) 35.2ms × (0.98,1.03) ~ (p=0.392)
BenchmarkJSONEncode-4 35.3ms × (0.98,1.03) 35.3ms × (0.98,1.02) ~ (p=0.813)
BenchmarkJSONDecode 119ms × (0.97,1.02) 117ms × (0.98,1.02) -1.80% (p=0.000)
BenchmarkJSONDecode-2 115ms × (0.99,1.02) 114ms × (0.98,1.02) -1.18% (p=0.000)
BenchmarkJSONDecode-4 116ms × (0.98,1.02) 114ms × (0.98,1.02) -1.43% (p=0.000)
BenchmarkMandelbrot200 6.03ms × (1.00,1.01) 6.03ms × (1.00,1.01) ~ (p=0.985)
BenchmarkMandelbrot200-2 6.03ms × (1.00,1.01) 6.02ms × (1.00,1.01) ~ (p=0.320)
BenchmarkMandelbrot200-4 6.03ms × (1.00,1.01) 6.03ms × (1.00,1.01) ~ (p=0.799)
BenchmarkGoParse 8.63ms × (0.89,1.10) 8.58ms × (0.93,1.09) ~ (p=0.667)
BenchmarkGoParse-2 8.20ms × (0.97,1.04) 8.37ms × (0.97,1.04) +1.96% (p=0.001)
BenchmarkGoParse-4 8.00ms × (0.98,1.02) 8.14ms × (0.99,1.02) +1.75% (p=0.000)
BenchmarkRegexpMatchEasy0_32 162ns × (1.00,1.01) 164ns × (0.98,1.04) +1.35% (p=0.011)
BenchmarkRegexpMatchEasy0_32-2 161ns × (1.00,1.01) 161ns × (1.00,1.00) ~ (p=0.185)
BenchmarkRegexpMatchEasy0_32-4 161ns × (1.00,1.00) 161ns × (1.00,1.00) -0.19% (p=0.001)
BenchmarkRegexpMatchEasy0_1K 540ns × (0.99,1.02) 566ns × (0.98,1.04) +4.98% (p=0.000)
BenchmarkRegexpMatchEasy0_1K-2 540ns × (0.99,1.01) 557ns × (0.99,1.01) +3.21% (p=0.000)
BenchmarkRegexpMatchEasy0_1K-4 541ns × (0.99,1.01) 559ns × (0.99,1.01) +3.26% (p=0.000)
BenchmarkRegexpMatchEasy1_32 139ns × (0.98,1.04) 139ns × (0.99,1.03) ~ (p=0.979)
BenchmarkRegexpMatchEasy1_32-2 139ns × (0.99,1.04) 139ns × (0.99,1.02) ~ (p=0.777)
BenchmarkRegexpMatchEasy1_32-4 139ns × (0.98,1.04) 139ns × (0.99,1.04) ~ (p=0.771)
BenchmarkRegexpMatchEasy1_1K 890ns × (0.99,1.03) 885ns × (1.00,1.01) -0.50% (p=0.004)
BenchmarkRegexpMatchEasy1_1K-2 888ns × (0.99,1.01) 885ns × (0.99,1.01) -0.37% (p=0.004)
BenchmarkRegexpMatchEasy1_1K-4 890ns × (0.99,1.02) 884ns × (1.00,1.00) -0.70% (p=0.000)
BenchmarkRegexpMatchMedium_32 252ns × (0.99,1.01) 251ns × (0.99,1.01) ~ (p=0.081)
BenchmarkRegexpMatchMedium_32-2 254ns × (0.99,1.04) 252ns × (0.99,1.01) -0.78% (p=0.027)
BenchmarkRegexpMatchMedium_32-4 253ns × (0.99,1.04) 252ns × (0.99,1.01) -0.70% (p=0.022)
BenchmarkRegexpMatchMedium_1K 72.9µs × (0.99,1.01) 72.7µs × (1.00,1.00) ~ (p=0.064)
BenchmarkRegexpMatchMedium_1K-2 74.1µs × (0.98,1.05) 72.9µs × (1.00,1.01) -1.61% (p=0.001)
BenchmarkRegexpMatchMedium_1K-4 73.6µs × (0.99,1.05) 72.8µs × (1.00,1.00) -1.13% (p=0.007)
BenchmarkRegexpMatchHard_32 3.88µs × (0.99,1.03) 3.92µs × (0.98,1.05) ~ (p=0.143)
BenchmarkRegexpMatchHard_32-2 3.89µs × (0.99,1.03) 3.93µs × (0.98,1.09) ~ (p=0.278)
BenchmarkRegexpMatchHard_32-4 3.90µs × (0.99,1.05) 3.93µs × (0.98,1.05) ~ (p=0.252)
BenchmarkRegexpMatchHard_1K 118µs × (0.99,1.01) 117µs × (0.99,1.02) -0.54% (p=0.003)
BenchmarkRegexpMatchHard_1K-2 118µs × (0.99,1.01) 118µs × (0.99,1.03) ~ (p=0.581)
BenchmarkRegexpMatchHard_1K-4 118µs × (0.99,1.02) 117µs × (0.99,1.01) -0.54% (p=0.002)
BenchmarkRevcomp 991ms × (0.95,1.10) 989ms × (0.94,1.08) ~ (p=0.879)
BenchmarkRevcomp-2 978ms × (0.95,1.11) 962ms × (0.96,1.08) ~ (p=0.257)
BenchmarkRevcomp-4 979ms × (0.96,1.07) 974ms × (0.96,1.11) ~ (p=0.678)
BenchmarkTemplate 141ms × (0.99,1.02) 145ms × (0.99,1.02) +2.75% (p=0.000)
BenchmarkTemplate-2 135ms × (0.98,1.02) 138ms × (0.99,1.02) +2.34% (p=0.000)
BenchmarkTemplate-4 136ms × (0.98,1.02) 140ms × (0.99,1.02) +2.71% (p=0.000)
BenchmarkTimeParse 640ns × (0.99,1.01) 622ns × (0.99,1.01) -2.88% (p=0.000)
BenchmarkTimeParse-2 640ns × (0.99,1.01) 622ns × (1.00,1.00) -2.81% (p=0.000)
BenchmarkTimeParse-4 640ns × (1.00,1.01) 622ns × (0.99,1.01) -2.82% (p=0.000)
BenchmarkTimeFormat 730ns × (0.98,1.02) 731ns × (0.98,1.03) ~ (p=0.767)
BenchmarkTimeFormat-2 709ns × (0.99,1.02) 707ns × (0.99,1.02) ~ (p=0.347)
BenchmarkTimeFormat-4 717ns × (0.98,1.01) 718ns × (0.98,1.02) ~ (p=0.793)
Change-Id: Ie779c47e912bf80eb918bafa13638bd8dfd6c2d9
Reviewed-on: https://go-review.googlesource.com/9406
Reviewed-by: Rick Hudson <rlh@golang.org>
2015-04-27 20:45:57 -06:00
|
|
|
// Each Finalizer is 5 words, ptr ptr INT ptr ptr (INT = uintptr here)
|
|
|
|
// Each byte describes 8 words.
|
|
|
|
// Need 8 Finalizers described by 5 bytes before pattern repeats:
|
|
|
|
// ptr ptr INT ptr ptr
|
|
|
|
// ptr ptr INT ptr ptr
|
|
|
|
// ptr ptr INT ptr ptr
|
|
|
|
// ptr ptr INT ptr ptr
|
|
|
|
// ptr ptr INT ptr ptr
|
|
|
|
// ptr ptr INT ptr ptr
|
|
|
|
// ptr ptr INT ptr ptr
|
|
|
|
// ptr ptr INT ptr ptr
|
2015-01-16 12:43:38 -07:00
|
|
|
// aka
|
cmd/internal/gc, runtime: use 1-bit bitmap for stack frames, data, bss
The bitmaps were 2 bits per pointer because we needed to distinguish
scalar, pointer, multiword, and we used the leftover value to distinguish
uninitialized from scalar, even though the garbage collector (GC) didn't care.
Now that there are no multiword structures from the GC's point of view,
cut the bitmaps down to 1 bit per pointer, recording just live pointer vs not.
The GC assumes the same layout for stack frames and for the maps
describing the global data and bss sections, so change them all in one CL.
The code still refers to 4-bit heap bitmaps and 2-bit "type bitmaps", since
the 2-bit representation lives (at least for now) in some of the reflect data.
Because these stack frame bitmaps are stored directly in the rodata in
the binary, this CL reduces the size of the 6g binary by about 1.1%.
Performance change is basically a wash, but using less memory,
and smaller binaries, and enables other bitmap reductions.
name old mean new mean delta
BenchmarkBinaryTree17 13.2s × (0.97,1.03) 13.0s × (0.99,1.01) -0.93% (p=0.005)
BenchmarkBinaryTree17-2 9.69s × (0.96,1.05) 9.51s × (0.96,1.03) -1.86% (p=0.001)
BenchmarkBinaryTree17-4 10.1s × (0.97,1.05) 10.0s × (0.96,1.05) ~ (p=0.141)
BenchmarkFannkuch11 4.35s × (0.99,1.01) 4.43s × (0.98,1.04) +1.75% (p=0.001)
BenchmarkFannkuch11-2 4.31s × (0.99,1.03) 4.32s × (1.00,1.00) ~ (p=0.095)
BenchmarkFannkuch11-4 4.32s × (0.99,1.02) 4.38s × (0.98,1.04) +1.38% (p=0.008)
BenchmarkFmtFprintfEmpty 83.5ns × (0.97,1.10) 87.3ns × (0.92,1.11) +4.55% (p=0.014)
BenchmarkFmtFprintfEmpty-2 81.8ns × (0.98,1.04) 82.5ns × (0.97,1.08) ~ (p=0.364)
BenchmarkFmtFprintfEmpty-4 80.9ns × (0.99,1.01) 82.6ns × (0.97,1.08) +2.12% (p=0.010)
BenchmarkFmtFprintfString 320ns × (0.95,1.04) 322ns × (0.97,1.05) ~ (p=0.368)
BenchmarkFmtFprintfString-2 303ns × (0.97,1.04) 304ns × (0.97,1.04) ~ (p=0.484)
BenchmarkFmtFprintfString-4 305ns × (0.97,1.05) 306ns × (0.98,1.05) ~ (p=0.543)
BenchmarkFmtFprintfInt 311ns × (0.98,1.03) 319ns × (0.97,1.03) +2.63% (p=0.000)
BenchmarkFmtFprintfInt-2 297ns × (0.98,1.04) 301ns × (0.97,1.04) +1.19% (p=0.023)
BenchmarkFmtFprintfInt-4 302ns × (0.98,1.02) 304ns × (0.97,1.03) ~ (p=0.126)
BenchmarkFmtFprintfIntInt 554ns × (0.96,1.05) 554ns × (0.97,1.03) ~ (p=0.975)
BenchmarkFmtFprintfIntInt-2 520ns × (0.98,1.03) 517ns × (0.98,1.02) ~ (p=0.153)
BenchmarkFmtFprintfIntInt-4 524ns × (0.98,1.02) 525ns × (0.98,1.03) ~ (p=0.597)
BenchmarkFmtFprintfPrefixedInt 433ns × (0.97,1.06) 434ns × (0.97,1.06) ~ (p=0.804)
BenchmarkFmtFprintfPrefixedInt-2 413ns × (0.98,1.04) 413ns × (0.98,1.03) ~ (p=0.881)
BenchmarkFmtFprintfPrefixedInt-4 420ns × (0.97,1.03) 421ns × (0.97,1.03) ~ (p=0.561)
BenchmarkFmtFprintfFloat 620ns × (0.99,1.03) 636ns × (0.97,1.03) +2.57% (p=0.000)
BenchmarkFmtFprintfFloat-2 601ns × (0.98,1.02) 617ns × (0.98,1.03) +2.58% (p=0.000)
BenchmarkFmtFprintfFloat-4 613ns × (0.98,1.03) 626ns × (0.98,1.02) +2.15% (p=0.000)
BenchmarkFmtManyArgs 2.19µs × (0.96,1.04) 2.23µs × (0.97,1.02) +1.65% (p=0.000)
BenchmarkFmtManyArgs-2 2.08µs × (0.98,1.03) 2.10µs × (0.99,1.02) +0.79% (p=0.019)
BenchmarkFmtManyArgs-4 2.10µs × (0.98,1.02) 2.13µs × (0.98,1.02) +1.72% (p=0.000)
BenchmarkGobDecode 21.3ms × (0.97,1.05) 21.1ms × (0.97,1.04) -1.36% (p=0.025)
BenchmarkGobDecode-2 20.0ms × (0.97,1.03) 19.2ms × (0.97,1.03) -4.00% (p=0.000)
BenchmarkGobDecode-4 19.5ms × (0.99,1.02) 19.0ms × (0.99,1.01) -2.39% (p=0.000)
BenchmarkGobEncode 18.3ms × (0.95,1.07) 18.1ms × (0.96,1.08) ~ (p=0.305)
BenchmarkGobEncode-2 16.8ms × (0.97,1.02) 16.4ms × (0.98,1.02) -2.79% (p=0.000)
BenchmarkGobEncode-4 15.4ms × (0.98,1.02) 15.4ms × (0.98,1.02) ~ (p=0.465)
BenchmarkGzip 650ms × (0.98,1.03) 655ms × (0.97,1.04) ~ (p=0.075)
BenchmarkGzip-2 652ms × (0.98,1.03) 655ms × (0.98,1.02) ~ (p=0.337)
BenchmarkGzip-4 656ms × (0.98,1.04) 653ms × (0.98,1.03) ~ (p=0.291)
BenchmarkGunzip 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.507)
BenchmarkGunzip-2 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.313)
BenchmarkGunzip-4 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.312)
BenchmarkHTTPClientServer 110µs × (0.98,1.03) 109µs × (0.99,1.02) -1.40% (p=0.000)
BenchmarkHTTPClientServer-2 154µs × (0.90,1.08) 149µs × (0.90,1.08) -3.43% (p=0.007)
BenchmarkHTTPClientServer-4 138µs × (0.97,1.04) 138µs × (0.96,1.04) ~ (p=0.670)
BenchmarkJSONEncode 40.2ms × (0.98,1.02) 40.2ms × (0.98,1.05) ~ (p=0.828)
BenchmarkJSONEncode-2 35.1ms × (0.99,1.02) 35.2ms × (0.98,1.03) ~ (p=0.392)
BenchmarkJSONEncode-4 35.3ms × (0.98,1.03) 35.3ms × (0.98,1.02) ~ (p=0.813)
BenchmarkJSONDecode 119ms × (0.97,1.02) 117ms × (0.98,1.02) -1.80% (p=0.000)
BenchmarkJSONDecode-2 115ms × (0.99,1.02) 114ms × (0.98,1.02) -1.18% (p=0.000)
BenchmarkJSONDecode-4 116ms × (0.98,1.02) 114ms × (0.98,1.02) -1.43% (p=0.000)
BenchmarkMandelbrot200 6.03ms × (1.00,1.01) 6.03ms × (1.00,1.01) ~ (p=0.985)
BenchmarkMandelbrot200-2 6.03ms × (1.00,1.01) 6.02ms × (1.00,1.01) ~ (p=0.320)
BenchmarkMandelbrot200-4 6.03ms × (1.00,1.01) 6.03ms × (1.00,1.01) ~ (p=0.799)
BenchmarkGoParse 8.63ms × (0.89,1.10) 8.58ms × (0.93,1.09) ~ (p=0.667)
BenchmarkGoParse-2 8.20ms × (0.97,1.04) 8.37ms × (0.97,1.04) +1.96% (p=0.001)
BenchmarkGoParse-4 8.00ms × (0.98,1.02) 8.14ms × (0.99,1.02) +1.75% (p=0.000)
BenchmarkRegexpMatchEasy0_32 162ns × (1.00,1.01) 164ns × (0.98,1.04) +1.35% (p=0.011)
BenchmarkRegexpMatchEasy0_32-2 161ns × (1.00,1.01) 161ns × (1.00,1.00) ~ (p=0.185)
BenchmarkRegexpMatchEasy0_32-4 161ns × (1.00,1.00) 161ns × (1.00,1.00) -0.19% (p=0.001)
BenchmarkRegexpMatchEasy0_1K 540ns × (0.99,1.02) 566ns × (0.98,1.04) +4.98% (p=0.000)
BenchmarkRegexpMatchEasy0_1K-2 540ns × (0.99,1.01) 557ns × (0.99,1.01) +3.21% (p=0.000)
BenchmarkRegexpMatchEasy0_1K-4 541ns × (0.99,1.01) 559ns × (0.99,1.01) +3.26% (p=0.000)
BenchmarkRegexpMatchEasy1_32 139ns × (0.98,1.04) 139ns × (0.99,1.03) ~ (p=0.979)
BenchmarkRegexpMatchEasy1_32-2 139ns × (0.99,1.04) 139ns × (0.99,1.02) ~ (p=0.777)
BenchmarkRegexpMatchEasy1_32-4 139ns × (0.98,1.04) 139ns × (0.99,1.04) ~ (p=0.771)
BenchmarkRegexpMatchEasy1_1K 890ns × (0.99,1.03) 885ns × (1.00,1.01) -0.50% (p=0.004)
BenchmarkRegexpMatchEasy1_1K-2 888ns × (0.99,1.01) 885ns × (0.99,1.01) -0.37% (p=0.004)
BenchmarkRegexpMatchEasy1_1K-4 890ns × (0.99,1.02) 884ns × (1.00,1.00) -0.70% (p=0.000)
BenchmarkRegexpMatchMedium_32 252ns × (0.99,1.01) 251ns × (0.99,1.01) ~ (p=0.081)
BenchmarkRegexpMatchMedium_32-2 254ns × (0.99,1.04) 252ns × (0.99,1.01) -0.78% (p=0.027)
BenchmarkRegexpMatchMedium_32-4 253ns × (0.99,1.04) 252ns × (0.99,1.01) -0.70% (p=0.022)
BenchmarkRegexpMatchMedium_1K 72.9µs × (0.99,1.01) 72.7µs × (1.00,1.00) ~ (p=0.064)
BenchmarkRegexpMatchMedium_1K-2 74.1µs × (0.98,1.05) 72.9µs × (1.00,1.01) -1.61% (p=0.001)
BenchmarkRegexpMatchMedium_1K-4 73.6µs × (0.99,1.05) 72.8µs × (1.00,1.00) -1.13% (p=0.007)
BenchmarkRegexpMatchHard_32 3.88µs × (0.99,1.03) 3.92µs × (0.98,1.05) ~ (p=0.143)
BenchmarkRegexpMatchHard_32-2 3.89µs × (0.99,1.03) 3.93µs × (0.98,1.09) ~ (p=0.278)
BenchmarkRegexpMatchHard_32-4 3.90µs × (0.99,1.05) 3.93µs × (0.98,1.05) ~ (p=0.252)
BenchmarkRegexpMatchHard_1K 118µs × (0.99,1.01) 117µs × (0.99,1.02) -0.54% (p=0.003)
BenchmarkRegexpMatchHard_1K-2 118µs × (0.99,1.01) 118µs × (0.99,1.03) ~ (p=0.581)
BenchmarkRegexpMatchHard_1K-4 118µs × (0.99,1.02) 117µs × (0.99,1.01) -0.54% (p=0.002)
BenchmarkRevcomp 991ms × (0.95,1.10) 989ms × (0.94,1.08) ~ (p=0.879)
BenchmarkRevcomp-2 978ms × (0.95,1.11) 962ms × (0.96,1.08) ~ (p=0.257)
BenchmarkRevcomp-4 979ms × (0.96,1.07) 974ms × (0.96,1.11) ~ (p=0.678)
BenchmarkTemplate 141ms × (0.99,1.02) 145ms × (0.99,1.02) +2.75% (p=0.000)
BenchmarkTemplate-2 135ms × (0.98,1.02) 138ms × (0.99,1.02) +2.34% (p=0.000)
BenchmarkTemplate-4 136ms × (0.98,1.02) 140ms × (0.99,1.02) +2.71% (p=0.000)
BenchmarkTimeParse 640ns × (0.99,1.01) 622ns × (0.99,1.01) -2.88% (p=0.000)
BenchmarkTimeParse-2 640ns × (0.99,1.01) 622ns × (1.00,1.00) -2.81% (p=0.000)
BenchmarkTimeParse-4 640ns × (1.00,1.01) 622ns × (0.99,1.01) -2.82% (p=0.000)
BenchmarkTimeFormat 730ns × (0.98,1.02) 731ns × (0.98,1.03) ~ (p=0.767)
BenchmarkTimeFormat-2 709ns × (0.99,1.02) 707ns × (0.99,1.02) ~ (p=0.347)
BenchmarkTimeFormat-4 717ns × (0.98,1.01) 718ns × (0.98,1.02) ~ (p=0.793)
Change-Id: Ie779c47e912bf80eb918bafa13638bd8dfd6c2d9
Reviewed-on: https://go-review.googlesource.com/9406
Reviewed-by: Rick Hudson <rlh@golang.org>
2015-04-27 20:45:57 -06:00
|
|
|
//
|
|
|
|
// ptr ptr INT ptr ptr ptr ptr INT
|
|
|
|
// ptr ptr ptr ptr INT ptr ptr ptr
|
|
|
|
// ptr INT ptr ptr ptr ptr INT ptr
|
|
|
|
// ptr ptr ptr INT ptr ptr ptr ptr
|
|
|
|
// INT ptr ptr ptr ptr INT ptr ptr
|
|
|
|
//
|
2015-01-16 12:43:38 -07:00
|
|
|
// Assumptions about Finalizer layout checked below.
|
cmd/internal/gc, runtime: use 1-bit bitmap for stack frames, data, bss
The bitmaps were 2 bits per pointer because we needed to distinguish
scalar, pointer, multiword, and we used the leftover value to distinguish
uninitialized from scalar, even though the garbage collector (GC) didn't care.
Now that there are no multiword structures from the GC's point of view,
cut the bitmaps down to 1 bit per pointer, recording just live pointer vs not.
The GC assumes the same layout for stack frames and for the maps
describing the global data and bss sections, so change them all in one CL.
The code still refers to 4-bit heap bitmaps and 2-bit "type bitmaps", since
the 2-bit representation lives (at least for now) in some of the reflect data.
Because these stack frame bitmaps are stored directly in the rodata in
the binary, this CL reduces the size of the 6g binary by about 1.1%.
Performance change is basically a wash, but using less memory,
and smaller binaries, and enables other bitmap reductions.
name old mean new mean delta
BenchmarkBinaryTree17 13.2s × (0.97,1.03) 13.0s × (0.99,1.01) -0.93% (p=0.005)
BenchmarkBinaryTree17-2 9.69s × (0.96,1.05) 9.51s × (0.96,1.03) -1.86% (p=0.001)
BenchmarkBinaryTree17-4 10.1s × (0.97,1.05) 10.0s × (0.96,1.05) ~ (p=0.141)
BenchmarkFannkuch11 4.35s × (0.99,1.01) 4.43s × (0.98,1.04) +1.75% (p=0.001)
BenchmarkFannkuch11-2 4.31s × (0.99,1.03) 4.32s × (1.00,1.00) ~ (p=0.095)
BenchmarkFannkuch11-4 4.32s × (0.99,1.02) 4.38s × (0.98,1.04) +1.38% (p=0.008)
BenchmarkFmtFprintfEmpty 83.5ns × (0.97,1.10) 87.3ns × (0.92,1.11) +4.55% (p=0.014)
BenchmarkFmtFprintfEmpty-2 81.8ns × (0.98,1.04) 82.5ns × (0.97,1.08) ~ (p=0.364)
BenchmarkFmtFprintfEmpty-4 80.9ns × (0.99,1.01) 82.6ns × (0.97,1.08) +2.12% (p=0.010)
BenchmarkFmtFprintfString 320ns × (0.95,1.04) 322ns × (0.97,1.05) ~ (p=0.368)
BenchmarkFmtFprintfString-2 303ns × (0.97,1.04) 304ns × (0.97,1.04) ~ (p=0.484)
BenchmarkFmtFprintfString-4 305ns × (0.97,1.05) 306ns × (0.98,1.05) ~ (p=0.543)
BenchmarkFmtFprintfInt 311ns × (0.98,1.03) 319ns × (0.97,1.03) +2.63% (p=0.000)
BenchmarkFmtFprintfInt-2 297ns × (0.98,1.04) 301ns × (0.97,1.04) +1.19% (p=0.023)
BenchmarkFmtFprintfInt-4 302ns × (0.98,1.02) 304ns × (0.97,1.03) ~ (p=0.126)
BenchmarkFmtFprintfIntInt 554ns × (0.96,1.05) 554ns × (0.97,1.03) ~ (p=0.975)
BenchmarkFmtFprintfIntInt-2 520ns × (0.98,1.03) 517ns × (0.98,1.02) ~ (p=0.153)
BenchmarkFmtFprintfIntInt-4 524ns × (0.98,1.02) 525ns × (0.98,1.03) ~ (p=0.597)
BenchmarkFmtFprintfPrefixedInt 433ns × (0.97,1.06) 434ns × (0.97,1.06) ~ (p=0.804)
BenchmarkFmtFprintfPrefixedInt-2 413ns × (0.98,1.04) 413ns × (0.98,1.03) ~ (p=0.881)
BenchmarkFmtFprintfPrefixedInt-4 420ns × (0.97,1.03) 421ns × (0.97,1.03) ~ (p=0.561)
BenchmarkFmtFprintfFloat 620ns × (0.99,1.03) 636ns × (0.97,1.03) +2.57% (p=0.000)
BenchmarkFmtFprintfFloat-2 601ns × (0.98,1.02) 617ns × (0.98,1.03) +2.58% (p=0.000)
BenchmarkFmtFprintfFloat-4 613ns × (0.98,1.03) 626ns × (0.98,1.02) +2.15% (p=0.000)
BenchmarkFmtManyArgs 2.19µs × (0.96,1.04) 2.23µs × (0.97,1.02) +1.65% (p=0.000)
BenchmarkFmtManyArgs-2 2.08µs × (0.98,1.03) 2.10µs × (0.99,1.02) +0.79% (p=0.019)
BenchmarkFmtManyArgs-4 2.10µs × (0.98,1.02) 2.13µs × (0.98,1.02) +1.72% (p=0.000)
BenchmarkGobDecode 21.3ms × (0.97,1.05) 21.1ms × (0.97,1.04) -1.36% (p=0.025)
BenchmarkGobDecode-2 20.0ms × (0.97,1.03) 19.2ms × (0.97,1.03) -4.00% (p=0.000)
BenchmarkGobDecode-4 19.5ms × (0.99,1.02) 19.0ms × (0.99,1.01) -2.39% (p=0.000)
BenchmarkGobEncode 18.3ms × (0.95,1.07) 18.1ms × (0.96,1.08) ~ (p=0.305)
BenchmarkGobEncode-2 16.8ms × (0.97,1.02) 16.4ms × (0.98,1.02) -2.79% (p=0.000)
BenchmarkGobEncode-4 15.4ms × (0.98,1.02) 15.4ms × (0.98,1.02) ~ (p=0.465)
BenchmarkGzip 650ms × (0.98,1.03) 655ms × (0.97,1.04) ~ (p=0.075)
BenchmarkGzip-2 652ms × (0.98,1.03) 655ms × (0.98,1.02) ~ (p=0.337)
BenchmarkGzip-4 656ms × (0.98,1.04) 653ms × (0.98,1.03) ~ (p=0.291)
BenchmarkGunzip 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.507)
BenchmarkGunzip-2 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.313)
BenchmarkGunzip-4 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.312)
BenchmarkHTTPClientServer 110µs × (0.98,1.03) 109µs × (0.99,1.02) -1.40% (p=0.000)
BenchmarkHTTPClientServer-2 154µs × (0.90,1.08) 149µs × (0.90,1.08) -3.43% (p=0.007)
BenchmarkHTTPClientServer-4 138µs × (0.97,1.04) 138µs × (0.96,1.04) ~ (p=0.670)
BenchmarkJSONEncode 40.2ms × (0.98,1.02) 40.2ms × (0.98,1.05) ~ (p=0.828)
BenchmarkJSONEncode-2 35.1ms × (0.99,1.02) 35.2ms × (0.98,1.03) ~ (p=0.392)
BenchmarkJSONEncode-4 35.3ms × (0.98,1.03) 35.3ms × (0.98,1.02) ~ (p=0.813)
BenchmarkJSONDecode 119ms × (0.97,1.02) 117ms × (0.98,1.02) -1.80% (p=0.000)
BenchmarkJSONDecode-2 115ms × (0.99,1.02) 114ms × (0.98,1.02) -1.18% (p=0.000)
BenchmarkJSONDecode-4 116ms × (0.98,1.02) 114ms × (0.98,1.02) -1.43% (p=0.000)
BenchmarkMandelbrot200 6.03ms × (1.00,1.01) 6.03ms × (1.00,1.01) ~ (p=0.985)
BenchmarkMandelbrot200-2 6.03ms × (1.00,1.01) 6.02ms × (1.00,1.01) ~ (p=0.320)
BenchmarkMandelbrot200-4 6.03ms × (1.00,1.01) 6.03ms × (1.00,1.01) ~ (p=0.799)
BenchmarkGoParse 8.63ms × (0.89,1.10) 8.58ms × (0.93,1.09) ~ (p=0.667)
BenchmarkGoParse-2 8.20ms × (0.97,1.04) 8.37ms × (0.97,1.04) +1.96% (p=0.001)
BenchmarkGoParse-4 8.00ms × (0.98,1.02) 8.14ms × (0.99,1.02) +1.75% (p=0.000)
BenchmarkRegexpMatchEasy0_32 162ns × (1.00,1.01) 164ns × (0.98,1.04) +1.35% (p=0.011)
BenchmarkRegexpMatchEasy0_32-2 161ns × (1.00,1.01) 161ns × (1.00,1.00) ~ (p=0.185)
BenchmarkRegexpMatchEasy0_32-4 161ns × (1.00,1.00) 161ns × (1.00,1.00) -0.19% (p=0.001)
BenchmarkRegexpMatchEasy0_1K 540ns × (0.99,1.02) 566ns × (0.98,1.04) +4.98% (p=0.000)
BenchmarkRegexpMatchEasy0_1K-2 540ns × (0.99,1.01) 557ns × (0.99,1.01) +3.21% (p=0.000)
BenchmarkRegexpMatchEasy0_1K-4 541ns × (0.99,1.01) 559ns × (0.99,1.01) +3.26% (p=0.000)
BenchmarkRegexpMatchEasy1_32 139ns × (0.98,1.04) 139ns × (0.99,1.03) ~ (p=0.979)
BenchmarkRegexpMatchEasy1_32-2 139ns × (0.99,1.04) 139ns × (0.99,1.02) ~ (p=0.777)
BenchmarkRegexpMatchEasy1_32-4 139ns × (0.98,1.04) 139ns × (0.99,1.04) ~ (p=0.771)
BenchmarkRegexpMatchEasy1_1K 890ns × (0.99,1.03) 885ns × (1.00,1.01) -0.50% (p=0.004)
BenchmarkRegexpMatchEasy1_1K-2 888ns × (0.99,1.01) 885ns × (0.99,1.01) -0.37% (p=0.004)
BenchmarkRegexpMatchEasy1_1K-4 890ns × (0.99,1.02) 884ns × (1.00,1.00) -0.70% (p=0.000)
BenchmarkRegexpMatchMedium_32 252ns × (0.99,1.01) 251ns × (0.99,1.01) ~ (p=0.081)
BenchmarkRegexpMatchMedium_32-2 254ns × (0.99,1.04) 252ns × (0.99,1.01) -0.78% (p=0.027)
BenchmarkRegexpMatchMedium_32-4 253ns × (0.99,1.04) 252ns × (0.99,1.01) -0.70% (p=0.022)
BenchmarkRegexpMatchMedium_1K 72.9µs × (0.99,1.01) 72.7µs × (1.00,1.00) ~ (p=0.064)
BenchmarkRegexpMatchMedium_1K-2 74.1µs × (0.98,1.05) 72.9µs × (1.00,1.01) -1.61% (p=0.001)
BenchmarkRegexpMatchMedium_1K-4 73.6µs × (0.99,1.05) 72.8µs × (1.00,1.00) -1.13% (p=0.007)
BenchmarkRegexpMatchHard_32 3.88µs × (0.99,1.03) 3.92µs × (0.98,1.05) ~ (p=0.143)
BenchmarkRegexpMatchHard_32-2 3.89µs × (0.99,1.03) 3.93µs × (0.98,1.09) ~ (p=0.278)
BenchmarkRegexpMatchHard_32-4 3.90µs × (0.99,1.05) 3.93µs × (0.98,1.05) ~ (p=0.252)
BenchmarkRegexpMatchHard_1K 118µs × (0.99,1.01) 117µs × (0.99,1.02) -0.54% (p=0.003)
BenchmarkRegexpMatchHard_1K-2 118µs × (0.99,1.01) 118µs × (0.99,1.03) ~ (p=0.581)
BenchmarkRegexpMatchHard_1K-4 118µs × (0.99,1.02) 117µs × (0.99,1.01) -0.54% (p=0.002)
BenchmarkRevcomp 991ms × (0.95,1.10) 989ms × (0.94,1.08) ~ (p=0.879)
BenchmarkRevcomp-2 978ms × (0.95,1.11) 962ms × (0.96,1.08) ~ (p=0.257)
BenchmarkRevcomp-4 979ms × (0.96,1.07) 974ms × (0.96,1.11) ~ (p=0.678)
BenchmarkTemplate 141ms × (0.99,1.02) 145ms × (0.99,1.02) +2.75% (p=0.000)
BenchmarkTemplate-2 135ms × (0.98,1.02) 138ms × (0.99,1.02) +2.34% (p=0.000)
BenchmarkTemplate-4 136ms × (0.98,1.02) 140ms × (0.99,1.02) +2.71% (p=0.000)
BenchmarkTimeParse 640ns × (0.99,1.01) 622ns × (0.99,1.01) -2.88% (p=0.000)
BenchmarkTimeParse-2 640ns × (0.99,1.01) 622ns × (1.00,1.00) -2.81% (p=0.000)
BenchmarkTimeParse-4 640ns × (1.00,1.01) 622ns × (0.99,1.01) -2.82% (p=0.000)
BenchmarkTimeFormat 730ns × (0.98,1.02) 731ns × (0.98,1.03) ~ (p=0.767)
BenchmarkTimeFormat-2 709ns × (0.99,1.02) 707ns × (0.99,1.02) ~ (p=0.347)
BenchmarkTimeFormat-4 717ns × (0.98,1.01) 718ns × (0.98,1.02) ~ (p=0.793)
Change-Id: Ie779c47e912bf80eb918bafa13638bd8dfd6c2d9
Reviewed-on: https://go-review.googlesource.com/9406
Reviewed-by: Rick Hudson <rlh@golang.org>
2015-04-27 20:45:57 -06:00
|
|
|
1<<0 | 1<<1 | 0<<2 | 1<<3 | 1<<4 | 1<<5 | 1<<6 | 0<<7,
|
|
|
|
1<<0 | 1<<1 | 1<<2 | 1<<3 | 0<<4 | 1<<5 | 1<<6 | 1<<7,
|
|
|
|
1<<0 | 0<<1 | 1<<2 | 1<<3 | 1<<4 | 1<<5 | 0<<6 | 1<<7,
|
|
|
|
1<<0 | 1<<1 | 1<<2 | 0<<3 | 1<<4 | 1<<5 | 1<<6 | 1<<7,
|
|
|
|
0<<0 | 1<<1 | 1<<2 | 1<<3 | 1<<4 | 0<<5 | 1<<6 | 1<<7,
|
2015-01-16 12:43:38 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot *ptrtype) {
|
2017-01-31 09:46:36 -07:00
|
|
|
if gcphase != _GCoff {
|
|
|
|
// Currently we assume that the finalizer queue won't
|
|
|
|
// grow during marking so we don't have to rescan it
|
|
|
|
// during mark termination. If we ever need to lift
|
|
|
|
// this assumption, we can do it by adding the
|
|
|
|
// necessary barriers to queuefinalizer (which it may
|
|
|
|
// have automatically).
|
|
|
|
throw("queuefinalizer during GC")
|
|
|
|
}
|
|
|
|
|
2015-01-16 12:43:38 -07:00
|
|
|
lock(&finlock)
|
2016-10-14 11:39:07 -06:00
|
|
|
if finq == nil || finq.cnt == uint32(len(finq.fin)) {
|
2015-01-16 12:43:38 -07:00
|
|
|
if finc == nil {
|
|
|
|
finc = (*finblock)(persistentalloc(_FinBlockSize, 0, &memstats.gc_sys))
|
|
|
|
finc.alllink = allfin
|
|
|
|
allfin = finc
|
|
|
|
if finptrmask[0] == 0 {
|
|
|
|
// Build pointer mask for Finalizer array in block.
|
|
|
|
// Check assumptions made in finalizer1 array above.
|
2015-11-11 10:39:30 -07:00
|
|
|
if (unsafe.Sizeof(finalizer{}) != 5*sys.PtrSize ||
|
2015-01-16 12:43:38 -07:00
|
|
|
unsafe.Offsetof(finalizer{}.fn) != 0 ||
|
2015-11-11 10:39:30 -07:00
|
|
|
unsafe.Offsetof(finalizer{}.arg) != sys.PtrSize ||
|
|
|
|
unsafe.Offsetof(finalizer{}.nret) != 2*sys.PtrSize ||
|
|
|
|
unsafe.Offsetof(finalizer{}.fint) != 3*sys.PtrSize ||
|
|
|
|
unsafe.Offsetof(finalizer{}.ot) != 4*sys.PtrSize) {
|
2015-01-16 12:43:38 -07:00
|
|
|
throw("finalizer out of sync")
|
|
|
|
}
|
|
|
|
for i := range finptrmask {
|
|
|
|
finptrmask[i] = finalizer1[i%len(finalizer1)]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
block := finc
|
|
|
|
finc = block.next
|
|
|
|
block.next = finq
|
|
|
|
finq = block
|
|
|
|
}
|
|
|
|
f := &finq.fin[finq.cnt]
|
2016-10-14 11:39:07 -06:00
|
|
|
atomic.Xadd(&finq.cnt, +1) // Sync with markroots
|
2015-01-16 12:43:38 -07:00
|
|
|
f.fn = fn
|
|
|
|
f.nret = nret
|
|
|
|
f.fint = fint
|
|
|
|
f.ot = ot
|
|
|
|
f.arg = p
|
|
|
|
fingwake = true
|
|
|
|
unlock(&finlock)
|
|
|
|
}
|
|
|
|
|
|
|
|
//go:nowritebarrier
|
|
|
|
func iterate_finq(callback func(*funcval, unsafe.Pointer, uintptr, *_type, *ptrtype)) {
|
|
|
|
for fb := allfin; fb != nil; fb = fb.alllink {
|
2016-10-14 11:39:07 -06:00
|
|
|
for i := uint32(0); i < fb.cnt; i++ {
|
2015-01-16 12:43:38 -07:00
|
|
|
f := &fb.fin[i]
|
|
|
|
callback(f.fn, f.arg, f.nret, f.fint, f.ot)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func wakefing() *g {
|
|
|
|
var res *g
|
|
|
|
lock(&finlock)
|
|
|
|
if fingwait && fingwake {
|
|
|
|
fingwait = false
|
|
|
|
fingwake = false
|
|
|
|
res = fing
|
|
|
|
}
|
|
|
|
unlock(&finlock)
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
2015-02-07 05:31:18 -07:00
|
|
|
var (
|
|
|
|
fingCreate uint32
|
|
|
|
fingRunning bool
|
|
|
|
)
|
2015-01-16 12:43:38 -07:00
|
|
|
|
|
|
|
func createfing() {
|
|
|
|
// start the finalizer goroutine exactly once
|
2015-11-02 12:09:24 -07:00
|
|
|
if fingCreate == 0 && atomic.Cas(&fingCreate, 0, 1) {
|
2015-01-16 12:43:38 -07:00
|
|
|
go runfinq()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is the goroutine that runs all of the finalizers
|
|
|
|
func runfinq() {
|
|
|
|
var (
|
|
|
|
frame unsafe.Pointer
|
|
|
|
framecap uintptr
|
|
|
|
)
|
|
|
|
|
|
|
|
for {
|
|
|
|
lock(&finlock)
|
|
|
|
fb := finq
|
|
|
|
finq = nil
|
|
|
|
if fb == nil {
|
|
|
|
gp := getg()
|
|
|
|
fing = gp
|
|
|
|
fingwait = true
|
2015-02-21 11:01:40 -07:00
|
|
|
goparkunlock(&finlock, "finalizer wait", traceEvGoBlock, 1)
|
2015-01-16 12:43:38 -07:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
unlock(&finlock)
|
|
|
|
if raceenabled {
|
|
|
|
racefingo()
|
|
|
|
}
|
|
|
|
for fb != nil {
|
2015-01-26 11:44:06 -07:00
|
|
|
for i := fb.cnt; i > 0; i-- {
|
2015-10-21 13:30:58 -06:00
|
|
|
f := &fb.fin[i-1]
|
2015-01-16 12:43:38 -07:00
|
|
|
|
2016-02-29 16:01:00 -07:00
|
|
|
framesz := unsafe.Sizeof((interface{})(nil)) + f.nret
|
2015-01-16 12:43:38 -07:00
|
|
|
if framecap < framesz {
|
|
|
|
// The frame does not contain pointers interesting for GC,
|
|
|
|
// all not yet finalized objects are stored in finq.
|
|
|
|
// If we do not mark it as FlagNoScan,
|
|
|
|
// the last finalized object is not collected.
|
2016-04-19 20:35:10 -06:00
|
|
|
frame = mallocgc(framesz, nil, true)
|
2015-01-16 12:43:38 -07:00
|
|
|
framecap = framesz
|
|
|
|
}
|
|
|
|
|
|
|
|
if f.fint == nil {
|
|
|
|
throw("missing type in runfinq")
|
|
|
|
}
|
2016-10-03 12:45:52 -06:00
|
|
|
// frame is effectively uninitialized
|
|
|
|
// memory. That means we have to clear
|
|
|
|
// it before writing to it to avoid
|
|
|
|
// confusing the write barrier.
|
|
|
|
*(*[2]uintptr)(frame) = [2]uintptr{}
|
2015-01-16 12:43:38 -07:00
|
|
|
switch f.fint.kind & kindMask {
|
|
|
|
case kindPtr:
|
|
|
|
// direct use of pointer
|
|
|
|
*(*unsafe.Pointer)(frame) = f.arg
|
|
|
|
case kindInterface:
|
|
|
|
ityp := (*interfacetype)(unsafe.Pointer(f.fint))
|
|
|
|
// set up with empty interface
|
|
|
|
(*eface)(frame)._type = &f.ot.typ
|
|
|
|
(*eface)(frame).data = f.arg
|
|
|
|
if len(ityp.mhdr) != 0 {
|
|
|
|
// convert to interface with methods
|
|
|
|
// this conversion is guaranteed to succeed - we checked in SetFinalizer
|
2016-10-28 12:37:45 -06:00
|
|
|
*(*iface)(frame) = assertE2I(ityp, *(*eface)(frame))
|
2015-01-16 12:43:38 -07:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
throw("bad kind in runfinq")
|
|
|
|
}
|
2015-02-07 05:31:18 -07:00
|
|
|
fingRunning = true
|
2015-01-16 12:43:38 -07:00
|
|
|
reflectcall(nil, unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz))
|
2015-02-07 05:31:18 -07:00
|
|
|
fingRunning = false
|
2015-01-16 12:43:38 -07:00
|
|
|
|
2016-10-14 11:39:07 -06:00
|
|
|
// Drop finalizer queue heap references
|
|
|
|
// before hiding them from markroot.
|
|
|
|
// This also ensures these will be
|
|
|
|
// clear if we reuse the finalizer.
|
2015-01-16 12:43:38 -07:00
|
|
|
f.fn = nil
|
|
|
|
f.arg = nil
|
|
|
|
f.ot = nil
|
2016-10-14 11:39:07 -06:00
|
|
|
atomic.Store(&fb.cnt, i-1)
|
2015-01-16 12:43:38 -07:00
|
|
|
}
|
|
|
|
next := fb.next
|
|
|
|
lock(&finlock)
|
|
|
|
fb.next = finc
|
|
|
|
finc = fb
|
|
|
|
unlock(&finlock)
|
|
|
|
fb = next
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-02-28 12:47:04 -07:00
|
|
|
// SetFinalizer sets the finalizer associated with obj to the provided
|
|
|
|
// finalizer function. When the garbage collector finds an unreachable block
|
2015-01-16 12:43:38 -07:00
|
|
|
// with an associated finalizer, it clears the association and runs
|
2016-02-28 12:47:04 -07:00
|
|
|
// finalizer(obj) in a separate goroutine. This makes obj reachable again,
|
|
|
|
// but now without an associated finalizer. Assuming that SetFinalizer
|
2015-01-16 12:43:38 -07:00
|
|
|
// is not called again, the next time the garbage collector sees
|
2016-02-28 12:47:04 -07:00
|
|
|
// that obj is unreachable, it will free obj.
|
2015-01-16 12:43:38 -07:00
|
|
|
//
|
2016-02-28 12:47:04 -07:00
|
|
|
// SetFinalizer(obj, nil) clears any finalizer associated with obj.
|
2015-01-16 12:43:38 -07:00
|
|
|
//
|
2016-09-22 01:37:28 -06:00
|
|
|
// The argument obj must be a pointer to an object allocated by calling
|
|
|
|
// new, by taking the address of a composite literal, or by taking the
|
|
|
|
// address of a local variable.
|
2016-02-28 12:47:04 -07:00
|
|
|
// The argument finalizer must be a function that takes a single argument
|
|
|
|
// to which obj's type can be assigned, and can have arbitrary ignored return
|
2016-10-03 09:52:20 -06:00
|
|
|
// values. If either of these is not true, SetFinalizer may abort the
|
2015-01-16 12:43:38 -07:00
|
|
|
// program.
|
|
|
|
//
|
|
|
|
// Finalizers are run in dependency order: if A points at B, both have
|
|
|
|
// finalizers, and they are otherwise unreachable, only the finalizer
|
|
|
|
// for A runs; once A is freed, the finalizer for B can run.
|
|
|
|
// If a cyclic structure includes a block with a finalizer, that
|
|
|
|
// cycle is not guaranteed to be garbage collected and the finalizer
|
|
|
|
// is not guaranteed to run, because there is no ordering that
|
|
|
|
// respects the dependencies.
|
|
|
|
//
|
2016-02-28 12:47:04 -07:00
|
|
|
// The finalizer for obj is scheduled to run at some arbitrary time after
|
|
|
|
// obj becomes unreachable.
|
2015-01-16 12:43:38 -07:00
|
|
|
// There is no guarantee that finalizers will run before a program exits,
|
|
|
|
// so typically they are useful only for releasing non-memory resources
|
|
|
|
// associated with an object during a long-running program.
|
|
|
|
// For example, an os.File object could use a finalizer to close the
|
|
|
|
// associated operating system file descriptor when a program discards
|
|
|
|
// an os.File without calling Close, but it would be a mistake
|
|
|
|
// to depend on a finalizer to flush an in-memory I/O buffer such as a
|
|
|
|
// bufio.Writer, because the buffer would not be flushed at program exit.
|
|
|
|
//
|
2016-02-28 12:47:04 -07:00
|
|
|
// It is not guaranteed that a finalizer will run if the size of *obj is
|
2015-01-16 12:43:38 -07:00
|
|
|
// zero bytes.
|
|
|
|
//
|
|
|
|
// It is not guaranteed that a finalizer will run for objects allocated
|
|
|
|
// in initializers for package-level variables. Such objects may be
|
|
|
|
// linker-allocated, not heap-allocated.
|
|
|
|
//
|
2016-05-13 10:02:40 -06:00
|
|
|
// A finalizer may run as soon as an object becomes unreachable.
|
|
|
|
// In order to use finalizers correctly, the program must ensure that
|
|
|
|
// the object is reachable until it is no longer required.
|
|
|
|
// Objects stored in global variables, or that can be found by tracing
|
|
|
|
// pointers from a global variable, are reachable. For other objects,
|
|
|
|
// pass the object to a call of the KeepAlive function to mark the
|
|
|
|
// last point in the function where the object must be reachable.
|
|
|
|
//
|
|
|
|
// For example, if p points to a struct that contains a file descriptor d,
|
|
|
|
// and p has a finalizer that closes that file descriptor, and if the last
|
|
|
|
// use of p in a function is a call to syscall.Write(p.d, buf, size), then
|
|
|
|
// p may be unreachable as soon as the program enters syscall.Write. The
|
|
|
|
// finalizer may run at that moment, closing p.d, causing syscall.Write
|
|
|
|
// to fail because it is writing to a closed file descriptor (or, worse,
|
|
|
|
// to an entirely different file descriptor opened by a different goroutine).
|
|
|
|
// To avoid this problem, call runtime.KeepAlive(p) after the call to
|
|
|
|
// syscall.Write.
|
|
|
|
//
|
2015-01-16 12:43:38 -07:00
|
|
|
// A single goroutine runs all finalizers for a program, sequentially.
|
|
|
|
// If a finalizer must run for a long time, it should do so by starting
|
|
|
|
// a new goroutine.
|
|
|
|
func SetFinalizer(obj interface{}, finalizer interface{}) {
|
2015-03-08 18:56:15 -06:00
|
|
|
if debug.sbrk != 0 {
|
|
|
|
// debug.sbrk never frees memory, so no finalizers run
|
|
|
|
// (and we don't have the data structures to record them).
|
|
|
|
return
|
|
|
|
}
|
2015-10-21 13:12:25 -06:00
|
|
|
e := efaceOf(&obj)
|
2015-01-16 12:43:38 -07:00
|
|
|
etyp := e._type
|
|
|
|
if etyp == nil {
|
|
|
|
throw("runtime.SetFinalizer: first argument is nil")
|
|
|
|
}
|
|
|
|
if etyp.kind&kindMask != kindPtr {
|
2016-04-07 14:29:16 -06:00
|
|
|
throw("runtime.SetFinalizer: first argument is " + etyp.string() + ", not pointer")
|
2015-01-16 12:43:38 -07:00
|
|
|
}
|
|
|
|
ot := (*ptrtype)(unsafe.Pointer(etyp))
|
|
|
|
if ot.elem == nil {
|
|
|
|
throw("nil elem type!")
|
|
|
|
}
|
|
|
|
|
|
|
|
// find the containing object
|
|
|
|
_, base, _ := findObject(e.data)
|
|
|
|
|
|
|
|
if base == nil {
|
|
|
|
// 0-length objects are okay.
|
|
|
|
if e.data == unsafe.Pointer(&zerobase) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Global initializers might be linker-allocated.
|
|
|
|
// var Foo = &Object{}
|
|
|
|
// func main() {
|
|
|
|
// runtime.SetFinalizer(Foo, nil)
|
|
|
|
// }
|
|
|
|
// The relevant segments are: noptrdata, data, bss, noptrbss.
|
|
|
|
// We cannot assume they are in any order or even contiguous,
|
|
|
|
// due to external linking.
|
2015-04-06 18:55:02 -06:00
|
|
|
for datap := &firstmoduledata; datap != nil; datap = datap.next {
|
2015-03-29 15:59:00 -06:00
|
|
|
if datap.noptrdata <= uintptr(e.data) && uintptr(e.data) < datap.enoptrdata ||
|
|
|
|
datap.data <= uintptr(e.data) && uintptr(e.data) < datap.edata ||
|
|
|
|
datap.bss <= uintptr(e.data) && uintptr(e.data) < datap.ebss ||
|
|
|
|
datap.noptrbss <= uintptr(e.data) && uintptr(e.data) < datap.enoptrbss {
|
|
|
|
return
|
|
|
|
}
|
2015-01-16 12:43:38 -07:00
|
|
|
}
|
|
|
|
throw("runtime.SetFinalizer: pointer not in allocated block")
|
|
|
|
}
|
|
|
|
|
|
|
|
if e.data != base {
|
|
|
|
// As an implementation detail we allow to set finalizers for an inner byte
|
|
|
|
// of an object if it could come from tiny alloc (see mallocgc for details).
|
|
|
|
if ot.elem == nil || ot.elem.kind&kindNoPointers == 0 || ot.elem.size >= maxTinySize {
|
|
|
|
throw("runtime.SetFinalizer: pointer not at beginning of allocated block")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-21 13:12:25 -06:00
|
|
|
f := efaceOf(&finalizer)
|
2015-01-16 12:43:38 -07:00
|
|
|
ftyp := f._type
|
|
|
|
if ftyp == nil {
|
|
|
|
// switch to system stack and remove finalizer
|
|
|
|
systemstack(func() {
|
|
|
|
removefinalizer(e.data)
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if ftyp.kind&kindMask != kindFunc {
|
2016-04-07 14:29:16 -06:00
|
|
|
throw("runtime.SetFinalizer: second argument is " + ftyp.string() + ", not a function")
|
2015-01-16 12:43:38 -07:00
|
|
|
}
|
|
|
|
ft := (*functype)(unsafe.Pointer(ftyp))
|
2016-02-23 09:31:13 -07:00
|
|
|
if ft.dotdotdot() {
|
2016-04-07 14:29:16 -06:00
|
|
|
throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string() + " because dotdotdot")
|
2016-02-23 09:31:13 -07:00
|
|
|
}
|
2016-09-03 16:57:48 -06:00
|
|
|
if ft.inCount != 1 {
|
2016-04-07 14:29:16 -06:00
|
|
|
throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string())
|
2015-01-16 12:43:38 -07:00
|
|
|
}
|
2016-02-23 09:31:13 -07:00
|
|
|
fint := ft.in()[0]
|
2015-01-16 12:43:38 -07:00
|
|
|
switch {
|
|
|
|
case fint == etyp:
|
|
|
|
// ok - same type
|
|
|
|
goto okarg
|
|
|
|
case fint.kind&kindMask == kindPtr:
|
2016-02-20 20:54:15 -07:00
|
|
|
if (fint.uncommon() == nil || etyp.uncommon() == nil) && (*ptrtype)(unsafe.Pointer(fint)).elem == ot.elem {
|
2015-01-16 12:43:38 -07:00
|
|
|
// ok - not same type, but both pointers,
|
|
|
|
// one or the other is unnamed, and same element type, so assignable.
|
|
|
|
goto okarg
|
|
|
|
}
|
|
|
|
case fint.kind&kindMask == kindInterface:
|
|
|
|
ityp := (*interfacetype)(unsafe.Pointer(fint))
|
|
|
|
if len(ityp.mhdr) == 0 {
|
|
|
|
// ok - satisfies empty interface
|
|
|
|
goto okarg
|
|
|
|
}
|
2016-10-28 12:37:45 -06:00
|
|
|
if _, ok := assertE2I2(ityp, *efaceOf(&obj)); ok {
|
2015-01-16 12:43:38 -07:00
|
|
|
goto okarg
|
|
|
|
}
|
|
|
|
}
|
2016-04-07 14:29:16 -06:00
|
|
|
throw("runtime.SetFinalizer: cannot pass " + etyp.string() + " to finalizer " + ftyp.string())
|
2015-01-16 12:43:38 -07:00
|
|
|
okarg:
|
|
|
|
// compute size needed for return parameters
|
|
|
|
nret := uintptr(0)
|
2016-02-23 09:31:13 -07:00
|
|
|
for _, t := range ft.out() {
|
|
|
|
nret = round(nret, uintptr(t.align)) + uintptr(t.size)
|
2015-01-16 12:43:38 -07:00
|
|
|
}
|
2015-11-11 10:39:30 -07:00
|
|
|
nret = round(nret, sys.PtrSize)
|
2015-01-16 12:43:38 -07:00
|
|
|
|
|
|
|
// make sure we have a finalizer goroutine
|
|
|
|
createfing()
|
|
|
|
|
|
|
|
systemstack(func() {
|
|
|
|
if !addfinalizer(e.data, (*funcval)(f.data), nret, fint, ot) {
|
|
|
|
throw("runtime.SetFinalizer: finalizer already set")
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-03-01 16:21:55 -07:00
|
|
|
// Look up pointer v in heap. Return the span containing the object,
|
|
|
|
// the start of the object, and the size of the object. If the object
|
2015-01-16 12:43:38 -07:00
|
|
|
// does not exist, return nil, nil, 0.
|
|
|
|
func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) {
|
|
|
|
c := gomcache()
|
|
|
|
c.local_nlookup++
|
2015-11-11 10:39:30 -07:00
|
|
|
if sys.PtrSize == 4 && c.local_nlookup >= 1<<30 {
|
2015-01-16 12:43:38 -07:00
|
|
|
// purge cache stats to prevent overflow
|
|
|
|
lock(&mheap_.lock)
|
|
|
|
purgecachedstats(c)
|
|
|
|
unlock(&mheap_.lock)
|
|
|
|
}
|
|
|
|
|
|
|
|
// find span
|
2015-10-26 18:53:22 -06:00
|
|
|
arena_start := mheap_.arena_start
|
|
|
|
arena_used := mheap_.arena_used
|
2015-01-16 12:43:38 -07:00
|
|
|
if uintptr(v) < arena_start || uintptr(v) >= arena_used {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
p := uintptr(v) >> pageShift
|
|
|
|
q := p - arena_start>>pageShift
|
2016-10-04 14:03:00 -06:00
|
|
|
s = mheap_.spans[q]
|
2015-01-16 12:43:38 -07:00
|
|
|
if s == nil {
|
|
|
|
return
|
|
|
|
}
|
2016-04-28 08:59:00 -06:00
|
|
|
x = unsafe.Pointer(s.base())
|
2015-01-16 12:43:38 -07:00
|
|
|
|
|
|
|
if uintptr(v) < uintptr(x) || uintptr(v) >= uintptr(unsafe.Pointer(s.limit)) || s.state != mSpanInUse {
|
|
|
|
s = nil
|
|
|
|
x = nil
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-02-29 16:01:00 -07:00
|
|
|
n = s.elemsize
|
2016-02-09 15:53:07 -07:00
|
|
|
if s.spanclass.sizeclass() != 0 {
|
2015-01-16 12:43:38 -07:00
|
|
|
x = add(x, (uintptr(v)-uintptr(x))/n*n)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2016-05-13 10:02:40 -06:00
|
|
|
|
2017-08-11 10:48:46 -06:00
|
|
|
// Mark KeepAlive as noinline so that it is easily detectable as an intrinsic.
|
2016-05-13 10:02:40 -06:00
|
|
|
//go:noinline
|
|
|
|
|
|
|
|
// KeepAlive marks its argument as currently reachable.
|
|
|
|
// This ensures that the object is not freed, and its finalizer is not run,
|
|
|
|
// before the point in the program where KeepAlive is called.
|
|
|
|
//
|
|
|
|
// A very simplified example showing where KeepAlive is required:
|
|
|
|
// type File struct { d int }
|
|
|
|
// d, err := syscall.Open("/file/path", syscall.O_RDONLY, 0)
|
|
|
|
// // ... do something if err != nil ...
|
2016-07-08 08:56:52 -06:00
|
|
|
// p := &File{d}
|
2016-05-13 10:02:40 -06:00
|
|
|
// runtime.SetFinalizer(p, func(p *File) { syscall.Close(p.d) })
|
|
|
|
// var buf [10]byte
|
|
|
|
// n, err := syscall.Read(p.d, buf[:])
|
|
|
|
// // Ensure p is not finalized until Read returns.
|
|
|
|
// runtime.KeepAlive(p)
|
|
|
|
// // No more uses of p after this point.
|
|
|
|
//
|
|
|
|
// Without the KeepAlive call, the finalizer could run at the start of
|
|
|
|
// syscall.Read, closing the file descriptor before syscall.Read makes
|
|
|
|
// the actual system call.
|
2017-08-11 10:48:46 -06:00
|
|
|
func KeepAlive(x interface{}) {
|
|
|
|
// Introduce a use of x that the compiler can't eliminate.
|
|
|
|
// This makes sure x is alive on entry. We need x to be alive
|
|
|
|
// on entry for "defer runtime.KeepAlive(x)"; see issue 21402.
|
|
|
|
if cgoAlwaysFalse {
|
|
|
|
println(x)
|
|
|
|
}
|
|
|
|
}
|