diff options
Diffstat (limited to 'vendor/github.com/bytedance/sonic/loader/wrapper.go')
-rw-r--r-- | vendor/github.com/bytedance/sonic/loader/wrapper.go | 185 |
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] + } +} |