Commit graph

78 commits

Author SHA1 Message Date
Damien Neil
114719e16e Revert "encoding/json: implement Is on all errors"
This reverts CL 254537.

Reason for revert: Reason for revert: The recommended way to check for a type of error is errors.As. API changes should also start with a proposal.

Change-Id: I07c37428575e99c80b17525833a61831d10963bb
Reviewed-on: https://go-review.googlesource.com/c/go/+/254857
Trust: Damien Neil <dneil@google.com>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
2020-09-14 21:33:20 +00:00
Carlos Alexandro Becker
95bb00d108 encoding/json: implement Is on all errors
Allows users to check:

      errors.Is(err, &UnmarshalTypeError{})
      errors.Is(err, &UnmarshalFieldError{})
      errors.Is(err, &InvalidUnmarshalError{})
      errors.Is(err, &UnsupportedValueError{})
      errors.Is(err, &MarshalerError{})

which is the recommended way of checking for kinds of errors.

SyntaxError.Is was implemented in CL 253037.
As and Unwrap relevant methods will be added in future CLs.

Change-Id: I1f8a503b8fdc0f3afdfe9669a91f3af8d960e028
GitHub-Last-Rev: 930cda5384
GitHub-Pull-Request: golang/go#41360
Reviewed-on: https://go-review.googlesource.com/c/go/+/254537
Run-TryBot: Emmanuel Odeke <emm.odeke@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
Trust: Emmanuel Odeke <emm.odeke@gmail.com>
2020-09-13 03:19:24 +00:00
Daniel Martí
b1a48af7e8 encoding/json: properly encode strings with ",string" again
golang.org/cl/193604 fixed one bug when one encodes a string with the
",string" option: if SetEscapeHTML(false) is used, we should not be
using HTML escaping for the inner string encoding. The CL correctly
fixed that.

The CL also tried to speed up this edge case. By avoiding an entire new
call to Marshal, the new Issue34127 benchmark reduced its time/op by
45%, and lowered the allocs/op from 3 to 2.

However, that last optimization wasn't correct:

	Since Go 1.2 every string can be marshaled to JSON without error
	even if it contains invalid UTF-8 byte sequences. Therefore
	there is no need to use Marshal again for the only reason of
	enclosing the string in double quotes.

JSON string encoding isn't just about adding quotes and taking care of
invalid UTF-8. We also need to escape some characters, like tabs and
newlines.

The new code failed to do that. The bug resulted in the added test case
failing to roundtrip properly; before our fix here, we'd see an error:

	invalid use of ,string struct tag, trying to unmarshal "\"\b\f\n\r\t\"\\\"" into string

If you pay close attention, you'll notice that the special characters
like tab and newline are only encoded once, not twice. When decoding
with the ",string" option, the outer string decode works, but the inner
string decode fails, as we are now decoding a JSON string with unescaped
special characters.

The fix we apply here isn't to go back to Marshal, as that would
re-introduce the bug with SetEscapeHTML(false). Instead, we can use a
new encode state from the pool - it results in minimal performance
impact, and even reduces allocs/op further. The performance impact seems
fair, given that we need to check the entire string for characters that
need to be escaped.

	name          old time/op    new time/op    delta
	Issue34127-8    89.7ns ± 2%   100.8ns ± 1%  +12.27%  (p=0.000 n=8+8)

	name          old alloc/op   new alloc/op   delta
	Issue34127-8     40.0B ± 0%     32.0B ± 0%  -20.00%  (p=0.000 n=8+8)

	name          old allocs/op  new allocs/op  delta
	Issue34127-8      2.00 ± 0%      1.00 ± 0%  -50.00%  (p=0.000 n=8+8)

Instead of adding another standalone test, we convert an existing
"string tag" test to be table-based, and add another test case there.

One test case from the original CL also had to be amended, due to the
same problem - when escaping '<' due to SetEscapeHTML(true), we need to
end up with double escaping, since we're using ",string".

Fixes #38173.

Change-Id: I2b0df9e4f1d3452fff74fe910e189c930dde4b5b
Reviewed-on: https://go-review.googlesource.com/c/go/+/226498
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
2020-05-08 13:29:11 +00:00
Jon Johnson
e9956791bf encoding/json: fix broken link to json.org
This updates the link to a newer image.

Change-Id: Ibdfe8c57d9217a325bcfde98cb6f952ca63d588a
GitHub-Last-Rev: f5970ba395
GitHub-Pull-Request: golang/go#36938
Reviewed-on: https://go-review.googlesource.com/c/go/+/217297
Reviewed-by: Toshihiro Shiino <shiino.toshihiro@gmail.com>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
2020-02-22 17:39:09 +00:00
Daniel Martí
64c9ee98b7 encoding/json: error when encoding a pointer cycle
Otherwise we'd panic with a stack overflow.

Most programs are in control of the data being encoded and can ensure
there are no cycles, but sometimes it's not that simple. For example,
running a user's html template with script tags can easily result in
crashes if the user can find a pointer cycle.

Adding the checks via a map to every ptrEncoder.encode call slowed down
the benchmarks below by a noticeable 13%. Instead, only start doing the
relatively expensive pointer cycle checks if we're many levels of
pointers deep in an encode state.

A threshold of 1000 is small enough to capture pointer cycles before
they're a problem (the goroutine stack limit is currently 1GB, and I
needed close to a million levels to reach it). Yet it's large enough
that reasonable uses of the json encoder only see a tiny 1% slow-down
due to the added ptrLevel field and check.

	name           old time/op    new time/op    delta
	CodeEncoder-8    2.34ms ± 1%    2.37ms ± 0%  +1.05%  (p=0.000 n=10+10)
	CodeMarshal-8    2.42ms ± 1%    2.44ms ± 0%  +1.10%  (p=0.000 n=10+10)

	name           old speed      new speed      delta
	CodeEncoder-8   829MB/s ± 1%   820MB/s ± 0%  -1.04%  (p=0.000 n=10+10)
	CodeMarshal-8   803MB/s ± 1%   795MB/s ± 0%  -1.09%  (p=0.000 n=10+10)

	name           old alloc/op   new alloc/op   delta
	CodeEncoder-8    43.1kB ± 8%    42.5kB ±10%    ~     (p=0.989 n=10+10)
	CodeMarshal-8    1.99MB ± 0%    1.99MB ± 0%    ~     (p=0.254 n=9+6)

	name           old allocs/op  new allocs/op  delta
	CodeEncoder-8      0.00           0.00         ~     (all equal)
	CodeMarshal-8      1.00 ± 0%      1.00 ± 0%    ~     (all equal)

Finally, add a few tests to ensure that the code handles the edge cases
properly.

Fixes #10769.

Change-Id: I73d48e0cf6ea140127ea031f2dbae6e6a55e58b8
Reviewed-on: https://go-review.googlesource.com/c/go/+/187920
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Reviewed-by: Andrew Bonventre <andybons@golang.org>
2019-11-11 16:24:21 +00:00
Phil Pearl
acbed0372e encoding/json: remove allocation when using a Marshaler with value receiver
If we marshal a non-pointer struct field whose type implements Marshaler with
a non-pointer receiver, then we avoid an allocation if we take the address of
the field before casting it to an interface.

name               old time/op    new time/op    delta
EncodeMarshaler-8     104ns ± 1%      92ns ± 2%  -11.72%  (p=0.001 n=7+7)

name               old alloc/op   new alloc/op   delta
EncodeMarshaler-8     36.0B ± 0%      4.0B ± 0%  -88.89%  (p=0.000 n=8+8)

