diff options
| author | Joe Tsai <joetsai@digital-static.net> | 2025-06-30 15:40:20 -0700 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2025-06-30 16:52:49 -0700 |
| commit | 6bd9944c9a9fb6b1da6288358b0620218d621441 (patch) | |
| tree | faadc9c53a43aa389c671b6cd6ae8ed6869b0bdc /src/encoding | |
| parent | e46d586eddfdd2186d77a5e996bbd6415cfcf2f5 (diff) | |
| download | go-6bd9944c9a9fb6b1da6288358b0620218d621441.tar.xz | |
encoding/json/v2: avoid escaping jsonopts.Struct
The jsonopts.Struct.join method unfortunately escapes
the receiver because it is passed to JoinUnknownOption,
which is a dynamically implemented function.
This affects jsontext.Encoder.reset and jsontext.Decoder.reset,
which relied on a local jsonopts.Struct to temporarily store
prior options such that it would have to be heap allocated.
Adjust the signature of JoinUnknownOption to avoid pointers
so that nothing escape.
This is a regression from
https://github.com/go-json-experiment/json/pull/163
Performance:
name old time/op new time/op delta
Marshal/Bool-32 72.1ns ± 2% 51.3ns ± 1% -28.77% (p=0.000 n=10+9)
name old allocs/op new allocs/op delta
Marshal/Bool-32 2.00 ± 0% 1.00 ± 0% -50.00% (p=0.000 n=10+10)
Updates #71845
Change-Id: Ife500d82d3d2beb13652553a4ffdf882c136f5a0
Reviewed-on: https://go-review.googlesource.com/c/go/+/685135
Auto-Submit: Joseph Tsai <joetsai@digital-static.net>
Reviewed-by: Damien Neil <dneil@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Diffstat (limited to 'src/encoding')
| -rw-r--r-- | src/encoding/json/internal/jsonopts/options.go | 8 | ||||
| -rw-r--r-- | src/encoding/json/v2/options.go | 5 |
2 files changed, 7 insertions, 6 deletions
diff --git a/src/encoding/json/internal/jsonopts/options.go b/src/encoding/json/internal/jsonopts/options.go index 2226830b6b..e4c3f47d36 100644 --- a/src/encoding/json/internal/jsonopts/options.go +++ b/src/encoding/json/internal/jsonopts/options.go @@ -65,7 +65,7 @@ func (*Struct) JSONOptions(internal.NotForPublicUse) {} // GetUnknownOption is injected by the "json" package to handle Options // declared in that package so that "jsonopts" can handle them. -var GetUnknownOption = func(*Struct, Options) (any, bool) { panic("unknown option") } +var GetUnknownOption = func(Struct, Options) (any, bool) { panic("unknown option") } func GetOption[T any](opts Options, setter func(T) Options) (T, bool) { // Collapse the options to *Struct to simplify lookup. @@ -104,14 +104,14 @@ func GetOption[T any](opts Options, setter func(T) Options) (T, bool) { } return any(structOpts.DepthLimit).(T), true default: - v, ok := GetUnknownOption(structOpts, opt) + v, ok := GetUnknownOption(*structOpts, opt) return v.(T), ok } } // JoinUnknownOption is injected by the "json" package to handle Options // declared in that package so that "jsonopts" can handle them. -var JoinUnknownOption = func(*Struct, Options) { panic("unknown option") } +var JoinUnknownOption = func(Struct, Options) Struct { panic("unknown option") } func (dst *Struct) Join(srcs ...Options) { dst.join(false, srcs...) @@ -182,7 +182,7 @@ func (dst *Struct) join(excludeCoderOptions bool, srcs ...Options) { } } default: - JoinUnknownOption(dst, src) + *dst = JoinUnknownOption(*dst, src) } } } diff --git a/src/encoding/json/v2/options.go b/src/encoding/json/v2/options.go index 12bbdb5d86..0942d2d307 100644 --- a/src/encoding/json/v2/options.go +++ b/src/encoding/json/v2/options.go @@ -257,7 +257,7 @@ func (*unmarshalersOption) JSONOptions(internal.NotForPublicUse) {} // Inject support into "jsonopts" to handle these types. func init() { - jsonopts.GetUnknownOption = func(src *jsonopts.Struct, zero jsonopts.Options) (any, bool) { + jsonopts.GetUnknownOption = func(src jsonopts.Struct, zero jsonopts.Options) (any, bool) { switch zero.(type) { case *marshalersOption: if !src.Flags.Has(jsonflags.Marshalers) { @@ -273,7 +273,7 @@ func init() { panic(fmt.Sprintf("unknown option %T", zero)) } } - jsonopts.JoinUnknownOption = func(dst *jsonopts.Struct, src jsonopts.Options) { + jsonopts.JoinUnknownOption = func(dst jsonopts.Struct, src jsonopts.Options) jsonopts.Struct { switch src := src.(type) { case *marshalersOption: dst.Flags.Set(jsonflags.Marshalers | 1) @@ -284,5 +284,6 @@ func init() { default: panic(fmt.Sprintf("unknown option %T", src)) } + return dst } } |
