Skip to content

Commit 7ba074f

Browse files
xiaostgopherbot
authored andcommitted
reflect: remove calling mapiterkey, mapiterelem
It makes use of the hiter structure which matches runtime.hiter's. This change mainly improves the performance of Next method of MapIter. goos: darwin goarch: arm64 pkg: reflect cpu: Apple M2 │ ./old.txt │ ./new.txt │ │ sec/op │ sec/op vs base │ MapIterNext-8 61.95n ± 0% 54.95n ± 0% -11.28% (p=0.000 n=10) for the change of `test/escape_reflect.go`: removing mapiterkey, mapiterelem would cause leaking MapIter content when calling SetIterKey and SetIterValue, and this may cause map bucket to be allocated on heap instead of stack. Reproduce: ``` { m := map[int]int{1: 2} // escapes to heap after this change it := reflect.ValueOf(m).MapRange() it.Next() var k, v int reflect.ValueOf(&k).Elem().SetIterKey(it) reflect.ValueOf(&v).Elem().SetIterValue(it) println(k, v) } ``` This CL would not introduce abi.NoEscape to fix this. It may need futher optimization and tests on hiter field usage and its escape analysis. Fixes #69416 Change-Id: Ibaa33bcf86228070b4a505b9512680791aa59f04 Reviewed-on: https://go-review.googlesource.com/c/go/+/612616 Reviewed-by: Keith Randall <[email protected]> Auto-Submit: Keith Randall <[email protected]> Reviewed-by: Michael Knyszek <[email protected]> Reviewed-by: Keith Randall <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent c71b5ff commit 7ba074f

File tree

5 files changed

+18
-24
lines changed

5 files changed

+18
-24
lines changed

