github.com/goshafaq/sonic@v0.0.0-20231026082336-871835fb94c6/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  	"errors"
    22  	"reflect"
    23  	"sync"
    24  	"unsafe"
    25  
    26  	"github.com/goshafaq/sonic/internal/caching"
    27  	"github.com/goshafaq/sonic/internal/rt"
    28  	"github.com/goshafaq/sonic/option"
    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  }