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

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package reflect implements run-time reflection, allowing a program to
     6  // manipulate objects with arbitrary types. The typical use is to take a value
     7  // with static type interface{} and extract its dynamic type information by
     8  // calling TypeOf, which returns a Type.
     9  //
    10  // A call to ValueOf returns a Value representing the run-time data.
    11  // Zero takes a Type and returns a Value representing a zero value
    12  // for that type.
    13  //
    14  // See "The Laws of Reflection" for an introduction to reflection in Go:
    15  // https://golang.org/doc/articles/laws_of_reflection.html
    16  
    17  package reflectx
    18  
    19  import (
    20  	"reflect"
    21  	"unsafe"
    22  )
    23  
    24  //go:linkname haveIdenticalUnderlyingType reflect.haveIdenticalUnderlyingType
    25  func haveIdenticalUnderlyingType(T, V *rtype, cmpTags bool) bool
    26  
    27  //go:linkname haveIdenticalType reflect.haveIdenticalType
    28  func haveIdenticalType(T, V reflect.Type, cmpTags bool) bool
    29  
    30  // memmove copies size bytes to dst from src. No write barriers are used.
    31  //go:noescape
    32  //go:linkname memmove reflect.memmove
    33  func memmove(dst, src unsafe.Pointer, size uintptr)
    34  
    35  // typedmemmove copies a value of type t to dst from src.
    36  //go:noescape
    37  //go:linkname typedmemmove reflect.typedmemmove
    38  func typedmemmove(t *rtype, dst, src unsafe.Pointer)
    39  
    40  // resolveTypeOff resolves an *rtype offset from a base type.
    41  // The (*rtype).typeOff method is a convenience wrapper for this function.
    42  // Implemented in the runtime package.
    43  //go:linkname resolveTypeOff reflect.resolveTypeOff
    44  func resolveTypeOff(rtype unsafe.Pointer, off int32) unsafe.Pointer
    45  
    46  // resolveTextOff resolves a function pointer offset from a base type.
    47  // The (*rtype).textOff method is a convenience wrapper for this function.
    48  // Implemented in the runtime package.
    49  //go:linkname resolveTextOff reflect.resolveTextOff
    50  func resolveTextOff(rtype unsafe.Pointer, off int32) unsafe.Pointer
    51  
    52  // addReflectOff adds a pointer to the reflection lookup map in the runtime.
    53  // It returns a new ID that can be used as a typeOff or textOff, and will
    54  // be resolved correctly. Implemented in the runtime package.
    55  //go:linkname addReflectOff reflect.addReflectOff
    56  func addReflectOff(ptr unsafe.Pointer) int32
    57  
    58  //go:linkname newName reflect.newName
    59  func newName(n, tag string, exported bool) name
    60  
    61  // resolveReflectName adds a name to the reflection lookup map in the runtime.
    62  // It returns a new nameOff that can be used to refer to the pointer.
    63  //go:linkname resolveReflectName reflect.resolveReflectName
    64  func resolveReflectName(n name) nameOff
    65  
    66  //go:linkname toType reflect.toType
    67  func toType(t *rtype) reflect.Type
    68  
    69  //go:linkname rtype_nameOff reflect.(*rtype).nameOff
    70  func rtype_nameOff(t *rtype, off nameOff) name
    71  
    72  //go:linkname rtype_typeOff reflect.(*rtype).typeOff
    73  func rtype_typeOff(t *rtype, off typeOff) *rtype
    74  
    75  //go:linkname rtype_textOff reflect.(*rtype).textOff
    76  func rtype_textOff(t *rtype, off textOff) unsafe.Pointer
    77  
    78  func (t *rtype) nameOff(off nameOff) name {
    79  	return rtype_nameOff(t, off)
    80  }
    81  
    82  func (t *rtype) typeOff(off typeOff) *rtype {
    83  	return rtype_typeOff(t, off)
    84  }
    85  
    86  func (t *rtype) textOff(off textOff) unsafe.Pointer {
    87  	return rtype_textOff(t, off)
    88  }
    89  
    90  // resolveReflectType adds a *rtype to the reflection lookup map in the runtime.
    91  // It returns a new typeOff that can be used to refer to the pointer.
    92  func resolveReflectType(t *rtype) typeOff {
    93  	return typeOff(addReflectOff(unsafe.Pointer(t)))
    94  }
    95  
    96  // resolveReflectText adds a function pointer to the reflection lookup map in
    97  // the runtime. It returns a new textOff that can be used to refer to the
    98  // pointer.
    99  func resolveReflectText(ptr unsafe.Pointer) textOff {
   100  	return textOff(addReflectOff(ptr))
   101  }
   102  
   103  type nameOff int32
   104  type typeOff int32
   105  type textOff int32
   106  
   107  // Method on non-interface type
   108  type method struct {
   109  	name nameOff // name of method
   110  	mtyp typeOff // method type (without receiver)
   111  	ifn  textOff // fn used in interface call (one-word receiver)
   112  	tfn  textOff // fn used for normal method call
   113  }
   114  
   115  type structTypeUncommon struct {
   116  	structType
   117  	u uncommonType
   118  }
   119  
   120  type tflag uint8
   121  
   122  const (
   123  	// tflagUncommon means that there is a pointer, *uncommonType,
   124  	// just beyond the outer type structure.
   125  	//
   126  	// For example, if t.Kind() == Struct and t.tflag&tflagUncommon != 0,
   127  	// then t has uncommonType data and it can be accessed as:
   128  	//
   129  	//	type tUncommon struct {
   130  	//		structType
   131  	//		u uncommonType
   132  	//	}
   133  	//	u := &(*tUncommon)(unsafe.Pointer(t)).u
   134  	tflagUncommon tflag = 1 << 0
   135  
   136  	// tflagExtraStar means the name in the str field has an
   137  	// extraneous '*' prefix. This is because for most types T in
   138  	// a program, the type *T also exists and reusing the str data
   139  	// saves binary size.
   140  	tflagExtraStar tflag = 1 << 1
   141  
   142  	// tflagNamed means the type has a name.
   143  	tflagNamed tflag = 1 << 2
   144  
   145  	// tflagRegularMemory means that equal and hash functions can treat
   146  	// this type as a single region of t.size bytes.
   147  	tflagRegularMemory tflag = 1 << 3
   148  
   149  	// tflagUserMethod means the type has reflctx user methods
   150  	tflagUserMethod tflag = 1 << 7
   151  )
   152  
   153  type rtype struct {
   154  	size       uintptr
   155  	ptrdata    uintptr // number of bytes in the type that can contain pointers
   156  	hash       uint32  // hash of type; avoids computation in hash tables
   157  	tflag      tflag   // extra type information flags
   158  	align      uint8   // alignment of variable with this type
   159  	fieldAlign uint8   // alignment of struct field with this type
   160  	kind       uint8   // enumeration for C
   161  	// function for comparing objects of this type
   162  	// (ptr to object A, ptr to object B) -> ==?
   163  	equal     func(unsafe.Pointer, unsafe.Pointer) bool
   164  	gcdata    *byte   // garbage collection data
   165  	str       nameOff // string form
   166  	ptrToThis typeOff // type for pointer to this type, may be zero
   167  }
   168  
   169  const (
   170  	kindDirectIface = 1 << 5
   171  	kindGCProg      = 1 << 6 // Type.gc points to GC program
   172  	kindMask        = (1 << 5) - 1
   173  )
   174  
   175  func (t *rtype) Kind() reflect.Kind {
   176  	return reflect.Kind(t.kind & kindMask)
   177  }
   178  
   179  // add returns p+x.
   180  //
   181  // The whySafe string is ignored, so that the function still inlines
   182  // as efficiently as p+x, but all call sites should use the string to
   183  // record why the addition is safe, which is to say why the addition
   184  // does not cause x to advance to the very end of p's allocation
   185  // and therefore point incorrectly at the next block in memory.
   186  func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer {
   187  	return unsafe.Pointer(uintptr(p) + x)
   188  }
   189  
   190  // stringHeader is a safe version of StringHeader used within this package.
   191  type stringHeader struct {
   192  	Data unsafe.Pointer
   193  	Len  int
   194  }
   195  
   196  // ChanDir represents a channel type's direction.
   197  type ChanDir int
   198  
   199  const (
   200  	RecvDir ChanDir             = 1 << iota // <-chan
   201  	SendDir                                 // chan<-
   202  	BothDir = RecvDir | SendDir             // chan
   203  )
   204  
   205  // arrayType represents a fixed array type.
   206  type arrayType struct {
   207  	rtype
   208  	elem  *rtype // array element type
   209  	slice *rtype // slice type
   210  	len   uintptr
   211  }
   212  
   213  // chanType represents a channel type.
   214  type chanType struct {
   215  	rtype
   216  	elem *rtype  // channel element type
   217  	dir  uintptr // channel direction (ChanDir)
   218  }
   219  
   220  // imethod represents a method on an interface type
   221  type imethod struct {
   222  	name nameOff // name of method
   223  	typ  typeOff // .(*FuncType) underneath
   224  }
   225  
   226  // interfaceType represents an interface type.
   227  type interfaceType struct {
   228  	rtype
   229  	pkgPath name      // import path
   230  	methods []imethod // sorted by hash
   231  }
   232  
   233  // mapType represents a map type.
   234  type mapType struct {
   235  	rtype
   236  	key    *rtype // map key type
   237  	elem   *rtype // map element (value) type
   238  	bucket *rtype // internal bucket structure
   239  	// function for hashing keys (ptr to key, seed) -> hash
   240  	hasher     func(unsafe.Pointer, uintptr) uintptr
   241  	keysize    uint8  // size of key slot
   242  	valuesize  uint8  // size of value slot
   243  	bucketsize uint16 // size of bucket
   244  	flags      uint32
   245  }
   246  
   247  // ptrType represents a pointer type.
   248  type ptrType struct {
   249  	rtype
   250  	elem *rtype // pointer element (pointed at) type
   251  }
   252  
   253  // sliceType represents a slice type.
   254  type sliceType struct {
   255  	rtype
   256  	elem *rtype // slice element type
   257  }
   258  
   259  // structType represents a struct type.
   260  type structType struct {
   261  	rtype
   262  	pkgPath name
   263  	fields  []structField // sorted by offset
   264  }
   265  
   266  // go/src/cmd/compile/internal/gc/alg.go#algtype1
   267  // IsRegularMemory reports whether t can be compared/hashed as regular memory.
   268  func isRegularMemory(t reflect.Type) bool {
   269  	switch t.Kind() {
   270  	case reflect.Func, reflect.Map, reflect.Slice, reflect.String, reflect.Interface:
   271  		return false
   272  	case reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
   273  		return false
   274  	case reflect.Array:
   275  		b := isRegularMemory(t.Elem())
   276  		if b {
   277  			return true
   278  		}
   279  		if t.Len() == 0 {
   280  			return true
   281  		}
   282  		return b
   283  	case reflect.Struct:
   284  		n := t.NumField()
   285  		switch n {
   286  		case 0:
   287  			return true
   288  		case 1:
   289  			f := t.Field(0)
   290  			if f.Name == "_" {
   291  				return false
   292  			}
   293  			return isRegularMemory(f.Type)
   294  		default:
   295  			for i := 0; i < n; i++ {
   296  				f := t.Field(i)
   297  				if f.Name == "_" || !isRegularMemory(f.Type) || ispaddedfield(t, i) {
   298  					return false
   299  				}
   300  			}
   301  		}
   302  	}
   303  	return true
   304  }
   305  
   306  // ispaddedfield reports whether the i'th field of struct type t is followed
   307  // by padding.
   308  func ispaddedfield(t reflect.Type, i int) bool {
   309  	end := t.Size()
   310  	if i+1 < t.NumField() {
   311  		end = t.Field(i + 1).Offset
   312  	}
   313  	fd := t.Field(i)
   314  	return fd.Offset+fd.Type.Size() != end
   315  }