name               old allocs/op  new allocs/op  delta
EncodeMarshaler-8      2.00 ± 0%      1.00 ± 0%  -50.00%  (p=0.000 n=8+8)

Test coverage already looks good enough for this change. TestRefValMarshal
already covers all possible combinations of value & pointer receivers on
value and pointer struct fields.

Change-Id: I6fc7f72396396d98f9a90c3c86e813690f41c099
Reviewed-on: https://go-review.googlesource.com/c/go/+/203608
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2019-10-28 11:22:20 +00:00
Eugene Kalinin
02196d3657 encoding/json: correct caller's name in encoding errors
1. Change mapencode.encode to use fmt.Error rather than MarshalerError.
MarshalerError refer to MarshalJSON, but mapencode.encode does not use that.

2. Add sourceFunc field to MarshalerError to record the name of the function
that creates the error, so that the Error method can report it correctly.

Fixes #29753

Change-Id: I186c2fac8470ae2f9e300501de3730face642230
Reviewed-on: https://go-review.googlesource.com/c/go/+/184119
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2019-10-16 22:58:08 +00:00
Lucas Bremgartner
49e7c7672d encoding/json: make Number with the ,string option marshal with quotes
Add quotes when marshaling a json.Number with the string option
set via a struct tag. This ensures that the resulting json
can be unmarshaled into the source struct without error.

Fixes #34268

Change-Id: Ide167d9dec77019554870b5957b37dc258119d81
GitHub-Last-Rev: dde81b7120
GitHub-Pull-Request: golang/go#34269
Reviewed-on: https://go-review.googlesource.com/c/go/+/195043
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2019-09-16 11:56:15 +00:00
William Poussier
cc39d8087b encoding/json: encode nil encoding.TextMarshaler instance as "null"
Fixes #34235.

Change-Id: Ia3795fd18860530fa6a4b171545f525e784ffdcb
GitHub-Last-Rev: 1a319c4528
GitHub-Pull-Request: golang/go#34238
Reviewed-on: https://go-review.googlesource.com/c/go/+/194642
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2019-09-11 18:37:43 +00:00
Lucas Bremgartner
0e015e20cf encoding/json: fix and optimize marshal for quoted string
Since Go 1.2 every string can be marshaled to JSON without error even if it
contains invalid UTF-8 byte sequences. Therefore there is no need to use
Marshal again for the only reason of enclosing the string in double quotes.
Not using Marshal here also removes the error check as there has not been a
way for Marshal to fail anyway.

name          old time/op    new time/op    delta
Issue34127-4     360ns ± 3%     200ns ± 3%  -44.56%  (p=0.008 n=5+5)

name          old alloc/op   new alloc/op   delta
Issue34127-4     56.0B ± 0%     40.0B ± 0%  -28.57%  (p=0.008 n=5+5)

name          old allocs/op  new allocs/op  delta
Issue34127-4      3.00 ± 0%      2.00 ± 0%  -33.33%  (p=0.008 n=5+5)

Fixes #34154

Change-Id: Ib60dc11980f9b20d8bef2982de7168943d632263
GitHub-Last-Rev: 9b0ac1d4c5
GitHub-Pull-Request: golang/go#34127
Reviewed-on: https://go-review.googlesource.com/c/go/+/193604
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2019-09-11 12:26:35 +00:00
andig
cf630586ca encoding/json: don't reset before returning buffer to pool
Reset is already performed when retrieving from pool

Change-Id: Ia810dd18d3e55a1565a5ad435a00d1e46724576c
GitHub-Last-Rev: d9df74a4ae
GitHub-Pull-Request: golang/go#34195
Reviewed-on: https://go-review.googlesource.com/c/go/+/194338
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
2019-09-10 14:58:40 +00:00
William Poussier
85f3ca7488 encoding/json: fix panic for nil instances of TextMarshaler in map keys
This change adds a a check in the encodeWithString.resolve method
to ensure that a reflect.Value with kind Ptr is not nil before
the type assertion to TextMarshaler.

If the value is nil, the method returns a nil error, and the map key
encodes to an empty string.

Fixes #33675

Change-Id: I0a04cf690ae67006f6a9c5f8cbb4cc99d236bca8
GitHub-Last-Rev: 6c987c9084
GitHub-Pull-Request: golang/go#33700
Reviewed-on: https://go-review.googlesource.com/c/go/+/190697
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
2019-09-01 16:39:38 +00:00
Daniel Martí
ae68a91272 encoding/json: remove unnecessary isValidNumber call
The decoder called this function to check numbers being decoded into a
json.Number. However, these can't be quoted as strings, so the tokenizer
has already verified they are valid JSON numbers.

Verified this by adding a test with such an input. As expected, it
produces a syntax error, not the fmt.Errorf - that line could never
execute.

Since the only remaining non-test caller of isvalidnumber is in
encode.go, move the function there.

This change should slightly reduce the amount of work when decoding into
json.Number, though that isn't very common nor part of any current
benchmarks.

Change-Id: I67a1723deb3d18d5b542d6dd35f3ae56a43f23eb
Reviewed-on: https://go-review.googlesource.com/c/go/+/184817
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2019-08-27 17:53:55 +00:00
Eli Bendersky
e81b731592 encoding/json: clarify Marshal behavior for string keys of maps
This is a documentation-only change.

Fixes #28827

Change-Id: Ife9ab997809048784f35872b09905bc209a05eff
Reviewed-on: https://go-review.googlesource.com/c/go/+/188417
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2019-07-31 21:49:08 +00:00
Daniel Martí
13327f219e encoding/json: obey SetEscapeHTML in all MarshalJSON cases
It wasn't obeyed in the case where the MarshalJSON method uses a pointer
receiver, and the encoder grabs the address of a value to find that
method. addrMarshalerEncoder is the function that does this work, but it
ignored opts.escapeHTML.

Here's the before and after of the added test case, which was failing
before the fix. Now the two cases are correct and consistent.

	{"NonPtr":"<str>","Ptr":"\u003cstr\u003e"}
	{"NonPtr":"<str>","Ptr":"<str>"}

Fixes #32896.

Change-Id: Idc53077ece074973558bd3bb5ad036380db0d02c
Reviewed-on: https://go-review.googlesource.com/c/go/+/184757
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
Reviewed-by: Caleb Spare <cespare@gmail.com>
2019-07-06 13:25:59 +00:00
Damien Neil
170b8b4b12 all: add Unwrap and Is methods to various error types
Add Unwrap methods to types which wrap an underlying error:

  "encodinc/csv".ParseError
  "encoding/json".MarshalerError
  "net/http".transportReadFromServerError
  "net".OpError
  "net".DNSConfigError
  "net/url".Error
  "os/exec".Error
  "signal/internal/pty".PtyError
  "text/template".ExecError

Add os.ErrTemporary. A case could be made for putting this error
value in package net, since no exported error types in package os
include a Temporary method. However, syscall errors returned from
the os package do include this method.

Add Is methods to error types with a Timeout or Temporary method,
making errors.Is(err, os.Err{Timeout,Temporary}) equivalent to
testing the corresponding method:

  "context".DeadlineExceeded
  "internal/poll".TimeoutError
  "net".adrinfoErrno
  "net".OpError
  "net".DNSError
  "net/http".httpError
  "net/http".tlsHandshakeTimeoutError
  "net/pipe".timeoutError
  "net/url".Error

Updates #30322
Updates #29934

