aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--loader/goroot.go1
-rw-r--r--src/internal/gclayout/gclayout.go33
-rw-r--r--src/reflect/type.go21
-rw-r--r--src/reflect/value.go7
-rw-r--r--src/runtime/slice.go9
-rw-r--r--src/runtime/string.go9
6 files changed, 73 insertions, 7 deletions
diff --git a/loader/goroot.go b/loader/goroot.go
index 05eeeda19..20fee016b 100644
--- a/loader/goroot.go
+++ b/loader/goroot.go
@@ -245,6 +245,7 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
"internal/cm/": false,
"internal/fuzz/": false,
"internal/reflectlite/": false,
+ "internal/gclayout": false,
"internal/task/": false,
"internal/wasi/": false,
"machine/": false,
diff --git a/src/internal/gclayout/gclayout.go b/src/internal/gclayout/gclayout.go
new file mode 100644
index 000000000..aa841d804
--- /dev/null
+++ b/src/internal/gclayout/gclayout.go
@@ -0,0 +1,33 @@
+package gclayout
+
+import "unsafe"
+
+// Internal constants for gc layout
+// See runtime/gc_precise.go
+
+var (
+ NoPtrs unsafe.Pointer
+ Pointer unsafe.Pointer
+ String unsafe.Pointer
+ Slice unsafe.Pointer
+)
+
+func init() {
+ var sizeBits uintptr
+
+ switch unsafe.Sizeof(uintptr(0)) {
+ case 8:
+ sizeBits = 6
+ case 4:
+ sizeBits = 5
+ case 2:
+ sizeBits = 4
+ }
+
+ var sizeShift = sizeBits + 1
+
+ NoPtrs = unsafe.Pointer(uintptr(0b0<<sizeShift) | uintptr(0b1<<1) | uintptr(1))
+ Pointer = unsafe.Pointer(uintptr(0b1<<sizeShift) | uintptr(0b1<<1) | uintptr(1))
+ String = unsafe.Pointer(uintptr(0b01<<sizeShift) | uintptr(0b10<<1) | uintptr(1))
+ Slice = unsafe.Pointer(uintptr(0b001<<sizeShift) | uintptr(0b11<<1) | uintptr(1))
+}
diff --git a/src/reflect/type.go b/src/reflect/type.go
index 5dd59b329..b18a1a9d4 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -64,6 +64,7 @@
package reflect
import (
+ "internal/gclayout"
"internal/itoa"
"unsafe"
)
@@ -961,6 +962,26 @@ func (t *rawType) Align() int {
}
}
+func (r *rawType) gcLayout() unsafe.Pointer {
+ kind := r.Kind()
+
+ if kind < String {
+ return gclayout.NoPtrs
+ }
+
+ switch kind {
+ case Pointer, UnsafePointer, Chan, Map:
+ return gclayout.Pointer
+ case String:
+ return gclayout.String
+ case Slice:
+ return gclayout.Slice
+ }
+
+ // Unknown (for now); let the conservative pointer scanning handle it
+ return nil
+}
+
// FieldAlign returns the alignment if this type is used in a struct field. It
// is currently an alias for Align() but this might change in the future.
func (t *rawType) FieldAlign() int {
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 15a900f9e..d1f8cb2f7 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -1479,7 +1479,8 @@ func MakeSlice(typ Type, len, cap int) Value {
ulen := uint(len)
ucap := uint(cap)
maxSize := (^uintptr(0)) / 2
- elementSize := rtype.elem().Size()
+ elem := rtype.elem()
+ elementSize := elem.Size()
if elementSize > 1 {
maxSize /= uintptr(elementSize)
}
@@ -1493,7 +1494,9 @@ func MakeSlice(typ Type, len, cap int) Value {
var slice sliceHeader
slice.cap = uintptr(ucap)
slice.len = uintptr(ulen)
- slice.data = alloc(size, nil)
+ layout := elem.gcLayout()
+
+ slice.data = alloc(size, layout)
return Value{
typecode: rtype,
diff --git a/src/runtime/slice.go b/src/runtime/slice.go
index 7d804b11b..c9603643a 100644
--- a/src/runtime/slice.go
+++ b/src/runtime/slice.go
@@ -3,6 +3,7 @@ package runtime
// This file implements compiler builtins for slices: append() and copy().
import (
+ "internal/gclayout"
"math/bits"
"unsafe"
)
@@ -47,7 +48,13 @@ func sliceGrow(oldBuf unsafe.Pointer, oldLen, oldCap, newCap, elemSize uintptr)
// memory allocators, this causes some difficult to debug issues.
newCap = 1 << bits.Len(uint(newCap))
- buf := alloc(newCap*elemSize, nil)
+ var layout unsafe.Pointer
+ // less type info here; can only go off element size
+ if elemSize < unsafe.Sizeof(uintptr(0)) {
+ layout = gclayout.NoPtrs
+ }
+
+ buf := alloc(newCap*elemSize, layout)
if oldLen > 0 {
// copy any data to new slice
memmove(buf, oldBuf, oldLen*elemSize)
diff --git a/src/runtime/string.go b/src/runtime/string.go
index aeefe1d4f..54485dfc2 100644
--- a/src/runtime/string.go
+++ b/src/runtime/string.go
@@ -3,6 +3,7 @@ package runtime
// This file implements functions related to Go strings.
import (
+ "internal/gclayout"
"unsafe"
)
@@ -59,7 +60,7 @@ func stringConcat(x, y _string) _string {
return x
} else {
length := x.length + y.length
- buf := alloc(length, nil)
+ buf := alloc(length, gclayout.NoPtrs)
memcpy(buf, unsafe.Pointer(x.ptr), x.length)
memcpy(unsafe.Add(buf, x.length), unsafe.Pointer(y.ptr), y.length)
return _string{ptr: (*byte)(buf), length: length}
@@ -72,7 +73,7 @@ func stringFromBytes(x struct {
len uintptr
cap uintptr
}) _string {
- buf := alloc(x.len, nil)
+ buf := alloc(x.len, gclayout.NoPtrs)
memcpy(buf, unsafe.Pointer(x.ptr), x.len)
return _string{ptr: (*byte)(buf), length: x.len}
}
@@ -83,7 +84,7 @@ func stringToBytes(x _string) (slice struct {
len uintptr
cap uintptr
}) {
- buf := alloc(x.length, nil)
+ buf := alloc(x.length, gclayout.NoPtrs)
memcpy(buf, unsafe.Pointer(x.ptr), x.length)
slice.ptr = (*byte)(buf)
slice.len = x.length
@@ -100,7 +101,7 @@ func stringFromRunes(runeSlice []rune) (s _string) {
}
// Allocate memory for the string.
- s.ptr = (*byte)(alloc(s.length, nil))
+ s.ptr = (*byte)(alloc(s.length, gclayout.NoPtrs))
// Encode runes to UTF-8 and store the resulting bytes in the string.
index := uintptr(0)