github.com/goplus/reflectx@v1.2.2/rtype.go (about)

     1  //go:build !js || (js && wasm)
     2  // +build !js js,wasm
     3  
     4  package reflectx
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"reflect"
    10  	"unsafe"
    11  )
    12  
    13  func toStructType(t *rtype) *structType {
    14  	return (*structType)(unsafe.Pointer(t))
    15  }
    16  
    17  func toKindType(t *rtype) unsafe.Pointer {
    18  	return unsafe.Pointer(t)
    19  }
    20  
    21  //go:linkname toUncommonType reflect.(*rtype).uncommon
    22  func toUncommonType(t *rtype) *uncommonType
    23  
    24  // uncommonType is present only for defined types or types with methods
    25  // (if T is a defined type, the uncommonTypes for T and *T have methods).
    26  // Using a pointer to this struct reduces the overall size required
    27  // to describe a non-defined type with no methods.
    28  type uncommonType struct {
    29  	pkgPath nameOff // import path; empty for built-in types like int, string
    30  	mcount  uint16  // number of methods
    31  	xcount  uint16  // number of exported methods
    32  	moff    uint32  // offset from this uncommontype to [mcount]method
    33  	_       uint32  // unused
    34  }
    35  
    36  type funcTypeFixed1 struct {
    37  	funcType
    38  	args [1]*rtype
    39  }
    40  
    41  type funcTypeFixed4 struct {
    42  	funcType
    43  	args [4]*rtype
    44  }
    45  type funcTypeFixed8 struct {
    46  	funcType
    47  	args [8]*rtype
    48  }
    49  type funcTypeFixed16 struct {
    50  	funcType
    51  	args [16]*rtype
    52  }
    53  type funcTypeFixed32 struct {
    54  	funcType
    55  	args [32]*rtype
    56  }
    57  type funcTypeFixed64 struct {
    58  	funcType
    59  	args [64]*rtype
    60  }
    61  type funcTypeFixed128 struct {
    62  	funcType
    63  	args [128]*rtype
    64  }
    65  
    66  // emptyInterface is the header for an interface{} value.
    67  type emptyInterface struct {
    68  	typ  *rtype
    69  	word unsafe.Pointer
    70  }
    71  
    72  func totype(typ reflect.Type) *rtype {
    73  	e := (*emptyInterface)(unsafe.Pointer(&typ))
    74  	return (*rtype)(e.word)
    75  }
    76  
    77  //go:nocheckptr
    78  func (t *uncommonType) methods() []method {
    79  	if t == nil || t.mcount == 0 {
    80  		return nil
    81  	}
    82  	return (*[1 << 16]method)(add(unsafe.Pointer(t), uintptr(t.moff), "t.mcount > 0"))[:t.mcount:t.mcount]
    83  }
    84  
    85  //go:nocheckptr
    86  func (t *uncommonType) exportedMethods() []method {
    87  	if t == nil || t.xcount == 0 {
    88  		return nil
    89  	}
    90  	return (*[1 << 16]method)(add(unsafe.Pointer(t), uintptr(t.moff), "t.xcount > 0"))[:t.xcount:t.xcount]
    91  }
    92  
    93  func tovalue(v *reflect.Value) *Value {
    94  	return (*Value)(unsafe.Pointer(v))
    95  }
    96  
    97  func toValue(v Value) reflect.Value {
    98  	return *(*reflect.Value)(unsafe.Pointer(&v))
    99  }
   100  
   101  func (t *rtype) uncommon() *uncommonType {
   102  	return toUncommonType(t)
   103  }
   104  
   105  func (t *rtype) exportedMethods() []method {
   106  	ut := t.uncommon()
   107  	if ut == nil {
   108  		return nil
   109  	}
   110  	return ut.exportedMethods()
   111  }
   112  
   113  func (t *rtype) methods() []method {
   114  	ut := t.uncommon()
   115  	if ut == nil {
   116  		return nil
   117  	}
   118  	return ut.methods()
   119  }
   120  
   121  func (t *funcType) in() []*rtype {
   122  	uadd := unsafe.Sizeof(*t)
   123  	if t.tflag&tflagUncommon != 0 {
   124  		uadd += unsafe.Sizeof(uncommonType{})
   125  	}
   126  	if t.inCount == 0 {
   127  		return nil
   128  	}
   129  	return (*[1 << 20]*rtype)(add(unsafe.Pointer(t), uadd, "t.inCount > 0"))[:t.inCount:t.inCount]
   130  }
   131  
   132  func (t *funcType) out() []*rtype {
   133  	uadd := unsafe.Sizeof(*t)
   134  	if t.tflag&tflagUncommon != 0 {
   135  		uadd += unsafe.Sizeof(uncommonType{})
   136  	}
   137  	outCount := t.outCount & (1<<15 - 1)
   138  	if outCount == 0 {
   139  		return nil
   140  	}
   141  	return (*[1 << 20]*rtype)(add(unsafe.Pointer(t), uadd, "outCount > 0"))[t.inCount : t.inCount+outCount : t.inCount+outCount]
   142  }
   143  
   144  func (t *rtype) IsVariadic() bool {
   145  	if t.Kind() != reflect.Func {
   146  		panic("reflect: IsVariadic of non-func type " + toType(t).String())
   147  	}
   148  	tt := (*funcType)(unsafe.Pointer(t))
   149  	return tt.outCount&(1<<15) != 0
   150  }
   151  
   152  type bitVector struct {
   153  	n    uint32 // number of bits
   154  	data []byte
   155  }
   156  
   157  // funcType represents a function type.
   158  //
   159  // A *rtype for each in and out parameter is stored in an array that
   160  // directly follows the funcType (and possibly its uncommonType). So
   161  // a function type with one method, one input, and one output is:
   162  //
   163  //	struct {
   164  //		funcType
   165  //		uncommonType
   166  //		[2]*rtype    // [0] is in, [1] is out
   167  //	}
   168  type funcType struct {
   169  	rtype
   170  	inCount  uint16
   171  	outCount uint16 // top bit is set if last input parameter is ...
   172  }
   173  
   174  type uncommonFuncType struct {
   175  	funcType
   176  	uncommonType
   177  	args [1]*rtype
   178  }
   179  
   180  func uncommonFuncTypeArgs(rt *rtype, nargs int) []*rtype {
   181  	f := (*uncommonFuncType)(unsafe.Pointer(rt))
   182  	return (*[1 << 16]*rtype)(unsafe.Pointer(&f.args))[:nargs:nargs]
   183  }
   184  
   185  func SetUnderlying(typ reflect.Type, styp reflect.Type) {
   186  	rt := totype(typ)
   187  	ort := totype(styp)
   188  	switch styp.Kind() {
   189  	case reflect.Struct:
   190  		st := (*structType)(unsafe.Pointer(rt))
   191  		ost := (*structType)(unsafe.Pointer(ort))
   192  		st.fields = ost.fields
   193  	case reflect.Ptr:
   194  		st := (*ptrType)(unsafe.Pointer(rt))
   195  		ost := (*ptrType)(unsafe.Pointer(ort))
   196  		st.elem = ost.elem
   197  	case reflect.Slice:
   198  		st := (*sliceType)(unsafe.Pointer(rt))
   199  		ost := (*sliceType)(unsafe.Pointer(ort))
   200  		st.elem = ost.elem
   201  	case reflect.Array:
   202  		st := (*arrayType)(unsafe.Pointer(rt))
   203  		ost := (*arrayType)(unsafe.Pointer(ort))
   204  		st.elem = ost.elem
   205  		st.slice = ost.slice
   206  		st.len = ost.len
   207  	case reflect.Chan:
   208  		st := (*chanType)(unsafe.Pointer(rt))
   209  		ost := (*chanType)(unsafe.Pointer(ort))
   210  		st.elem = ost.elem
   211  		st.dir = ost.dir
   212  	case reflect.Interface:
   213  		st := (*interfaceType)(unsafe.Pointer(rt))
   214  		ost := (*interfaceType)(unsafe.Pointer(ort))
   215  		st.methods = ost.methods
   216  	case reflect.Map:
   217  		st := (*mapType)(unsafe.Pointer(rt))
   218  		ost := (*mapType)(unsafe.Pointer(ort))
   219  		st.key = ost.key
   220  		st.elem = ost.elem
   221  		st.bucket = ost.bucket
   222  		st.hasher = ost.hasher
   223  		st.keysize = ost.keysize
   224  		st.valuesize = ost.valuesize
   225  		st.bucketsize = ost.bucketsize
   226  		st.flags = ost.flags
   227  	case reflect.Func:
   228  		st := (*funcType)(unsafe.Pointer(rt))
   229  		ost := (*funcType)(unsafe.Pointer(ort))
   230  		st.inCount = ost.inCount
   231  		st.outCount = ost.outCount
   232  		numIn := typ.NumIn()
   233  		numOut := typ.NumOut()
   234  		narg := numIn + numOut
   235  		if narg > 0 {
   236  			args := uncommonFuncTypeArgs(rt, narg)
   237  			var i int
   238  			for i = 0; i < numIn; i++ {
   239  				args[i] = totype(styp.In(i))
   240  			}
   241  			for j := 0; j < numOut; j++ {
   242  				args[i+j] = totype(styp.Out(j))
   243  			}
   244  		}
   245  	}
   246  	rt.size = ort.size
   247  	rt.tflag |= tflagUncommon | tflagExtraStar | tflagNamed
   248  	rt.kind = ort.kind
   249  	rt.align = ort.align
   250  	rt.fieldAlign = ort.fieldAlign
   251  	rt.gcdata = ort.gcdata
   252  	rt.ptrdata = ort.ptrdata
   253  	rt.equal = ort.equal
   254  	//rt.str = resolveReflectName(ort.nameOff(ort.str))
   255  	if isRegularMemory(typ) {
   256  		rt.tflag |= tflagRegularMemory
   257  	}
   258  }
   259  
   260  func newType(pkg string, name string, styp reflect.Type, mcount int, xcount int) (*rtype, []method) {
   261  	var rt *rtype
   262  	var fnoff uint32
   263  	var tt reflect.Value
   264  	ort := totype(styp)
   265  	skind := styp.Kind()
   266  	switch skind {
   267  	case reflect.Struct:
   268  		tt = reflect.New(reflect.StructOf([]reflect.StructField{
   269  			{Name: "S", Type: reflect.TypeOf(structType{})},
   270  			{Name: "U", Type: reflect.TypeOf(uncommonType{})},
   271  			{Name: "M", Type: reflect.ArrayOf(mcount, reflect.TypeOf(method{}))},
   272  		}))
   273  		st := (*structType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr()))
   274  		ost := (*structType)(unsafe.Pointer(ort))
   275  		st.fields = ost.fields
   276  	case reflect.Ptr:
   277  		tt = reflect.New(reflect.StructOf([]reflect.StructField{
   278  			{Name: "S", Type: reflect.TypeOf(ptrType{})},
   279  			{Name: "U", Type: reflect.TypeOf(uncommonType{})},
   280  			{Name: "M", Type: reflect.ArrayOf(mcount, reflect.TypeOf(method{}))},
   281  		}))
   282  		st := (*ptrType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr()))
   283  		st.elem = totype(styp.Elem())
   284  	case reflect.Interface:
   285  		tt = reflect.New(reflect.StructOf([]reflect.StructField{
   286  			{Name: "S", Type: reflect.TypeOf(interfaceType{})},
   287  			{Name: "U", Type: reflect.TypeOf(uncommonType{})},
   288  		}))
   289  		st := (*interfaceType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr()))
   290  		ost := (*interfaceType)(unsafe.Pointer(ort))
   291  		for _, m := range ost.methods {
   292  			st.methods = append(st.methods, imethod{
   293  				name: resolveReflectName(ost.nameOff(m.name)),
   294  				typ:  resolveReflectType(ost.typeOff(m.typ)),
   295  			})
   296  		}
   297  	case reflect.Slice:
   298  		tt = reflect.New(reflect.StructOf([]reflect.StructField{
   299  			{Name: "S", Type: reflect.TypeOf(sliceType{})},
   300  			{Name: "U", Type: reflect.TypeOf(uncommonType{})},
   301  			{Name: "M", Type: reflect.ArrayOf(mcount, reflect.TypeOf(method{}))},
   302  		}))
   303  		st := (*sliceType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr()))
   304  		st.elem = totype(styp.Elem())
   305  	case reflect.Array:
   306  		tt = reflect.New(reflect.StructOf([]reflect.StructField{
   307  			{Name: "S", Type: reflect.TypeOf(arrayType{})},
   308  			{Name: "U", Type: reflect.TypeOf(uncommonType{})},
   309  			{Name: "M", Type: reflect.ArrayOf(mcount, reflect.TypeOf(method{}))},
   310  		}))
   311  		st := (*arrayType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr()))
   312  		ost := (*arrayType)(unsafe.Pointer(ort))
   313  		st.elem = ost.elem
   314  		st.slice = ost.slice
   315  		st.len = ost.len
   316  	case reflect.Chan:
   317  		tt = reflect.New(reflect.StructOf([]reflect.StructField{
   318  			{Name: "S", Type: reflect.TypeOf(chanType{})},
   319  			{Name: "U", Type: reflect.TypeOf(uncommonType{})},
   320  			{Name: "M", Type: reflect.ArrayOf(mcount, reflect.TypeOf(method{}))},
   321  		}))
   322  		st := (*chanType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr()))
   323  		ost := (*chanType)(unsafe.Pointer(ort))
   324  		st.elem = ost.elem
   325  		st.dir = ost.dir
   326  	case reflect.Func:
   327  		numIn := styp.NumIn()
   328  		numOut := styp.NumOut()
   329  		narg := numIn + numOut
   330  		tt = reflect.New(reflect.StructOf([]reflect.StructField{
   331  			{Name: "S", Type: reflect.TypeOf(funcType{})},
   332  			{Name: "U", Type: reflect.TypeOf(uncommonType{})},
   333  			{Name: "N", Type: reflect.ArrayOf(narg, reflect.TypeOf((*rtype)(nil)))},
   334  			{Name: "M", Type: reflect.ArrayOf(mcount, reflect.TypeOf(method{}))},
   335  		}))
   336  		st := (*funcType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr()))
   337  		ost := (*funcType)(unsafe.Pointer(ort))
   338  		st.inCount = ost.inCount
   339  		st.outCount = ost.outCount
   340  		if narg > 0 {
   341  			args := make([]*rtype, narg, narg)
   342  			fnoff = uint32(unsafe.Sizeof((*rtype)(nil))) * uint32(narg)
   343  			var i int
   344  			for i = 0; i < numIn; i++ {
   345  				args[i] = totype(styp.In(i))
   346  			}
   347  			for j := 0; j < numOut; j++ {
   348  				args[i+j] = totype(styp.Out(j))
   349  			}
   350  			copy(tt.Elem().Field(2).Slice(0, narg).Interface().([]*rtype), args)
   351  		}
   352  	case reflect.Map:
   353  		tt = reflect.New(reflect.StructOf([]reflect.StructField{
   354  			{Name: "S", Type: reflect.TypeOf(mapType{})},
   355  			{Name: "U", Type: reflect.TypeOf(uncommonType{})},
   356  			{Name: "M", Type: reflect.ArrayOf(mcount, reflect.TypeOf(method{}))},
   357  		}))
   358  		st := (*mapType)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr()))
   359  		ost := (*mapType)(unsafe.Pointer(ort))
   360  		st.key = ost.key
   361  		st.elem = ost.elem
   362  		st.bucket = ost.bucket
   363  		st.hasher = ost.hasher
   364  		st.keysize = ost.keysize
   365  		st.valuesize = ost.valuesize
   366  		st.bucketsize = ost.bucketsize
   367  		st.flags = ost.flags
   368  	default:
   369  		tt = reflect.New(reflect.StructOf([]reflect.StructField{
   370  			{Name: "S", Type: reflect.TypeOf(rtype{})},
   371  			{Name: "U", Type: reflect.TypeOf(uncommonType{})},
   372  			{Name: "M", Type: reflect.ArrayOf(mcount, reflect.TypeOf(method{}))},
   373  		}))
   374  	}
   375  	rt = (*rtype)(unsafe.Pointer(tt.Elem().Field(0).UnsafeAddr()))
   376  	rt.size = ort.size
   377  	rt.tflag = ort.tflag | tflagUncommon
   378  	rt.kind = ort.kind
   379  	rt.align = ort.align
   380  	rt.fieldAlign = ort.fieldAlign
   381  	rt.gcdata = ort.gcdata
   382  	rt.ptrdata = ort.ptrdata
   383  	rt.equal = ort.equal
   384  	rt.str = resolveReflectName(ort.nameOff(ort.str))
   385  	ut := (*uncommonType)(unsafe.Pointer(tt.Elem().Field(1).UnsafeAddr()))
   386  	ut.mcount = uint16(mcount)
   387  	ut.xcount = uint16(xcount)
   388  	ut.moff = uint32(unsafe.Sizeof(uncommonType{}))
   389  	if skind == reflect.Interface {
   390  		return rt, nil
   391  	} else if skind == reflect.Func {
   392  		ut.moff += fnoff
   393  		return rt, tt.Elem().Field(3).Slice(0, mcount).Interface().([]method)
   394  	}
   395  	return rt, tt.Elem().Field(2).Slice(0, mcount).Interface().([]method)
   396  }
   397  
   398  func NamedTypeOf(pkgpath string, name string, from reflect.Type) reflect.Type {
   399  	rt, _ := newType(pkgpath, name, from, 0, 0)
   400  	setTypeName(rt, pkgpath, name)
   401  	return toType(rt)
   402  }
   403  
   404  //go:linkname typesByString reflect.typesByString
   405  func typesByString(s string) []*rtype
   406  
   407  //go:linkname typelinks reflect.typelinks
   408  func typelinks() (sections []unsafe.Pointer, offset [][]int32)
   409  
   410  //go:linkname rtypeOff reflect.rtypeOff
   411  func rtypeOff(section unsafe.Pointer, off int32) *rtype
   412  
   413  func TypeLinks() []reflect.Type {
   414  	var r []reflect.Type
   415  	sections, offset := typelinks()
   416  	for i, offs := range offset {
   417  		rodata := sections[i]
   418  		for _, off := range offs {
   419  			typ := (*rtype)(resolveTypeOff(unsafe.Pointer(rodata), off))
   420  			r = append(r, toType(typ))
   421  		}
   422  	}
   423  	return r
   424  }
   425  
   426  func TypesByString(s string) []reflect.Type {
   427  	sections, offset := typelinks()
   428  	var ret []reflect.Type
   429  
   430  	for offsI, offs := range offset {
   431  		section := sections[offsI]
   432  
   433  		// We are looking for the first index i where the string becomes >= s.
   434  		// This is a copy of sort.Search, with f(h) replaced by (*typ[h].String() >= s).
   435  		i, j := 0, len(offs)
   436  		for i < j {
   437  			h := i + (j-i)/2 // avoid overflow when computing h
   438  			// i ≤ h < j
   439  			typ := toType(rtypeOff(section, offs[h]))
   440  			if !(typ.String() >= s) {
   441  				i = h + 1 // preserves f(i-1) == false
   442  			} else {
   443  				j = h // preserves f(j) == true
   444  			}
   445  		}
   446  		// i == j, f(i-1) == false, and f(j) (= f(i)) == true  =>  answer is i.
   447  
   448  		// Having found the first, linear scan forward to find the last.
   449  		// We could do a second binary search, but the caller is going
   450  		// to do a linear scan anyway.
   451  		for j := i; j < len(offs); j++ {
   452  			typ := toType(rtypeOff(section, offs[j]))
   453  			if typ.String() != s {
   454  				break
   455  			}
   456  			ret = append(ret, typ)
   457  		}
   458  	}
   459  	return ret
   460  }
   461  
   462  func DumpType(w io.Writer, typ reflect.Type) {
   463  	rt := totype(typ)
   464  	fmt.Fprintf(w, "%#v\n", rt)
   465  	for _, m := range rt.methods() {
   466  		fmt.Fprintf(w, "%v %v (%v)\t\t%#v\n",
   467  			rt.nameOff(m.name).name(),
   468  			rt.nameOff(m.name).pkgPath(),
   469  			toType(rt.typeOff(m.mtyp)),
   470  			m)
   471  	}
   472  }
   473  
   474  func NumMethodX(typ reflect.Type) int {
   475  	return totype(typ).NumMethodX()
   476  }
   477  
   478  func MethodX(typ reflect.Type, i int) reflect.Method {
   479  	return totype(typ).MethodX(i)
   480  }
   481  
   482  func (t *rtype) NumMethodX() int {
   483  	return len(t.methods())
   484  }
   485  
   486  func (t *rtype) MethodX(i int) (m reflect.Method) {
   487  	if t.Kind() == reflect.Interface {
   488  		return toType(t).Method(i)
   489  	}
   490  	methods := t.methods()
   491  	if i < 0 || i >= len(methods) {
   492  		panic("reflect: Method index out of range")
   493  	}
   494  	p := methods[i]
   495  	pname := t.nameOff(p.name)
   496  	m.Name = pname.name()
   497  	m.Index = i
   498  	fl := flag(reflect.Func)
   499  	if t.tflag&tflagUserMethod != 0 {
   500  		fl |= flagIndir
   501  	}
   502  	mtyp := t.typeOff(p.mtyp)
   503  	if mtyp == nil {
   504  		return
   505  	}
   506  	ft := (*funcType)(unsafe.Pointer(mtyp))
   507  	in := make([]reflect.Type, 0, 1+len(ft.in()))
   508  	in = append(in, toType(t))
   509  	for _, arg := range ft.in() {
   510  		in = append(in, toType(arg))
   511  	}
   512  	out := make([]reflect.Type, 0, len(ft.out()))
   513  	for _, ret := range ft.out() {
   514  		out = append(out, toType(ret))
   515  	}
   516  	mt := reflect.FuncOf(in, out, ft.IsVariadic())
   517  	m.Type = mt
   518  	tfn := t.textOff(p.tfn)
   519  	fn := unsafe.Pointer(&tfn)
   520  	m.Func = toValue(Value{totype(mt), fn, fl})
   521  	return m
   522  }
   523  
   524  func (t *rtype) MethodByNameX(name string) (m reflect.Method, ok bool) {
   525  	if t.Kind() == reflect.Interface {
   526  		return toType(t).MethodByName(name)
   527  	}
   528  	if ut := t.uncommon(); ut != nil {
   529  		for i, p := range ut.methods() {
   530  			if t.nameOff(p.name).name() == name {
   531  				return t.MethodX(i), true
   532  			}
   533  		}
   534  	}
   535  	return reflect.Method{}, false
   536  }
   537  
   538  // Field returns the i'th field of the struct v.
   539  // It panics if v's Kind is not Struct or i is out of range.
   540  func FieldX(v reflect.Value, i int) reflect.Value {
   541  	mustBe("reflect.Value.Field", v, reflect.Struct)
   542  	rv := tovalue(&v)
   543  	tt := (*structType)(unsafe.Pointer(rv.typ))
   544  	if uint(i) >= uint(len(tt.fields)) {
   545  		panic("reflect: Field index out of range")
   546  	}
   547  	field := &tt.fields[i]
   548  	typ := field.typ
   549  
   550  	// Inherit permission bits from v, but clear flagEmbedRO.
   551  	fl := rv.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())
   552  	// Using an unexported field forces flagRO.
   553  	// if !field.name.isExported() {
   554  	// 	if field.embedded() {
   555  	// 		fl |= flagEmbedRO
   556  	// 	} else {
   557  	// 		fl |= flagStickyRO
   558  	// 	}
   559  	// }
   560  	// Either flagIndir is set and v.ptr points at struct,
   561  	// or flagIndir is not set and v.ptr is the actual struct data.
   562  	// In the former case, we want v.ptr + offset.
   563  	// In the latter case, we must have field.offset = 0,
   564  	// so v.ptr + field.offset is still the correct address.
   565  	ptr := add(rv.ptr, field.offset(), "same as non-reflect &v.field")
   566  	return toValue(Value{typ, ptr, fl})
   567  }