-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cmd/compile: de-virtualize interface calls
With this change, code like h := sha1.New() h.Write(buf) sum := h.Sum() gets compiled into static calls rather than interface calls, because the compiler is able to prove that 'h' is really a *sha1.digest. The InterCall re-write rule hits a few dozen times during make.bash, and hundreds of times during all.bash. The most common pattern identified by the compiler is a constructor like func New() Interface { return &impl{...} } where the constructor gets inlined into the caller, and the result is used immediately. Examples include {sha1,md5,crc32,crc64,...}.New, base64.NewEncoder, base64.NewDecoder, errors.New, net.Pipe, and so on. Some existing benchmarks that change on darwin/amd64: Crc64/ISO4KB-8 2.67µs ± 1% 2.66µs ± 0% -0.36% (p=0.015 n=10+10) Crc64/ISO1KB-8 694ns ± 0% 690ns ± 1% -0.59% (p=0.001 n=10+10) Adler32KB-8 473ns ± 1% 471ns ± 0% -0.39% (p=0.010 n=10+9) On architectures like amd64, the reduction in code size appears to contribute more to benchmark improvements than just removing the indirect call, since that branch gets predicted accurately when called in a loop. Updates golang#19361 Change-Id: Ia9d30afdd5f6b4d38d38b14b88f308acae8ce7ed
- Loading branch information
Showing
10 changed files
with
259 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// errorcheck -0 -d=ssa/opt/debug=3 | ||
|
||
package main | ||
|
||
import ( | ||
"crypto/sha1" | ||
"errors" | ||
"fmt" | ||
"sync" | ||
) | ||
|
||
func f0() { | ||
v := errors.New("error string") | ||
_ = v.Error() // ERROR "de-virtualizing call$" | ||
} | ||
|
||
func f1() { | ||
h := sha1.New() | ||
buf := make([]byte, 4) | ||
h.Write(buf) // ERROR "de-virtualizing call$" | ||
_ = h.Sum(nil) // ERROR "de-virtualizing call$" | ||
} | ||
|
||
func f2() { | ||
// trickier case: make sure we see this is *sync.rlocker | ||
// instead of *sync.RWMutex, | ||
// even though they are the same pointers | ||
var m sync.RWMutex | ||
r := m.RLocker() | ||
|
||
// deadlock if the type of 'r' is improperly interpreted | ||
// as *sync.RWMutex | ||
r.Lock() // ERROR "de-virtualizing call$" | ||
m.RLock() | ||
r.Unlock() // ERROR "de-virtualizing call$" | ||
m.RUnlock() | ||
} | ||
|
||
type multiword struct{ a, b, c int } | ||
|
||
func (m multiword) Error() string { return fmt.Sprintf("%d, %d, %d", m.a, m.b, m.c) } | ||
|
||
func f3() { | ||
// can't de-virtualize this one yet; | ||
// it passes through a call to iconvT2I | ||
var err error | ||
err = multiword{1, 2, 3} | ||
if err.Error() != "1, 2, 3" { | ||
panic("bad call") | ||
} | ||
|
||
// ... but we can do this one | ||
err = &multiword{1, 2, 3} | ||
if err.Error() != "1, 2, 3" { // ERROR "de-virtualizing call$" | ||
panic("bad call") | ||
} | ||
} | ||
|
||
func main() { | ||
f0() | ||
f1() | ||
f2() | ||
f3() | ||
} |