2014-08-07 14:58:42 -06:00
|
|
|
// 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
|
|
|
|
|
2015-11-02 12:09:24 -07:00
|
|
|
import (
|
|
|
|
"runtime/internal/atomic"
|
2015-11-11 10:39:30 -07:00
|
|
|
"runtime/internal/sys"
|
2015-11-02 12:09:24 -07:00
|
|
|
"unsafe"
|
|
|
|
)
|
2014-08-07 14:58:42 -06:00
|
|
|
|
|
|
|
const (
|
|
|
|
hashSize = 1009
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2014-08-27 21:32:49 -06:00
|
|
|
ifaceLock mutex // lock for accessing hash
|
2014-08-07 14:58:42 -06:00
|
|
|
hash [hashSize]*itab
|
|
|
|
)
|
|
|
|
|
2016-03-18 16:16:53 -06:00
|
|
|
func itabhash(inter *interfacetype, typ *_type) uint32 {
|
|
|
|
// compiler has provided some good hash codes for us.
|
|
|
|
h := inter.typ.hash
|
|
|
|
h += 17 * typ.hash
|
|
|
|
// TODO(rsc): h += 23 * x.mhash ?
|
|
|
|
return h % hashSize
|
|
|
|
}
|
|
|
|
|
2014-08-07 14:58:42 -06:00
|
|
|
func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
|
|
|
|
if len(inter.mhdr) == 0 {
|
2014-12-27 21:58:00 -07:00
|
|
|
throw("internal error - misuse of itab")
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// easy case
|
2016-03-18 16:16:53 -06:00
|
|
|
if typ.tflag&tflagUncommon == 0 {
|
2014-08-07 14:58:42 -06:00
|
|
|
if canfail {
|
|
|
|
return nil
|
|
|
|
}
|
2016-03-28 19:51:10 -06:00
|
|
|
name := inter.typ.nameOff(inter.mhdr[0].name)
|
|
|
|
panic(&TypeAssertionError{"", typ._string, inter.typ._string, name.name()})
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
|
2016-03-18 16:16:53 -06:00
|
|
|
h := itabhash(inter, typ)
|
2014-08-07 14:58:42 -06:00
|
|
|
|
|
|
|
// 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 {
|
2014-08-27 21:32:49 -06:00
|
|
|
lock(&ifaceLock)
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2015-11-02 12:09:24 -07:00
|
|
|
for m = (*itab)(atomic.Loadp(unsafe.Pointer(&hash[h]))); m != nil; m = m.link {
|
2014-08-07 14:58:42 -06:00
|
|
|
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
|
2016-03-18 16:16:53 -06:00
|
|
|
// interface function was missing, so try
|
|
|
|
// adding the itab again, which will throw an error.
|
|
|
|
additab(m, locked != 0, false)
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if locked != 0 {
|
2014-08-27 21:32:49 -06:00
|
|
|
unlock(&ifaceLock)
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
return m
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-11 10:39:30 -07:00
|
|
|
m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*sys.PtrSize, 0, &memstats.other_sys))
|
2014-08-07 14:58:42 -06:00
|
|
|
m.inter = inter
|
|
|
|
m._type = typ
|
2016-03-18 16:16:53 -06:00
|
|
|
additab(m, true, canfail)
|
|
|
|
unlock(&ifaceLock)
|
|
|
|
if m.bad != 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return m
|
|
|
|
}
|
|
|
|
|
|
|
|
func additab(m *itab, locked, canfail bool) {
|
|
|
|
inter := m.inter
|
|
|
|
typ := m._type
|
|
|
|
x := typ.uncommon()
|
2014-08-07 14:58:42 -06:00
|
|
|
|
|
|
|
// 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)
|
cmd/compile, etc: store method tables as offsets
This CL introduces the typeOff type and a lookup method of the same
name that can turn a typeOff offset into an *rtype.
In a typical Go binary (built with buildmode=exe, pie, c-archive, or
c-shared), there is one moduledata and all typeOff values are offsets
relative to firstmoduledata.types. This makes computing the pointer
cheap in typical programs.
With buildmode=shared (and one day, buildmode=plugin) there are
multiple modules whose relative offset is determined at runtime.
We identify a type in the general case by the pair of the original
*rtype that references it and its typeOff value. We determine
the module from the original pointer, and then use the typeOff from
there to compute the final *rtype.
To ensure there is only one *rtype representing each type, the
runtime initializes a typemap for each module, using any identical
type from an earlier module when resolving that offset. This means
that types computed from an offset match the type mapped by the
pointer dynamic relocations.
A series of followup CLs will replace other *rtype values with typeOff
(and name/*string with nameOff).
For types created at runtime by reflect, type offsets are treated as
global IDs and reference into a reflect offset map kept by the runtime.
darwin/amd64:
cmd/go: -57KB (0.6%)
jujud: -557KB (0.8%)
linux/amd64 PIE:
cmd/go: -361KB (3.0%)
jujud: -3.5MB (4.2%)
For #6853.
Change-Id: Icf096fd884a0a0cb9f280f46f7a26c70a9006c96
Reviewed-on: https://go-review.googlesource.com/21285
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: David Crawshaw <crawshaw@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-03-28 08:32:27 -06:00
|
|
|
nt := int(x.mcount)
|
|
|
|
xmhdr := (*[1 << 16]method)(add(unsafe.Pointer(x), uintptr(x.moff)))[:nt:nt]
|
2014-08-07 14:58:42 -06:00
|
|
|
j := 0
|
|
|
|
for k := 0; k < ni; k++ {
|
2015-01-06 21:38:44 -07:00
|
|
|
i := &inter.mhdr[k]
|
2016-03-28 19:51:10 -06:00
|
|
|
itype := inter.typ.typeOff(i.ityp)
|
|
|
|
name := inter.typ.nameOff(i.name)
|
|
|
|
iname := name.name()
|
|
|
|
ipkg := name.pkgPath()
|
2016-03-31 08:02:10 -06:00
|
|
|
if ipkg == "" {
|
|
|
|
ipkg = inter.pkgpath.name()
|
2016-03-21 11:21:55 -06:00
|
|
|
}
|
2014-08-07 14:58:42 -06:00
|
|
|
for ; j < nt; j++ {
|
cmd/compile, etc: store method tables as offsets
This CL introduces the typeOff type and a lookup method of the same
name that can turn a typeOff offset into an *rtype.
In a typical Go binary (built with buildmode=exe, pie, c-archive, or
c-shared), there is one moduledata and all typeOff values are offsets
relative to firstmoduledata.types. This makes computing the pointer
cheap in typical programs.
With buildmode=shared (and one day, buildmode=plugin) there are
multiple modules whose relative offset is determined at runtime.
We identify a type in the general case by the pair of the original
*rtype that references it and its typeOff value. We determine
the module from the original pointer, and then use the typeOff from
there to compute the final *rtype.
To ensure there is only one *rtype representing each type, the
runtime initializes a typemap for each module, using any identical
type from an earlier module when resolving that offset. This means
that types computed from an offset match the type mapped by the
pointer dynamic relocations.
A series of followup CLs will replace other *rtype values with typeOff
(and name/*string with nameOff).
For types created at runtime by reflect, type offsets are treated as
global IDs and reference into a reflect offset map kept by the runtime.
darwin/amd64:
cmd/go: -57KB (0.6%)
jujud: -557KB (0.8%)
linux/amd64 PIE:
cmd/go: -361KB (3.0%)
jujud: -3.5MB (4.2%)
For #6853.
Change-Id: Icf096fd884a0a0cb9f280f46f7a26c70a9006c96
Reviewed-on: https://go-review.googlesource.com/21285
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: David Crawshaw <crawshaw@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-03-28 08:32:27 -06:00
|
|
|
t := &xmhdr[j]
|
2016-03-28 19:51:10 -06:00
|
|
|
tname := typ.nameOff(t.name)
|
|
|
|
if typ.typeOff(t.mtyp) == itype && tname.name() == iname {
|
|
|
|
pkgPath := tname.pkgPath()
|
2016-03-31 08:02:10 -06:00
|
|
|
if pkgPath == "" {
|
|
|
|
pkgPath = x.pkgpath.name()
|
2016-03-21 11:21:55 -06:00
|
|
|
}
|
2016-03-28 19:51:10 -06:00
|
|
|
if tname.isExported() || pkgPath == ipkg {
|
2016-03-21 11:21:55 -06:00
|
|
|
if m != nil {
|
cmd/compile, etc: store method tables as offsets
This CL introduces the typeOff type and a lookup method of the same
name that can turn a typeOff offset into an *rtype.
In a typical Go binary (built with buildmode=exe, pie, c-archive, or
c-shared), there is one moduledata and all typeOff values are offsets
relative to firstmoduledata.types. This makes computing the pointer
cheap in typical programs.
With buildmode=shared (and one day, buildmode=plugin) there are
multiple modules whose relative offset is determined at runtime.
We identify a type in the general case by the pair of the original
*rtype that references it and its typeOff value. We determine
the module from the original pointer, and then use the typeOff from
there to compute the final *rtype.
To ensure there is only one *rtype representing each type, the
runtime initializes a typemap for each module, using any identical
type from an earlier module when resolving that offset. This means
that types computed from an offset match the type mapped by the
pointer dynamic relocations.
A series of followup CLs will replace other *rtype values with typeOff
(and name/*string with nameOff).
For types created at runtime by reflect, type offsets are treated as
global IDs and reference into a reflect offset map kept by the runtime.
darwin/amd64:
cmd/go: -57KB (0.6%)
jujud: -557KB (0.8%)
linux/amd64 PIE:
cmd/go: -361KB (3.0%)
jujud: -3.5MB (4.2%)
For #6853.
Change-Id: Icf096fd884a0a0cb9f280f46f7a26c70a9006c96
Reviewed-on: https://go-review.googlesource.com/21285
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: David Crawshaw <crawshaw@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-03-28 08:32:27 -06:00
|
|
|
ifn := typ.textOff(t.ifn)
|
|
|
|
*(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*sys.PtrSize)) = ifn
|
2016-03-21 11:21:55 -06:00
|
|
|
}
|
|
|
|
goto nextimethod
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// didn't find method
|
|
|
|
if !canfail {
|
2016-03-18 16:16:53 -06:00
|
|
|
if locked {
|
2014-08-27 21:32:49 -06:00
|
|
|
unlock(&ifaceLock)
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2016-03-21 11:21:55 -06:00
|
|
|
panic(&TypeAssertionError{"", typ._string, inter.typ._string, iname})
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
m.bad = 1
|
|
|
|
break
|
|
|
|
nextimethod:
|
|
|
|
}
|
2016-03-18 16:16:53 -06:00
|
|
|
if !locked {
|
2014-12-27 21:58:00 -07:00
|
|
|
throw("invalid itab locking")
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2016-03-18 16:16:53 -06:00
|
|
|
h := itabhash(inter, typ)
|
2014-08-07 14:58:42 -06:00
|
|
|
m.link = hash[h]
|
cmd/cc, runtime: preserve C runtime type names in generated Go
uintptr or uint64 in the runtime C were turning into uint in the Go,
bool was turning into uint8, and so on. Fix that.
Also delete Go wrappers for C functions.
The C functions can be called directly now
(but still eventually need to be converted to Go).
LGTM=bradfitz, minux, iant
R=golang-codereviews, bradfitz, iant, minux
CC=golang-codereviews, khr, r
https://golang.org/cl/138740043
2014-08-27 19:59:49 -06:00
|
|
|
atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m))
|
2016-03-18 16:16:53 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
func itabsinit() {
|
|
|
|
lock(&ifaceLock)
|
|
|
|
for m := &firstmoduledata; m != nil; m = m.next {
|
|
|
|
for _, i := range m.itablinks {
|
|
|
|
additab(i, true, false)
|
|
|
|
}
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2016-03-18 16:16:53 -06:00
|
|
|
unlock(&ifaceLock)
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
|
2015-10-21 13:12:25 -06:00
|
|
|
func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e eface) {
|
2015-09-18 03:40:36 -06:00
|
|
|
if raceenabled {
|
|
|
|
raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&t)), funcPC(convT2E))
|
|
|
|
}
|
2015-10-21 12:04:42 -06:00
|
|
|
if msanenabled {
|
|
|
|
msanread(elem, t.size)
|
|
|
|
}
|
2014-08-18 19:13:11 -06:00
|
|
|
if isDirectIface(t) {
|
2015-10-21 13:12:25 -06:00
|
|
|
e._type = t
|
|
|
|
typedmemmove(t, unsafe.Pointer(&e.data), elem)
|
2014-08-07 14:58:42 -06:00
|
|
|
} else {
|
2015-03-27 09:21:14 -06:00
|
|
|
if x == nil {
|
|
|
|
x = newobject(t)
|
|
|
|
}
|
2014-08-07 14:58:42 -06:00
|
|
|
// TODO: We allocate a zeroed object only to overwrite it with
|
2016-03-01 16:21:55 -07:00
|
|
|
// actual data. Figure out how to avoid zeroing. Also below in convT2I.
|
2014-12-29 08:07:47 -07:00
|
|
|
typedmemmove(t, x, elem)
|
2015-10-21 13:12:25 -06:00
|
|
|
e._type = t
|
|
|
|
e.data = x
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-03-18 18:21:33 -06:00
|
|
|
func convT2I(tab *itab, elem unsafe.Pointer, x unsafe.Pointer) (i iface) {
|
|
|
|
t := tab._type
|
2015-09-18 03:40:36 -06:00
|
|
|
if raceenabled {
|
2016-04-12 17:25:48 -06:00
|
|
|
raceReadObjectPC(t, elem, getcallerpc(unsafe.Pointer(&tab)), funcPC(convT2I))
|
2015-09-18 03:40:36 -06:00
|
|
|
}
|
2015-10-21 12:04:42 -06:00
|
|
|
if msanenabled {
|
|
|
|
msanread(elem, t.size)
|
|
|
|
}
|
2014-08-18 19:13:11 -06:00
|
|
|
if isDirectIface(t) {
|
2015-10-21 13:12:25 -06:00
|
|
|
i.tab = tab
|
|
|
|
typedmemmove(t, unsafe.Pointer(&i.data), elem)
|
2014-08-07 14:58:42 -06:00
|
|
|
} else {
|
2015-03-27 09:21:14 -06:00
|
|
|
if x == nil {
|
|
|
|
x = newobject(t)
|
|
|
|
}
|
2014-12-29 08:07:47 -07:00
|
|
|
typedmemmove(t, x, elem)
|
2015-10-21 13:12:25 -06:00
|
|
|
i.tab = tab
|
|
|
|
i.data = x
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-03-19 22:06:10 -06:00
|
|
|
func panicdottype(have, want, iface *_type) {
|
|
|
|
haveString := ""
|
|
|
|
if have != nil {
|
2016-02-16 20:23:14 -07:00
|
|
|
haveString = have._string
|
2015-03-19 22:06:10 -06:00
|
|
|
}
|
2016-02-16 20:23:14 -07:00
|
|
|
panic(&TypeAssertionError{iface._string, haveString, want._string, ""})
|
2015-03-19 22:06:10 -06:00
|
|
|
}
|
|
|
|
|
2015-10-21 13:12:25 -06:00
|
|
|
func assertI2T(t *_type, i iface, r unsafe.Pointer) {
|
|
|
|
tab := i.tab
|
2014-08-07 14:58:42 -06:00
|
|
|
if tab == nil {
|
2016-02-16 20:23:14 -07:00
|
|
|
panic(&TypeAssertionError{"", "", t._string, ""})
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
if tab._type != t {
|
2016-02-16 20:23:14 -07:00
|
|
|
panic(&TypeAssertionError{tab.inter.typ._string, tab._type._string, t._string, ""})
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2014-12-29 14:15:05 -07:00
|
|
|
if r != nil {
|
|
|
|
if isDirectIface(t) {
|
2015-10-21 13:12:25 -06:00
|
|
|
writebarrierptr((*uintptr)(r), uintptr(i.data))
|
2014-12-29 14:15:05 -07:00
|
|
|
} else {
|
2015-10-21 13:12:25 -06:00
|
|
|
typedmemmove(t, r, i.data)
|
2014-12-29 14:15:05 -07:00
|
|
|
}
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-10-21 13:12:25 -06:00
|
|
|
func assertI2T2(t *_type, i iface, r unsafe.Pointer) bool {
|
|
|
|
tab := i.tab
|
2014-08-07 14:58:42 -06:00
|
|
|
if tab == nil || tab._type != t {
|
2014-12-29 14:15:05 -07:00
|
|
|
if r != nil {
|
2016-02-29 16:01:00 -07:00
|
|
|
memclr(r, t.size)
|
2014-12-29 14:15:05 -07:00
|
|
|
}
|
|
|
|
return false
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2014-12-29 14:15:05 -07:00
|
|
|
if r != nil {
|
|
|
|
if isDirectIface(t) {
|
2015-10-21 13:12:25 -06:00
|
|
|
writebarrierptr((*uintptr)(r), uintptr(i.data))
|
2014-12-29 14:15:05 -07:00
|
|
|
} else {
|
2015-10-21 13:12:25 -06:00
|
|
|
typedmemmove(t, r, i.data)
|
2014-12-29 14:15:05 -07:00
|
|
|
}
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2014-12-29 14:15:05 -07:00
|
|
|
return true
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
|
2015-10-21 13:12:25 -06:00
|
|
|
func assertE2T(t *_type, e eface, r unsafe.Pointer) {
|
|
|
|
if e._type == nil {
|
2016-02-16 20:23:14 -07:00
|
|
|
panic(&TypeAssertionError{"", "", t._string, ""})
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2015-10-21 13:12:25 -06:00
|
|
|
if e._type != t {
|
2016-02-16 20:23:14 -07:00
|
|
|
panic(&TypeAssertionError{"", e._type._string, t._string, ""})
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2014-12-29 14:15:05 -07:00
|
|
|
if r != nil {
|
|
|
|
if isDirectIface(t) {
|
2015-10-21 13:12:25 -06:00
|
|
|
writebarrierptr((*uintptr)(r), uintptr(e.data))
|
2014-12-29 14:15:05 -07:00
|
|
|
} else {
|
2015-10-21 13:12:25 -06:00
|
|
|
typedmemmove(t, r, e.data)
|
2014-12-29 14:15:05 -07:00
|
|
|
}
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-24 11:35:49 -06:00
|
|
|
var testingAssertE2T2GC bool
|
|
|
|
|
2015-03-17 16:14:31 -06:00
|
|
|
// The compiler ensures that r is non-nil.
|
2015-10-21 13:12:25 -06:00
|
|
|
func assertE2T2(t *_type, e eface, r unsafe.Pointer) bool {
|
2015-08-24 11:35:49 -06:00
|
|
|
if testingAssertE2T2GC {
|
|
|
|
GC()
|
|
|
|
}
|
2015-10-21 13:12:25 -06:00
|
|
|
if e._type != t {
|
2016-02-29 16:01:00 -07:00
|
|
|
memclr(r, t.size)
|
2014-12-29 14:15:05 -07:00
|
|
|
return false
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2015-03-17 16:14:31 -06:00
|
|
|
if isDirectIface(t) {
|
2015-10-21 13:12:25 -06:00
|
|
|
writebarrierptr((*uintptr)(r), uintptr(e.data))
|
2015-03-17 16:14:31 -06:00
|
|
|
} else {
|
2015-10-21 13:12:25 -06:00
|
|
|
typedmemmove(t, r, e.data)
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2014-12-29 14:15:05 -07:00
|
|
|
return true
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
|
2015-10-21 13:12:25 -06:00
|
|
|
func convI2E(i iface) (r eface) {
|
|
|
|
tab := i.tab
|
2014-08-07 14:58:42 -06:00
|
|
|
if tab == nil {
|
|
|
|
return
|
|
|
|
}
|
2015-10-21 13:12:25 -06:00
|
|
|
r._type = tab._type
|
|
|
|
r.data = i.data
|
2014-08-07 14:58:42 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-10-21 13:12:25 -06:00
|
|
|
func assertI2E(inter *interfacetype, i iface, r *eface) {
|
|
|
|
tab := i.tab
|
2014-08-07 14:58:42 -06:00
|
|
|
if tab == nil {
|
|
|
|
// explicit conversions require non-nil interface value.
|
2016-02-16 20:23:14 -07:00
|
|
|
panic(&TypeAssertionError{"", "", inter.typ._string, ""})
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2015-10-21 13:12:25 -06:00
|
|
|
r._type = tab._type
|
|
|
|
r.data = i.data
|
2014-08-07 14:58:42 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-03-17 16:14:31 -06:00
|
|
|
// The compiler ensures that r is non-nil.
|
2015-10-21 13:12:25 -06:00
|
|
|
func assertI2E2(inter *interfacetype, i iface, r *eface) bool {
|
|
|
|
tab := i.tab
|
2014-08-07 14:58:42 -06:00
|
|
|
if tab == nil {
|
2014-12-29 14:15:05 -07:00
|
|
|
return false
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2015-10-21 13:12:25 -06:00
|
|
|
r._type = tab._type
|
|
|
|
r.data = i.data
|
2014-12-29 14:15:05 -07:00
|
|
|
return true
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
|
2015-10-21 13:12:25 -06:00
|
|
|
func convI2I(inter *interfacetype, i iface) (r iface) {
|
|
|
|
tab := i.tab
|
2014-08-07 14:58:42 -06:00
|
|
|
if tab == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if tab.inter == inter {
|
2015-10-21 13:12:25 -06:00
|
|
|
r.tab = tab
|
|
|
|
r.data = i.data
|
2014-08-07 14:58:42 -06:00
|
|
|
return
|
|
|
|
}
|
2015-10-21 13:12:25 -06:00
|
|
|
r.tab = getitab(inter, tab._type, false)
|
|
|
|
r.data = i.data
|
2014-08-07 14:58:42 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-10-21 13:12:25 -06:00
|
|
|
func assertI2I(inter *interfacetype, i iface, r *iface) {
|
|
|
|
tab := i.tab
|
2014-08-07 14:58:42 -06:00
|
|
|
if tab == nil {
|
|
|
|
// explicit conversions require non-nil interface value.
|
2016-02-16 20:23:14 -07:00
|
|
|
panic(&TypeAssertionError{"", "", inter.typ._string, ""})
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
if tab.inter == inter {
|
2015-10-21 13:12:25 -06:00
|
|
|
r.tab = tab
|
|
|
|
r.data = i.data
|
2014-08-07 14:58:42 -06:00
|
|
|
return
|
|
|
|
}
|
2015-10-21 13:12:25 -06:00
|
|
|
r.tab = getitab(inter, tab._type, false)
|
|
|
|
r.data = i.data
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
|
2015-10-21 13:12:25 -06:00
|
|
|
func assertI2I2(inter *interfacetype, i iface, r *iface) bool {
|
|
|
|
tab := i.tab
|
2014-08-07 14:58:42 -06:00
|
|
|
if tab == nil {
|
2014-12-29 14:15:05 -07:00
|
|
|
if r != nil {
|
2015-10-21 13:12:25 -06:00
|
|
|
*r = iface{}
|
2014-12-29 14:15:05 -07:00
|
|
|
}
|
|
|
|
return false
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2014-12-29 14:15:05 -07:00
|
|
|
if tab.inter != inter {
|
|
|
|
tab = getitab(inter, tab._type, true)
|
|
|
|
if tab == nil {
|
|
|
|
if r != nil {
|
2015-10-21 13:12:25 -06:00
|
|
|
*r = iface{}
|
2014-12-29 14:15:05 -07:00
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if r != nil {
|
2015-10-21 13:12:25 -06:00
|
|
|
r.tab = tab
|
|
|
|
r.data = i.data
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2014-12-29 14:15:05 -07:00
|
|
|
return true
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
|
2015-10-21 13:12:25 -06:00
|
|
|
func assertE2I(inter *interfacetype, e eface, r *iface) {
|
|
|
|
t := e._type
|
2014-08-07 14:58:42 -06:00
|
|
|
if t == nil {
|
|
|
|
// explicit conversions require non-nil interface value.
|
2016-02-16 20:23:14 -07:00
|
|
|
panic(&TypeAssertionError{"", "", inter.typ._string, ""})
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2015-10-21 13:12:25 -06:00
|
|
|
r.tab = getitab(inter, t, false)
|
|
|
|
r.data = e.data
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
|
2015-07-29 22:46:42 -06:00
|
|
|
var testingAssertE2I2GC bool
|
|
|
|
|
2015-10-21 13:12:25 -06:00
|
|
|
func assertE2I2(inter *interfacetype, e eface, r *iface) bool {
|
2015-07-29 22:46:42 -06:00
|
|
|
if testingAssertE2I2GC {
|
|
|
|
GC()
|
|
|
|
}
|
2015-10-21 13:12:25 -06:00
|
|
|
t := e._type
|
2014-08-07 14:58:42 -06:00
|
|
|
if t == nil {
|
2014-12-29 14:15:05 -07:00
|
|
|
if r != nil {
|
2015-10-21 13:12:25 -06:00
|
|
|
*r = iface{}
|
2014-12-29 14:15:05 -07:00
|
|
|
}
|
|
|
|
return false
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
tab := getitab(inter, t, true)
|
|
|
|
if tab == nil {
|
2014-12-29 14:15:05 -07:00
|
|
|
if r != nil {
|
2015-10-21 13:12:25 -06:00
|
|
|
*r = iface{}
|
2014-12-29 14:15:05 -07:00
|
|
|
}
|
|
|
|
return false
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2014-12-29 14:15:05 -07:00
|
|
|
if r != nil {
|
2015-10-21 13:12:25 -06:00
|
|
|
r.tab = tab
|
|
|
|
r.data = e.data
|
2014-12-29 14:15:05 -07:00
|
|
|
}
|
|
|
|
return true
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
|
2014-12-22 11:27:53 -07:00
|
|
|
//go:linkname reflect_ifaceE2I reflect.ifaceE2I
|
2015-10-21 13:12:25 -06:00
|
|
|
func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) {
|
2014-12-29 14:15:05 -07:00
|
|
|
assertE2I(inter, e, dst)
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
|
2015-10-21 13:12:25 -06:00
|
|
|
func assertE2E(inter *interfacetype, e eface, r *eface) {
|
|
|
|
if e._type == nil {
|
2014-08-07 14:58:42 -06:00
|
|
|
// explicit conversions require non-nil interface value.
|
2016-02-16 20:23:14 -07:00
|
|
|
panic(&TypeAssertionError{"", "", inter.typ._string, ""})
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2014-12-29 14:15:05 -07:00
|
|
|
*r = e
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
|
2015-03-17 16:14:31 -06:00
|
|
|
// The compiler ensures that r is non-nil.
|
2015-10-21 13:12:25 -06:00
|
|
|
func assertE2E2(inter *interfacetype, e eface, r *eface) bool {
|
|
|
|
if e._type == nil {
|
|
|
|
*r = eface{}
|
2014-12-29 14:15:05 -07:00
|
|
|
return false
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
2015-03-17 16:14:31 -06:00
|
|
|
*r = e
|
2014-12-29 14:15:05 -07:00
|
|
|
return true
|
2014-08-07 14:58:42 -06:00
|
|
|
}
|
|
|
|
|
2014-08-28 08:36:48 -06:00
|
|
|
func iterate_itabs(fn func(*itab)) {
|
2014-08-28 09:45:30 -06:00
|
|
|
for _, h := range &hash {
|
2014-08-28 08:36:48 -06:00
|
|
|
for ; h != nil; h = h.link {
|
|
|
|
fn(h)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|