/* * Copyright 2021 ByteDance Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package encoder import ( `bytes` `sync` `unsafe` `errors` `reflect` `github.com/bytedance/sonic/internal/caching` `github.com/bytedance/sonic/option` `github.com/bytedance/sonic/internal/rt` ) const ( _MaxStack = 4096 // 4k states _StackSize = unsafe.Sizeof(_Stack{}) ) var ( bytesPool = sync.Pool{} stackPool = sync.Pool{} bufferPool = sync.Pool{} programCache = caching.CreateProgramCache() ) type _State struct { x int f uint64 p unsafe.Pointer q unsafe.Pointer } type _Stack struct { sp uint64 sb [_MaxStack]_State } type _Encoder func( rb *[]byte, vp unsafe.Pointer, sb *_Stack, fv uint64, ) error var _KeepAlive struct { rb *[]byte vp unsafe.Pointer sb *_Stack fv uint64 err error frame [_FP_offs]byte } var errCallShadow = errors.New("DON'T CALL THIS!") // Faker func of _Encoder, used to export its stackmap as _Encoder's func _Encoder_Shadow(rb *[]byte, vp unsafe.Pointer, sb *_Stack, fv uint64) (err error) { // align to assembler_amd64.go: _FP_offs var frame [_FP_offs]byte // must keep all args and frames noticeable to GC _KeepAlive.rb = rb _KeepAlive.vp = vp _KeepAlive.sb = sb _KeepAlive.fv = fv _KeepAlive.err = err _KeepAlive.frame = frame return errCallShadow } func newBytes() []byte { if ret := bytesPool.Get(); ret != nil { return ret.([]byte) } else { return make([]byte, 0, option.DefaultEncoderBufferSize) } } func newStack() *_Stack { if ret := stackPool.Get(); ret == nil { return new(_Stack) } else { return ret.(*_Stack) } } func resetStack(p *_Stack) { memclrNoHeapPointers(unsafe.Pointer(p), _StackSize) } func newBuffer() *bytes.Buffer { if ret := bufferPool.Get(); ret != nil { return ret.(*bytes.Buffer) } else { return bytes.NewBuffer(make([]byte, 0, option.DefaultEncoderBufferSize)) } } func freeBytes(p []byte) { p = p[:0] bytesPool.Put(p) } func freeStack(p *_Stack) { p.sp = 0 stackPool.Put(p) } func freeBuffer(p *bytes.Buffer) { p.Reset() bufferPool.Put(p) } func makeEncoder(vt *rt.GoType, ex ...interface{}) (interface{}, error) { if pp, err := newCompiler().compile(vt.Pack(), ex[0].(bool)); err != nil { return nil, err } else { as := newAssembler(pp) as.name = vt.String() return as.Load(), nil } } func findOrCompile(vt *rt.GoType, pv bool) (_Encoder, error) { if val := programCache.Get(vt); val != nil { return val.(_Encoder), nil } else if ret, err := programCache.Compute(vt, makeEncoder, pv); err == nil { return ret.(_Encoder), nil } else { return nil, err } } func pretouchType(_vt reflect.Type, opts option.CompileOptions, v uint8) (map[reflect.Type]uint8, error) { /* compile function */ compiler := newCompiler().apply(opts) encoder := func(vt *rt.GoType, ex ...interface{}) (interface{}, error) { if pp, err := compiler.compile(_vt, ex[0].(bool)); err != nil { return nil, err } else { as := newAssembler(pp) as.name = vt.String() return as.Load(), nil } } /* find or compile */ vt := rt.UnpackType(_vt) if val := programCache.Get(vt); val != nil { return nil, nil } else if _, err := programCache.Compute(vt, encoder, v == 1); err == nil { return compiler.rec, nil } else { return nil, err } } func pretouchRec(vtm map[reflect.Type]uint8, opts option.CompileOptions) error { if opts.RecursiveDepth < 0 || len(vtm) == 0 { return nil } next := make(map[reflect.Type]uint8) for vt, v := range vtm { sub, err := pretouchType(vt, opts, v) if err != nil { return err } for svt, v := range sub { next[svt] = v } } opts.RecursiveDepth -= 1 return pretouchRec(next, opts) }