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  `