Commit 562d06fc authored by Josh Bleecher Snyder's avatar Josh Bleecher Snyder

cmd/compile: inline _, ok = i.(T)

We already inlined

_, ok = e.(T)
_, ok = i.(E)
_, ok = e.(E)

The only ok-only variants not inlined are now

_, ok = i.(I)
_, ok = e.(I)

These call getitab, so are non-trivial.

Change-Id: Ie45fd8933ee179a679b92ce925079b94cff0ee12
Reviewed-on: https://go-review.googlesource.com/26658
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarKeith Randall <khr@golang.org>
parent e6e26eeb
...@@ -2317,6 +2317,16 @@ func isdirectiface(t *Type) bool { ...@@ -2317,6 +2317,16 @@ func isdirectiface(t *Type) bool {
return false return false
} }
// itabType loads the _type field from a runtime.itab struct.
func itabType(itab *Node) *Node {
typ := NodSym(ODOTPTR, itab, nil)
typ.Type = Ptrto(Types[TUINT8])
typ.Typecheck = 1
typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab
typ.Bounded = true // guaranteed not to fault
return typ
}
// iet returns 'T' if t is a concrete type, // iet returns 'T' if t is a concrete type,
// 'I' if t is an interface type, and 'E' if t is an empty interface type. // 'I' if t is an interface type, and 'E' if t is an empty interface type.
// It is used to build calls to the conv* and assert* runtime routines. // It is used to build calls to the conv* and assert* runtime routines.
......
...@@ -589,11 +589,7 @@ func (s *typeSwitch) walk(sw *Node) { ...@@ -589,11 +589,7 @@ func (s *typeSwitch) walk(sw *Node) {
if !cond.Right.Type.IsEmptyInterface() { if !cond.Right.Type.IsEmptyInterface() {
// Load type from itab. // Load type from itab.
typ = NodSym(ODOTPTR, typ, nil) typ = itabType(typ)
typ.Type = Ptrto(Types[TUINT8])
typ.Typecheck = 1
typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab
typ.Bounded = true // guaranteed not to fault
} }
// Load hash from type. // Load hash from type.
h := NodSym(ODOTPTR, typ, nil) h := NodSym(ODOTPTR, typ, nil)
......
...@@ -960,19 +960,27 @@ opswitch: ...@@ -960,19 +960,27 @@ opswitch:
fromKind := from.Type.iet() fromKind := from.Type.iet()
toKind := t.iet() toKind := t.iet()
res := n.List.First()
// Avoid runtime calls in a few cases of the form _, ok := i.(T). // Avoid runtime calls in a few cases of the form _, ok := i.(T).
// This is faster and shorter and allows the corresponding assertX2X2 // This is faster and shorter and allows the corresponding assertX2X2
// routines to skip nil checks on their last argument. // routines to skip nil checks on their last argument.
if isblank(n.List.First()) { if isblank(res) {
var fast *Node var fast *Node
switch { switch toKind {
case fromKind == 'E' && toKind == 'T': case 'T':
tab := Nod(OITAB, from, nil) // type:eface::tab:iface tab := Nod(OITAB, from, nil)
typ := Nod(OCONVNOP, typename(t), nil) if fromKind == 'E' {
typ.Type = Ptrto(Types[TUINTPTR]) typ := Nod(OCONVNOP, typename(t), nil)
fast = Nod(OEQ, tab, typ) typ.Type = Ptrto(Types[TUINTPTR])
case fromKind == 'I' && toKind == 'E', fast = Nod(OEQ, tab, typ)
fromKind == 'E' && toKind == 'E': break
}
fast = Nod(OANDAND,
Nod(ONE, nodnil(), tab),
Nod(OEQ, itabType(tab), typename(t)),
)
case 'E':
tab := Nod(OITAB, from, nil) tab := Nod(OITAB, from, nil)
fast = Nod(ONE, nodnil(), tab) fast = Nod(ONE, nodnil(), tab)
} }
...@@ -987,10 +995,10 @@ opswitch: ...@@ -987,10 +995,10 @@ opswitch:
} }
var resptr *Node // &res var resptr *Node // &res
if isblank(n.List.First()) { if isblank(res) {
resptr = nodnil() resptr = nodnil()
} else { } else {
resptr = Nod(OADDR, n.List.First(), nil) resptr = Nod(OADDR, res, nil)
} }
resptr.Etype = 1 // addr does not escape resptr.Etype = 1 // addr does not escape
......
...@@ -218,20 +218,17 @@ func assertI2T(t *_type, i iface, r unsafe.Pointer) { ...@@ -218,20 +218,17 @@ func assertI2T(t *_type, i iface, r unsafe.Pointer) {
} }
} }
// The compiler ensures that r is non-nil.
func assertI2T2(t *_type, i iface, r unsafe.Pointer) bool { func assertI2T2(t *_type, i iface, r unsafe.Pointer) bool {
tab := i.tab tab := i.tab
if tab == nil || tab._type != t { if tab == nil || tab._type != t {
if r != nil { memclr(r, t.size)
memclr(r, t.size)
}
return false return false
} }
if r != nil { if isDirectIface(t) {
if isDirectIface(t) { writebarrierptr((*uintptr)(r), uintptr(i.data))
writebarrierptr((*uintptr)(r), uintptr(i.data)) } else {
} else { typedmemmove(t, r, i.data)
typedmemmove(t, r, i.data)
}
} }
return true return true
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment