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