2016-09-08 21:39:33 -07:00
|
|
|
// Copyright 2016 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.
|
|
|
|
|
|
|
|
|
|
// This file implements TestFormats; a test that verifies
|
|
|
|
|
// format strings in the compiler (this directory and all
|
|
|
|
|
// subdirectories, recursively).
|
|
|
|
|
//
|
|
|
|
|
// TestFormats finds potential (Printf, etc.) format strings.
|
|
|
|
|
// If they are used in a call, the format verbs are verified
|
|
|
|
|
// based on the matching argument type against a precomputed
|
|
|
|
|
// table of valid formats. The knownFormats table can be used
|
|
|
|
|
// to automatically rewrite format strings with the -u flag.
|
|
|
|
|
//
|
|
|
|
|
// A new knownFormats table based on the found formats is printed
|
|
|
|
|
// when the test is run in verbose mode (-v flag). The table
|
|
|
|
|
// needs to be updated whenever a new (type, format) combination
|
2016-09-09 21:08:46 -07:00
|
|
|
// is found and the format verb is not 'v' or 'T' (as in "%v" or
|
|
|
|
|
// "%T").
|
2016-09-08 21:39:33 -07:00
|
|
|
//
|
|
|
|
|
// Run as: go test -run Formats [-u][-v]
|
|
|
|
|
//
|
|
|
|
|
// Known bugs:
|
|
|
|
|
// - indexed format strings ("%[2]s", etc.) are not supported
|
|
|
|
|
// (the test will fail)
|
|
|
|
|
// - format strings that are not simple string literals cannot
|
|
|
|
|
// be updated automatically
|
|
|
|
|
// (the test will fail with respective warnings)
|
|
|
|
|
// - format strings in _test packages outside the current
|
|
|
|
|
// package are not processed
|
|
|
|
|
// (the test will report those files)
|
|
|
|
|
//
|
|
|
|
|
package main_test
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"flag"
|
|
|
|
|
"fmt"
|
|
|
|
|
"go/ast"
|
|
|
|
|
"go/build"
|
|
|
|
|
"go/constant"
|
|
|
|
|
"go/format"
|
|
|
|
|
"go/importer"
|
|
|
|
|
"go/parser"
|
|
|
|
|
"go/token"
|
|
|
|
|
"go/types"
|
|
|
|
|
"internal/testenv"
|
|
|
|
|
"io/ioutil"
|
|
|
|
|
"log"
|
|
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"sort"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
"testing"
|
|
|
|
|
"unicode/utf8"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var update = flag.Bool("u", false, "update format strings")
|
|
|
|
|
|
|
|
|
|
// The following variables collect information across all processed files.
|
|
|
|
|
var (
|
|
|
|
|
fset = token.NewFileSet()
|
|
|
|
|
formatStrings = make(map[*ast.BasicLit]bool) // set of all potential format strings found
|
|
|
|
|
foundFormats = make(map[string]bool) // set of all formats found
|
2016-09-09 19:54:09 -07:00
|
|
|
callSites = make(map[*ast.CallExpr]*callSite) // map of all calls
|
2016-09-08 21:39:33 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// A File is a corresponding (filename, ast) pair.
|
|
|
|
|
type File struct {
|
|
|
|
|
name string
|
|
|
|
|
ast *ast.File
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestFormats(t *testing.T) {
|
|
|
|
|
testenv.MustHaveGoBuild(t) // more restrictive than necessary, but that's ok
|
|
|
|
|
|
|
|
|
|
// process all directories
|
|
|
|
|
filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
|
|
|
|
|
if info.IsDir() {
|
|
|
|
|
if info.Name() == "testdata" {
|
|
|
|
|
return filepath.SkipDir
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
importPath := filepath.Join("cmd/compile", path)
|
2016-09-09 19:54:09 -07:00
|
|
|
if blacklistedPackages[filepath.ToSlash(importPath)] {
|
|
|
|
|
return filepath.SkipDir
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-08 21:39:33 -07:00
|
|
|
pkg, err := build.Import(importPath, path, 0)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if _, ok := err.(*build.NoGoError); ok {
|
|
|
|
|
return nil // nothing to do here
|
|
|
|
|
}
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
collectPkgFormats(t, pkg)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// test and rewrite formats
|
|
|
|
|
updatedFiles := make(map[string]File) // files that were rewritten
|
|
|
|
|
for _, p := range callSites {
|
|
|
|
|
// test current format literal and determine updated one
|
|
|
|
|
out := formatReplace(p.str, func(index int, in string) string {
|
|
|
|
|
if in == "*" {
|
|
|
|
|
return in // cannot rewrite '*' (as in "%*d")
|
|
|
|
|
}
|
|
|
|
|
// in != '*'
|
|
|
|
|
typ := p.types[index]
|
|
|
|
|
format := typ + " " + in // e.g., "*Node %n"
|
|
|
|
|
|
|
|
|
|
// check if format is known
|
|
|
|
|
out, known := knownFormats[format]
|
|
|
|
|
|
|
|
|
|
// record format if not yet found
|
|
|
|
|
_, found := foundFormats[format]
|
|
|
|
|
if !found {
|
|
|
|
|
foundFormats[format] = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// report an error if the format is unknown and this is the first
|
2016-09-09 21:08:46 -07:00
|
|
|
// time we see it; ignore "%v" and "%T" which are always valid
|
|
|
|
|
if !known && !found && in != "%v" && in != "%T" {
|
2016-09-08 21:39:33 -07:00
|
|
|
t.Errorf("%s: unknown format %q for %s argument", posString(p.arg), in, typ)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if out == "" {
|
|
|
|
|
out = in
|
|
|
|
|
}
|
|
|
|
|
return out
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// replace existing format literal if it changed
|
|
|
|
|
if out != p.str {
|
|
|
|
|
// we cannot replace the argument if it's not a string literal for now
|
|
|
|
|
// (e.g., it may be "foo" + "bar")
|
|
|
|
|
lit, ok := p.arg.(*ast.BasicLit)
|
|
|
|
|
if !ok {
|
|
|
|
|
delete(callSites, p.call) // treat as if we hadn't found this site
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if testing.Verbose() {
|
|
|
|
|
fmt.Printf("%s:\n\t- %q\n\t+ %q\n", posString(p.arg), p.str, out)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// find argument index of format argument
|
|
|
|
|
index := -1
|
|
|
|
|
for i, arg := range p.call.Args {
|
|
|
|
|
if p.arg == arg {
|
|
|
|
|
index = i
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if index < 0 {
|
|
|
|
|
// we may have processed the same call site twice,
|
|
|
|
|
// but that shouldn't happen
|
|
|
|
|
panic("internal error: matching argument not found")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// replace literal
|
|
|
|
|
new := *lit // make a copy
|
|
|
|
|
new.Value = strconv.Quote(out) // this may introduce "-quotes where there were `-quotes
|
|
|
|
|
p.call.Args[index] = &new
|
|
|
|
|
updatedFiles[p.file.name] = p.file
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// write dirty files back
|
|
|
|
|
var filesUpdated bool
|
|
|
|
|
if len(updatedFiles) > 0 && *update {
|
|
|
|
|
for _, file := range updatedFiles {
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
if err := format.Node(&buf, fset, file.ast); err != nil {
|
|
|
|
|
t.Errorf("WARNING: formatting %s failed: %v", file.name, err)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if err := ioutil.WriteFile(file.name, buf.Bytes(), 0x666); err != nil {
|
|
|
|
|
t.Errorf("WARNING: writing %s failed: %v", file.name, err)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
fmt.Printf("updated %s\n", file.name)
|
|
|
|
|
filesUpdated = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// report all function names containing a format string
|
|
|
|
|
if len(callSites) > 0 && testing.Verbose() {
|
|
|
|
|
set := make(map[string]bool)
|
|
|
|
|
for _, p := range callSites {
|
|
|
|
|
set[nodeString(p.call.Fun)] = true
|
|
|
|
|
}
|
|
|
|
|
var list []string
|
|
|
|
|
for s := range set {
|
|
|
|
|
list = append(list, s)
|
|
|
|
|
}
|
|
|
|
|
fmt.Println("\nFunctions")
|
|
|
|
|
printList(list)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// report all formats found
|
|
|
|
|
if len(foundFormats) > 0 && testing.Verbose() {
|
|
|
|
|
var list []string
|
|
|
|
|
for s := range foundFormats {
|
|
|
|
|
list = append(list, fmt.Sprintf("%q: \"\",", s))
|
|
|
|
|
}
|
|
|
|
|
fmt.Println("\nvar knownFormats = map[string]string{")
|
|
|
|
|
printList(list)
|
|
|
|
|
fmt.Println("}")
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-08 16:10:26 -08:00
|
|
|
// check that knownFormats is up to date
|
|
|
|
|
if !testing.Verbose() && !*update {
|
|
|
|
|
var mismatch bool
|
|
|
|
|
for s := range foundFormats {
|
|
|
|
|
if _, ok := knownFormats[s]; !ok {
|
|
|
|
|
mismatch = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if !mismatch {
|
|
|
|
|
for s := range knownFormats {
|
|
|
|
|
if _, ok := foundFormats[s]; !ok {
|
|
|
|
|
mismatch = true
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if mismatch {
|
|
|
|
|
t.Errorf("knownFormats is out of date; please run with -v to regenerate")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-08 21:39:33 -07:00
|
|
|
// all format strings of calls must be in the formatStrings set (self-verification)
|
|
|
|
|
for _, p := range callSites {
|
|
|
|
|
if lit, ok := p.arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
|
|
|
|
|
if formatStrings[lit] {
|
|
|
|
|
// ok
|
|
|
|
|
delete(formatStrings, lit)
|
|
|
|
|
} else {
|
|
|
|
|
// this should never happen
|
|
|
|
|
panic(fmt.Sprintf("internal error: format string not found (%s)", posString(lit)))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if we have any strings left, we may need to update them manually
|
|
|
|
|
if len(formatStrings) > 0 && filesUpdated {
|
|
|
|
|
var list []string
|
|
|
|
|
for lit := range formatStrings {
|
|
|
|
|
list = append(list, fmt.Sprintf("%s: %s", posString(lit), nodeString(lit)))
|
|
|
|
|
}
|
|
|
|
|
fmt.Println("\nWARNING: Potentially missed format strings")
|
|
|
|
|
printList(list)
|
|
|
|
|
t.Fail()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fmt.Println()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A callSite describes a function call that appears to contain
|
|
|
|
|
// a format string.
|
|
|
|
|
type callSite struct {
|
|
|
|
|
file File
|
|
|
|
|
call *ast.CallExpr // call containing the format string
|
|
|
|
|
arg ast.Expr // format argument (string literal or constant)
|
|
|
|
|
str string // unquoted format string
|
|
|
|
|
types []string // argument types
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func collectPkgFormats(t *testing.T, pkg *build.Package) {
|
|
|
|
|
// collect all files
|
|
|
|
|
var filenames []string
|
|
|
|
|
filenames = append(filenames, pkg.GoFiles...)
|
|
|
|
|
filenames = append(filenames, pkg.CgoFiles...)
|
|
|
|
|
filenames = append(filenames, pkg.TestGoFiles...)
|
|
|
|
|
|
|
|
|
|
// TODO(gri) verify _test files outside package
|
|
|
|
|
for _, name := range pkg.XTestGoFiles {
|
|
|
|
|
// don't process this test itself
|
|
|
|
|
if name != "fmt_test.go" && testing.Verbose() {
|
|
|
|
|
fmt.Printf("WARNING: %s not processed\n", filepath.Join(pkg.Dir, name))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// make filenames relative to .
|
|
|
|
|
for i, name := range filenames {
|
|
|
|
|
filenames[i] = filepath.Join(pkg.Dir, name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// parse all files
|
|
|
|
|
files := make([]*ast.File, len(filenames))
|
|
|
|
|
for i, filename := range filenames {
|
|
|
|
|
f, err := parser.ParseFile(fset, filename, nil, parser.ParseComments)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
files[i] = f
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// typecheck package
|
|
|
|
|
conf := types.Config{Importer: importer.Default()}
|
|
|
|
|
etypes := make(map[ast.Expr]types.TypeAndValue)
|
|
|
|
|
if _, err := conf.Check(pkg.ImportPath, fset, files, &types.Info{Types: etypes}); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// collect all potential format strings (for extra verification later)
|
|
|
|
|
for _, file := range files {
|
|
|
|
|
ast.Inspect(file, func(n ast.Node) bool {
|
|
|
|
|
if s, ok := stringLit(n); ok && isFormat(s) {
|
|
|
|
|
formatStrings[n.(*ast.BasicLit)] = true
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// collect all formats/arguments of calls with format strings
|
|
|
|
|
for index, file := range files {
|
|
|
|
|
ast.Inspect(file, func(n ast.Node) bool {
|
|
|
|
|
if call, ok := n.(*ast.CallExpr); ok {
|
|
|
|
|
// ignore blacklisted functions
|
2016-09-09 19:54:09 -07:00
|
|
|
if blacklistedFunctions[nodeString(call.Fun)] {
|
2016-09-08 21:39:33 -07:00
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
// look for an arguments that might be a format string
|
|
|
|
|
for i, arg := range call.Args {
|
|
|
|
|
if s, ok := stringVal(etypes[arg]); ok && isFormat(s) {
|
|
|
|
|
// make sure we have enough arguments
|
|
|
|
|
n := numFormatArgs(s)
|
|
|
|
|
if i+1+n > len(call.Args) {
|
|
|
|
|
t.Errorf("%s: not enough format args (blacklist %s?)", posString(call), nodeString(call.Fun))
|
|
|
|
|
break // ignore this call
|
|
|
|
|
}
|
|
|
|
|
// assume last n arguments are to be formatted;
|
|
|
|
|
// determine their types
|
|
|
|
|
argTypes := make([]string, n)
|
|
|
|
|
for i, arg := range call.Args[len(call.Args)-n:] {
|
|
|
|
|
if tv, ok := etypes[arg]; ok {
|
|
|
|
|
argTypes[i] = typeString(tv.Type)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// collect call site
|
|
|
|
|
if callSites[call] != nil {
|
|
|
|
|
panic("internal error: file processed twice?")
|
|
|
|
|
}
|
|
|
|
|
callSites[call] = &callSite{
|
|
|
|
|
file: File{filenames[index], file},
|
|
|
|
|
call: call,
|
|
|
|
|
arg: arg,
|
|
|
|
|
str: s,
|
|
|
|
|
types: argTypes,
|
|
|
|
|
}
|
|
|
|
|
break // at most one format per argument list
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// printList prints list in sorted order.
|
|
|
|
|
func printList(list []string) {
|
|
|
|
|
sort.Strings(list)
|
|
|
|
|
for _, s := range list {
|
|
|
|
|
fmt.Println("\t", s)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// posString returns a string representation of n's position
|
|
|
|
|
// in the form filename:line:col: .
|
|
|
|
|
func posString(n ast.Node) string {
|
|
|
|
|
if n == nil {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
return fset.Position(n.Pos()).String()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// nodeString returns a string representation of n.
|
|
|
|
|
func nodeString(n ast.Node) string {
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
if err := format.Node(&buf, fset, n); err != nil {
|
|
|
|
|
log.Fatal(err) // should always succeed
|
|
|
|
|
}
|
|
|
|
|
return buf.String()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// typeString returns a string representation of n.
|
|
|
|
|
func typeString(typ types.Type) string {
|
2016-09-09 19:54:09 -07:00
|
|
|
return filepath.ToSlash(typ.String())
|
2016-09-08 21:39:33 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// stringLit returns the unquoted string value and true if
|
|
|
|
|
// n represents a string literal; otherwise it returns ""
|
|
|
|
|
// and false.
|
|
|
|
|
func stringLit(n ast.Node) (string, bool) {
|
|
|
|
|
if lit, ok := n.(*ast.BasicLit); ok && lit.Kind == token.STRING {
|
|
|
|
|
s, err := strconv.Unquote(lit.Value)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err) // should not happen with correct ASTs
|
|
|
|
|
}
|
|
|
|
|
return s, true
|
|
|
|
|
}
|
|
|
|
|
return "", false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// stringVal returns the (unquoted) string value and true if
|
|
|
|
|
// tv is a string constant; otherwise it returns "" and false.
|
|
|
|
|
func stringVal(tv types.TypeAndValue) (string, bool) {
|
|
|
|
|
if tv.IsValue() && tv.Value != nil && tv.Value.Kind() == constant.String {
|
|
|
|
|
return constant.StringVal(tv.Value), true
|
|
|
|
|
}
|
|
|
|
|
return "", false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// formatIter iterates through the string s in increasing
|
|
|
|
|
// index order and calls f for each format specifier '%..v'.
|
|
|
|
|
// The arguments for f describe the specifier's index range.
|
2017-08-19 22:33:51 +02:00
|
|
|
// If a format specifier contains a "*", f is called with
|
2016-09-08 21:39:33 -07:00
|
|
|
// the index range for "*" alone, before being called for
|
|
|
|
|
// the entire specifier. The result of f is the index of
|
|
|
|
|
// the rune at which iteration continues.
|
|
|
|
|
func formatIter(s string, f func(i, j int) int) {
|
|
|
|
|
i := 0 // index after current rune
|
|
|
|
|
var r rune // current rune
|
|
|
|
|
|
|
|
|
|
next := func() {
|
|
|
|
|
r1, w := utf8.DecodeRuneInString(s[i:])
|
|
|
|
|
if w == 0 {
|
|
|
|
|
r1 = -1 // signal end-of-string
|
|
|
|
|
}
|
|
|
|
|
r = r1
|
|
|
|
|
i += w
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
flags := func() {
|
|
|
|
|
for r == ' ' || r == '#' || r == '+' || r == '-' || r == '0' {
|
|
|
|
|
next()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
index := func() {
|
|
|
|
|
if r == '[' {
|
|
|
|
|
log.Fatalf("cannot handle indexed arguments: %s", s)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
digits := func() {
|
|
|
|
|
index()
|
|
|
|
|
if r == '*' {
|
|
|
|
|
i = f(i-1, i)
|
|
|
|
|
next()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
for '0' <= r && r <= '9' {
|
|
|
|
|
next()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for next(); r >= 0; next() {
|
|
|
|
|
if r == '%' {
|
|
|
|
|
i0 := i
|
|
|
|
|
next()
|
|
|
|
|
flags()
|
|
|
|
|
digits()
|
|
|
|
|
if r == '.' {
|
|
|
|
|
next()
|
|
|
|
|
digits()
|
|
|
|
|
}
|
|
|
|
|
index()
|
2016-09-09 19:54:09 -07:00
|
|
|
// accept any letter (a-z, A-Z) as format verb;
|
|
|
|
|
// ignore anything else
|
|
|
|
|
if 'a' <= r && r <= 'z' || 'A' <= r && r <= 'Z' {
|
2016-09-08 21:39:33 -07:00
|
|
|
i = f(i0-1, i)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// isFormat reports whether s contains format specifiers.
|
|
|
|
|
func isFormat(s string) (yes bool) {
|
|
|
|
|
formatIter(s, func(i, j int) int {
|
|
|
|
|
yes = true
|
|
|
|
|
return len(s) // stop iteration
|
|
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// oneFormat reports whether s is exactly one format specifier.
|
|
|
|
|
func oneFormat(s string) (yes bool) {
|
|
|
|
|
formatIter(s, func(i, j int) int {
|
|
|
|
|
yes = i == 0 && j == len(s)
|
|
|
|
|
return j
|
|
|
|
|
})
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// numFormatArgs returns the number of format specifiers in s.
|
|
|
|
|
func numFormatArgs(s string) int {
|
|
|
|
|
count := 0
|
|
|
|
|
formatIter(s, func(i, j int) int {
|
|
|
|
|
count++
|
|
|
|
|
return j
|
|
|
|
|
})
|
|
|
|
|
return count
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// formatReplace replaces the i'th format specifier s in the incoming
|
|
|
|
|
// string in with the result of f(i, s) and returns the new string.
|
|
|
|
|
func formatReplace(in string, f func(i int, s string) string) string {
|
|
|
|
|
var buf []byte
|
|
|
|
|
i0 := 0
|
|
|
|
|
index := 0
|
|
|
|
|
formatIter(in, func(i, j int) int {
|
|
|
|
|
if sub := in[i:j]; sub != "*" { // ignore calls for "*" width/length specifiers
|
|
|
|
|
buf = append(buf, in[i0:i]...)
|
|
|
|
|
buf = append(buf, f(index, sub)...)
|
|
|
|
|
i0 = j
|
|
|
|
|
}
|
|
|
|
|
index++
|
|
|
|
|
return j
|
|
|
|
|
})
|
|
|
|
|
return string(append(buf, in[i0:]...))
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-09 19:54:09 -07:00
|
|
|
// blacklistedPackages is the set of packages which can
|
|
|
|
|
// be ignored.
|
2016-10-13 15:13:41 -04:00
|
|
|
var blacklistedPackages = map[string]bool{}
|
2016-09-09 19:54:09 -07:00
|
|
|
|
|
|
|
|
// blacklistedFunctions is the set of functions which may have
|
2016-09-08 21:39:33 -07:00
|
|
|
// format-like arguments but which don't do any formatting and
|
|
|
|
|
// thus may be ignored.
|
2016-09-09 19:54:09 -07:00
|
|
|
var blacklistedFunctions = map[string]bool{}
|
2016-09-08 21:39:33 -07:00
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
|
// verify that knownFormats entries are correctly formatted
|
|
|
|
|
for key, val := range knownFormats {
|
|
|
|
|
// key must be "typename format", and format starts with a '%'
|
|
|
|
|
// (formats containing '*' alone are not collected in this table)
|
2017-09-21 19:01:27 +02:00
|
|
|
i := strings.IndexByte(key, '%')
|
2016-09-08 21:39:33 -07:00
|
|
|
if i < 0 || !oneFormat(key[i:]) {
|
|
|
|
|
log.Fatalf("incorrect knownFormats key: %q", key)
|
|
|
|
|
}
|
|
|
|
|
// val must be "format" or ""
|
|
|
|
|
if val != "" && !oneFormat(val) {
|
|
|
|
|
log.Fatalf("incorrect knownFormats value: %q (key = %q)", val, key)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-09 19:54:09 -07:00
|
|
|
// knownFormats entries are of the form "typename format" -> "newformat".
|
2016-09-08 21:39:33 -07:00
|
|
|
// An absent entry means that the format is not recognized as valid.
|
2016-09-09 19:54:09 -07:00
|
|
|
// An empty new format means that the format should remain unchanged.
|
2016-09-08 21:39:33 -07:00
|
|
|
// To print out a new table, run: go test -run Formats -v.
|
|
|
|
|
var knownFormats = map[string]string{
|
|
|
|
|
"*bytes.Buffer %s": "",
|
|
|
|
|
"*cmd/compile/internal/gc.Mpflt %v": "",
|
|
|
|
|
"*cmd/compile/internal/gc.Mpint %v": "",
|
|
|
|
|
"*cmd/compile/internal/gc.Node %#v": "",
|
2016-09-09 21:08:46 -07:00
|
|
|
"*cmd/compile/internal/gc.Node %+S": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"*cmd/compile/internal/gc.Node %+v": "",
|
|
|
|
|
"*cmd/compile/internal/gc.Node %0j": "",
|
2016-09-09 21:08:46 -07:00
|
|
|
"*cmd/compile/internal/gc.Node %L": "",
|
|
|
|
|
"*cmd/compile/internal/gc.Node %S": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"*cmd/compile/internal/gc.Node %j": "",
|
|
|
|
|
"*cmd/compile/internal/gc.Node %p": "",
|
|
|
|
|
"*cmd/compile/internal/gc.Node %v": "",
|
|
|
|
|
"*cmd/compile/internal/ssa.Block %s": "",
|
|
|
|
|
"*cmd/compile/internal/ssa.Block %v": "",
|
|
|
|
|
"*cmd/compile/internal/ssa.Func %s": "",
|
[dev.debug] cmd/compile: better DWARF with optimizations on
Debuggers use DWARF information to find local variables on the
stack and in registers. Prior to this CL, the DWARF information for
functions claimed that all variables were on the stack at all times.
That's incorrect when optimizations are enabled, and results in
debuggers showing data that is out of date or complete gibberish.
After this CL, the compiler is capable of representing variable
locations more accurately, and attempts to do so. Due to limitations of
the SSA backend, it's not possible to be completely correct.
There are a number of problems in the current design. One of the easier
to understand is that variable names currently must be attached to an
SSA value, but not all assignments in the source code actually result
in machine code. For example:
type myint int
var a int
b := myint(int)
and
b := (*uint64)(unsafe.Pointer(a))
don't generate machine code because the underlying representation is the
same, so the correct value of b will not be set when the user would
expect.
Generating the more precise debug information is behind a flag,
dwarflocationlists. Because of the issues described above, setting the
flag may not make the debugging experience much better, and may actually
make it worse in cases where the variable actually is on the stack and
the more complicated analysis doesn't realize it.
A number of changes are included:
- Add a new pseudo-instruction, RegKill, which indicates that the value
in the register has been clobbered.
- Adjust regalloc to emit RegKills in the right places. Significantly,
this means that phis are mixed with StoreReg and RegKills after
regalloc.
- Track variable decomposition in ssa.LocalSlots.
- After the SSA backend is done, analyze the result and build location
lists for each LocalSlot.
- After assembly is done, update the location lists with the assembled
PC offsets, recompose variables, and build DWARF location lists. Emit the
list as a new linker symbol, one per function.
- In the linker, aggregate the location lists into a .debug_loc section.
TODO:
- currently disabled for non-X86/AMD64 because there are no data tables.
go build -toolexec 'toolstash -cmp' -a std succeeds.
With -dwarflocationlists false:
before: f02812195637909ff675782c0b46836a8ff01976
after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec
benchstat -geomean /tmp/220352263 /tmp/621364410
completed 15 of 15, estimated time remaining 0s (eta 3:52PM)
name old time/op new time/op delta
Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14)
Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15)
GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14)
Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15)
GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15)
Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13)
Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15)
XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15)
[Geo mean] 206ms 377ms +82.86%
name old user-time/op new user-time/op delta
Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15)
Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14)
GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15)
Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15)
GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15)
Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13)
Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15)
XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15)
[Geo mean] 317ms 583ms +83.72%
name old alloc/op new alloc/op delta
Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15)
Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15)
GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14)
Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15)
GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15)
Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15)
Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15)
XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15)
[Geo mean] 42.1MB 75.0MB +78.05%
name old allocs/op new allocs/op delta
Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15)
Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14)
GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14)
Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15)
GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15)
Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15)
Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15)
XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15)
[Geo mean] 439k 755k +72.01%
name old text-bytes new text-bytes delta
HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15)
name old data-bytes new data-bytes delta
HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal)
name old bss-bytes new bss-bytes delta
HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal)
name old exe-bytes new exe-bytes delta
HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal)
Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8
Reviewed-on: https://go-review.googlesource.com/41770
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
|
|
|
"*cmd/compile/internal/ssa.Func %v": "",
|
|
|
|
|
"*cmd/compile/internal/ssa.LocalSlot %+v": "",
|
|
|
|
|
"*cmd/compile/internal/ssa.LocalSlot %v": "",
|
2017-08-17 12:23:34 -07:00
|
|
|
"*cmd/compile/internal/ssa.Register %s": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"*cmd/compile/internal/ssa.SparseTreeNode %v": "",
|
|
|
|
|
"*cmd/compile/internal/ssa.Value %s": "",
|
|
|
|
|
"*cmd/compile/internal/ssa.Value %v": "",
|
[dev.debug] cmd/compile: better DWARF with optimizations on
Debuggers use DWARF information to find local variables on the
stack and in registers. Prior to this CL, the DWARF information for
functions claimed that all variables were on the stack at all times.
That's incorrect when optimizations are enabled, and results in
debuggers showing data that is out of date or complete gibberish.
After this CL, the compiler is capable of representing variable
locations more accurately, and attempts to do so. Due to limitations of
the SSA backend, it's not possible to be completely correct.
There are a number of problems in the current design. One of the easier
to understand is that variable names currently must be attached to an
SSA value, but not all assignments in the source code actually result
in machine code. For example:
type myint int
var a int
b := myint(int)
and
b := (*uint64)(unsafe.Pointer(a))
don't generate machine code because the underlying representation is the
same, so the correct value of b will not be set when the user would
expect.
Generating the more precise debug information is behind a flag,
dwarflocationlists. Because of the issues described above, setting the
flag may not make the debugging experience much better, and may actually
make it worse in cases where the variable actually is on the stack and
the more complicated analysis doesn't realize it.
A number of changes are included:
- Add a new pseudo-instruction, RegKill, which indicates that the value
in the register has been clobbered.
- Adjust regalloc to emit RegKills in the right places. Significantly,
this means that phis are mixed with StoreReg and RegKills after
regalloc.
- Track variable decomposition in ssa.LocalSlots.
- After the SSA backend is done, analyze the result and build location
lists for each LocalSlot.
- After assembly is done, update the location lists with the assembled
PC offsets, recompose variables, and build DWARF location lists. Emit the
list as a new linker symbol, one per function.
- In the linker, aggregate the location lists into a .debug_loc section.
TODO:
- currently disabled for non-X86/AMD64 because there are no data tables.
go build -toolexec 'toolstash -cmp' -a std succeeds.
With -dwarflocationlists false:
before: f02812195637909ff675782c0b46836a8ff01976
after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec
benchstat -geomean /tmp/220352263 /tmp/621364410
completed 15 of 15, estimated time remaining 0s (eta 3:52PM)
name old time/op new time/op delta
Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14)
Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15)
GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14)
Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15)
GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15)
Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13)
Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15)
XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15)
[Geo mean] 206ms 377ms +82.86%
name old user-time/op new user-time/op delta
Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15)
Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14)
GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15)
Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15)
GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15)
Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13)
Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15)
XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15)
[Geo mean] 317ms 583ms +83.72%
name old alloc/op new alloc/op delta
Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15)
Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15)
GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14)
Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15)
GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15)
Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15)
Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15)
XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15)
[Geo mean] 42.1MB 75.0MB +78.05%
name old allocs/op new allocs/op delta
Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15)
Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14)
GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14)
Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15)
GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15)
Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15)
Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15)
XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15)
[Geo mean] 439k 755k +72.01%
name old text-bytes new text-bytes delta
HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15)
name old data-bytes new data-bytes delta
HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal)
name old bss-bytes new bss-bytes delta
HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal)
name old exe-bytes new exe-bytes delta
HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal)
Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8
Reviewed-on: https://go-review.googlesource.com/41770
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
|
|
|
"*cmd/compile/internal/ssa.VarLoc %v": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"*cmd/compile/internal/ssa.sparseTreeMapEntry %v": "",
|
cmd/compile: factor out Pkg, Sym, and Type into package types
- created new package cmd/compile/internal/types
- moved Pkg, Sym, Type to new package
- to break cycles, for now we need the (ugly) types/utils.go
file which contains a handful of functions that must be installed
early by the gc frontend
- to break cycles, for now we need two functions to convert between
*gc.Node and *types.Node (the latter is a dummy type)
- adjusted the gc's code to use the new package and the conversion
functions as needed
- made several Pkg, Sym, and Type methods functions as needed
- renamed constructors typ, typPtr, typArray, etc. to types.New,
types.NewPtr, types.NewArray, etc.
Passes toolstash-check -all.
Change-Id: I8adfa5e85c731645d0a7fd2030375ed6ebf54b72
Reviewed-on: https://go-review.googlesource.com/39855
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-04-04 17:54:02 -07:00
|
|
|
"*cmd/compile/internal/types.Field %p": "",
|
|
|
|
|
"*cmd/compile/internal/types.Field %v": "",
|
|
|
|
|
"*cmd/compile/internal/types.Sym %+v": "",
|
|
|
|
|
"*cmd/compile/internal/types.Sym %-v": "",
|
|
|
|
|
"*cmd/compile/internal/types.Sym %0S": "",
|
|
|
|
|
"*cmd/compile/internal/types.Sym %S": "",
|
|
|
|
|
"*cmd/compile/internal/types.Sym %p": "",
|
|
|
|
|
"*cmd/compile/internal/types.Sym %v": "",
|
|
|
|
|
"*cmd/compile/internal/types.Type %#v": "",
|
|
|
|
|
"*cmd/compile/internal/types.Type %+v": "",
|
|
|
|
|
"*cmd/compile/internal/types.Type %-S": "",
|
|
|
|
|
"*cmd/compile/internal/types.Type %0S": "",
|
|
|
|
|
"*cmd/compile/internal/types.Type %L": "",
|
|
|
|
|
"*cmd/compile/internal/types.Type %S": "",
|
|
|
|
|
"*cmd/compile/internal/types.Type %p": "",
|
cmd/compile: change ssa.Type into *types.Type
When package ssa was created, Type was in package gc.
To avoid circular dependencies, we used an interface (ssa.Type)
to represent type information in SSA.
In the Go 1.9 cycle, gri extricated the Type type from package gc.
As a result, we can now use it in package ssa.
Now, instead of package types depending on package ssa,
it is the other way.
This is a more sensible dependency tree,
and helps compiler performance a bit.
Though this is a big CL, most of the changes are
mechanical and uninteresting.
Interesting bits:
* Add new singleton globals to package types for the special
SSA types Memory, Void, Invalid, Flags, and Int128.
* Add two new Types, TSSA for the special types,
and TTUPLE, for SSA tuple types.
ssa.MakeTuple is now types.NewTuple.
* Move type comparison result constants CMPlt, CMPeq, and CMPgt
to package types.
* We had picked the name "types" in our rules for the handy
list of types provided by ssa.Config. That conflicted with
the types package name, so change it to "typ".
* Update the type comparison routine to handle tuples and special
types inline.
* Teach gc/fmt.go how to print special types.
* We can now eliminate ElemTypes in favor of just Elem,
and probably also some other duplicated Type methods
designed to return ssa.Type instead of *types.Type.
* The ssa tests were using their own dummy types,
and they were not particularly careful about types in general.
Of necessity, this CL switches them to use *types.Type;
it does not make them more type-accurate.
Unfortunately, using types.Type means initializing a bit
of the types universe.
This is prime for refactoring and improvement.
This shrinks ssa.Value; it now fits in a smaller size class
on 64 bit systems. This doesn't have a giant impact,
though, since most Values are preallocated in a chunk.
name old alloc/op new alloc/op delta
Template 37.9MB ± 0% 37.7MB ± 0% -0.57% (p=0.000 n=10+8)
Unicode 28.9MB ± 0% 28.7MB ± 0% -0.52% (p=0.000 n=10+10)
GoTypes 110MB ± 0% 109MB ± 0% -0.88% (p=0.000 n=10+10)
Flate 24.7MB ± 0% 24.6MB ± 0% -0.66% (p=0.000 n=10+10)
GoParser 31.1MB ± 0% 30.9MB ± 0% -0.61% (p=0.000 n=10+9)
Reflect 73.9MB ± 0% 73.4MB ± 0% -0.62% (p=0.000 n=10+8)
Tar 25.8MB ± 0% 25.6MB ± 0% -0.77% (p=0.000 n=9+10)
XML 41.2MB ± 0% 40.9MB ± 0% -0.80% (p=0.000 n=10+10)
[Geo mean] 40.5MB 40.3MB -0.68%
name old allocs/op new allocs/op delta
Template 385k ± 0% 386k ± 0% ~ (p=0.356 n=10+9)
Unicode 343k ± 1% 344k ± 0% ~ (p=0.481 n=10+10)
GoTypes 1.16M ± 0% 1.16M ± 0% -0.16% (p=0.004 n=10+10)
Flate 238k ± 1% 238k ± 1% ~ (p=0.853 n=10+10)
GoParser 320k ± 0% 320k ± 0% ~ (p=0.720 n=10+9)
Reflect 957k ± 0% 957k ± 0% ~ (p=0.460 n=10+8)
Tar 252k ± 0% 252k ± 0% ~ (p=0.133 n=9+10)
XML 400k ± 0% 400k ± 0% ~ (p=0.796 n=10+10)
[Geo mean] 428k 428k -0.01%
Removing all the interface calls helps non-trivially with CPU, though.
name old time/op new time/op delta
Template 178ms ± 4% 173ms ± 3% -2.90% (p=0.000 n=94+96)
Unicode 85.0ms ± 4% 83.9ms ± 4% -1.23% (p=0.000 n=96+96)
GoTypes 543ms ± 3% 528ms ± 3% -2.73% (p=0.000 n=98+96)
Flate 116ms ± 3% 113ms ± 4% -2.34% (p=0.000 n=96+99)
GoParser 144ms ± 3% 140ms ± 4% -2.80% (p=0.000 n=99+97)
Reflect 344ms ± 3% 334ms ± 4% -3.02% (p=0.000 n=100+99)
Tar 106ms ± 5% 103ms ± 4% -3.30% (p=0.000 n=98+94)
XML 198ms ± 5% 192ms ± 4% -2.88% (p=0.000 n=92+95)
[Geo mean] 178ms 173ms -2.65%
name old user-time/op new user-time/op delta
Template 229ms ± 5% 224ms ± 5% -2.36% (p=0.000 n=95+99)
Unicode 107ms ± 6% 106ms ± 5% -1.13% (p=0.001 n=93+95)
GoTypes 696ms ± 4% 679ms ± 4% -2.45% (p=0.000 n=97+99)
Flate 137ms ± 4% 134ms ± 5% -2.66% (p=0.000 n=99+96)
GoParser 176ms ± 5% 172ms ± 8% -2.27% (p=0.000 n=98+100)
Reflect 430ms ± 6% 411ms ± 5% -4.46% (p=0.000 n=100+92)
Tar 128ms ±13% 123ms ±13% -4.21% (p=0.000 n=100+100)
XML 239ms ± 6% 233ms ± 6% -2.50% (p=0.000 n=95+97)
[Geo mean] 220ms 213ms -2.76%
Change-Id: I15c7d6268347f8358e75066dfdbd77db24e8d0c1
Reviewed-on: https://go-review.googlesource.com/42145
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-28 14:12:28 -07:00
|
|
|
"*cmd/compile/internal/types.Type %s": "",
|
cmd/compile: factor out Pkg, Sym, and Type into package types
- created new package cmd/compile/internal/types
- moved Pkg, Sym, Type to new package
- to break cycles, for now we need the (ugly) types/utils.go
file which contains a handful of functions that must be installed
early by the gc frontend
- to break cycles, for now we need two functions to convert between
*gc.Node and *types.Node (the latter is a dummy type)
- adjusted the gc's code to use the new package and the conversion
functions as needed
- made several Pkg, Sym, and Type methods functions as needed
- renamed constructors typ, typPtr, typArray, etc. to types.New,
types.NewPtr, types.NewArray, etc.
Passes toolstash-check -all.
Change-Id: I8adfa5e85c731645d0a7fd2030375ed6ebf54b72
Reviewed-on: https://go-review.googlesource.com/39855
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-04-04 17:54:02 -07:00
|
|
|
"*cmd/compile/internal/types.Type %v": "",
|
[dev.debug] cmd/compile: better DWARF with optimizations on
Debuggers use DWARF information to find local variables on the
stack and in registers. Prior to this CL, the DWARF information for
functions claimed that all variables were on the stack at all times.
That's incorrect when optimizations are enabled, and results in
debuggers showing data that is out of date or complete gibberish.
After this CL, the compiler is capable of representing variable
locations more accurately, and attempts to do so. Due to limitations of
the SSA backend, it's not possible to be completely correct.
There are a number of problems in the current design. One of the easier
to understand is that variable names currently must be attached to an
SSA value, but not all assignments in the source code actually result
in machine code. For example:
type myint int
var a int
b := myint(int)
and
b := (*uint64)(unsafe.Pointer(a))
don't generate machine code because the underlying representation is the
same, so the correct value of b will not be set when the user would
expect.
Generating the more precise debug information is behind a flag,
dwarflocationlists. Because of the issues described above, setting the
flag may not make the debugging experience much better, and may actually
make it worse in cases where the variable actually is on the stack and
the more complicated analysis doesn't realize it.
A number of changes are included:
- Add a new pseudo-instruction, RegKill, which indicates that the value
in the register has been clobbered.
- Adjust regalloc to emit RegKills in the right places. Significantly,
this means that phis are mixed with StoreReg and RegKills after
regalloc.
- Track variable decomposition in ssa.LocalSlots.
- After the SSA backend is done, analyze the result and build location
lists for each LocalSlot.
- After assembly is done, update the location lists with the assembled
PC offsets, recompose variables, and build DWARF location lists. Emit the
list as a new linker symbol, one per function.
- In the linker, aggregate the location lists into a .debug_loc section.
TODO:
- currently disabled for non-X86/AMD64 because there are no data tables.
go build -toolexec 'toolstash -cmp' -a std succeeds.
With -dwarflocationlists false:
before: f02812195637909ff675782c0b46836a8ff01976
after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec
benchstat -geomean /tmp/220352263 /tmp/621364410
completed 15 of 15, estimated time remaining 0s (eta 3:52PM)
name old time/op new time/op delta
Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14)
Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15)
GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14)
Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15)
GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15)
Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13)
Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15)
XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15)
[Geo mean] 206ms 377ms +82.86%
name old user-time/op new user-time/op delta
Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15)
Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14)
GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15)
Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15)
GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15)
Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13)
Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15)
XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15)
[Geo mean] 317ms 583ms +83.72%
name old alloc/op new alloc/op delta
Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15)
Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15)
GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14)
Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15)
GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15)
Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15)
Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15)
XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15)
[Geo mean] 42.1MB 75.0MB +78.05%
name old allocs/op new allocs/op delta
Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15)
Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14)
GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14)
Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15)
GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15)
Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15)
Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15)
XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15)
[Geo mean] 439k 755k +72.01%
name old text-bytes new text-bytes delta
HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15)
name old data-bytes new data-bytes delta
HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal)
name old bss-bytes new bss-bytes delta
HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal)
name old exe-bytes new exe-bytes delta
HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal)
Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8
Reviewed-on: https://go-review.googlesource.com/41770
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
|
|
|
"*cmd/internal/dwarf.Location %#v": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"*cmd/internal/obj.Addr %v": "",
|
2017-03-06 07:32:37 -08:00
|
|
|
"*cmd/internal/obj.LSym %v": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"*cmd/internal/obj.Prog %s": "",
|
2016-11-08 16:10:26 -08:00
|
|
|
"*math/big.Int %#x": "",
|
2017-02-13 16:00:09 -08:00
|
|
|
"*math/big.Int %s": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"[16]byte %x": "",
|
|
|
|
|
"[]*cmd/compile/internal/gc.Node %v": "",
|
|
|
|
|
"[]*cmd/compile/internal/gc.Sig %#v": "",
|
[dev.debug] cmd/compile: better DWARF with optimizations on
Debuggers use DWARF information to find local variables on the
stack and in registers. Prior to this CL, the DWARF information for
functions claimed that all variables were on the stack at all times.
That's incorrect when optimizations are enabled, and results in
debuggers showing data that is out of date or complete gibberish.
After this CL, the compiler is capable of representing variable
locations more accurately, and attempts to do so. Due to limitations of
the SSA backend, it's not possible to be completely correct.
There are a number of problems in the current design. One of the easier
to understand is that variable names currently must be attached to an
SSA value, but not all assignments in the source code actually result
in machine code. For example:
type myint int
var a int
b := myint(int)
and
b := (*uint64)(unsafe.Pointer(a))
don't generate machine code because the underlying representation is the
same, so the correct value of b will not be set when the user would
expect.
Generating the more precise debug information is behind a flag,
dwarflocationlists. Because of the issues described above, setting the
flag may not make the debugging experience much better, and may actually
make it worse in cases where the variable actually is on the stack and
the more complicated analysis doesn't realize it.
A number of changes are included:
- Add a new pseudo-instruction, RegKill, which indicates that the value
in the register has been clobbered.
- Adjust regalloc to emit RegKills in the right places. Significantly,
this means that phis are mixed with StoreReg and RegKills after
regalloc.
- Track variable decomposition in ssa.LocalSlots.
- After the SSA backend is done, analyze the result and build location
lists for each LocalSlot.
- After assembly is done, update the location lists with the assembled
PC offsets, recompose variables, and build DWARF location lists. Emit the
list as a new linker symbol, one per function.
- In the linker, aggregate the location lists into a .debug_loc section.
TODO:
- currently disabled for non-X86/AMD64 because there are no data tables.
go build -toolexec 'toolstash -cmp' -a std succeeds.
With -dwarflocationlists false:
before: f02812195637909ff675782c0b46836a8ff01976
after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec
benchstat -geomean /tmp/220352263 /tmp/621364410
completed 15 of 15, estimated time remaining 0s (eta 3:52PM)
name old time/op new time/op delta
Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14)
Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15)
GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14)
Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15)
GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15)
Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13)
Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15)
XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15)
[Geo mean] 206ms 377ms +82.86%
name old user-time/op new user-time/op delta
Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15)
Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14)
GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15)
Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15)
GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15)
Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13)
Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15)
XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15)
[Geo mean] 317ms 583ms +83.72%
name old alloc/op new alloc/op delta
Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15)
Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15)
GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14)
Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15)
GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15)
Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15)
Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15)
XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15)
[Geo mean] 42.1MB 75.0MB +78.05%
name old allocs/op new allocs/op delta
Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15)
Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14)
GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14)
Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15)
GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15)
Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15)
Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15)
XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15)
[Geo mean] 439k 755k +72.01%
name old text-bytes new text-bytes delta
HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15)
name old data-bytes new data-bytes delta
HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal)
name old bss-bytes new bss-bytes delta
HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal)
name old exe-bytes new exe-bytes delta
HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal)
Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8
Reviewed-on: https://go-review.googlesource.com/41770
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
|
|
|
"[]*cmd/compile/internal/ssa.Block %+v": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"[]*cmd/compile/internal/ssa.Value %v": "",
|
[dev.debug] cmd/compile: better DWARF with optimizations on
Debuggers use DWARF information to find local variables on the
stack and in registers. Prior to this CL, the DWARF information for
functions claimed that all variables were on the stack at all times.
That's incorrect when optimizations are enabled, and results in
debuggers showing data that is out of date or complete gibberish.
After this CL, the compiler is capable of representing variable
locations more accurately, and attempts to do so. Due to limitations of
the SSA backend, it's not possible to be completely correct.
There are a number of problems in the current design. One of the easier
to understand is that variable names currently must be attached to an
SSA value, but not all assignments in the source code actually result
in machine code. For example:
type myint int
var a int
b := myint(int)
and
b := (*uint64)(unsafe.Pointer(a))
don't generate machine code because the underlying representation is the
same, so the correct value of b will not be set when the user would
expect.
Generating the more precise debug information is behind a flag,
dwarflocationlists. Because of the issues described above, setting the
flag may not make the debugging experience much better, and may actually
make it worse in cases where the variable actually is on the stack and
the more complicated analysis doesn't realize it.
A number of changes are included:
- Add a new pseudo-instruction, RegKill, which indicates that the value
in the register has been clobbered.
- Adjust regalloc to emit RegKills in the right places. Significantly,
this means that phis are mixed with StoreReg and RegKills after
regalloc.
- Track variable decomposition in ssa.LocalSlots.
- After the SSA backend is done, analyze the result and build location
lists for each LocalSlot.
- After assembly is done, update the location lists with the assembled
PC offsets, recompose variables, and build DWARF location lists. Emit the
list as a new linker symbol, one per function.
- In the linker, aggregate the location lists into a .debug_loc section.
TODO:
- currently disabled for non-X86/AMD64 because there are no data tables.
go build -toolexec 'toolstash -cmp' -a std succeeds.
With -dwarflocationlists false:
before: f02812195637909ff675782c0b46836a8ff01976
after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec
benchstat -geomean /tmp/220352263 /tmp/621364410
completed 15 of 15, estimated time remaining 0s (eta 3:52PM)
name old time/op new time/op delta
Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14)
Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15)
GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14)
Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15)
GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15)
Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13)
Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15)
XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15)
[Geo mean] 206ms 377ms +82.86%
name old user-time/op new user-time/op delta
Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15)
Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14)
GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15)
Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15)
GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15)
Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13)
Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15)
XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15)
[Geo mean] 317ms 583ms +83.72%
name old alloc/op new alloc/op delta
Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15)
Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15)
GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14)
Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15)
GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15)
Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15)
Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15)
XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15)
[Geo mean] 42.1MB 75.0MB +78.05%
name old allocs/op new allocs/op delta
Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15)
Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14)
GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14)
Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15)
GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15)
Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15)
Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15)
XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15)
[Geo mean] 439k 755k +72.01%
name old text-bytes new text-bytes delta
HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15)
name old data-bytes new data-bytes delta
HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal)
name old bss-bytes new bss-bytes delta
HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal)
name old exe-bytes new exe-bytes delta
HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal)
Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8
Reviewed-on: https://go-review.googlesource.com/41770
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
|
|
|
"[][]cmd/compile/internal/ssa.SlotID %v": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"[]byte %s": "",
|
|
|
|
|
"[]byte %x": "",
|
|
|
|
|
"[]cmd/compile/internal/ssa.Edge %v": "",
|
|
|
|
|
"[]cmd/compile/internal/ssa.ID %v": "",
|
[dev.debug] cmd/compile: better DWARF with optimizations on
Debuggers use DWARF information to find local variables on the
stack and in registers. Prior to this CL, the DWARF information for
functions claimed that all variables were on the stack at all times.
That's incorrect when optimizations are enabled, and results in
debuggers showing data that is out of date or complete gibberish.
After this CL, the compiler is capable of representing variable
locations more accurately, and attempts to do so. Due to limitations of
the SSA backend, it's not possible to be completely correct.
There are a number of problems in the current design. One of the easier
to understand is that variable names currently must be attached to an
SSA value, but not all assignments in the source code actually result
in machine code. For example:
type myint int
var a int
b := myint(int)
and
b := (*uint64)(unsafe.Pointer(a))
don't generate machine code because the underlying representation is the
same, so the correct value of b will not be set when the user would
expect.
Generating the more precise debug information is behind a flag,
dwarflocationlists. Because of the issues described above, setting the
flag may not make the debugging experience much better, and may actually
make it worse in cases where the variable actually is on the stack and
the more complicated analysis doesn't realize it.
A number of changes are included:
- Add a new pseudo-instruction, RegKill, which indicates that the value
in the register has been clobbered.
- Adjust regalloc to emit RegKills in the right places. Significantly,
this means that phis are mixed with StoreReg and RegKills after
regalloc.
- Track variable decomposition in ssa.LocalSlots.
- After the SSA backend is done, analyze the result and build location
lists for each LocalSlot.
- After assembly is done, update the location lists with the assembled
PC offsets, recompose variables, and build DWARF location lists. Emit the
list as a new linker symbol, one per function.
- In the linker, aggregate the location lists into a .debug_loc section.
TODO:
- currently disabled for non-X86/AMD64 because there are no data tables.
go build -toolexec 'toolstash -cmp' -a std succeeds.
With -dwarflocationlists false:
before: f02812195637909ff675782c0b46836a8ff01976
after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec
benchstat -geomean /tmp/220352263 /tmp/621364410
completed 15 of 15, estimated time remaining 0s (eta 3:52PM)
name old time/op new time/op delta
Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14)
Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15)
GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14)
Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15)
GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15)
Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13)
Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15)
XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15)
[Geo mean] 206ms 377ms +82.86%
name old user-time/op new user-time/op delta
Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15)
Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14)
GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15)
Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15)
GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15)
Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13)
Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15)
XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15)
[Geo mean] 317ms 583ms +83.72%
name old alloc/op new alloc/op delta
Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15)
Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15)
GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14)
Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15)
GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15)
Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15)
Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15)
XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15)
[Geo mean] 42.1MB 75.0MB +78.05%
name old allocs/op new allocs/op delta
Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15)
Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14)
GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14)
Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15)
GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15)
Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15)
Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15)
XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15)
[Geo mean] 439k 755k +72.01%
name old text-bytes new text-bytes delta
HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15)
name old data-bytes new data-bytes delta
HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal)
name old bss-bytes new bss-bytes delta
HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal)
name old exe-bytes new exe-bytes delta
HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal)
Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8
Reviewed-on: https://go-review.googlesource.com/41770
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
|
|
|
"[]cmd/compile/internal/ssa.VarLocList %v": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"[]string %v": "",
|
|
|
|
|
"bool %v": "",
|
|
|
|
|
"byte %08b": "",
|
|
|
|
|
"byte %c": "",
|
|
|
|
|
"cmd/compile/internal/arm.shift %d": "",
|
|
|
|
|
"cmd/compile/internal/gc.Class %d": "",
|
2017-09-18 14:53:56 -07:00
|
|
|
"cmd/compile/internal/gc.Class %s": "",
|
[dev.debug] cmd/compile: better DWARF with optimizations on
Debuggers use DWARF information to find local variables on the
stack and in registers. Prior to this CL, the DWARF information for
functions claimed that all variables were on the stack at all times.
That's incorrect when optimizations are enabled, and results in
debuggers showing data that is out of date or complete gibberish.
After this CL, the compiler is capable of representing variable
locations more accurately, and attempts to do so. Due to limitations of
the SSA backend, it's not possible to be completely correct.
There are a number of problems in the current design. One of the easier
to understand is that variable names currently must be attached to an
SSA value, but not all assignments in the source code actually result
in machine code. For example:
type myint int
var a int
b := myint(int)
and
b := (*uint64)(unsafe.Pointer(a))
don't generate machine code because the underlying representation is the
same, so the correct value of b will not be set when the user would
expect.
Generating the more precise debug information is behind a flag,
dwarflocationlists. Because of the issues described above, setting the
flag may not make the debugging experience much better, and may actually
make it worse in cases where the variable actually is on the stack and
the more complicated analysis doesn't realize it.
A number of changes are included:
- Add a new pseudo-instruction, RegKill, which indicates that the value
in the register has been clobbered.
- Adjust regalloc to emit RegKills in the right places. Significantly,
this means that phis are mixed with StoreReg and RegKills after
regalloc.
- Track variable decomposition in ssa.LocalSlots.
- After the SSA backend is done, analyze the result and build location
lists for each LocalSlot.
- After assembly is done, update the location lists with the assembled
PC offsets, recompose variables, and build DWARF location lists. Emit the
list as a new linker symbol, one per function.
- In the linker, aggregate the location lists into a .debug_loc section.
TODO:
- currently disabled for non-X86/AMD64 because there are no data tables.
go build -toolexec 'toolstash -cmp' -a std succeeds.
With -dwarflocationlists false:
before: f02812195637909ff675782c0b46836a8ff01976
after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec
benchstat -geomean /tmp/220352263 /tmp/621364410
completed 15 of 15, estimated time remaining 0s (eta 3:52PM)
name old time/op new time/op delta
Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14)
Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15)
GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14)
Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15)
GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15)
Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13)
Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15)
XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15)
[Geo mean] 206ms 377ms +82.86%
name old user-time/op new user-time/op delta
Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15)
Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14)
GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15)
Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15)
GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15)
Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13)
Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15)
XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15)
[Geo mean] 317ms 583ms +83.72%
name old alloc/op new alloc/op delta
Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15)
Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15)
GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14)
Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15)
GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15)
Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15)
Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15)
XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15)
[Geo mean] 42.1MB 75.0MB +78.05%
name old allocs/op new allocs/op delta
Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15)
Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14)
GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14)
Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15)
GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15)
Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15)
Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15)
XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15)
[Geo mean] 439k 755k +72.01%
name old text-bytes new text-bytes delta
HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15)
name old data-bytes new data-bytes delta
HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal)
name old bss-bytes new bss-bytes delta
HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal)
name old exe-bytes new exe-bytes delta
HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal)
Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8
Reviewed-on: https://go-review.googlesource.com/41770
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
|
|
|
"cmd/compile/internal/gc.Class %v": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"cmd/compile/internal/gc.Ctype %d": "",
|
|
|
|
|
"cmd/compile/internal/gc.Ctype %v": "",
|
|
|
|
|
"cmd/compile/internal/gc.Level %d": "",
|
|
|
|
|
"cmd/compile/internal/gc.Level %v": "",
|
|
|
|
|
"cmd/compile/internal/gc.Nodes %#v": "",
|
|
|
|
|
"cmd/compile/internal/gc.Nodes %+v": "",
|
|
|
|
|
"cmd/compile/internal/gc.Nodes %.v": "",
|
|
|
|
|
"cmd/compile/internal/gc.Nodes %v": "",
|
|
|
|
|
"cmd/compile/internal/gc.Op %#v": "",
|
|
|
|
|
"cmd/compile/internal/gc.Op %v": "",
|
|
|
|
|
"cmd/compile/internal/gc.Val %#v": "",
|
2016-09-09 21:08:46 -07:00
|
|
|
"cmd/compile/internal/gc.Val %T": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"cmd/compile/internal/gc.Val %v": "",
|
cmd/compile: eliminate fmtmode and fmtpkgpfx globals
The fmtmode and fmtpkgpfx globals stand in the
way of making the compiler more concurrent (#15756).
This CL removes them.
The natural way to eliminate a global is to explicitly
thread it as a parameter through all function calls.
However, most of the functions in gc/fmt.go
get called indirectly, by way of fmt format strings,
so there's nowhere natural to add a parameter.
Since there are only a few fmtmode modes,
use named types to distinguish between modes.
For example, fmtNodeErr, fmtNodeDbg, and fmtNodeTypeId
are all gc.Node, but they print in different modes.
Varying the type allows us to thread mode through fmt.
Handle fmtpkgpfx by converting it to a printing mode,
FTypeIdName, and using the same type-based approach.
To avoid a loss of readability and danger of bugs
from introducing conversions at all call sites,
instead add a helper that systematically modifies the args.
The only remaining gc/fmt.go global is dumpdepth.
Since that is used for debugging only,
it that can be handled with a global mutex,
or some similarly basic, if inefficient, protection.
Passes toolstash -cmp. No compiler performance impact.
For future reference, other options for threading state
that were considered and rejected:
* Wrapping values in structs, such as:
type fmtNode struct {
n *Node
mode fmtMode
}
This reduces the proliferation of types, and supports
easily adding extra local parameters.
However, putting such a struct into an interface{} allocates.
This is unacceptable in this particular area of code.
* Passing state via precision, such as:
fmt.Fprintf("%*v", mode, n)
where mode is the state encoded as an integer.
This avoids extra allocations, but it is out of keeping
with the intended semantics of precision, and is less readable.
* Modify the fmt package to support setting/getting context
via fmt.State. Unavailable due to Go 1 compatibility,
and probably the wrong solution anyway.
* Give up on package fmt. This would be a huge readability
regression and cause high code churn.
* Attempt a de-novo rewrite that circumvents these problems.
Too high a risk of bugs, with insufficient reward for the effort,
particularly since long term plans call for elimination
of gc.Node.
Change-Id: Iea2440d5a34a938e64273707de27e3a897cb41d1
Reviewed-on: https://go-review.googlesource.com/38147
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
2016-11-07 16:14:32 -08:00
|
|
|
"cmd/compile/internal/gc.fmtMode %d": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"cmd/compile/internal/gc.initKind %d": "",
|
cmd/compile: cover control flow insns in location lists
The information that's used to generate DWARF location lists is very
ssa.Value centric; it uses Values as start and end coordinates to define
ranges. That mostly works fine, but control flow instructions don't come
from Values, so the ranges couldn't cover them.
Control flow instructions are generated when the SSA representation is
converted to assembly, so that's the best place to extend the ranges
to cover them. (Before that, there's nothing to refer to, and afterward
the boundaries between blocks have been lost.) That requires block
information in the debugInfo type, which then flows down to make
everything else awkward. On the plus side, there's a little less copying
slices around than there used to be, so it should be a little faster.
Previously, the ranges for empty blocks were not very meaningful. That
was fine, because they had no Values to cover, so no debug information
was generated for them. But they do have control flow instructions
(that's why they exist) and so now it's important that the information
be correct. Introduce two sentinel values, BlockStart and BlockEnd, that
denote the boundary of a block, even if the block is empty. BlockEnd
replaces the previous SurvivedBlock flag.
There's one more problem: the last instruction in the function will be a
control flow instruction, so any live ranges need to be extended past
it. But there's no instruction after it to use as the end of the range.
Instead, leave the EndProg field of those ranges as nil and fix it up to
point to past the end of the assembled text at the very last moment.
Change-Id: I81f884020ff36fd6fe8d7888fc57c99412c4245b
Reviewed-on: https://go-review.googlesource.com/63010
Reviewed-by: Alessandro Arzilli <alessandro.arzilli@gmail.com>
Reviewed-by: David Chase <drchase@google.com>
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-09-11 14:28:34 -04:00
|
|
|
"cmd/compile/internal/gc.locID %v": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"cmd/compile/internal/ssa.BranchPrediction %d": "",
|
|
|
|
|
"cmd/compile/internal/ssa.Edge %v": "",
|
2016-11-08 16:10:26 -08:00
|
|
|
"cmd/compile/internal/ssa.GCNode %v": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"cmd/compile/internal/ssa.ID %d": "",
|
[dev.debug] cmd/compile: better DWARF with optimizations on
Debuggers use DWARF information to find local variables on the
stack and in registers. Prior to this CL, the DWARF information for
functions claimed that all variables were on the stack at all times.
That's incorrect when optimizations are enabled, and results in
debuggers showing data that is out of date or complete gibberish.
After this CL, the compiler is capable of representing variable
locations more accurately, and attempts to do so. Due to limitations of
the SSA backend, it's not possible to be completely correct.
There are a number of problems in the current design. One of the easier
to understand is that variable names currently must be attached to an
SSA value, but not all assignments in the source code actually result
in machine code. For example:
type myint int
var a int
b := myint(int)
and
b := (*uint64)(unsafe.Pointer(a))
don't generate machine code because the underlying representation is the
same, so the correct value of b will not be set when the user would
expect.
Generating the more precise debug information is behind a flag,
dwarflocationlists. Because of the issues described above, setting the
flag may not make the debugging experience much better, and may actually
make it worse in cases where the variable actually is on the stack and
the more complicated analysis doesn't realize it.
A number of changes are included:
- Add a new pseudo-instruction, RegKill, which indicates that the value
in the register has been clobbered.
- Adjust regalloc to emit RegKills in the right places. Significantly,
this means that phis are mixed with StoreReg and RegKills after
regalloc.
- Track variable decomposition in ssa.LocalSlots.
- After the SSA backend is done, analyze the result and build location
lists for each LocalSlot.
- After assembly is done, update the location lists with the assembled
PC offsets, recompose variables, and build DWARF location lists. Emit the
list as a new linker symbol, one per function.
- In the linker, aggregate the location lists into a .debug_loc section.
TODO:
- currently disabled for non-X86/AMD64 because there are no data tables.
go build -toolexec 'toolstash -cmp' -a std succeeds.
With -dwarflocationlists false:
before: f02812195637909ff675782c0b46836a8ff01976
after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec
benchstat -geomean /tmp/220352263 /tmp/621364410
completed 15 of 15, estimated time remaining 0s (eta 3:52PM)
name old time/op new time/op delta
Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14)
Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15)
GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14)
Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15)
GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15)
Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13)
Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15)
XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15)
[Geo mean] 206ms 377ms +82.86%
name old user-time/op new user-time/op delta
Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15)
Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14)
GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15)
Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15)
GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15)
Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13)
Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15)
XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15)
[Geo mean] 317ms 583ms +83.72%
name old alloc/op new alloc/op delta
Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15)
Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15)
GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14)
Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15)
GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15)
Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15)
Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15)
XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15)
[Geo mean] 42.1MB 75.0MB +78.05%
name old allocs/op new allocs/op delta
Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15)
Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14)
GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14)
Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15)
GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15)
Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15)
Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15)
XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15)
[Geo mean] 439k 755k +72.01%
name old text-bytes new text-bytes delta
HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15)
name old data-bytes new data-bytes delta
HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal)
name old bss-bytes new bss-bytes delta
HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal)
name old exe-bytes new exe-bytes delta
HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal)
Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8
Reviewed-on: https://go-review.googlesource.com/41770
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
|
|
|
"cmd/compile/internal/ssa.ID %v": "",
|
2017-08-17 12:23:34 -07:00
|
|
|
"cmd/compile/internal/ssa.LocalSlot %s": "",
|
|
|
|
|
"cmd/compile/internal/ssa.Location %s": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"cmd/compile/internal/ssa.Op %s": "",
|
|
|
|
|
"cmd/compile/internal/ssa.Op %v": "",
|
|
|
|
|
"cmd/compile/internal/ssa.ValAndOff %s": "",
|
[dev.debug] cmd/compile: better DWARF with optimizations on
Debuggers use DWARF information to find local variables on the
stack and in registers. Prior to this CL, the DWARF information for
functions claimed that all variables were on the stack at all times.
That's incorrect when optimizations are enabled, and results in
debuggers showing data that is out of date or complete gibberish.
After this CL, the compiler is capable of representing variable
locations more accurately, and attempts to do so. Due to limitations of
the SSA backend, it's not possible to be completely correct.
There are a number of problems in the current design. One of the easier
to understand is that variable names currently must be attached to an
SSA value, but not all assignments in the source code actually result
in machine code. For example:
type myint int
var a int
b := myint(int)
and
b := (*uint64)(unsafe.Pointer(a))
don't generate machine code because the underlying representation is the
same, so the correct value of b will not be set when the user would
expect.
Generating the more precise debug information is behind a flag,
dwarflocationlists. Because of the issues described above, setting the
flag may not make the debugging experience much better, and may actually
make it worse in cases where the variable actually is on the stack and
the more complicated analysis doesn't realize it.
A number of changes are included:
- Add a new pseudo-instruction, RegKill, which indicates that the value
in the register has been clobbered.
- Adjust regalloc to emit RegKills in the right places. Significantly,
this means that phis are mixed with StoreReg and RegKills after
regalloc.
- Track variable decomposition in ssa.LocalSlots.
- After the SSA backend is done, analyze the result and build location
lists for each LocalSlot.
- After assembly is done, update the location lists with the assembled
PC offsets, recompose variables, and build DWARF location lists. Emit the
list as a new linker symbol, one per function.
- In the linker, aggregate the location lists into a .debug_loc section.
TODO:
- currently disabled for non-X86/AMD64 because there are no data tables.
go build -toolexec 'toolstash -cmp' -a std succeeds.
With -dwarflocationlists false:
before: f02812195637909ff675782c0b46836a8ff01976
after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec
benchstat -geomean /tmp/220352263 /tmp/621364410
completed 15 of 15, estimated time remaining 0s (eta 3:52PM)
name old time/op new time/op delta
Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14)
Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15)
GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14)
Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15)
GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15)
Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13)
Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15)
XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15)
[Geo mean] 206ms 377ms +82.86%
name old user-time/op new user-time/op delta
Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15)
Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14)
GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15)
Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15)
GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15)
Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13)
Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15)
XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15)
[Geo mean] 317ms 583ms +83.72%
name old alloc/op new alloc/op delta
Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15)
Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15)
GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14)
Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15)
GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15)
Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15)
Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15)
XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15)
[Geo mean] 42.1MB 75.0MB +78.05%
name old allocs/op new allocs/op delta
Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15)
Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14)
GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14)
Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15)
GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15)
Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15)
Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15)
XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15)
[Geo mean] 439k 755k +72.01%
name old text-bytes new text-bytes delta
HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15)
name old data-bytes new data-bytes delta
HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal)
name old bss-bytes new bss-bytes delta
HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal)
name old exe-bytes new exe-bytes delta
HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal)
Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8
Reviewed-on: https://go-review.googlesource.com/41770
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
|
|
|
"cmd/compile/internal/ssa.VarLocList %v": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"cmd/compile/internal/ssa.rbrank %d": "",
|
|
|
|
|
"cmd/compile/internal/ssa.regMask %d": "",
|
|
|
|
|
"cmd/compile/internal/ssa.register %d": "",
|
|
|
|
|
"cmd/compile/internal/syntax.Expr %#v": "",
|
|
|
|
|
"cmd/compile/internal/syntax.Node %T": "",
|
|
|
|
|
"cmd/compile/internal/syntax.Operator %d": "",
|
|
|
|
|
"cmd/compile/internal/syntax.Operator %s": "",
|
|
|
|
|
"cmd/compile/internal/syntax.token %d": "",
|
|
|
|
|
"cmd/compile/internal/syntax.token %q": "",
|
|
|
|
|
"cmd/compile/internal/syntax.token %s": "",
|
cmd/compile: factor out Pkg, Sym, and Type into package types
- created new package cmd/compile/internal/types
- moved Pkg, Sym, Type to new package
- to break cycles, for now we need the (ugly) types/utils.go
file which contains a handful of functions that must be installed
early by the gc frontend
- to break cycles, for now we need two functions to convert between
*gc.Node and *types.Node (the latter is a dummy type)
- adjusted the gc's code to use the new package and the conversion
functions as needed
- made several Pkg, Sym, and Type methods functions as needed
- renamed constructors typ, typPtr, typArray, etc. to types.New,
types.NewPtr, types.NewArray, etc.
Passes toolstash-check -all.
Change-Id: I8adfa5e85c731645d0a7fd2030375ed6ebf54b72
Reviewed-on: https://go-review.googlesource.com/39855
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-04-04 17:54:02 -07:00
|
|
|
"cmd/compile/internal/types.EType %d": "",
|
|
|
|
|
"cmd/compile/internal/types.EType %s": "",
|
|
|
|
|
"cmd/compile/internal/types.EType %v": "",
|
[dev.debug] cmd/compile: better DWARF with optimizations on
Debuggers use DWARF information to find local variables on the
stack and in registers. Prior to this CL, the DWARF information for
functions claimed that all variables were on the stack at all times.
That's incorrect when optimizations are enabled, and results in
debuggers showing data that is out of date or complete gibberish.
After this CL, the compiler is capable of representing variable
locations more accurately, and attempts to do so. Due to limitations of
the SSA backend, it's not possible to be completely correct.
There are a number of problems in the current design. One of the easier
to understand is that variable names currently must be attached to an
SSA value, but not all assignments in the source code actually result
in machine code. For example:
type myint int
var a int
b := myint(int)
and
b := (*uint64)(unsafe.Pointer(a))
don't generate machine code because the underlying representation is the
same, so the correct value of b will not be set when the user would
expect.
Generating the more precise debug information is behind a flag,
dwarflocationlists. Because of the issues described above, setting the
flag may not make the debugging experience much better, and may actually
make it worse in cases where the variable actually is on the stack and
the more complicated analysis doesn't realize it.
A number of changes are included:
- Add a new pseudo-instruction, RegKill, which indicates that the value
in the register has been clobbered.
- Adjust regalloc to emit RegKills in the right places. Significantly,
this means that phis are mixed with StoreReg and RegKills after
regalloc.
- Track variable decomposition in ssa.LocalSlots.
- After the SSA backend is done, analyze the result and build location
lists for each LocalSlot.
- After assembly is done, update the location lists with the assembled
PC offsets, recompose variables, and build DWARF location lists. Emit the
list as a new linker symbol, one per function.
- In the linker, aggregate the location lists into a .debug_loc section.
TODO:
- currently disabled for non-X86/AMD64 because there are no data tables.
go build -toolexec 'toolstash -cmp' -a std succeeds.
With -dwarflocationlists false:
before: f02812195637909ff675782c0b46836a8ff01976
after: 06f61e8112a42ac34fb80e0c818b3cdb84a5e7ec
benchstat -geomean /tmp/220352263 /tmp/621364410
completed 15 of 15, estimated time remaining 0s (eta 3:52PM)
name old time/op new time/op delta
Template 199ms ± 3% 198ms ± 2% ~ (p=0.400 n=15+14)
Unicode 96.6ms ± 5% 96.4ms ± 5% ~ (p=0.838 n=15+15)
GoTypes 653ms ± 2% 647ms ± 2% ~ (p=0.102 n=15+14)
Flate 133ms ± 6% 129ms ± 3% -2.62% (p=0.041 n=15+15)
GoParser 164ms ± 5% 159ms ± 3% -3.05% (p=0.000 n=15+15)
Reflect 428ms ± 4% 422ms ± 3% ~ (p=0.156 n=15+13)
Tar 123ms ±10% 124ms ± 8% ~ (p=0.461 n=15+15)
XML 228ms ± 3% 224ms ± 3% -1.57% (p=0.045 n=15+15)
[Geo mean] 206ms 377ms +82.86%
name old user-time/op new user-time/op delta
Template 292ms ±10% 301ms ±12% ~ (p=0.189 n=15+15)
Unicode 166ms ±37% 158ms ±14% ~ (p=0.418 n=15+14)
GoTypes 962ms ± 6% 963ms ± 7% ~ (p=0.976 n=15+15)
Flate 207ms ±19% 200ms ±14% ~ (p=0.345 n=14+15)
GoParser 246ms ±22% 240ms ±15% ~ (p=0.587 n=15+15)
Reflect 611ms ±13% 587ms ±14% ~ (p=0.085 n=15+13)
Tar 211ms ±12% 217ms ±14% ~ (p=0.355 n=14+15)
XML 335ms ±15% 320ms ±18% ~ (p=0.169 n=15+15)
[Geo mean] 317ms 583ms +83.72%
name old alloc/op new alloc/op delta
Template 40.2MB ± 0% 40.2MB ± 0% -0.15% (p=0.000 n=14+15)
Unicode 29.2MB ± 0% 29.3MB ± 0% ~ (p=0.624 n=15+15)
GoTypes 114MB ± 0% 114MB ± 0% -0.15% (p=0.000 n=15+14)
Flate 25.7MB ± 0% 25.6MB ± 0% -0.18% (p=0.000 n=13+15)
GoParser 32.2MB ± 0% 32.2MB ± 0% -0.14% (p=0.003 n=15+15)
Reflect 77.8MB ± 0% 77.9MB ± 0% ~ (p=0.061 n=15+15)
Tar 27.1MB ± 0% 27.0MB ± 0% -0.11% (p=0.029 n=15+15)
XML 42.7MB ± 0% 42.5MB ± 0% -0.29% (p=0.000 n=15+15)
[Geo mean] 42.1MB 75.0MB +78.05%
name old allocs/op new allocs/op delta
Template 402k ± 1% 398k ± 0% -0.91% (p=0.000 n=15+15)
Unicode 344k ± 1% 344k ± 0% ~ (p=0.715 n=15+14)
GoTypes 1.18M ± 0% 1.17M ± 0% -0.91% (p=0.000 n=15+14)
Flate 243k ± 0% 240k ± 1% -1.05% (p=0.000 n=13+15)
GoParser 327k ± 1% 324k ± 1% -0.96% (p=0.000 n=15+15)
Reflect 984k ± 1% 982k ± 0% ~ (p=0.050 n=15+15)
Tar 261k ± 1% 259k ± 1% -0.77% (p=0.000 n=15+15)
XML 411k ± 0% 404k ± 1% -1.55% (p=0.000 n=15+15)
[Geo mean] 439k 755k +72.01%
name old text-bytes new text-bytes delta
HelloSize 694kB ± 0% 694kB ± 0% -0.00% (p=0.000 n=15+15)
name old data-bytes new data-bytes delta
HelloSize 5.55kB ± 0% 5.55kB ± 0% ~ (all equal)
name old bss-bytes new bss-bytes delta
HelloSize 133kB ± 0% 133kB ± 0% ~ (all equal)
name old exe-bytes new exe-bytes delta
HelloSize 1.04MB ± 0% 1.04MB ± 0% ~ (all equal)
Change-Id: I991fc553ef175db46bb23b2128317bbd48de70d8
Reviewed-on: https://go-review.googlesource.com/41770
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
2017-07-21 18:30:19 -04:00
|
|
|
"cmd/internal/dwarf.Location %#v": "",
|
2016-12-09 17:15:05 -08:00
|
|
|
"cmd/internal/src.Pos %s": "",
|
2017-03-06 19:43:21 -05:00
|
|
|
"cmd/internal/src.Pos %v": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
"error %v": "",
|
|
|
|
|
"float64 %.2f": "",
|
|
|
|
|
"float64 %.3f": "",
|
|
|
|
|
"float64 %.6g": "",
|
|
|
|
|
"float64 %g": "",
|
|
|
|
|
"int %-12d": "",
|
|
|
|
|
"int %-6d": "",
|
|
|
|
|
"int %-8o": "",
|
|
|
|
|
"int %6d": "",
|
|
|
|
|
"int %c": "",
|
|
|
|
|
"int %d": "",
|
|
|
|
|
"int %v": "",
|
|
|
|
|
"int %x": "",
|
|
|
|
|
"int16 %d": "",
|
|
|
|
|
"int16 %x": "",
|
|
|
|
|
"int32 %d": "",
|
|
|
|
|
"int32 %v": "",
|
|
|
|
|
"int32 %x": "",
|
|
|
|
|
"int64 %+d": "",
|
|
|
|
|
"int64 %-10d": "",
|
|
|
|
|
"int64 %X": "",
|
|
|
|
|
"int64 %d": "",
|
|
|
|
|
"int64 %v": "",
|
|
|
|
|
"int64 %x": "",
|
|
|
|
|
"int8 %d": "",
|
|
|
|
|
"int8 %x": "",
|
|
|
|
|
"interface{} %#v": "",
|
|
|
|
|
"interface{} %T": "",
|
|
|
|
|
"interface{} %q": "",
|
|
|
|
|
"interface{} %s": "",
|
|
|
|
|
"interface{} %v": "",
|
|
|
|
|
"map[*cmd/compile/internal/gc.Node]*cmd/compile/internal/ssa.Value %v": "",
|
2016-09-09 19:54:09 -07:00
|
|
|
"reflect.Type %s": "",
|
|
|
|
|
"rune %#U": "",
|
|
|
|
|
"rune %c": "",
|
2017-04-19 19:24:27 +01:00
|
|
|
"string %-*s": "",
|
2016-09-09 19:54:09 -07:00
|
|
|
"string %-16s": "",
|
|
|
|
|
"string %.*s": "",
|
|
|
|
|
"string %q": "",
|
|
|
|
|
"string %s": "",
|
|
|
|
|
"string %v": "",
|
|
|
|
|
"time.Duration %d": "",
|
|
|
|
|
"time.Duration %v": "",
|
|
|
|
|
"uint %04x": "",
|
2016-11-29 16:13:09 -08:00
|
|
|
"uint %5d": "",
|
2016-09-09 19:54:09 -07:00
|
|
|
"uint %d": "",
|
|
|
|
|
"uint16 %d": "",
|
|
|
|
|
"uint16 %v": "",
|
|
|
|
|
"uint16 %x": "",
|
|
|
|
|
"uint32 %d": "",
|
|
|
|
|
"uint32 %x": "",
|
|
|
|
|
"uint64 %08x": "",
|
|
|
|
|
"uint64 %d": "",
|
|
|
|
|
"uint64 %x": "",
|
|
|
|
|
"uint8 %d": "",
|
|
|
|
|
"uint8 %x": "",
|
|
|
|
|
"uintptr %d": "",
|
2016-09-08 21:39:33 -07:00
|
|
|
}
|