Change-Id: I409fb20c072ea39116ebfb8c7534d493483870dc
Reviewed-on: https://go-review.googlesource.com/c/go/+/170037
Run-TryBot: Damien Neil <dneil@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
2019-05-04 16:14:12 +00:00
Russ Cox
d92bc7a55a encoding/json: document HTML escaping in Compact
Make explicit that Compact does HTML escaping.

Fixes #30357.

Change-Id: I4648f8f3e907d659db977d07253f716df6e07d7b
Reviewed-on: https://go-review.googlesource.com/c/go/+/173417
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2019-04-23 14:22:20 +00:00
Daniel Martí
7e08c7f43d encoding/json: index names for the struct decoder
In the common case, structs have a handful of fields and most inputs
match struct field names exactly.

The previous code would do a linear search over the fields, stopping at
the first exact match, and otherwise using the first case insensitive
match.

This is unfortunate, because it means that for the common case, we'd do
a linear search with bytes.Equal. Even for structs with only two or
three fields, that is pretty wasteful.

Worse even, up until the exact match was found via the linear search,
all previous fields would run their equalFold functions, which aren't
cheap even in the simple case.

Instead, cache a map along with the field list that indexes the fields
by their name. This way, a case sensitive field search doesn't involve a
linear search, nor does it involve any equalFold func calls.

This patch should also slightly speed up cases where there's a case
insensitive match but not a case sensitive one, as then we'd avoid
calling bytes.Equal on all the fields. Though that's not a common case,
and there are no benchmarks for it.

name           old time/op    new time/op    delta
CodeDecoder-8    11.0ms ± 0%    10.6ms ± 1%  -4.42%  (p=0.000 n=9+10)

name           old speed      new speed      delta
CodeDecoder-8   176MB/s ± 0%   184MB/s ± 1%  +4.62%  (p=0.000 n=9+10)

name           old alloc/op   new alloc/op   delta
CodeDecoder-8    2.28MB ± 0%    2.28MB ± 0%    ~     (p=0.725 n=10+10)

name           old allocs/op  new allocs/op  delta
CodeDecoder-8     76.9k ± 0%     76.9k ± 0%    ~     (all equal)

Updates #28923.

Change-Id: I9929c1f06c76505e5b96914199315dbdaae5dc76
Reviewed-on: https://go-review.googlesource.com/c/go/+/172918
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2019-04-23 05:54:51 +00:00
Daniel Martí
49662bc6b0 all: simplify multiple for loops
If a for loop has a simple condition and begins with a simple
"if x { break; }"; we can simply add "!x" to the loop's condition.

While at it, simplify a few assignments to use the common pattern
"x := staticDefault; if cond { x = otherValue(); }".

Finally, simplify a couple of var declarations.

Change-Id: I413982c6abd32905adc85a9a666cb3819139c19f
Reviewed-on: https://go-review.googlesource.com/c/go/+/165342
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2019-03-08 14:29:19 +00:00
Daniel Martí
340129e4c8 all: join a few chained ifs
I had been finding these over a year or so, but none were big enough
changes to warrant CLs. They're a handful now, so clean them all up in a
single commit.

The smaller bodies get a bit simpler, but most importantly, the larger
bodies get unindented.

Change-Id: I5707a6fee27d4c9ff9efd3d363af575d7a4bf2aa
Reviewed-on: https://go-review.googlesource.com/c/go/+/165340
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2019-03-05 20:31:32 +00:00
GuilhermeCaruso
5fae09b738 encoding/json: add comment for mashalererror struct
Change-Id: Iaabbfe5a4c1bbedd19d4087f1b79e5a38bdd3878
GitHub-Last-Rev: 55c91fc190
GitHub-Pull-Request: golang/go#29752
Reviewed-on: https://go-review.googlesource.com/c/157958
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2019-01-15 23:30:58 +00:00
Daniel Martí
969b9d8127 encoding/json: fix handling of nil anonymous structs
Given the following types:

	type S2 struct{ Field string }
	type S  struct{ *S2 }

Marshalling a value of type T1 should result in "{}", as there's no way
to access any value of T2.Field. This is how Go 1.10 and earlier
versions behave.

However, in the recent refactor golang.org/cl/125417 I broke this logic.
When the encoder found an anonymous struct pointer field that was nil,
it no longer skipped the embedded fields underneath it. This can be seen
in the added test:

	--- FAIL: TestAnonymousFields/EmbeddedFieldBehindNilPointer (0.00s)
	    encode_test.go:430: Marshal() = "{\"Field\":\"\\u003c*json.S2 Value\\u003e\"}", want "{}"

The human error was a misplaced label, meaning we weren't actually
skipping the right loop iteration. Fix that.

Change-Id: Iba8a4a77d358dac73dcba4018498fe4f81afa263
Reviewed-on: https://go-review.googlesource.com/131376
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-08-26 17:12:02 +00:00
Daniel Martí
c21ba224ec encoding/json: remove a branch in the structEncoder loop
Encoders like map and array can use the much cheaper "i > 0" check to
see if we're not writing the first element. However, since struct fields
support omitempty, we need to keep track of that separately.

This is much more expensive - after calling the field encoder itself,
and retrieving the field via reflection, this branch was the third most
expensive piece of this field loop.

Instead, hoist the branch logic outside of the loop. The code doesn't
get much more complex, since we just delay the writing of each byte
until the next iteration. Yet the performance improvement is noticeable,
even when the struct types in CodeEncoder only have 2 and 7 fields,
respectively.

name           old time/op    new time/op    delta
CodeEncoder-4    5.39ms ± 0%    5.31ms ± 0%  -1.37%  (p=0.010 n=4+6)

name           old speed      new speed      delta
CodeEncoder-4   360MB/s ± 0%   365MB/s ± 0%  +1.39%  (p=0.010 n=4+6)

Updates #5683.

Change-Id: I2662cf459e0dfd68e56fa52bc898a417e84266c2
Reviewed-on: https://go-review.googlesource.com/131401
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2018-08-25 23:59:43 +00:00
Daniel Martí
88f4bccec5 encoding/json: avoid some more pointer receivers
A few encoder struct types, such as map and slice, only encapsulate
other prepared encoder funcs. Using pointer receivers has no advantage,
and makes calling these methods slightly more expensive.

Not a huge performance win, but certainly an easy one. The struct types
used in the benchmark below contain one slice field and one pointer
field.

name           old time/op    new time/op    delta
CodeEncoder-4    5.48ms ± 0%    5.39ms ± 0%  -1.66%  (p=0.010 n=6+4)

name           old speed      new speed      delta
CodeEncoder-4   354MB/s ± 0%   360MB/s ± 0%  +1.69%  (p=0.010 n=6+4)

Updates #5683.

Change-Id: I9f78dbe07fcc6fbf19a6d96c22f5d6970db9eca4
Reviewed-on: https://go-review.googlesource.com/131400
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2018-08-25 23:58:26 +00:00
Daniel Martí
9d1540b77c encoding/json: simplify some pieces of the encoder
Some WriteByte('\\') calls can be deduplicated.

fillField is used in two occasions, but it is unnecessary when adding
fields to the "next" stack, as those aren't used for the final encoding.
Inline the func with its only remaining call.

Finally, unindent a default-if block.

The performance of the encoder is unaffected:

name           old time/op    new time/op    delta
CodeEncoder-4    6.65ms ± 1%    6.65ms ± 0%   ~     (p=0.662 n=6+5)

Change-Id: Ie55baeab89abad9b9f13e9f6ca886a670c30dba9
Reviewed-on: https://go-review.googlesource.com/122461
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-08-22 16:14:05 +00:00
Daniel Martí
75e7e05aee encoding/json: inline fieldByIndex
This function was only used in a single place - in the field encoding
loop within the struct encoder.

