From 9a2a34e1c1be53fce0782a0b5e14e6f7ceaad62a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Daniel=20Mart=C3=AD?= Date: Sun, 8 Jul 2018 13:17:56 +0100 Subject: [PATCH] encoding/json: defer error context work until necessary MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Calling Name on a reflect.Type is somewhat expensive, as it involves a number of nested calls and string handling. This cost was showing up when decoding structs, as we were calling it to set up an error context. We can avoid the extra work unless we do encounter an error, which makes decoding via struct types faster. name old time/op new time/op delta CodeDecoder-4 31.0ms ± 1% 29.9ms ± 1% -3.69% (p=0.002 n=6+6) name old speed new speed delta CodeDecoder-4 62.6MB/s ± 1% 65.0MB/s ± 1% +3.83% (p=0.002 n=6+6) Updates #5683. Change-Id: I48a3a85ef0ba96f524b7c3e9096cb2c4589e077a Reviewed-on: https://go-review.googlesource.com/122467 Run-TryBot: Daniel Martí TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick --- src/encoding/json/decode.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go index 97fee54f4e..16da48617e 100644 --- a/src/encoding/json/decode.go +++ b/src/encoding/json/decode.go @@ -267,7 +267,7 @@ type decodeState struct { opcode int // last read result scan scanner errorContext struct { // provides context for type errors - Struct string + Struct reflect.Type Field string } savedError error @@ -289,7 +289,7 @@ func (d *decodeState) init(data []byte) *decodeState { d.data = data d.off = 0 d.savedError = nil - d.errorContext.Struct = "" + d.errorContext.Struct = nil d.errorContext.Field = "" return d } @@ -304,10 +304,10 @@ func (d *decodeState) saveError(err error) { // addErrorContext returns a new error enhanced with information from d.errorContext func (d *decodeState) addErrorContext(err error) error { - if d.errorContext.Struct != "" || d.errorContext.Field != "" { + if d.errorContext.Struct != nil || d.errorContext.Field != "" { switch err := err.(type) { case *UnmarshalTypeError: - err.Struct = d.errorContext.Struct + err.Struct = d.errorContext.Struct.Name() err.Field = d.errorContext.Field return err } @@ -744,7 +744,7 @@ func (d *decodeState) object(v reflect.Value) error { subv = subv.Field(i) } d.errorContext.Field = f.name - d.errorContext.Struct = v.Type().Name() + d.errorContext.Struct = v.Type() } else if d.disallowUnknownFields { d.saveError(fmt.Errorf("json: unknown field %q", key)) } @@ -832,7 +832,7 @@ func (d *decodeState) object(v reflect.Value) error { return errPhase } - d.errorContext.Struct = "" + d.errorContext.Struct = nil d.errorContext.Field = "" } return nil -- 2.50.0