github.com/goplusjs/reflectx@v0.5.4/methodof.go (about)

     1  //go:build !js || (js && wasm)
     2  // +build !js js,wasm
     3  
     4  package reflectx
     5  
     6  import (
     7  	"fmt"
     8  	"log"
     9  	"reflect"
    10  	"sort"
    11  	"strings"
    12  	"sync"
    13  	"unsafe"
    14  )
    15  
    16  var (
    17  	typInfoMap   = make(map[reflect.Type][]*methodInfo)
    18  	valueInfoMap = make(map[reflect.Value]typeInfo)
    19  )
    20  
    21  func isMethod(typ reflect.Type) (ok bool) {
    22  	_, ok = typInfoMap[typ]
    23  	return
    24  }
    25  
    26  type typeInfo struct {
    27  	typ         reflect.Type
    28  	oneFieldPtr bool
    29  }
    30  
    31  type methodInfo struct {
    32  	Type     reflect.Type
    33  	Func     reflect.Value
    34  	inTyp    reflect.Type
    35  	outTyp   reflect.Type
    36  	name     string
    37  	index    int
    38  	isz      uintptr
    39  	osz      uintptr
    40  	pointer  bool
    41  	variadic bool
    42  	onePtr   bool
    43  }
    44  
    45  func MethodByIndex(typ reflect.Type, index int) reflect.Method {
    46  	m := MethodX(typ, index)
    47  	if isMethod(typ) {
    48  		tovalue(&m.Func).flag |= flagIndir
    49  	}
    50  	return m
    51  }
    52  
    53  func MethodByName(typ reflect.Type, name string) (m reflect.Method, ok bool) {
    54  	m, ok = MethodByNameX(typ, name)
    55  	if !ok {
    56  		return
    57  	}
    58  	if isMethod(typ) {
    59  		tovalue(&m.Func).flag |= flagIndir
    60  	}
    61  	return
    62  }
    63  
    64  func checkStoreMethodValue(v reflect.Value) {
    65  	if v.Kind() == reflect.Ptr {
    66  		v = v.Elem()
    67  	}
    68  	if !v.IsValid() {
    69  		return
    70  	}
    71  	typ := v.Type()
    72  	if isMethod(typ) {
    73  		valueInfoMap[v] = typeInfo{typ, checkOneFieldPtr(typ)}
    74  	}
    75  	if v.Kind() == reflect.Struct {
    76  		for i := 0; i < v.NumField(); i++ {
    77  			sf := v.Field(i)
    78  			checkStoreMethodValue(sf)
    79  		}
    80  	}
    81  }
    82  
    83  func resizeMethod(typ reflect.Type, mcount int, xcount int) error {
    84  	rt := totype(typ)
    85  	ut := toUncommonType(rt)
    86  	if ut == nil {
    87  		return fmt.Errorf("not found uncommonType of %v", typ)
    88  	}
    89  	if uint16(mcount) > ut.mcount {
    90  		return fmt.Errorf("too many methods of %v", typ)
    91  	}
    92  	ut.xcount = uint16(xcount)
    93  	return nil
    94  }
    95  
    96  // func updateMethod(typ reflect.Type, methods []Method, rmap map[reflect.Type]reflect.Type) bool {
    97  // 	ptyp := reflect.PtrTo(typ)
    98  // 	pinfos, ok := typInfoMap[ptyp]
    99  // 	if !ok && ptyp.NumMethod() > 0 {
   100  // 		log.Printf("warning cannot found type info: %v\n", ptyp)
   101  // 		return false
   102  // 	}
   103  // 	infos, ok := typInfoMap[typ]
   104  // 	if !ok && typ.NumMethod() > 0 {
   105  // 		log.Printf("warning cannot found type info: %v\n", typ)
   106  // 		return false
   107  // 	}
   108  // 	rt := totype(typ)
   109  // 	prt := totype(ptyp)
   110  // 	ms := toUncommonType(rt).exportedMethods()
   111  // 	pms := toUncommonType(prt).exportedMethods()
   112  // 	itype := itypeIndex(typ)
   113  // 	for _, m := range methods {
   114  // 		var i int
   115  // 		var index int
   116  // 		f, ok := ptyp.MethodByName(m.Name)
   117  // 		if !ok {
   118  // 			log.Printf("warning cannot found method: (%v).%v\n", ptyp, m.Name)
   119  // 			continue
   120  // 		}
   121  // 		i = f.Index
   122  // 		if !m.Pointer {
   123  // 			f, ok := typ.MethodByName(m.Name)
   124  // 			if !ok {
   125  // 				log.Printf("warning cannot found method: (%v).%v\n", typ, m.Name)
   126  // 			}
   127  // 			index = f.Index
   128  // 		}
   129  // 		inTyp, outTyp, mtyp, tfn, ifn, ptfn, pifn := createMethod(itype, typ, ptyp, m, i, index, rmap)
   130  // 		isz := argsTypeSize(inTyp, true)
   131  // 		osz := argsTypeSize(outTyp, false)
   132  // 		pindex := i
   133  // 		if !m.Pointer {
   134  // 			pindex = index
   135  // 		}
   136  // 		pms[i].mtyp = mtyp
   137  // 		pms[i].tfn = ptfn
   138  // 		pms[i].ifn = pifn
   139  // 		onePtr := checkOneFieldPtr(typ)
   140  // 		pinfos[i] = &methodInfo{
   141  // 			inTyp:    inTyp,
   142  // 			outTyp:   outTyp,
   143  // 			name:     m.Name,
   144  // 			index:    pindex,
   145  // 			isz:      isz,
   146  // 			osz:      osz,
   147  // 			pointer:  m.Pointer,
   148  // 			variadic: m.Type.IsVariadic(),
   149  // 			onePtr:   onePtr,
   150  // 		}
   151  // 		if !m.Pointer {
   152  // 			ms[index].mtyp = mtyp
   153  // 			ms[index].tfn = tfn
   154  // 			ms[index].ifn = ifn
   155  // 			infos[index] = &methodInfo{
   156  // 				inTyp:    inTyp,
   157  // 				outTyp:   outTyp,
   158  // 				name:     m.Name,
   159  // 				index:    index,
   160  // 				isz:      isz,
   161  // 				osz:      osz,
   162  // 				pointer:  m.Pointer,
   163  // 				variadic: m.Type.IsVariadic(),
   164  // 				onePtr:   onePtr,
   165  // 			}
   166  // 		}
   167  // 	}
   168  // 	return true
   169  // }
   170  
   171  func createMethod(itype int, typ reflect.Type, ptyp reflect.Type, m Method, i int, index int, max int, pmax int, isexport bool) (mfn reflect.Value, inTyp, outTyp reflect.Type, mtyp typeOff, tfn, ifn, ptfn, pifn textOff) {
   172  	var in []reflect.Type
   173  	var out []reflect.Type
   174  	var ntyp reflect.Type
   175  	in, out, ntyp, inTyp, outTyp = parserMethodType(m.Type, nil)
   176  	mtyp = resolveReflectType(totype(ntyp))
   177  	var ftyp reflect.Type
   178  	if m.Pointer {
   179  		ftyp = reflect.FuncOf(append([]reflect.Type{ptyp}, in...), out, m.Type.IsVariadic())
   180  	} else {
   181  		ftyp = reflect.FuncOf(append([]reflect.Type{typ}, in...), out, m.Type.IsVariadic())
   182  	}
   183  	output := len(out) > 0
   184  
   185  	mfn = reflect.MakeFunc(ftyp, m.Func)
   186  	ptr := tovalue(&mfn).ptr
   187  
   188  	sz := int(inTyp.Size())
   189  	ifunc := icall(itype, i, pmax, true, output)
   190  
   191  	if ifunc == nil {
   192  		log.Printf("warning cannot wrapper method index:%v, size: %v\n", i, sz)
   193  	} else {
   194  		pifn = resolveReflectText(unsafe.Pointer(reflect.ValueOf(ifunc).Pointer()))
   195  	}
   196  	tfn = resolveReflectText(unsafe.Pointer(ptr))
   197  	if !m.Pointer {
   198  		ctyp := reflect.FuncOf(append([]reflect.Type{ptyp}, in...), out, m.Type.IsVariadic())
   199  		cv := reflect.MakeFunc(ctyp, func(args []reflect.Value) (results []reflect.Value) {
   200  			return args[0].Elem().Method(index).Call(args[1:])
   201  		})
   202  		ptfn = resolveReflectText(tovalue(&cv).ptr)
   203  		ifunc := icall(itype, index, max, false, output)
   204  		if ifunc == nil {
   205  			log.Printf("warning cannot wrapper method index:%v, size: %v\n", i, sz)
   206  		} else {
   207  			ifn = resolveReflectText(unsafe.Pointer(reflect.ValueOf(ifunc).Pointer()))
   208  		}
   209  	} else {
   210  		ptfn = tfn
   211  	}
   212  	return
   213  }
   214  
   215  func setMethodSet(typ reflect.Type, methods []Method) error {
   216  	sort.Slice(methods, func(i, j int) bool {
   217  		n := strings.Compare(methods[i].Name, methods[j].Name)
   218  		if n == 0 && methods[i].Type == methods[j].Type {
   219  			panic(fmt.Sprintf("method redeclared: %v", methods[j].Name))
   220  		}
   221  		return n < 0
   222  	})
   223  	var mcount, pcount int
   224  	var xcount, pxcount int
   225  	pcount = len(methods)
   226  	var mlist []string
   227  	for _, m := range methods {
   228  		isexport := methodIsExported(m.Name)
   229  		if isexport {
   230  			pxcount++
   231  		}
   232  		if !m.Pointer {
   233  			if isexport {
   234  				xcount++
   235  			}
   236  			mlist = append(mlist, m.Name)
   237  			mcount++
   238  		}
   239  	}
   240  	ptyp := reflect.PtrTo(typ)
   241  	if err := resizeMethod(typ, mcount, xcount); err != nil {
   242  		return err
   243  	}
   244  	if err := resizeMethod(ptyp, pcount, pxcount); err != nil {
   245  		return err
   246  	}
   247  	rt := totype(typ)
   248  	prt := totype(ptyp)
   249  
   250  	ms := rt.methods()
   251  	pms := prt.methods()
   252  
   253  	infos := make([]*methodInfo, mcount, mcount)
   254  	pinfos := make([]*methodInfo, pcount, pcount)
   255  	itype := itypeIndex(typ)
   256  	var index int
   257  	for i, m := range methods {
   258  		isexport := methodIsExported(m.Name)
   259  		nm := newNameEx(m.Name, "", isexport, !isexport)
   260  		mname := resolveReflectName(nm)
   261  		if !isexport {
   262  			nm.setPkgPath(resolveReflectName(newName(m.PkgPath, "", false)))
   263  		}
   264  		mfn, inTyp, outTyp, mtyp, tfn, ifn, ptfn, pifn := createMethod(itype, typ, ptyp, m, i, index, mcount, pcount, isexport)
   265  		isz := argsTypeSize(inTyp, true)
   266  		osz := argsTypeSize(outTyp, false)
   267  		pindex := i
   268  		if !m.Pointer {
   269  			pindex = index
   270  		}
   271  		onePtr := checkOneFieldPtr(typ) || typ.Kind() == reflect.Func
   272  		pms[i].name = mname
   273  		pms[i].mtyp = mtyp
   274  		pms[i].tfn = ptfn
   275  		pms[i].ifn = pifn
   276  		pinfos[i] = &methodInfo{
   277  			Type:     ptyp,
   278  			Func:     mfn,
   279  			inTyp:    inTyp,
   280  			outTyp:   outTyp,
   281  			name:     m.Name,
   282  			index:    pindex,
   283  			isz:      isz,
   284  			osz:      osz,
   285  			pointer:  m.Pointer,
   286  			variadic: m.Type.IsVariadic(),
   287  			onePtr:   onePtr,
   288  		}
   289  		if !m.Pointer {
   290  			ms[index].name = mname
   291  			ms[index].mtyp = mtyp
   292  			ms[index].tfn = tfn
   293  			ms[index].ifn = ifn
   294  			infos[index] = &methodInfo{
   295  				Type:     typ,
   296  				Func:     mfn,
   297  				inTyp:    inTyp,
   298  				outTyp:   outTyp,
   299  				name:     m.Name,
   300  				index:    index,
   301  				isz:      isz,
   302  				osz:      osz,
   303  				pointer:  m.Pointer,
   304  				variadic: m.Type.IsVariadic(),
   305  				onePtr:   onePtr,
   306  			}
   307  			index++
   308  		}
   309  	}
   310  	typInfoMap[typ] = infos
   311  	typInfoMap[ptyp] = pinfos
   312  	return nil
   313  }
   314  
   315  func newMethodSet(styp reflect.Type, maxmfunc, maxpfunc int) reflect.Type {
   316  	rt, _ := newType("", "", styp, maxmfunc, 0)
   317  	prt, _ := newType("", "", reflect.PtrTo(styp), maxpfunc, 0)
   318  	rt.ptrToThis = resolveReflectType(prt)
   319  	(*ptrType)(unsafe.Pointer(prt)).elem = rt
   320  	setTypeName(rt, styp.PkgPath(), styp.Name())
   321  	prt.uncommon().pkgPath = resolveReflectName(newName(styp.PkgPath(), "", false))
   322  	typ := toType(rt)
   323  	if nt, ok := ntypeMap[styp]; ok {
   324  		ntypeMap[typ] = &Named{Name: nt.Name, PkgPath: nt.PkgPath, Type: typ, From: nt.From, Kind: nt.Kind}
   325  	}
   326  	return typ
   327  }
   328  
   329  // func _methodOf(styp reflect.Type, methods []Method) reflect.Type {
   330  // 	sort.Slice(methods, func(i, j int) bool {
   331  // 		n := strings.Compare(methods[i].Name, methods[j].Name)
   332  // 		if n == 0 && methods[i].Type == methods[j].Type {
   333  // 			panic(fmt.Sprintf("method redeclared: %v", methods[j].Name))
   334  // 		}
   335  // 		return n < 0
   336  // 	})
   337  // 	var mcount, pcount int
   338  // 	pcount = len(methods)
   339  // 	var mlist []string
   340  // 	for _, m := range methods {
   341  // 		if !m.Pointer {
   342  // 			mlist = append(mlist, m.Name)
   343  // 			mcount++
   344  // 		}
   345  // 	}
   346  // 	rt, tt := newType("", "", styp, mcount, mcount)
   347  // 	prt, ptt := newType("", "", reflect.PtrTo(styp), mcount, pcount)
   348  // 	rt.ptrToThis = resolveReflectType(prt)
   349  
   350  // 	(*ptrType)(unsafe.Pointer(prt)).elem = rt
   351  // 	setTypeName(rt, styp.PkgPath(), styp.Name())
   352  // 	typ := toType(rt)
   353  // 	ptyp := reflect.PtrTo(typ)
   354  // 	ms := make([]method, mcount, mcount)
   355  // 	pms := make([]method, pcount, pcount)
   356  // 	infos := make([]*methodInfo, mcount, mcount)
   357  // 	pinfos := make([]*methodInfo, pcount, pcount)
   358  // 	rmap := make(map[reflect.Type]reflect.Type)
   359  // 	rmap[styp] = typ
   360  // 	itype := itypeIndex(typ)
   361  // 	var index int
   362  // 	for i, m := range methods {
   363  // 		name := resolveReflectName(newName(m.Name, "", true))
   364  // 		inTyp, outTyp, mtyp, tfn, ifn, ptfn, pifn := createMethod(itype, typ, ptyp, m, i, index, rmap)
   365  // 		isz := argsTypeSize(inTyp, true)
   366  // 		osz := argsTypeSize(outTyp, false)
   367  // 		pindex := i
   368  // 		if !m.Pointer {
   369  // 			pindex = index
   370  // 		}
   371  // 		onePtr := checkOneFieldPtr(typ)
   372  // 		pms[i].name = name
   373  // 		pms[i].mtyp = mtyp
   374  // 		pms[i].tfn = ptfn
   375  // 		pms[i].ifn = pifn
   376  // 		pinfos[i] = &methodInfo{
   377  // 			inTyp:    inTyp,
   378  // 			outTyp:   outTyp,
   379  // 			name:     m.Name,
   380  // 			index:    pindex,
   381  // 			isz:      isz,
   382  // 			osz:      osz,
   383  // 			pointer:  m.Pointer,
   384  // 			variadic: m.Type.IsVariadic(),
   385  // 			onePtr:   onePtr,
   386  // 		}
   387  // 		if !m.Pointer {
   388  // 			ms[index].name = name
   389  // 			ms[index].mtyp = mtyp
   390  // 			ms[index].tfn = tfn
   391  // 			ms[index].ifn = ifn
   392  // 			infos[index] = &methodInfo{
   393  // 				inTyp:    inTyp,
   394  // 				outTyp:   outTyp,
   395  // 				name:     m.Name,
   396  // 				index:    index,
   397  // 				isz:      isz,
   398  // 				osz:      osz,
   399  // 				pointer:  m.Pointer,
   400  // 				variadic: m.Type.IsVariadic(),
   401  // 				onePtr:   onePtr,
   402  // 			}
   403  // 			index++
   404  // 		}
   405  // 	}
   406  // 	copy(tt, ms)
   407  // 	copy(ptt, pms)
   408  // 	typInfoMap[typ] = infos
   409  // 	typInfoMap[ptyp] = pinfos
   410  // 	return typ
   411  // }
   412  
   413  func checkOneFieldPtr(typ reflect.Type) bool {
   414  	return typ.Kind() == reflect.Struct &&
   415  		typ.NumField() == 1 &&
   416  		typ.Field(0).Type.Kind() == reflect.Ptr
   417  }
   418  
   419  const (
   420  	uintptrAligin = unsafe.Sizeof(uintptr(0))
   421  )
   422  
   423  func argsTypeSize(typ reflect.Type, offset bool) (off uintptr) {
   424  	numIn := typ.NumField()
   425  	if numIn == 0 {
   426  		return 0
   427  	}
   428  	for i := 0; i < numIn; i++ {
   429  		t := typ.Field(i).Type
   430  		targ := totype(t)
   431  		a := uintptr(targ.align)
   432  		off = (off + a - 1) &^ (a - 1)
   433  		n := targ.size
   434  		if n == 0 {
   435  			continue
   436  		}
   437  		off += n
   438  	}
   439  	if offset {
   440  		off = (off + uintptrAligin - 1) &^ (uintptrAligin - 1)
   441  		if off == 0 {
   442  			return uintptrAligin
   443  		}
   444  	}
   445  	return
   446  }
   447  
   448  func resetTypeList() {
   449  	itypList = nil
   450  	typInfoMap = make(map[reflect.Type][]*methodInfo)
   451  	valueInfoMap = make(map[reflect.Value]typeInfo)
   452  }
   453  
   454  var (
   455  	itypList []reflect.Type
   456  )
   457  
   458  var (
   459  	mu sync.Mutex
   460  )
   461  
   462  func isUserType(typ reflect.Type) bool {
   463  	for _, t := range itypList {
   464  		if t == typ {
   465  			return true
   466  		}
   467  	}
   468  	return false
   469  }
   470  
   471  func itypeIndex(typ reflect.Type) int {
   472  	mu.Lock()
   473  	defer mu.Unlock()
   474  	for i, t := range itypList {
   475  		if t == typ {
   476  			return i
   477  		}
   478  	}
   479  	itypList = append(itypList, typ)
   480  	return len(itypList) - 1
   481  }
   482  
   483  type iparam struct {
   484  	data []byte
   485  }
   486  
   487  type unsafeptr = unsafe.Pointer
   488  
   489  func i_y(itype int, index int, ptr unsafeptr, pin iparam, ptrto bool) (pout iparam) {
   490  	typ := itypList[itype]
   491  	otyp := typ
   492  	if ptrto {
   493  		typ = reflect.PtrTo(typ)
   494  	}
   495  	infos, ok := typInfoMap[typ]
   496  	if !ok {
   497  		log.Panicln("cannot found type info", typ)
   498  		return
   499  	}
   500  	info := infos[index]
   501  	var method reflect.Method
   502  	if ptrto && !info.pointer {
   503  		method.Func = info.Func
   504  	} else {
   505  		method = MethodByIndex(typ, info.index)
   506  		method.Func = info.Func
   507  	}
   508  	var receiver reflect.Value
   509  	if !ptrto && info.onePtr {
   510  		receiver = reflect.NewAt(otyp, unsafe.Pointer(&ptr)).Elem() //.Elem().Field(0)
   511  	} else {
   512  		receiver = reflect.NewAt(otyp, ptr)
   513  		if !ptrto || !info.pointer {
   514  			receiver = receiver.Elem()
   515  		}
   516  	}
   517  	in := []reflect.Value{receiver}
   518  	if inCount := method.Func.Type().NumIn(); inCount > 1 {
   519  		sz := info.inTyp.Size()
   520  		var inArgs reflect.Value
   521  		if sz == 0 {
   522  			inArgs = reflect.New(info.inTyp).Elem()
   523  		} else {
   524  			inArgs = reflect.NewAt(info.inTyp, unsafe.Pointer(&pin)).Elem()
   525  		}
   526  		if info.variadic {
   527  			for i := 1; i < inCount-1; i++ {
   528  				in = append(in, inArgs.Field(i-1))
   529  			}
   530  			slice := inArgs.Field(inCount - 2)
   531  			for i := 0; i < slice.Len(); i++ {
   532  				in = append(in, slice.Index(i))
   533  			}
   534  		} else {
   535  			for i := 1; i < inCount; i++ {
   536  				in = append(in, inArgs.Field(i-1))
   537  			}
   538  		}
   539  	}
   540  	r := method.Func.Call(in)
   541  	if info.outTyp.NumField() > 0 {
   542  		out := reflect.New(info.outTyp).Elem()
   543  		for i, v := range r {
   544  			out.Field(i).Set(v)
   545  		}
   546  		pout.data = make([]byte, info.osz, info.osz)
   547  		memmove(unsafe.Pointer(&pout), unsafe.Pointer(out.UnsafeAddr()), info.osz)
   548  		// po := unsafe.Pointer(out.UnsafeAddr())
   549  		// p := unsafe.Pointer(&pout)
   550  		// for i := uintptr(0); i < info.osz; i++ {
   551  		// 	*(*byte)(add(p, i, "")) = *(*byte)(add(po, uintptr(i), ""))
   552  		// }
   553  	}
   554  	return
   555  }
   556  
   557  func i_x(itype int, index int, ptr unsafe.Pointer, p unsafe.Pointer, ptrto bool) {
   558  	typ := itypList[itype]
   559  	otyp := typ
   560  	if ptrto {
   561  		typ = reflect.PtrTo(typ)
   562  	}
   563  	infos, ok := typInfoMap[typ]
   564  	if !ok {
   565  		log.Panicln("cannot found type info", typ)
   566  		return
   567  	}
   568  	info := infos[index]
   569  	var method reflect.Method
   570  	if ptrto && !info.pointer {
   571  		method.Func = info.Func
   572  	} else {
   573  		method = MethodByIndex(typ, info.index)
   574  		method.Func = info.Func
   575  	}
   576  	var receiver reflect.Value
   577  	if !ptrto && info.onePtr {
   578  		receiver = reflect.NewAt(otyp, unsafe.Pointer(&ptr)).Elem() //.Elem().Field(0)
   579  	} else {
   580  		receiver = reflect.NewAt(otyp, ptr)
   581  		if !ptrto || !info.pointer {
   582  			receiver = receiver.Elem()
   583  		}
   584  	}
   585  	in := []reflect.Value{receiver}
   586  	if inCount := method.Func.Type().NumIn(); inCount > 1 {
   587  		sz := info.inTyp.Size()
   588  		buf := make([]byte, sz, sz)
   589  		if sz > info.isz {
   590  			sz = info.isz
   591  		}
   592  		for i := uintptr(0); i < sz; i++ {
   593  			buf[i] = *(*byte)(add(p, i, ""))
   594  		}
   595  		var inArgs reflect.Value
   596  		if sz == 0 {
   597  			inArgs = reflect.New(info.inTyp).Elem()
   598  		} else {
   599  			inArgs = reflect.NewAt(info.inTyp, unsafe.Pointer(&buf[0])).Elem()
   600  		}
   601  		if info.variadic {
   602  			for i := 1; i < inCount-1; i++ {
   603  				in = append(in, inArgs.Field(i-1))
   604  			}
   605  			slice := inArgs.Field(inCount - 2)
   606  			for i := 0; i < slice.Len(); i++ {
   607  				in = append(in, slice.Index(i))
   608  			}
   609  		} else {
   610  			for i := 1; i < inCount; i++ {
   611  				in = append(in, inArgs.Field(i-1))
   612  			}
   613  		}
   614  	}
   615  	r := method.Func.Call(in)
   616  	if info.outTyp.NumField() > 0 {
   617  		out := reflect.New(info.outTyp).Elem()
   618  		for i, v := range r {
   619  			out.Field(i).Set(v)
   620  		}
   621  		po := unsafe.Pointer(out.UnsafeAddr())
   622  		for i := uintptr(0); i < info.osz; i++ {
   623  			*(*byte)(add(p, info.isz+i, "")) = *(*byte)(add(po, uintptr(i), ""))
   624  		}
   625  	}
   626  }
   627  
   628  func i_x_dyn(i int, ptr unsafe.Pointer, p unsafe.Pointer, ptrto bool) bool {
   629  	var receiver reflect.Value
   630  	var typ reflect.Type
   631  	if !ptrto {
   632  		for v, t := range valueInfoMap {
   633  			if t.oneFieldPtr {
   634  				if ptr == unsafe.Pointer(*(**uintptr)(tovalue(&v).ptr)) {
   635  					receiver = v
   636  					typ = t.typ
   637  					break
   638  				}
   639  			}
   640  		}
   641  	}
   642  	if typ == nil {
   643  		for v, t := range valueInfoMap {
   644  			if ptr == tovalue(&v).ptr {
   645  				receiver = v
   646  				typ = t.typ
   647  				break
   648  			}
   649  		}
   650  	}
   651  	if typ == nil {
   652  		log.Panicln("cannot found ptr type", i, ptr)
   653  		return false
   654  	}
   655  	if ptrto {
   656  		typ = reflect.PtrTo(typ)
   657  	}
   658  	infos, ok := typInfoMap[typ]
   659  	if !ok {
   660  		log.Panicln("cannot found type info", typ)
   661  		return false
   662  	}
   663  	info := infos[i]
   664  	var method reflect.Method
   665  	if ptrto && !info.pointer {
   666  		method = MethodByIndex(typ.Elem(), info.index)
   667  	} else {
   668  		method = MethodByIndex(typ, info.index)
   669  	}
   670  	if ptrto && info.pointer {
   671  		receiver = receiver.Addr()
   672  	}
   673  	in := []reflect.Value{receiver}
   674  	if inCount := method.Type.NumIn(); inCount > 1 {
   675  		sz := info.inTyp.Size()
   676  		buf := make([]byte, sz, sz)
   677  		if sz > info.isz {
   678  			sz = info.isz
   679  		}
   680  		for i := uintptr(0); i < sz; i++ {
   681  			buf[i] = *(*byte)(add(p, i, ""))
   682  		}
   683  		var inArgs reflect.Value
   684  		if sz == 0 {
   685  			inArgs = reflect.New(info.inTyp).Elem()
   686  		} else {
   687  			inArgs = reflect.NewAt(info.inTyp, unsafe.Pointer(&buf[0])).Elem()
   688  		}
   689  		if info.variadic {
   690  			for i := 1; i < inCount-1; i++ {
   691  				in = append(in, inArgs.Field(i-1))
   692  			}
   693  			slice := inArgs.Field(inCount - 2)
   694  			for i := 0; i < slice.Len(); i++ {
   695  				in = append(in, slice.Index(i))
   696  			}
   697  		} else {
   698  			for i := 1; i < inCount; i++ {
   699  				in = append(in, inArgs.Field(i-1))
   700  			}
   701  		}
   702  	}
   703  	r := method.Func.Call(in)
   704  	if info.outTyp.NumField() > 0 {
   705  		out := reflect.New(info.outTyp).Elem()
   706  		for i, v := range r {
   707  			out.Field(i).Set(v)
   708  		}
   709  		po := unsafe.Pointer(out.UnsafeAddr())
   710  		for i := uintptr(0); i < info.osz; i++ {
   711  			*(*byte)(add(p, info.isz+i, "")) = *(*byte)(add(po, uintptr(i), ""))
   712  		}
   713  	}
   714  	return true
   715  }