summaryrefslogtreecommitdiff
path: root/vendor/github.com/bytedance/sonic/loader/wrapper.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/bytedance/sonic/loader/wrapper.go')
-rw-r--r--vendor/github.com/bytedance/sonic/loader/wrapper.go185
1 files changed, 185 insertions, 0 deletions
diff --git a/vendor/github.com/bytedance/sonic/loader/wrapper.go b/vendor/github.com/bytedance/sonic/loader/wrapper.go
new file mode 100644
index 000000000..73ebc3518
--- /dev/null
+++ b/vendor/github.com/bytedance/sonic/loader/wrapper.go
@@ -0,0 +1,185 @@
+/**
+* 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 (
+ `reflect`
+ `unsafe`
+
+ `github.com/bytedance/sonic/internal/abi`
+ `github.com/bytedance/sonic/internal/rt`
+)
+
+var _C_Redzone = []bool{false, false, false, false}
+
+// CFunc is a function information for C func
+type CFunc struct {
+ // C function name
+ Name string
+
+ // entry pc relative to entire text segment
+ EntryOff uint32
+
+ // function text size in bytes
+ TextSize uint32
+
+ // maximum stack depth of the function
+ MaxStack uintptr
+
+ // PC->SP delta lists of the function
+ Pcsp [][2]uint32
+}
+
+// GoC is the wrapper for Go calls to C
+type GoC struct {
+ // CName is the name of corresponding C function
+ CName string
+
+ // CEntry points out where to store the entry address of corresponding C function.
+ // It won't be set if nil
+ CEntry *uintptr
+
+ // GoFunc is the POINTER of corresponding go stub function.
+ // It is used to generate Go-C ABI conversion wrapper and receive the wrapper's address
+ // eg. &func(a int, b int) int
+ // FOR
+ // int add(int a, int b)
+ // It won't be set if nil
+ GoFunc interface{}
+}
+
+// WrapGoC wraps C functions and loader it into Go stubs
+func WrapGoC(text []byte, natives []CFunc, stubs []GoC, modulename string, filename string) {
+ funcs := make([]Func, len(natives))
+
+ // register C funcs
+ for i, f := range natives {
+ fn := Func{
+ Flag: FuncFlag_ASM,
+ EntryOff: f.EntryOff,
+ TextSize: f.TextSize,
+ Name: f.Name,
+ }
+ if len(f.Pcsp) != 0 {
+ fn.Pcsp = (*Pcdata)(unsafe.Pointer(&natives[i].Pcsp))
+ }
+ // NOTICE: always forbid async preempt
+ fn.PcUnsafePoint = &Pcdata{
+ {PC: f.TextSize, Val: PCDATA_UnsafePointUnsafe},
+ }
+ // NOTICE: always refer to first file
+ fn.Pcfile = &Pcdata{
+ {PC: f.TextSize, Val: 0},
+ }
+ // NOTICE: always refer to first line
+ fn.Pcline = &Pcdata{
+ {PC: f.TextSize, Val: 1},
+ }
+ // NOTICE: copystack need locals stackmap
+ fn.PcStackMapIndex = &Pcdata{
+ {PC: f.TextSize, Val: 0},
+ }
+ sm := rt.StackMapBuilder{}
+ sm.AddField(false)
+ fn.ArgsPointerMaps = sm.Build()
+ fn.LocalsPointerMaps = sm.Build()
+ funcs[i] = fn
+ }
+ rets := Load(text, funcs, modulename, []string{filename})
+
+ // got absolute entry address
+ native_entry := **(**uintptr)(unsafe.Pointer(&rets[0]))
+ // println("native_entry: ", native_entry)
+
+ wraps := make([]Func, 0, len(stubs))
+ wrapIds := make([]int, 0, len(stubs))
+ code := make([]byte, 0, len(wraps))
+ entryOff := uint32(0)
+
+ // register go wrappers
+ for i := range stubs {
+ for j := range natives {
+ if stubs[i].CName != natives[j].Name {
+ continue
+ }
+
+ // calculate corresponding C entry
+ pc := uintptr(native_entry + uintptr(natives[j].EntryOff))
+ if stubs[i].CEntry != nil {
+ *stubs[i].CEntry = pc
+ }
+
+ // no need to generate wrapper, continue next
+ if stubs[i].GoFunc == nil {
+ continue
+ }
+
+ // assemble wrapper codes
+ layout := abi.NewFunctionLayout(reflect.TypeOf(stubs[i].GoFunc).Elem())
+ frame := abi.NewFrame(&layout, _C_Redzone, true)
+ tcode := abi.CallC(pc, frame, natives[j].MaxStack)
+ code = append(code, tcode...)
+ size := uint32(len(tcode))
+
+ fn := Func{
+ Flag: FuncFlag_ASM,
+ ArgsSize: int32(layout.ArgSize()),
+ EntryOff: entryOff,
+ TextSize: size,
+ Name: stubs[i].CName + "_go",
+ }
+
+ // add check-stack and grow-stack texts' pcsp
+ fn.Pcsp = &Pcdata{
+ {PC: uint32(frame.StackCheckTextSize()), Val: 0},
+ {PC: size - uint32(frame.GrowStackTextSize()), Val: int32(frame.Size())},
+ {PC: size, Val: 0},
+ }
+ // NOTICE: always refer to first file
+ fn.Pcfile = &Pcdata{
+ {PC: size, Val: 0},
+ }
+ // NOTICE: always refer to first line
+ fn.Pcline = &Pcdata{
+ {PC: size, Val: 1},
+ }
+ // NOTICE: always forbid async preempt
+ fn.PcUnsafePoint = &Pcdata{
+ {PC: size, Val: PCDATA_UnsafePointUnsafe},
+ }
+
+ // register pointer stackmaps
+ fn.PcStackMapIndex = &Pcdata{
+ {PC: size, Val: 0},
+ }
+ fn.ArgsPointerMaps = frame.ArgPtrs()
+ fn.LocalsPointerMaps = frame.LocalPtrs()
+
+ entryOff += size
+ wraps = append(wraps, fn)
+ wrapIds = append(wrapIds, i)
+ }
+ }
+ gofuncs := Load(code, wraps, modulename+"/go", []string{filename+".go"})
+
+ // set go func value
+ for i := range gofuncs {
+ idx := wrapIds[i]
+ w := rt.UnpackEface(stubs[idx].GoFunc)
+ *(*Function)(w.Value) = gofuncs[i]
+ }
+}