github.com/bytedance/sonic@v1.11.7-0.20240517092252-d2edb31b167b/internal/encoder/pools.go (about)

     1  /*
     2   * Copyright 2021 ByteDance Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package encoder
    18  
    19  import (
    20      `bytes`
    21      `sync`
    22      `unsafe`
    23      `errors`
    24      `reflect`
    25  
    26      `github.com/bytedance/sonic/internal/caching`
    27      `github.com/bytedance/sonic/option`
    28      `github.com/bytedance/sonic/internal/rt`
    29  )
    30  
    31  const (
    32      _MaxStack  = 4096      // 4k states
    33  
    34      _StackSize = unsafe.Sizeof(_Stack{})
    35  )
    36  
    37  var (
    38      bytesPool    = sync.Pool{}
    39      stackPool    = sync.Pool{}
    40      bufferPool   = sync.Pool{}
    41      programCache = caching.CreateProgramCache()
    42  )
    43  
    44  type _State struct {
    45      x int
    46      f uint64
    47      p unsafe.Pointer
    48      q unsafe.Pointer
    49  }
    50  
    51  type _Stack struct {
    52      sp uint64
    53      sb [_MaxStack]_State
    54  }
    55  
    56  type _Encoder func(
    57      rb *[]byte,
    58      vp unsafe.Pointer,
    59      sb *_Stack,
    60      fv uint64,
    61  ) error
    62  
    63  var _KeepAlive struct {
    64      rb *[]byte
    65      vp unsafe.Pointer
    66      sb *_Stack
    67      fv uint64
    68      err error
    69      frame [_FP_offs]byte
    70  }
    71  
    72  var errCallShadow = errors.New("DON'T CALL THIS!")
    73  
    74  // Faker func of _Encoder, used to export its stackmap as _Encoder's
    75  func _Encoder_Shadow(rb *[]byte, vp unsafe.Pointer, sb *_Stack, fv uint64) (err error) {
    76      // align to assembler_amd64.go: _FP_offs
    77      var frame [_FP_offs]byte
    78  
    79      // must keep all args and frames noticeable to GC
    80      _KeepAlive.rb = rb
    81      _KeepAlive.vp = vp
    82      _KeepAlive.sb = sb
    83      _KeepAlive.fv = fv
    84      _KeepAlive.err = err
    85      _KeepAlive.frame = frame
    86  
    87      return errCallShadow
    88  }
    89  
    90  func newBytes() []byte {
    91      if ret := bytesPool.Get(); ret != nil {
    92          return ret.([]byte)
    93      } else {
    94          return make([]byte, 0, option.DefaultEncoderBufferSize)
    95      }
    96  }
    97  
    98  func newStack() *_Stack {
    99      if ret := stackPool.Get(); ret == nil {
   100          return new(_Stack)
   101      } else {
   102          return ret.(*_Stack)
   103      }
   104  }
   105  
   106  func resetStack(p *_Stack) {
   107      memclrNoHeapPointers(unsafe.Pointer(p), _StackSize)
   108  }
   109  
   110  func newBuffer() *bytes.Buffer {
   111      if ret := bufferPool.Get(); ret != nil {
   112          return ret.(*bytes.Buffer)
   113      } else {
   114          return bytes.NewBuffer(make([]byte, 0, option.DefaultEncoderBufferSize))
   115      }
   116  }
   117  
   118  func freeBytes(p []byte) {
   119      p = p[:0]
   120      bytesPool.Put(p)
   121  }
   122  
   123  func freeStack(p *_Stack) {
   124      p.sp = 0
   125      stackPool.Put(p)
   126  }
   127  
   128  func freeBuffer(p *bytes.Buffer) {
   129      p.Reset()
   130      bufferPool.Put(p)
   131  }
   132  
   133  func makeEncoder(vt *rt.GoType, ex ...interface{}) (interface{}, error) {
   134      if pp, err := newCompiler().compile(vt.Pack(), ex[0].(bool)); err != nil {
   135          return nil, err
   136      } else {
   137          as := newAssembler(pp)
   138          as.name = vt.String()
   139          return as.Load(), nil
   140      }
   141  }
   142  
   143  func findOrCompile(vt *rt.GoType, pv bool) (_Encoder, error) {
   144      if val := programCache.Get(vt); val != nil {
   145          return val.(_Encoder), nil
   146      } else if ret, err := programCache.Compute(vt, makeEncoder, pv); err == nil {
   147          return ret.(_Encoder), nil
   148      } else {
   149          return nil, err
   150      }
   151  }
   152  
   153  func pretouchType(_vt reflect.Type, opts option.CompileOptions, v uint8) (map[reflect.Type]uint8, error) {
   154      /* compile function */
   155      compiler := newCompiler().apply(opts)
   156      encoder := func(vt *rt.GoType, ex ...interface{}) (interface{}, error) {
   157          if pp, err := compiler.compile(_vt, ex[0].(bool)); err != nil {
   158              return nil, err
   159          } else {
   160              as := newAssembler(pp)
   161              as.name = vt.String()
   162              return as.Load(), nil
   163          }
   164      }
   165  
   166      /* find or compile */
   167      vt := rt.UnpackType(_vt)
   168      if val := programCache.Get(vt); val != nil {
   169          return nil, nil
   170      } else if _, err := programCache.Compute(vt, encoder, v == 1); err == nil {
   171          return compiler.rec, nil
   172      } else {
   173          return nil, err
   174      }
   175  }
   176  
   177  func pretouchRec(vtm map[reflect.Type]uint8, opts option.CompileOptions) error {
   178      if opts.RecursiveDepth < 0 || len(vtm) == 0 {
   179          return nil
   180      }
   181      next := make(map[reflect.Type]uint8)
   182      for vt, v := range vtm {
   183          sub, err := pretouchType(vt, opts, v)
   184          if err != nil {
   185              return err
   186          }
   187          for svt, v := range sub {
   188              next[svt] = v
   189          }
   190      }
   191      opts.RecursiveDepth -= 1
   192      return pretouchRec(next, opts)
   193  }