src/reflect/map_noswiss.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ func (v Value) MapKeys() []Value {
223223
a := make([]Value, mlen)
224224
var i int
225225
for i = 0; i < len(a); i++ {
226-
key := mapiterkey(&it)
226+
key := it.key
227227
if key == nil {
228228
// Someone deleted an entry from the map since we
229229
// called maplen above. It's a data race, but nothing
@@ -274,7 +274,7 @@ func (iter *MapIter) Key() Value {
274274
if !iter.hiter.initialized() {
275275
panic("MapIter.Key called before Next")
276276
}
277-
iterkey := mapiterkey(&iter.hiter)
277+
iterkey := iter.hiter.key
278278
if iterkey == nil {
279279
panic("MapIter.Key called on exhausted iterator")
280280
}
@@ -292,7 +292,7 @@ func (v Value) SetIterKey(iter *MapIter) {
292292
if !iter.hiter.initialized() {
293293
panic("reflect: Value.SetIterKey called before Next")
294294
}
295-
iterkey := mapiterkey(&iter.hiter)
295+
iterkey := iter.hiter.key
296296
if iterkey == nil {
297297
panic("reflect: Value.SetIterKey called on exhausted iterator")
298298
}
@@ -317,7 +317,7 @@ func (iter *MapIter) Value() Value {
317317
if !iter.hiter.initialized() {
318318
panic("MapIter.Value called before Next")
319319
}
320-
iterelem := mapiterelem(&iter.hiter)
320+
iterelem := iter.hiter.elem
321321
if iterelem == nil {
322322
panic("MapIter.Value called on exhausted iterator")
323323
}
@@ -335,7 +335,7 @@ func (v Value) SetIterValue(iter *MapIter) {
335335
if !iter.hiter.initialized() {
336336
panic("reflect: Value.SetIterValue called before Next")
337337
}
338-
iterelem := mapiterelem(&iter.hiter)
338+
iterelem := iter.hiter.elem
339339
if iterelem == nil {
340340
panic("reflect: Value.SetIterValue called on exhausted iterator")
341341
}
@@ -365,12 +365,12 @@ func (iter *MapIter) Next() bool {
365365
if !iter.hiter.initialized() {
366366
mapiterinit(iter.m.typ(), iter.m.pointer(), &iter.hiter)
367367
} else {
368-
if mapiterkey(&iter.hiter) == nil {
368+
if iter.hiter.key == nil {
369369
panic("MapIter.Next called on exhausted iterator")
370370
}
371371
mapiternext(&iter.hiter)
372372
}
373-
return mapiterkey(&iter.hiter) != nil
373+
return iter.hiter.key != nil
374374
}
375375

376376
// Reset modifies iter to iterate over v.

src/reflect/map_swiss.go

+7-7
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ func (v Value) MapKeys() []Value {
224224
a := make([]Value, mlen)
225225
var i int
226226
for i = 0; i < len(a); i++ {
227-
key := mapiterkey(&it)
227+
key := it.key
228228
if key == nil {
229229
// Someone deleted an entry from the map since we
230230
// called maplen above. It's a data race, but nothing
@@ -275,7 +275,7 @@ func (iter *MapIter) Key() Value {
275275
if !iter.hiter.initialized() {
276276
panic("MapIter.Key called before Next")
277277
}
278-
iterkey := mapiterkey(&iter.hiter)
278+
iterkey := iter.hiter.key
279279
if iterkey == nil {
280280
panic("MapIter.Key called on exhausted iterator")
281281
}
@@ -293,7 +293,7 @@ func (v Value) SetIterKey(iter *MapIter) {
293293
if !iter.hiter.initialized() {
294294
panic("reflect: Value.SetIterKey called before Next")
295295
}
296-
iterkey := mapiterkey(&iter.hiter)
296+
iterkey := iter.hiter.key
297297
if iterkey == nil {
298298
panic("reflect: Value.SetIterKey called on exhausted iterator")
299299
}
@@ -318,7 +318,7 @@ func (iter *MapIter) Value() Value {
318318
if !iter.hiter.initialized() {
319319
panic("MapIter.Value called before Next")
320320
}
321-
iterelem := mapiterelem(&iter.hiter)
321+
iterelem := iter.hiter.elem
322322
if iterelem == nil {
323323
panic("MapIter.Value called on exhausted iterator")
324324
}
@@ -336,7 +336,7 @@ func (v Value) SetIterValue(iter *MapIter) {
336336
if !iter.hiter.initialized() {
337337
panic("reflect: Value.SetIterValue called before Next")
338338
}
339-
iterelem := mapiterelem(&iter.hiter)
339+
iterelem := iter.hiter.elem
340340
if iterelem == nil {
341341
panic("reflect: Value.SetIterValue called on exhausted iterator")
342342
}
@@ -366,12 +366,12 @@ func (iter *MapIter) Next() bool {
366366
if !iter.hiter.initialized() {
367367
mapiterinit(iter.m.typ(), iter.m.pointer(), &iter.hiter)
368368
} else {
369-
if mapiterkey(&iter.hiter) == nil {
369+
if iter.hiter.key == nil {
370370
panic("MapIter.Next called on exhausted iterator")
371371
}
372372
mapiternext(&iter.hiter)
373373
}
374-
return mapiterkey(&iter.hiter) != nil
374+
return iter.hiter.key != nil
375375
}
376376

377377
// Reset modifies iter to iterate over v.

src/reflect/value.go

-6
Original file line numberDiff line numberDiff line change
@@ -3596,12 +3596,6 @@ func mapdelete_faststr(t *abi.Type, m unsafe.Pointer, key string)
35963596
//go:noescape
35973597
func mapiterinit(t *abi.Type, m unsafe.Pointer, it *hiter)
35983598

3599-
//go:noescape
3600-
func mapiterkey(it *hiter) (key unsafe.Pointer)
3601-
3602-
//go:noescape
3603-
func mapiterelem(it *hiter) (elem unsafe.Pointer)
3604-
36053599
//go:noescape
36063600
func mapiternext(it *hiter)
36073601

src/runtime/map_noswiss.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -1528,7 +1528,7 @@ func reflect_mapiternext(it *hiter) {
15281528
mapiternext(it)
15291529
}
15301530

1531-
// reflect_mapiterkey is for package reflect,
1531+
// reflect_mapiterkey was for package reflect,
15321532
// but widely used packages access it using linkname.
15331533
// Notable members of the hall of shame include:
15341534
// - github.com/goccy/go-json
@@ -1542,7 +1542,7 @@ func reflect_mapiterkey(it *hiter) unsafe.Pointer {
15421542
return it.key
15431543
}
15441544

1545-
// reflect_mapiterelem is for package reflect,
1545+
// reflect_mapiterelem was for package reflect,
15461546
// but widely used packages access it using linkname.
15471547
// Notable members of the hall of shame include:
15481548
// - github.com/goccy/go-json

test/escape_reflect.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,7 @@ func mapdelete(m map[string]string, k string) { // ERROR "m does not escape" "le
423423
}
424424

425425
// Unfortunate: v doesn't need to leak.
426-
func setiterkey1(v reflect.Value, it *reflect.MapIter) { // ERROR "leaking param: v$" "it does not escape"
426+
func setiterkey1(v reflect.Value, it *reflect.MapIter) { // ERROR "leaking param: v$" "leaking param content: it$"
427427
v.SetIterKey(it)
428428
}
429429

@@ -434,7 +434,7 @@ func setiterkey2(v reflect.Value, m map[string]string) { // ERROR "leaking param
434434
}
435435

436436
// Unfortunate: v doesn't need to leak.
437-
func setitervalue1(v reflect.Value, it *reflect.MapIter) { // ERROR "leaking param: v$" "it does not escape"
437+
func setitervalue1(v reflect.Value, it *reflect.MapIter) { // ERROR "leaking param: v$" "leaking param content: it$"
438438
v.SetIterValue(it)
439439
}
440440

0 commit comments

Comments
 (0)