...
Run Format

Source file src/runtime/iface.go

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

View as plain text