2014-07-30 10:01:52 -06:00
|
|
|
// Copyright 2014 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package runtime
|
|
|
|
|
2014-08-15 13:22:33 -06:00
|
|
|
import "unsafe"
|
2014-07-30 10:01:52 -06:00
|
|
|
|
|
|
|
const (
|
2014-08-07 03:34:30 -06:00
|
|
|
debugMalloc = false
|
|
|
|
|
2014-09-16 08:22:15 -06:00
|
|
|
flagNoScan = _FlagNoScan
|
|
|
|
flagNoZero = _FlagNoZero
|
2014-07-30 10:01:52 -06:00
|
|
|
|
2014-09-16 08:22:15 -06:00
|
|
|
maxTinySize = _TinySize
|
|
|
|
tinySizeClass = _TinySizeClass
|
|
|
|
maxSmallSize = _MaxSmallSize
|
2014-07-30 10:01:52 -06:00
|
|
|
|
2014-09-16 08:22:15 -06:00
|
|
|
pageShift = _PageShift
|
|
|
|
pageSize = _PageSize
|
|
|
|
pageMask = _PageMask
|
2014-08-07 03:34:30 -06:00
|
|
|
|
2014-09-16 08:22:15 -06:00
|
|
|
bitsPerPointer = _BitsPerPointer
|
|
|
|
bitsMask = _BitsMask
|
|
|
|
pointersPerByte = _PointersPerByte
|
|
|
|
maxGCMask = _MaxGCMask
|
|
|
|
bitsDead = _BitsDead
|
|
|
|
bitsPointer = _BitsPointer
|
2014-11-11 15:05:02 -07:00
|
|
|
bitsScalar = _BitsScalar
|
2014-08-07 03:34:30 -06:00
|
|
|
|
2014-09-16 08:22:15 -06:00
|
|
|
mSpanInUse = _MSpanInUse
|
2014-08-28 14:23:10 -06:00
|
|
|
|
2014-11-11 15:05:02 -07:00
|
|
|
concurrentSweep = _ConcurrentSweep
|
2014-07-30 10:01:52 -06:00
|
|
|
)
|
|
|
|
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
// Page number (address>>pageShift)
|
|
|
|
type pageID uintptr
|
|
|
|
|
2014-09-16 08:22:15 -06:00
|
|
|
// base address for all 0-byte allocations
|
|
|
|
var zerobase uintptr
|
2014-07-30 10:01:52 -06:00
|
|
|
|
2014-08-05 07:03:06 -06:00
|
|
|
// Allocate an object of size bytes.
|
|
|
|
// Small objects are allocated from the per-P cache's free lists.
|
2014-07-30 10:01:52 -06:00
|
|
|
// Large objects (> 32 kB) are allocated straight from the heap.
|
2014-11-03 11:26:46 -07:00
|
|
|
func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
|
2014-07-30 10:01:52 -06:00
|
|
|
if size == 0 {
|
2014-09-16 08:22:15 -06:00
|
|
|
return unsafe.Pointer(&zerobase)
|
2014-07-30 10:01:52 -06:00
|
|
|
}
|
|
|
|
size0 := size
|
|
|
|
|
2014-09-08 23:08:34 -06:00
|
|
|
if flags&flagNoScan == 0 && typ == nil {
|
|
|
|
gothrow("malloc missing type")
|
|
|
|
}
|
|
|
|
|
2014-08-18 06:33:39 -06:00
|
|
|
// This function must be atomic wrt GC, but for performance reasons
|
|
|
|
// we don't acquirem/releasem on fast path. The code below does not have
|
|
|
|
// split stack checks, so it can't be preempted by GC.
|
[dev.cc] runtime: delete scalararg, ptrarg; rename onM to systemstack
Scalararg and ptrarg are not "signal safe".
Go code filling them out can be interrupted by a signal,
and then the signal handler runs, and if it also ends up
in Go code that uses scalararg or ptrarg, now the old
values have been smashed.
For the pieces of code that do need to run in a signal handler,
we introduced onM_signalok, which is really just onM
except that the _signalok is meant to convey that the caller
asserts that scalarg and ptrarg will be restored to their old
values after the call (instead of the usual behavior, zeroing them).
Scalararg and ptrarg are also untyped and therefore error-prone.
Go code can always pass a closure instead of using scalararg
and ptrarg; they were only really necessary for C code.
And there's no more C code.
For all these reasons, delete scalararg and ptrarg, converting
the few remaining references to use closures.
Once those are gone, there is no need for a distinction between
onM and onM_signalok, so replace both with a single function
equivalent to the current onM_signalok (that is, it can be called
on any of the curg, g0, and gsignal stacks).
The name onM and the phrase 'm stack' are misnomers,
because on most system an M has two system stacks:
the main thread stack and the signal handling stack.
Correct the misnomer by naming the replacement function systemstack.
Fix a few references to "M stack" in code.
The main motivation for this change is to eliminate scalararg/ptrarg.
Rick and I have already seen them cause problems because
the calling sequence m.ptrarg[0] = p is a heap pointer assignment,
so it gets a write barrier. The write barrier also uses onM, so it has
all the same problems as if it were being invoked by a signal handler.
We worked around this by saving and restoring the old values
and by calling onM_signalok, but there's no point in keeping this nice
home for bugs around any longer.
This CL also changes funcline to return the file name as a result
instead of filling in a passed-in *string. (The *string signature is
left over from when the code was written in and called from C.)
That's arguably an unrelated change, except that once I had done
the ptrarg/scalararg/onM cleanup I started getting false positives
about the *string argument escaping (not allowed in package runtime).
The compiler is wrong, but the easiest fix is to write the code like
Go code instead of like C code. I am a bit worried that the compiler
is wrong because of some use of uninitialized memory in the escape
analysis. If that's the reason, it will go away when we convert the
compiler to Go. (And if not, we'll debug it the next time.)
LGTM=khr
R=r, khr
CC=austin, golang-codereviews, iant, rlh
https://golang.org/cl/174950043
2014-11-12 12:54:31 -07:00
|
|
|
// Functions like roundup/add are inlined. And systemstack/racemalloc are nosplit.
|
2014-08-18 06:33:39 -06:00
|
|
|
// If debugMalloc = true, these assumptions are checked below.
|
|
|
|
if debugMalloc {
|
|
|
|
mp := acquirem()
|
|
|
|
if mp.mallocing != 0 {
|
|
|
|
gothrow("malloc deadlock")
|
|
|
|
}
|
|
|
|
mp.mallocing = 1
|
|
|
|
if mp.curg != nil {
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
mp.curg.stackguard0 = ^uintptr(0xfff) | 0xbad
|
2014-08-18 06:33:39 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
c := gomcache()
|
2014-07-30 10:01:52 -06:00
|
|
|
var s *mspan
|
|
|
|
var x unsafe.Pointer
|
|
|
|
if size <= maxSmallSize {
|
|
|
|
if flags&flagNoScan != 0 && size < maxTinySize {
|
|
|
|
// Tiny allocator.
|
|
|
|
//
|
|
|
|
// Tiny allocator combines several tiny allocation requests
|
|
|
|
// into a single memory block. The resulting memory block
|
|
|
|
// is freed when all subobjects are unreachable. The subobjects
|
|
|
|
// must be FlagNoScan (don't have pointers), this ensures that
|
|
|
|
// the amount of potentially wasted memory is bounded.
|
|
|
|
//
|
|
|
|
// Size of the memory block used for combining (maxTinySize) is tunable.
|
|
|
|
// Current setting is 16 bytes, which relates to 2x worst case memory
|
|
|
|
// wastage (when all but one subobjects are unreachable).
|
|
|
|
// 8 bytes would result in no wastage at all, but provides less
|
|
|
|
// opportunities for combining.
|
|
|
|
// 32 bytes provides more opportunities for combining,
|
|
|
|
// but can lead to 4x worst case wastage.
|
|
|
|
// The best case winning is 8x regardless of block size.
|
|
|
|
//
|
|
|
|
// Objects obtained from tiny allocator must not be freed explicitly.
|
|
|
|
// So when an object will be freed explicitly, we ensure that
|
|
|
|
// its size >= maxTinySize.
|
|
|
|
//
|
|
|
|
// SetFinalizer has a special case for objects potentially coming
|
|
|
|
// from tiny allocator, it such case it allows to set finalizers
|
|
|
|
// for an inner byte of a memory block.
|
|
|
|
//
|
|
|
|
// The main targets of tiny allocator are small strings and
|
|
|
|
// standalone escaping variables. On a json benchmark
|
|
|
|
// the allocator reduces number of allocations by ~12% and
|
|
|
|
// reduces heap size by ~20%.
|
|
|
|
tinysize := uintptr(c.tinysize)
|
|
|
|
if size <= tinysize {
|
|
|
|
tiny := unsafe.Pointer(c.tiny)
|
|
|
|
// Align tiny pointer for required (conservative) alignment.
|
|
|
|
if size&7 == 0 {
|
|
|
|
tiny = roundup(tiny, 8)
|
|
|
|
} else if size&3 == 0 {
|
|
|
|
tiny = roundup(tiny, 4)
|
|
|
|
} else if size&1 == 0 {
|
|
|
|
tiny = roundup(tiny, 2)
|
|
|
|
}
|
|
|
|
size1 := size + (uintptr(tiny) - uintptr(unsafe.Pointer(c.tiny)))
|
|
|
|
if size1 <= tinysize {
|
|
|
|
// The object fits into existing tiny block.
|
|
|
|
x = tiny
|
|
|
|
c.tiny = (*byte)(add(x, size))
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
c.tinysize -= uintptr(size1)
|
2014-09-17 12:49:32 -06:00
|
|
|
c.local_tinyallocs++
|
2014-08-18 06:33:39 -06:00
|
|
|
if debugMalloc {
|
|
|
|
mp := acquirem()
|
|
|
|
if mp.mallocing == 0 {
|
|
|
|
gothrow("bad malloc")
|
|
|
|
}
|
|
|
|
mp.mallocing = 0
|
|
|
|
if mp.curg != nil {
|
runtime: assume precisestack, copystack, StackCopyAlways, ScanStackByFrames
Commit to stack copying for stack growth.
We're carrying around a surprising amount of cruft from older schemes.
I am confident that precise stack scans and stack copying are here to stay.
Delete fallback code for when precise stack info is disabled.
Delete fallback code for when copying stacks is disabled.
Delete fallback code for when StackCopyAlways is disabled.
Delete Stktop chain - there is only one stack segment now.
Delete M.moreargp, M.moreargsize, M.moreframesize, M.cret.
Delete G.writenbuf (unrelated, just dead).
Delete runtime.lessstack, runtime.oldstack.
Delete many amd64 morestack variants.
Delete initialization of morestack frame/arg sizes (shortens split prologue!).
Replace G's stackguard/stackbase/stack0/stacksize/
syscallstack/syscallguard/forkstackguard with simple stack
bounds (lo, hi).
Update liblink, runtime/cgo for adjustments to G.
LGTM=khr
R=khr, bradfitz
CC=golang-codereviews, iant, r
https://golang.org/cl/137410043
2014-09-09 11:39:57 -06:00
|
|
|
mp.curg.stackguard0 = mp.curg.stack.lo + _StackGuard
|
2014-08-18 06:33:39 -06:00
|
|
|
}
|
2014-09-08 16:42:48 -06:00
|
|
|
// Note: one releasem for the acquirem just above.
|
|
|
|
// The other for the acquirem at start of malloc.
|
2014-08-18 06:33:39 -06:00
|
|
|
releasem(mp)
|
|
|
|
releasem(mp)
|
|
|
|
}
|
2014-07-30 10:01:52 -06:00
|
|
|
return x
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Allocate a new maxTinySize block.
|
|
|
|
s = c.alloc[tinySizeClass]
|
|
|
|
v := s.freelist
|
2014-11-20 10:08:13 -07:00
|
|
|
if v.ptr() == nil {
|
[dev.cc] runtime: delete scalararg, ptrarg; rename onM to systemstack
Scalararg and ptrarg are not "signal safe".
Go code filling them out can be interrupted by a signal,
and then the signal handler runs, and if it also ends up
in Go code that uses scalararg or ptrarg, now the old
values have been smashed.
For the pieces of code that do need to run in a signal handler,
we introduced onM_signalok, which is really just onM
except that the _signalok is meant to convey that the caller
asserts that scalarg and ptrarg will be restored to their old
values after the call (instead of the usual behavior, zeroing them).
Scalararg and ptrarg are also untyped and therefore error-prone.
Go code can always pass a closure instead of using scalararg
and ptrarg; they were only really necessary for C code.
And there's no more C code.
For all these reasons, delete scalararg and ptrarg, converting
the few remaining references to use closures.
Once those are gone, there is no need for a distinction between
onM and onM_signalok, so replace both with a single function
equivalent to the current onM_signalok (that is, it can be called
on any of the curg, g0, and gsignal stacks).
The name onM and the phrase 'm stack' are misnomers,
because on most system an M has two system stacks:
the main thread stack and the signal handling stack.
Correct the misnomer by naming the replacement function systemstack.
Fix a few references to "M stack" in code.
The main motivation for this change is to eliminate scalararg/ptrarg.
Rick and I have already seen them cause problems because
the calling sequence m.ptrarg[0] = p is a heap pointer assignment,
so it gets a write barrier. The write barrier also uses onM, so it has
all the same problems as if it were being invoked by a signal handler.
We worked around this by saving and restoring the old values
and by calling onM_signalok, but there's no point in keeping this nice
home for bugs around any longer.
This CL also changes funcline to return the file name as a result
instead of filling in a passed-in *string. (The *string signature is
left over from when the code was written in and called from C.)
That's arguably an unrelated change, except that once I had done
the ptrarg/scalararg/onM cleanup I started getting false positives
about the *string argument escaping (not allowed in package runtime).
The compiler is wrong, but the easiest fix is to write the code like
Go code instead of like C code. I am a bit worried that the compiler
is wrong because of some use of uninitialized memory in the escape
analysis. If that's the reason, it will go away when we convert the
compiler to Go. (And if not, we'll debug it the next time.)
LGTM=khr
R=r, khr
CC=austin, golang-codereviews, iant, rlh
https://golang.org/cl/174950043
2014-11-12 12:54:31 -07:00
|
|
|
systemstack(func() {
|
2014-11-11 15:05:02 -07:00
|
|
|
mCache_Refill(c, tinySizeClass)
|
|
|
|
})
|
2014-07-30 10:01:52 -06:00
|
|
|
s = c.alloc[tinySizeClass]
|
|
|
|
v = s.freelist
|
|
|
|
}
|
2014-11-20 10:08:13 -07:00
|
|
|
s.freelist = v.ptr().next
|
2014-07-30 10:01:52 -06:00
|
|
|
s.ref++
|
|
|
|
//TODO: prefetch v.next
|
|
|
|
x = unsafe.Pointer(v)
|
|
|
|
(*[2]uint64)(x)[0] = 0
|
|
|
|
(*[2]uint64)(x)[1] = 0
|
|
|
|
// See if we need to replace the existing tiny block with the new one
|
|
|
|
// based on amount of remaining free space.
|
|
|
|
if maxTinySize-size > tinysize {
|
|
|
|
c.tiny = (*byte)(add(x, size))
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
c.tinysize = uintptr(maxTinySize - size)
|
2014-07-30 10:01:52 -06:00
|
|
|
}
|
|
|
|
size = maxTinySize
|
|
|
|
} else {
|
|
|
|
var sizeclass int8
|
|
|
|
if size <= 1024-8 {
|
|
|
|
sizeclass = size_to_class8[(size+7)>>3]
|
|
|
|
} else {
|
|
|
|
sizeclass = size_to_class128[(size-1024+127)>>7]
|
|
|
|
}
|
|
|
|
size = uintptr(class_to_size[sizeclass])
|
|
|
|
s = c.alloc[sizeclass]
|
|
|
|
v := s.freelist
|
2014-11-20 10:08:13 -07:00
|
|
|
if v.ptr() == nil {
|
[dev.cc] runtime: delete scalararg, ptrarg; rename onM to systemstack
Scalararg and ptrarg are not "signal safe".
Go code filling them out can be interrupted by a signal,
and then the signal handler runs, and if it also ends up
in Go code that uses scalararg or ptrarg, now the old
values have been smashed.
For the pieces of code that do need to run in a signal handler,
we introduced onM_signalok, which is really just onM
except that the _signalok is meant to convey that the caller
asserts that scalarg and ptrarg will be restored to their old
values after the call (instead of the usual behavior, zeroing them).
Scalararg and ptrarg are also untyped and therefore error-prone.
Go code can always pass a closure instead of using scalararg
and ptrarg; they were only really necessary for C code.
And there's no more C code.
For all these reasons, delete scalararg and ptrarg, converting
the few remaining references to use closures.
Once those are gone, there is no need for a distinction between
onM and onM_signalok, so replace both with a single function
equivalent to the current onM_signalok (that is, it can be called
on any of the curg, g0, and gsignal stacks).
The name onM and the phrase 'm stack' are misnomers,
because on most system an M has two system stacks:
the main thread stack and the signal handling stack.
Correct the misnomer by naming the replacement function systemstack.
Fix a few references to "M stack" in code.
The main motivation for this change is to eliminate scalararg/ptrarg.
Rick and I have already seen them cause problems because
the calling sequence m.ptrarg[0] = p is a heap pointer assignment,
so it gets a write barrier. The write barrier also uses onM, so it has
all the same problems as if it were being invoked by a signal handler.
We worked around this by saving and restoring the old values
and by calling onM_signalok, but there's no point in keeping this nice
home for bugs around any longer.
This CL also changes funcline to return the file name as a result
instead of filling in a passed-in *string. (The *string signature is
left over from when the code was written in and called from C.)
That's arguably an unrelated change, except that once I had done
the ptrarg/scalararg/onM cleanup I started getting false positives
about the *string argument escaping (not allowed in package runtime).
The compiler is wrong, but the easiest fix is to write the code like
Go code instead of like C code. I am a bit worried that the compiler
is wrong because of some use of uninitialized memory in the escape
analysis. If that's the reason, it will go away when we convert the
compiler to Go. (And if not, we'll debug it the next time.)
LGTM=khr
R=r, khr
CC=austin, golang-codereviews, iant, rlh
https://golang.org/cl/174950043
2014-11-12 12:54:31 -07:00
|
|
|
systemstack(func() {
|
2014-11-11 15:05:02 -07:00
|
|
|
mCache_Refill(c, int32(sizeclass))
|
|
|
|
})
|
2014-07-30 10:01:52 -06:00
|
|
|
s = c.alloc[sizeclass]
|
|
|
|
v = s.freelist
|
|
|
|
}
|
2014-11-20 10:08:13 -07:00
|
|
|
s.freelist = v.ptr().next
|
2014-07-30 10:01:52 -06:00
|
|
|
s.ref++
|
|
|
|
//TODO: prefetch
|
|
|
|
x = unsafe.Pointer(v)
|
|
|
|
if flags&flagNoZero == 0 {
|
2014-11-20 10:08:13 -07:00
|
|
|
v.ptr().next = 0
|
2014-07-30 10:01:52 -06:00
|
|
|
if size > 2*ptrSize && ((*[2]uintptr)(x))[1] != 0 {
|
|
|
|
memclr(unsafe.Pointer(v), size)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
c.local_cachealloc += intptr(size)
|
2014-07-30 10:01:52 -06:00
|
|
|
} else {
|
2014-11-11 15:05:02 -07:00
|
|
|
var s *mspan
|
[dev.cc] runtime: delete scalararg, ptrarg; rename onM to systemstack
Scalararg and ptrarg are not "signal safe".
Go code filling them out can be interrupted by a signal,
and then the signal handler runs, and if it also ends up
in Go code that uses scalararg or ptrarg, now the old
values have been smashed.
For the pieces of code that do need to run in a signal handler,
we introduced onM_signalok, which is really just onM
except that the _signalok is meant to convey that the caller
asserts that scalarg and ptrarg will be restored to their old
values after the call (instead of the usual behavior, zeroing them).
Scalararg and ptrarg are also untyped and therefore error-prone.
Go code can always pass a closure instead of using scalararg
and ptrarg; they were only really necessary for C code.
And there's no more C code.
For all these reasons, delete scalararg and ptrarg, converting
the few remaining references to use closures.
Once those are gone, there is no need for a distinction between
onM and onM_signalok, so replace both with a single function
equivalent to the current onM_signalok (that is, it can be called
on any of the curg, g0, and gsignal stacks).
The name onM and the phrase 'm stack' are misnomers,
because on most system an M has two system stacks:
the main thread stack and the signal handling stack.
Correct the misnomer by naming the replacement function systemstack.
Fix a few references to "M stack" in code.
The main motivation for this change is to eliminate scalararg/ptrarg.
Rick and I have already seen them cause problems because
the calling sequence m.ptrarg[0] = p is a heap pointer assignment,
so it gets a write barrier. The write barrier also uses onM, so it has
all the same problems as if it were being invoked by a signal handler.
We worked around this by saving and restoring the old values
and by calling onM_signalok, but there's no point in keeping this nice
home for bugs around any longer.
This CL also changes funcline to return the file name as a result
instead of filling in a passed-in *string. (The *string signature is
left over from when the code was written in and called from C.)
That's arguably an unrelated change, except that once I had done
the ptrarg/scalararg/onM cleanup I started getting false positives
about the *string argument escaping (not allowed in package runtime).
The compiler is wrong, but the easiest fix is to write the code like
Go code instead of like C code. I am a bit worried that the compiler
is wrong because of some use of uninitialized memory in the escape
analysis. If that's the reason, it will go away when we convert the
compiler to Go. (And if not, we'll debug it the next time.)
LGTM=khr
R=r, khr
CC=austin, golang-codereviews, iant, rlh
https://golang.org/cl/174950043
2014-11-12 12:54:31 -07:00
|
|
|
systemstack(func() {
|
2014-11-11 15:05:02 -07:00
|
|
|
s = largeAlloc(size, uint32(flags))
|
|
|
|
})
|
2014-07-30 10:01:52 -06:00
|
|
|
x = unsafe.Pointer(uintptr(s.start << pageShift))
|
|
|
|
size = uintptr(s.elemsize)
|
|
|
|
}
|
|
|
|
|
2014-08-13 10:42:55 -06:00
|
|
|
if flags&flagNoScan != 0 {
|
|
|
|
// All objects are pre-marked as noscan.
|
|
|
|
goto marked
|
|
|
|
}
|
|
|
|
|
runtime: use traceback to traverse defer structures
This makes the GC and the stack copying agree about how
to interpret the defer structures. Previously, only the stack
copying treated them precisely.
This removes an untyped memory allocation and fixes
at least three copystack bugs.
To make sure the GC can find the deferred argument
frame until it has been copied, keep a Defer on the defer list
during its execution.
In addition to making it possible to remove the untyped
memory allocation, keeping the Defer on the list fixes
two races between copystack and execution of defers
(in both gopanic and Goexit). The problem is that once
the defer has been taken off the list, a stack copy that
happens before the deferred arguments have been copied
back to the stack will not update the arguments correctly.
The new tests TestDeferPtrsPanic and TestDeferPtrsGoexit
(variations on the existing TestDeferPtrs) pass now but
failed before this CL.
In addition to those fixes, keeping the Defer on the list
helps correct a dangling pointer error during copystack.
The traceback routines walk the Defer chain to provide
information about where a panic may resume execution.
When the executing Defer was not on the Defer chain
but instead linked from the Panic chain, the traceback
had to walk the Panic chain too. But Panic structs are
on the stack and being updated by copystack.
Traceback's use of the Panic chain while copystack is
updating those structs means that it can follow an
updated pointer and find itself reading from the new stack.
The new stack is usually all zeros, so it sees an incorrect
early end to the chain. The new TestPanicUseStack makes
this happen at tip and dies when adjustdefers finds an
unexpected argp. The new StackCopyPoison mode
causes an earlier bad dereference instead.
By keeping the Defer on the list, traceback can avoid
walking the Panic chain at all, making it okay for copystack
to update the Panics.
We'd have the same problem for any Defers on the stack.
There was only one: gopanic's dabort. Since we are not
taking the executing Defer off the chain, we can use it
to do what dabort was doing, and then there are no
Defers on the stack ever, so it is okay for traceback to use
the Defer chain even while copystack is executing:
copystack cannot modify the Defer chain.
LGTM=khr
R=khr
CC=dvyukov, golang-codereviews, iant, rlh
https://golang.org/cl/141490043
2014-09-16 08:36:38 -06:00
|
|
|
// If allocating a defer+arg block, now that we've picked a malloc size
|
|
|
|
// large enough to hold everything, cut the "asked for" size down to
|
|
|
|
// just the defer header, so that the GC bitmap will record the arg block
|
|
|
|
// as containing nothing at all (as if it were unused space at the end of
|
|
|
|
// a malloc block caused by size rounding).
|
|
|
|
// The defer arg areas are scanned as part of scanstack.
|
|
|
|
if typ == deferType {
|
|
|
|
size0 = unsafe.Sizeof(_defer{})
|
|
|
|
}
|
|
|
|
|
2014-08-07 03:34:30 -06:00
|
|
|
// From here till marked label marking the object as allocated
|
|
|
|
// and storing type info in the GC bitmap.
|
2014-08-13 10:42:55 -06:00
|
|
|
{
|
|
|
|
arena_start := uintptr(unsafe.Pointer(mheap_.arena_start))
|
|
|
|
off := (uintptr(x) - arena_start) / ptrSize
|
2014-08-19 07:38:00 -06:00
|
|
|
xbits := (*uint8)(unsafe.Pointer(arena_start - off/wordsPerBitmapByte - 1))
|
|
|
|
shift := (off % wordsPerBitmapByte) * gcBits
|
2014-08-13 10:42:55 -06:00
|
|
|
if debugMalloc && ((*xbits>>shift)&(bitMask|bitPtrMask)) != bitBoundary {
|
|
|
|
println("runtime: bits =", (*xbits>>shift)&(bitMask|bitPtrMask))
|
|
|
|
gothrow("bad bits in markallocated")
|
|
|
|
}
|
2014-08-07 03:34:30 -06:00
|
|
|
|
2014-08-13 10:42:55 -06:00
|
|
|
var ti, te uintptr
|
|
|
|
var ptrmask *uint8
|
2014-08-07 03:34:30 -06:00
|
|
|
if size == ptrSize {
|
2014-08-13 10:42:55 -06:00
|
|
|
// It's one word and it has pointers, it must be a pointer.
|
|
|
|
*xbits |= (bitsPointer << 2) << shift
|
|
|
|
goto marked
|
2014-08-07 03:34:30 -06:00
|
|
|
}
|
2014-08-19 05:59:42 -06:00
|
|
|
if typ.kind&kindGCProg != 0 {
|
|
|
|
nptr := (uintptr(typ.size) + ptrSize - 1) / ptrSize
|
|
|
|
masksize := nptr
|
|
|
|
if masksize%2 != 0 {
|
|
|
|
masksize *= 2 // repeated
|
2014-08-07 03:34:30 -06:00
|
|
|
}
|
2014-08-19 05:59:42 -06:00
|
|
|
masksize = masksize * pointersPerByte / 8 // 4 bits per word
|
|
|
|
masksize++ // unroll flag in the beginning
|
|
|
|
if masksize > maxGCMask && typ.gc[1] != 0 {
|
2014-10-30 08:16:03 -06:00
|
|
|
// write barriers have not been updated to deal with this case yet.
|
|
|
|
gothrow("maxGCMask too small for now")
|
2014-08-19 05:59:42 -06:00
|
|
|
// If the mask is too large, unroll the program directly
|
|
|
|
// into the GC bitmap. It's 7 times slower than copying
|
|
|
|
// from the pre-unrolled mask, but saves 1/16 of type size
|
|
|
|
// memory for the mask.
|
[dev.cc] runtime: delete scalararg, ptrarg; rename onM to systemstack
Scalararg and ptrarg are not "signal safe".
Go code filling them out can be interrupted by a signal,
and then the signal handler runs, and if it also ends up
in Go code that uses scalararg or ptrarg, now the old
values have been smashed.
For the pieces of code that do need to run in a signal handler,
we introduced onM_signalok, which is really just onM
except that the _signalok is meant to convey that the caller
asserts that scalarg and ptrarg will be restored to their old
values after the call (instead of the usual behavior, zeroing them).
Scalararg and ptrarg are also untyped and therefore error-prone.
Go code can always pass a closure instead of using scalararg
and ptrarg; they were only really necessary for C code.
And there's no more C code.
For all these reasons, delete scalararg and ptrarg, converting
the few remaining references to use closures.
Once those are gone, there is no need for a distinction between
onM and onM_signalok, so replace both with a single function
equivalent to the current onM_signalok (that is, it can be called
on any of the curg, g0, and gsignal stacks).
The name onM and the phrase 'm stack' are misnomers,
because on most system an M has two system stacks:
the main thread stack and the signal handling stack.
Correct the misnomer by naming the replacement function systemstack.
Fix a few references to "M stack" in code.
The main motivation for this change is to eliminate scalararg/ptrarg.
Rick and I have already seen them cause problems because
the calling sequence m.ptrarg[0] = p is a heap pointer assignment,
so it gets a write barrier. The write barrier also uses onM, so it has
all the same problems as if it were being invoked by a signal handler.
We worked around this by saving and restoring the old values
and by calling onM_signalok, but there's no point in keeping this nice
home for bugs around any longer.
This CL also changes funcline to return the file name as a result
instead of filling in a passed-in *string. (The *string signature is
left over from when the code was written in and called from C.)
That's arguably an unrelated change, except that once I had done
the ptrarg/scalararg/onM cleanup I started getting false positives
about the *string argument escaping (not allowed in package runtime).
The compiler is wrong, but the easiest fix is to write the code like
Go code instead of like C code. I am a bit worried that the compiler
is wrong because of some use of uninitialized memory in the escape
analysis. If that's the reason, it will go away when we convert the
compiler to Go. (And if not, we'll debug it the next time.)
LGTM=khr
R=r, khr
CC=austin, golang-codereviews, iant, rlh
https://golang.org/cl/174950043
2014-11-12 12:54:31 -07:00
|
|
|
systemstack(func() {
|
|
|
|
unrollgcproginplace_m(x, typ, size, size0)
|
|
|
|
})
|
2014-08-07 03:34:30 -06:00
|
|
|
goto marked
|
|
|
|
}
|
2014-08-19 05:59:42 -06:00
|
|
|
ptrmask = (*uint8)(unsafe.Pointer(uintptr(typ.gc[0])))
|
2014-10-22 09:21:16 -06:00
|
|
|
// Check whether the program is already unrolled
|
|
|
|
// by checking if the unroll flag byte is set
|
|
|
|
maskword := uintptr(atomicloadp(unsafe.Pointer(ptrmask)))
|
|
|
|
if *(*uint8)(unsafe.Pointer(&maskword)) == 0 {
|
[dev.cc] runtime: delete scalararg, ptrarg; rename onM to systemstack
Scalararg and ptrarg are not "signal safe".
Go code filling them out can be interrupted by a signal,
and then the signal handler runs, and if it also ends up
in Go code that uses scalararg or ptrarg, now the old
values have been smashed.
For the pieces of code that do need to run in a signal handler,
we introduced onM_signalok, which is really just onM
except that the _signalok is meant to convey that the caller
asserts that scalarg and ptrarg will be restored to their old
values after the call (instead of the usual behavior, zeroing them).
Scalararg and ptrarg are also untyped and therefore error-prone.
Go code can always pass a closure instead of using scalararg
and ptrarg; they were only really necessary for C code.
And there's no more C code.
For all these reasons, delete scalararg and ptrarg, converting
the few remaining references to use closures.
Once those are gone, there is no need for a distinction between
onM and onM_signalok, so replace both with a single function
equivalent to the current onM_signalok (that is, it can be called
on any of the curg, g0, and gsignal stacks).
The name onM and the phrase 'm stack' are misnomers,
because on most system an M has two system stacks:
the main thread stack and the signal handling stack.
Correct the misnomer by naming the replacement function systemstack.
Fix a few references to "M stack" in code.
The main motivation for this change is to eliminate scalararg/ptrarg.
Rick and I have already seen them cause problems because
the calling sequence m.ptrarg[0] = p is a heap pointer assignment,
so it gets a write barrier. The write barrier also uses onM, so it has
all the same problems as if it were being invoked by a signal handler.
We worked around this by saving and restoring the old values
and by calling onM_signalok, but there's no point in keeping this nice
home for bugs around any longer.
This CL also changes funcline to return the file name as a result
instead of filling in a passed-in *string. (The *string signature is
left over from when the code was written in and called from C.)
That's arguably an unrelated change, except that once I had done
the ptrarg/scalararg/onM cleanup I started getting false positives
about the *string argument escaping (not allowed in package runtime).
The compiler is wrong, but the easiest fix is to write the code like
Go code instead of like C code. I am a bit worried that the compiler
is wrong because of some use of uninitialized memory in the escape
analysis. If that's the reason, it will go away when we convert the
compiler to Go. (And if not, we'll debug it the next time.)
LGTM=khr
R=r, khr
CC=austin, golang-codereviews, iant, rlh
https://golang.org/cl/174950043
2014-11-12 12:54:31 -07:00
|
|
|
systemstack(func() {
|
|
|
|
unrollgcprog_m(typ)
|
|
|
|
})
|
2014-08-07 03:34:30 -06:00
|
|
|
}
|
2014-08-19 05:59:42 -06:00
|
|
|
ptrmask = (*uint8)(add(unsafe.Pointer(ptrmask), 1)) // skip the unroll flag byte
|
|
|
|
} else {
|
2014-10-07 09:06:51 -06:00
|
|
|
ptrmask = (*uint8)(unsafe.Pointer(typ.gc[0])) // pointer to unrolled mask
|
2014-08-07 03:34:30 -06:00
|
|
|
}
|
|
|
|
if size == 2*ptrSize {
|
2014-08-19 07:38:00 -06:00
|
|
|
*xbits = *ptrmask | bitBoundary
|
2014-08-07 03:34:30 -06:00
|
|
|
goto marked
|
|
|
|
}
|
2014-08-19 05:59:42 -06:00
|
|
|
te = uintptr(typ.size) / ptrSize
|
|
|
|
// If the type occupies odd number of words, its mask is repeated.
|
|
|
|
if te%2 == 0 {
|
|
|
|
te /= 2
|
|
|
|
}
|
2014-08-13 10:42:55 -06:00
|
|
|
// Copy pointer bitmask into the bitmap.
|
|
|
|
for i := uintptr(0); i < size0; i += 2 * ptrSize {
|
2014-08-19 05:59:42 -06:00
|
|
|
v := *(*uint8)(add(unsafe.Pointer(ptrmask), ti))
|
|
|
|
ti++
|
|
|
|
if ti == te {
|
|
|
|
ti = 0
|
2014-08-07 03:34:30 -06:00
|
|
|
}
|
2014-08-13 10:42:55 -06:00
|
|
|
if i == 0 {
|
|
|
|
v |= bitBoundary
|
|
|
|
}
|
|
|
|
if i+ptrSize == size0 {
|
|
|
|
v &^= uint8(bitPtrMask << 4)
|
|
|
|
}
|
|
|
|
|
2014-08-19 07:38:00 -06:00
|
|
|
*xbits = v
|
|
|
|
xbits = (*byte)(add(unsafe.Pointer(xbits), ^uintptr(0)))
|
2014-08-07 03:34:30 -06:00
|
|
|
}
|
2014-08-13 10:42:55 -06:00
|
|
|
if size0%(2*ptrSize) == 0 && size0 < size {
|
|
|
|
// Mark the word after last object's word as bitsDead.
|
2014-08-19 07:38:00 -06:00
|
|
|
*xbits = bitsDead << 2
|
2014-08-07 03:34:30 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
marked:
|
2014-11-04 11:31:34 -07:00
|
|
|
|
|
|
|
// GCmarkterminate allocates black
|
|
|
|
// All slots hold nil so no scanning is needed.
|
|
|
|
// This may be racing with GC so do it atomically if there can be
|
|
|
|
// a race marking the bit.
|
|
|
|
if gcphase == _GCmarktermination {
|
2014-11-15 06:00:38 -07:00
|
|
|
systemstack(func() {
|
|
|
|
gcmarknewobject_m(uintptr(x))
|
|
|
|
})
|
2014-11-04 11:31:34 -07:00
|
|
|
}
|
|
|
|
|
2014-07-30 10:01:52 -06:00
|
|
|
if raceenabled {
|
|
|
|
racemalloc(x, size)
|
|
|
|
}
|
2014-08-18 06:33:39 -06:00
|
|
|
|
|
|
|
if debugMalloc {
|
|
|
|
mp := acquirem()
|
|
|
|
if mp.mallocing == 0 {
|
|
|
|
gothrow("bad malloc")
|
|
|
|
}
|
|
|
|
mp.mallocing = 0
|
|
|
|
if mp.curg != nil {
|
runtime: assume precisestack, copystack, StackCopyAlways, ScanStackByFrames
Commit to stack copying for stack growth.
We're carrying around a surprising amount of cruft from older schemes.
I am confident that precise stack scans and stack copying are here to stay.
Delete fallback code for when precise stack info is disabled.
Delete fallback code for when copying stacks is disabled.
Delete fallback code for when StackCopyAlways is disabled.
Delete Stktop chain - there is only one stack segment now.
Delete M.moreargp, M.moreargsize, M.moreframesize, M.cret.
Delete G.writenbuf (unrelated, just dead).
Delete runtime.lessstack, runtime.oldstack.
Delete many amd64 morestack variants.
Delete initialization of morestack frame/arg sizes (shortens split prologue!).
Replace G's stackguard/stackbase/stack0/stacksize/
syscallstack/syscallguard/forkstackguard with simple stack
bounds (lo, hi).
Update liblink, runtime/cgo for adjustments to G.
LGTM=khr
R=khr, bradfitz
CC=golang-codereviews, iant, r
https://golang.org/cl/137410043
2014-09-09 11:39:57 -06:00
|
|
|
mp.curg.stackguard0 = mp.curg.stack.lo + _StackGuard
|
2014-08-18 06:33:39 -06:00
|
|
|
}
|
2014-09-08 16:42:48 -06:00
|
|
|
// Note: one releasem for the acquirem just above.
|
|
|
|
// The other for the acquirem at start of malloc.
|
2014-08-18 06:33:39 -06:00
|
|
|
releasem(mp)
|
|
|
|
releasem(mp)
|
|
|
|
}
|
|
|
|
|
2014-07-30 10:01:52 -06:00
|
|
|
if debug.allocfreetrace != 0 {
|
|
|
|
tracealloc(x, size, typ)
|
|
|
|
}
|
2014-08-12 15:03:32 -06:00
|
|
|
|
|
|
|
if rate := MemProfileRate; rate > 0 {
|
|
|
|
if size < uintptr(rate) && int32(size) < c.next_sample {
|
|
|
|
c.next_sample -= int32(size)
|
|
|
|
} else {
|
2014-08-18 06:33:39 -06:00
|
|
|
mp := acquirem()
|
2014-08-12 15:03:32 -06:00
|
|
|
profilealloc(mp, x, size)
|
2014-08-18 06:33:39 -06:00
|
|
|
releasem(mp)
|
2014-07-30 10:01:52 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-20 10:08:13 -07:00
|
|
|
if memstats.heap_alloc >= memstats.next_gc/2 {
|
2014-07-30 10:01:52 -06:00
|
|
|
gogc(0)
|
|
|
|
}
|
|
|
|
|
|
|
|
return x
|
|
|
|
}
|
|
|
|
|
2014-10-30 08:16:03 -06:00
|
|
|
func loadPtrMask(typ *_type) []uint8 {
|
|
|
|
var ptrmask *uint8
|
|
|
|
nptr := (uintptr(typ.size) + ptrSize - 1) / ptrSize
|
|
|
|
if typ.kind&kindGCProg != 0 {
|
|
|
|
masksize := nptr
|
|
|
|
if masksize%2 != 0 {
|
|
|
|
masksize *= 2 // repeated
|
|
|
|
}
|
|
|
|
masksize = masksize * pointersPerByte / 8 // 4 bits per word
|
|
|
|
masksize++ // unroll flag in the beginning
|
|
|
|
if masksize > maxGCMask && typ.gc[1] != 0 {
|
|
|
|
// write barriers have not been updated to deal with this case yet.
|
|
|
|
gothrow("maxGCMask too small for now")
|
|
|
|
}
|
|
|
|
ptrmask = (*uint8)(unsafe.Pointer(uintptr(typ.gc[0])))
|
|
|
|
// Check whether the program is already unrolled
|
|
|
|
// by checking if the unroll flag byte is set
|
|
|
|
maskword := uintptr(atomicloadp(unsafe.Pointer(ptrmask)))
|
|
|
|
if *(*uint8)(unsafe.Pointer(&maskword)) == 0 {
|
2014-11-15 06:00:38 -07:00
|
|
|
systemstack(func() {
|
|
|
|
unrollgcprog_m(typ)
|
|
|
|
})
|
2014-10-30 08:16:03 -06:00
|
|
|
}
|
|
|
|
ptrmask = (*uint8)(add(unsafe.Pointer(ptrmask), 1)) // skip the unroll flag byte
|
|
|
|
} else {
|
|
|
|
ptrmask = (*uint8)(unsafe.Pointer(typ.gc[0])) // pointer to unrolled mask
|
|
|
|
}
|
|
|
|
return (*[1 << 30]byte)(unsafe.Pointer(ptrmask))[:(nptr+1)/2]
|
|
|
|
}
|
|
|
|
|
2014-07-30 10:01:52 -06:00
|
|
|
// implementation of new builtin
|
|
|
|
func newobject(typ *_type) unsafe.Pointer {
|
2014-11-03 11:26:46 -07:00
|
|
|
flags := uint32(0)
|
2014-07-30 10:01:52 -06:00
|
|
|
if typ.kind&kindNoPointers != 0 {
|
|
|
|
flags |= flagNoScan
|
|
|
|
}
|
2014-09-08 23:08:34 -06:00
|
|
|
return mallocgc(uintptr(typ.size), typ, flags)
|
2014-07-30 10:01:52 -06:00
|
|
|
}
|
|
|
|
|
2014-12-22 11:27:53 -07:00
|
|
|
//go:linkname reflect_unsafe_New reflect.unsafe_New
|
|
|
|
func reflect_unsafe_New(typ *_type) unsafe.Pointer {
|
|
|
|
return newobject(typ)
|
|
|
|
}
|
|
|
|
|
2014-07-30 10:01:52 -06:00
|
|
|
// implementation of make builtin for slices
|
|
|
|
func newarray(typ *_type, n uintptr) unsafe.Pointer {
|
2014-11-03 11:26:46 -07:00
|
|
|
flags := uint32(0)
|
2014-07-30 10:01:52 -06:00
|
|
|
if typ.kind&kindNoPointers != 0 {
|
|
|
|
flags |= flagNoScan
|
|
|
|
}
|
2014-11-11 15:05:02 -07:00
|
|
|
if int(n) < 0 || (typ.size > 0 && n > _MaxMem/uintptr(typ.size)) {
|
2014-07-30 10:01:52 -06:00
|
|
|
panic("runtime: allocation size out of range")
|
|
|
|
}
|
2014-09-08 23:08:34 -06:00
|
|
|
return mallocgc(uintptr(typ.size)*n, typ, flags)
|
2014-07-30 10:01:52 -06:00
|
|
|
}
|
|
|
|
|
2014-12-22 11:27:53 -07:00
|
|
|
//go:linkname reflect_unsafe_NewArray reflect.unsafe_NewArray
|
|
|
|
func reflect_unsafe_NewArray(typ *_type, n uintptr) unsafe.Pointer {
|
|
|
|
return newarray(typ, n)
|
|
|
|
}
|
|
|
|
|
2014-07-31 13:43:40 -06:00
|
|
|
// rawmem returns a chunk of pointerless memory. It is
|
|
|
|
// not zeroed.
|
|
|
|
func rawmem(size uintptr) unsafe.Pointer {
|
2014-09-08 23:08:34 -06:00
|
|
|
return mallocgc(size, nil, flagNoScan|flagNoZero)
|
2014-07-31 13:43:40 -06:00
|
|
|
}
|
|
|
|
|
2014-07-30 10:01:52 -06:00
|
|
|
// round size up to next size class
|
|
|
|
func goroundupsize(size uintptr) uintptr {
|
|
|
|
if size < maxSmallSize {
|
|
|
|
if size <= 1024-8 {
|
|
|
|
return uintptr(class_to_size[size_to_class8[(size+7)>>3]])
|
|
|
|
}
|
|
|
|
return uintptr(class_to_size[size_to_class128[(size-1024+127)>>7]])
|
|
|
|
}
|
|
|
|
if size+pageSize < size {
|
|
|
|
return size
|
|
|
|
}
|
|
|
|
return (size + pageSize - 1) &^ pageMask
|
|
|
|
}
|
|
|
|
|
|
|
|
func profilealloc(mp *m, x unsafe.Pointer, size uintptr) {
|
|
|
|
c := mp.mcache
|
|
|
|
rate := MemProfileRate
|
|
|
|
if size < uintptr(rate) {
|
|
|
|
// pick next profile time
|
|
|
|
// If you change this, also change allocmcache.
|
|
|
|
if rate > 0x3fffffff { // make 2*rate not overflow
|
|
|
|
rate = 0x3fffffff
|
|
|
|
}
|
2014-09-02 15:33:33 -06:00
|
|
|
next := int32(fastrand1()) % (2 * int32(rate))
|
2014-07-30 10:01:52 -06:00
|
|
|
// Subtract the "remainder" of the current allocation.
|
|
|
|
// Otherwise objects that are close in size to sampling rate
|
|
|
|
// will be under-sampled, because we consistently discard this remainder.
|
|
|
|
next -= (int32(size) - c.next_sample)
|
|
|
|
if next < 0 {
|
|
|
|
next = 0
|
|
|
|
}
|
|
|
|
c.next_sample = next
|
|
|
|
}
|
2014-09-01 16:51:12 -06:00
|
|
|
|
|
|
|
mProf_Malloc(x, size)
|
2014-07-30 10:01:52 -06:00
|
|
|
}
|
|
|
|
|
2014-12-12 07:51:20 -07:00
|
|
|
// For now this must be bracketed with a stoptheworld and a starttheworld to ensure
|
|
|
|
// all go routines see the new barrier.
|
|
|
|
func gcinstallmarkwb() {
|
|
|
|
gcphase = _GCmark
|
|
|
|
}
|
|
|
|
|
|
|
|
// force = 0 - start concurrent GC
|
|
|
|
// force = 1 - do STW GC regardless of current heap usage
|
|
|
|
// force = 2 - go STW GC and eager sweep
|
2014-07-30 10:01:52 -06:00
|
|
|
func gogc(force int32) {
|
2014-08-29 08:44:38 -06:00
|
|
|
// The gc is turned off (via enablegc) until the bootstrap has completed.
|
|
|
|
// Also, malloc gets called in the guts of a number of libraries that might be
|
|
|
|
// holding locks. To avoid deadlocks during stoptheworld, don't bother
|
|
|
|
// trying to run gc while holding a lock. The next mallocgc without a lock
|
|
|
|
// will do the gc instead.
|
2014-12-12 07:51:20 -07:00
|
|
|
|
2014-07-30 10:01:52 -06:00
|
|
|
mp := acquirem()
|
2014-08-29 08:44:38 -06:00
|
|
|
if gp := getg(); gp == mp.g0 || mp.locks > 1 || !memstats.enablegc || panicking != 0 || gcpercent < 0 {
|
2014-07-30 10:01:52 -06:00
|
|
|
releasem(mp)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
releasem(mp)
|
2014-08-21 01:46:53 -06:00
|
|
|
mp = nil
|
2014-07-30 10:01:52 -06:00
|
|
|
|
|
|
|
semacquire(&worldsema, false)
|
|
|
|
|
|
|
|
if force == 0 && memstats.heap_alloc < memstats.next_gc {
|
|
|
|
// typically threads which lost the race to grab
|
|
|
|
// worldsema exit here when gc is done.
|
|
|
|
semrelease(&worldsema)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2014-12-12 07:51:20 -07:00
|
|
|
// Pick up the remaining unswept/not being swept spans concurrently
|
|
|
|
for gosweepone() != ^uintptr(0) {
|
|
|
|
sweep.nbgsweep++
|
|
|
|
}
|
|
|
|
|
2014-07-30 10:01:52 -06:00
|
|
|
// Ok, we're doing it! Stop everybody else
|
2014-12-12 07:51:20 -07:00
|
|
|
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
startTime := nanotime()
|
2014-07-30 10:01:52 -06:00
|
|
|
mp = acquirem()
|
|
|
|
mp.gcing = 1
|
2014-08-21 01:46:53 -06:00
|
|
|
releasem(mp)
|
2014-12-12 07:51:20 -07:00
|
|
|
gctimer.count++
|
|
|
|
if force == 0 {
|
|
|
|
gctimer.cycle.sweepterm = nanotime()
|
|
|
|
}
|
[dev.cc] runtime: delete scalararg, ptrarg; rename onM to systemstack
Scalararg and ptrarg are not "signal safe".
Go code filling them out can be interrupted by a signal,
and then the signal handler runs, and if it also ends up
in Go code that uses scalararg or ptrarg, now the old
values have been smashed.
For the pieces of code that do need to run in a signal handler,
we introduced onM_signalok, which is really just onM
except that the _signalok is meant to convey that the caller
asserts that scalarg and ptrarg will be restored to their old
values after the call (instead of the usual behavior, zeroing them).
Scalararg and ptrarg are also untyped and therefore error-prone.
Go code can always pass a closure instead of using scalararg
and ptrarg; they were only really necessary for C code.
And there's no more C code.
For all these reasons, delete scalararg and ptrarg, converting
the few remaining references to use closures.
Once those are gone, there is no need for a distinction between
onM and onM_signalok, so replace both with a single function
equivalent to the current onM_signalok (that is, it can be called
on any of the curg, g0, and gsignal stacks).
The name onM and the phrase 'm stack' are misnomers,
because on most system an M has two system stacks:
the main thread stack and the signal handling stack.
Correct the misnomer by naming the replacement function systemstack.
Fix a few references to "M stack" in code.
The main motivation for this change is to eliminate scalararg/ptrarg.
Rick and I have already seen them cause problems because
the calling sequence m.ptrarg[0] = p is a heap pointer assignment,
so it gets a write barrier. The write barrier also uses onM, so it has
all the same problems as if it were being invoked by a signal handler.
We worked around this by saving and restoring the old values
and by calling onM_signalok, but there's no point in keeping this nice
home for bugs around any longer.
This CL also changes funcline to return the file name as a result
instead of filling in a passed-in *string. (The *string signature is
left over from when the code was written in and called from C.)
That's arguably an unrelated change, except that once I had done
the ptrarg/scalararg/onM cleanup I started getting false positives
about the *string argument escaping (not allowed in package runtime).
The compiler is wrong, but the easiest fix is to write the code like
Go code instead of like C code. I am a bit worried that the compiler
is wrong because of some use of uninitialized memory in the escape
analysis. If that's the reason, it will go away when we convert the
compiler to Go. (And if not, we'll debug it the next time.)
LGTM=khr
R=r, khr
CC=austin, golang-codereviews, iant, rlh
https://golang.org/cl/174950043
2014-11-12 12:54:31 -07:00
|
|
|
systemstack(stoptheworld)
|
2014-11-15 06:00:38 -07:00
|
|
|
systemstack(finishsweep_m) // finish sweep before we start concurrent scan.
|
2014-12-12 07:51:20 -07:00
|
|
|
if force == 0 { // Do as much work concurrently as possible
|
2014-11-15 06:00:38 -07:00
|
|
|
systemstack(starttheworld)
|
2014-12-12 07:51:20 -07:00
|
|
|
gctimer.cycle.scan = nanotime()
|
2014-11-10 11:42:34 -07:00
|
|
|
// Do a concurrent heap scan before we stop the world.
|
2014-11-15 06:00:38 -07:00
|
|
|
systemstack(gcscan_m)
|
2014-12-12 07:51:20 -07:00
|
|
|
gctimer.cycle.installmarkwb = nanotime()
|
2014-11-15 06:00:38 -07:00
|
|
|
systemstack(stoptheworld)
|
2014-12-12 07:51:20 -07:00
|
|
|
gcinstallmarkwb()
|
2014-11-15 06:00:38 -07:00
|
|
|
systemstack(starttheworld)
|
2014-12-12 07:51:20 -07:00
|
|
|
gctimer.cycle.mark = nanotime()
|
2014-11-15 06:00:38 -07:00
|
|
|
systemstack(gcmark_m)
|
2014-12-12 07:51:20 -07:00
|
|
|
gctimer.cycle.markterm = nanotime()
|
2014-11-15 06:00:38 -07:00
|
|
|
systemstack(stoptheworld)
|
|
|
|
systemstack(gcinstalloffwb_m)
|
2014-11-10 11:42:34 -07:00
|
|
|
}
|
2014-11-15 06:00:38 -07:00
|
|
|
|
2014-08-21 01:46:53 -06:00
|
|
|
if mp != acquirem() {
|
|
|
|
gothrow("gogc: rescheduled")
|
|
|
|
}
|
2014-07-30 10:01:52 -06:00
|
|
|
|
|
|
|
clearpools()
|
|
|
|
|
|
|
|
// Run gc on the g0 stack. We do this so that the g stack
|
|
|
|
// we're currently running on will no longer change. Cuts
|
|
|
|
// the root set down a bit (g0 stacks are not scanned, and
|
|
|
|
// we don't need to scan gc's internal state). We also
|
|
|
|
// need to switch to g0 so we can shrink the stack.
|
|
|
|
n := 1
|
|
|
|
if debug.gctrace > 1 {
|
|
|
|
n = 2
|
|
|
|
}
|
2014-11-15 06:00:38 -07:00
|
|
|
eagersweep := force >= 2
|
2014-07-30 10:01:52 -06:00
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
if i > 0 {
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
startTime = nanotime()
|
2014-07-30 10:01:52 -06:00
|
|
|
}
|
|
|
|
// switch to g0, call gc, then switch back
|
[dev.cc] runtime: delete scalararg, ptrarg; rename onM to systemstack
Scalararg and ptrarg are not "signal safe".
Go code filling them out can be interrupted by a signal,
and then the signal handler runs, and if it also ends up
in Go code that uses scalararg or ptrarg, now the old
values have been smashed.
For the pieces of code that do need to run in a signal handler,
we introduced onM_signalok, which is really just onM
except that the _signalok is meant to convey that the caller
asserts that scalarg and ptrarg will be restored to their old
values after the call (instead of the usual behavior, zeroing them).
Scalararg and ptrarg are also untyped and therefore error-prone.
Go code can always pass a closure instead of using scalararg
and ptrarg; they were only really necessary for C code.
And there's no more C code.
For all these reasons, delete scalararg and ptrarg, converting
the few remaining references to use closures.
Once those are gone, there is no need for a distinction between
onM and onM_signalok, so replace both with a single function
equivalent to the current onM_signalok (that is, it can be called
on any of the curg, g0, and gsignal stacks).
The name onM and the phrase 'm stack' are misnomers,
because on most system an M has two system stacks:
the main thread stack and the signal handling stack.
Correct the misnomer by naming the replacement function systemstack.
Fix a few references to "M stack" in code.
The main motivation for this change is to eliminate scalararg/ptrarg.
Rick and I have already seen them cause problems because
the calling sequence m.ptrarg[0] = p is a heap pointer assignment,
so it gets a write barrier. The write barrier also uses onM, so it has
all the same problems as if it were being invoked by a signal handler.
We worked around this by saving and restoring the old values
and by calling onM_signalok, but there's no point in keeping this nice
home for bugs around any longer.
This CL also changes funcline to return the file name as a result
instead of filling in a passed-in *string. (The *string signature is
left over from when the code was written in and called from C.)
That's arguably an unrelated change, except that once I had done
the ptrarg/scalararg/onM cleanup I started getting false positives
about the *string argument escaping (not allowed in package runtime).
The compiler is wrong, but the easiest fix is to write the code like
Go code instead of like C code. I am a bit worried that the compiler
is wrong because of some use of uninitialized memory in the escape
analysis. If that's the reason, it will go away when we convert the
compiler to Go. (And if not, we'll debug it the next time.)
LGTM=khr
R=r, khr
CC=austin, golang-codereviews, iant, rlh
https://golang.org/cl/174950043
2014-11-12 12:54:31 -07:00
|
|
|
systemstack(func() {
|
|
|
|
gc_m(startTime, eagersweep)
|
|
|
|
})
|
2014-07-30 10:01:52 -06:00
|
|
|
}
|
|
|
|
|
2014-11-15 06:00:38 -07:00
|
|
|
systemstack(func() {
|
|
|
|
gccheckmark_m(startTime, eagersweep)
|
|
|
|
})
|
2014-11-04 11:31:34 -07:00
|
|
|
|
2014-07-30 10:01:52 -06:00
|
|
|
// all done
|
|
|
|
mp.gcing = 0
|
2014-12-12 07:51:20 -07:00
|
|
|
|
|
|
|
if force == 0 {
|
|
|
|
gctimer.cycle.sweep = nanotime()
|
|
|
|
}
|
|
|
|
|
2014-07-30 10:01:52 -06:00
|
|
|
semrelease(&worldsema)
|
2014-12-12 07:51:20 -07:00
|
|
|
|
|
|
|
if force == 0 {
|
|
|
|
if gctimer.verbose > 1 {
|
|
|
|
GCprinttimes()
|
|
|
|
} else if gctimer.verbose > 0 {
|
|
|
|
calctimes() // ignore result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[dev.cc] runtime: delete scalararg, ptrarg; rename onM to systemstack
Scalararg and ptrarg are not "signal safe".
Go code filling them out can be interrupted by a signal,
and then the signal handler runs, and if it also ends up
in Go code that uses scalararg or ptrarg, now the old
values have been smashed.
For the pieces of code that do need to run in a signal handler,
we introduced onM_signalok, which is really just onM
except that the _signalok is meant to convey that the caller
asserts that scalarg and ptrarg will be restored to their old
values after the call (instead of the usual behavior, zeroing them).
Scalararg and ptrarg are also untyped and therefore error-prone.
Go code can always pass a closure instead of using scalararg
and ptrarg; they were only really necessary for C code.
And there's no more C code.
For all these reasons, delete scalararg and ptrarg, converting
the few remaining references to use closures.
Once those are gone, there is no need for a distinction between
onM and onM_signalok, so replace both with a single function
equivalent to the current onM_signalok (that is, it can be called
on any of the curg, g0, and gsignal stacks).
The name onM and the phrase 'm stack' are misnomers,
because on most system an M has two system stacks:
the main thread stack and the signal handling stack.
Correct the misnomer by naming the replacement function systemstack.
Fix a few references to "M stack" in code.
The main motivation for this change is to eliminate scalararg/ptrarg.
Rick and I have already seen them cause problems because
the calling sequence m.ptrarg[0] = p is a heap pointer assignment,
so it gets a write barrier. The write barrier also uses onM, so it has
all the same problems as if it were being invoked by a signal handler.
We worked around this by saving and restoring the old values
and by calling onM_signalok, but there's no point in keeping this nice
home for bugs around any longer.
This CL also changes funcline to return the file name as a result
instead of filling in a passed-in *string. (The *string signature is
left over from when the code was written in and called from C.)
That's arguably an unrelated change, except that once I had done
the ptrarg/scalararg/onM cleanup I started getting false positives
about the *string argument escaping (not allowed in package runtime).
The compiler is wrong, but the easiest fix is to write the code like
Go code instead of like C code. I am a bit worried that the compiler
is wrong because of some use of uninitialized memory in the escape
analysis. If that's the reason, it will go away when we convert the
compiler to Go. (And if not, we'll debug it the next time.)
LGTM=khr
R=r, khr
CC=austin, golang-codereviews, iant, rlh
https://golang.org/cl/174950043
2014-11-12 12:54:31 -07:00
|
|
|
systemstack(starttheworld)
|
2014-12-12 07:51:20 -07:00
|
|
|
|
2014-07-30 10:01:52 -06:00
|
|
|
releasem(mp)
|
2014-08-21 01:46:53 -06:00
|
|
|
mp = nil
|
2014-07-30 10:01:52 -06:00
|
|
|
|
|
|
|
// now that gc is done, kick off finalizer thread if needed
|
|
|
|
if !concurrentSweep {
|
|
|
|
// give the queued finalizers, if any, a chance to run
|
2014-09-11 14:22:21 -06:00
|
|
|
Gosched()
|
2014-07-30 10:01:52 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-04 11:31:34 -07:00
|
|
|
func GCcheckmarkenable() {
|
2014-11-15 06:00:38 -07:00
|
|
|
systemstack(gccheckmarkenable_m)
|
2014-11-04 11:31:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func GCcheckmarkdisable() {
|
2014-11-15 06:00:38 -07:00
|
|
|
systemstack(gccheckmarkdisable_m)
|
2014-11-04 11:31:34 -07:00
|
|
|
}
|
|
|
|
|
2014-12-12 07:51:20 -07:00
|
|
|
// gctimes records the time in nanoseconds of each phase of the concurrent GC.
|
|
|
|
type gctimes struct {
|
|
|
|
sweepterm int64 // stw
|
|
|
|
scan int64 // stw
|
|
|
|
installmarkwb int64
|
|
|
|
mark int64
|
|
|
|
markterm int64 // stw
|
|
|
|
sweep int64
|
|
|
|
}
|
|
|
|
|
|
|
|
// gcchronograph holds timer information related to GC phases
|
|
|
|
// max records the maximum time spent in each GC phase since GCstarttimes.
|
|
|
|
// total records the total time spent in each GC phase since GCstarttimes.
|
|
|
|
// cycle records the absolute time (as returned by nanoseconds()) that each GC phase last started at.
|
|
|
|
type gcchronograph struct {
|
|
|
|
count int64
|
|
|
|
verbose int64
|
|
|
|
maxpause int64
|
|
|
|
max gctimes
|
|
|
|
total gctimes
|
|
|
|
cycle gctimes
|
|
|
|
}
|
|
|
|
|
|
|
|
var gctimer gcchronograph
|
|
|
|
|
|
|
|
// GCstarttimes initializes the gc timess. All previous timess are lost.
|
|
|
|
func GCstarttimes(verbose int64) {
|
|
|
|
gctimer = gcchronograph{verbose: verbose}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GCendtimes stops the gc timers.
|
|
|
|
func GCendtimes() {
|
|
|
|
gctimer.verbose = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// calctimes converts gctimer.cycle into the elapsed times, updates gctimer.total
|
|
|
|
// and updates gctimer.max with the max pause time.
|
|
|
|
func calctimes() gctimes {
|
|
|
|
var times gctimes
|
|
|
|
|
|
|
|
var max = func(a, b int64) int64 {
|
|
|
|
if a > b {
|
|
|
|
return a
|
|
|
|
}
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
|
|
|
times.sweepterm = gctimer.cycle.scan - gctimer.cycle.sweepterm
|
|
|
|
gctimer.total.sweepterm += times.sweepterm
|
|
|
|
gctimer.max.sweepterm = max(gctimer.max.sweepterm, times.sweepterm)
|
|
|
|
gctimer.maxpause = max(gctimer.maxpause, gctimer.max.sweepterm)
|
|
|
|
|
|
|
|
times.scan = gctimer.cycle.installmarkwb - gctimer.cycle.scan
|
|
|
|
gctimer.total.scan += times.scan
|
|
|
|
gctimer.max.scan = max(gctimer.max.scan, times.scan)
|
|
|
|
|
|
|
|
times.installmarkwb = gctimer.cycle.mark - gctimer.cycle.installmarkwb
|
|
|
|
gctimer.total.installmarkwb += times.installmarkwb
|
|
|
|
gctimer.max.installmarkwb = max(gctimer.max.installmarkwb, times.installmarkwb)
|
|
|
|
gctimer.maxpause = max(gctimer.maxpause, gctimer.max.installmarkwb)
|
|
|
|
|
|
|
|
times.mark = gctimer.cycle.markterm - gctimer.cycle.mark
|
|
|
|
gctimer.total.mark += times.mark
|
|
|
|
gctimer.max.mark = max(gctimer.max.mark, times.mark)
|
|
|
|
|
|
|
|
times.markterm = gctimer.cycle.sweep - gctimer.cycle.markterm
|
|
|
|
gctimer.total.markterm += times.markterm
|
|
|
|
gctimer.max.markterm = max(gctimer.max.markterm, times.markterm)
|
|
|
|
gctimer.maxpause = max(gctimer.maxpause, gctimer.max.markterm)
|
|
|
|
|
|
|
|
return times
|
|
|
|
}
|
|
|
|
|
|
|
|
// GCprinttimes prints latency information in nanoseconds about various
|
|
|
|
// phases in the GC. The information for each phase includes the maximum pause
|
|
|
|
// and total time since the most recent call to GCstarttimes as well as
|
|
|
|
// the information from the most recent Concurent GC cycle. Calls from the
|
|
|
|
// application to runtime.GC() are ignored.
|
|
|
|
func GCprinttimes() {
|
|
|
|
times := calctimes()
|
|
|
|
println("GC:", gctimer.count, "maxpause=", gctimer.maxpause, "Go routines=", allglen)
|
|
|
|
println(" sweep termination: max=", gctimer.max.sweepterm, "total=", gctimer.total.sweepterm, "cycle=", times.sweepterm, "absolute time=", gctimer.cycle.sweepterm)
|
|
|
|
println(" scan: max=", gctimer.max.scan, "total=", gctimer.total.scan, "cycle=", times.scan, "absolute time=", gctimer.cycle.scan)
|
|
|
|
println(" installmarkwb: max=", gctimer.max.installmarkwb, "total=", gctimer.total.installmarkwb, "cycle=", times.installmarkwb, "absolute time=", gctimer.cycle.installmarkwb)
|
|
|
|
println(" mark: max=", gctimer.max.mark, "total=", gctimer.total.mark, "cycle=", times.mark, "absolute time=", gctimer.cycle.mark)
|
|
|
|
println(" markterm: max=", gctimer.max.markterm, "total=", gctimer.total.markterm, "cycle=", times.markterm, "absolute time=", gctimer.cycle.markterm)
|
|
|
|
cycletime := gctimer.cycle.sweep - gctimer.cycle.sweepterm
|
|
|
|
println(" Total cycle time =", cycletime)
|
|
|
|
totalstw := times.sweepterm + times.installmarkwb + times.markterm
|
|
|
|
println(" Cycle STW time =", totalstw)
|
|
|
|
}
|
|
|
|
|
2014-07-30 10:01:52 -06:00
|
|
|
// GC runs a garbage collection.
|
|
|
|
func GC() {
|
|
|
|
gogc(2)
|
|
|
|
}
|
|
|
|
|
2014-10-06 12:18:09 -06:00
|
|
|
// linker-provided
|
|
|
|
var noptrdata struct{}
|
2014-11-19 13:25:33 -07:00
|
|
|
var enoptrdata struct{}
|
|
|
|
var noptrbss struct{}
|
2014-10-06 12:18:09 -06:00
|
|
|
var enoptrbss struct{}
|
|
|
|
|
2014-07-30 10:01:52 -06:00
|
|
|
// SetFinalizer sets the finalizer associated with x to f.
|
|
|
|
// When the garbage collector finds an unreachable block
|
|
|
|
// with an associated finalizer, it clears the association and runs
|
|
|
|
// f(x) in a separate goroutine. This makes x reachable again, but
|
|
|
|
// now without an associated finalizer. Assuming that SetFinalizer
|
|
|
|
// is not called again, the next time the garbage collector sees
|
|
|
|
// that x is unreachable, it will free x.
|
|
|
|
//
|
|
|
|
// SetFinalizer(x, nil) clears any finalizer associated with x.
|
|
|
|
//
|
|
|
|
// The argument x must be a pointer to an object allocated by
|
|
|
|
// calling new or by taking the address of a composite literal.
|
|
|
|
// The argument f must be a function that takes a single argument
|
|
|
|
// to which x's type can be assigned, and can have arbitrary ignored return
|
|
|
|
// values. If either of these is not true, SetFinalizer aborts the
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
// The finalizer for x is scheduled to run at some arbitrary time after
|
|
|
|
// x becomes unreachable.
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
// It is not guaranteed that a finalizer will run if the size of *x is
|
|
|
|
// zero bytes.
|
|
|
|
//
|
2014-10-06 12:18:09 -06:00
|
|
|
// 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.
|
|
|
|
//
|
2014-07-30 10:01:52 -06: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{}) {
|
|
|
|
e := (*eface)(unsafe.Pointer(&obj))
|
2014-08-28 14:23:10 -06:00
|
|
|
etyp := e._type
|
|
|
|
if etyp == nil {
|
2014-07-30 10:01:52 -06:00
|
|
|
gothrow("runtime.SetFinalizer: first argument is nil")
|
|
|
|
}
|
2014-08-28 14:23:10 -06:00
|
|
|
if etyp.kind&kindMask != kindPtr {
|
|
|
|
gothrow("runtime.SetFinalizer: first argument is " + *etyp._string + ", not pointer")
|
|
|
|
}
|
|
|
|
ot := (*ptrtype)(unsafe.Pointer(etyp))
|
|
|
|
if ot.elem == nil {
|
|
|
|
gothrow("nil elem type!")
|
|
|
|
}
|
|
|
|
|
|
|
|
// find the containing object
|
|
|
|
_, base, _ := findObject(e.data)
|
|
|
|
|
|
|
|
if base == nil {
|
2014-10-06 12:18:09 -06:00
|
|
|
// 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)
|
|
|
|
// }
|
2014-11-19 13:25:33 -07:00
|
|
|
// The relevant segments are: noptrdata, data, bss, noptrbss.
|
|
|
|
// We cannot assume they are in any order or even contiguous,
|
|
|
|
// due to external linking.
|
|
|
|
if uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrdata)) ||
|
|
|
|
uintptr(unsafe.Pointer(&data)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&edata)) ||
|
|
|
|
uintptr(unsafe.Pointer(&bss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&ebss)) ||
|
|
|
|
uintptr(unsafe.Pointer(&noptrbss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrbss)) {
|
2014-10-06 12:18:09 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
gothrow("runtime.SetFinalizer: pointer not in allocated block")
|
2014-08-28 14:23:10 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
|
|
|
gothrow("runtime.SetFinalizer: pointer not at beginning of allocated block")
|
|
|
|
}
|
2014-07-30 10:01:52 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
f := (*eface)(unsafe.Pointer(&finalizer))
|
|
|
|
ftyp := f._type
|
2014-08-28 14:23:10 -06:00
|
|
|
if ftyp == nil {
|
[dev.cc] runtime: delete scalararg, ptrarg; rename onM to systemstack
Scalararg and ptrarg are not "signal safe".
Go code filling them out can be interrupted by a signal,
and then the signal handler runs, and if it also ends up
in Go code that uses scalararg or ptrarg, now the old
values have been smashed.
For the pieces of code that do need to run in a signal handler,
we introduced onM_signalok, which is really just onM
except that the _signalok is meant to convey that the caller
asserts that scalarg and ptrarg will be restored to their old
values after the call (instead of the usual behavior, zeroing them).
Scalararg and ptrarg are also untyped and therefore error-prone.
Go code can always pass a closure instead of using scalararg
and ptrarg; they were only really necessary for C code.
And there's no more C code.
For all these reasons, delete scalararg and ptrarg, converting
the few remaining references to use closures.
Once those are gone, there is no need for a distinction between
onM and onM_signalok, so replace both with a single function
equivalent to the current onM_signalok (that is, it can be called
on any of the curg, g0, and gsignal stacks).
The name onM and the phrase 'm stack' are misnomers,
because on most system an M has two system stacks:
the main thread stack and the signal handling stack.
Correct the misnomer by naming the replacement function systemstack.
Fix a few references to "M stack" in code.
The main motivation for this change is to eliminate scalararg/ptrarg.
Rick and I have already seen them cause problems because
the calling sequence m.ptrarg[0] = p is a heap pointer assignment,
so it gets a write barrier. The write barrier also uses onM, so it has
all the same problems as if it were being invoked by a signal handler.
We worked around this by saving and restoring the old values
and by calling onM_signalok, but there's no point in keeping this nice
home for bugs around any longer.
This CL also changes funcline to return the file name as a result
instead of filling in a passed-in *string. (The *string signature is
left over from when the code was written in and called from C.)
That's arguably an unrelated change, except that once I had done
the ptrarg/scalararg/onM cleanup I started getting false positives
about the *string argument escaping (not allowed in package runtime).
The compiler is wrong, but the easiest fix is to write the code like
Go code instead of like C code. I am a bit worried that the compiler
is wrong because of some use of uninitialized memory in the escape
analysis. If that's the reason, it will go away when we convert the
compiler to Go. (And if not, we'll debug it the next time.)
LGTM=khr
R=r, khr
CC=austin, golang-codereviews, iant, rlh
https://golang.org/cl/174950043
2014-11-12 12:54:31 -07:00
|
|
|
// switch to system stack and remove finalizer
|
|
|
|
systemstack(func() {
|
2014-11-11 15:05:02 -07:00
|
|
|
removefinalizer(e.data)
|
|
|
|
})
|
2014-08-28 14:23:10 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if ftyp.kind&kindMask != kindFunc {
|
2014-07-30 10:01:52 -06:00
|
|
|
gothrow("runtime.SetFinalizer: second argument is " + *ftyp._string + ", not a function")
|
|
|
|
}
|
2014-08-28 14:23:10 -06:00
|
|
|
ft := (*functype)(unsafe.Pointer(ftyp))
|
|
|
|
ins := *(*[]*_type)(unsafe.Pointer(&ft.in))
|
|
|
|
if ft.dotdotdot || len(ins) != 1 {
|
|
|
|
gothrow("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string)
|
|
|
|
}
|
|
|
|
fint := ins[0]
|
|
|
|
switch {
|
|
|
|
case fint == etyp:
|
|
|
|
// ok - same type
|
|
|
|
goto okarg
|
|
|
|
case fint.kind&kindMask == kindPtr:
|
|
|
|
if (fint.x == nil || fint.x.name == nil || etyp.x == nil || etyp.x.name == nil) && (*ptrtype)(unsafe.Pointer(fint)).elem == ot.elem {
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
if _, ok := assertE2I2(ityp, obj); ok {
|
|
|
|
goto okarg
|
|
|
|
}
|
|
|
|
}
|
|
|
|
gothrow("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string)
|
|
|
|
okarg:
|
|
|
|
// compute size needed for return parameters
|
|
|
|
nret := uintptr(0)
|
|
|
|
for _, t := range *(*[]*_type)(unsafe.Pointer(&ft.out)) {
|
|
|
|
nret = round(nret, uintptr(t.align)) + uintptr(t.size)
|
|
|
|
}
|
|
|
|
nret = round(nret, ptrSize)
|
|
|
|
|
|
|
|
// make sure we have a finalizer goroutine
|
|
|
|
createfing()
|
|
|
|
|
[dev.cc] runtime: delete scalararg, ptrarg; rename onM to systemstack
Scalararg and ptrarg are not "signal safe".
Go code filling them out can be interrupted by a signal,
and then the signal handler runs, and if it also ends up
in Go code that uses scalararg or ptrarg, now the old
values have been smashed.
For the pieces of code that do need to run in a signal handler,
we introduced onM_signalok, which is really just onM
except that the _signalok is meant to convey that the caller
asserts that scalarg and ptrarg will be restored to their old
values after the call (instead of the usual behavior, zeroing them).
Scalararg and ptrarg are also untyped and therefore error-prone.
Go code can always pass a closure instead of using scalararg
and ptrarg; they were only really necessary for C code.
And there's no more C code.
For all these reasons, delete scalararg and ptrarg, converting
the few remaining references to use closures.
Once those are gone, there is no need for a distinction between
onM and onM_signalok, so replace both with a single function
equivalent to the current onM_signalok (that is, it can be called
on any of the curg, g0, and gsignal stacks).
The name onM and the phrase 'm stack' are misnomers,
because on most system an M has two system stacks:
the main thread stack and the signal handling stack.
Correct the misnomer by naming the replacement function systemstack.
Fix a few references to "M stack" in code.
The main motivation for this change is to eliminate scalararg/ptrarg.
Rick and I have already seen them cause problems because
the calling sequence m.ptrarg[0] = p is a heap pointer assignment,
so it gets a write barrier. The write barrier also uses onM, so it has
all the same problems as if it were being invoked by a signal handler.
We worked around this by saving and restoring the old values
and by calling onM_signalok, but there's no point in keeping this nice
home for bugs around any longer.
This CL also changes funcline to return the file name as a result
instead of filling in a passed-in *string. (The *string signature is
left over from when the code was written in and called from C.)
That's arguably an unrelated change, except that once I had done
the ptrarg/scalararg/onM cleanup I started getting false positives
about the *string argument escaping (not allowed in package runtime).
The compiler is wrong, but the easiest fix is to write the code like
Go code instead of like C code. I am a bit worried that the compiler
is wrong because of some use of uninitialized memory in the escape
analysis. If that's the reason, it will go away when we convert the
compiler to Go. (And if not, we'll debug it the next time.)
LGTM=khr
R=r, khr
CC=austin, golang-codereviews, iant, rlh
https://golang.org/cl/174950043
2014-11-12 12:54:31 -07:00
|
|
|
systemstack(func() {
|
2014-11-11 15:05:02 -07:00
|
|
|
if !addfinalizer(e.data, (*funcval)(f.data), nret, fint, ot) {
|
|
|
|
gothrow("runtime.SetFinalizer: finalizer already set")
|
|
|
|
}
|
|
|
|
})
|
2014-07-30 10:01:52 -06:00
|
|
|
}
|
2014-08-28 14:23:10 -06:00
|
|
|
|
|
|
|
// round n up to a multiple of a. a must be a power of 2.
|
|
|
|
func round(n, a uintptr) uintptr {
|
|
|
|
return (n + a - 1) &^ (a - 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
// does not exist, return nil, nil, 0.
|
|
|
|
func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) {
|
|
|
|
c := gomcache()
|
|
|
|
c.local_nlookup++
|
|
|
|
if ptrSize == 4 && c.local_nlookup >= 1<<30 {
|
|
|
|
// purge cache stats to prevent overflow
|
|
|
|
lock(&mheap_.lock)
|
|
|
|
purgecachedstats(c)
|
|
|
|
unlock(&mheap_.lock)
|
|
|
|
}
|
|
|
|
|
|
|
|
// find span
|
|
|
|
arena_start := uintptr(unsafe.Pointer(mheap_.arena_start))
|
|
|
|
arena_used := uintptr(unsafe.Pointer(mheap_.arena_used))
|
|
|
|
if uintptr(v) < arena_start || uintptr(v) >= arena_used {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
p := uintptr(v) >> pageShift
|
|
|
|
q := p - arena_start>>pageShift
|
|
|
|
s = *(**mspan)(add(unsafe.Pointer(mheap_.spans), q*ptrSize))
|
|
|
|
if s == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
x = unsafe.Pointer(uintptr(s.start) << pageShift)
|
|
|
|
|
|
|
|
if uintptr(v) < uintptr(x) || uintptr(v) >= uintptr(unsafe.Pointer(s.limit)) || s.state != mSpanInUse {
|
|
|
|
s = nil
|
|
|
|
x = nil
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
n = uintptr(s.elemsize)
|
|
|
|
if s.sizeclass != 0 {
|
|
|
|
x = add(x, (uintptr(v)-uintptr(x))/n*n)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var fingCreate uint32
|
|
|
|
|
|
|
|
func createfing() {
|
|
|
|
// start the finalizer goroutine exactly once
|
|
|
|
if fingCreate == 0 && cas(&fingCreate, 0, 1) {
|
|
|
|
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
|
|
|
|
gp.issystem = true
|
|
|
|
goparkunlock(&finlock, "finalizer wait")
|
|
|
|
gp.issystem = false
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
unlock(&finlock)
|
|
|
|
if raceenabled {
|
|
|
|
racefingo()
|
|
|
|
}
|
|
|
|
for fb != nil {
|
|
|
|
for i := int32(0); i < fb.cnt; i++ {
|
|
|
|
f := (*finalizer)(add(unsafe.Pointer(&fb.fin), uintptr(i)*unsafe.Sizeof(finalizer{})))
|
|
|
|
|
|
|
|
framesz := unsafe.Sizeof((interface{})(nil)) + uintptr(f.nret)
|
|
|
|
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.
|
2014-09-08 23:08:34 -06:00
|
|
|
frame = mallocgc(framesz, nil, flagNoScan)
|
2014-08-28 14:23:10 -06:00
|
|
|
framecap = framesz
|
|
|
|
}
|
|
|
|
|
|
|
|
if f.fint == nil {
|
|
|
|
gothrow("missing type in runfinq")
|
|
|
|
}
|
|
|
|
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
|
|
|
|
*(*fInterface)(frame) = assertE2I(ityp, *(*interface{})(frame))
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
gothrow("bad kind in runfinq")
|
|
|
|
}
|
2014-09-06 11:19:08 -06:00
|
|
|
reflectcall(unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz))
|
2014-08-28 14:23:10 -06:00
|
|
|
|
|
|
|
// drop finalizer queue references to finalized object
|
|
|
|
f.fn = nil
|
|
|
|
f.arg = nil
|
|
|
|
f.ot = nil
|
|
|
|
}
|
|
|
|
fb.cnt = 0
|
|
|
|
next := fb.next
|
|
|
|
lock(&finlock)
|
|
|
|
fb.next = finc
|
|
|
|
finc = fb
|
|
|
|
unlock(&finlock)
|
|
|
|
fb = next
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-09-03 22:54:06 -06:00
|
|
|
|
|
|
|
var persistent struct {
|
|
|
|
lock mutex
|
|
|
|
pos unsafe.Pointer
|
|
|
|
end unsafe.Pointer
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wrapper around sysAlloc that can allocate small chunks.
|
|
|
|
// There is no associated free operation.
|
|
|
|
// Intended for things like function/type/debug-related persistent data.
|
|
|
|
// If align is 0, uses default align (currently 8).
|
|
|
|
func persistentalloc(size, align uintptr, stat *uint64) unsafe.Pointer {
|
|
|
|
const (
|
|
|
|
chunk = 256 << 10
|
|
|
|
maxBlock = 64 << 10 // VM reservation granularity is 64K on windows
|
|
|
|
)
|
|
|
|
|
|
|
|
if align != 0 {
|
|
|
|
if align&(align-1) != 0 {
|
|
|
|
gothrow("persistentalloc: align is not a power of 2")
|
|
|
|
}
|
|
|
|
if align > _PageSize {
|
|
|
|
gothrow("persistentalloc: align is too large")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
align = 8
|
|
|
|
}
|
|
|
|
|
|
|
|
if size >= maxBlock {
|
|
|
|
return sysAlloc(size, stat)
|
|
|
|
}
|
|
|
|
|
|
|
|
lock(&persistent.lock)
|
|
|
|
persistent.pos = roundup(persistent.pos, align)
|
|
|
|
if uintptr(persistent.pos)+size > uintptr(persistent.end) {
|
|
|
|
persistent.pos = sysAlloc(chunk, &memstats.other_sys)
|
|
|
|
if persistent.pos == nil {
|
|
|
|
unlock(&persistent.lock)
|
|
|
|
gothrow("runtime: cannot allocate memory")
|
|
|
|
}
|
|
|
|
persistent.end = add(persistent.pos, chunk)
|
|
|
|
}
|
|
|
|
p := persistent.pos
|
|
|
|
persistent.pos = add(persistent.pos, size)
|
|
|
|
unlock(&persistent.lock)
|
|
|
|
|
|
|
|
if stat != &memstats.other_sys {
|
|
|
|
xadd64(stat, int64(size))
|
|
|
|
xadd64(&memstats.other_sys, -int64(size))
|
|
|
|
}
|
|
|
|
return p
|
|
|
|
}
|