1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
// 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 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)
|