From: korzhao Date: Sun, 30 Jul 2023 07:02:15 +0000 (+0800) Subject: encoding/json: optimize Unmarshal for maps X-Git-Tag: go1.22rc1~1471 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=1eaeec10958bf41d082ef212ee689fd8c1284320;p=gostls13.git encoding/json: optimize Unmarshal for maps benchmark old ns/op new ns/op delta BenchmarkUnmarshalMap-10 218 172 -21.28% benchmark old allocs new allocs delta BenchmarkUnmarshalMap-10 15 12 -20.00% benchmark old bytes new bytes delta BenchmarkUnmarshalMap-10 328 256 -21.95% Change-Id: Ie20ab62731c752eb0040c6d1591fedd7d12b1e0c Reviewed-on: https://go-review.googlesource.com/c/go/+/514100 TryBot-Result: Gopher Robot Run-TryBot: Ian Lance Taylor Reviewed-by: David Chase Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor Auto-Submit: Ian Lance Taylor --- diff --git a/src/encoding/json/bench_test.go b/src/encoding/json/bench_test.go index d3af0dc0ed..bafccdf193 100644 --- a/src/encoding/json/bench_test.go +++ b/src/encoding/json/bench_test.go @@ -385,6 +385,19 @@ func BenchmarkUnmarshalInt64(b *testing.B) { }) } +func BenchmarkUnmarshalMap(b *testing.B) { + b.ReportAllocs() + data := []byte(`{"key1":"value1","key2":"value2","key3":"value3"}`) + b.RunParallel(func(pb *testing.PB) { + x := make(map[string]string, 3) + for pb.Next() { + if err := Unmarshal(data, &x); err != nil { + b.Fatal("Unmarshal:", err) + } + } + }) +} + func BenchmarkIssue10335(b *testing.B) { b.ReportAllocs() j := []byte(`{"a":{ }}`) diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go index 53470d8c88..2142816d88 100644 --- a/src/encoding/json/decode.go +++ b/src/encoding/json/decode.go @@ -762,17 +762,17 @@ func (d *decodeState) object(v reflect.Value) error { if v.Kind() == reflect.Map { kt := t.Key() var kv reflect.Value - switch { - case reflect.PointerTo(kt).Implements(textUnmarshalerType): + if reflect.PointerTo(kt).Implements(textUnmarshalerType) { kv = reflect.New(kt) if err := d.literalStore(item, kv, true); err != nil { return err } kv = kv.Elem() - case kt.Kind() == reflect.String: - kv = reflect.ValueOf(key).Convert(kt) - default: + } else { switch kt.Kind() { + case reflect.String: + kv = reflect.New(kt).Elem() + kv.SetString(string(key)) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: s := string(key) n, err := strconv.ParseInt(s, 10, 64) @@ -780,7 +780,8 @@ func (d *decodeState) object(v reflect.Value) error { d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) break } - kv = reflect.ValueOf(n).Convert(kt) + kv = reflect.New(kt).Elem() + kv.SetInt(n) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: s := string(key) n, err := strconv.ParseUint(s, 10, 64) @@ -788,7 +789,8 @@ func (d *decodeState) object(v reflect.Value) error { d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) break } - kv = reflect.ValueOf(n).Convert(kt) + kv = reflect.New(kt).Elem() + kv.SetUint(n) default: panic("json: Unexpected key type") // should never occur }