...

Source file src/runtime/type.go

Documentation: runtime

		 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  // Runtime type representation.
		 6  
		 7  package runtime
		 8  
		 9  import "unsafe"
		10  
		11  // tflag is documented in reflect/type.go.
		12  //
		13  // tflag values must be kept in sync with copies in:
		14  //	cmd/compile/internal/reflectdata/reflect.go
		15  //	cmd/link/internal/ld/decodesym.go
		16  //	reflect/type.go
		17  //			internal/reflectlite/type.go
		18  type tflag uint8
		19  
		20  const (
		21  	tflagUncommon			tflag = 1 << 0
		22  	tflagExtraStar		 tflag = 1 << 1
		23  	tflagNamed				 tflag = 1 << 2
		24  	tflagRegularMemory tflag = 1 << 3 // equal and hash can treat values of this type as a single region of t.size bytes
		25  )
		26  
		27  // Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize,
		28  // ../cmd/compile/internal/reflectdata/reflect.go:/^func.dcommontype and
		29  // ../reflect/type.go:/^type.rtype.
		30  // ../internal/reflectlite/type.go:/^type.rtype.
		31  type _type struct {
		32  	size			 uintptr
		33  	ptrdata		uintptr // size of memory prefix holding all pointers
		34  	hash			 uint32
		35  	tflag			tflag
		36  	align			uint8
		37  	fieldAlign uint8
		38  	kind			 uint8
		39  	// function for comparing objects of this type
		40  	// (ptr to object A, ptr to object B) -> ==?
		41  	equal func(unsafe.Pointer, unsafe.Pointer) bool
		42  	// gcdata stores the GC type data for the garbage collector.
		43  	// If the KindGCProg bit is set in kind, gcdata is a GC program.
		44  	// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
		45  	gcdata		*byte
		46  	str			 nameOff
		47  	ptrToThis typeOff
		48  }
		49  
		50  func (t *_type) string() string {
		51  	s := t.nameOff(t.str).name()
		52  	if t.tflag&tflagExtraStar != 0 {
		53  		return s[1:]
		54  	}
		55  	return s
		56  }
		57  
		58  func (t *_type) uncommon() *uncommontype {
		59  	if t.tflag&tflagUncommon == 0 {
		60  		return nil
		61  	}
		62  	switch t.kind & kindMask {
		63  	case kindStruct:
		64  		type u struct {
		65  			structtype
		66  			u uncommontype
		67  		}
		68  		return &(*u)(unsafe.Pointer(t)).u
		69  	case kindPtr:
		70  		type u struct {
		71  			ptrtype
		72  			u uncommontype
		73  		}
		74  		return &(*u)(unsafe.Pointer(t)).u
		75  	case kindFunc:
		76  		type u struct {
		77  			functype
		78  			u uncommontype
		79  		}
		80  		return &(*u)(unsafe.Pointer(t)).u
		81  	case kindSlice:
		82  		type u struct {
		83  			slicetype
		84  			u uncommontype
		85  		}
		86  		return &(*u)(unsafe.Pointer(t)).u
		87  	case kindArray:
		88  		type u struct {
		89  			arraytype
		90  			u uncommontype
		91  		}
		92  		return &(*u)(unsafe.Pointer(t)).u
		93  	case kindChan:
		94  		type u struct {
		95  			chantype
		96  			u uncommontype
		97  		}
		98  		return &(*u)(unsafe.Pointer(t)).u
		99  	case kindMap:
	 100  		type u struct {
	 101  			maptype
	 102  			u uncommontype
	 103  		}
	 104  		return &(*u)(unsafe.Pointer(t)).u
	 105  	case kindInterface:
	 106  		type u struct {
	 107  			interfacetype
	 108  			u uncommontype
	 109  		}
	 110  		return &(*u)(unsafe.Pointer(t)).u
	 111  	default:
	 112  		type u struct {
	 113  			_type
	 114  			u uncommontype
	 115  		}
	 116  		return &(*u)(unsafe.Pointer(t)).u
	 117  	}
	 118  }
	 119  
	 120  func (t *_type) name() string {
	 121  	if t.tflag&tflagNamed == 0 {
	 122  		return ""
	 123  	}
	 124  	s := t.string()
	 125  	i := len(s) - 1
	 126  	for i >= 0 && s[i] != '.' {
	 127  		i--
	 128  	}
	 129  	return s[i+1:]
	 130  }
	 131  
	 132  // pkgpath returns the path of the package where t was defined, if
	 133  // available. This is not the same as the reflect package's PkgPath
	 134  // method, in that it returns the package path for struct and interface
	 135  // types, not just named types.
	 136  func (t *_type) pkgpath() string {
	 137  	if u := t.uncommon(); u != nil {
	 138  		return t.nameOff(u.pkgpath).name()
	 139  	}
	 140  	switch t.kind & kindMask {
	 141  	case kindStruct:
	 142  		st := (*structtype)(unsafe.Pointer(t))
	 143  		return st.pkgPath.name()
	 144  	case kindInterface:
	 145  		it := (*interfacetype)(unsafe.Pointer(t))
	 146  		return it.pkgpath.name()
	 147  	}
	 148  	return ""
	 149  }
	 150  
	 151  // reflectOffs holds type offsets defined at run time by the reflect package.
	 152  //
	 153  // When a type is defined at run time, its *rtype data lives on the heap.
	 154  // There are a wide range of possible addresses the heap may use, that
	 155  // may not be representable as a 32-bit offset. Moreover the GC may
	 156  // one day start moving heap memory, in which case there is no stable
	 157  // offset that can be defined.
	 158  //
	 159  // To provide stable offsets, we add pin *rtype objects in a global map
	 160  // and treat the offset as an identifier. We use negative offsets that
	 161  // do not overlap with any compile-time module offsets.
	 162  //
	 163  // Entries are created by reflect.addReflectOff.
	 164  var reflectOffs struct {
	 165  	lock mutex
	 166  	next int32
	 167  	m		map[int32]unsafe.Pointer
	 168  	minv map[unsafe.Pointer]int32
	 169  }
	 170  
	 171  func reflectOffsLock() {
	 172  	lock(&reflectOffs.lock)
	 173  	if raceenabled {
	 174  		raceacquire(unsafe.Pointer(&reflectOffs.lock))
	 175  	}
	 176  }
	 177  
	 178  func reflectOffsUnlock() {
	 179  	if raceenabled {
	 180  		racerelease(unsafe.Pointer(&reflectOffs.lock))
	 181  	}
	 182  	unlock(&reflectOffs.lock)
	 183  }
	 184  
	 185  func resolveNameOff(ptrInModule unsafe.Pointer, off nameOff) name {
	 186  	if off == 0 {
	 187  		return name{}
	 188  	}
	 189  	base := uintptr(ptrInModule)
	 190  	for md := &firstmoduledata; md != nil; md = md.next {
	 191  		if base >= md.types && base < md.etypes {
	 192  			res := md.types + uintptr(off)
	 193  			if res > md.etypes {
	 194  				println("runtime: nameOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes))
	 195  				throw("runtime: name offset out of range")
	 196  			}
	 197  			return name{(*byte)(unsafe.Pointer(res))}
	 198  		}
	 199  	}
	 200  
	 201  	// No module found. see if it is a run time name.
	 202  	reflectOffsLock()
	 203  	res, found := reflectOffs.m[int32(off)]
	 204  	reflectOffsUnlock()
	 205  	if !found {
	 206  		println("runtime: nameOff", hex(off), "base", hex(base), "not in ranges:")
	 207  		for next := &firstmoduledata; next != nil; next = next.next {
	 208  			println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
	 209  		}
	 210  		throw("runtime: name offset base pointer out of range")
	 211  	}
	 212  	return name{(*byte)(res)}
	 213  }
	 214  
	 215  func (t *_type) nameOff(off nameOff) name {
	 216  	return resolveNameOff(unsafe.Pointer(t), off)
	 217  }
	 218  
	 219  func resolveTypeOff(ptrInModule unsafe.Pointer, off typeOff) *_type {
	 220  	if off == 0 || off == -1 {
	 221  		// -1 is the sentinel value for unreachable code.
	 222  		// See cmd/link/internal/ld/data.go:relocsym.
	 223  		return nil
	 224  	}
	 225  	base := uintptr(ptrInModule)
	 226  	var md *moduledata
	 227  	for next := &firstmoduledata; next != nil; next = next.next {
	 228  		if base >= next.types && base < next.etypes {
	 229  			md = next
	 230  			break
	 231  		}
	 232  	}
	 233  	if md == nil {
	 234  		reflectOffsLock()
	 235  		res := reflectOffs.m[int32(off)]
	 236  		reflectOffsUnlock()
	 237  		if res == nil {
	 238  			println("runtime: typeOff", hex(off), "base", hex(base), "not in ranges:")
	 239  			for next := &firstmoduledata; next != nil; next = next.next {
	 240  				println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
	 241  			}
	 242  			throw("runtime: type offset base pointer out of range")
	 243  		}
	 244  		return (*_type)(res)
	 245  	}
	 246  	if t := md.typemap[off]; t != nil {
	 247  		return t
	 248  	}
	 249  	res := md.types + uintptr(off)
	 250  	if res > md.etypes {
	 251  		println("runtime: typeOff", hex(off), "out of range", hex(md.types), "-", hex(md.etypes))
	 252  		throw("runtime: type offset out of range")
	 253  	}
	 254  	return (*_type)(unsafe.Pointer(res))
	 255  }
	 256  
	 257  func (t *_type) typeOff(off typeOff) *_type {
	 258  	return resolveTypeOff(unsafe.Pointer(t), off)
	 259  }
	 260  
	 261  func (t *_type) textOff(off textOff) unsafe.Pointer {
	 262  	if off == -1 {
	 263  		// -1 is the sentinel value for unreachable code.
	 264  		// See cmd/link/internal/ld/data.go:relocsym.
	 265  		return unsafe.Pointer(funcPC(unreachableMethod))
	 266  	}
	 267  	base := uintptr(unsafe.Pointer(t))
	 268  	var md *moduledata
	 269  	for next := &firstmoduledata; next != nil; next = next.next {
	 270  		if base >= next.types && base < next.etypes {
	 271  			md = next
	 272  			break
	 273  		}
	 274  	}
	 275  	if md == nil {
	 276  		reflectOffsLock()
	 277  		res := reflectOffs.m[int32(off)]
	 278  		reflectOffsUnlock()
	 279  		if res == nil {
	 280  			println("runtime: textOff", hex(off), "base", hex(base), "not in ranges:")
	 281  			for next := &firstmoduledata; next != nil; next = next.next {
	 282  				println("\ttypes", hex(next.types), "etypes", hex(next.etypes))
	 283  			}
	 284  			throw("runtime: text offset base pointer out of range")
	 285  		}
	 286  		return res
	 287  	}
	 288  	res := uintptr(0)
	 289  
	 290  	// The text, or instruction stream is generated as one large buffer.	The off (offset) for a method is
	 291  	// its offset within this buffer.	If the total text size gets too large, there can be issues on platforms like ppc64 if
	 292  	// the target of calls are too far for the call instruction.	To resolve the large text issue, the text is split
	 293  	// into multiple text sections to allow the linker to generate long calls when necessary.	When this happens, the vaddr
	 294  	// for each text section is set to its offset within the text.	Each method's offset is compared against the section
	 295  	// vaddrs and sizes to determine the containing section.	Then the section relative offset is added to the section's
	 296  	// relocated baseaddr to compute the method addess.
	 297  
	 298  	if len(md.textsectmap) > 1 {
	 299  		for i := range md.textsectmap {
	 300  			sectaddr := md.textsectmap[i].vaddr
	 301  			sectlen := md.textsectmap[i].length
	 302  			if uintptr(off) >= sectaddr && uintptr(off) < sectaddr+sectlen {
	 303  				res = md.textsectmap[i].baseaddr + uintptr(off) - uintptr(md.textsectmap[i].vaddr)
	 304  				break
	 305  			}
	 306  		}
	 307  	} else {
	 308  		// single text section
	 309  		res = md.text + uintptr(off)
	 310  	}
	 311  
	 312  	if res > md.etext && GOARCH != "wasm" { // on wasm, functions do not live in the same address space as the linear memory
	 313  		println("runtime: textOff", hex(off), "out of range", hex(md.text), "-", hex(md.etext))
	 314  		throw("runtime: text offset out of range")
	 315  	}
	 316  	return unsafe.Pointer(res)
	 317  }
	 318  
	 319  func (t *functype) in() []*_type {
	 320  	// See funcType in reflect/type.go for details on data layout.
	 321  	uadd := uintptr(unsafe.Sizeof(functype{}))
	 322  	if t.typ.tflag&tflagUncommon != 0 {
	 323  		uadd += unsafe.Sizeof(uncommontype{})
	 324  	}
	 325  	return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[:t.inCount]
	 326  }
	 327  
	 328  func (t *functype) out() []*_type {
	 329  	// See funcType in reflect/type.go for details on data layout.
	 330  	uadd := uintptr(unsafe.Sizeof(functype{}))
	 331  	if t.typ.tflag&tflagUncommon != 0 {
	 332  		uadd += unsafe.Sizeof(uncommontype{})
	 333  	}
	 334  	outCount := t.outCount & (1<<15 - 1)
	 335  	return (*[1 << 20]*_type)(add(unsafe.Pointer(t), uadd))[t.inCount : t.inCount+outCount]
	 336  }
	 337  
	 338  func (t *functype) dotdotdot() bool {
	 339  	return t.outCount&(1<<15) != 0
	 340  }
	 341  
	 342  type nameOff int32
	 343  type typeOff int32
	 344  type textOff int32
	 345  
	 346  type method struct {
	 347  	name nameOff
	 348  	mtyp typeOff
	 349  	ifn	textOff
	 350  	tfn	textOff
	 351  }
	 352  
	 353  type uncommontype struct {
	 354  	pkgpath nameOff
	 355  	mcount	uint16 // number of methods
	 356  	xcount	uint16 // number of exported methods
	 357  	moff		uint32 // offset from this uncommontype to [mcount]method
	 358  	_			 uint32 // unused
	 359  }
	 360  
	 361  type imethod struct {
	 362  	name nameOff
	 363  	ityp typeOff
	 364  }
	 365  
	 366  type interfacetype struct {
	 367  	typ		 _type
	 368  	pkgpath name
	 369  	mhdr		[]imethod
	 370  }
	 371  
	 372  type maptype struct {
	 373  	typ		_type
	 374  	key		*_type
	 375  	elem	 *_type
	 376  	bucket *_type // internal type representing a hash bucket
	 377  	// function for hashing keys (ptr to key, seed) -> hash
	 378  	hasher		 func(unsafe.Pointer, uintptr) uintptr
	 379  	keysize		uint8	// size of key slot
	 380  	elemsize	 uint8	// size of elem slot
	 381  	bucketsize uint16 // size of bucket
	 382  	flags			uint32
	 383  }
	 384  
	 385  // Note: flag values must match those used in the TMAP case
	 386  // in ../cmd/compile/internal/reflectdata/reflect.go:writeType.
	 387  func (mt *maptype) indirectkey() bool { // store ptr to key instead of key itself
	 388  	return mt.flags&1 != 0
	 389  }
	 390  func (mt *maptype) indirectelem() bool { // store ptr to elem instead of elem itself
	 391  	return mt.flags&2 != 0
	 392  }
	 393  func (mt *maptype) reflexivekey() bool { // true if k==k for all keys
	 394  	return mt.flags&4 != 0
	 395  }
	 396  func (mt *maptype) needkeyupdate() bool { // true if we need to update key on an overwrite
	 397  	return mt.flags&8 != 0
	 398  }
	 399  func (mt *maptype) hashMightPanic() bool { // true if hash function might panic
	 400  	return mt.flags&16 != 0
	 401  }
	 402  
	 403  type arraytype struct {
	 404  	typ	 _type
	 405  	elem	*_type
	 406  	slice *_type
	 407  	len	 uintptr
	 408  }
	 409  
	 410  type chantype struct {
	 411  	typ	_type
	 412  	elem *_type
	 413  	dir	uintptr
	 414  }
	 415  
	 416  type slicetype struct {
	 417  	typ	_type
	 418  	elem *_type
	 419  }
	 420  
	 421  type functype struct {
	 422  	typ			_type
	 423  	inCount	uint16
	 424  	outCount uint16
	 425  }
	 426  
	 427  type ptrtype struct {
	 428  	typ	_type
	 429  	elem *_type
	 430  }
	 431  
	 432  type structfield struct {
	 433  	name			 name
	 434  	typ				*_type
	 435  	offsetAnon uintptr
	 436  }
	 437  
	 438  func (f *structfield) offset() uintptr {
	 439  	return f.offsetAnon >> 1
	 440  }
	 441  
	 442  type structtype struct {
	 443  	typ		 _type
	 444  	pkgPath name
	 445  	fields	[]structfield
	 446  }
	 447  
	 448  // name is an encoded type name with optional extra data.
	 449  // See reflect/type.go for details.
	 450  type name struct {
	 451  	bytes *byte
	 452  }
	 453  
	 454  func (n name) data(off int) *byte {
	 455  	return (*byte)(add(unsafe.Pointer(n.bytes), uintptr(off)))
	 456  }
	 457  
	 458  func (n name) isExported() bool {
	 459  	return (*n.bytes)&(1<<0) != 0
	 460  }
	 461  
	 462  func (n name) readvarint(off int) (int, int) {
	 463  	v := 0
	 464  	for i := 0; ; i++ {
	 465  		x := *n.data(off + i)
	 466  		v += int(x&0x7f) << (7 * i)
	 467  		if x&0x80 == 0 {
	 468  			return i + 1, v
	 469  		}
	 470  	}
	 471  }
	 472  
	 473  func (n name) name() (s string) {
	 474  	if n.bytes == nil {
	 475  		return ""
	 476  	}
	 477  	i, l := n.readvarint(1)
	 478  	if l == 0 {
	 479  		return ""
	 480  	}
	 481  	hdr := (*stringStruct)(unsafe.Pointer(&s))
	 482  	hdr.str = unsafe.Pointer(n.data(1 + i))
	 483  	hdr.len = l
	 484  	return
	 485  }
	 486  
	 487  func (n name) tag() (s string) {
	 488  	if *n.data(0)&(1<<1) == 0 {
	 489  		return ""
	 490  	}
	 491  	i, l := n.readvarint(1)
	 492  	i2, l2 := n.readvarint(1 + i + l)
	 493  	hdr := (*stringStruct)(unsafe.Pointer(&s))
	 494  	hdr.str = unsafe.Pointer(n.data(1 + i + l + i2))
	 495  	hdr.len = l2
	 496  	return
	 497  }
	 498  
	 499  func (n name) pkgPath() string {
	 500  	if n.bytes == nil || *n.data(0)&(1<<2) == 0 {
	 501  		return ""
	 502  	}
	 503  	i, l := n.readvarint(1)
	 504  	off := 1 + i + l
	 505  	if *n.data(0)&(1<<1) != 0 {
	 506  		i2, l2 := n.readvarint(off)
	 507  		off += i2 + l2
	 508  	}
	 509  	var nameOff nameOff
	 510  	copy((*[4]byte)(unsafe.Pointer(&nameOff))[:], (*[4]byte)(unsafe.Pointer(n.data(off)))[:])
	 511  	pkgPathName := resolveNameOff(unsafe.Pointer(n.bytes), nameOff)
	 512  	return pkgPathName.name()
	 513  }
	 514  
	 515  func (n name) isBlank() bool {
	 516  	if n.bytes == nil {
	 517  		return false
	 518  	}
	 519  	_, l := n.readvarint(1)
	 520  	return l == 1 && *n.data(2) == '_'
	 521  }
	 522  
	 523  // typelinksinit scans the types from extra modules and builds the
	 524  // moduledata typemap used to de-duplicate type pointers.
	 525  func typelinksinit() {
	 526  	if firstmoduledata.next == nil {
	 527  		return
	 528  	}
	 529  	typehash := make(map[uint32][]*_type, len(firstmoduledata.typelinks))
	 530  
	 531  	modules := activeModules()
	 532  	prev := modules[0]
	 533  	for _, md := range modules[1:] {
	 534  		// Collect types from the previous module into typehash.
	 535  	collect:
	 536  		for _, tl := range prev.typelinks {
	 537  			var t *_type
	 538  			if prev.typemap == nil {
	 539  				t = (*_type)(unsafe.Pointer(prev.types + uintptr(tl)))
	 540  			} else {
	 541  				t = prev.typemap[typeOff(tl)]
	 542  			}
	 543  			// Add to typehash if not seen before.
	 544  			tlist := typehash[t.hash]
	 545  			for _, tcur := range tlist {
	 546  				if tcur == t {
	 547  					continue collect
	 548  				}
	 549  			}
	 550  			typehash[t.hash] = append(tlist, t)
	 551  		}
	 552  
	 553  		if md.typemap == nil {
	 554  			// If any of this module's typelinks match a type from a
	 555  			// prior module, prefer that prior type by adding the offset
	 556  			// to this module's typemap.
	 557  			tm := make(map[typeOff]*_type, len(md.typelinks))
	 558  			pinnedTypemaps = append(pinnedTypemaps, tm)
	 559  			md.typemap = tm
	 560  			for _, tl := range md.typelinks {
	 561  				t := (*_type)(unsafe.Pointer(md.types + uintptr(tl)))
	 562  				for _, candidate := range typehash[t.hash] {
	 563  					seen := map[_typePair]struct{}{}
	 564  					if typesEqual(t, candidate, seen) {
	 565  						t = candidate
	 566  						break
	 567  					}
	 568  				}
	 569  				md.typemap[typeOff(tl)] = t
	 570  			}
	 571  		}
	 572  
	 573  		prev = md
	 574  	}
	 575  }
	 576  
	 577  type _typePair struct {
	 578  	t1 *_type
	 579  	t2 *_type
	 580  }
	 581  
	 582  // typesEqual reports whether two types are equal.
	 583  //
	 584  // Everywhere in the runtime and reflect packages, it is assumed that
	 585  // there is exactly one *_type per Go type, so that pointer equality
	 586  // can be used to test if types are equal. There is one place that
	 587  // breaks this assumption: buildmode=shared. In this case a type can
	 588  // appear as two different pieces of memory. This is hidden from the
	 589  // runtime and reflect package by the per-module typemap built in
	 590  // typelinksinit. It uses typesEqual to map types from later modules
	 591  // back into earlier ones.
	 592  //
	 593  // Only typelinksinit needs this function.
	 594  func typesEqual(t, v *_type, seen map[_typePair]struct{}) bool {
	 595  	tp := _typePair{t, v}
	 596  	if _, ok := seen[tp]; ok {
	 597  		return true
	 598  	}
	 599  
	 600  	// mark these types as seen, and thus equivalent which prevents an infinite loop if
	 601  	// the two types are identical, but recursively defined and loaded from
	 602  	// different modules
	 603  	seen[tp] = struct{}{}
	 604  
	 605  	if t == v {
	 606  		return true
	 607  	}
	 608  	kind := t.kind & kindMask
	 609  	if kind != v.kind&kindMask {
	 610  		return false
	 611  	}
	 612  	if t.string() != v.string() {
	 613  		return false
	 614  	}
	 615  	ut := t.uncommon()
	 616  	uv := v.uncommon()
	 617  	if ut != nil || uv != nil {
	 618  		if ut == nil || uv == nil {
	 619  			return false
	 620  		}
	 621  		pkgpatht := t.nameOff(ut.pkgpath).name()
	 622  		pkgpathv := v.nameOff(uv.pkgpath).name()
	 623  		if pkgpatht != pkgpathv {
	 624  			return false
	 625  		}
	 626  	}
	 627  	if kindBool <= kind && kind <= kindComplex128 {
	 628  		return true
	 629  	}
	 630  	switch kind {
	 631  	case kindString, kindUnsafePointer:
	 632  		return true
	 633  	case kindArray:
	 634  		at := (*arraytype)(unsafe.Pointer(t))
	 635  		av := (*arraytype)(unsafe.Pointer(v))
	 636  		return typesEqual(at.elem, av.elem, seen) && at.len == av.len
	 637  	case kindChan:
	 638  		ct := (*chantype)(unsafe.Pointer(t))
	 639  		cv := (*chantype)(unsafe.Pointer(v))
	 640  		return ct.dir == cv.dir && typesEqual(ct.elem, cv.elem, seen)
	 641  	case kindFunc:
	 642  		ft := (*functype)(unsafe.Pointer(t))
	 643  		fv := (*functype)(unsafe.Pointer(v))
	 644  		if ft.outCount != fv.outCount || ft.inCount != fv.inCount {
	 645  			return false
	 646  		}
	 647  		tin, vin := ft.in(), fv.in()
	 648  		for i := 0; i < len(tin); i++ {
	 649  			if !typesEqual(tin[i], vin[i], seen) {
	 650  				return false
	 651  			}
	 652  		}
	 653  		tout, vout := ft.out(), fv.out()
	 654  		for i := 0; i < len(tout); i++ {
	 655  			if !typesEqual(tout[i], vout[i], seen) {
	 656  				return false
	 657  			}
	 658  		}
	 659  		return true
	 660  	case kindInterface:
	 661  		it := (*interfacetype)(unsafe.Pointer(t))
	 662  		iv := (*interfacetype)(unsafe.Pointer(v))
	 663  		if it.pkgpath.name() != iv.pkgpath.name() {
	 664  			return false
	 665  		}
	 666  		if len(it.mhdr) != len(iv.mhdr) {
	 667  			return false
	 668  		}
	 669  		for i := range it.mhdr {
	 670  			tm := &it.mhdr[i]
	 671  			vm := &iv.mhdr[i]
	 672  			// Note the mhdr array can be relocated from
	 673  			// another module. See #17724.
	 674  			tname := resolveNameOff(unsafe.Pointer(tm), tm.name)
	 675  			vname := resolveNameOff(unsafe.Pointer(vm), vm.name)
	 676  			if tname.name() != vname.name() {
	 677  				return false
	 678  			}
	 679  			if tname.pkgPath() != vname.pkgPath() {
	 680  				return false
	 681  			}
	 682  			tityp := resolveTypeOff(unsafe.Pointer(tm), tm.ityp)
	 683  			vityp := resolveTypeOff(unsafe.Pointer(vm), vm.ityp)
	 684  			if !typesEqual(tityp, vityp, seen) {
	 685  				return false
	 686  			}
	 687  		}
	 688  		return true
	 689  	case kindMap:
	 690  		mt := (*maptype)(unsafe.Pointer(t))
	 691  		mv := (*maptype)(unsafe.Pointer(v))
	 692  		return typesEqual(mt.key, mv.key, seen) && typesEqual(mt.elem, mv.elem, seen)
	 693  	case kindPtr:
	 694  		pt := (*ptrtype)(unsafe.Pointer(t))
	 695  		pv := (*ptrtype)(unsafe.Pointer(v))
	 696  		return typesEqual(pt.elem, pv.elem, seen)
	 697  	case kindSlice:
	 698  		st := (*slicetype)(unsafe.Pointer(t))
	 699  		sv := (*slicetype)(unsafe.Pointer(v))
	 700  		return typesEqual(st.elem, sv.elem, seen)
	 701  	case kindStruct:
	 702  		st := (*structtype)(unsafe.Pointer(t))
	 703  		sv := (*structtype)(unsafe.Pointer(v))
	 704  		if len(st.fields) != len(sv.fields) {
	 705  			return false
	 706  		}
	 707  		if st.pkgPath.name() != sv.pkgPath.name() {
	 708  			return false
	 709  		}
	 710  		for i := range st.fields {
	 711  			tf := &st.fields[i]
	 712  			vf := &sv.fields[i]
	 713  			if tf.name.name() != vf.name.name() {
	 714  				return false
	 715  			}
	 716  			if !typesEqual(tf.typ, vf.typ, seen) {
	 717  				return false
	 718  			}
	 719  			if tf.name.tag() != vf.name.tag() {
	 720  				return false
	 721  			}
	 722  			if tf.offsetAnon != vf.offsetAnon {
	 723  				return false
	 724  			}
	 725  		}
	 726  		return true
	 727  	default:
	 728  		println("runtime: impossible type kind", kind)
	 729  		throw("runtime: impossible type kind")
	 730  		return false
	 731  	}
	 732  }
	 733  

View as plain text