mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 18:32:25 -06:00 
			
		
		
		
	
		
			
				
	
	
		
			193 lines
		
	
	
		
			No EOL
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			193 lines
		
	
	
		
			No EOL
		
	
	
		
			4.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
 * 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)
 | 
						|
} |