mirror of
https://github.com/golang/go
synced 2024-11-19 02:14:43 -07:00
encoding/json: avoid allocation when decoding number types
In CL 345488, we optimized strconv.ParseXXX for []byte arguments. That allows immediate casting of a []byte to a string that does not escape to be copied on the stack. Performance: goos: darwin goarch: arm64 pkg: encoding/json old sec/op new sec/op delta CodeUnmarshal-10 3.019m ± 6% 2.865m ± 10% -5.10% (p=0.043 n=10) CodeUnmarshalReuse-10 2.528m ± 4% 2.274m ± 13% -10.03% (p=0.009 n=10) geomean 2.762m 2.553m -7.60% old B/s new B/s delta CodeUnmarshal-10 613.1Mi ± 5% 646.0Mi ± 9% +5.37% (p=0.043 n=10) CodeUnmarshalReuse-10 732.1Mi ± 4% 813.7Mi ± 12% +11.15% (p=0.009 n=10) geomean 669.9Mi 725.0Mi +8.22% old B/op new B/op delta CodeUnmarshal-10 2.782Mi ± 0% 1.918Mi ± 0% -31.04% (p=0.000 n=10) CodeUnmarshalReuse-10 1600.8Ki ± 0% 713.3Ki ± 0% -55.44% (p=0.000 n=10) geomean 2.085Mi 1.156Mi -44.57% old allocs/op new allocs/op delta CodeUnmarshal-10 91.31k ± 0% 39.99k ± 0% -56.20% (p=0.000 n=10) CodeUnmarshalReuse-10 76.58k ± 0% 25.23k ± 0% -67.06% (p=0.000 n=10) geomean 83.62k 31.76k -62.02% Change-Id: I208c57089040daee0f9d979d1df725e3acf34f81 Reviewed-on: https://go-review.googlesource.com/c/go/+/518277 Reviewed-by: Dmitri Shuralyov <dmitshur@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Michael Knyszek <mknyszek@google.com> Reviewed-by: Joseph Tsai <joetsai@digital-static.net> Run-TryBot: Joseph Tsai <joetsai@digital-static.net> Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
This commit is contained in:
parent
4c5dac7202
commit
ddad9b618c
@ -962,13 +962,12 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
|||||||
}
|
}
|
||||||
panic(phasePanicMsg)
|
panic(phasePanicMsg)
|
||||||
}
|
}
|
||||||
s := string(item)
|
|
||||||
switch v.Kind() {
|
switch v.Kind() {
|
||||||
default:
|
default:
|
||||||
if v.Kind() == reflect.String && v.Type() == numberType {
|
if v.Kind() == reflect.String && v.Type() == numberType {
|
||||||
// s must be a valid number, because it's
|
// s must be a valid number, because it's
|
||||||
// already been tokenized.
|
// already been tokenized.
|
||||||
v.SetString(s)
|
v.SetString(string(item))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if fromQuoted {
|
if fromQuoted {
|
||||||
@ -976,7 +975,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
|||||||
}
|
}
|
||||||
d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())})
|
d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())})
|
||||||
case reflect.Interface:
|
case reflect.Interface:
|
||||||
n, err := d.convertNumber(s)
|
n, err := d.convertNumber(string(item))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.saveError(err)
|
d.saveError(err)
|
||||||
break
|
break
|
||||||
@ -988,25 +987,25 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
|
|||||||
v.Set(reflect.ValueOf(n))
|
v.Set(reflect.ValueOf(n))
|
||||||
|
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
n, err := strconv.ParseInt(s, 10, 64)
|
n, err := strconv.ParseInt(string(item), 10, 64)
|
||||||
if err != nil || v.OverflowInt(n) {
|
if err != nil || v.OverflowInt(n) {
|
||||||
d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())})
|
d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.SetInt(n)
|
v.SetInt(n)
|
||||||
|
|
||||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
n, err := strconv.ParseUint(s, 10, 64)
|
n, err := strconv.ParseUint(string(item), 10, 64)
|
||||||
if err != nil || v.OverflowUint(n) {
|
if err != nil || v.OverflowUint(n) {
|
||||||
d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())})
|
d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.SetUint(n)
|
v.SetUint(n)
|
||||||
|
|
||||||
case reflect.Float32, reflect.Float64:
|
case reflect.Float32, reflect.Float64:
|
||||||
n, err := strconv.ParseFloat(s, v.Type().Bits())
|
n, err := strconv.ParseFloat(string(item), v.Type().Bits())
|
||||||
if err != nil || v.OverflowFloat(n) {
|
if err != nil || v.OverflowFloat(n) {
|
||||||
d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: v.Type(), Offset: int64(d.readIndex())})
|
d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
v.SetFloat(n)
|
v.SetFloat(n)
|
||||||
|
Loading…
Reference in New Issue
Block a user