github.com/goplus/reflectx@v1.2.2/cmd/icall_gen/icall_gen.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "flag" 6 "fmt" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "strconv" 11 "strings" 12 ) 13 14 var ( 15 output = flag.String("o", "", "set output file path") 16 pkgName = flag.String("pkg", "icall", "set package name") 17 presetSize = flag.Int("size", 0, "set methods preset size") 18 ) 19 20 func main() { 21 flag.Parse() 22 if *output == "" || *pkgName == "" || *presetSize == 0 { 23 flag.Usage() 24 return 25 } 26 // write icall.go 27 err := writeFile(*output, *pkgName, *presetSize) 28 if err != nil { 29 fmt.Fprintln(os.Stderr, err) 30 os.Exit(2) 31 } 32 // write icall_regabi.go 33 err = writeRegAbi(*output, *pkgName, *presetSize) 34 if err != nil { 35 fmt.Fprintln(os.Stderr, err) 36 os.Exit(2) 37 } 38 } 39 40 func writeFile(filename string, pkgName string, size int) error { 41 dir, _ := filepath.Split(filename) 42 if dir != "" { 43 err := os.MkdirAll(dir, 0777) 44 if err != nil { 45 return fmt.Errorf("make dir %v error: %v", dir, err) 46 } 47 } 48 49 var buf bytes.Buffer 50 r := strings.NewReplacer("$pkgname", pkgName, "$max_size", strconv.Itoa(size)) 51 buf.WriteString(r.Replace(head)) 52 53 fnWrite := func(name string, t string) { 54 buf.WriteString(fmt.Sprintf("\nvar %v = []interface{}{\n", name)) 55 for i := 0; i < size; i++ { 56 r := strings.NewReplacer("$index", strconv.Itoa(i)) 57 buf.WriteString(r.Replace(t)) 58 } 59 buf.WriteString("}\n") 60 } 61 fnWrite("icall_array", templ_fn) 62 return ioutil.WriteFile(filename, buf.Bytes(), 0666) 63 } 64 65 var head = `//go:build (!go1.17 || (go1.17 && !go1.18 && !goexperiment.regabireflect) || (go1.18 && !go1.19 && !goexperiment.regabireflect && !amd64) || (go1.19 && !go1.20 && !goexperiment.regabiargs && !amd64 && !arm64 && !ppc64 && !ppc64le) || (go1.20 && !goexperiment.regabiargs && !amd64 && !arm64 && !ppc64 && !ppc64le && !riscv64)) && (!js || (js && wasm)) 66 // +build !go1.17 go1.17,!go1.18,!goexperiment.regabireflect go1.18,!go1.19,!goexperiment.regabireflect,!amd64 go1.19,!go1.20,!goexperiment.regabiargs,!amd64,!arm64,!ppc64,!ppc64le go1.20,!goexperiment.regabiargs,!amd64,!arm64,!ppc64,!ppc64le,!riscv64 67 // +build !js js,wasm 68 69 package $pkgname 70 71 import ( 72 "reflect" 73 "unsafe" 74 75 "github.com/goplus/reflectx/abi" 76 ) 77 78 const capacity = $max_size 79 80 type provider struct { 81 used map[int]*abi.MethodInfo 82 } 83 84 func (p *provider) Insert(info *abi.MethodInfo) (ifn unsafe.Pointer, index int) { 85 for i := 0; i < capacity; i++ { 86 if _, ok := p.used[i]; !ok { 87 p.used[i] = info 88 fn := icall_array[i] 89 return unsafe.Pointer(reflect.ValueOf(fn).Pointer()), i 90 } 91 } 92 return nil, -1 93 } 94 95 func (p *provider) Available() int { 96 return capacity - len(p.used) 97 } 98 99 func (p *provider) Remove(indexs []int) { 100 for _, n := range indexs { 101 delete(p.used, n) 102 } 103 } 104 105 func (p *provider) Used() int { 106 return len(p.used) 107 } 108 109 func (p *provider) Cap() int { 110 return len(icall_array) 111 } 112 113 func (p *provider) Clear() { 114 p.used = make(map[int]*abi.MethodInfo) 115 } 116 117 var ( 118 mp = &provider{ 119 used: make(map[int]*abi.MethodInfo), 120 } 121 ) 122 123 func init() { 124 abi.AddMethodProvider(mp) 125 } 126 127 func i_x(index int, ptr unsafe.Pointer, p unsafe.Pointer) { 128 info := mp.used[index] 129 var receiver reflect.Value 130 if !info.Pointer && info.OnePtr { 131 receiver = reflect.NewAt(info.Type, unsafe.Pointer(&ptr)).Elem() 132 } else { 133 receiver = reflect.NewAt(info.Type, ptr) 134 if !info.Pointer || info.Indirect { 135 receiver = receiver.Elem() 136 } 137 } 138 in := []reflect.Value{receiver} 139 if inCount := info.Func.Type().NumIn(); inCount > 1 { 140 sz := info.InTyp.Size() 141 buf := make([]byte, sz, sz) 142 if sz > info.InSize { 143 sz = info.InSize 144 } 145 for i := uintptr(0); i < sz; i++ { 146 buf[i] = *(*byte)(add(p, i, "")) 147 } 148 var inArgs reflect.Value 149 if sz == 0 { 150 inArgs = reflect.New(info.InTyp).Elem() 151 } else { 152 inArgs = reflect.NewAt(info.InTyp, unsafe.Pointer(&buf[0])).Elem() 153 } 154 for i := 1; i < inCount; i++ { 155 in = append(in, inArgs.Field(i-1)) 156 } 157 } 158 var r []reflect.Value 159 if info.Variadic { 160 r = info.Func.CallSlice(in) 161 } else { 162 r = info.Func.Call(in) 163 } 164 if info.OutTyp.NumField() > 0 { 165 out := reflect.New(info.OutTyp).Elem() 166 for i, v := range r { 167 out.Field(i).Set(v) 168 } 169 po := unsafe.Pointer(out.UnsafeAddr()) 170 for i := uintptr(0); i < info.OutSize; i++ { 171 *(*byte)(add(p, info.InSize+i, "")) = *(*byte)(add(po, uintptr(i), "")) 172 } 173 } 174 } 175 176 func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { 177 return unsafe.Pointer(uintptr(p) + x) 178 } 179 180 type unsafeptr = unsafe.Pointer 181 ` 182 183 var templ_fn = ` func(p, a unsafeptr) { i_x($index, p, unsafeptr(&a)) }, 184 `