cmd/internal/gc: inline x := y.(*T) and x, ok := y.(*T)
These can be implemented with just a compare and a move instruction.
Do so, avoiding the overhead of a call into the runtime.
These assertions are a significant cost in Go code that uses interface{}
as a safe alternative to C's void* (or unsafe.Pointer), such as the
current version of the Go compiler.
*T here includes pointer to T but also any Go type represented as
a single pointer (chan, func, map). It does not include [1]*T or struct{*int}.
That requires more work in other parts of the compiler; there is a TODO.
Change-Id: I7ff681c20d2c3eb6ad11dd7b3a37b1f3dda23965
Reviewed-on: https://go-review.googlesource.com/7862
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/src/cmd/internal/gc/walk.go b/src/cmd/internal/gc/walk.go
index 2784648..c6ad507 100644
--- a/src/cmd/internal/gc/walk.go
+++ b/src/cmd/internal/gc/walk.go
@@ -670,14 +670,27 @@
default:
walkexpr(&n.Right, init)
- // x = i.(T); n->left is x, n->right->left is i.
- // orderstmt made sure x is addressable.
case ODOTTYPE:
+ // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
+ // It needs to be removed in all three places.
+ // That would allow inlining x.(struct{*int}) the same as x.(*int).
+ if isdirectiface(n.Right.Type) && !Isfat(n.Right.Type) && flag_race == 0 {
+ // handled directly during cgen
+ walkexpr(&n.Right, init)
+ break
+ }
+
+ // x = i.(T); n->left is x, n->right->left is i.
+ // orderstmt made sure x is addressable.
walkexpr(&n.Right.Left, init)
n1 := Nod(OADDR, n.Left, nil)
r := n.Right // i.(T)
+ if Debug_typeassert > 0 {
+ Warn("type assertion not inlined")
+ }
+
buf := "assert" + type2IET(r.Left.Type) + "2" + type2IET(r.Type)
fn := syslook(buf, 1)
substArgTypes(fn, r.Left.Type, r.Type)
@@ -686,9 +699,9 @@
walkexpr(&n, init)
goto ret
- // x = <-c; n->left is x, n->right->left is c.
- // orderstmt made sure x is addressable.
case ORECV:
+ // x = <-c; n->left is x, n->right->left is c.
+ // orderstmt made sure x is addressable.
walkexpr(&n.Right.Left, init)
n1 := Nod(OADDR, n.Left, nil)
@@ -851,13 +864,23 @@
n = mkcall1(mapfndel("mapdelete", t), nil, init, typename(t), map_, key)
goto ret
- // res, ok = i.(T)
- // orderstmt made sure a is addressable.
case OAS2DOTTYPE:
+ e := n.Rlist.N // i.(T)
+ // TODO(rsc): The Isfat is for consistency with componentgen and orderexpr.
+ // It needs to be removed in all three places.
+ // That would allow inlining x.(struct{*int}) the same as x.(*int).
+ if isdirectiface(e.Type) && !Isfat(e.Type) && flag_race == 0 {
+ // handled directly during gen.
+ walkexprlistsafe(n.List, init)
+ walkexpr(&e.Left, init)
+ goto ret
+ }
+
+ // res, ok = i.(T)
+ // orderstmt made sure a is addressable.
*init = concat(*init, n.Ninit)
n.Ninit = nil
- e := n.Rlist.N // i.(T)
walkexprlistsafe(n.List, init)
walkexpr(&e.Left, init)
t := e.Type // T
@@ -889,6 +912,9 @@
fast = Nod(ONE, nodnil(), tab)
}
if fast != nil {
+ if Debug_typeassert > 0 {
+ Warn("type assertion (ok only) inlined")
+ }
n = Nod(OAS, ok, fast)
typecheck(&n, Etop)
goto ret
@@ -903,6 +929,9 @@
}
resptr.Etype = 1 // addr does not escape
+ if Debug_typeassert > 0 {
+ Warn("type assertion not inlined")
+ }
buf := "assert" + fromKind + "2" + toKind + "2"
fn := syslook(buf, 1)
substArgTypes(fn, from.Type, t)
@@ -911,9 +940,12 @@
typecheck(&n, Etop)
goto ret
- case ODOTTYPE,
- ODOTTYPE2:
- Fatal("walkexpr ODOTTYPE") // should see inside OAS or OAS2 only
+ case ODOTTYPE, ODOTTYPE2:
+ if !isdirectiface(n.Type) || Isfat(n.Type) {
+ Fatal("walkexpr ODOTTYPE") // should see inside OAS only
+ }
+ walkexpr(&n.Left, init)
+ goto ret
case OCONVIFACE:
walkexpr(&n.Left, init)