Skip to content

Commit

Permalink
fix: free the large buffer from pool (#369)
Browse files Browse the repository at this point in the history
Co-authored-by: liuqiang <liuqiang.06@bytedance.com>
  • Loading branch information
liuq19 and liuq19 authored Feb 24, 2023
1 parent e60b954 commit 3696f91
Showing 1 changed file with 33 additions and 16 deletions.
49 changes: 33 additions & 16 deletions encoder/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
`encoding/json`
`reflect`
`runtime`
`unsafe`

`github.com/bytedance/sonic/internal/native`
`github.com/bytedance/sonic/internal/native/types`
Expand Down Expand Up @@ -161,21 +162,31 @@ func Quote(s string) string {

// Encode returns the JSON encoding of val, encoded with opts.
func Encode(val interface{}, opts Options) ([]byte, error) {
var ret []byte

buf := newBytes()
err := EncodeInto(&buf, val, opts)
err := encodeInto(&buf, val, opts)

/* check for errors */
if err != nil {
freeBytes(buf)
return nil, err
}

if opts & EscapeHTML != 0 || opts & ValidateString != 0 {
/* htmlescape or correct UTF-8 if opts enable */
old := buf
buf = encodeFinish(old, opts)
pbuf := ((*rt.GoSlice)(unsafe.Pointer(&buf))).Ptr
pold := ((*rt.GoSlice)(unsafe.Pointer(&old))).Ptr

/* return when allocated a new buffer */
if pbuf != pold {
freeBytes(old)
return buf, nil
}

/* make a copy of the result */
ret := make([]byte, len(buf))
ret = make([]byte, len(buf))
copy(ret, buf)

freeBytes(buf)
Expand All @@ -186,6 +197,15 @@ func Encode(val interface{}, opts Options) ([]byte, error) {
// EncodeInto is like Encode but uses a user-supplied buffer instead of allocating
// a new one.
func EncodeInto(buf *[]byte, val interface{}, opts Options) error {
err := encodeInto(buf, val, opts)
if err != nil {
return err
}
*buf = encodeFinish(*buf, opts)
return err
}

func encodeInto(buf *[]byte, val interface{}, opts Options) error {
stk := newStack()
efv := rt.UnpackEface(val)
err := encodeTypedPointer(buf, efv.Type, &efv.Value, stk, uint64(opts))
Expand All @@ -196,25 +216,22 @@ func EncodeInto(buf *[]byte, val interface{}, opts Options) error {
}
freeStack(stk)

/* EscapeHTML needs to allocate a new buffer*/
if opts & EscapeHTML != 0 {
dest := HTMLEscape(nil, *buf)
freeBytes(*buf) // free origin used buffer
*buf = dest
}

if opts & ValidateString != 0 && !utf8.Validate(*buf) {
dest := utf8.CorrectWith(nil, *buf, `\ufffd`)
freeBytes(*buf) // free origin used buffer
*buf = dest
}

/* avoid GC ahead */
runtime.KeepAlive(buf)
runtime.KeepAlive(efv)
return err
}

func encodeFinish(buf []byte, opts Options) []byte {
if opts & EscapeHTML != 0 {
buf = HTMLEscape(nil, buf)
}
if opts & ValidateString != 0 && !utf8.Validate(buf) {
buf = utf8.CorrectWith(nil, buf, `\ufffd`)
}
return buf
}

var typeByte = rt.UnpackType(reflect.TypeOf(byte(0)))

// HTMLEscape appends to dst the JSON-encoded src with <, >, &, U+2028 and U+2029
Expand Down

0 comments on commit 3696f91

Please sign in to comment.