...
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		m.inhash = 1
   143		atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m))
   144	}
   145	
   146	func itabsinit() {
   147		lock(&ifaceLock)
   148		for _, md := range activeModules() {
   149			for _, i := range md.itablinks {
   150				// itablinks is a slice of pointers to the itabs used in this
   151				// module. A given itab may be used in more than one module
   152				// and thanks to the way global symbol resolution works, the
   153				// pointed-to itab may already have been inserted into the
   154				// global 'hash'.
   155				if i.inhash == 0 {
   156					additab(i, true, false)
   157				}
   158			}
   159		}
   160		unlock(&ifaceLock)
   161	}
   162	
   163	// panicdottype is called when doing an i.(T) conversion and the conversion fails.
   164	// have = the dynamic type we have.
   165	// want = the static type we're trying to convert to.
   166	// iface = the static type we're converting from.
   167	func panicdottype(have, want, iface *_type) {
   168		haveString := ""
   169		if have != nil {
   170			haveString = have.string()
   171		}
   172		panic(&TypeAssertionError{iface.string(), haveString, want.string(), ""})
   173	}
   174	
   175	// panicnildottype is called when doing a i.(T) conversion and the interface i is nil.
   176	// want = the static type we're trying to convert to.
   177	func panicnildottype(want *_type) {
   178		panic(&TypeAssertionError{"", "", want.string(), ""})
   179		// TODO: Add the static type we're converting from as well.
   180		// It might generate a better error message.
   181		// Just to match other nil conversion errors, we don't for now.
   182	}
   183	
   184	// The conv and assert functions below do very similar things.
   185	// The convXXX functions are guaranteed by the compiler to succeed.
   186	// The assertXXX functions may fail (either panicking or returning false,
   187	// depending on whether they are 1-result or 2-result).
   188	// The convXXX functions succeed on a nil input, whereas the assertXXX
   189	// functions fail on a nil input.
   190	
   191	func convT2E(t *_type, elem unsafe.Pointer) (e eface) {
   192		if raceenabled {
   193			raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2E))
   194		}
   195		if msanenabled {
   196			msanread(elem, t.size)
   197		}
   198		if isDirectIface(t) {
   199			// This case is implemented directly by the compiler.
   200			throw("direct convT2E")
   201		}
   202		x := newobject(t)
   203		// TODO: We allocate a zeroed object only to overwrite it with
   204		// actual data. Figure out how to avoid zeroing. Also below in convT2I.
   205		typedmemmove(t, x, elem)
   206		e._type = t
   207		e.data = x
   208		return
   209	}
   210	
   211	func convT2I(tab *itab, elem unsafe.Pointer) (i iface) {
   212		t := tab._type
   213		if raceenabled {
   214			raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&tab)), funcPC(convT2I))
   215		}
   216		if msanenabled {
   217			msanread(elem, t.size)
   218		}
   219		if isDirectIface(t) {
   220			// This case is implemented directly by the compiler.
   221			throw("direct convT2I")
   222		}
   223		x := newobject(t)
   224		typedmemmove(t, x, elem)
   225		i.tab = tab
   226		i.data = x
   227		return
   228	}
   229	
   230	func convI2I(inter *interfacetype, i iface) (r iface) {
   231		tab := i.tab
   232		if tab == nil {
   233			return
   234		}
   235		if tab.inter == inter {
   236			r.tab = tab
   237			r.data = i.data
   238			return
   239		}
   240		r.tab = getitab(inter, tab._type, false)
   241		r.data = i.data
   242		return
   243	}
   244	
   245	func assertI2I(inter *interfacetype, i iface) (r iface) {
   246		tab := i.tab
   247		if tab == nil {
   248			// explicit conversions require non-nil interface value.
   249			panic(&TypeAssertionError{"", "", inter.typ.string(), ""})
   250		}
   251		if tab.inter == inter {
   252			r.tab = tab
   253			r.data = i.data
   254			return
   255		}
   256		r.tab = getitab(inter, tab._type, false)
   257		r.data = i.data
   258		return
   259	}
   260	
   261	func assertI2I2(inter *interfacetype, i iface) (r iface, b bool) {
   262		tab := i.tab
   263		if tab == nil {
   264			return
   265		}
   266		if tab.inter != inter {
   267			tab = getitab(inter, tab._type, true)
   268			if tab == nil {
   269				return
   270			}
   271		}
   272		r.tab = tab
   273		r.data = i.data
   274		b = true
   275		return
   276	}
   277	
   278	func assertE2I(inter *interfacetype, e eface) (r iface) {
   279		t := e._type
   280		if t == nil {
   281			// explicit conversions require non-nil interface value.
   282			panic(&TypeAssertionError{"", "", inter.typ.string(), ""})
   283		}
   284		r.tab = getitab(inter, t, false)
   285		r.data = e.data
   286		return
   287	}
   288	
   289	func assertE2I2(inter *interfacetype, e eface) (r iface, b bool) {
   290		t := e._type
   291		if t == nil {
   292			return
   293		}
   294		tab := getitab(inter, t, true)
   295		if tab == nil {
   296			return
   297		}
   298		r.tab = tab
   299		r.data = e.data
   300		b = true
   301		return
   302	}
   303	
   304	//go:linkname reflect_ifaceE2I reflect.ifaceE2I
   305	func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) {
   306		*dst = assertE2I(inter, e)
   307	}
   308	
   309	func iterate_itabs(fn func(*itab)) {
   310		for _, h := range &hash {
   311			for ; h != nil; h = h.link {
   312				fn(h)
   313			}
   314		}
   315	}
   316	

View as plain text