From 912bb817b08669acf99d0c2a665acf69558d93a6 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Thu, 29 Jun 2017 17:06:54 +0000 Subject: [PATCH] Revert "encoding/json: reduce unmarshal mallocs for unmapped fields" This reverts commit df68afd07ce67727 (https://golang.org/cl/33276) Reason for revert: made other benchmarks worse Fixes #20693 (details) Updates #17914 Updates #10335 Change-Id: If451b620803ccb0536b89c76c4353d2185d57d7e Reviewed-on: https://go-review.googlesource.com/47211 Run-TryBot: Brad Fitzpatrick TryBot-Result: Gobot Gobot Reviewed-by: Russ Cox --- src/encoding/json/decode.go | 62 ++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go index 710c835547e7a..420a07e1549c4 100644 --- a/src/encoding/json/decode.go +++ b/src/encoding/json/decode.go @@ -361,40 +361,47 @@ func (d *decodeState) scanWhile(op int) int { return newOp } -// discardObject and discardArray are dummy data targets -// used by the (*decodeState).value method, which -// accepts a zero reflect.Value to discard a value. -// The (*decodeState).object and (*decodeState).array methods, -// however, require a valid reflect.Value destination. -// These are the target values used when the caller of value -// wants to skip a field. -// -// Because these values refer to zero-sized objects -// and thus can't be mutated, they're safe for concurrent use -// by different goroutines unmarshalling skipped fields. -var ( - discardObject = reflect.ValueOf(struct{}{}) - discardArray = reflect.ValueOf([0]interface{}{}) -) - // value decodes a JSON value from d.data[d.off:] into the value. -// It updates d.off to point past the decoded value. If v is -// invalid, the JSON value is discarded. +// it updates d.off to point past the decoded value. func (d *decodeState) value(v reflect.Value) { + if !v.IsValid() { + _, rest, err := nextValue(d.data[d.off:], &d.nextscan) + if err != nil { + d.error(err) + } + d.off = len(d.data) - len(rest) + + // d.scan thinks we're still at the beginning of the item. + // Feed in an empty string - the shortest, simplest value - + // so that it knows we got to the end of the value. + if d.scan.redo { + // rewind. + d.scan.redo = false + d.scan.step = stateBeginValue + } + d.scan.step(&d.scan, '"') + d.scan.step(&d.scan, '"') + + n := len(d.scan.parseState) + if n > 0 && d.scan.parseState[n-1] == parseObjectKey { + // d.scan thinks we just read an object key; finish the object + d.scan.step(&d.scan, ':') + d.scan.step(&d.scan, '"') + d.scan.step(&d.scan, '"') + d.scan.step(&d.scan, '}') + } + + return + } + switch op := d.scanWhile(scanSkipSpace); op { default: d.error(errPhase) case scanBeginArray: - if !v.IsValid() { - v = discardArray - } d.array(v) case scanBeginObject: - if !v.IsValid() { - v = discardObject - } d.object(v) case scanBeginLiteral: @@ -512,7 +519,8 @@ func (d *decodeState) array(v reflect.Value) { d.off-- d.next() return - case reflect.Array, reflect.Slice: + case reflect.Array: + case reflect.Slice: break } @@ -791,9 +799,7 @@ func (d *decodeState) literal(v reflect.Value) { d.off-- d.scan.undo(op) - if v.IsValid() { - d.literalStore(d.data[start:d.off], v, false) - } + d.literalStore(d.data[start:d.off], v, false) } // convertNumber converts the number literal s to a float64 or a Number