diff options
-rw-r--r-- | loader/goroot.go | 1 | ||||
-rw-r--r-- | src/internal/gclayout/gclayout.go | 33 | ||||
-rw-r--r-- | src/reflect/type.go | 21 | ||||
-rw-r--r-- | src/reflect/value.go | 7 | ||||
-rw-r--r-- | src/runtime/slice.go | 9 | ||||
-rw-r--r-- | src/runtime/string.go | 9 |
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) |