rsc.io/go@v0.0.0-20150416155037-e040fd465409/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  	"unsafe"
     9  )
    10  
    11  const (
    12  	hashSize = 1009
    13  )
    14  
    15  var (
    16  	ifaceLock mutex // lock for accessing hash
    17  	hash      [hashSize]*itab
    18  )
    19  
    20  // fInterface is our standard non-empty interface.  We use it instead
    21  // of interface{f()} in function prototypes because gofmt insists on
    22  // putting lots of newlines in the otherwise concise interface{f()}.
    23  type fInterface interface {
    24  	f()
    25  }
    26  
    27  func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
    28  	if len(inter.mhdr) == 0 {
    29  		throw("internal error - misuse of itab")
    30  	}
    31  
    32  	// easy case
    33  	x := typ.x
    34  	if x == nil {
    35  		if canfail {
    36  			return nil
    37  		}
    38  		panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *inter.mhdr[0].name})
    39  	}
    40  
    41  	// compiler has provided some good hash codes for us.
    42  	h := inter.typ.hash
    43  	h += 17 * typ.hash
    44  	// TODO(rsc): h += 23 * x.mhash ?
    45  	h %= hashSize
    46  
    47  	// look twice - once without lock, once with.
    48  	// common case will be no lock contention.
    49  	var m *itab
    50  	var locked int
    51  	for locked = 0; locked < 2; locked++ {
    52  		if locked != 0 {
    53  			lock(&ifaceLock)
    54  		}
    55  		for m = (*itab)(atomicloadp(unsafe.Pointer(&hash[h]))); m != nil; m = m.link {
    56  			if m.inter == inter && m._type == typ {
    57  				if m.bad != 0 {
    58  					m = nil
    59  					if !canfail {
    60  						// this can only happen if the conversion
    61  						// was already done once using the , ok form
    62  						// and we have a cached negative result.
    63  						// the cached result doesn't record which
    64  						// interface function was missing, so jump
    65  						// down to the interface check, which will
    66  						// do more work but give a better error.
    67  						goto search
    68  					}
    69  				}
    70  				if locked != 0 {
    71  					unlock(&ifaceLock)
    72  				}
    73  				return m
    74  			}
    75  		}
    76  	}
    77  
    78  	m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*ptrSize, 0, &memstats.other_sys))
    79  	m.inter = inter
    80  	m._type = typ
    81  
    82  search:
    83  	// both inter and typ have method sorted by name,
    84  	// and interface names are unique,
    85  	// so can iterate over both in lock step;
    86  	// the loop is O(ni+nt) not O(ni*nt).
    87  	ni := len(inter.mhdr)
    88  	nt := len(x.mhdr)
    89  	j := 0
    90  	for k := 0; k < ni; k++ {
    91  		i := &inter.mhdr[k]
    92  		iname := i.name
    93  		ipkgpath := i.pkgpath
    94  		itype := i._type
    95  		for ; j < nt; j++ {
    96  			t := &x.mhdr[j]
    97  			if t.mtyp == itype && (t.name == iname || *t.name == *iname) && t.pkgpath == ipkgpath {
    98  				if m != nil {
    99  					*(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*ptrSize)) = t.ifn
   100  				}
   101  				goto nextimethod
   102  			}
   103  		}
   104  		// didn't find method
   105  		if !canfail {
   106  			if locked != 0 {
   107  				unlock(&ifaceLock)
   108  			}
   109  			panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *iname})
   110  		}
   111  		m.bad = 1
   112  		break
   113  	nextimethod:
   114  	}
   115  	if locked == 0 {
   116  		throw("invalid itab locking")
   117  	}
   118  	m.link = hash[h]
   119  	atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m))
   120  	unlock(&ifaceLock)
   121  	if m.bad != 0 {
   122  		return nil
   123  	}
   124  	return m
   125  }
   126  
   127  func typ2Itab(t *_type, inter *interfacetype, cache **itab) *itab {
   128  	tab := getitab(inter, t, false)
   129  	atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab))
   130  	return tab
   131  }
   132  
   133  func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e interface{}) {
   134  	ep := (*eface)(unsafe.Pointer(&e))
   135  	if isDirectIface(t) {
   136  		ep._type = t
   137  		typedmemmove(t, unsafe.Pointer(&ep.data), elem)
   138  	} else {
   139  		if x == nil {
   140  			x = newobject(t)
   141  		}
   142  		// TODO: We allocate a zeroed object only to overwrite it with
   143  		// actual data.  Figure out how to avoid zeroing.  Also below in convT2I.
   144  		typedmemmove(t, x, elem)
   145  		ep._type = t
   146  		ep.data = x
   147  	}
   148  	return
   149  }
   150  
   151  func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer, x unsafe.Pointer) (i fInterface) {
   152  	tab := (*itab)(atomicloadp(unsafe.Pointer(cache)))
   153  	if tab == nil {
   154  		tab = getitab(inter, t, false)
   155  		atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab))
   156  	}
   157  	pi := (*iface)(unsafe.Pointer(&i))
   158  	if isDirectIface(t) {
   159  		pi.tab = tab
   160  		typedmemmove(t, unsafe.Pointer(&pi.data), elem)
   161  	} else {
   162  		if x == nil {
   163  			x = newobject(t)
   164  		}
   165  		typedmemmove(t, x, elem)
   166  		pi.tab = tab
   167  		pi.data = x
   168  	}
   169  	return
   170  }
   171  
   172  func panicdottype(have, want, iface *_type) {
   173  	haveString := ""
   174  	if have != nil {
   175  		haveString = *have._string
   176  	}
   177  	panic(&TypeAssertionError{*iface._string, haveString, *want._string, ""})
   178  }
   179  
   180  func assertI2T(t *_type, i fInterface, r unsafe.Pointer) {
   181  	ip := (*iface)(unsafe.Pointer(&i))
   182  	tab := ip.tab
   183  	if tab == nil {
   184  		panic(&TypeAssertionError{"", "", *t._string, ""})
   185  	}
   186  	if tab._type != t {
   187  		panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""})
   188  	}
   189  	if r != nil {
   190  		if isDirectIface(t) {
   191  			writebarrierptr((*uintptr)(r), uintptr(ip.data))
   192  		} else {
   193  			typedmemmove(t, r, ip.data)
   194  		}
   195  	}
   196  }
   197  
   198  func assertI2T2(t *_type, i fInterface, r unsafe.Pointer) bool {
   199  	ip := (*iface)(unsafe.Pointer(&i))
   200  	tab := ip.tab
   201  	if tab == nil || tab._type != t {
   202  		if r != nil {
   203  			memclr(r, uintptr(t.size))
   204  		}
   205  		return false
   206  	}
   207  	if r != nil {
   208  		if isDirectIface(t) {
   209  			writebarrierptr((*uintptr)(r), uintptr(ip.data))
   210  		} else {
   211  			typedmemmove(t, r, ip.data)
   212  		}
   213  	}
   214  	return true
   215  }
   216  
   217  func assertE2T(t *_type, e interface{}, r unsafe.Pointer) {
   218  	ep := (*eface)(unsafe.Pointer(&e))
   219  	if ep._type == nil {
   220  		panic(&TypeAssertionError{"", "", *t._string, ""})
   221  	}
   222  	if ep._type != t {
   223  		panic(&TypeAssertionError{"", *ep._type._string, *t._string, ""})
   224  	}
   225  	if r != nil {
   226  		if isDirectIface(t) {
   227  			writebarrierptr((*uintptr)(r), uintptr(ep.data))
   228  		} else {
   229  			typedmemmove(t, r, ep.data)
   230  		}
   231  	}
   232  }
   233  
   234  // The compiler ensures that r is non-nil.
   235  func assertE2T2(t *_type, e interface{}, r unsafe.Pointer) bool {
   236  	ep := (*eface)(unsafe.Pointer(&e))
   237  	if ep._type != t {
   238  		memclr(r, uintptr(t.size))
   239  		return false
   240  	}
   241  	if isDirectIface(t) {
   242  		writebarrierptr((*uintptr)(r), uintptr(ep.data))
   243  	} else {
   244  		typedmemmove(t, r, ep.data)
   245  	}
   246  	return true
   247  }
   248  
   249  func convI2E(i fInterface) (r interface{}) {
   250  	ip := (*iface)(unsafe.Pointer(&i))
   251  	tab := ip.tab
   252  	if tab == nil {
   253  		return
   254  	}
   255  	rp := (*eface)(unsafe.Pointer(&r))
   256  	rp._type = tab._type
   257  	rp.data = ip.data
   258  	return
   259  }
   260  
   261  func assertI2E(inter *interfacetype, i fInterface, r *interface{}) {
   262  	ip := (*iface)(unsafe.Pointer(&i))
   263  	tab := ip.tab
   264  	if tab == nil {
   265  		// explicit conversions require non-nil interface value.
   266  		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
   267  	}
   268  	rp := (*eface)(unsafe.Pointer(r))
   269  	rp._type = tab._type
   270  	rp.data = ip.data
   271  	return
   272  }
   273  
   274  // The compiler ensures that r is non-nil.
   275  func assertI2E2(inter *interfacetype, i fInterface, r *interface{}) bool {
   276  	ip := (*iface)(unsafe.Pointer(&i))
   277  	tab := ip.tab
   278  	if tab == nil {
   279  		return false
   280  	}
   281  	rp := (*eface)(unsafe.Pointer(r))
   282  	rp._type = tab._type
   283  	rp.data = ip.data
   284  	return true
   285  }
   286  
   287  func convI2I(inter *interfacetype, i fInterface) (r fInterface) {
   288  	ip := (*iface)(unsafe.Pointer(&i))
   289  	tab := ip.tab
   290  	if tab == nil {
   291  		return
   292  	}
   293  	rp := (*iface)(unsafe.Pointer(&r))
   294  	if tab.inter == inter {
   295  		rp.tab = tab
   296  		rp.data = ip.data
   297  		return
   298  	}
   299  	rp.tab = getitab(inter, tab._type, false)
   300  	rp.data = ip.data
   301  	return
   302  }
   303  
   304  func assertI2I(inter *interfacetype, i fInterface, r *fInterface) {
   305  	ip := (*iface)(unsafe.Pointer(&i))
   306  	tab := ip.tab
   307  	if tab == nil {
   308  		// explicit conversions require non-nil interface value.
   309  		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
   310  	}
   311  	rp := (*iface)(unsafe.Pointer(r))
   312  	if tab.inter == inter {
   313  		rp.tab = tab
   314  		rp.data = ip.data
   315  		return
   316  	}
   317  	rp.tab = getitab(inter, tab._type, false)
   318  	rp.data = ip.data
   319  }
   320  
   321  func assertI2I2(inter *interfacetype, i fInterface, r *fInterface) bool {
   322  	ip := (*iface)(unsafe.Pointer(&i))
   323  	tab := ip.tab
   324  	if tab == nil {
   325  		if r != nil {
   326  			*r = nil
   327  		}
   328  		return false
   329  	}
   330  	if tab.inter != inter {
   331  		tab = getitab(inter, tab._type, true)
   332  		if tab == nil {
   333  			if r != nil {
   334  				*r = nil
   335  			}
   336  			return false
   337  		}
   338  	}
   339  	if r != nil {
   340  		rp := (*iface)(unsafe.Pointer(r))
   341  		rp.tab = tab
   342  		rp.data = ip.data
   343  	}
   344  	return true
   345  }
   346  
   347  func assertE2I(inter *interfacetype, e interface{}, r *fInterface) {
   348  	ep := (*eface)(unsafe.Pointer(&e))
   349  	t := ep._type
   350  	if t == nil {
   351  		// explicit conversions require non-nil interface value.
   352  		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
   353  	}
   354  	rp := (*iface)(unsafe.Pointer(r))
   355  	rp.tab = getitab(inter, t, false)
   356  	rp.data = ep.data
   357  }
   358  
   359  func assertE2I2(inter *interfacetype, e interface{}, r *fInterface) bool {
   360  	ep := (*eface)(unsafe.Pointer(&e))
   361  	t := ep._type
   362  	if t == nil {
   363  		if r != nil {
   364  			*r = nil
   365  		}
   366  		return false
   367  	}
   368  	tab := getitab(inter, t, true)
   369  	if tab == nil {
   370  		if r != nil {
   371  			*r = nil
   372  		}
   373  		return false
   374  	}
   375  	if r != nil {
   376  		rp := (*iface)(unsafe.Pointer(r))
   377  		rp.tab = tab
   378  		rp.data = ep.data
   379  	}
   380  	return true
   381  }
   382  
   383  //go:linkname reflect_ifaceE2I reflect.ifaceE2I
   384  func reflect_ifaceE2I(inter *interfacetype, e interface{}, dst *fInterface) {
   385  	assertE2I(inter, e, dst)
   386  }
   387  
   388  func assertE2E(inter *interfacetype, e interface{}, r *interface{}) {
   389  	ep := (*eface)(unsafe.Pointer(&e))
   390  	if ep._type == nil {
   391  		// explicit conversions require non-nil interface value.
   392  		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
   393  	}
   394  	*r = e
   395  }
   396  
   397  // The compiler ensures that r is non-nil.
   398  func assertE2E2(inter *interfacetype, e interface{}, r *interface{}) bool {
   399  	ep := (*eface)(unsafe.Pointer(&e))
   400  	if ep._type == nil {
   401  		*r = nil
   402  		return false
   403  	}
   404  	*r = e
   405  	return true
   406  }
   407  
   408  func ifacethash(i fInterface) uint32 {
   409  	ip := (*iface)(unsafe.Pointer(&i))
   410  	tab := ip.tab
   411  	if tab == nil {
   412  		return 0
   413  	}
   414  	return tab._type.hash
   415  }
   416  
   417  func efacethash(e interface{}) uint32 {
   418  	ep := (*eface)(unsafe.Pointer(&e))
   419  	t := ep._type
   420  	if t == nil {
   421  		return 0
   422  	}
   423  	return t.hash
   424  }
   425  
   426  func iterate_itabs(fn func(*itab)) {
   427  	for _, h := range &hash {
   428  		for ; h != nil; h = h.link {
   429  			fn(h)
   430  		}
   431  	}
   432  }