Inlining the function call manually lets us get rid of the call
overhead. But most importantly, it lets us simplify the logic afterward.
We no longer need to use reflect.Value{} and !fv.IsValid(), as we can
skip the field immediately.

The two factors combined (mostly just the latter) give a moderate speed
improvement to this hot loop.

name           old time/op    new time/op    delta
CodeEncoder-4    6.01ms ± 1%    5.91ms ± 1%  -1.66%  (p=0.002 n=6+6)

name           old speed      new speed      delta
CodeEncoder-4   323MB/s ± 1%   328MB/s ± 1%  +1.69%  (p=0.002 n=6+6)

Updates #5683.

Change-Id: I12757c325a68abb2856026cf719c122612a1f38e
Reviewed-on: https://go-review.googlesource.com/125417
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2018-08-22 15:55:40 +00:00
Daniel Martí
8148726676 encoding/json: simplify the structEncoder type
structEncoder had two slices - the list of fields, and a list containing
the encoder for each field. structEncoder.encode then looped over the
fields, and indexed into the second slice to grab the field encoder.

However, this makes it very hard for the compiler to be able to prove
that the two slices always have the same length, and that the index
expression doesn't need a bounds check.

Merge the two slices into one to completely remove the need for bounds
checks in the hot loop.

While at it, don't copy the field elements when ranging, which greatly
speeds up the hot loop in structEncoder.

name           old time/op    new time/op    delta
CodeEncoder-4    6.18ms ± 0%    5.56ms ± 0%  -10.08%  (p=0.002 n=6+6)

name           old speed      new speed      delta
CodeEncoder-4   314MB/s ± 0%   349MB/s ± 0%  +11.21%  (p=0.002 n=6+6)

name           old alloc/op   new alloc/op   delta
CodeEncoder-4    93.2kB ± 0%    62.1kB ± 0%  -33.33%  (p=0.002 n=6+6)

Updates #5683.

Change-Id: I0dd47783530f439b125e084aede09dda172eb1e8
Reviewed-on: https://go-review.googlesource.com/125416
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-08-22 15:08:21 +00:00
Daniel Martí
30d3ebe367 encoding/json: remove alloc when encoding short byte slices
If the encoded bytes fit in the bootstrap array encodeState.scratch, use
that instead of allocating a new byte slice.

Also tweaked the Encoding vs Encoder heuristic to use the length of the
encoded bytes, not the length of the input bytes. Encoding is used for
allocations of up to 1024 bytes, as we measured 2048 to be the point
where it no longer provides a noticeable advantage.

Also added some benchmarks. Only the first case changes in behavior.

name                 old time/op    new time/op    delta
MarshalBytes/32-4       420ns ± 1%     383ns ± 1%   -8.69%  (p=0.002 n=6+6)
MarshalBytes/256-4      913ns ± 1%     915ns ± 0%     ~     (p=0.580 n=5+6)
MarshalBytes/4096-4    7.72µs ± 0%    7.74µs ± 0%     ~     (p=0.340 n=5+6)

name                 old alloc/op   new alloc/op   delta
MarshalBytes/32-4        112B ± 0%       64B ± 0%  -42.86%  (p=0.002 n=6+6)
MarshalBytes/256-4       736B ± 0%      736B ± 0%     ~     (all equal)
MarshalBytes/4096-4    7.30kB ± 0%    7.30kB ± 0%     ~     (all equal)

name                 old allocs/op  new allocs/op  delta
MarshalBytes/32-4        2.00 ± 0%      1.00 ± 0%  -50.00%  (p=0.002 n=6+6)
MarshalBytes/256-4       2.00 ± 0%      2.00 ± 0%     ~     (all equal)
MarshalBytes/4096-4      2.00 ± 0%      2.00 ± 0%     ~     (all equal)

Updates #5683.

Change-Id: I5fa55c27bd7728338d770ae7c0756885ba9a5724
Reviewed-on: https://go-review.googlesource.com/122462
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-08-21 09:05:51 +00:00
Daniel Martí
2d3599e57d encoding/json: encode struct field names ahead of time
Struct field names are static, so we can run HTMLEscape on them when
building each struct type encoder. Then, when running the struct
encoder, we can select either the original or the escaped field name to
write directly.

When the encoder is not escaping HTML, using the original string works
because neither Go struct field names nor JSON tags allow any characters
that would need to be escaped, like '"', '\\', or '\n'.

When the encoder is escaping HTML, the only difference is that '<', '>',
and '&' are allowed via JSON struct field tags, hence why we use
HTMLEscape to properly escape them.

All of the above lets us encode field names with a simple if/else and
WriteString calls, which are considerably simpler and faster than
encoding an arbitrary string.

While at it, also include the quotes and colon in these strings, to
avoid three WriteByte calls in the loop hot path.

Also added a few tests, to ensure that the behavior in these edge cases
is not broken. The output of the tests is the same if this optimization
is reverted.

name           old time/op    new time/op    delta
CodeEncoder-4    7.12ms ± 0%    6.14ms ± 0%  -13.85%  (p=0.004 n=6+5)

name           old speed      new speed      delta
CodeEncoder-4   272MB/s ± 0%   316MB/s ± 0%  +16.08%  (p=0.004 n=6+5)

name           old alloc/op   new alloc/op   delta
CodeEncoder-4    91.9kB ± 0%    93.2kB ± 0%   +1.43%  (p=0.002 n=6+6)

name           old allocs/op  new allocs/op  delta
CodeEncoder-4      0.00           0.00          ~     (all equal)

Updates #5683.

Change-Id: I6f6a340d0de4670799ce38cf95b2092822d2e3ef
Reviewed-on: https://go-review.googlesource.com/122460
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-08-21 09:05:48 +00:00
Tim Cooper
dc272a4393 encoding/json: call reflect.TypeOf with nil pointers rather than allocating
Updates #26775

Change-Id: I83c9eeda59769d2f35e0cc98f3a8579861d5978b
Reviewed-on: https://go-review.googlesource.com/119715
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2018-08-21 02:38:02 +00:00
Michael Fraenkel
fc21598931 encoding/json: simplify dominantField
Fixes #18037

Change-Id: I20e27bcc013b00b726eb348daf5ca86b138ddcc2
Reviewed-on: https://go-review.googlesource.com/107598
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2018-04-17 23:04:19 +00:00
Jeremy Jackins
c0547476f3 encoding/json: make use of encodeStatePool in Marshal
On my system, this seems to be a significant win, with a major
reduction in allocations and minor speed improvement.

name           old time/op    new time/op    delta
CodeMarshal      9.75ms ± 3%    9.24ms ± 1%   -5.21%  (p=0.001 n=5+10)
CodeMarshal-4    4.98ms ± 1%    4.71ms ± 1%   -5.44%  (p=0.001 n=5+10)
CodeMarshal-8    4.80ms ± 0%    4.77ms ± 1%   -0.70%  (p=0.012 n=5+9)

name           old speed      new speed      delta
CodeMarshal     199MB/s ± 3%   210MB/s ± 1%   +5.46%  (p=0.001 n=5+10)
CodeMarshal-4   390MB/s ± 1%   412MB/s ± 1%   +5.76%  (p=0.001 n=5+10)
CodeMarshal-8   404MB/s ± 0%   407MB/s ± 1%   +0.70%  (p=0.012 n=5+9)

