github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/src/runtime/iface.go (about)

     1  // Copyright 2014 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 runtime
     6  
     7  import (
     8  	"runtime/internal/atomic"
     9  	"runtime/internal/sys"
    10  	"unsafe"
    11  )
    12  
    13  const (
    14  	hashSize = 1009
    15  )
    16  
    17  var (
    18  	ifaceLock mutex // lock for accessing hash
    19  	hash      [hashSize]*itab
    20  )
    21  
    22  func itabhash(inter *interfacetype, typ *_type) uint32 {
    23  	// compiler has provided some good hash codes for us.
    24  	h := inter.typ.hash
    25  	h += 17 * typ.hash
    26  	// TODO(rsc): h += 23 * x.mhash ?
    27  	return h % hashSize
    28  }
    29  
    30  func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
    31  	if len(inter.mhdr) == 0 {
    32  		throw("internal error - misuse of itab")
    33  	}
    34  
    35  	// easy case
    36  	if typ.tflag&tflagUncommon == 0 {
    37  		if canfail {
    38  			return nil
    39  		}
    40  		name := inter.typ.nameOff(inter.mhdr[0].name)
    41  		panic(&TypeAssertionError{"", typ.string(), inter.typ.string(), name.name()})
    42  	}
    43  
    44  	h := itabhash(inter, typ)
    45  
    46  	// look twice - once without lock, once with.
    47  	// common case will be no lock contention.
    48  	var m *itab
    49  	var locked int
    50  	for locked = 0; locked < 2; locked++ {
    51  		if locked != 0 {
    52  			lock(&ifaceLock)
    53  		}
    54  		for m = (*itab)(atomic.Loadp(unsafe.Pointer(&hash[h]))); m != nil; m = m.link {
    55  			if m.inter == inter && m._type == typ {
    56  				if m.bad != 0 {
    57  					if !canfail {
    58  						// this can only happen if the conversion
    59  						// was already done once using the , ok form
    60  						// and we have a cached negative result.
    61  						// the cached result doesn't record which
    62  						// interface function was missing, so try
    63  						// adding the itab again, which will throw an error.
    64  						additab(m, locked != 0, false)
    65  					}
    66  					m = nil
    67  				}
    68  				if locked != 0 {
    69  					unlock(&ifaceLock)
    70  				}
    71  				return m
    72  			}
    73  		}
    74  	}
    75  
    76  	m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*sys.PtrSize, 0, &memstats.other_sys))
    77  	m.inter = inter
    78  	m._type = typ
    79  	additab(m, true, canfail)
    80  	unlock(&ifaceLock)
    81  	if m.bad != 0 {
    82  		return nil
    83  	}
    84  	return m
    85  }
    86  
    87  func additab(m *itab, locked, canfail bool) {
    88  	inter := m.inter
    89  	typ := m._type
    90  	x := typ.uncommon()
    91  
    92  	// both inter and typ have method sorted by name,
    93  	// and interface names are unique,
    94  	// so can iterate over both in lock step;
    95  	// the loop is O(ni+nt) not O(ni*nt).
    96  	ni := len(inter.mhdr)
    97  	nt := int(x.mcount)
    98  	xmhdr := (*[1 << 16]method)(add(unsafe.Pointer(x), uintptr(x.moff)))[:nt:nt]
    99  	j := 0
   100  	for k := 0; k < ni; k++ {
   101  		i := &inter.mhdr[k]
   102  		itype := inter.typ.typeOff(i.ityp)
   103  		name := inter.typ.nameOff(i.name)
   104  		iname := name.name()
   105  		ipkg := name.pkgPath()
   106  		if ipkg == "" {
   107  			ipkg = inter.pkgpath.name()
   108  		}
   109  		for ; j < nt; j++ {
   110  			t := &xmhdr[j]
   111  			tname := typ.nameOff(t.name)
   112  			if typ.typeOff(t.mtyp) == itype && tname.name() == iname {
   113  				pkgPath := tname.pkgPath()
   114  				if pkgPath == "" {
   115  					pkgPath = typ.nameOff(x.pkgpath).name()
   116  				}
   117  				if tname.isExported() || pkgPath == ipkg {
   118  					if m != nil {
   119  						ifn := typ.textOff(t.ifn)
   120  						*(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*sys.PtrSize)) = ifn
   121  					}
   122  					goto nextimethod
   123  				}
   124  			}
   125  		}
   126  		// didn't find method
   127  		if !canfail {
   128  			if locked {
   129  				unlock(&ifaceLock)
   130  			}
   131  			panic(&TypeAssertionError{"", typ.string(), inter.typ.string(), iname})
   132  		}
   133  		m.bad = 1
   134  		break
   135  	nextimethod:
   136  	}
   137  	if !locked {
   138  		throw("invalid itab locking")
   139  	}
   140  	h := itabhash(inter, typ)
   141  	m.link = hash[h]
   142  	m.inhash = 1
   143  	atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m))
   144  }
   145  
   146  func itabsinit() {
   147  	lock(&ifaceLock)
   148  	for _, md := range activeModules() {
   149  		for _, i := range md.itablinks {
   150  			// itablinks is a slice of pointers to the itabs used in this
   151  			// module. A given itab may be used in more than one module
   152  			// and thanks to the way global symbol resolution works, the
   153  			// pointed-to itab may already have been inserted into the
   154  			// global 'hash'.
   155  			if i.inhash == 0 {
   156  				additab(i, true, false)
   157  			}
   158  		}
   159  	}
   160  	unlock(&ifaceLock)
   161  }
   162  
   163  // panicdottype is called when doing an i.(T) conversion and the conversion fails.
   164  // have = the dynamic type we have.
   165  // want = the static type we're trying to convert to.
   166  // iface = the static type we're converting from.
   167  func panicdottype(have, want, iface *_type) {
   168  	haveString := ""
   169  	if have != nil {
   170  		haveString = have.string()
   171  	}
   172  	panic(&TypeAssertionError{iface.string(), haveString, want.string(), ""})
   173  }
   174  
   175  // panicnildottype is called when doing a i.(T) conversion and the interface i is nil.
   176  // want = the static type we're trying to convert to.
   177  func panicnildottype(want *_type) {
   178  	panic(&TypeAssertionError{"", "", want.string(), ""})
   179  	// TODO: Add the static type we're converting from as well.
   180  	// It might generate a better error message.
   181  	// Just to match other nil conversion errors, we don't for now.
   182  }
   183  
   184  // The conv and assert functions below do very similar things.
   185  // The convXXX functions are guaranteed by the compiler to succeed.
   186  // The assertXXX functions may fail (either panicking or returning false,
   187  // depending on whether they are 1-result or 2-result).
   188  // The convXXX functions succeed on a nil input, whereas the assertXXX
   189  // functions fail on a nil input.
   190  
   191  func convT2E(t *_type, elem unsafe.Pointer) (e eface) {
   192  	if raceenabled {
   193  		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2E))
   194  	}
   195  	if msanenabled {
   196  		msanread(elem, t.size)
   197  	}
   198  	if isDirectIface(t) {
   199  		// This case is implemented directly by the compiler.
   200  		throw("direct convT2E")
   201  	}
   202  	x := newobject(t)
   203  	// TODO: We allocate a zeroed object only to overwrite it with
   204  	// actual data. Figure out how to avoid zeroing. Also below in convT2I.
   205  	typedmemmove(t, x, elem)
   206  	e._type = t
   207  	e.data = x
   208  	return
   209  }
   210  
   211  func convT2I(tab *itab, elem unsafe.Pointer) (i iface) {
   212  	t := tab._type
   213  	if raceenabled {
   214  		raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&tab)), funcPC(convT2I))
   215  	}
   216  	if msanenabled {
   217  		msanread(elem, t.size)
   218  	}
   219  	if isDirectIface(t) {
   220  		// This case is implemented directly by the compiler.
   221  		throw("direct convT2I")
   222  	}
   223  	x := newobject(t)
   224  	typedmemmove(t, x, elem)
   225  	i.tab = tab
   226  	i.data = x
   227  	return
   228  }
   229  
   230  func convI2I(inter *interfacetype, i iface) (r iface) {
   231  	tab := i.tab
   232  	if tab == nil {
   233  		return
   234  	}
   235  	if tab.inter == inter {
   236  		r.tab = tab
   237  		r.data = i.data
   238  		return
   239  	}
   240  	r.tab = getitab(inter, tab._type, false)
   241  	r.data = i.data
   242  	return
   243  }
   244  
   245  func assertI2I(inter *interfacetype, i iface) (r iface) {
   246  	tab := i.tab
   247  	if tab == nil {
   248  		// explicit conversions require non-nil interface value.
   249  		panic(&TypeAssertionError{"", "", inter.typ.string(), ""})
   250  	}
   251  	if tab.inter == inter {
   252  		r.tab = tab
   253  		r.data = i.data
   254  		return
   255  	}
   256  	r.tab = getitab(inter, tab._type, false)
   257  	r.data = i.data
   258  	return
   259  }
   260  
   261  func assertI2I2(inter *interfacetype, i iface) (r iface, b bool) {
   262  	tab := i.tab
   263  	if tab == nil {
   264  		return
   265  	}
   266  	if tab.inter != inter {
   267  		tab = getitab(inter, tab._type, true)
   268  		if tab == nil {
   269  			return
   270  		}
   271  	}
   272  	r.tab = tab
   273  	r.data = i.data
   274  	b = true
   275  	return
   276  }
   277  
   278  func assertE2I(inter *interfacetype, e eface) (r iface) {
   279  	t := e._type
   280  	if t == nil {
   281  		// explicit conversions require non-nil interface value.
   282  		panic(&TypeAssertionError{"", "", inter.typ.string(), ""})
   283  	}
   284  	r.tab = getitab(inter, t, false)
   285  	r.data = e.data
   286  	return
   287  }
   288  
   289  func assertE2I2(inter *interfacetype, e eface) (r iface, b bool) {
   290  	t := e._type
   291  	if t == nil {
   292  		return
   293  	}
   294  	tab := getitab(inter, t, true)
   295  	if tab == nil {
   296  		return
   297  	}
   298  	r.tab = tab
   299  	r.data = e.data
   300  	b = true
   301  	return
   302  }
   303  
   304  //go:linkname reflect_ifaceE2I reflect.ifaceE2I
   305  func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) {
   306  	*dst = assertE2I(inter, e)
   307  }
   308  
   309  func iterate_itabs(fn func(*itab)) {
   310  	for _, h := range &hash {
   311  		for ; h != nil; h = h.link {
   312  			fn(h)
   313  		}
   314  	}
   315  }
   316  
   317  // staticbytes is used to avoid convT2E for byte-sized values.
   318  var staticbytes = [...]byte{
   319  	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
   320  	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
   321  	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
   322  	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
   323  	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
   324  	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
   325  	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
   326  	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
   327  	0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
   328  	0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
   329  	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
   330  	0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
   331  	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
   332  	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
   333  	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
   334  	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
   335  	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
   336  	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
   337  	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
   338  	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
   339  	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
   340  	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
   341  	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
   342  	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
   343  	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
   344  	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
   345  	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
   346  	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
   347  	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
   348  	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
   349  	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
   350  	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
   351  }