1
2
3
4
5
6
7 package maps
8
9 import (
10 "internal/abi"
11 "internal/asan"
12 "internal/msan"
13 "internal/race"
14 "internal/runtime/sys"
15 "unsafe"
16 )
17
18
19
20
21
22
23 var errNilAssign error
24
25
26
27
28
29
30
31 var zeroVal [abi.ZeroValSize]byte
32
33
34
35
36
37
38
39
40 func runtime_mapaccess1(typ *abi.SwissMapType, m *Map, key unsafe.Pointer) unsafe.Pointer {
41 if race.Enabled && m != nil {
42 callerpc := sys.GetCallerPC()
43 pc := abi.FuncPCABIInternal(runtime_mapaccess1)
44 race.ReadPC(unsafe.Pointer(m), callerpc, pc)
45 race.ReadObjectPC(typ.Key, key, callerpc, pc)
46 }
47 if msan.Enabled && m != nil {
48 msan.Read(key, typ.Key.Size_)
49 }
50 if asan.Enabled && m != nil {
51 asan.Read(key, typ.Key.Size_)
52 }
53
54 if m == nil || m.Used() == 0 {
55 if err := mapKeyError(typ, key); err != nil {
56 panic(err)
57 }
58 return unsafe.Pointer(&zeroVal[0])
59 }
60
61 if m.writing != 0 {
62 fatal("concurrent map read and map write")
63 }
64
65 hash := typ.Hasher(key, m.seed)
66
67 if m.dirLen <= 0 {
68 _, elem, ok := m.getWithKeySmall(typ, hash, key)
69 if !ok {
70 return unsafe.Pointer(&zeroVal[0])
71 }
72 return elem
73 }
74
75
76 idx := m.directoryIndex(hash)
77 t := m.directoryAt(idx)
78
79
80 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
81 for ; ; seq = seq.next() {
82 g := t.groups.group(typ, seq.offset)
83
84 match := g.ctrls().matchH2(h2(hash))
85
86 for match != 0 {
87 i := match.first()
88
89 slotKey := g.key(typ, i)
90 slotKeyOrig := slotKey
91 if typ.IndirectKey() {
92 slotKey = *((*unsafe.Pointer)(slotKey))
93 }
94 if typ.Key.Equal(key, slotKey) {
95 slotElem := unsafe.Pointer(uintptr(slotKeyOrig) + typ.ElemOff)
96 if typ.IndirectElem() {
97 slotElem = *((*unsafe.Pointer)(slotElem))
98 }
99 return slotElem
100 }
101 match = match.removeFirst()
102 }
103
104 match = g.ctrls().matchEmpty()
105 if match != 0 {
106
107
108 return unsafe.Pointer(&zeroVal[0])
109 }
110 }
111 }
112
113
114 func runtime_mapaccess2(typ *abi.SwissMapType, m *Map, key unsafe.Pointer) (unsafe.Pointer, bool) {
115 if race.Enabled && m != nil {
116 callerpc := sys.GetCallerPC()
117 pc := abi.FuncPCABIInternal(runtime_mapaccess1)
118 race.ReadPC(unsafe.Pointer(m), callerpc, pc)
119 race.ReadObjectPC(typ.Key, key, callerpc, pc)
120 }
121 if msan.Enabled && m != nil {
122 msan.Read(key, typ.Key.Size_)
123 }
124 if asan.Enabled && m != nil {
125 asan.Read(key, typ.Key.Size_)
126 }
127
128 if m == nil || m.Used() == 0 {
129 if err := mapKeyError(typ, key); err != nil {
130 panic(err)
131 }
132 return unsafe.Pointer(&zeroVal[0]), false
133 }
134
135 if m.writing != 0 {
136 fatal("concurrent map read and map write")
137 }
138
139 hash := typ.Hasher(key, m.seed)
140
141 if m.dirLen == 0 {
142 _, elem, ok := m.getWithKeySmall(typ, hash, key)
143 if !ok {
144 return unsafe.Pointer(&zeroVal[0]), false
145 }
146 return elem, true
147 }
148
149
150 idx := m.directoryIndex(hash)
151 t := m.directoryAt(idx)
152
153
154 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
155 for ; ; seq = seq.next() {
156 g := t.groups.group(typ, seq.offset)
157
158 match := g.ctrls().matchH2(h2(hash))
159
160 for match != 0 {
161 i := match.first()
162
163 slotKey := g.key(typ, i)
164 slotKeyOrig := slotKey
165 if typ.IndirectKey() {
166 slotKey = *((*unsafe.Pointer)(slotKey))
167 }
168 if typ.Key.Equal(key, slotKey) {
169 slotElem := unsafe.Pointer(uintptr(slotKeyOrig) + typ.ElemOff)
170 if typ.IndirectElem() {
171 slotElem = *((*unsafe.Pointer)(slotElem))
172 }
173 return slotElem, true
174 }
175 match = match.removeFirst()
176 }
177
178 match = g.ctrls().matchEmpty()
179 if match != 0 {
180
181
182 return unsafe.Pointer(&zeroVal[0]), false
183 }
184 }
185 }
186
187
188 func runtime_mapassign(typ *abi.SwissMapType, m *Map, key unsafe.Pointer) unsafe.Pointer {
189 if m == nil {
190 panic(errNilAssign)
191 }
192 if race.Enabled {
193 callerpc := sys.GetCallerPC()
194 pc := abi.FuncPCABIInternal(runtime_mapassign)
195 race.WritePC(unsafe.Pointer(m), callerpc, pc)
196 race.ReadObjectPC(typ.Key, key, callerpc, pc)
197 }
198 if msan.Enabled {
199 msan.Read(key, typ.Key.Size_)
200 }
201 if asan.Enabled {
202 asan.Read(key, typ.Key.Size_)
203 }
204 if m.writing != 0 {
205 fatal("concurrent map writes")
206 }
207
208 hash := typ.Hasher(key, m.seed)
209
210
211
212 m.writing ^= 1
213
214 if m.dirPtr == nil {
215 m.growToSmall(typ)
216 }
217
218 if m.dirLen == 0 {
219 if m.used < abi.SwissMapGroupSlots {
220 elem := m.putSlotSmall(typ, hash, key)
221
222 if m.writing == 0 {
223 fatal("concurrent map writes")
224 }
225 m.writing ^= 1
226
227 return elem
228 }
229
230
231 m.growToTable(typ)
232 }
233
234 var slotElem unsafe.Pointer
235 outer:
236 for {
237
238 idx := m.directoryIndex(hash)
239 t := m.directoryAt(idx)
240
241 seq := makeProbeSeq(h1(hash), t.groups.lengthMask)
242
243
244
245
246 var firstDeletedGroup groupReference
247 var firstDeletedSlot uintptr
248
249 for ; ; seq = seq.next() {
250 g := t.groups.group(typ, seq.offset)
251 match := g.ctrls().matchH2(h2(hash))
252
253
254 for match != 0 {
255 i := match.first()
256
257 slotKey := g.key(typ, i)
258 slotKeyOrig := slotKey
259 if typ.IndirectKey() {
260 slotKey = *((*unsafe.Pointer)(slotKey))
261 }
262 if typ.Key.Equal(key, slotKey) {
263 if typ.NeedKeyUpdate() {
264 typedmemmove(typ.Key, slotKey, key)
265 }
266
267 slotElem = unsafe.Pointer(uintptr(slotKeyOrig) + typ.ElemOff)
268 if typ.IndirectElem() {
269 slotElem = *((*unsafe.Pointer)(slotElem))
270 }
271
272 t.checkInvariants(typ, m)
273 break outer
274 }
275 match = match.removeFirst()
276 }
277
278
279
280 match = g.ctrls().matchEmpty()
281 if match != 0 {
282
283
284
285 var i uintptr
286
287
288
289 if firstDeletedGroup.data != nil {
290 g = firstDeletedGroup
291 i = firstDeletedSlot
292 t.growthLeft++
293 } else {
294
295 i = match.first()
296 }
297
298
299 if t.growthLeft > 0 {
300 slotKey := g.key(typ, i)
301 slotKeyOrig := slotKey
302 if typ.IndirectKey() {
303 kmem := newobject(typ.Key)
304 *(*unsafe.Pointer)(slotKey) = kmem
305 slotKey = kmem
306 }
307 typedmemmove(typ.Key, slotKey, key)
308
309 slotElem = unsafe.Pointer(uintptr(slotKeyOrig) + typ.ElemOff)
310 if typ.IndirectElem() {
311 emem := newobject(typ.Elem)
312 *(*unsafe.Pointer)(slotElem) = emem
313 slotElem = emem
314 }
315
316 g.ctrls().set(i, ctrl(h2(hash)))
317 t.growthLeft--
318 t.used++
319 m.used++
320
321 t.checkInvariants(typ, m)
322 break outer
323 }
324
325 t.rehash(typ, m)
326 continue outer
327 }
328
329
330
331
332
333
334 if firstDeletedGroup.data == nil {
335
336
337 match = g.ctrls().matchEmptyOrDeleted()
338 if match != 0 {
339 firstDeletedGroup = g
340 firstDeletedSlot = match.first()
341 }
342 }
343 }
344 }
345
346 if m.writing == 0 {
347 fatal("concurrent map writes")
348 }
349 m.writing ^= 1
350
351 return slotElem
352 }
353
View as plain text