diff --git a/internal/encoding/json/encode.go b/internal/encoding/json/encode.go
index 643d5077..dd4a1aa4 100644
--- a/internal/encoding/json/encode.go
+++ b/internal/encoding/json/encode.go
@@ -481,10 +481,13 @@ func marshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
b, err := m.MarshalJSON()
if err == nil {
- e.Grow(len(b))
- out := e.AvailableBuffer()
- out, err = appendCompact(out, b, opts.escapeHTML)
- e.Buffer.Write(out)
+ // EDIT(begin): skip appendCompact validation - MarshalJSON output is already valid compact JSON.
+ // appendCompact scans every byte to validate/compact, which is O(n) per nested MarshalJSON call.
+ // For deeply nested structures this becomes a significant bottleneck.
+ // HTML escaping is also skipped because MarshalJSON implementations in this SDK use Marshal()
+ // internally, which already performs HTML escaping when escapeHTML is enabled (the default).
+ e.Buffer.Write(b)
+ // EDIT(end)
}
if err != nil {
e.error(&MarshalerError{v.Type(), err, "MarshalJSON"})
@@ -507,10 +510,11 @@ func addrMarshalerEncoder(e *encodeState, v reflect.Value, opts encOpts) {
m := va.Interface().(Marshaler)
b, err := m.MarshalJSON()
if err == nil {
- e.Grow(len(b))
- out := e.AvailableBuffer()
- out, err = appendCompact(out, b, opts.escapeHTML)
- e.Buffer.Write(out)
+ // EDIT(begin): skip appendCompact validation - MarshalJSON output is already valid compact JSON.
+ // HTML escaping is also skipped because MarshalJSON implementations in this SDK use Marshal()
+ // internally, which already performs HTML escaping when escapeHTML is enabled (the default).
+ e.Buffer.Write(b)
+ // EDIT(end)
}
if err != nil {
e.error(&MarshalerError{v.Type(), err, "MarshalJSON"})
diff --git a/internal/encoding/json/encode_test.go b/internal/encoding/json/encode_test.go
new file mode 100644
index 00000000..1904835c
--- /dev/null
+++ b/internal/encoding/json/encode_test.go
@@ -0,0 +1,199 @@
+package json
+
+import (
+ "bytes"
+ "strings"
+ "testing"
+)
+
+// Inner implements MarshalJSON to trigger the optimized code path
+type benchInner struct {
+ Name string `json:"name"`
+ Value int `json:"value"`
+}
+
+func (b benchInner) MarshalJSON() ([]byte, error) {
+ return Marshal(struct {
+ Name string `json:"name"`
+ Value int `json:"value"`
+ }{b.Name, b.Value})
+}
+
+// Nested structure with multiple MarshalJSON calls
+type benchNested struct {
+ Inner benchInner `json:"inner"`
+ Items []int `json:"items"`
+}
+
+func (b benchNested) MarshalJSON() ([]byte, error) {
+ return Marshal(struct {
+ Inner benchInner `json:"inner"`
+ Items []int `json:"items"`
+ }{b.Inner, b.Items})
+}
+
+// Deeply nested to amplify the effect
+type benchDeep struct {
+ Level1 benchNested `json:"level1"`
+ Level2 benchNested `json:"level2"`
+ Data string `json:"data"`
+}
+
+func (b benchDeep) MarshalJSON() ([]byte, error) {
+ return Marshal(struct {
+ Level1 benchNested `json:"level1"`
+ Level2 benchNested `json:"level2"`
+ Data string `json:"data"`
+ }{b.Level1, b.Level2, b.Data})
+}
+
+func BenchmarkMarshalNestedMarshalJSON(b *testing.B) {
+ data := benchDeep{
+ Level1: benchNested{
+ Inner: benchInner{Name: "test1", Value: 100},
+ Items: []int{1, 2, 3, 4, 5},
+ },
+ Level2: benchNested{
+ Inner: benchInner{Name: "test2", Value: 200},
+ Items: []int{6, 7, 8, 9, 10},
+ },
+ Data: "some test data here",
+ }
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, err := Marshal(data)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+// Slice of nested structs - common real-world pattern
+func BenchmarkMarshalSliceOfNestedMarshalJSON(b *testing.B) {
+ data := make([]benchDeep, 50)
+ for i := range data {
+ data[i] = benchDeep{
+ Level1: benchNested{
+ Inner: benchInner{Name: "test1", Value: i},
+ Items: []int{1, 2, 3, 4, 5},
+ },
+ Level2: benchNested{
+ Inner: benchInner{Name: "test2", Value: i * 2},
+ Items: []int{6, 7, 8, 9, 10},
+ },
+ Data: "some test data here that is a bit longer to simulate real payloads",
+ }
+ }
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, err := Marshal(data)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+// Test that HTML escaping is preserved for nested MarshalJSON calls
+type htmlTestInner struct {
+ Content string `json:"content"`
+}
+
+func (h htmlTestInner) MarshalJSON() ([]byte, error) {
+ return Marshal(struct {
+ Content string `json:"content"`
+ }{h.Content})
+}
+
+type htmlTestOuter struct {
+ Inner htmlTestInner `json:"inner"`
+}
+
+func (h htmlTestOuter) MarshalJSON() ([]byte, error) {
+ return Marshal(struct {
+ Inner htmlTestInner `json:"inner"`
+ }{h.Inner})
+}
+
+func TestMarshalHTMLEscapeWithNestedMarshalJSON(t *testing.T) {
+ // Test that HTML-sensitive characters are escaped in nested MarshalJSON
+ data := htmlTestOuter{
+ Inner: htmlTestInner{
+ Content: "",
+ },
+ }
+
+ result, err := Marshal(data)
+ if err != nil {
+ t.Fatalf("Marshal failed: %v", err)
+ }
+
+ // The < and > should be escaped as \u003c and \u003e
+ if strings.Contains(string(result), "