File: helper_unsafe_compiler_gc.go

package info (click to toggle)
golang-github-ugorji-go-codec 1.2.8-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bookworm-proposed-updates, experimental, forky, sid, trixie
  • size: 2,532 kB
  • sloc: sh: 462; python: 100; makefile: 4
file content (168 lines) | stat: -rw-r--r-- 5,484 bytes parent folder | download
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)