name           old alloc/op   new alloc/op   delta
CodeMarshal      4.59MB ± 0%    1.96MB ± 0%  -57.22%  (p=0.000 n=5+9)
CodeMarshal-4    4.59MB ± 0%    2.00MB ± 0%  -56.39%  (p=0.000 n=5+8)
CodeMarshal-8    4.59MB ± 0%    2.06MB ± 0%  -55.05%  (p=0.001 n=5+9)

name           old allocs/op  new allocs/op  delta
CodeMarshal        16.0 ± 0%       1.0 ± 0%  -93.75%  (p=0.000 n=5+10)
CodeMarshal-4      16.0 ± 0%       1.0 ± 0%  -93.75%  (p=0.000 n=5+10)
CodeMarshal-8      16.0 ± 0%       1.0 ± 0%  -93.75%  (p=0.000 n=5+10)

Change-Id: I9d09850d8227f523f861ae1b4ca248c4a4b16aaf
Reviewed-on: https://go-review.googlesource.com/84897
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2018-04-13 17:31:52 +00:00
Pascal S. de Kloe
74a92b8e8d encoding/json: apply conventional error handling in decoder
name                            old time/op    new time/op    delta
CodeEncoder-12                    1.89ms ± 1%    1.91ms ± 0%   +1.16%  (p=0.000 n=20+19)
CodeMarshal-12                    2.09ms ± 1%    2.12ms ± 0%   +1.63%  (p=0.000 n=17+18)
CodeDecoder-12                    8.43ms ± 1%    8.32ms ± 1%   -1.35%  (p=0.000 n=18+20)
UnicodeDecoder-12                  399ns ± 0%     339ns ± 0%  -15.00%  (p=0.000 n=20+19)
DecoderStream-12                   281ns ± 1%     231ns ± 0%  -17.91%  (p=0.000 n=20+16)
CodeUnmarshal-12                  9.35ms ± 2%    9.15ms ± 2%   -2.11%  (p=0.000 n=20+20)
CodeUnmarshalReuse-12             8.41ms ± 2%    8.29ms ± 2%   -1.34%  (p=0.000 n=20+20)
UnmarshalString-12                81.2ns ± 2%    74.0ns ± 4%   -8.89%  (p=0.000 n=20+20)
UnmarshalFloat64-12               71.1ns ± 2%    64.3ns ± 1%   -9.60%  (p=0.000 n=20+19)
UnmarshalInt64-12                 60.6ns ± 2%    53.2ns ± 0%  -12.28%  (p=0.000 n=18+18)
Issue10335-12                     96.9ns ± 0%    87.7ns ± 1%   -9.52%  (p=0.000 n=17+20)
Unmapped-12                        247ns ± 4%     231ns ± 3%   -6.34%  (p=0.000 n=20+20)
TypeFieldsCache/MissTypes1-12     11.1µs ± 0%    11.1µs ± 0%     ~     (p=0.376 n=19+20)
TypeFieldsCache/MissTypes10-12    33.9µs ± 0%    33.8µs ± 0%   -0.32%  (p=0.000 n=18+9)

name                            old speed      new speed      delta
CodeEncoder-12                  1.03GB/s ± 1%  1.01GB/s ± 0%   -1.15%  (p=0.000 n=20+19)
CodeMarshal-12                   930MB/s ± 1%   915MB/s ± 0%   -1.60%  (p=0.000 n=17+18)
CodeDecoder-12                   230MB/s ± 1%   233MB/s ± 1%   +1.37%  (p=0.000 n=18+20)
UnicodeDecoder-12               35.0MB/s ± 0%  41.2MB/s ± 0%  +17.60%  (p=0.000 n=20+19)
CodeUnmarshal-12                 208MB/s ± 2%   212MB/s ± 2%   +2.16%  (p=0.000 n=20+20)

name                            old alloc/op   new alloc/op   delta
Issue10335-12                       184B ± 0%      184B ± 0%     ~     (all equal)
Unmapped-12                         216B ± 0%      216B ± 0%     ~     (all equal)

name                            old allocs/op  new allocs/op  delta
Issue10335-12                       3.00 ± 0%      3.00 ± 0%     ~     (all equal)
Unmapped-12                         4.00 ± 0%      4.00 ± 0%     ~     (all equal)

Change-Id: I4b1a87a205da2ef9a572f86f85bc833653c61570
Reviewed-on: https://go-review.googlesource.com/98440
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2018-03-03 17:16:47 +00:00
Joe Tsai
f0756ca2ea encoding/json: use sync.Map for field cache
The previous type cache is quadratic in time in the situation where
new types are continually encountered. Now that it is possible to dynamically
create new types with the reflect package, this can cause json to
perform very poorly.

Switch to sync.Map which does well when the cache has hit steady state,
but also handles occasional updates in better than quadratic time.

benchmark                                     old ns/op      new ns/op     delta
BenchmarkTypeFieldsCache/MissTypes1-8         14817          16202         +9.35%
BenchmarkTypeFieldsCache/MissTypes10-8        70926          69144         -2.51%
BenchmarkTypeFieldsCache/MissTypes100-8       976467         208973        -78.60%
BenchmarkTypeFieldsCache/MissTypes1000-8      79520162       1750371       -97.80%
BenchmarkTypeFieldsCache/MissTypes10000-8     6873625837     16847806      -99.75%
BenchmarkTypeFieldsCache/HitTypes1000-8       7.51           8.80          +17.18%
BenchmarkTypeFieldsCache/HitTypes10000-8      7.58           8.68          +14.51%

The old implementation takes 12 minutes just to build a cache of size 1e5
due to the quadratic behavior. I did not bother benchmark sizes above that.

Change-Id: I5e6facc1eb8e1b80e5ca285e4dd2cc8815618dad
Reviewed-on: https://go-review.googlesource.com/76850
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
Reviewed-by: Bryan Mills <bcmills@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2018-03-03 00:08:09 +00:00
Joe Tsai
91a6a2a30f encoding/json: make error capture logic in recover more type safe
Rather than only ignoring runtime.Error panics, which are a very
narrow set of possible panic values, switch it such that the json
package only captures panic values that have been properly wrapped
in a jsonError struct. This ensures that only intentional panics
originating from the json package are captured.

Fixes #23012

Change-Id: I5e85200259edd2abb1b0512ce6cc288849151a6d
Reviewed-on: https://go-review.googlesource.com/94019
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2018-02-14 21:34:26 +00:00
Joe Tsai
70f441bc49 encoding/json: error when trying to set an embedded pointer to unexported struct types
This CL reverts CL 76851 and takes a different approach to #21357.
The changes in encode.go and encode_test.go are reverts that
rolls back the changed behavior in CL 76851 where
embedded pointers to unexported struct types were
unilaterally ignored in both marshal and unmarshal.

Instead, these fields are handled as before with the exception that
it returns an error when Unmarshal is unable to set an unexported field.
The behavior of Marshal is now unchanged with regards to #21357.

This policy maintains the greatest degree of backwards compatibility
and avoids silently discarding data the user may have expected to be present.

Fixes #21357

Change-Id: I7dc753280c99f786ac51acf7e6c0246618c8b2b1
Reviewed-on: https://go-review.googlesource.com/82135
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-12-06 19:27:26 +00:00
rajender
671cf92c32 encoding/json: remove the word "text" in "JSON text" from package docs.
It was added in CL 79995. It is unnecessarily confusing.

Change-Id: Ib8ff35b9f71b54ff99d2d6e0534c7128e1f4345a
Reviewed-on: https://go-review.googlesource.com/80035
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-11-27 18:51:36 +00:00
rajender
0d26474606 encoding/json: update RFC number
Existing docs mention obsolete RFC 4627. Update it with current one,
https://tools.ietf.org/html/rfc7159.

