mirror of
https://github.com/golang/go
synced 2024-11-23 20:30:04 -07:00
internal/unsafeheader: consolidate stringHeader and sliceHeader declarations into an internal package
The new package "internal/unsafeheader" depends only on "unsafe", and provides declarations equivalent to reflect.StringHeader and reflect.SliceHeader but with Data fields of the proper unsafe.Pointer type (instead of uintptr). Unlike the types it replaces, the "internal/unsafeheader" package has a regression test to ensure that its header types remain equivalent to the declarations provided by the "reflect" package. Since "internal/unsafeheader" has almost no dependencies, it can be used in other low-level packages such as "syscall" and "reflect". This change is based on the corresponding x/sys change in CL 231177. Fixes #37805 Updates #19367 Change-Id: I7a6d93ef8dd6e235bcab94e7c47270aad047af31 Reviewed-on: https://go-review.googlesource.com/c/go/+/231223 Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
4c78d54fdd
commit
da382a3978
1
src/cmd/dist/buildtool.go
vendored
1
src/cmd/dist/buildtool.go
vendored
@ -97,6 +97,7 @@ var bootstrapDirs = []string{
|
|||||||
"debug/pe",
|
"debug/pe",
|
||||||
"internal/goversion",
|
"internal/goversion",
|
||||||
"internal/race",
|
"internal/race",
|
||||||
|
"internal/unsafeheader",
|
||||||
"internal/xcoff",
|
"internal/xcoff",
|
||||||
"math/big",
|
"math/big",
|
||||||
"math/bits",
|
"math/bits",
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"internal/unsafeheader"
|
||||||
"io"
|
"io"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
@ -502,16 +503,15 @@ func (r *Reader) StringAt(off uint32, len uint32) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func toString(b []byte) string {
|
func toString(b []byte) string {
|
||||||
type stringHeader struct {
|
|
||||||
str unsafe.Pointer
|
|
||||||
len int
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(b) == 0 {
|
if len(b) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
ss := stringHeader{str: unsafe.Pointer(&b[0]), len: len(b)}
|
|
||||||
s := *(*string)(unsafe.Pointer(&ss))
|
var s string
|
||||||
|
hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
|
||||||
|
hdr.Data = unsafe.Pointer(&b[0])
|
||||||
|
hdr.Len = len(b)
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
"cmd/internal/sys"
|
"cmd/internal/sys"
|
||||||
"cmd/oldlink/internal/sym"
|
"cmd/oldlink/internal/sym"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"internal/unsafeheader"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
@ -595,17 +596,16 @@ func (r *objReader) readData() []byte {
|
|||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
type stringHeader struct {
|
|
||||||
str unsafe.Pointer
|
|
||||||
len int
|
|
||||||
}
|
|
||||||
|
|
||||||
func mkROString(rodata []byte) string {
|
func mkROString(rodata []byte) string {
|
||||||
if len(rodata) == 0 {
|
if len(rodata) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
ss := stringHeader{str: unsafe.Pointer(&rodata[0]), len: len(rodata)}
|
|
||||||
s := *(*string)(unsafe.Pointer(&ss))
|
var s string
|
||||||
|
hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
|
||||||
|
hdr.Data = unsafe.Pointer(&rodata[0])
|
||||||
|
hdr.Len = len(rodata)
|
||||||
|
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,7 +46,8 @@ var pkgDeps = map[string][]string{
|
|||||||
"unsafe": {},
|
"unsafe": {},
|
||||||
"internal/cpu": {},
|
"internal/cpu": {},
|
||||||
"internal/bytealg": {"unsafe", "internal/cpu"},
|
"internal/bytealg": {"unsafe", "internal/cpu"},
|
||||||
"internal/reflectlite": {"runtime", "unsafe"},
|
"internal/reflectlite": {"runtime", "unsafe", "internal/unsafeheader"},
|
||||||
|
"internal/unsafeheader": {"unsafe"},
|
||||||
|
|
||||||
"L0": {
|
"L0": {
|
||||||
"errors",
|
"errors",
|
||||||
@ -119,7 +120,7 @@ var pkgDeps = map[string][]string{
|
|||||||
"image/color": {"L2"}, // interfaces
|
"image/color": {"L2"}, // interfaces
|
||||||
"image/color/palette": {"L2", "image/color"},
|
"image/color/palette": {"L2", "image/color"},
|
||||||
"internal/fmtsort": {"reflect", "sort"},
|
"internal/fmtsort": {"reflect", "sort"},
|
||||||
"reflect": {"L2"},
|
"reflect": {"L2", "internal/unsafeheader"},
|
||||||
"sort": {"internal/reflectlite"},
|
"sort": {"internal/reflectlite"},
|
||||||
|
|
||||||
"L3": {
|
"L3": {
|
||||||
@ -147,7 +148,7 @@ var pkgDeps = map[string][]string{
|
|||||||
// End of linear dependency definitions.
|
// End of linear dependency definitions.
|
||||||
|
|
||||||
// Operating system access.
|
// Operating system access.
|
||||||
"syscall": {"L0", "internal/oserror", "internal/race", "internal/syscall/windows/sysdll", "syscall/js", "unicode/utf16"},
|
"syscall": {"L0", "internal/oserror", "internal/race", "internal/syscall/windows/sysdll", "internal/unsafeheader", "syscall/js", "unicode/utf16"},
|
||||||
"syscall/js": {"L0"},
|
"syscall/js": {"L0"},
|
||||||
"internal/oserror": {"L0"},
|
"internal/oserror": {"L0"},
|
||||||
"internal/syscall/unix": {"L0", "syscall"},
|
"internal/syscall/unix": {"L0", "syscall"},
|
||||||
|
@ -4,7 +4,10 @@
|
|||||||
|
|
||||||
package reflectlite
|
package reflectlite
|
||||||
|
|
||||||
import "unsafe"
|
import (
|
||||||
|
"internal/unsafeheader"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
// Swapper returns a function that swaps the elements in the provided
|
// Swapper returns a function that swaps the elements in the provided
|
||||||
// slice.
|
// slice.
|
||||||
@ -58,7 +61,7 @@ func Swapper(slice interface{}) func(i, j int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s := (*sliceHeader)(v.ptr)
|
s := (*unsafeheader.Slice)(v.ptr)
|
||||||
tmp := unsafe_New(typ) // swap scratch space
|
tmp := unsafe_New(typ) // swap scratch space
|
||||||
|
|
||||||
return func(i, j int) {
|
return func(i, j int) {
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
package reflectlite
|
package reflectlite
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"internal/unsafeheader"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -338,7 +339,7 @@ func (n name) name() (s string) {
|
|||||||
}
|
}
|
||||||
b := (*[4]byte)(unsafe.Pointer(n.bytes))
|
b := (*[4]byte)(unsafe.Pointer(n.bytes))
|
||||||
|
|
||||||
hdr := (*stringHeader)(unsafe.Pointer(&s))
|
hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
|
||||||
hdr.Data = unsafe.Pointer(&b[3])
|
hdr.Data = unsafe.Pointer(&b[3])
|
||||||
hdr.Len = int(b[1])<<8 | int(b[2])
|
hdr.Len = int(b[1])<<8 | int(b[2])
|
||||||
return s
|
return s
|
||||||
@ -350,7 +351,7 @@ func (n name) tag() (s string) {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
nl := n.nameLen()
|
nl := n.nameLen()
|
||||||
hdr := (*stringHeader)(unsafe.Pointer(&s))
|
hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
|
||||||
hdr.Data = unsafe.Pointer(n.data(3+nl+2, "non-empty string"))
|
hdr.Data = unsafe.Pointer(n.data(3+nl+2, "non-empty string"))
|
||||||
hdr.Len = tl
|
hdr.Len = tl
|
||||||
return s
|
return s
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package reflectlite
|
package reflectlite
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"internal/unsafeheader"
|
||||||
"runtime"
|
"runtime"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
@ -335,10 +336,10 @@ func (v Value) Len() int {
|
|||||||
return maplen(v.pointer())
|
return maplen(v.pointer())
|
||||||
case Slice:
|
case Slice:
|
||||||
// Slice is bigger than a word; assume flagIndir.
|
// Slice is bigger than a word; assume flagIndir.
|
||||||
return (*sliceHeader)(v.ptr).Len
|
return (*unsafeheader.Slice)(v.ptr).Len
|
||||||
case String:
|
case String:
|
||||||
// String is bigger than a word; assume flagIndir.
|
// String is bigger than a word; assume flagIndir.
|
||||||
return (*stringHeader)(v.ptr).Len
|
return (*unsafeheader.String)(v.ptr).Len
|
||||||
}
|
}
|
||||||
panic(&ValueError{"reflect.Value.Len", v.kind()})
|
panic(&ValueError{"reflect.Value.Len", v.kind()})
|
||||||
}
|
}
|
||||||
@ -379,19 +380,6 @@ func (v Value) Type() Type {
|
|||||||
return v.typ
|
return v.typ
|
||||||
}
|
}
|
||||||
|
|
||||||
// stringHeader is a safe version of StringHeader used within this package.
|
|
||||||
type stringHeader struct {
|
|
||||||
Data unsafe.Pointer
|
|
||||||
Len int
|
|
||||||
}
|
|
||||||
|
|
||||||
// sliceHeader is a safe version of SliceHeader used within this package.
|
|
||||||
type sliceHeader struct {
|
|
||||||
Data unsafe.Pointer
|
|
||||||
Len int
|
|
||||||
Cap int
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* constructors
|
* constructors
|
||||||
*/
|
*/
|
||||||
|
37
src/internal/unsafeheader/unsafeheader.go
Normal file
37
src/internal/unsafeheader/unsafeheader.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2020 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 unsafeheader contains header declarations for the Go runtime's slice
|
||||||
|
// and string implementations.
|
||||||
|
//
|
||||||
|
// This package allows packages that cannot import "reflect" to use types that
|
||||||
|
// are tested to be equivalent to reflect.SliceHeader and reflect.StringHeader.
|
||||||
|
package unsafeheader
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Slice is the runtime representation of a slice.
|
||||||
|
// It cannot be used safely or portably and its representation may
|
||||||
|
// change in a later release.
|
||||||
|
//
|
||||||
|
// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the
|
||||||
|
// data it references will not be garbage collected.
|
||||||
|
type Slice struct {
|
||||||
|
Data unsafe.Pointer
|
||||||
|
Len int
|
||||||
|
Cap int
|
||||||
|
}
|
||||||
|
|
||||||
|
// String is the runtime representation of a string.
|
||||||
|
// It cannot be used safely or portably and its representation may
|
||||||
|
// change in a later release.
|
||||||
|
//
|
||||||
|
// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the
|
||||||
|
// data it references will not be garbage collected.
|
||||||
|
type String struct {
|
||||||
|
Data unsafe.Pointer
|
||||||
|
Len int
|
||||||
|
}
|
100
src/internal/unsafeheader/unsafeheader_test.go
Normal file
100
src/internal/unsafeheader/unsafeheader_test.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
// Copyright 2020 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 unsafeheader_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"internal/unsafeheader"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestTypeMatchesReflectType ensures that the name and layout of the
|
||||||
|
// unsafeheader types matches the corresponding Header types in the reflect
|
||||||
|
// package.
|
||||||
|
func TestTypeMatchesReflectType(t *testing.T) {
|
||||||
|
t.Run("Slice", func(t *testing.T) {
|
||||||
|
testHeaderMatchesReflect(t, unsafeheader.Slice{}, reflect.SliceHeader{})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("String", func(t *testing.T) {
|
||||||
|
testHeaderMatchesReflect(t, unsafeheader.String{}, reflect.StringHeader{})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testHeaderMatchesReflect(t *testing.T, header, reflectHeader interface{}) {
|
||||||
|
h := reflect.TypeOf(header)
|
||||||
|
rh := reflect.TypeOf(reflectHeader)
|
||||||
|
|
||||||
|
for i := 0; i < h.NumField(); i++ {
|
||||||
|
f := h.Field(i)
|
||||||
|
rf, ok := rh.FieldByName(f.Name)
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("Field %d of %v is named %s, but no such field exists in %v", i, h, f.Name, rh)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !typeCompatible(f.Type, rf.Type) {
|
||||||
|
t.Errorf("%v.%s has type %v, but %v.%s has type %v", h, f.Name, f.Type, rh, rf.Name, rf.Type)
|
||||||
|
}
|
||||||
|
if f.Offset != rf.Offset {
|
||||||
|
t.Errorf("%v.%s has offset %d, but %v.%s has offset %d", h, f.Name, f.Offset, rh, rf.Name, rf.Offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if h.NumField() != rh.NumField() {
|
||||||
|
t.Errorf("%v has %d fields, but %v has %d", h, h.NumField(), rh, rh.NumField())
|
||||||
|
}
|
||||||
|
if h.Align() != rh.Align() {
|
||||||
|
t.Errorf("%v has alignment %d, but %v has alignment %d", h, h.Align(), rh, rh.Align())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
unsafePointerType = reflect.TypeOf(unsafe.Pointer(nil))
|
||||||
|
uintptrType = reflect.TypeOf(uintptr(0))
|
||||||
|
)
|
||||||
|
|
||||||
|
func typeCompatible(t, rt reflect.Type) bool {
|
||||||
|
return t == rt || (t == unsafePointerType && rt == uintptrType)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestWriteThroughHeader ensures that the headers in the unsafeheader package
|
||||||
|
// can successfully mutate variables of the corresponding built-in types.
|
||||||
|
//
|
||||||
|
// This test is expected to fail under -race (which implicitly enables
|
||||||
|
// -d=checkptr) if the runtime views the header types as incompatible with the
|
||||||
|
// underlying built-in types.
|
||||||
|
func TestWriteThroughHeader(t *testing.T) {
|
||||||
|
t.Run("Slice", func(t *testing.T) {
|
||||||
|
s := []byte("Hello, checkptr!")[:5]
|
||||||
|
|
||||||
|
var alias []byte
|
||||||
|
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&alias))
|
||||||
|
hdr.Data = unsafe.Pointer(&s[0])
|
||||||
|
hdr.Cap = cap(s)
|
||||||
|
hdr.Len = len(s)
|
||||||
|
|
||||||
|
if !bytes.Equal(alias, s) {
|
||||||
|
t.Errorf("alias of %T(%q) constructed via Slice = %T(%q)", s, s, alias, alias)
|
||||||
|
}
|
||||||
|
if cap(alias) != cap(s) {
|
||||||
|
t.Errorf("alias of %T with cap %d has cap %d", s, cap(s), cap(alias))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("String", func(t *testing.T) {
|
||||||
|
s := "Hello, checkptr!"
|
||||||
|
|
||||||
|
var alias string
|
||||||
|
hdr := (*unsafeheader.String)(unsafe.Pointer(&alias))
|
||||||
|
hdr.Data = (*unsafeheader.String)(unsafe.Pointer(&s)).Data
|
||||||
|
hdr.Len = len(s)
|
||||||
|
|
||||||
|
if alias != s {
|
||||||
|
t.Errorf("alias of %q constructed via String = %q", s, alias)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -4,7 +4,10 @@
|
|||||||
|
|
||||||
package reflect
|
package reflect
|
||||||
|
|
||||||
import "unsafe"
|
import (
|
||||||
|
"internal/unsafeheader"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
// Swapper returns a function that swaps the elements in the provided
|
// Swapper returns a function that swaps the elements in the provided
|
||||||
// slice.
|
// slice.
|
||||||
@ -58,7 +61,7 @@ func Swapper(slice interface{}) func(i, j int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s := (*sliceHeader)(v.ptr)
|
s := (*unsafeheader.Slice)(v.ptr)
|
||||||
tmp := unsafe_New(typ) // swap scratch space
|
tmp := unsafe_New(typ) // swap scratch space
|
||||||
|
|
||||||
return func(i, j int) {
|
return func(i, j int) {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
package reflect
|
package reflect
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"internal/unsafeheader"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"unicode"
|
"unicode"
|
||||||
@ -490,7 +491,7 @@ func (n name) name() (s string) {
|
|||||||
}
|
}
|
||||||
b := (*[4]byte)(unsafe.Pointer(n.bytes))
|
b := (*[4]byte)(unsafe.Pointer(n.bytes))
|
||||||
|
|
||||||
hdr := (*stringHeader)(unsafe.Pointer(&s))
|
hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
|
||||||
hdr.Data = unsafe.Pointer(&b[3])
|
hdr.Data = unsafe.Pointer(&b[3])
|
||||||
hdr.Len = int(b[1])<<8 | int(b[2])
|
hdr.Len = int(b[1])<<8 | int(b[2])
|
||||||
return s
|
return s
|
||||||
@ -502,7 +503,7 @@ func (n name) tag() (s string) {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
nl := n.nameLen()
|
nl := n.nameLen()
|
||||||
hdr := (*stringHeader)(unsafe.Pointer(&s))
|
hdr := (*unsafeheader.String)(unsafe.Pointer(&s))
|
||||||
hdr.Data = unsafe.Pointer(n.data(3+nl+2, "non-empty string"))
|
hdr.Data = unsafe.Pointer(n.data(3+nl+2, "non-empty string"))
|
||||||
hdr.Len = tl
|
hdr.Len = tl
|
||||||
return s
|
return s
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package reflect
|
package reflect
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"internal/unsafeheader"
|
||||||
"math"
|
"math"
|
||||||
"runtime"
|
"runtime"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
@ -766,7 +767,7 @@ func (v Value) Cap() int {
|
|||||||
return chancap(v.pointer())
|
return chancap(v.pointer())
|
||||||
case Slice:
|
case Slice:
|
||||||
// Slice is always bigger than a word; assume flagIndir.
|
// Slice is always bigger than a word; assume flagIndir.
|
||||||
return (*sliceHeader)(v.ptr).Cap
|
return (*unsafeheader.Slice)(v.ptr).Cap
|
||||||
}
|
}
|
||||||
panic(&ValueError{"reflect.Value.Cap", v.kind()})
|
panic(&ValueError{"reflect.Value.Cap", v.kind()})
|
||||||
}
|
}
|
||||||
@ -945,7 +946,7 @@ func (v Value) Index(i int) Value {
|
|||||||
case Slice:
|
case Slice:
|
||||||
// Element flag same as Elem of Ptr.
|
// Element flag same as Elem of Ptr.
|
||||||
// Addressable, indirect, possibly read-only.
|
// Addressable, indirect, possibly read-only.
|
||||||
s := (*sliceHeader)(v.ptr)
|
s := (*unsafeheader.Slice)(v.ptr)
|
||||||
if uint(i) >= uint(s.Len) {
|
if uint(i) >= uint(s.Len) {
|
||||||
panic("reflect: slice index out of range")
|
panic("reflect: slice index out of range")
|
||||||
}
|
}
|
||||||
@ -956,7 +957,7 @@ func (v Value) Index(i int) Value {
|
|||||||
return Value{typ, val, fl}
|
return Value{typ, val, fl}
|
||||||
|
|
||||||
case String:
|
case String:
|
||||||
s := (*stringHeader)(v.ptr)
|
s := (*unsafeheader.String)(v.ptr)
|
||||||
if uint(i) >= uint(s.Len) {
|
if uint(i) >= uint(s.Len) {
|
||||||
panic("reflect: string index out of range")
|
panic("reflect: string index out of range")
|
||||||
}
|
}
|
||||||
@ -1143,10 +1144,10 @@ func (v Value) Len() int {
|
|||||||
return maplen(v.pointer())
|
return maplen(v.pointer())
|
||||||
case Slice:
|
case Slice:
|
||||||
// Slice is bigger than a word; assume flagIndir.
|
// Slice is bigger than a word; assume flagIndir.
|
||||||
return (*sliceHeader)(v.ptr).Len
|
return (*unsafeheader.Slice)(v.ptr).Len
|
||||||
case String:
|
case String:
|
||||||
// String is bigger than a word; assume flagIndir.
|
// String is bigger than a word; assume flagIndir.
|
||||||
return (*stringHeader)(v.ptr).Len
|
return (*unsafeheader.String)(v.ptr).Len
|
||||||
}
|
}
|
||||||
panic(&ValueError{"reflect.Value.Len", v.kind()})
|
panic(&ValueError{"reflect.Value.Len", v.kind()})
|
||||||
}
|
}
|
||||||
@ -1632,7 +1633,7 @@ func (v Value) SetInt(x int64) {
|
|||||||
func (v Value) SetLen(n int) {
|
func (v Value) SetLen(n int) {
|
||||||
v.mustBeAssignable()
|
v.mustBeAssignable()
|
||||||
v.mustBe(Slice)
|
v.mustBe(Slice)
|
||||||
s := (*sliceHeader)(v.ptr)
|
s := (*unsafeheader.Slice)(v.ptr)
|
||||||
if uint(n) > uint(s.Cap) {
|
if uint(n) > uint(s.Cap) {
|
||||||
panic("reflect: slice length out of range in SetLen")
|
panic("reflect: slice length out of range in SetLen")
|
||||||
}
|
}
|
||||||
@ -1645,7 +1646,7 @@ func (v Value) SetLen(n int) {
|
|||||||
func (v Value) SetCap(n int) {
|
func (v Value) SetCap(n int) {
|
||||||
v.mustBeAssignable()
|
v.mustBeAssignable()
|
||||||
v.mustBe(Slice)
|
v.mustBe(Slice)
|
||||||
s := (*sliceHeader)(v.ptr)
|
s := (*unsafeheader.Slice)(v.ptr)
|
||||||
if n < s.Len || n > s.Cap {
|
if n < s.Len || n > s.Cap {
|
||||||
panic("reflect: slice capacity out of range in SetCap")
|
panic("reflect: slice capacity out of range in SetCap")
|
||||||
}
|
}
|
||||||
@ -1747,18 +1748,18 @@ func (v Value) Slice(i, j int) Value {
|
|||||||
|
|
||||||
case Slice:
|
case Slice:
|
||||||
typ = (*sliceType)(unsafe.Pointer(v.typ))
|
typ = (*sliceType)(unsafe.Pointer(v.typ))
|
||||||
s := (*sliceHeader)(v.ptr)
|
s := (*unsafeheader.Slice)(v.ptr)
|
||||||
base = s.Data
|
base = s.Data
|
||||||
cap = s.Cap
|
cap = s.Cap
|
||||||
|
|
||||||
case String:
|
case String:
|
||||||
s := (*stringHeader)(v.ptr)
|
s := (*unsafeheader.String)(v.ptr)
|
||||||
if i < 0 || j < i || j > s.Len {
|
if i < 0 || j < i || j > s.Len {
|
||||||
panic("reflect.Value.Slice: string slice index out of bounds")
|
panic("reflect.Value.Slice: string slice index out of bounds")
|
||||||
}
|
}
|
||||||
var t stringHeader
|
var t unsafeheader.String
|
||||||
if i < s.Len {
|
if i < s.Len {
|
||||||
t = stringHeader{arrayAt(s.Data, i, 1, "i < s.Len"), j - i}
|
t = unsafeheader.String{Data: arrayAt(s.Data, i, 1, "i < s.Len"), Len: j - i}
|
||||||
}
|
}
|
||||||
return Value{v.typ, unsafe.Pointer(&t), v.flag}
|
return Value{v.typ, unsafe.Pointer(&t), v.flag}
|
||||||
}
|
}
|
||||||
@ -1770,8 +1771,8 @@ func (v Value) Slice(i, j int) Value {
|
|||||||
// Declare slice so that gc can see the base pointer in it.
|
// Declare slice so that gc can see the base pointer in it.
|
||||||
var x []unsafe.Pointer
|
var x []unsafe.Pointer
|
||||||
|
|
||||||
// Reinterpret as *sliceHeader to edit.
|
// Reinterpret as *unsafeheader.Slice to edit.
|
||||||
s := (*sliceHeader)(unsafe.Pointer(&x))
|
s := (*unsafeheader.Slice)(unsafe.Pointer(&x))
|
||||||
s.Len = j - i
|
s.Len = j - i
|
||||||
s.Cap = cap - i
|
s.Cap = cap - i
|
||||||
if cap-i > 0 {
|
if cap-i > 0 {
|
||||||
@ -1809,7 +1810,7 @@ func (v Value) Slice3(i, j, k int) Value {
|
|||||||
|
|
||||||
case Slice:
|
case Slice:
|
||||||
typ = (*sliceType)(unsafe.Pointer(v.typ))
|
typ = (*sliceType)(unsafe.Pointer(v.typ))
|
||||||
s := (*sliceHeader)(v.ptr)
|
s := (*unsafeheader.Slice)(v.ptr)
|
||||||
base = s.Data
|
base = s.Data
|
||||||
cap = s.Cap
|
cap = s.Cap
|
||||||
}
|
}
|
||||||
@ -1822,8 +1823,8 @@ func (v Value) Slice3(i, j, k int) Value {
|
|||||||
// can see the base pointer in it.
|
// can see the base pointer in it.
|
||||||
var x []unsafe.Pointer
|
var x []unsafe.Pointer
|
||||||
|
|
||||||
// Reinterpret as *sliceHeader to edit.
|
// Reinterpret as *unsafeheader.Slice to edit.
|
||||||
s := (*sliceHeader)(unsafe.Pointer(&x))
|
s := (*unsafeheader.Slice)(unsafe.Pointer(&x))
|
||||||
s.Len = j - i
|
s.Len = j - i
|
||||||
s.Cap = k - i
|
s.Cap = k - i
|
||||||
if k-i > 0 {
|
if k-i > 0 {
|
||||||
@ -1960,12 +1961,6 @@ type StringHeader struct {
|
|||||||
Len int
|
Len int
|
||||||
}
|
}
|
||||||
|
|
||||||
// stringHeader is a safe version of StringHeader used within this package.
|
|
||||||
type stringHeader struct {
|
|
||||||
Data unsafe.Pointer
|
|
||||||
Len int
|
|
||||||
}
|
|
||||||
|
|
||||||
// SliceHeader is the runtime representation of a slice.
|
// SliceHeader is the runtime representation of a slice.
|
||||||
// It cannot be used safely or portably and its representation may
|
// It cannot be used safely or portably and its representation may
|
||||||
// change in a later release.
|
// change in a later release.
|
||||||
@ -1978,13 +1973,6 @@ type SliceHeader struct {
|
|||||||
Cap int
|
Cap int
|
||||||
}
|
}
|
||||||
|
|
||||||
// sliceHeader is a safe version of SliceHeader used within this package.
|
|
||||||
type sliceHeader struct {
|
|
||||||
Data unsafe.Pointer
|
|
||||||
Len int
|
|
||||||
Cap int
|
|
||||||
}
|
|
||||||
|
|
||||||
func typesMustMatch(what string, t1, t2 Type) {
|
func typesMustMatch(what string, t1, t2 Type) {
|
||||||
if t1 != t2 {
|
if t1 != t2 {
|
||||||
panic(what + ": " + t1.String() + " != " + t2.String())
|
panic(what + ": " + t1.String() + " != " + t2.String())
|
||||||
@ -2085,22 +2073,22 @@ func Copy(dst, src Value) int {
|
|||||||
typesMustMatch("reflect.Copy", de, se)
|
typesMustMatch("reflect.Copy", de, se)
|
||||||
}
|
}
|
||||||
|
|
||||||
var ds, ss sliceHeader
|
var ds, ss unsafeheader.Slice
|
||||||
if dk == Array {
|
if dk == Array {
|
||||||
ds.Data = dst.ptr
|
ds.Data = dst.ptr
|
||||||
ds.Len = dst.Len()
|
ds.Len = dst.Len()
|
||||||
ds.Cap = ds.Len
|
ds.Cap = ds.Len
|
||||||
} else {
|
} else {
|
||||||
ds = *(*sliceHeader)(dst.ptr)
|
ds = *(*unsafeheader.Slice)(dst.ptr)
|
||||||
}
|
}
|
||||||
if sk == Array {
|
if sk == Array {
|
||||||
ss.Data = src.ptr
|
ss.Data = src.ptr
|
||||||
ss.Len = src.Len()
|
ss.Len = src.Len()
|
||||||
ss.Cap = ss.Len
|
ss.Cap = ss.Len
|
||||||
} else if sk == Slice {
|
} else if sk == Slice {
|
||||||
ss = *(*sliceHeader)(src.ptr)
|
ss = *(*unsafeheader.Slice)(src.ptr)
|
||||||
} else {
|
} else {
|
||||||
sh := *(*stringHeader)(src.ptr)
|
sh := *(*unsafeheader.String)(src.ptr)
|
||||||
ss.Data = sh.Data
|
ss.Data = sh.Data
|
||||||
ss.Len = sh.Len
|
ss.Len = sh.Len
|
||||||
ss.Cap = sh.Len
|
ss.Cap = sh.Len
|
||||||
@ -2288,7 +2276,7 @@ func MakeSlice(typ Type, len, cap int) Value {
|
|||||||
panic("reflect.MakeSlice: len > cap")
|
panic("reflect.MakeSlice: len > cap")
|
||||||
}
|
}
|
||||||
|
|
||||||
s := sliceHeader{unsafe_NewArray(typ.Elem().(*rtype), cap), len, cap}
|
s := unsafeheader.Slice{Data: unsafe_NewArray(typ.Elem().(*rtype), cap), Len: len, Cap: cap}
|
||||||
return Value{typ.(*rtype), unsafe.Pointer(&s), flagIndir | flag(Slice)}
|
return Value{typ.(*rtype), unsafe.Pointer(&s), flagIndir | flag(Slice)}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2805,7 +2793,7 @@ func typedmemclrpartial(t *rtype, ptr unsafe.Pointer, off, size uintptr)
|
|||||||
// typedslicecopy copies a slice of elemType values from src to dst,
|
// typedslicecopy copies a slice of elemType values from src to dst,
|
||||||
// returning the number of elements copied.
|
// returning the number of elements copied.
|
||||||
//go:noescape
|
//go:noescape
|
||||||
func typedslicecopy(elemType *rtype, dst, src sliceHeader) int
|
func typedslicecopy(elemType *rtype, dst, src unsafeheader.Slice) int
|
||||||
|
|
||||||
//go:noescape
|
//go:noescape
|
||||||
func typehash(t *rtype, p unsafe.Pointer, h uintptr) uintptr
|
func typehash(t *rtype, p unsafe.Pointer, h uintptr) uintptr
|
||||||
|
@ -9,6 +9,7 @@ package syscall
|
|||||||
import (
|
import (
|
||||||
"internal/oserror"
|
"internal/oserror"
|
||||||
"internal/race"
|
"internal/race"
|
||||||
|
"internal/unsafeheader"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
@ -60,15 +61,12 @@ func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (d
|
|||||||
return nil, errno
|
return nil, errno
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slice memory layout
|
// Use unsafe to turn addr into a []byte.
|
||||||
var sl = struct {
|
var b []byte
|
||||||
addr uintptr
|
hdr := (*unsafeheader.Slice)(unsafe.Pointer(&b))
|
||||||
len int
|
hdr.Data = unsafe.Pointer(addr)
|
||||||
cap int
|
hdr.Cap = length
|
||||||
}{addr, length, length}
|
hdr.Len = length
|
||||||
|
|
||||||
// Use unsafe to turn sl into a []byte.
|
|
||||||
b := *(*[]byte)(unsafe.Pointer(&sl))
|
|
||||||
|
|
||||||
// Register mapping in m and return it.
|
// Register mapping in m and return it.
|
||||||
p := &b[cap(b)-1]
|
p := &b[cap(b)-1]
|
||||||
|
Loading…
Reference in New Issue
Block a user