aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/slice.go
diff options
context:
space:
mode:
authorJoe Tsai <joetsai@digital-static.net>2022-03-02 13:01:48 -0800
committerJoseph Tsai <joetsai@digital-static.net>2022-10-15 17:02:11 +0000
commit61f0409c31cad8729d7982425d353d7b2ea80534 (patch)
tree017883773a9694862745945370b7ff6630526d9e /src/runtime/slice.go
parent9ddb8ea73724d717a9bbf44be7d585ba5587504f (diff)
downloadgo-61f0409c31cad8729d7982425d353d7b2ea80534.tar.xz
reflect: add Value.Grow
The Grow method is like the proposed slices.Grow function in that it ensures that the slice has enough capacity to append n elements without allocating. The implementation of Grow is a thin wrapper over runtime.growslice. This also changes Append and AppendSlice to use growslice under the hood. Fixes #48000 Change-Id: I992a58584a2ff1448c1c2bc0877fe76073609111 Reviewed-on: https://go-review.googlesource.com/c/go/+/389635 Run-TryBot: Joseph Tsai <joetsai@digital-static.net> Reviewed-by: Keith Randall <khr@golang.org> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Ian Lance Taylor <iant@google.com>
Diffstat (limited to 'src/runtime/slice.go')
-rw-r--r--src/runtime/slice.go39
1 files changed, 31 insertions, 8 deletions
diff --git a/src/runtime/slice.go b/src/runtime/slice.go
index 284ee1f484..134d14f1a0 100644
--- a/src/runtime/slice.go
+++ b/src/runtime/slice.go
@@ -126,16 +126,18 @@ func mulUintptr(a, b uintptr) (uintptr, bool) {
// growslice allocates new backing store for a slice.
//
// arguments:
-// oldPtr = pointer to the slice's backing array
-// newLen = new length (= oldLen + num)
-// oldCap = original slice's capacity.
-// num = number of elements being added
-// et = element type
+//
+// oldPtr = pointer to the slice's backing array
+// newLen = new length (= oldLen + num)
+// oldCap = original slice's capacity.
+// num = number of elements being added
+// et = element type
//
// return values:
-// newPtr = pointer to the new backing store
-// newLen = same value as the argument
-// newCap = capacity of the new backing store
+//
+// newPtr = pointer to the new backing store
+// newLen = same value as the argument
+// newCap = capacity of the new backing store
//
// Requires that uint(newLen) > uint(oldCap).
// Assumes the original slice length is newLen - num
@@ -264,6 +266,8 @@ func growslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, et *_type) slice
p = mallocgc(capmem, nil, false)
// The append() that calls growslice is going to overwrite from oldLen to newLen.
// Only clear the part that will not be overwritten.
+ // The reflect_growslice() that calls growslice will manually clear
+ // the region not cleared here.
memclrNoHeapPointers(add(p, newlenmem), capmem-newlenmem)
} else {
// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory.
@@ -279,6 +283,25 @@ func growslice(oldPtr unsafe.Pointer, newLen, oldCap, num int, et *_type) slice
return slice{p, newLen, newcap}
}
+//go:linkname reflect_growslice reflect.growslice
+func reflect_growslice(et *_type, old slice, num int) slice {
+ // Semantically equivalent to slices.Grow, except that the caller
+ // is responsible for ensuring that old.len+num > old.cap.
+ num -= old.cap - old.len // preserve memory of old[old.len:old.cap]
+ new := growslice(old.array, old.cap+num, old.cap, num, et)
+ // growslice does not zero out new[old.cap:new.len] since it assumes that
+ // the memory will be overwritten by an append() that called growslice.
+ // Since the caller of reflect_growslice is not append(),
+ // zero out this region before returning the slice to the reflect package.
+ if et.ptrdata == 0 {
+ oldcapmem := uintptr(old.cap) * et.size
+ newlenmem := uintptr(new.len) * et.size
+ memclrNoHeapPointers(add(new.array, oldcapmem), newlenmem-oldcapmem)
+ }
+ new.len = old.len // preserve the old length
+ return new
+}
+
func isPowerOfTwo(x uintptr) bool {
return x&(x-1) == 0
}