You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
weishi/vendor/github.com/ugorji/go/codec/helper_unsafe_compiler_gc.go

172 lines
5.5 KiB

// Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved.
// Use of this source code is governed by a MIT license found in the LICENSE file.
//go:build !safe && !codec.safe && !appengine && go1.9 && gc
// +build !safe,!codec.safe,!appengine,go1.9,gc
package codec
import (
"reflect"
_ "runtime" // needed for go linkname(s)
"unsafe"
)
// keep in sync with
// $GOROOT/src/cmd/compile/internal/gc/reflect.go: MAXKEYSIZE, MAXELEMSIZE
// $GOROOT/src/runtime/map.go: maxKeySize, maxElemSize
// $GOROOT/src/reflect/type.go: maxKeySize, maxElemSize
//
// We use these to determine whether the type is stored indirectly in the map or not.
const (
// mapMaxKeySize = 128
mapMaxElemSize = 128
)
func unsafeGrowslice(typ unsafe.Pointer, old unsafeSlice, cap, incr int) (v unsafeSlice) {
return growslice(typ, old, cap+incr)
}
func rvType(rv reflect.Value) reflect.Type {
return rvPtrToType(((*unsafeReflectValue)(unsafe.Pointer(&rv))).typ) // rv.Type()
}
// mapStoresElemIndirect tells if the element type is stored indirectly in the map.
//
// This is used to determine valIsIndirect which is passed into mapSet/mapGet calls.
//
// If valIsIndirect doesn't matter, then just return false and ignore the value
// passed in mapGet/mapSet calls
func mapStoresElemIndirect(elemsize uintptr) bool {
return elemsize > mapMaxElemSize
}
func mapSet(m, k, v reflect.Value, keyFastKind mapKeyFastKind, valIsIndirect, valIsRef bool) {
var urv = (*unsafeReflectValue)(unsafe.Pointer(&k))
var kptr = unsafeMapKVPtr(urv)
urv = (*unsafeReflectValue)(unsafe.Pointer(&v))
var vtyp = urv.typ
var vptr = unsafeMapKVPtr(urv)
urv = (*unsafeReflectValue)(unsafe.Pointer(&m))
mptr := rvRefPtr(urv)
var vvptr unsafe.Pointer
// mapassign_fastXXX don't take indirect into account.
// It was hard to infer what makes it work all the time.
// Sometimes, we got vvptr == nil when we dereferenced vvptr (if valIsIndirect).
// Consequently, only use fastXXX functions if !valIsIndirect
if valIsIndirect {
vvptr = mapassign(urv.typ, mptr, kptr)
typedmemmove(vtyp, vvptr, vptr)
// reflect_mapassign(urv.typ, mptr, kptr, vptr)
return
}
switch keyFastKind {
case mapKeyFastKind32:
vvptr = mapassign_fast32(urv.typ, mptr, *(*uint32)(kptr))
case mapKeyFastKind32ptr:
vvptr = mapassign_fast32ptr(urv.typ, mptr, *(*unsafe.Pointer)(kptr))
case mapKeyFastKind64:
vvptr = mapassign_fast64(urv.typ, mptr, *(*uint64)(kptr))
case mapKeyFastKind64ptr:
vvptr = mapassign_fast64ptr(urv.typ, mptr, *(*unsafe.Pointer)(kptr))
case mapKeyFastKindStr:
vvptr = mapassign_faststr(urv.typ, mptr, *(*string)(kptr))
default:
vvptr = mapassign(urv.typ, mptr, kptr)
}
// if keyFastKind != 0 && valIsIndirect {
// vvptr = *(*unsafe.Pointer)(vvptr)
// }
typedmemmove(vtyp, vvptr, vptr)
}
func mapGet(m, k, v reflect.Value, keyFastKind mapKeyFastKind, valIsIndirect, valIsRef bool) (_ reflect.Value) {
var urv = (*unsafeReflectValue)(unsafe.Pointer(&k))
var kptr = unsafeMapKVPtr(urv)
urv = (*unsafeReflectValue)(unsafe.Pointer(&m))
mptr := rvRefPtr(urv)
var vvptr unsafe.Pointer
var ok bool
// Note that mapaccess2_fastXXX functions do not check if the value needs to be copied.
// if they do, we should dereference the pointer and return that
switch keyFastKind {
case mapKeyFastKind32, mapKeyFastKind32ptr:
vvptr, ok = mapaccess2_fast32(urv.typ, mptr, *(*uint32)(kptr))
case mapKeyFastKind64, mapKeyFastKind64ptr:
vvptr, ok = mapaccess2_fast64(urv.typ, mptr, *(*uint64)(kptr))
case mapKeyFastKindStr:
vvptr, ok = mapaccess2_faststr(urv.typ, mptr, *(*string)(kptr))
default:
vvptr, ok = mapaccess2(urv.typ, mptr, kptr)
}
if !ok {
return
}
urv = (*unsafeReflectValue)(unsafe.Pointer(&v))
if keyFastKind != 0 && valIsIndirect {
urv.ptr = *(*unsafe.Pointer)(vvptr)
} else if helperUnsafeDirectAssignMapEntry || valIsRef {
urv.ptr = vvptr
} else {
typedmemmove(urv.typ, urv.ptr, vvptr)
}
return v
}
//go:linkname unsafeZeroArr runtime.zeroVal
var unsafeZeroArr [1024]byte
//go:linkname rvPtrToType reflect.toType
//go:noescape
func rvPtrToType(typ unsafe.Pointer) reflect.Type
//go:linkname growslice runtime.growslice
//go:noescape
func growslice(typ unsafe.Pointer, old unsafeSlice, cap int) unsafeSlice
//go:linkname mapassign_fast32 runtime.mapassign_fast32
//go:noescape
func mapassign_fast32(typ unsafe.Pointer, m unsafe.Pointer, key uint32) unsafe.Pointer
//go:linkname mapassign_fast32ptr runtime.mapassign_fast32ptr
//go:noescape
func mapassign_fast32ptr(typ unsafe.Pointer, m unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer
//go:linkname mapassign_fast64 runtime.mapassign_fast64
//go:noescape
func mapassign_fast64(typ unsafe.Pointer, m unsafe.Pointer, key uint64) unsafe.Pointer
//go:linkname mapassign_fast64ptr runtime.mapassign_fast64ptr
//go:noescape
func mapassign_fast64ptr(typ unsafe.Pointer, m unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer
//go:linkname mapassign_faststr runtime.mapassign_faststr
//go:noescape
func mapassign_faststr(typ unsafe.Pointer, m unsafe.Pointer, s string) unsafe.Pointer
//go:linkname mapaccess2_fast32 runtime.mapaccess2_fast32
//go:noescape
func mapaccess2_fast32(typ unsafe.Pointer, m unsafe.Pointer, key uint32) (val unsafe.Pointer, ok bool)
//go:linkname mapaccess2_fast64 runtime.mapaccess2_fast64
//go:noescape
func mapaccess2_fast64(typ unsafe.Pointer, m unsafe.Pointer, key uint64) (val unsafe.Pointer, ok bool)
//go:linkname mapaccess2_faststr runtime.mapaccess2_faststr
//go:noescape
func mapaccess2_faststr(typ unsafe.Pointer, m unsafe.Pointer, key string) (val unsafe.Pointer, ok bool)