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