mirror of
https://github.com/golang/go
synced 2024-11-19 07:04:43 -07:00
cmd/internal/gc, runtime: speed up some cases of _, ok := i.(T)
Some type assertions of the form _, ok := i.(T) allow efficient inlining. Such type assertions commonly show up in type switches. For example, with this optimization, using 6g, the length of encoding/binary's intDataSize function shrinks from 2224 to 1728 bytes (-22%). benchmark old ns/op new ns/op delta BenchmarkAssertI2E2Blank 4.67 0.82 -82.44% BenchmarkAssertE2T2Blank 4.38 0.83 -81.05% BenchmarkAssertE2E2Blank 3.88 0.83 -78.61% BenchmarkAssertE2E2 14.2 14.4 +1.41% BenchmarkAssertE2T2 10.3 10.4 +0.97% BenchmarkAssertI2E2 13.4 13.3 -0.75% Change-Id: Ie9798c3e85432bb8e0f2c723afc376e233639df7 Reviewed-on: https://go-review.googlesource.com/7697 Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
55b4516fd6
commit
25e793d7ea
@ -869,6 +869,32 @@ func walkexpr(np **Node, init **NodeList) {
|
|||||||
oktype = ok.Type
|
oktype = ok.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fromKind := type2IET(from.Type)
|
||||||
|
toKind := type2IET(t)
|
||||||
|
|
||||||
|
// Avoid runtime calls in a few cases of the form _, ok := i.(T).
|
||||||
|
// This is faster and shorter and allows the corresponding assertX2X2
|
||||||
|
// routines to skip nil checks on their last argument.
|
||||||
|
if isblank(n.List.N) {
|
||||||
|
var fast *Node
|
||||||
|
switch {
|
||||||
|
case fromKind == "E" && toKind == "T":
|
||||||
|
tab := Nod(OITAB, from, nil) // type:eface::tab:iface
|
||||||
|
typ := Nod(OCONVNOP, typename(t), nil)
|
||||||
|
typ.Type = Ptrto(Types[TUINTPTR])
|
||||||
|
fast = Nod(OEQ, tab, typ)
|
||||||
|
case fromKind == "I" && toKind == "E",
|
||||||
|
fromKind == "E" && toKind == "E":
|
||||||
|
tab := Nod(OITAB, from, nil)
|
||||||
|
fast = Nod(ONE, tab, nodnil())
|
||||||
|
}
|
||||||
|
if fast != nil {
|
||||||
|
n = Nod(OAS, ok, fast)
|
||||||
|
typecheck(&n, Etop)
|
||||||
|
goto ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var resptr *Node // &res
|
var resptr *Node // &res
|
||||||
if isblank(n.List.N) {
|
if isblank(n.List.N) {
|
||||||
resptr = nodnil()
|
resptr = nodnil()
|
||||||
@ -877,7 +903,7 @@ func walkexpr(np **Node, init **NodeList) {
|
|||||||
}
|
}
|
||||||
resptr.Etype = 1 // addr does not escape
|
resptr.Etype = 1 // addr does not escape
|
||||||
|
|
||||||
buf := "assert" + type2IET(from.Type) + "2" + type2IET(t) + "2"
|
buf := "assert" + fromKind + "2" + toKind + "2"
|
||||||
fn := syslook(buf, 1)
|
fn := syslook(buf, 1)
|
||||||
substArgTypes(fn, from.Type, t)
|
substArgTypes(fn, from.Type, t)
|
||||||
call := mkcall1(fn, oktype, init, typename(t), from, resptr)
|
call := mkcall1(fn, oktype, init, typename(t), from, resptr)
|
||||||
|
@ -219,20 +219,17 @@ func assertE2T(t *_type, e interface{}, r unsafe.Pointer) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The compiler ensures that r is non-nil.
|
||||||
func assertE2T2(t *_type, e interface{}, r unsafe.Pointer) bool {
|
func assertE2T2(t *_type, e interface{}, r unsafe.Pointer) bool {
|
||||||
ep := (*eface)(unsafe.Pointer(&e))
|
ep := (*eface)(unsafe.Pointer(&e))
|
||||||
if ep._type != t {
|
if ep._type != t {
|
||||||
if r != nil {
|
memclr(r, uintptr(t.size))
|
||||||
memclr(r, uintptr(t.size))
|
|
||||||
}
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if r != nil {
|
if isDirectIface(t) {
|
||||||
if isDirectIface(t) {
|
writebarrierptr((*uintptr)(r), uintptr(ep.data))
|
||||||
writebarrierptr((*uintptr)(r), uintptr(ep.data))
|
} else {
|
||||||
} else {
|
typedmemmove(t, r, ep.data)
|
||||||
typedmemmove(t, r, ep.data)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -262,17 +259,16 @@ func assertI2E(inter *interfacetype, i fInterface, r *interface{}) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The compiler ensures that r is non-nil.
|
||||||
func assertI2E2(inter *interfacetype, i fInterface, r *interface{}) bool {
|
func assertI2E2(inter *interfacetype, i fInterface, r *interface{}) bool {
|
||||||
ip := (*iface)(unsafe.Pointer(&i))
|
ip := (*iface)(unsafe.Pointer(&i))
|
||||||
tab := ip.tab
|
tab := ip.tab
|
||||||
if tab == nil {
|
if tab == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if r != nil {
|
rp := (*eface)(unsafe.Pointer(r))
|
||||||
rp := (*eface)(unsafe.Pointer(r))
|
rp._type = tab._type
|
||||||
rp._type = tab._type
|
rp.data = ip.data
|
||||||
rp.data = ip.data
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,17 +382,14 @@ func assertE2E(inter *interfacetype, e interface{}, r *interface{}) {
|
|||||||
*r = e
|
*r = e
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The compiler ensures that r is non-nil.
|
||||||
func assertE2E2(inter *interfacetype, e interface{}, r *interface{}) bool {
|
func assertE2E2(inter *interfacetype, e interface{}, r *interface{}) bool {
|
||||||
ep := (*eface)(unsafe.Pointer(&e))
|
ep := (*eface)(unsafe.Pointer(&e))
|
||||||
if ep._type == nil {
|
if ep._type == nil {
|
||||||
if r != nil {
|
*r = nil
|
||||||
*r = nil
|
|
||||||
}
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if r != nil {
|
*r = e
|
||||||
*r = e
|
|
||||||
}
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ var (
|
|||||||
ts TS
|
ts TS
|
||||||
tm TM
|
tm TM
|
||||||
tl TL
|
tl TL
|
||||||
|
ok bool
|
||||||
)
|
)
|
||||||
|
|
||||||
// Issue 9370
|
// Issue 9370
|
||||||
@ -178,3 +179,45 @@ func BenchmarkAssertE2E(b *testing.B) {
|
|||||||
e_ = e
|
e_ = e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkAssertE2T2(b *testing.B) {
|
||||||
|
e = tm
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
tm, ok = e.(TM)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAssertE2T2Blank(b *testing.B) {
|
||||||
|
e = tm
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, ok = e.(TM)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAssertI2E2(b *testing.B) {
|
||||||
|
i1 = tm
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
e, ok = i1.(interface{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAssertI2E2Blank(b *testing.B) {
|
||||||
|
i1 = tm
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, ok = i1.(interface{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAssertE2E2(b *testing.B) {
|
||||||
|
e = tm
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
e_, ok = e.(interface{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkAssertE2E2Blank(b *testing.B) {
|
||||||
|
e = tm
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_, ok = e.(interface{})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user