aboutsummaryrefslogtreecommitdiff
path: root/src/encoding
diff options
context:
space:
mode:
authorJoe Tsai <joetsai@digital-static.net>2025-06-30 15:40:20 -0700
committerGopher Robot <gobot@golang.org>2025-06-30 16:52:49 -0700
commit6bd9944c9a9fb6b1da6288358b0620218d621441 (patch)
treefaadc9c53a43aa389c671b6cd6ae8ed6869b0bdc /src/encoding
parente46d586eddfdd2186d77a5e996bbd6415cfcf2f5 (diff)
downloadgo-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.go8
-rw-r--r--src/encoding/json/v2/options.go5
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
}
}