Current implementation already adhere to RFC 7159.

Fixes #22888

Change-Id: I705ec1313f6f655b3bc41d2f847b30e479bf9b15
Reviewed-on: https://go-review.googlesource.com/79995
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-11-27 18:04:57 +00:00
Joe Tsai
0cee4b7b78 encoding/json: always ignore embedded pointers to unexported struct types
CL 60410 fixes a bug in reflect that allows assignments to an embedded
field of a pointer to an unexported struct type.
This breaks the json package because unmarshal is now unable to assign
a newly allocated struct to such fields.

In order to be consistent in the behavior for marshal and unmarshal,
this CL changes both marshal and unmarshal to always ignore
embedded pointers to unexported structs.

Fixes #21357

Change-Id: If62ea11155555e61115ebb9cfa5305caf101bde5
Reviewed-on: https://go-review.googlesource.com/76851
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-11-13 18:23:38 +00:00
Ian Lance Taylor
ed3d672766 encoding/json: permit encoding uintptr as a string
Fixes #22629

Change-Id: I31e85f9faa125ee0dfd6d3c5fa89334b00d61e6e
Reviewed-on: https://go-review.googlesource.com/76530
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Emmanuel Odeke <emm.odeke@gmail.com>
Reviewed-by: Joe Tsai <joetsai@google.com>
2017-11-08 20:34:55 +00:00
Joe Tsai
a3e013b082 encoding/json: use Deprecated markers
In #10909, it was decided that "Deprecated:" is a magic string for
tools (e.g., #17056 for godoc) to detect deprecated identifiers.
Use those convention instead of custom written prose.

Change-Id: Ia514fc3c88fc502e86c6e3de361c435f4cb80b22
Reviewed-on: https://go-review.googlesource.com/70110
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
2017-10-11 22:09:22 +00:00
Joe Tsai
6872a8e1c9 encoding/json: cleanup detection of unexported embedded fields
CL 60410 fixes the compiler such that reflect.StructField.PkgPath
is non-empty if and only if the field is unexported.
Given that property, we can cleanup the logic in the json encoder
to avoid parsing the field name to detect export properties.

Updates #21122

Change-Id: Ic01b9c4ca76386774846b742b0c1b9b948f53e7c
Reviewed-on: https://go-review.googlesource.com/65550
Run-TryBot: Joe Tsai <thebrokentoaster@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-09-23 00:33:34 +00:00
tbunyk
b86fae041b encoding/json: update documentation for MarshalIndent
Make arguments semantics clear without the need to look for
json.Indent documentation.

Change-Id: If9adfe9f477a30d426ae83790b0f2578c0a809b7
Reviewed-on: https://go-review.googlesource.com/61670
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-09-12 18:12:24 +00:00
Daniel Martí
5d39af9d9b all: remove some unused result params
Most of these are return values that were part of a receiving parameter,
so they're still accessible.

A few others are not, but those have never had a use.

Found with github.com/mvdan/unparam, after Kevin Burke's suggestion that
the tool should also warn about unused result parameters.

Change-Id: Id8b5ed89912a99db22027703a88bd94d0b292b8b
Reviewed-on: https://go-review.googlesource.com/55910
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2017-08-28 06:52:55 +00:00
Joe Tsai
b817359249 encoding/json: ignore embedded fields of pointers to unexported non-structs
https://golang.org/cl/33773 fixes the JSON marshaler to avoid serializing
embedded fields on unexported types of non-struct types. However, Go allows
embedding pointer to types, so the check for whether the field is a non-struct
type must first dereference the pointer to get at the underlying type.

Furthermore, due to a edge-case in the behavior of StructField.PkgPath not
being a reliable indicator of whether the field is unexported (see #21122),
we use our own logic to determine whether the field is exported or not.

The logic in this CL may be simplified depending on what happens in #21122.

Fixes #21121
Updates #21122

Change-Id: I8dfd1cdfac8a87950df294a566fb96dfd04fd749
Reviewed-on: https://go-review.googlesource.com/50711
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-07-22 01:29:58 +00:00
thoeni
296b35382c encoding/json: don't marshal unexported embedded fields of non struct type
Marshal must process unexported embedded fields of struct type,
looking for exported fields in those structs. However, it must
not process unexported embedded fields of non-struct type.

For example, consider:

    type t1 struct {
        X int
    }
    type t2 int
    type T struct {
        t1
        t2
    }

When considering T, Marshal must process t1 to find t1.X.
Marshal must not process t2, but it was. Fix that.

Fixes #18009

Change-Id: I62ba0b65ba30fd927990e101a26405a9998787a3
Reviewed-on: https://go-review.googlesource.com/33773
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
2017-06-14 19:01:08 +00:00
Bryan C. Mills
d6ce7e4fec encoding/json: replace encoderCache RWMutex with a sync.Map
This provides a moderate speedup for encoding when using many CPU cores.

name                    old time/op    new time/op    delta
CodeEncoder               14.1ms ±10%    13.5ms ± 4%      ~     (p=0.867 n=8+7)
CodeEncoder-6             2.58ms ± 8%    2.72ms ± 6%      ~     (p=0.065 n=8+8)
CodeEncoder-48             629µs ± 1%     629µs ± 1%      ~     (p=0.867 n=8+7)
CodeMarshal               14.9ms ± 5%    14.9ms ± 5%      ~     (p=0.721 n=8+8)
CodeMarshal-6             3.28ms ±11%    3.24ms ±12%      ~     (p=0.798 n=8+8)
CodeMarshal-48             739µs ± 1%     745µs ± 2%      ~     (p=0.328 n=8+8)
CodeDecoder               49.7ms ± 4%    49.2ms ± 4%      ~     (p=0.463 n=7+8)
CodeDecoder-6             10.1ms ± 8%    10.4ms ± 3%      ~     (p=0.232 n=7+8)
CodeDecoder-48            2.60ms ± 3%    2.61ms ± 2%      ~     (p=1.000 n=8+8)
DecoderStream              352ns ± 5%     344ns ± 4%      ~     (p=0.077 n=8+8)
DecoderStream-6            485ns ± 8%     503ns ± 6%      ~     (p=0.123 n=8+8)
DecoderStream-48           522ns ± 7%     520ns ± 5%      ~     (p=0.959 n=8+8)
CodeUnmarshal             52.2ms ± 5%    54.4ms ±18%      ~     (p=0.955 n=7+8)
CodeUnmarshal-6           12.4ms ± 6%    12.3ms ± 6%      ~     (p=0.878 n=8+8)
CodeUnmarshal-48          3.46ms ± 7%    3.40ms ± 9%      ~     (p=0.442 n=8+8)
CodeUnmarshalReuse        48.9ms ± 6%    50.3ms ± 7%      ~     (p=0.279 n=8+8)
CodeUnmarshalReuse-6      10.3ms ±11%    10.3ms ±10%      ~     (p=0.959 n=8+8)
CodeUnmarshalReuse-48     2.68ms ± 3%    2.67ms ± 4%      ~     (p=0.878 n=8+8)
UnmarshalString            476ns ± 7%     474ns ± 7%      ~     (p=0.644 n=8+8)
UnmarshalString-6          164ns ± 9%     160ns ±10%      ~     (p=0.556 n=8+8)
UnmarshalString-48         181ns ± 0%     177ns ± 2%    -2.36%  (p=0.001 n=7+7)
UnmarshalFloat64           414ns ± 4%     418ns ± 4%      ~     (p=0.382 n=8+8)
UnmarshalFloat64-6         147ns ± 9%     143ns ±16%      ~     (p=0.457 n=8+8)
UnmarshalFloat64-48        176ns ± 2%     174ns ± 2%      ~     (p=0.118 n=8+8)
UnmarshalInt64             369ns ± 4%     354ns ± 1%    -3.85%  (p=0.005 n=8+7)
UnmarshalInt64-6           132ns ±11%     132ns ±10%      ~     (p=0.982 n=8+8)
UnmarshalInt64-48          177ns ± 3%     174ns ± 2%    -1.84%  (p=0.028 n=8+7)
Issue10335                 540ns ± 5%     535ns ± 0%      ~     (p=0.330 n=7+7)
Issue10335-6               159ns ± 8%     164ns ± 8%      ~     (p=0.246 n=8+8)
Issue10335-48              186ns ± 1%     182ns ± 2%    -1.89%  (p=0.010 n=8+8)
Unmapped                  1.74µs ± 2%    1.76µs ± 6%      ~     (p=0.181 n=6+8)
Unmapped-6                 414ns ± 5%     402ns ±10%      ~     (p=0.244 n=7+8)
Unmapped-48                226ns ± 2%     224ns ± 2%      ~     (p=0.144 n=7+8)
NumberIsValid             20.1ns ± 4%    19.7ns ± 3%      ~     (p=0.204 n=8+8)
NumberIsValid-6           20.4ns ± 8%    22.2ns ±16%      ~     (p=0.129 n=7+8)
NumberIsValid-48          23.1ns ±12%    23.8ns ± 8%      ~     (p=0.104 n=8+8)
NumberIsValidRegexp        629ns ± 5%     622ns ± 0%      ~     (p=0.148 n=7+7)
NumberIsValidRegexp-6      757ns ± 2%     725ns ±14%      ~     (p=0.351 n=8+7)
NumberIsValidRegexp-48     757ns ± 2%     723ns ±13%      ~     (p=0.521 n=8+8)
SkipValue                 13.2ms ± 9%    13.3ms ± 1%      ~     (p=0.130 n=8+8)
SkipValue-6               15.1ms ±10%    14.8ms ± 2%      ~     (p=0.397 n=7+8)
SkipValue-48              13.9ms ±12%    14.3ms ± 1%      ~     (p=0.694 n=8+7)
EncoderEncode              433ns ± 4%     410ns ± 3%    -5.48%  (p=0.001 n=8+8)
EncoderEncode-6            221ns ±15%      75ns ± 5%   -66.15%  (p=0.000 n=7+8)
EncoderEncode-48           161ns ± 4%      19ns ± 7%   -88.29%  (p=0.000 n=7+8)

name                    old speed      new speed      delta
CodeEncoder              139MB/s ±10%   144MB/s ± 4%      ~     (p=0.844 n=8+7)
CodeEncoder-6            756MB/s ± 8%   714MB/s ± 6%      ~     (p=0.065 n=8+8)
CodeEncoder-48          3.08GB/s ± 1%  3.09GB/s ± 1%      ~     (p=0.867 n=8+7)
CodeMarshal              130MB/s ± 5%   130MB/s ± 5%      ~     (p=0.721 n=8+8)
CodeMarshal-6            594MB/s ±10%   601MB/s ±11%      ~     (p=0.798 n=8+8)
CodeMarshal-48          2.62GB/s ± 1%  2.60GB/s ± 2%      ~     (p=0.328 n=8+8)
CodeDecoder             39.0MB/s ± 4%  39.5MB/s ± 4%      ~     (p=0.463 n=7+8)
CodeDecoder-6            189MB/s ±13%   187MB/s ± 3%      ~     (p=0.505 n=8+8)
CodeDecoder-48           746MB/s ± 2%   745MB/s ± 2%      ~     (p=1.000 n=8+8)
CodeUnmarshal           37.2MB/s ± 5%  35.9MB/s ±16%      ~     (p=0.955 n=7+8)
CodeUnmarshal-6          157MB/s ± 6%   158MB/s ± 6%      ~     (p=0.878 n=8+8)
CodeUnmarshal-48         561MB/s ± 7%   572MB/s ±10%      ~     (p=0.442 n=8+8)
SkipValue                141MB/s ±10%   139MB/s ± 1%      ~     (p=0.130 n=8+8)
SkipValue-6              131MB/s ± 3%   133MB/s ± 2%      ~     (p=0.662 n=6+8)
SkipValue-48             138MB/s ±11%   132MB/s ± 1%      ~     (p=0.281 n=8+7)

name                    old alloc/op   new alloc/op   delta
CodeEncoder               45.9kB ± 0%    45.9kB ± 0%    -0.02%  (p=0.002 n=7+8)
CodeEncoder-6             55.1kB ± 0%    55.1kB ± 0%    -0.01%  (p=0.002 n=7+8)
CodeEncoder-48             110kB ± 0%     110kB ± 0%    -0.00%  (p=0.030 n=7+8)
CodeMarshal               4.59MB ± 0%    4.59MB ± 0%    -0.00%  (p=0.000 n=8+8)
CodeMarshal-6             4.59MB ± 0%    4.59MB ± 0%    -0.00%  (p=0.000 n=8+8)
CodeMarshal-48            4.59MB ± 0%    4.59MB ± 0%    -0.00%  (p=0.001 n=7+8)
CodeDecoder               2.28MB ± 5%    2.21MB ± 0%      ~     (p=0.257 n=8+7)
CodeDecoder-6             2.43MB ±11%    2.51MB ± 0%      ~     (p=0.473 n=8+8)
CodeDecoder-48            2.93MB ± 0%    2.93MB ± 0%      ~     (p=0.554 n=7+8)
DecoderStream              16.0B ± 0%     16.0B ± 0%      ~     (all equal)
DecoderStream-6            16.0B ± 0%     16.0B ± 0%      ~     (all equal)
DecoderStream-48           16.0B ± 0%     16.0B ± 0%      ~     (all equal)
CodeUnmarshal             3.28MB ± 0%    3.28MB ± 0%      ~     (p=1.000 n=7+7)
CodeUnmarshal-6           3.28MB ± 0%    3.28MB ± 0%      ~     (p=0.593 n=8+8)
CodeUnmarshal-48          3.28MB ± 0%    3.28MB ± 0%      ~     (p=0.670 n=8+8)
CodeUnmarshalReuse        1.87MB ± 0%    1.88MB ± 1%    +0.48%  (p=0.011 n=7+8)
CodeUnmarshalReuse-6      1.90MB ± 1%    1.90MB ± 1%      ~     (p=0.589 n=8+8)
CodeUnmarshalReuse-48     1.96MB ± 0%    1.96MB ± 0%    +0.00%  (p=0.002 n=7+8)
UnmarshalString             304B ± 0%      304B ± 0%      ~     (all equal)
UnmarshalString-6           304B ± 0%      304B ± 0%      ~     (all equal)
UnmarshalString-48          304B ± 0%      304B ± 0%      ~     (all equal)
UnmarshalFloat64            292B ± 0%      292B ± 0%      ~     (all equal)
UnmarshalFloat64-6          292B ± 0%      292B ± 0%      ~     (all equal)
UnmarshalFloat64-48         292B ± 0%      292B ± 0%      ~     (all equal)
UnmarshalInt64              289B ± 0%      289B ± 0%      ~     (all equal)
UnmarshalInt64-6            289B ± 0%      289B ± 0%      ~     (all equal)
UnmarshalInt64-48           289B ± 0%      289B ± 0%      ~     (all equal)
Issue10335                  312B ± 0%      312B ± 0%      ~     (all equal)
Issue10335-6                312B ± 0%      312B ± 0%      ~     (all equal)
Issue10335-48               312B ± 0%      312B ± 0%      ~     (all equal)
Unmapped                    344B ± 0%      344B ± 0%      ~     (all equal)
Unmapped-6                  344B ± 0%      344B ± 0%      ~     (all equal)
Unmapped-48                 344B ± 0%      344B ± 0%      ~     (all equal)
NumberIsValid              0.00B          0.00B           ~     (all equal)
NumberIsValid-6            0.00B          0.00B           ~     (all equal)
NumberIsValid-48           0.00B          0.00B           ~     (all equal)
NumberIsValidRegexp        0.00B          0.00B           ~     (all equal)
NumberIsValidRegexp-6      0.00B          0.00B           ~     (all equal)
NumberIsValidRegexp-48     0.00B          0.00B           ~     (all equal)
SkipValue                  0.00B          0.00B           ~     (all equal)
SkipValue-6                0.00B          0.00B           ~     (all equal)
SkipValue-48              15.0B ±167%      0.0B           ~     (p=0.200 n=8+8)
EncoderEncode              8.00B ± 0%     0.00B       -100.00%  (p=0.000 n=8+8)
EncoderEncode-6            8.00B ± 0%     0.00B       -100.00%  (p=0.000 n=8+8)
EncoderEncode-48           8.00B ± 0%     0.00B       -100.00%  (p=0.000 n=8+8)

name                    old allocs/op  new allocs/op  delta
CodeEncoder                 1.00 ± 0%      0.00       -100.00%  (p=0.000 n=8+8)
CodeEncoder-6               1.00 ± 0%      0.00       -100.00%  (p=0.000 n=8+8)
CodeEncoder-48              1.00 ± 0%      0.00       -100.00%  (p=0.000 n=8+8)
CodeMarshal                 17.0 ± 0%      16.0 ± 0%    -5.88%  (p=0.000 n=8+8)
CodeMarshal-6               17.0 ± 0%      16.0 ± 0%    -5.88%  (p=0.000 n=8+8)
CodeMarshal-48              17.0 ± 0%      16.0 ± 0%    -5.88%  (p=0.000 n=8+8)
CodeDecoder                89.6k ± 0%     89.5k ± 0%      ~     (p=0.154 n=8+7)
CodeDecoder-6              89.8k ± 0%     89.9k ± 0%      ~     (p=0.467 n=8+8)
CodeDecoder-48             90.5k ± 0%     90.5k ± 0%      ~     (p=0.533 n=8+7)
DecoderStream               2.00 ± 0%      2.00 ± 0%      ~     (all equal)
DecoderStream-6             2.00 ± 0%      2.00 ± 0%      ~     (all equal)
DecoderStream-48            2.00 ± 0%      2.00 ± 0%      ~     (all equal)
CodeUnmarshal               105k ± 0%      105k ± 0%      ~     (all equal)
CodeUnmarshal-6             105k ± 0%      105k ± 0%      ~     (all equal)
CodeUnmarshal-48            105k ± 0%      105k ± 0%      ~     (all equal)
CodeUnmarshalReuse         89.5k ± 0%     89.6k ± 0%      ~     (p=0.246 n=7+8)
CodeUnmarshalReuse-6       89.8k ± 0%     89.8k ± 0%      ~     (p=1.000 n=8+8)
CodeUnmarshalReuse-48      90.5k ± 0%     90.5k ± 0%      ~     (all equal)
UnmarshalString             2.00 ± 0%      2.00 ± 0%      ~     (all equal)
UnmarshalString-6           2.00 ± 0%      2.00 ± 0%      ~     (all equal)
UnmarshalString-48          2.00 ± 0%      2.00 ± 0%      ~     (all equal)
UnmarshalFloat64            2.00 ± 0%      2.00 ± 0%      ~     (all equal)
UnmarshalFloat64-6          2.00 ± 0%      2.00 ± 0%      ~     (all equal)
UnmarshalFloat64-48         2.00 ± 0%      2.00 ± 0%      ~     (all equal)
UnmarshalInt64              2.00 ± 0%      2.00 ± 0%      ~     (all equal)
UnmarshalInt64-6            2.00 ± 0%      2.00 ± 0%      ~     (all equal)
UnmarshalInt64-48           2.00 ± 0%      2.00 ± 0%      ~     (all equal)
Issue10335                  3.00 ± 0%      3.00 ± 0%      ~     (all equal)
Issue10335-6                3.00 ± 0%      3.00 ± 0%      ~     (all equal)
Issue10335-48               3.00 ± 0%      3.00 ± 0%      ~     (all equal)
Unmapped                    4.00 ± 0%      4.00 ± 0%      ~     (all equal)
Unmapped-6                  4.00 ± 0%      4.00 ± 0%      ~     (all equal)
Unmapped-48                 4.00 ± 0%      4.00 ± 0%      ~     (all equal)
NumberIsValid               0.00           0.00           ~     (all equal)
NumberIsValid-6             0.00           0.00           ~     (all equal)
NumberIsValid-48            0.00           0.00           ~     (all equal)
NumberIsValidRegexp         0.00           0.00           ~     (all equal)
NumberIsValidRegexp-6       0.00           0.00           ~     (all equal)
NumberIsValidRegexp-48      0.00           0.00           ~     (all equal)
SkipValue                   0.00           0.00           ~     (all equal)
SkipValue-6                 0.00           0.00           ~     (all equal)
SkipValue-48                0.00           0.00           ~     (all equal)
EncoderEncode               1.00 ± 0%      0.00       -100.00%  (p=0.000 n=8+8)
EncoderEncode-6             1.00 ± 0%      0.00       -100.00%  (p=0.000 n=8+8)
EncoderEncode-48            1.00 ± 0%      0.00       -100.00%  (p=0.000 n=8+8)

https://perf.golang.org/search?q=upload:20170427.2

updates #17973
updates #18177

Change-Id: I5881c7a2bfad1766e6aa3444bb630883e0be467b
Reviewed-on: https://go-review.googlesource.com/41931
Run-TryBot: Bryan Mills <bcmills@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2017-04-28 20:19:10 +00:00
Russ Cox
9073af247d encoding/json: document what happens to MarshalText's result
Fixes #17743.

Change-Id: Ib5afb6248bb060f2ad8dd3d5f78e95271af62a57
Reviewed-on: https://go-review.googlesource.com/33135
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Quentin Smith <quentin@golang.org>
Reviewed-by: Caleb Spare <cespare@gmail.com>
2016-11-22 01:32:20 +00:00
Emmanuel Odeke
add721ef91 encoding/json: encode nil Marshaler as "null"
Fixes #16042.

Change-Id: I0a28aa004246b7b0ffaaab457e077ad9035363c2
Reviewed-on: https://go-review.googlesource.com/31932
Reviewed-by: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-11-11 14:50:51 +00:00
Richard Gibson
20c48c9557 encoding/json: explicitly document and test "-" key tag
Struct fields can be suppressed in JSON serialization by "-" tags, but
that doesn't preclude generation of "-" object keys.
Document and verify the mechanism for doing so.

Change-Id: I7f60e1759cfee15cb7b2447cd35fab91c5b004e6
Reviewed-on: https://go-review.googlesource.com/21204
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-10-06 14:42:16 +00:00