github.com/reiver/go@v0.0.0-20150109200633-1d0c7792f172/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.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) (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  		x := newobject(t)
   140  		// TODO: We allocate a zeroed object only to overwrite it with
   141  		// actual data.  Figure out how to avoid zeroing.  Also below in convT2I.
   142  		typedmemmove(t, x, elem)
   143  		ep._type = t
   144  		ep.data = x
   145  	}
   146  	return
   147  }
   148  
   149  func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer) (i fInterface) {
   150  	tab := (*itab)(atomicloadp(unsafe.Pointer(cache)))
   151  	if tab == nil {
   152  		tab = getitab(inter, t, false)
   153  		atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab))
   154  	}
   155  	pi := (*iface)(unsafe.Pointer(&i))
   156  	if isDirectIface(t) {
   157  		pi.tab = tab
   158  		typedmemmove(t, unsafe.Pointer(&pi.data), elem)
   159  	} else {
   160  		x := newobject(t)
   161  		typedmemmove(t, x, elem)
   162  		pi.tab = tab
   163  		pi.data = x
   164  	}
   165  	return
   166  }
   167  
   168  func assertI2T(t *_type, i fInterface, r unsafe.Pointer) {
   169  	ip := (*iface)(unsafe.Pointer(&i))
   170  	tab := ip.tab
   171  	if tab == nil {
   172  		panic(&TypeAssertionError{"", "", *t._string, ""})
   173  	}
   174  	if tab._type != t {
   175  		panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""})
   176  	}
   177  	if r != nil {
   178  		if isDirectIface(t) {
   179  			writebarrierptr((*uintptr)(r), uintptr(ip.data))
   180  		} else {
   181  			typedmemmove(t, r, ip.data)
   182  		}
   183  	}
   184  }
   185  
   186  func assertI2T2(t *_type, i fInterface, r unsafe.Pointer) bool {
   187  	ip := (*iface)(unsafe.Pointer(&i))
   188  	tab := ip.tab
   189  	if tab == nil || tab._type != t {
   190  		if r != nil {
   191  			memclr(r, uintptr(t.size))
   192  		}
   193  		return false
   194  	}
   195  	if r != nil {
   196  		if isDirectIface(t) {
   197  			writebarrierptr((*uintptr)(r), uintptr(ip.data))
   198  		} else {
   199  			typedmemmove(t, r, ip.data)
   200  		}
   201  	}
   202  	return true
   203  }
   204  
   205  func assertE2T(t *_type, e interface{}, r unsafe.Pointer) {
   206  	ep := (*eface)(unsafe.Pointer(&e))
   207  	if ep._type == nil {
   208  		panic(&TypeAssertionError{"", "", *t._string, ""})
   209  	}
   210  	if ep._type != t {
   211  		panic(&TypeAssertionError{"", *ep._type._string, *t._string, ""})
   212  	}
   213  	if r != nil {
   214  		if isDirectIface(t) {
   215  			writebarrierptr((*uintptr)(r), uintptr(ep.data))
   216  		} else {
   217  			typedmemmove(t, r, ep.data)
   218  		}
   219  	}
   220  }
   221  
   222  func assertE2T2(t *_type, e interface{}, r unsafe.Pointer) bool {
   223  	ep := (*eface)(unsafe.Pointer(&e))
   224  	if ep._type != t {
   225  		if r != nil {
   226  			memclr(r, uintptr(t.size))
   227  		}
   228  		return false
   229  	}
   230  	if r != nil {
   231  		if isDirectIface(t) {
   232  			writebarrierptr((*uintptr)(r), uintptr(ep.data))
   233  		} else {
   234  			typedmemmove(t, r, ep.data)
   235  		}
   236  	}
   237  	return true
   238  }
   239  
   240  func convI2E(i fInterface) (r interface{}) {
   241  	ip := (*iface)(unsafe.Pointer(&i))
   242  	tab := ip.tab
   243  	if tab == nil {
   244  		return
   245  	}
   246  	rp := (*eface)(unsafe.Pointer(&r))
   247  	rp._type = tab._type
   248  	rp.data = ip.data
   249  	return
   250  }
   251  
   252  func assertI2E(inter *interfacetype, i fInterface, r *interface{}) {
   253  	ip := (*iface)(unsafe.Pointer(&i))
   254  	tab := ip.tab
   255  	if tab == nil {
   256  		// explicit conversions require non-nil interface value.
   257  		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
   258  	}
   259  	rp := (*eface)(unsafe.Pointer(r))
   260  	rp._type = tab._type
   261  	rp.data = ip.data
   262  	return
   263  }
   264  
   265  func assertI2E2(inter *interfacetype, i fInterface, r *interface{}) bool {
   266  	ip := (*iface)(unsafe.Pointer(&i))
   267  	tab := ip.tab
   268  	if tab == nil {
   269  		return false
   270  	}
   271  	if r != nil {
   272  		rp := (*eface)(unsafe.Pointer(r))
   273  		rp._type = tab._type
   274  		rp.data = ip.data
   275  	}
   276  	return true
   277  }
   278  
   279  func convI2I(inter *interfacetype, i fInterface) (r fInterface) {
   280  	ip := (*iface)(unsafe.Pointer(&i))
   281  	tab := ip.tab
   282  	if tab == nil {
   283  		return
   284  	}
   285  	rp := (*iface)(unsafe.Pointer(&r))
   286  	if tab.inter == inter {
   287  		rp.tab = tab
   288  		rp.data = ip.data
   289  		return
   290  	}
   291  	rp.tab = getitab(inter, tab._type, false)
   292  	rp.data = ip.data
   293  	return
   294  }
   295  
   296  func assertI2I(inter *interfacetype, i fInterface, r *fInterface) {
   297  	ip := (*iface)(unsafe.Pointer(&i))
   298  	tab := ip.tab
   299  	if tab == nil {
   300  		// explicit conversions require non-nil interface value.
   301  		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
   302  	}
   303  	rp := (*iface)(unsafe.Pointer(r))
   304  	if tab.inter == inter {
   305  		rp.tab = tab
   306  		rp.data = ip.data
   307  		return
   308  	}
   309  	rp.tab = getitab(inter, tab._type, false)
   310  	rp.data = ip.data
   311  }
   312  
   313  func assertI2I2(inter *interfacetype, i fInterface, r *fInterface) bool {
   314  	ip := (*iface)(unsafe.Pointer(&i))
   315  	tab := ip.tab
   316  	if tab == nil {
   317  		if r != nil {
   318  			*r = nil
   319  		}
   320  		return false
   321  	}
   322  	if tab.inter != inter {
   323  		tab = getitab(inter, tab._type, true)
   324  		if tab == nil {
   325  			if r != nil {
   326  				*r = nil
   327  			}
   328  			return false
   329  		}
   330  	}
   331  	if r != nil {
   332  		rp := (*iface)(unsafe.Pointer(r))
   333  		rp.tab = tab
   334  		rp.data = ip.data
   335  	}
   336  	return true
   337  }
   338  
   339  func assertE2I(inter *interfacetype, e interface{}, r *fInterface) {
   340  	ep := (*eface)(unsafe.Pointer(&e))
   341  	t := ep._type
   342  	if t == nil {
   343  		// explicit conversions require non-nil interface value.
   344  		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
   345  	}
   346  	rp := (*iface)(unsafe.Pointer(r))
   347  	rp.tab = getitab(inter, t, false)
   348  	rp.data = ep.data
   349  }
   350  
   351  func assertE2I2(inter *interfacetype, e interface{}, r *fInterface) bool {
   352  	ep := (*eface)(unsafe.Pointer(&e))
   353  	t := ep._type
   354  	if t == nil {
   355  		if r != nil {
   356  			*r = nil
   357  		}
   358  		return false
   359  	}
   360  	tab := getitab(inter, t, true)
   361  	if tab == nil {
   362  		if r != nil {
   363  			*r = nil
   364  		}
   365  		return false
   366  	}
   367  	if r != nil {
   368  		rp := (*iface)(unsafe.Pointer(r))
   369  		rp.tab = tab
   370  		rp.data = ep.data
   371  	}
   372  	return true
   373  }
   374  
   375  //go:linkname reflect_ifaceE2I reflect.ifaceE2I
   376  func reflect_ifaceE2I(inter *interfacetype, e interface{}, dst *fInterface) {
   377  	assertE2I(inter, e, dst)
   378  }
   379  
   380  func assertE2E(inter *interfacetype, e interface{}, r *interface{}) {
   381  	ep := (*eface)(unsafe.Pointer(&e))
   382  	if ep._type == nil {
   383  		// explicit conversions require non-nil interface value.
   384  		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
   385  	}
   386  	*r = e
   387  }
   388  
   389  func assertE2E2(inter *interfacetype, e interface{}, r *interface{}) bool {
   390  	ep := (*eface)(unsafe.Pointer(&e))
   391  	if ep._type == nil {
   392  		if r != nil {
   393  			*r = nil
   394  		}
   395  		return false
   396  	}
   397  	if r != nil {
   398  		*r = e
   399  	}
   400  	return true
   401  }
   402  
   403  func ifacethash(i fInterface) uint32 {
   404  	ip := (*iface)(unsafe.Pointer(&i))
   405  	tab := ip.tab
   406  	if tab == nil {
   407  		return 0
   408  	}
   409  	return tab._type.hash
   410  }
   411  
   412  func efacethash(e interface{}) uint32 {
   413  	ep := (*eface)(unsafe.Pointer(&e))
   414  	t := ep._type
   415  	if t == nil {
   416  		return 0
   417  	}
   418  	return t.hash
   419  }
   420  
   421  func iterate_itabs(fn func(*itab)) {
   422  	for _, h := range &hash {
   423  		for ; h != nil; h = h.link {
   424  			fn(h)
   425  		}
   426  	}
   427  }