summaryrefslogtreecommitdiff
path: root/vendor/github.com/bytedance/sonic/loader
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/bytedance/sonic/loader')
-rw-r--r--vendor/github.com/bytedance/sonic/loader/funcdata.go144
-rw-r--r--vendor/github.com/bytedance/sonic/loader/funcdata_go115.go541
-rw-r--r--vendor/github.com/bytedance/sonic/loader/funcdata_go118.go541
-rw-r--r--vendor/github.com/bytedance/sonic/loader/funcdata_go120.go545
-rw-r--r--vendor/github.com/bytedance/sonic/loader/loader.go37
-rw-r--r--vendor/github.com/bytedance/sonic/loader/loader_go115.go33
-rw-r--r--vendor/github.com/bytedance/sonic/loader/loader_go118.go104
-rw-r--r--vendor/github.com/bytedance/sonic/loader/mmap_unix.go45
-rw-r--r--vendor/github.com/bytedance/sonic/loader/mmap_windows.go84
-rw-r--r--vendor/github.com/bytedance/sonic/loader/pcdata.go100
-rw-r--r--vendor/github.com/bytedance/sonic/loader/stubs.go35
11 files changed, 2209 insertions, 0 deletions
diff --git a/vendor/github.com/bytedance/sonic/loader/funcdata.go b/vendor/github.com/bytedance/sonic/loader/funcdata.go
new file mode 100644
index 000000000..9b760f615
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/loader/funcdata.go
@@ -0,0 +1,144 @@
+/**
+ * Copyright 2023 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 loader
+
+import (
+ `encoding`
+ `encoding/binary`
+ `fmt`
+ `reflect`
+ `strings`
+ `sync`
+ `unsafe`
+)
+
+const (
+ _MinLC uint8 = 1
+ _PtrSize uint8 = 8
+)
+
+const (
+ _N_FUNCDATA = 8
+ _INVALID_FUNCDATA_OFFSET = ^uint32(0)
+ _FUNC_SIZE = unsafe.Sizeof(_func{})
+
+ _MINFUNC = 16 // minimum size for a function
+ _BUCKETSIZE = 256 * _MINFUNC
+ _SUBBUCKETS = 16
+ _SUB_BUCKETSIZE = _BUCKETSIZE / _SUBBUCKETS
+)
+
+// PCDATA and FUNCDATA table indexes.
+//
+// See funcdata.h and $GROOT/src/cmd/internal/objabi/funcdata.go.
+const (
+ _FUNCDATA_ArgsPointerMaps = 0
+ _FUNCDATA_LocalsPointerMaps = 1
+ _FUNCDATA_StackObjects = 2
+ _FUNCDATA_InlTree = 3
+ _FUNCDATA_OpenCodedDeferInfo = 4
+ _FUNCDATA_ArgInfo = 5
+ _FUNCDATA_ArgLiveInfo = 6
+ _FUNCDATA_WrapInfo = 7
+
+ // ArgsSizeUnknown is set in Func.argsize to mark all functions
+ // whose argument size is unknown (C vararg functions, and
+ // assembly code without an explicit specification).
+ // This value is generated by the compiler, assembler, or linker.
+ ArgsSizeUnknown = -0x80000000
+)
+
+// moduledata used to cache the funcdata and findfuncbucket of one module
+var moduleCache = struct {
+ m map[*moduledata][]byte
+ sync.Mutex
+}{
+ m: make(map[*moduledata][]byte),
+}
+
+// Func contains information about a function.
+type Func struct {
+ ID uint8 // see runtime/symtab.go
+ Flag uint8 // see runtime/symtab.go
+ ArgsSize int32 // args byte size
+ EntryOff uint32 // start pc, offset to moduledata.text
+ TextSize uint32 // size of func text
+ DeferReturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
+ FileIndex uint32 // index into filetab
+ Name string // name of function
+
+ // PC data
+ Pcsp *Pcdata // PC -> SP delta
+ Pcfile *Pcdata // PC -> file index
+ Pcline *Pcdata // PC -> line number
+ PcUnsafePoint *Pcdata // PC -> unsafe point, must be PCDATA_UnsafePointSafe or PCDATA_UnsafePointUnsafe
+ PcStackMapIndex *Pcdata // PC -> stack map index, relative to ArgsPointerMaps and LocalsPointerMaps
+ PcInlTreeIndex *Pcdata // PC -> inlining tree index, relative to InlTree
+ PcArgLiveIndex *Pcdata // PC -> arg live index, relative to ArgLiveInfo
+
+ // Func data, must implement encoding.BinaryMarshaler
+ ArgsPointerMaps encoding.BinaryMarshaler // concrete type: *StackMap
+ LocalsPointerMaps encoding.BinaryMarshaler // concrete type: *StackMap
+ StackObjects encoding.BinaryMarshaler
+ InlTree encoding.BinaryMarshaler
+ OpenCodedDeferInfo encoding.BinaryMarshaler
+ ArgInfo encoding.BinaryMarshaler
+ ArgLiveInfo encoding.BinaryMarshaler
+ WrapInfo encoding.BinaryMarshaler
+}
+
+func getOffsetOf(data interface{}, field string) uintptr {
+ t := reflect.TypeOf(data)
+ fv, ok := t.FieldByName(field)
+ if !ok {
+ panic(fmt.Sprintf("field %s not found in struct %s", field, t.Name()))
+ }
+ return fv.Offset
+}
+
+func rnd(v int64, r int64) int64 {
+ if r <= 0 {
+ return v
+ }
+ v += r - 1
+ c := v % r
+ if c < 0 {
+ c += r
+ }
+ v -= c
+ return v
+}
+
+var (
+ byteOrder binary.ByteOrder = binary.LittleEndian
+)
+
+func funcNameParts(name string) (string, string, string) {
+ i := strings.IndexByte(name, '[')
+ if i < 0 {
+ return name, "", ""
+ }
+ // TODO: use LastIndexByte once the bootstrap compiler is >= Go 1.5.
+ j := len(name) - 1
+ for j > i && name[j] != ']' {
+ j--
+ }
+ if j <= i {
+ return name, "", ""
+ }
+ return name[:i], "[...]", name[j+1:]
+} \ No newline at end of file
diff --git a/vendor/github.com/bytedance/sonic/loader/funcdata_go115.go b/vendor/github.com/bytedance/sonic/loader/funcdata_go115.go
new file mode 100644
index 000000000..f35f03d56
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/loader/funcdata_go115.go
@@ -0,0 +1,541 @@
+// go:build go1.15 && !go1.18
+// +build go1.15,!go1.18
+
+/*
+ * 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 loader
+
+import (
+ `encoding`
+ `os`
+ `unsafe`
+
+ `github.com/bytedance/sonic/internal/rt`
+)
+
+const (
+ _Magic uint32 = 0xfffffff0
+)
+
+type pcHeader struct {
+ magic uint32 // 0xFFFFFFF0
+ pad1, pad2 uint8 // 0,0
+ minLC uint8 // min instruction size
+ ptrSize uint8 // size of a ptr in bytes
+ nfunc int // number of functions in the module
+ nfiles uint // number of entries in the file tab
+ textStart uintptr // base for function entry PC offsets in this module, equal to moduledata.text
+ funcnameOffset uintptr // offset to the funcnametab variable from pcHeader
+ cuOffset uintptr // offset to the cutab variable from pcHeader
+ filetabOffset uintptr // offset to the filetab variable from pcHeader
+ pctabOffset uintptr // offset to the pctab variable from pcHeader
+ pclnOffset uintptr // offset to the pclntab variable from pcHeader
+}
+
+type moduledata struct {
+ pcHeader *pcHeader
+ funcnametab []byte
+ cutab []uint32
+ filetab []byte
+ pctab []byte
+ pclntable []byte
+ ftab []funcTab
+ findfunctab uintptr
+ minpc, maxpc uintptr // first func address, last func address + last func size
+
+ text, etext uintptr // start/end of text, (etext-text) must be greater than MIN_FUNC
+ noptrdata, enoptrdata uintptr
+ data, edata uintptr
+ bss, ebss uintptr
+ noptrbss, enoptrbss uintptr
+ end, gcdata, gcbss uintptr
+ types, etypes uintptr
+ rodata uintptr
+ gofunc uintptr // go.func.* is actual funcinfo object in image
+
+ textsectmap []textSection // see runtime/symtab.go: textAddr()
+ typelinks []int32 // offsets from types
+ itablinks []*rt.GoItab
+
+ ptab []ptabEntry
+
+ pluginpath string
+ pkghashes []modulehash
+
+ modulename string
+ modulehashes []modulehash
+
+ hasmain uint8 // 1 if module contains the main function, 0 otherwise
+
+ gcdatamask, gcbssmask bitVector
+
+ typemap map[int32]*rt.GoType // offset to *_rtype in previous module
+
+ bad bool // module failed to load and should be ignored
+
+ next *moduledata
+}
+
+type _func struct {
+ entryOff uint32 // start pc, as offset from moduledata.text/pcHeader.textStart
+ nameOff int32 // function name, as index into moduledata.funcnametab.
+
+ args int32 // in/out args size
+ deferreturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
+
+ pcsp uint32
+ pcfile uint32
+ pcln uint32
+ npcdata uint32
+ cuOffset uint32 // runtime.cutab offset of this function's CU
+ funcID uint8 // set for certain special runtime functions
+ flag uint8
+ _ [1]byte // pad
+ nfuncdata uint8 //
+
+ // The end of the struct is followed immediately by two variable-length
+ // arrays that reference the pcdata and funcdata locations for this
+ // function.
+
+ // pcdata contains the offset into moduledata.pctab for the start of
+ // that index's table. e.g.,
+ // &moduledata.pctab[_func.pcdata[_PCDATA_UnsafePoint]] is the start of
+ // the unsafe point table.
+ //
+ // An offset of 0 indicates that there is no table.
+ //
+ // pcdata [npcdata]uint32
+
+ // funcdata contains the offset past moduledata.gofunc which contains a
+ // pointer to that index's funcdata. e.g.,
+ // *(moduledata.gofunc + _func.funcdata[_FUNCDATA_ArgsPointerMaps]) is
+ // the argument pointer map.
+ //
+ // An offset of ^uint32(0) indicates that there is no entry.
+ //
+ // funcdata [nfuncdata]uint32
+}
+
+type funcTab struct {
+ entry uint32
+ funcoff uint32
+}
+
+type bitVector struct {
+ n int32 // # of bits
+ bytedata *uint8
+}
+
+type ptabEntry struct {
+ name int32
+ typ int32
+}
+
+type textSection struct {
+ vaddr uintptr // prelinked section vaddr
+ end uintptr // vaddr + section length
+ baseaddr uintptr // relocated section address
+}
+
+type modulehash struct {
+ modulename string
+ linktimehash string
+ runtimehash *string
+}
+
+// findfuncbucket is an array of these structures.
+// Each bucket represents 4096 bytes of the text segment.
+// Each subbucket represents 256 bytes of the text segment.
+// To find a function given a pc, locate the bucket and subbucket for
+// that pc. Add together the idx and subbucket value to obtain a
+// function index. Then scan the functab array starting at that
+// index to find the target function.
+// This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead.
+type findfuncbucket struct {
+ idx uint32
+ _SUBBUCKETS [16]byte
+}
+
+// func name table format:
+// nameOff[0] -> namePartA namePartB namePartC \x00
+// nameOff[1] -> namePartA namePartB namePartC \x00
+// ...
+func makeFuncnameTab(funcs []Func) (tab []byte, offs []int32) {
+ offs = make([]int32, len(funcs))
+ offset := 0
+
+ for i, f := range funcs {
+ offs[i] = int32(offset)
+
+ a, b, c := funcNameParts(f.Name)
+ tab = append(tab, a...)
+ tab = append(tab, b...)
+ tab = append(tab, c...)
+ tab = append(tab, 0)
+ offset += len(a) + len(b) + len(c) + 1
+ }
+
+ return
+}
+
+type compilationUnit struct {
+ fileNames []string
+}
+
+// CU table format:
+// cuOffsets[0] -> filetabOffset[0] filetabOffset[1] ... filetabOffset[len(CUs[0].fileNames)-1]
+// cuOffsets[1] -> filetabOffset[len(CUs[0].fileNames)] ... filetabOffset[len(CUs[0].fileNames) + len(CUs[1].fileNames)-1]
+// ...
+//
+// file name table format:
+// filetabOffset[0] -> CUs[0].fileNames[0] \x00
+// ...
+// filetabOffset[len(CUs[0]-1)] -> CUs[0].fileNames[len(CUs[0].fileNames)-1] \x00
+// ...
+// filetabOffset[SUM(CUs,fileNames)-1] -> CUs[len(CU)-1].fileNames[len(CUs[len(CU)-1].fileNames)-1] \x00
+func makeFilenametab(cus []compilationUnit) (cutab []uint32, filetab []byte, cuOffsets []uint32) {
+ cuOffsets = make([]uint32, len(cus))
+ cuOffset := 0
+ fileOffset := 0
+
+ for i, cu := range cus {
+ cuOffsets[i] = uint32(cuOffset)
+
+ for _, name := range cu.fileNames {
+ cutab = append(cutab, uint32(fileOffset))
+
+ fileOffset += len(name) + 1
+ filetab = append(filetab, name...)
+ filetab = append(filetab, 0)
+ }
+
+ cuOffset += len(cu.fileNames)
+ }
+
+ return
+}
+
+func writeFuncdata(out *[]byte, funcs []Func) (fstart int, funcdataOffs [][]uint32) {
+ fstart = len(*out)
+ *out = append(*out, byte(0))
+ offs := uint32(1)
+
+ funcdataOffs = make([][]uint32, len(funcs))
+ for i, f := range funcs {
+
+ var writer = func(fd encoding.BinaryMarshaler) {
+ var ab []byte
+ var err error
+ if fd != nil {
+ ab, err = fd.MarshalBinary()
+ if err != nil {
+ panic(err)
+ }
+ funcdataOffs[i] = append(funcdataOffs[i], offs)
+ } else {
+ ab = []byte{0}
+ funcdataOffs[i] = append(funcdataOffs[i], _INVALID_FUNCDATA_OFFSET)
+ }
+ *out = append(*out, ab...)
+ offs += uint32(len(ab))
+ }
+
+ writer(f.ArgsPointerMaps)
+ writer(f.LocalsPointerMaps)
+ writer(f.StackObjects)
+ writer(f.InlTree)
+ writer(f.OpenCodedDeferInfo)
+ writer(f.ArgInfo)
+ writer(f.ArgLiveInfo)
+ writer(f.WrapInfo)
+ }
+ return
+}
+
+func makeFtab(funcs []_func, lastFuncSize uint32) (ftab []funcTab) {
+ // Allocate space for the pc->func table. This structure consists of a pc offset
+ // and an offset to the func structure. After that, we have a single pc
+ // value that marks the end of the last function in the binary.
+ var size int64 = int64(len(funcs)*2*4 + 4)
+ var startLocations = make([]uint32, len(funcs))
+ for i, f := range funcs {
+ size = rnd(size, int64(_PtrSize))
+ //writePCToFunc
+ startLocations[i] = uint32(size)
+ size += int64(uint8(_FUNC_SIZE)+f.nfuncdata*4+uint8(f.npcdata)*4)
+ }
+
+ ftab = make([]funcTab, 0, len(funcs)+1)
+
+ // write a map of pc->func info offsets
+ for i, f := range funcs {
+ ftab = append(ftab, funcTab{uint32(f.entryOff), uint32(startLocations[i])})
+ }
+
+ // Final entry of table is just end pc offset.
+ lastFunc := funcs[len(funcs)-1]
+ ftab = append(ftab, funcTab{uint32(lastFunc.entryOff + lastFuncSize), 0})
+
+ return
+}
+
+// Pcln table format: [...]funcTab + [...]_Func
+func makePclntable(funcs []_func, lastFuncSize uint32, pcdataOffs [][]uint32, funcdataOffs [][]uint32) (pclntab []byte) {
+ // Allocate space for the pc->func table. This structure consists of a pc offset
+ // and an offset to the func structure. After that, we have a single pc
+ // value that marks the end of the last function in the binary.
+ var size int64 = int64(len(funcs)*2*4 + 4)
+ var startLocations = make([]uint32, len(funcs))
+ for i := range funcs {
+ size = rnd(size, int64(_PtrSize))
+ //writePCToFunc
+ startLocations[i] = uint32(size)
+ size += int64(int(_FUNC_SIZE)+len(funcdataOffs[i])*4+len(pcdataOffs[i])*4)
+ }
+
+ pclntab = make([]byte, size, size)
+
+ // write a map of pc->func info offsets
+ offs := 0
+ for i, f := range funcs {
+ byteOrder.PutUint32(pclntab[offs:offs+4], uint32(f.entryOff))
+ byteOrder.PutUint32(pclntab[offs+4:offs+8], uint32(startLocations[i]))
+ offs += 8
+ }
+ // Final entry of table is just end pc offset.
+ lastFunc := funcs[len(funcs)-1]
+ byteOrder.PutUint32(pclntab[offs:offs+4], uint32(lastFunc.entryOff+lastFuncSize))
+
+ // write func info table
+ for i, f := range funcs {
+ off := startLocations[i]
+
+ // write _func structure to pclntab
+ fb := rt.BytesFrom(unsafe.Pointer(&f), int(_FUNC_SIZE), int(_FUNC_SIZE))
+ copy(pclntab[off:off+uint32(_FUNC_SIZE)], fb)
+ off += uint32(_FUNC_SIZE)
+
+ // NOTICE: _func.pcdata always starts from PcUnsafePoint, which is index 3
+ for j := 3; j < len(pcdataOffs[i]); j++ {
+ byteOrder.PutUint32(pclntab[off:off+4], uint32(pcdataOffs[i][j]))
+ off += 4
+ }
+
+ // funcdata refs as offsets from gofunc
+ for _, funcdata := range funcdataOffs[i] {
+ byteOrder.PutUint32(pclntab[off:off+4], uint32(funcdata))
+ off += 4
+ }
+
+ }
+
+ return
+}
+
+// findfunc table used to map pc to belonging func,
+// returns the index in the func table.
+//
+// All text section are divided into buckets sized _BUCKETSIZE(4K):
+// every bucket is divided into _SUBBUCKETS sized _SUB_BUCKETSIZE(64),
+// and it has a base idx to plus the offset stored in jth subbucket.
+// see findfunc() in runtime/symtab.go
+func writeFindfunctab(out *[]byte, ftab []funcTab) (start int) {
+ start = len(*out)
+
+ max := ftab[len(ftab)-1].entry
+ min := ftab[0].entry
+ nbuckets := (max - min + _BUCKETSIZE - 1) / _BUCKETSIZE
+ n := (max - min + _SUB_BUCKETSIZE - 1) / _SUB_BUCKETSIZE
+
+ tab := make([]findfuncbucket, 0, nbuckets)
+ var s, e = 0, 0
+ for i := 0; i<int(nbuckets); i++ {
+ var pc = min + uint32((i+1)*_BUCKETSIZE)
+ // find the end func of the bucket
+ for ; e < len(ftab)-1 && ftab[e+1].entry <= pc; e++ {}
+ // store the start func of the bucket
+ var fb = findfuncbucket{idx: uint32(s)}
+
+ for j := 0; j<_SUBBUCKETS && (i*_SUBBUCKETS+j)<int(n); j++ {
+ pc = min + uint32(i*_BUCKETSIZE) + uint32((j+1)*_SUB_BUCKETSIZE)
+ var ss = s
+ // find the end func of the subbucket
+ for ; ss < len(ftab)-1 && ftab[ss+1].entry <= pc; ss++ {}
+ // store the start func of the subbucket
+ fb._SUBBUCKETS[j] = byte(uint32(s) - fb.idx)
+ s = ss
+ }
+ s = e
+ tab = append(tab, fb)
+ }
+
+ // write findfuncbucket
+ if len(tab) > 0 {
+ size := int(unsafe.Sizeof(findfuncbucket{}))*len(tab)
+ *out = append(*out, rt.BytesFrom(unsafe.Pointer(&tab[0]), size, size)...)
+ }
+ return
+}
+
+func makeModuledata(name string, filenames []string, funcs []Func, text []byte) (mod *moduledata) {
+ mod = new(moduledata)
+ mod.modulename = name
+
+ // make filename table
+ cu := make([]string, 0, len(filenames))
+ for _, f := range filenames {
+ cu = append(cu, f)
+ }
+ cutab, filetab, cuOffs := makeFilenametab([]compilationUnit{{cu}})
+ mod.cutab = cutab
+ mod.filetab = filetab
+
+ // make funcname table
+ funcnametab, nameOffs := makeFuncnameTab(funcs)
+ mod.funcnametab = funcnametab
+
+ // make pcdata table
+ // NOTICE: _func only use offset to index pcdata, thus no need mmap() pcdata
+ pctab, pcdataOffs, _funcs := makePctab(funcs, cuOffs, nameOffs)
+ mod.pctab = pctab
+
+ // write func data
+ // NOTICE: _func use mod.gofunc+offset to directly point funcdata, thus need cache funcdata
+ // TODO: estimate accurate capacity
+ cache := make([]byte, 0, len(funcs)*int(_PtrSize))
+ fstart, funcdataOffs := writeFuncdata(&cache, funcs)
+
+ // make pc->func (binary search) func table
+ lastFuncsize := funcs[len(funcs)-1].TextSize
+ ftab := makeFtab(_funcs, lastFuncsize)
+ mod.ftab = ftab
+
+ // write pc->func (modmap) findfunc table
+ ffstart := writeFindfunctab(&cache, ftab)
+
+ // make pclnt table
+ pclntab := makePclntable(_funcs, lastFuncsize, pcdataOffs, funcdataOffs)
+ mod.pclntable = pclntab
+
+ // mmap() text and funcdata segements
+ p := os.Getpagesize()
+ size := int(rnd(int64(len(text)), int64(p)))
+ addr := mmap(size)
+ // copy the machine code
+ s := rt.BytesFrom(unsafe.Pointer(addr), len(text), size)
+ copy(s, text)
+ // make it executable
+ mprotect(addr, size)
+
+ // assign addresses
+ mod.text = addr
+ mod.etext = addr + uintptr(size)
+ mod.minpc = addr
+ mod.maxpc = addr + uintptr(len(text))
+
+ // cache funcdata and findfuncbucket
+ moduleCache.Lock()
+ moduleCache.m[mod] = cache
+ moduleCache.Unlock()
+ mod.gofunc = uintptr(unsafe.Pointer(&cache[fstart]))
+ mod.findfunctab = uintptr(unsafe.Pointer(&cache[ffstart]))
+
+ // make pc header
+ mod.pcHeader = &pcHeader {
+ magic : _Magic,
+ minLC : _MinLC,
+ ptrSize : _PtrSize,
+ nfunc : len(funcs),
+ nfiles: uint(len(cu)),
+ textStart: mod.text,
+ funcnameOffset: getOffsetOf(moduledata{}, "funcnametab"),
+ cuOffset: getOffsetOf(moduledata{}, "cutab"),
+ filetabOffset: getOffsetOf(moduledata{}, "filetab"),
+ pctabOffset: getOffsetOf(moduledata{}, "pctab"),
+ pclnOffset: getOffsetOf(moduledata{}, "pclntable"),
+ }
+
+ // sepecial case: gcdata and gcbss must by non-empty
+ mod.gcdata = uintptr(unsafe.Pointer(&emptyByte))
+ mod.gcbss = uintptr(unsafe.Pointer(&emptyByte))
+
+ return
+}
+
+// makePctab generates pcdelta->valuedelta tables for functions,
+// and returns the table and the entry offset of every kind pcdata in the table.
+func makePctab(funcs []Func, cuOffset []uint32, nameOffset []int32) (pctab []byte, pcdataOffs [][]uint32, _funcs []_func) {
+ _funcs = make([]_func, len(funcs))
+
+ // Pctab offsets of 0 are considered invalid in the runtime. We respect
+ // that by just padding a single byte at the beginning of runtime.pctab,
+ // that way no real offsets can be zero.
+ pctab = make([]byte, 1, 12*len(funcs)+1)
+ pcdataOffs = make([][]uint32, len(funcs))
+
+ for i, f := range funcs {
+ _f := &_funcs[i]
+
+ var writer = func(pc *Pcdata) {
+ var ab []byte
+ var err error
+ if pc != nil {
+ ab, err = pc.MarshalBinary()
+ if err != nil {
+ panic(err)
+ }
+ pcdataOffs[i] = append(pcdataOffs[i], uint32(len(pctab)))
+ } else {
+ ab = []byte{0}
+ pcdataOffs[i] = append(pcdataOffs[i], _PCDATA_INVALID_OFFSET)
+ }
+ pctab = append(pctab, ab...)
+ }
+
+ if f.Pcsp != nil {
+ _f.pcsp = uint32(len(pctab))
+ }
+ writer(f.Pcsp)
+ if f.Pcfile != nil {
+ _f.pcfile = uint32(len(pctab))
+ }
+ writer(f.Pcfile)
+ if f.Pcline != nil {
+ _f.pcln = uint32(len(pctab))
+ }
+ writer(f.Pcline)
+ writer(f.PcUnsafePoint)
+ writer(f.PcStackMapIndex)
+ writer(f.PcInlTreeIndex)
+ writer(f.PcArgLiveIndex)
+
+ _f.entryOff = f.EntryOff
+ _f.nameOff = nameOffset[i]
+ _f.args = f.ArgsSize
+ _f.deferreturn = f.DeferReturn
+ // NOTICE: _func.pcdata is always as [PCDATA_UnsafePoint(0) : PCDATA_ArgLiveIndex(3)]
+ _f.npcdata = uint32(_N_PCDATA)
+ _f.cuOffset = cuOffset[i]
+ _f.funcID = f.ID
+ _f.flag = f.Flag
+ _f.nfuncdata = uint8(_N_FUNCDATA)
+ }
+
+ return
+}
+
+func registerFunction(name string, pc uintptr, textSize uintptr, fp int, args int, size uintptr, argptrs uintptr, localptrs uintptr) {} \ No newline at end of file
diff --git a/vendor/github.com/bytedance/sonic/loader/funcdata_go118.go b/vendor/github.com/bytedance/sonic/loader/funcdata_go118.go
new file mode 100644
index 000000000..a2bac857a
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/loader/funcdata_go118.go
@@ -0,0 +1,541 @@
+// go:build go1.18 && !go1.20
+// +build go1.18,!go1.20
+
+/*
+ * 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 loader
+
+import (
+ `encoding`
+ `os`
+ `unsafe`
+
+ `github.com/bytedance/sonic/internal/rt`
+)
+
+const (
+ _Magic uint32 = 0xfffffff0
+)
+
+type pcHeader struct {
+ magic uint32 // 0xFFFFFFF0
+ pad1, pad2 uint8 // 0,0
+ minLC uint8 // min instruction size
+ ptrSize uint8 // size of a ptr in bytes
+ nfunc int // number of functions in the module
+ nfiles uint // number of entries in the file tab
+ textStart uintptr // base for function entry PC offsets in this module, equal to moduledata.text
+ funcnameOffset uintptr // offset to the funcnametab variable from pcHeader
+ cuOffset uintptr // offset to the cutab variable from pcHeader
+ filetabOffset uintptr // offset to the filetab variable from pcHeader
+ pctabOffset uintptr // offset to the pctab variable from pcHeader
+ pclnOffset uintptr // offset to the pclntab variable from pcHeader
+}
+
+type moduledata struct {
+ pcHeader *pcHeader
+ funcnametab []byte
+ cutab []uint32
+ filetab []byte
+ pctab []byte
+ pclntable []byte
+ ftab []funcTab
+ findfunctab uintptr
+ minpc, maxpc uintptr // first func address, last func address + last func size
+
+ text, etext uintptr // start/end of text, (etext-text) must be greater than MIN_FUNC
+ noptrdata, enoptrdata uintptr
+ data, edata uintptr
+ bss, ebss uintptr
+ noptrbss, enoptrbss uintptr
+ end, gcdata, gcbss uintptr
+ types, etypes uintptr
+ rodata uintptr
+ gofunc uintptr // go.func.* is actual funcinfo object in image
+
+ textsectmap []textSection // see runtime/symtab.go: textAddr()
+ typelinks []int32 // offsets from types
+ itablinks []*rt.GoItab
+
+ ptab []ptabEntry
+
+ pluginpath string
+ pkghashes []modulehash
+
+ modulename string
+ modulehashes []modulehash
+
+ hasmain uint8 // 1 if module contains the main function, 0 otherwise
+
+ gcdatamask, gcbssmask bitVector
+
+ typemap map[int32]*rt.GoType // offset to *_rtype in previous module
+
+ bad bool // module failed to load and should be ignored
+
+ next *moduledata
+}
+
+type _func struct {
+ entryOff uint32 // start pc, as offset from moduledata.text/pcHeader.textStart
+ nameOff int32 // function name, as index into moduledata.funcnametab.
+
+ args int32 // in/out args size
+ deferreturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
+
+ pcsp uint32
+ pcfile uint32
+ pcln uint32
+ npcdata uint32
+ cuOffset uint32 // runtime.cutab offset of this function's CU
+ funcID uint8 // set for certain special runtime functions
+ flag uint8
+ _ [1]byte // pad
+ nfuncdata uint8 //
+
+ // The end of the struct is followed immediately by two variable-length
+ // arrays that reference the pcdata and funcdata locations for this
+ // function.
+
+ // pcdata contains the offset into moduledata.pctab for the start of
+ // that index's table. e.g.,
+ // &moduledata.pctab[_func.pcdata[_PCDATA_UnsafePoint]] is the start of
+ // the unsafe point table.
+ //
+ // An offset of 0 indicates that there is no table.
+ //
+ // pcdata [npcdata]uint32
+
+ // funcdata contains the offset past moduledata.gofunc which contains a
+ // pointer to that index's funcdata. e.g.,
+ // *(moduledata.gofunc + _func.funcdata[_FUNCDATA_ArgsPointerMaps]) is
+ // the argument pointer map.
+ //
+ // An offset of ^uint32(0) indicates that there is no entry.
+ //
+ // funcdata [nfuncdata]uint32
+}
+
+type funcTab struct {
+ entry uint32
+ funcoff uint32
+}
+
+type bitVector struct {
+ n int32 // # of bits
+ bytedata *uint8
+}
+
+type ptabEntry struct {
+ name int32
+ typ int32
+}
+
+type textSection struct {
+ vaddr uintptr // prelinked section vaddr
+ end uintptr // vaddr + section length
+ baseaddr uintptr // relocated section address
+}
+
+type modulehash struct {
+ modulename string
+ linktimehash string
+ runtimehash *string
+}
+
+// findfuncbucket is an array of these structures.
+// Each bucket represents 4096 bytes of the text segment.
+// Each subbucket represents 256 bytes of the text segment.
+// To find a function given a pc, locate the bucket and subbucket for
+// that pc. Add together the idx and subbucket value to obtain a
+// function index. Then scan the functab array starting at that
+// index to find the target function.
+// This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead.
+type findfuncbucket struct {
+ idx uint32
+ _SUBBUCKETS [16]byte
+}
+
+// func name table format:
+// nameOff[0] -> namePartA namePartB namePartC \x00
+// nameOff[1] -> namePartA namePartB namePartC \x00
+// ...
+func makeFuncnameTab(funcs []Func) (tab []byte, offs []int32) {
+ offs = make([]int32, len(funcs))
+ offset := 0
+
+ for i, f := range funcs {
+ offs[i] = int32(offset)
+
+ a, b, c := funcNameParts(f.Name)
+ tab = append(tab, a...)
+ tab = append(tab, b...)
+ tab = append(tab, c...)
+ tab = append(tab, 0)
+ offset += len(a) + len(b) + len(c) + 1
+ }
+
+ return
+}
+
+type compilationUnit struct {
+ fileNames []string
+}
+
+// CU table format:
+// cuOffsets[0] -> filetabOffset[0] filetabOffset[1] ... filetabOffset[len(CUs[0].fileNames)-1]
+// cuOffsets[1] -> filetabOffset[len(CUs[0].fileNames)] ... filetabOffset[len(CUs[0].fileNames) + len(CUs[1].fileNames)-1]
+// ...
+//
+// file name table format:
+// filetabOffset[0] -> CUs[0].fileNames[0] \x00
+// ...
+// filetabOffset[len(CUs[0]-1)] -> CUs[0].fileNames[len(CUs[0].fileNames)-1] \x00
+// ...
+// filetabOffset[SUM(CUs,fileNames)-1] -> CUs[len(CU)-1].fileNames[len(CUs[len(CU)-1].fileNames)-1] \x00
+func makeFilenametab(cus []compilationUnit) (cutab []uint32, filetab []byte, cuOffsets []uint32) {
+ cuOffsets = make([]uint32, len(cus))
+ cuOffset := 0
+ fileOffset := 0
+
+ for i, cu := range cus {
+ cuOffsets[i] = uint32(cuOffset)
+
+ for _, name := range cu.fileNames {
+ cutab = append(cutab, uint32(fileOffset))
+
+ fileOffset += len(name) + 1
+ filetab = append(filetab, name...)
+ filetab = append(filetab, 0)
+ }
+
+ cuOffset += len(cu.fileNames)
+ }
+
+ return
+}
+
+func writeFuncdata(out *[]byte, funcs []Func) (fstart int, funcdataOffs [][]uint32) {
+ fstart = len(*out)
+ *out = append(*out, byte(0))
+ offs := uint32(1)
+
+ funcdataOffs = make([][]uint32, len(funcs))
+ for i, f := range funcs {
+
+ var writer = func(fd encoding.BinaryMarshaler) {
+ var ab []byte
+ var err error
+ if fd != nil {
+ ab, err = fd.MarshalBinary()
+ if err != nil {
+ panic(err)
+ }
+ funcdataOffs[i] = append(funcdataOffs[i], offs)
+ } else {
+ ab = []byte{0}
+ funcdataOffs[i] = append(funcdataOffs[i], _INVALID_FUNCDATA_OFFSET)
+ }
+ *out = append(*out, ab...)
+ offs += uint32(len(ab))
+ }
+
+ writer(f.ArgsPointerMaps)
+ writer(f.LocalsPointerMaps)
+ writer(f.StackObjects)
+ writer(f.InlTree)
+ writer(f.OpenCodedDeferInfo)
+ writer(f.ArgInfo)
+ writer(f.ArgLiveInfo)
+ writer(f.WrapInfo)
+ }
+ return
+}
+
+func makeFtab(funcs []_func, lastFuncSize uint32) (ftab []funcTab) {
+ // Allocate space for the pc->func table. This structure consists of a pc offset
+ // and an offset to the func structure. After that, we have a single pc
+ // value that marks the end of the last function in the binary.
+ var size int64 = int64(len(funcs)*2*4 + 4)
+ var startLocations = make([]uint32, len(funcs))
+ for i, f := range funcs {
+ size = rnd(size, int64(_PtrSize))
+ //writePCToFunc
+ startLocations[i] = uint32(size)
+ size += int64(uint8(_FUNC_SIZE)+f.nfuncdata*4+uint8(f.npcdata)*4)
+ }
+
+ ftab = make([]funcTab, 0, len(funcs)+1)
+
+ // write a map of pc->func info offsets
+ for i, f := range funcs {
+ ftab = append(ftab, funcTab{uint32(f.entryOff), uint32(startLocations[i])})
+ }
+
+ // Final entry of table is just end pc offset.
+ lastFunc := funcs[len(funcs)-1]
+ ftab = append(ftab, funcTab{uint32(lastFunc.entryOff + lastFuncSize), 0})
+
+ return
+}
+
+// Pcln table format: [...]funcTab + [...]_Func
+func makePclntable(funcs []_func, lastFuncSize uint32, pcdataOffs [][]uint32, funcdataOffs [][]uint32) (pclntab []byte) {
+ // Allocate space for the pc->func table. This structure consists of a pc offset
+ // and an offset to the func structure. After that, we have a single pc
+ // value that marks the end of the last function in the binary.
+ var size int64 = int64(len(funcs)*2*4 + 4)
+ var startLocations = make([]uint32, len(funcs))
+ for i := range funcs {
+ size = rnd(size, int64(_PtrSize))
+ //writePCToFunc
+ startLocations[i] = uint32(size)
+ size += int64(int(_FUNC_SIZE)+len(funcdataOffs[i])*4+len(pcdataOffs[i])*4)
+ }
+
+ pclntab = make([]byte, size, size)
+
+ // write a map of pc->func info offsets
+ offs := 0
+ for i, f := range funcs {
+ byteOrder.PutUint32(pclntab[offs:offs+4], uint32(f.entryOff))
+ byteOrder.PutUint32(pclntab[offs+4:offs+8], uint32(startLocations[i]))
+ offs += 8
+ }
+ // Final entry of table is just end pc offset.
+ lastFunc := funcs[len(funcs)-1]
+ byteOrder.PutUint32(pclntab[offs:offs+4], uint32(lastFunc.entryOff+lastFuncSize))
+
+ // write func info table
+ for i, f := range funcs {
+ off := startLocations[i]
+
+ // write _func structure to pclntab
+ fb := rt.BytesFrom(unsafe.Pointer(&f), int(_FUNC_SIZE), int(_FUNC_SIZE))
+ copy(pclntab[off:off+uint32(_FUNC_SIZE)], fb)
+ off += uint32(_FUNC_SIZE)
+
+ // NOTICE: _func.pcdata always starts from PcUnsafePoint, which is index 3
+ for j := 3; j < len(pcdataOffs[i]); j++ {
+ byteOrder.PutUint32(pclntab[off:off+4], uint32(pcdataOffs[i][j]))
+ off += 4
+ }
+
+ // funcdata refs as offsets from gofunc
+ for _, funcdata := range funcdataOffs[i] {
+ byteOrder.PutUint32(pclntab[off:off+4], uint32(funcdata))
+ off += 4
+ }
+
+ }
+
+ return
+}
+
+// findfunc table used to map pc to belonging func,
+// returns the index in the func table.
+//
+// All text section are divided into buckets sized _BUCKETSIZE(4K):
+// every bucket is divided into _SUBBUCKETS sized _SUB_BUCKETSIZE(64),
+// and it has a base idx to plus the offset stored in jth subbucket.
+// see findfunc() in runtime/symtab.go
+func writeFindfunctab(out *[]byte, ftab []funcTab) (start int) {
+ start = len(*out)
+
+ max := ftab[len(ftab)-1].entry
+ min := ftab[0].entry
+ nbuckets := (max - min + _BUCKETSIZE - 1) / _BUCKETSIZE
+ n := (max - min + _SUB_BUCKETSIZE - 1) / _SUB_BUCKETSIZE
+
+ tab := make([]findfuncbucket, 0, nbuckets)
+ var s, e = 0, 0
+ for i := 0; i<int(nbuckets); i++ {
+ var pc = min + uint32((i+1)*_BUCKETSIZE)
+ // find the end func of the bucket
+ for ; e < len(ftab)-1 && ftab[e+1].entry <= pc; e++ {}
+ // store the start func of the bucket
+ var fb = findfuncbucket{idx: uint32(s)}
+
+ for j := 0; j<_SUBBUCKETS && (i*_SUBBUCKETS+j)<int(n); j++ {
+ pc = min + uint32(i*_BUCKETSIZE) + uint32((j+1)*_SUB_BUCKETSIZE)
+ var ss = s
+ // find the end func of the subbucket
+ for ; ss < len(ftab)-1 && ftab[ss+1].entry <= pc; ss++ {}
+ // store the start func of the subbucket
+ fb._SUBBUCKETS[j] = byte(uint32(s) - fb.idx)
+ s = ss
+ }
+ s = e
+ tab = append(tab, fb)
+ }
+
+ // write findfuncbucket
+ if len(tab) > 0 {
+ size := int(unsafe.Sizeof(findfuncbucket{}))*len(tab)
+ *out = append(*out, rt.BytesFrom(unsafe.Pointer(&tab[0]), size, size)...)
+ }
+ return
+}
+
+func makeModuledata(name string, filenames []string, funcs []Func, text []byte) (mod *moduledata) {
+ mod = new(moduledata)
+ mod.modulename = name
+
+ // make filename table
+ cu := make([]string, 0, len(filenames))
+ for _, f := range filenames {
+ cu = append(cu, f)
+ }
+ cutab, filetab, cuOffs := makeFilenametab([]compilationUnit{{cu}})
+ mod.cutab = cutab
+ mod.filetab = filetab
+
+ // make funcname table
+ funcnametab, nameOffs := makeFuncnameTab(funcs)
+ mod.funcnametab = funcnametab
+
+ // make pcdata table
+ // NOTICE: _func only use offset to index pcdata, thus no need mmap() pcdata
+ pctab, pcdataOffs, _funcs := makePctab(funcs, cuOffs, nameOffs)
+ mod.pctab = pctab
+
+ // write func data
+ // NOTICE: _func use mod.gofunc+offset to directly point funcdata, thus need cache funcdata
+ // TODO: estimate accurate capacity
+ cache := make([]byte, 0, len(funcs)*int(_PtrSize))
+ fstart, funcdataOffs := writeFuncdata(&cache, funcs)
+
+ // make pc->func (binary search) func table
+ lastFuncsize := funcs[len(funcs)-1].TextSize
+ ftab := makeFtab(_funcs, lastFuncsize)
+ mod.ftab = ftab
+
+ // write pc->func (modmap) findfunc table
+ ffstart := writeFindfunctab(&cache, ftab)
+
+ // make pclnt table
+ pclntab := makePclntable(_funcs, lastFuncsize, pcdataOffs, funcdataOffs)
+ mod.pclntable = pclntab
+
+ // mmap() text and funcdata segements
+ p := os.Getpagesize()
+ size := int(rnd(int64(len(text)), int64(p)))
+ addr := mmap(size)
+ // copy the machine code
+ s := rt.BytesFrom(unsafe.Pointer(addr), len(text), size)
+ copy(s, text)
+ // make it executable
+ mprotect(addr, size)
+
+ // assign addresses
+ mod.text = addr
+ mod.etext = addr + uintptr(size)
+ mod.minpc = addr
+ mod.maxpc = addr + uintptr(len(text))
+
+ // cache funcdata and findfuncbucket
+ moduleCache.Lock()
+ moduleCache.m[mod] = cache
+ moduleCache.Unlock()
+ mod.gofunc = uintptr(unsafe.Pointer(&cache[fstart]))
+ mod.findfunctab = uintptr(unsafe.Pointer(&cache[ffstart]))
+
+ // make pc header
+ mod.pcHeader = &pcHeader {
+ magic : _Magic,
+ minLC : _MinLC,
+ ptrSize : _PtrSize,
+ nfunc : len(funcs),
+ nfiles: uint(len(cu)),
+ textStart: mod.text,
+ funcnameOffset: getOffsetOf(moduledata{}, "funcnametab"),
+ cuOffset: getOffsetOf(moduledata{}, "cutab"),
+ filetabOffset: getOffsetOf(moduledata{}, "filetab"),
+ pctabOffset: getOffsetOf(moduledata{}, "pctab"),
+ pclnOffset: getOffsetOf(moduledata{}, "pclntable"),
+ }
+
+ // sepecial case: gcdata and gcbss must by non-empty
+ mod.gcdata = uintptr(unsafe.Pointer(&emptyByte))
+ mod.gcbss = uintptr(unsafe.Pointer(&emptyByte))
+
+ return
+}
+
+// makePctab generates pcdelta->valuedelta tables for functions,
+// and returns the table and the entry offset of every kind pcdata in the table.
+func makePctab(funcs []Func, cuOffset []uint32, nameOffset []int32) (pctab []byte, pcdataOffs [][]uint32, _funcs []_func) {
+ _funcs = make([]_func, len(funcs))
+
+ // Pctab offsets of 0 are considered invalid in the runtime. We respect
+ // that by just padding a single byte at the beginning of runtime.pctab,
+ // that way no real offsets can be zero.
+ pctab = make([]byte, 1, 12*len(funcs)+1)
+ pcdataOffs = make([][]uint32, len(funcs))
+
+ for i, f := range funcs {
+ _f := &_funcs[i]
+
+ var writer = func(pc *Pcdata) {
+ var ab []byte
+ var err error
+ if pc != nil {
+ ab, err = pc.MarshalBinary()
+ if err != nil {
+ panic(err)
+ }
+ pcdataOffs[i] = append(pcdataOffs[i], uint32(len(pctab)))
+ } else {
+ ab = []byte{0}
+ pcdataOffs[i] = append(pcdataOffs[i], _PCDATA_INVALID_OFFSET)
+ }
+ pctab = append(pctab, ab...)
+ }
+
+ if f.Pcsp != nil {
+ _f.pcsp = uint32(len(pctab))
+ }
+ writer(f.Pcsp)
+ if f.Pcfile != nil {
+ _f.pcfile = uint32(len(pctab))
+ }
+ writer(f.Pcfile)
+ if f.Pcline != nil {
+ _f.pcln = uint32(len(pctab))
+ }
+ writer(f.Pcline)
+ writer(f.PcUnsafePoint)
+ writer(f.PcStackMapIndex)
+ writer(f.PcInlTreeIndex)
+ writer(f.PcArgLiveIndex)
+
+ _f.entryOff = f.EntryOff
+ _f.nameOff = nameOffset[i]
+ _f.args = f.ArgsSize
+ _f.deferreturn = f.DeferReturn
+ // NOTICE: _func.pcdata is always as [PCDATA_UnsafePoint(0) : PCDATA_ArgLiveIndex(3)]
+ _f.npcdata = uint32(_N_PCDATA)
+ _f.cuOffset = cuOffset[i]
+ _f.funcID = f.ID
+ _f.flag = f.Flag
+ _f.nfuncdata = uint8(_N_FUNCDATA)
+ }
+
+ return
+}
+
+func registerFunction(name string, pc uintptr, textSize uintptr, fp int, args int, size uintptr, argptrs uintptr, localptrs uintptr) {} \ No newline at end of file
diff --git a/vendor/github.com/bytedance/sonic/loader/funcdata_go120.go b/vendor/github.com/bytedance/sonic/loader/funcdata_go120.go
new file mode 100644
index 000000000..906fe375d
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/loader/funcdata_go120.go
@@ -0,0 +1,545 @@
+//go:build go1.20 && !go1.21
+// +build go1.20,!go1.21
+
+/*
+ * 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 loader
+
+import (
+ `encoding`
+ `os`
+ `unsafe`
+
+ `github.com/bytedance/sonic/internal/rt`
+)
+
+const (
+ _Magic uint32 = 0xFFFFFFF1
+)
+
+type moduledata struct {
+ pcHeader *pcHeader
+ funcnametab []byte
+ cutab []uint32
+ filetab []byte
+ pctab []byte
+ pclntable []byte
+ ftab []funcTab
+ findfunctab uintptr
+ minpc, maxpc uintptr // first func address, last func address + last func size
+
+ text, etext uintptr // start/end of text, (etext-text) must be greater than MIN_FUNC
+ noptrdata, enoptrdata uintptr
+ data, edata uintptr
+ bss, ebss uintptr
+ noptrbss, enoptrbss uintptr
+ covctrs, ecovctrs uintptr
+ end, gcdata, gcbss uintptr
+ types, etypes uintptr
+ rodata uintptr
+
+ // TODO: generate funcinfo object to memory
+ gofunc uintptr // go.func.* is actual funcinfo object in image
+
+ textsectmap []textSection // see runtime/symtab.go: textAddr()
+ typelinks []int32 // offsets from types
+ itablinks []*rt.GoItab
+
+ ptab []ptabEntry
+
+ pluginpath string
+ pkghashes []modulehash
+
+ modulename string
+ modulehashes []modulehash
+
+ hasmain uint8 // 1 if module contains the main function, 0 otherwise
+
+ gcdatamask, gcbssmask bitVector
+
+ typemap map[int32]*rt.GoType // offset to *_rtype in previous module
+
+ bad bool // module failed to load and should be ignored
+
+ next *moduledata
+}
+
+type _func struct {
+ entryOff uint32 // start pc, as offset from moduledata.text/pcHeader.textStart
+ nameOff int32 // function name, as index into moduledata.funcnametab.
+
+ args int32 // in/out args size
+ deferreturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
+
+ pcsp uint32
+ pcfile uint32
+ pcln uint32
+ npcdata uint32
+ cuOffset uint32 // runtime.cutab offset of this function's CU
+ startLine int32 // line number of start of function (func keyword/TEXT directive)
+ funcID uint8 // set for certain special runtime functions
+ flag uint8
+ _ [1]byte // pad
+ nfuncdata uint8 //
+
+ // The end of the struct is followed immediately by two variable-length
+ // arrays that reference the pcdata and funcdata locations for this
+ // function.
+
+ // pcdata contains the offset into moduledata.pctab for the start of
+ // that index's table. e.g.,
+ // &moduledata.pctab[_func.pcdata[_PCDATA_UnsafePoint]] is the start of
+ // the unsafe point table.
+ //
+ // An offset of 0 indicates that there is no table.
+ //
+ // pcdata [npcdata]uint32
+
+ // funcdata contains the offset past moduledata.gofunc which contains a
+ // pointer to that index's funcdata. e.g.,
+ // *(moduledata.gofunc + _func.funcdata[_FUNCDATA_ArgsPointerMaps]) is
+ // the argument pointer map.
+ //
+ // An offset of ^uint32(0) indicates that there is no entry.
+ //
+ // funcdata [nfuncdata]uint32
+}
+
+type funcTab struct {
+ entry uint32
+ funcoff uint32
+}
+
+type pcHeader struct {
+ magic uint32 // 0xFFFFFFF0
+ pad1, pad2 uint8 // 0,0
+ minLC uint8 // min instruction size
+ ptrSize uint8 // size of a ptr in bytes
+ nfunc int // number of functions in the module
+ nfiles uint // number of entries in the file tab
+ textStart uintptr // base for function entry PC offsets in this module, equal to moduledata.text
+ funcnameOffset uintptr // offset to the funcnametab variable from pcHeader
+ cuOffset uintptr // offset to the cutab variable from pcHeader
+ filetabOffset uintptr // offset to the filetab variable from pcHeader
+ pctabOffset uintptr // offset to the pctab variable from pcHeader
+ pclnOffset uintptr // offset to the pclntab variable from pcHeader
+}
+
+type bitVector struct {
+ n int32 // # of bits
+ bytedata *uint8
+}
+
+type ptabEntry struct {
+ name int32
+ typ int32
+}
+
+type textSection struct {
+ vaddr uintptr // prelinked section vaddr
+ end uintptr // vaddr + section length
+ baseaddr uintptr // relocated section address
+}
+
+type modulehash struct {
+ modulename string
+ linktimehash string
+ runtimehash *string
+}
+
+// findfuncbucket is an array of these structures.
+// Each bucket represents 4096 bytes of the text segment.
+// Each subbucket represents 256 bytes of the text segment.
+// To find a function given a pc, locate the bucket and subbucket for
+// that pc. Add together the idx and subbucket value to obtain a
+// function index. Then scan the functab array starting at that
+// index to find the target function.
+// This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead.
+type findfuncbucket struct {
+ idx uint32
+ _SUBBUCKETS [16]byte
+}
+
+// func name table format:
+// nameOff[0] -> namePartA namePartB namePartC \x00
+// nameOff[1] -> namePartA namePartB namePartC \x00
+// ...
+func makeFuncnameTab(funcs []Func) (tab []byte, offs []int32) {
+ offs = make([]int32, len(funcs))
+ offset := 0
+
+ for i, f := range funcs {
+ offs[i] = int32(offset)
+
+ a, b, c := funcNameParts(f.Name)
+ tab = append(tab, a...)
+ tab = append(tab, b...)
+ tab = append(tab, c...)
+ tab = append(tab, 0)
+ offset += len(a) + len(b) + len(c) + 1
+ }
+
+ return
+}
+
+type compilationUnit struct {
+ fileNames []string
+}
+
+// CU table format:
+// cuOffsets[0] -> filetabOffset[0] filetabOffset[1] ... filetabOffset[len(CUs[0].fileNames)-1]
+// cuOffsets[1] -> filetabOffset[len(CUs[0].fileNames)] ... filetabOffset[len(CUs[0].fileNames) + len(CUs[1].fileNames)-1]
+// ...
+//
+// file name table format:
+// filetabOffset[0] -> CUs[0].fileNames[0] \x00
+// ...
+// filetabOffset[len(CUs[0]-1)] -> CUs[0].fileNames[len(CUs[0].fileNames)-1] \x00
+// ...
+// filetabOffset[SUM(CUs,fileNames)-1] -> CUs[len(CU)-1].fileNames[len(CUs[len(CU)-1].fileNames)-1] \x00
+func makeFilenametab(cus []compilationUnit) (cutab []uint32, filetab []byte, cuOffsets []uint32) {
+ cuOffsets = make([]uint32, len(cus))
+ cuOffset := 0
+ fileOffset := 0
+
+ for i, cu := range cus {
+ cuOffsets[i] = uint32(cuOffset)
+
+ for _, name := range cu.fileNames {
+ cutab = append(cutab, uint32(fileOffset))
+
+ fileOffset += len(name) + 1
+ filetab = append(filetab, name...)
+ filetab = append(filetab, 0)
+ }
+
+ cuOffset += len(cu.fileNames)
+ }
+
+ return
+}
+
+func writeFuncdata(out *[]byte, funcs []Func) (fstart int, funcdataOffs [][]uint32) {
+ fstart = len(*out)
+ *out = append(*out, byte(0))
+ offs := uint32(1)
+
+ funcdataOffs = make([][]uint32, len(funcs))
+ for i, f := range funcs {
+
+ var writer = func(fd encoding.BinaryMarshaler) {
+ var ab []byte
+ var err error
+ if fd != nil {
+ ab, err = fd.MarshalBinary()
+ if err != nil {
+ panic(err)
+ }
+ funcdataOffs[i] = append(funcdataOffs[i], offs)
+ } else {
+ ab = []byte{0}
+ funcdataOffs[i] = append(funcdataOffs[i], _INVALID_FUNCDATA_OFFSET)
+ }
+ *out = append(*out, ab...)
+ offs += uint32(len(ab))
+ }
+
+ writer(f.ArgsPointerMaps)
+ writer(f.LocalsPointerMaps)
+ writer(f.StackObjects)
+ writer(f.InlTree)
+ writer(f.OpenCodedDeferInfo)
+ writer(f.ArgInfo)
+ writer(f.ArgLiveInfo)
+ writer(f.WrapInfo)
+ }
+ return
+}
+
+func makeFtab(funcs []_func, lastFuncSize uint32) (ftab []funcTab) {
+ // Allocate space for the pc->func table. This structure consists of a pc offset
+ // and an offset to the func structure. After that, we have a single pc
+ // value that marks the end of the last function in the binary.
+ var size int64 = int64(len(funcs)*2*4 + 4)
+ var startLocations = make([]uint32, len(funcs))
+ for i, f := range funcs {
+ size = rnd(size, int64(_PtrSize))
+ //writePCToFunc
+ startLocations[i] = uint32(size)
+ size += int64(uint8(_FUNC_SIZE)+f.nfuncdata*4+uint8(f.npcdata)*4)
+ }
+
+ ftab = make([]funcTab, 0, len(funcs)+1)
+
+ // write a map of pc->func info offsets
+ for i, f := range funcs {
+ ftab = append(ftab, funcTab{uint32(f.entryOff), uint32(startLocations[i])})
+ }
+
+ // Final entry of table is just end pc offset.
+ lastFunc := funcs[len(funcs)-1]
+ ftab = append(ftab, funcTab{uint32(lastFunc.entryOff + lastFuncSize), 0})
+
+ return
+}
+
+// Pcln table format: [...]funcTab + [...]_Func
+func makePclntable(funcs []_func, lastFuncSize uint32, pcdataOffs [][]uint32, funcdataOffs [][]uint32) (pclntab []byte) {
+ // Allocate space for the pc->func table. This structure consists of a pc offset
+ // and an offset to the func structure. After that, we have a single pc
+ // value that marks the end of the last function in the binary.
+ var size int64 = int64(len(funcs)*2*4 + 4)
+ var startLocations = make([]uint32, len(funcs))
+ for i := range funcs {
+ size = rnd(size, int64(_PtrSize))
+ //writePCToFunc
+ startLocations[i] = uint32(size)
+ size += int64(int(_FUNC_SIZE)+len(funcdataOffs[i])*4+len(pcdataOffs[i])*4)
+ }
+
+ pclntab = make([]byte, size, size)
+
+ // write a map of pc->func info offsets
+ offs := 0
+ for i, f := range funcs {
+ byteOrder.PutUint32(pclntab[offs:offs+4], uint32(f.entryOff))
+ byteOrder.PutUint32(pclntab[offs+4:offs+8], uint32(startLocations[i]))
+ offs += 8
+ }
+ // Final entry of table is just end pc offset.
+ lastFunc := funcs[len(funcs)-1]
+ byteOrder.PutUint32(pclntab[offs:offs+4], uint32(lastFunc.entryOff+lastFuncSize))
+
+ // write func info table
+ for i, f := range funcs {
+ off := startLocations[i]
+
+ // write _func structure to pclntab
+ fb := rt.BytesFrom(unsafe.Pointer(&f), int(_FUNC_SIZE), int(_FUNC_SIZE))
+ copy(pclntab[off:off+uint32(_FUNC_SIZE)], fb)
+ off += uint32(_FUNC_SIZE)
+
+ // NOTICE: _func.pcdata always starts from PcUnsafePoint, which is index 3
+ for j := 3; j < len(pcdataOffs[i]); j++ {
+ byteOrder.PutUint32(pclntab[off:off+4], uint32(pcdataOffs[i][j]))
+ off += 4
+ }
+
+ // funcdata refs as offsets from gofunc
+ for _, funcdata := range funcdataOffs[i] {
+ byteOrder.PutUint32(pclntab[off:off+4], uint32(funcdata))
+ off += 4
+ }
+
+ }
+
+ return
+}
+
+// findfunc table used to map pc to belonging func,
+// returns the index in the func table.
+//
+// All text section are divided into buckets sized _BUCKETSIZE(4K):
+// every bucket is divided into _SUBBUCKETS sized _SUB_BUCKETSIZE(64),
+// and it has a base idx to plus the offset stored in jth subbucket.
+// see findfunc() in runtime/symtab.go
+func writeFindfunctab(out *[]byte, ftab []funcTab) (start int) {
+ start = len(*out)
+
+ max := ftab[len(ftab)-1].entry
+ min := ftab[0].entry
+ nbuckets := (max - min + _BUCKETSIZE - 1) / _BUCKETSIZE
+ n := (max - min + _SUB_BUCKETSIZE - 1) / _SUB_BUCKETSIZE
+
+ tab := make([]findfuncbucket, 0, nbuckets)
+ var s, e = 0, 0
+ for i := 0; i<int(nbuckets); i++ {
+ var pc = min + uint32((i+1)*_BUCKETSIZE)
+ // find the end func of the bucket
+ for ; e < len(ftab)-1 && ftab[e+1].entry <= pc; e++ {}
+ // store the start func of the bucket
+ var fb = findfuncbucket{idx: uint32(s)}
+
+ for j := 0; j<_SUBBUCKETS && (i*_SUBBUCKETS+j)<int(n); j++ {
+ pc = min + uint32(i*_BUCKETSIZE) + uint32((j+1)*_SUB_BUCKETSIZE)
+ var ss = s
+ // find the end func of the subbucket
+ for ; ss < len(ftab)-1 && ftab[ss+1].entry <= pc; ss++ {}
+ // store the start func of the subbucket
+ fb._SUBBUCKETS[j] = byte(uint32(s) - fb.idx)
+ s = ss
+ }
+ s = e
+ tab = append(tab, fb)
+ }
+
+ // write findfuncbucket
+ if len(tab) > 0 {
+ size := int(unsafe.Sizeof(findfuncbucket{}))*len(tab)
+ *out = append(*out, rt.BytesFrom(unsafe.Pointer(&tab[0]), size, size)...)
+ }
+ return
+}
+
+func makeModuledata(name string, filenames []string, funcs []Func, text []byte) (mod *moduledata) {
+ mod = new(moduledata)
+ mod.modulename = name
+
+ // make filename table
+ cu := make([]string, 0, len(filenames))
+ for _, f := range filenames {
+ cu = append(cu, f)
+ }
+ cutab, filetab, cuOffs := makeFilenametab([]compilationUnit{{cu}})
+ mod.cutab = cutab
+ mod.filetab = filetab
+
+ // make funcname table
+ funcnametab, nameOffs := makeFuncnameTab(funcs)
+ mod.funcnametab = funcnametab
+
+ // make pcdata table
+ // NOTICE: _func only use offset to index pcdata, thus no need mmap() pcdata
+ pctab, pcdataOffs, _funcs := makePctab(funcs, cuOffs, nameOffs)
+ mod.pctab = pctab
+
+ // write func data
+ // NOTICE: _func use mod.gofunc+offset to directly point funcdata, thus need cache funcdata
+ // TODO: estimate accurate capacity
+ cache := make([]byte, 0, len(funcs)*int(_PtrSize))
+ fstart, funcdataOffs := writeFuncdata(&cache, funcs)
+
+ // make pc->func (binary search) func table
+ lastFuncsize := funcs[len(funcs)-1].TextSize
+ ftab := makeFtab(_funcs, lastFuncsize)
+ mod.ftab = ftab
+
+ // write pc->func (modmap) findfunc table
+ ffstart := writeFindfunctab(&cache, ftab)
+
+ // make pclnt table
+ pclntab := makePclntable(_funcs, lastFuncsize, pcdataOffs, funcdataOffs)
+ mod.pclntable = pclntab
+
+ // mmap() text and funcdata segements
+ p := os.Getpagesize()
+ size := int(rnd(int64(len(text)), int64(p)))
+ addr := mmap(size)
+ // copy the machine code
+ s := rt.BytesFrom(unsafe.Pointer(addr), len(text), size)
+ copy(s, text)
+ // make it executable
+ mprotect(addr, size)
+
+ // assign addresses
+ mod.text = addr
+ mod.etext = addr + uintptr(size)
+ mod.minpc = addr
+ mod.maxpc = addr + uintptr(len(text))
+
+ // cache funcdata and findfuncbucket
+ moduleCache.Lock()
+ moduleCache.m[mod] = cache
+ moduleCache.Unlock()
+ mod.gofunc = uintptr(unsafe.Pointer(&cache[fstart]))
+ mod.findfunctab = uintptr(unsafe.Pointer(&cache[ffstart]))
+
+ // make pc header
+ mod.pcHeader = &pcHeader {
+ magic : _Magic,
+ minLC : _MinLC,
+ ptrSize : _PtrSize,
+ nfunc : len(funcs),
+ nfiles: uint(len(cu)),
+ textStart: mod.text,
+ funcnameOffset: getOffsetOf(moduledata{}, "funcnametab"),
+ cuOffset: getOffsetOf(moduledata{}, "cutab"),
+ filetabOffset: getOffsetOf(moduledata{}, "filetab"),
+ pctabOffset: getOffsetOf(moduledata{}, "pctab"),
+ pclnOffset: getOffsetOf(moduledata{}, "pclntable"),
+ }
+
+ // sepecial case: gcdata and gcbss must by non-empty
+ mod.gcdata = uintptr(unsafe.Pointer(&emptyByte))
+ mod.gcbss = uintptr(unsafe.Pointer(&emptyByte))
+
+ return
+}
+
+// makePctab generates pcdelta->valuedelta tables for functions,
+// and returns the table and the entry offset of every kind pcdata in the table.
+func makePctab(funcs []Func, cuOffset []uint32, nameOffset []int32) (pctab []byte, pcdataOffs [][]uint32, _funcs []_func) {
+ _funcs = make([]_func, len(funcs))
+
+ // Pctab offsets of 0 are considered invalid in the runtime. We respect
+ // that by just padding a single byte at the beginning of runtime.pctab,
+ // that way no real offsets can be zero.
+ pctab = make([]byte, 1, 12*len(funcs)+1)
+ pcdataOffs = make([][]uint32, len(funcs))
+
+ for i, f := range funcs {
+ _f := &_funcs[i]
+
+ var writer = func(pc *Pcdata) {
+ var ab []byte
+ var err error
+ if pc != nil {
+ ab, err = pc.MarshalBinary()
+ if err != nil {
+ panic(err)
+ }
+ pcdataOffs[i] = append(pcdataOffs[i], uint32(len(pctab)))
+ } else {
+ ab = []byte{0}
+ pcdataOffs[i] = append(pcdataOffs[i], _PCDATA_INVALID_OFFSET)
+ }
+ pctab = append(pctab, ab...)
+ }
+
+ if f.Pcsp != nil {
+ _f.pcsp = uint32(len(pctab))
+ }
+ writer(f.Pcsp)
+ if f.Pcfile != nil {
+ _f.pcfile = uint32(len(pctab))
+ }
+ writer(f.Pcfile)
+ if f.Pcline != nil {
+ _f.pcln = uint32(len(pctab))
+ }
+ writer(f.Pcline)
+ writer(f.PcUnsafePoint)
+ writer(f.PcStackMapIndex)
+ writer(f.PcInlTreeIndex)
+ writer(f.PcArgLiveIndex)
+
+ _f.entryOff = f.EntryOff
+ _f.nameOff = nameOffset[i]
+ _f.args = f.ArgsSize
+ _f.deferreturn = f.DeferReturn
+ // NOTICE: _func.pcdata is always as [PCDATA_UnsafePoint(0) : PCDATA_ArgLiveIndex(3)]
+ _f.npcdata = uint32(_N_PCDATA)
+ _f.cuOffset = cuOffset[i]
+ _f.funcID = f.ID
+ _f.flag = f.Flag
+ _f.nfuncdata = uint8(_N_FUNCDATA)
+ }
+
+ return
+}
+
+func registerFunction(name string, pc uintptr, textSize uintptr, fp int, args int, size uintptr, argptrs uintptr, localptrs uintptr) {} \ No newline at end of file
diff --git a/vendor/github.com/bytedance/sonic/loader/loader.go b/vendor/github.com/bytedance/sonic/loader/loader.go
new file mode 100644
index 000000000..929d8c23d
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/loader/loader.go
@@ -0,0 +1,37 @@
+/**
+ * Copyright 2023 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 loader
+
+import (
+ `unsafe`
+)
+
+// Function is a function pointer
+type Function unsafe.Pointer
+
+// Options used to load a module
+type Options struct {
+ // NoPreempt is used to disable async preemption for this module
+ NoPreempt bool
+}
+
+// Loader is a helper used to load a module simply
+type Loader struct {
+ Name string // module name
+ File string // file name
+ Options
+} \ No newline at end of file
diff --git a/vendor/github.com/bytedance/sonic/loader/loader_go115.go b/vendor/github.com/bytedance/sonic/loader/loader_go115.go
new file mode 100644
index 000000000..1e44b36a6
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/loader/loader_go115.go
@@ -0,0 +1,33 @@
+//go:build go1.15 && !go1.18
+// +build go1.15,!go1.18
+
+/*
+ * 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 loader
+
+import (
+
+ `github.com/bytedance/sonic/internal/loader`
+)
+
+func (self Loader) LoadOne(text []byte, funcName string, frameSize int, argSize int, argStackmap []bool, localStackmap []bool) Function {
+ return Function(loader.Loader(text).Load(funcName, frameSize, argSize, argStackmap, localStackmap))
+}
+
+func Load(modulename string, filenames []string, funcs []Func, text []byte) (out []Function) {
+ panic("not implemented")
+} \ No newline at end of file
diff --git a/vendor/github.com/bytedance/sonic/loader/loader_go118.go b/vendor/github.com/bytedance/sonic/loader/loader_go118.go
new file mode 100644
index 000000000..9a0fe4843
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/loader/loader_go118.go
@@ -0,0 +1,104 @@
+//go:build go1.18 && !go1.21
+// +build go1.18,!go1.21
+
+/*
+ * 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 loader
+
+import (
+ `github.com/bytedance/sonic/internal/rt`
+)
+
+// LoadFuncs loads only one function as module, and returns the function pointer
+// - text: machine code
+// - funcName: function name
+// - frameSize: stack frame size.
+// - argSize: argument total size (in bytes)
+// - argPtrs: indicates if a slot (8 Bytes) of arguments memory stores pointer, from low to high
+// - localPtrs: indicates if a slot (8 Bytes) of local variants memory stores pointer, from low to high
+//
+// WARN:
+// - the function MUST has fixed SP offset equaling to this, otherwise it go.gentraceback will fail
+// - the function MUST has only one stack map for all arguments and local variants
+func (self Loader) LoadOne(text []byte, funcName string, frameSize int, argSize int, argPtrs []bool, localPtrs []bool) Function {
+ size := uint32(len(text))
+
+ fn := Func{
+ Name: funcName,
+ TextSize: size,
+ ArgsSize: int32(argSize),
+ }
+
+ // NOTICE: suppose the function has fixed SP offset equaling to frameSize, thus make only one pcsp pair
+ fn.Pcsp = &Pcdata{
+ {PC: size, Val: int32(frameSize)},
+ }
+
+ if self.NoPreempt {
+ fn.PcUnsafePoint = &Pcdata{
+ {PC: size, Val: PCDATA_UnsafePointUnsafe},
+ }
+ } else {
+ fn.PcUnsafePoint = &Pcdata{
+ {PC: size, Val: PCDATA_UnsafePointSafe},
+ }
+ }
+
+ // NOTICE: suppose the function has only one stack map at index 0
+ fn.PcStackMapIndex = &Pcdata{
+ {PC: size, Val: 0},
+ }
+
+ if argPtrs != nil {
+ args := rt.StackMapBuilder{}
+ for _, b := range argPtrs {
+ args.AddField(b)
+ }
+ fn.ArgsPointerMaps = args.Build()
+ }
+
+ if localPtrs != nil {
+ locals := rt .StackMapBuilder{}
+ for _, b := range localPtrs {
+ locals.AddField(b)
+ }
+ fn.LocalsPointerMaps = locals.Build()
+ }
+
+ out := Load(text, []Func{fn}, self.Name + funcName, []string{self.File})
+ return out[0]
+}
+
+// Load loads given machine codes and corresponding function information into go moduledata
+// and returns runnable function pointer
+// WARN: this API is experimental, use it carefully
+func Load(text []byte, funcs []Func, modulename string, filenames []string) (out []Function) {
+ // generate module data and allocate memory address
+ mod := makeModuledata(modulename, filenames, funcs, text)
+
+ // verify and register the new module
+ moduledataverify1(mod)
+ registerModule(mod)
+
+ // encapsulate function address
+ out = make([]Function, len(funcs))
+ for i, f := range funcs {
+ m := uintptr(mod.text + uintptr(f.EntryOff))
+ out[i] = Function(&m)
+ }
+ return
+} \ No newline at end of file
diff --git a/vendor/github.com/bytedance/sonic/loader/mmap_unix.go b/vendor/github.com/bytedance/sonic/loader/mmap_unix.go
new file mode 100644
index 000000000..50b80bf20
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/loader/mmap_unix.go
@@ -0,0 +1,45 @@
+//go:build darwin || linux
+// +build darwin linux
+
+/**
+ * Copyright 2023 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 loader
+
+import (
+ `syscall`
+)
+
+const (
+ _AP = syscall.MAP_ANON | syscall.MAP_PRIVATE
+ _RX = syscall.PROT_READ | syscall.PROT_EXEC
+ _RW = syscall.PROT_READ | syscall.PROT_WRITE
+)
+
+
+func mmap(nb int) uintptr {
+ if m, _, e := syscall.RawSyscall6(syscall.SYS_MMAP, 0, uintptr(nb), _RW, _AP, 0, 0); e != 0 {
+ panic(e)
+ } else {
+ return m
+ }
+}
+
+func mprotect(p uintptr, nb int) {
+ if _, _, err := syscall.RawSyscall(syscall.SYS_MPROTECT, p, uintptr(nb), _RX); err != 0 {
+ panic(err)
+ }
+} \ No newline at end of file
diff --git a/vendor/github.com/bytedance/sonic/loader/mmap_windows.go b/vendor/github.com/bytedance/sonic/loader/mmap_windows.go
new file mode 100644
index 000000000..1760a7117
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/loader/mmap_windows.go
@@ -0,0 +1,84 @@
+//go:build windows
+// +build windows
+
+// build
+
+/*
+ * 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 loader
+
+import (
+ `syscall`
+ `unsafe`
+)
+
+const (
+ MEM_COMMIT = 0x00001000
+ MEM_RESERVE = 0x00002000
+)
+
+var (
+ libKernel32 = syscall.NewLazyDLL("KERNEL32.DLL")
+ libKernel32_VirtualAlloc = libKernel32.NewProc("VirtualAlloc")
+ libKernel32_VirtualProtect = libKernel32.NewProc("VirtualProtect")
+)
+
+func mmap(nb int) uintptr {
+ addr, err := winapi_VirtualAlloc(0, nb, MEM_COMMIT|MEM_RESERVE, syscall.PAGE_READWRITE)
+ if err != nil {
+ panic(err)
+ }
+ return addr
+}
+
+func mprotect(p uintptr, nb int) (oldProtect int) {
+ err := winapi_VirtualProtect(p, nb, syscall.PAGE_EXECUTE_READ, &oldProtect)
+ if err != nil {
+ panic(err)
+ }
+ return
+}
+
+// winapi_VirtualAlloc allocate memory
+// Doc: https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc
+func winapi_VirtualAlloc(lpAddr uintptr, dwSize int, flAllocationType int, flProtect int) (uintptr, error) {
+ r1, _, err := libKernel32_VirtualAlloc.Call(
+ lpAddr,
+ uintptr(dwSize),
+ uintptr(flAllocationType),
+ uintptr(flProtect),
+ )
+ if r1 == 0 {
+ return 0, err
+ }
+ return r1, nil
+}
+
+// winapi_VirtualProtect change memory protection
+// Doc: https://docs.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualprotect
+func winapi_VirtualProtect(lpAddr uintptr, dwSize int, flNewProtect int, lpflOldProtect *int) error {
+ r1, _, err := libKernel32_VirtualProtect.Call(
+ lpAddr,
+ uintptr(dwSize),
+ uintptr(flNewProtect),
+ uintptr(unsafe.Pointer(lpflOldProtect)),
+ )
+ if r1 == 0 {
+ return err
+ }
+ return nil
+}
diff --git a/vendor/github.com/bytedance/sonic/loader/pcdata.go b/vendor/github.com/bytedance/sonic/loader/pcdata.go
new file mode 100644
index 000000000..b5c62d17b
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/loader/pcdata.go
@@ -0,0 +1,100 @@
+/**
+ * Copyright 2023 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 loader
+
+const (
+ _N_PCDATA = 4
+
+ _PCDATA_UnsafePoint = 0
+ _PCDATA_StackMapIndex = 1
+ _PCDATA_InlTreeIndex = 2
+ _PCDATA_ArgLiveIndex = 3
+
+ _PCDATA_INVALID_OFFSET = 0
+)
+
+const (
+ // PCDATA_UnsafePoint values.
+ PCDATA_UnsafePointSafe = -1 // Safe for async preemption
+ PCDATA_UnsafePointUnsafe = -2 // Unsafe for async preemption
+
+ // PCDATA_Restart1(2) apply on a sequence of instructions, within
+ // which if an async preemption happens, we should back off the PC
+ // to the start of the sequence when resume.
+ // We need two so we can distinguish the start/end of the sequence
+ // in case that two sequences are next to each other.
+ PCDATA_Restart1 = -3
+ PCDATA_Restart2 = -4
+
+ // Like PCDATA_RestartAtEntry, but back to function entry if async
+ // preempted.
+ PCDATA_RestartAtEntry = -5
+
+ _PCDATA_START_VAL = -1
+)
+
+var emptyByte byte
+
+func encodeValue(v int) []byte {
+ return encodeVariant(toZigzag(v))
+}
+
+func toZigzag(v int) int {
+ return (v << 1) ^ (v >> 31)
+}
+
+func encodeVariant(v int) []byte {
+ var u int
+ var r []byte
+
+ /* split every 7 bits */
+ for v > 127 {
+ u = v & 0x7f
+ v = v >> 7
+ r = append(r, byte(u) | 0x80)
+ }
+
+ /* check for last one */
+ if v == 0 {
+ return r
+ }
+
+ /* add the last one */
+ r = append(r, byte(v))
+ return r
+}
+
+type Pcvalue struct {
+ PC uint32 // PC offset from func entry
+ Val int32
+}
+
+type Pcdata []Pcvalue
+
+// see https://docs.google.com/document/d/1lyPIbmsYbXnpNj57a261hgOYVpNRcgydurVQIyZOz_o/pub
+func (self Pcdata) MarshalBinary() (data []byte, err error) {
+ // delta value always starts from -1
+ sv := int32(_PCDATA_START_VAL)
+ sp := uint32(0)
+ for _, v := range self {
+ data = append(data, encodeVariant(toZigzag(int(v.Val - sv)))...)
+ data = append(data, encodeVariant(int(v.PC - sp))...)
+ sp = v.PC
+ sv = v.Val
+ }
+ return
+} \ No newline at end of file
diff --git a/vendor/github.com/bytedance/sonic/loader/stubs.go b/vendor/github.com/bytedance/sonic/loader/stubs.go
new file mode 100644
index 000000000..71439c4b7
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/loader/stubs.go
@@ -0,0 +1,35 @@
+/**
+ * Copyright 2023 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 loader
+
+import (
+ _ `unsafe`
+)
+
+//go:linkname lastmoduledatap runtime.lastmoduledatap
+//goland:noinspection GoUnusedGlobalVariable
+var lastmoduledatap *moduledata
+
+func registerModule(mod *moduledata) {
+ lastmoduledatap.next = mod
+ lastmoduledatap = mod
+}
+
+//go:linkname moduledataverify1 runtime.moduledataverify1
+func moduledataverify1(_ *moduledata)
+
+