2014-07-31 13:43:40 -06:00
|
|
|
// Copyright 2009 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
|
|
|
|
|
|
|
|
import (
|
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
2015-04-10 16:01:54 -06:00
|
|
|
type slice struct {
|
2014-07-31 13:43:40 -06:00
|
|
|
array unsafe.Pointer
|
|
|
|
len int
|
|
|
|
cap int
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: take uintptrs instead of int64s?
|
2015-04-10 16:01:54 -06:00
|
|
|
func makeslice(t *slicetype, len64, cap64 int64) slice {
|
2014-07-31 13:43:40 -06:00
|
|
|
// NOTE: The len > MaxMem/elemsize check here is not strictly necessary,
|
|
|
|
// but it produces a 'len out of range' error instead of a 'cap out of range' error
|
|
|
|
// when someone does make([]T, bignumber). 'cap out of range' is true too,
|
|
|
|
// but since the cap is only being supplied implicitly, saying len is clearer.
|
|
|
|
// See issue 4085.
|
|
|
|
len := int(len64)
|
2014-11-11 15:05:02 -07:00
|
|
|
if len64 < 0 || int64(len) != len64 || t.elem.size > 0 && uintptr(len) > _MaxMem/uintptr(t.elem.size) {
|
2014-07-31 13:43:40 -06:00
|
|
|
panic(errorString("makeslice: len out of range"))
|
|
|
|
}
|
|
|
|
cap := int(cap64)
|
2014-11-11 15:05:02 -07:00
|
|
|
if cap < len || int64(cap) != cap64 || t.elem.size > 0 && uintptr(cap) > _MaxMem/uintptr(t.elem.size) {
|
2014-07-31 13:43:40 -06:00
|
|
|
panic(errorString("makeslice: cap out of range"))
|
|
|
|
}
|
|
|
|
p := newarray(t.elem, uintptr(cap))
|
2015-04-10 16:01:54 -06:00
|
|
|
return slice{p, len, cap}
|
2014-07-31 13:43:40 -06:00
|
|
|
}
|
|
|
|
|
2015-04-10 16:01:54 -06:00
|
|
|
func growslice(t *slicetype, old slice, n int) slice {
|
2014-07-31 13:43:40 -06:00
|
|
|
if n < 1 {
|
|
|
|
panic(errorString("growslice: invalid n"))
|
|
|
|
}
|
|
|
|
|
2015-02-26 23:13:05 -07:00
|
|
|
cap := old.cap + n
|
|
|
|
if cap < old.cap || t.elem.size > 0 && uintptr(cap) > _MaxMem/uintptr(t.elem.size) {
|
2014-07-31 13:43:40 -06:00
|
|
|
panic(errorString("growslice: cap out of range"))
|
|
|
|
}
|
|
|
|
|
|
|
|
if raceenabled {
|
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
|
|
|
callerpc := getcallerpc(unsafe.Pointer(&t))
|
2014-09-04 13:53:45 -06:00
|
|
|
racereadrangepc(old.array, uintptr(old.len*int(t.elem.size)), callerpc, funcPC(growslice))
|
2014-07-31 13:43:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
et := t.elem
|
|
|
|
if et.size == 0 {
|
2015-03-11 10:07:50 -06:00
|
|
|
// append should not create a slice with nil pointer but non-zero len.
|
|
|
|
// We assume that append doesn't need to preserve old.array in this case.
|
2015-04-10 16:01:54 -06:00
|
|
|
return slice{unsafe.Pointer(&zerobase), old.len, cap}
|
2014-07-31 13:43:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
newcap := old.cap
|
|
|
|
if newcap+newcap < cap {
|
|
|
|
newcap = cap
|
|
|
|
} else {
|
|
|
|
for {
|
|
|
|
if old.len < 1024 {
|
|
|
|
newcap += newcap
|
|
|
|
} else {
|
|
|
|
newcap += newcap / 4
|
|
|
|
}
|
|
|
|
if newcap >= cap {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-11 15:05:02 -07:00
|
|
|
if uintptr(newcap) >= _MaxMem/uintptr(et.size) {
|
2014-07-31 13:43:40 -06:00
|
|
|
panic(errorString("growslice: cap out of range"))
|
|
|
|
}
|
|
|
|
lenmem := uintptr(old.len) * uintptr(et.size)
|
2014-12-29 00:16:32 -07:00
|
|
|
capmem := roundupsize(uintptr(newcap) * uintptr(et.size))
|
2014-07-31 13:43:40 -06:00
|
|
|
newcap = int(capmem / uintptr(et.size))
|
|
|
|
var p unsafe.Pointer
|
|
|
|
if et.kind&kindNoPointers != 0 {
|
|
|
|
p = rawmem(capmem)
|
2014-12-22 20:42:05 -07:00
|
|
|
memmove(p, old.array, lenmem)
|
2014-07-31 13:43:40 -06:00
|
|
|
memclr(add(p, lenmem), capmem-lenmem)
|
|
|
|
} else {
|
2014-12-22 20:42:05 -07:00
|
|
|
// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan unitialized memory.
|
runtime: replace needwb() with writeBarrierEnabled
Reduce the write barrier check to a single load and compare
so that it can be inlined into write barrier use sites.
Makes the standard write barrier a little faster too.
name old new delta
BenchmarkBinaryTree17 17.9s × (0.99,1.01) 17.9s × (1.00,1.01) ~
BenchmarkFannkuch11 4.35s × (1.00,1.00) 4.43s × (1.00,1.00) +1.81%
BenchmarkFmtFprintfEmpty 120ns × (0.93,1.06) 110ns × (1.00,1.06) -7.92%
BenchmarkFmtFprintfString 479ns × (0.99,1.00) 487ns × (0.99,1.00) +1.67%
BenchmarkFmtFprintfInt 452ns × (0.99,1.02) 450ns × (0.99,1.00) ~
BenchmarkFmtFprintfIntInt 766ns × (0.99,1.01) 762ns × (1.00,1.00) ~
BenchmarkFmtFprintfPrefixedInt 576ns × (0.98,1.01) 584ns × (0.99,1.01) ~
BenchmarkFmtFprintfFloat 730ns × (1.00,1.01) 738ns × (1.00,1.00) +1.16%
BenchmarkFmtManyArgs 2.84µs × (0.99,1.00) 2.80µs × (1.00,1.01) -1.22%
BenchmarkGobDecode 39.3ms × (0.98,1.01) 39.0ms × (0.99,1.00) ~
BenchmarkGobEncode 39.5ms × (0.99,1.01) 37.8ms × (0.98,1.01) -4.33%
BenchmarkGzip 663ms × (1.00,1.01) 661ms × (0.99,1.01) ~
BenchmarkGunzip 143ms × (1.00,1.00) 142ms × (1.00,1.00) ~
BenchmarkHTTPClientServer 132µs × (0.99,1.01) 132µs × (0.99,1.01) ~
BenchmarkJSONEncode 57.4ms × (0.99,1.01) 56.3ms × (0.99,1.01) -1.96%
BenchmarkJSONDecode 139ms × (0.99,1.00) 138ms × (0.99,1.01) ~
BenchmarkMandelbrot200 6.03ms × (1.00,1.00) 6.01ms × (1.00,1.00) ~
BenchmarkGoParse 10.3ms × (0.89,1.14) 10.2ms × (0.87,1.05) ~
BenchmarkRegexpMatchEasy0_32 209ns × (1.00,1.00) 208ns × (1.00,1.00) ~
BenchmarkRegexpMatchEasy0_1K 591ns × (0.99,1.00) 588ns × (1.00,1.00) ~
BenchmarkRegexpMatchEasy1_32 184ns × (0.99,1.02) 182ns × (0.99,1.01) ~
BenchmarkRegexpMatchEasy1_1K 1.01µs × (1.00,1.00) 0.99µs × (1.00,1.01) -2.33%
BenchmarkRegexpMatchMedium_32 330ns × (1.00,1.00) 323ns × (1.00,1.01) -2.12%
BenchmarkRegexpMatchMedium_1K 92.6µs × (1.00,1.00) 89.9µs × (1.00,1.00) -2.92%
BenchmarkRegexpMatchHard_32 4.80µs × (0.95,1.00) 4.72µs × (0.95,1.01) ~
BenchmarkRegexpMatchHard_1K 136µs × (1.00,1.00) 133µs × (1.00,1.01) -1.86%
BenchmarkRevcomp 900ms × (0.99,1.04) 900ms × (1.00,1.05) ~
BenchmarkTemplate 172ms × (1.00,1.00) 168ms × (0.99,1.01) -2.07%
BenchmarkTimeParse 637ns × (1.00,1.00) 637ns × (1.00,1.00) ~
BenchmarkTimeFormat 744ns × (1.00,1.01) 738ns × (1.00,1.00) -0.67%
Change-Id: I4ecc925805da1f5ee264377f1f7574f54ee575e7
Reviewed-on: https://go-review.googlesource.com/9321
Reviewed-by: Austin Clements <austin@google.com>
2015-04-24 12:00:55 -06:00
|
|
|
// TODO(rsc): Use memmove when !writeBarrierEnabled.
|
2014-07-31 13:43:40 -06:00
|
|
|
p = newarray(et, uintptr(newcap))
|
2014-12-22 20:42:05 -07:00
|
|
|
for i := 0; i < old.len; i++ {
|
2014-12-29 08:05:57 -07:00
|
|
|
typedmemmove(et, add(p, uintptr(i)*et.size), add(old.array, uintptr(i)*et.size))
|
2014-12-22 20:42:05 -07:00
|
|
|
}
|
2014-07-31 13:43:40 -06:00
|
|
|
}
|
|
|
|
|
2015-04-10 16:01:54 -06:00
|
|
|
return slice{p, old.len, newcap}
|
2014-07-31 13:43:40 -06:00
|
|
|
}
|
|
|
|
|
2015-04-10 16:01:54 -06:00
|
|
|
func slicecopy(to, fm slice, width uintptr) int {
|
2014-12-30 13:31:17 -07:00
|
|
|
if fm.len == 0 || to.len == 0 {
|
2014-07-31 13:43:40 -06:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
n := fm.len
|
|
|
|
if to.len < n {
|
|
|
|
n = to.len
|
|
|
|
}
|
|
|
|
|
2014-12-30 13:31:17 -07:00
|
|
|
if width == 0 {
|
|
|
|
return n
|
|
|
|
}
|
|
|
|
|
2014-07-31 13:43:40 -06:00
|
|
|
if raceenabled {
|
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
|
|
|
callerpc := getcallerpc(unsafe.Pointer(&to))
|
2014-09-03 09:10:38 -06:00
|
|
|
pc := funcPC(slicecopy)
|
2014-09-04 13:53:45 -06:00
|
|
|
racewriterangepc(to.array, uintptr(n*int(width)), callerpc, pc)
|
|
|
|
racereadrangepc(fm.array, uintptr(n*int(width)), callerpc, pc)
|
2014-07-31 13:43:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
size := uintptr(n) * width
|
|
|
|
if size == 1 { // common case worth about 2x to do here
|
|
|
|
// TODO: is this still worth it with new memmove impl?
|
|
|
|
*(*byte)(to.array) = *(*byte)(fm.array) // known to be a byte pointer
|
|
|
|
} else {
|
|
|
|
memmove(to.array, fm.array, size)
|
|
|
|
}
|
|
|
|
return int(n)
|
|
|
|
}
|
|
|
|
|
|
|
|
func slicestringcopy(to []byte, fm string) int {
|
|
|
|
if len(fm) == 0 || len(to) == 0 {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
n := len(fm)
|
|
|
|
if len(to) < n {
|
|
|
|
n = len(to)
|
|
|
|
}
|
|
|
|
|
|
|
|
if raceenabled {
|
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
|
|
|
callerpc := getcallerpc(unsafe.Pointer(&to))
|
2014-09-03 09:10:38 -06:00
|
|
|
pc := funcPC(slicestringcopy)
|
2014-09-04 13:53:45 -06:00
|
|
|
racewriterangepc(unsafe.Pointer(&to[0]), uintptr(n), callerpc, pc)
|
2014-07-31 13:43:40 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
memmove(unsafe.Pointer(&to[0]), unsafe.Pointer((*stringStruct)(unsafe.Pointer(&fm)).str), uintptr(n))
|
|
|
|
return n
|
|
|
|
}
|