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