diff options
Diffstat (limited to 'src/pkg/runtime/iface.go')
-rw-r--r-- | src/pkg/runtime/iface.go | 439 |
1 files changed, 0 insertions, 439 deletions
diff --git a/src/pkg/runtime/iface.go b/src/pkg/runtime/iface.go deleted file mode 100644 index f60b6a79c..000000000 --- a/src/pkg/runtime/iface.go +++ /dev/null @@ -1,439 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "unsafe" -) - -const ( - hashSize = 1009 -) - -var ( - ifaceLock mutex // lock for accessing hash - hash [hashSize]*itab -) - -// fInterface is our standard non-empty interface. We use it instead -// of interface{f()} in function prototypes because gofmt insists on -// putting lots of newlines in the otherwise concise interface{f()}. -type fInterface interface { - f() -} - -func getitab(inter *interfacetype, typ *_type, canfail bool) *itab { - if len(inter.mhdr) == 0 { - gothrow("internal error - misuse of itab") - } - - // easy case - x := typ.x - if x == nil { - if canfail { - return nil - } - i := (*imethod)(add(unsafe.Pointer(inter), unsafe.Sizeof(interfacetype{}))) - panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *i.name}) - } - - // compiler has provided some good hash codes for us. - h := inter.typ.hash - h += 17 * typ.hash - // TODO(rsc): h += 23 * x.mhash ? - h %= hashSize - - // look twice - once without lock, once with. - // common case will be no lock contention. - var m *itab - var locked int - for locked = 0; locked < 2; locked++ { - if locked != 0 { - lock(&ifaceLock) - } - for m = (*itab)(atomicloadp(unsafe.Pointer(&hash[h]))); m != nil; m = m.link { - if m.inter == inter && m._type == typ { - if m.bad != 0 { - m = nil - if !canfail { - // this can only happen if the conversion - // was already done once using the , ok form - // and we have a cached negative result. - // the cached result doesn't record which - // interface function was missing, so jump - // down to the interface check, which will - // do more work but give a better error. - goto search - } - } - if locked != 0 { - unlock(&ifaceLock) - } - return m - } - } - } - - m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr))*ptrSize, 0, &memstats.other_sys)) - m.inter = inter - m._type = typ - -search: - // both inter and typ have method sorted by name, - // and interface names are unique, - // so can iterate over both in lock step; - // the loop is O(ni+nt) not O(ni*nt). - ni := len(inter.mhdr) - nt := len(x.mhdr) - j := 0 - for k := 0; k < ni; k++ { - i := (*imethod)(add(unsafe.Pointer(inter), unsafe.Sizeof(interfacetype{})+uintptr(k)*unsafe.Sizeof(imethod{}))) - iname := i.name - ipkgpath := i.pkgpath - itype := i._type - for ; j < nt; j++ { - t := (*method)(add(unsafe.Pointer(x), unsafe.Sizeof(uncommontype{})+uintptr(j)*unsafe.Sizeof(method{}))) - if t.mtyp == itype && t.name == iname && t.pkgpath == ipkgpath { - if m != nil { - *(*unsafe.Pointer)(add(unsafe.Pointer(m), unsafe.Sizeof(itab{})+uintptr(k)*ptrSize)) = t.ifn - } - goto nextimethod - } - } - // didn't find method - if !canfail { - if locked != 0 { - unlock(&ifaceLock) - } - panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *iname}) - } - m.bad = 1 - break - nextimethod: - } - if locked == 0 { - gothrow("invalid itab locking") - } - m.link = hash[h] - atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m)) - unlock(&ifaceLock) - if m.bad != 0 { - return nil - } - return m -} - -func typ2Itab(t *_type, inter *interfacetype, cache **itab) *itab { - tab := getitab(inter, t, false) - atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab)) - return tab -} - -func convT2E(t *_type, elem unsafe.Pointer) (e interface{}) { - size := uintptr(t.size) - ep := (*eface)(unsafe.Pointer(&e)) - if isDirectIface(t) { - ep._type = t - memmove(unsafe.Pointer(&ep.data), elem, size) - } else { - x := newobject(t) - // TODO: We allocate a zeroed object only to overwrite it with - // actual data. Figure out how to avoid zeroing. Also below in convT2I. - memmove(x, elem, size) - ep._type = t - ep.data = x - } - return -} - -func convT2I(t *_type, inter *interfacetype, cache **itab, elem unsafe.Pointer) (i fInterface) { - tab := (*itab)(atomicloadp(unsafe.Pointer(cache))) - if tab == nil { - tab = getitab(inter, t, false) - atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab)) - } - size := uintptr(t.size) - pi := (*iface)(unsafe.Pointer(&i)) - if isDirectIface(t) { - pi.tab = tab - memmove(unsafe.Pointer(&pi.data), elem, size) - } else { - x := newobject(t) - memmove(x, elem, size) - pi.tab = tab - pi.data = x - } - return -} - -// TODO: give these routines a pointer to the result area instead of writing -// extra data in the outargs section. Then we can get rid of go:nosplit. -//go:nosplit -func assertI2T(t *_type, i fInterface) (r struct{}) { - ip := (*iface)(unsafe.Pointer(&i)) - tab := ip.tab - if tab == nil { - panic(&TypeAssertionError{"", "", *t._string, ""}) - } - if tab._type != t { - panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""}) - } - size := uintptr(t.size) - if isDirectIface(t) { - memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), size) - } else { - memmove(unsafe.Pointer(&r), ip.data, size) - } - return -} - -//go:nosplit -func assertI2T2(t *_type, i fInterface) (r byte) { - ip := (*iface)(unsafe.Pointer(&i)) - size := uintptr(t.size) - ok := (*bool)(add(unsafe.Pointer(&r), size)) - tab := ip.tab - if tab == nil || tab._type != t { - *ok = false - memclr(unsafe.Pointer(&r), size) - return - } - *ok = true - if isDirectIface(t) { - memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), size) - } else { - memmove(unsafe.Pointer(&r), ip.data, size) - } - return -} - -func assertI2TOK(t *_type, i fInterface) bool { - ip := (*iface)(unsafe.Pointer(&i)) - tab := ip.tab - return tab != nil && tab._type == t -} - -//go:nosplit -func assertE2T(t *_type, e interface{}) (r struct{}) { - ep := (*eface)(unsafe.Pointer(&e)) - if ep._type == nil { - panic(&TypeAssertionError{"", "", *t._string, ""}) - } - if ep._type != t { - panic(&TypeAssertionError{"", *ep._type._string, *t._string, ""}) - } - size := uintptr(t.size) - if isDirectIface(t) { - memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), size) - } else { - memmove(unsafe.Pointer(&r), ep.data, size) - } - return -} - -//go:nosplit -func assertE2T2(t *_type, e interface{}) (r byte) { - ep := (*eface)(unsafe.Pointer(&e)) - size := uintptr(t.size) - ok := (*bool)(add(unsafe.Pointer(&r), size)) - if ep._type != t { - *ok = false - memclr(unsafe.Pointer(&r), size) - return - } - *ok = true - if isDirectIface(t) { - memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), size) - } else { - memmove(unsafe.Pointer(&r), ep.data, size) - } - return -} - -func assertE2TOK(t *_type, e interface{}) bool { - ep := (*eface)(unsafe.Pointer(&e)) - return t == ep._type -} - -func convI2E(i fInterface) (r interface{}) { - ip := (*iface)(unsafe.Pointer(&i)) - tab := ip.tab - if tab == nil { - return - } - rp := (*eface)(unsafe.Pointer(&r)) - rp._type = tab._type - rp.data = ip.data - return -} - -func assertI2E(inter *interfacetype, i fInterface) (r interface{}) { - ip := (*iface)(unsafe.Pointer(&i)) - tab := ip.tab - if tab == nil { - // explicit conversions require non-nil interface value. - panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) - } - rp := (*eface)(unsafe.Pointer(&r)) - rp._type = tab._type - rp.data = ip.data - return -} - -func assertI2E2(inter *interfacetype, i fInterface) (r interface{}, ok bool) { - ip := (*iface)(unsafe.Pointer(&i)) - tab := ip.tab - if tab == nil { - return - } - rp := (*eface)(unsafe.Pointer(&r)) - rp._type = tab._type - rp.data = ip.data - ok = true - return -} - -func convI2I(inter *interfacetype, i fInterface) (r fInterface) { - ip := (*iface)(unsafe.Pointer(&i)) - tab := ip.tab - if tab == nil { - return - } - rp := (*iface)(unsafe.Pointer(&r)) - if tab.inter == inter { - rp.tab = tab - rp.data = ip.data - return - } - rp.tab = getitab(inter, tab._type, false) - rp.data = ip.data - return -} - -func assertI2I(inter *interfacetype, i fInterface) (r fInterface) { - ip := (*iface)(unsafe.Pointer(&i)) - tab := ip.tab - if tab == nil { - // explicit conversions require non-nil interface value. - panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) - } - rp := (*iface)(unsafe.Pointer(&r)) - if tab.inter == inter { - rp.tab = tab - rp.data = ip.data - return - } - rp.tab = getitab(inter, tab._type, false) - rp.data = ip.data - return -} - -func assertI2I2(inter *interfacetype, i fInterface) (r fInterface, ok bool) { - ip := (*iface)(unsafe.Pointer(&i)) - tab := ip.tab - if tab == nil { - return - } - rp := (*iface)(unsafe.Pointer(&r)) - if tab.inter == inter { - rp.tab = tab - rp.data = ip.data - ok = true - return - } - tab = getitab(inter, tab._type, true) - if tab == nil { - rp.data = nil - rp.tab = nil - ok = false - return - } - rp.tab = tab - rp.data = ip.data - ok = true - return -} - -func assertE2I(inter *interfacetype, e interface{}) (r fInterface) { - ep := (*eface)(unsafe.Pointer(&e)) - t := ep._type - if t == nil { - // explicit conversions require non-nil interface value. - panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) - } - rp := (*iface)(unsafe.Pointer(&r)) - rp.tab = getitab(inter, t, false) - rp.data = ep.data - return -} - -func assertE2I2(inter *interfacetype, e interface{}) (r fInterface, ok bool) { - ep := (*eface)(unsafe.Pointer(&e)) - t := ep._type - if t == nil { - return - } - tab := getitab(inter, t, true) - if tab == nil { - return - } - rp := (*iface)(unsafe.Pointer(&r)) - rp.tab = tab - rp.data = ep.data - ok = true - return -} - -func reflect_ifaceE2I(inter *interfacetype, e interface{}, dst *fInterface) { - *dst = assertE2I(inter, e) -} - -func assertE2E(inter *interfacetype, e interface{}) interface{} { - ep := (*eface)(unsafe.Pointer(&e)) - if ep._type == nil { - // explicit conversions require non-nil interface value. - panic(&TypeAssertionError{"", "", *inter.typ._string, ""}) - } - return e -} - -func assertE2E2(inter *interfacetype, e interface{}) (interface{}, bool) { - ep := (*eface)(unsafe.Pointer(&e)) - if ep._type == nil { - return nil, false - } - return e, true -} - -func ifacethash(i fInterface) uint32 { - ip := (*iface)(unsafe.Pointer(&i)) - tab := ip.tab - if tab == nil { - return 0 - } - return tab._type.hash -} - -func efacethash(e interface{}) uint32 { - ep := (*eface)(unsafe.Pointer(&e)) - t := ep._type - if t == nil { - return 0 - } - return t.hash -} - -func iterate_itabs(fn func(*itab)) { - for _, h := range &hash { - for ; h != nil; h = h.link { - fn(h) - } - } -} - -func ifaceE2I2(inter *interfacetype, e interface{}, r *fInterface) (ok bool) { - *r, ok = assertE2I2(inter, e) - return -} |