Compare commits
12 Commits
master
...
release.r5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb10bce0c2 | ||
|
|
ff5182390a | ||
|
|
36d155b2b5 | ||
|
|
f86856b083 | ||
|
|
f12a1d38b2 | ||
|
|
3b32b3eb3d | ||
|
|
f70c7b2b63 | ||
|
|
01a1c91696 | ||
|
|
dbdc8698df | ||
|
|
47906598d8 | ||
|
|
0ea0d7b65c | ||
|
|
35f3007cf1 |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -14,6 +14,78 @@ hg pull
|
||||
hg update release.r<i>NN</i>
|
||||
</pre>
|
||||
|
||||
<h2 id="r58">r58 (released 2011/06/29)</h2>
|
||||
|
||||
<p>
|
||||
The r58 release corresponds to
|
||||
<code><a href="weekly.html#2011-06-09">weekly.2011-06-09</a></code>
|
||||
with additional bug fixes.
|
||||
This section highlights the most significant changes in this release.
|
||||
For a more detailed summary, see the
|
||||
<a href="weekly.html#2011-06-09">weekly release notes</a>.
|
||||
For complete information, see the
|
||||
<a href="http://code.google.com/p/go/source/list?r=release-branch.r58">Mercurial change list</a>.
|
||||
</p>
|
||||
|
||||
<h3 id="r58.lang">Language</h3>
|
||||
|
||||
<p>
|
||||
This release fixes a <a href="http://code.google.com/p/go/source/detail?r=b720749486e1">use of uninitialized memory in programs that misuse <code>goto</code></a>.
|
||||
</p>
|
||||
|
||||
<h3 id="r58.pkg">Packages</h3>
|
||||
|
||||
<p>
|
||||
As usual, <a href="/cmd/gofix/">gofix</a> will handle the bulk of the rewrites
|
||||
necessary for these changes to package APIs.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/http/">Package http</a> drops the <code>finalURL</code> return
|
||||
value from the <a href="/pkg/http/#Client.Get">Client.Get</a> method. The value
|
||||
is now available via the new <code>Request</code> field on <a
|
||||
href="/pkg/http/#Response">http.Response</a>.
|
||||
Most instances of the type map[string][]string in have been
|
||||
replaced with the new <a href="/pkg/http/#Values">Values</a> type.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/exec/">Package exec</a> has been redesigned with a more
|
||||
convenient and succinct API.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/strconv/">Package strconv</a>'s <a href="/pkg/strconv/#Quote">Quote</a>
|
||||
function now escapes only those Unicode code points not classified as printable
|
||||
by <a href="/pkg/unicode/#IsPrint">unicode.IsPrint</a>.
|
||||
Previously Quote would escape all non-ASCII characters.
|
||||
This also affects the <a href="/pkg/fmt/">fmt</a> package's <code>"%q"</code>
|
||||
formatting directive. The previous quoting behavior is still available via
|
||||
strconv's new <a href="/pkg/strconv/#QuoteToASCII">QuoteToASCII</a> function.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/os/signal/">Package os/signal</a>'s
|
||||
<a href="/pkg/os/#Signal">Signal</a> and
|
||||
<a href="/pkg/os/#UnixSignal">UnixSignal</a> types have been moved to the
|
||||
<a href="/pkg/os/">os</a> package.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/pkg/image/draw/">Package image/draw</a> is the new name for
|
||||
<code>exp/draw</code>. The GUI-related code from <code>exp/draw</code> is now
|
||||
located in the <a href="/pkg/exp/gui/">exp/gui</a> package.
|
||||
</p>
|
||||
|
||||
<h3 id="r58.cmd">Tools</h3>
|
||||
|
||||
<p>
|
||||
<a href="/cmd/goinstall/">Goinstall</a> now observes the GOPATH environment
|
||||
variable to build and install your own code and external libraries outside of
|
||||
the Go tree (and avoid writing Makefiles).
|
||||
</p>
|
||||
|
||||
|
||||
<h2 id="r57">r57 (released 2011/05/03)</h2>
|
||||
|
||||
<p>
|
||||
@@ -162,6 +234,7 @@ For other uses, see the <a href="/pkg/runtime/pprof/">runtime/pprof</a> document
|
||||
<h3 id="r57.minor">Minor revisions</h3>
|
||||
|
||||
<p>r57.1 fixes a <a href="http://code.google.com/p/go/source/detail?r=ff2bc62726e7145eb2ecc1e0f076998e4a8f86f0">nil pointer dereference in http.FormFile</a>.</p>
|
||||
<p>r57.2 fixes a <a href="http://code.google.com/p/go/source/detail?r=063b0ff67d8277df03c956208abc068076818dae">use of uninitialized memory in programs that misuse <code>goto</code></a>.</p>
|
||||
|
||||
<h2 id="r56">r56 (released 2011/03/16)</h2>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ hg pull
|
||||
hg update weekly.<i>YYYY-MM-DD</i>
|
||||
</pre>
|
||||
|
||||
<h2 id="2011-06-09">2011-06-09</h2>
|
||||
<h2 id="2011-06-09">2011-06-09 (<a href="release.html#r58">base for r58</a>)</h2>
|
||||
|
||||
<pre>
|
||||
This release includes changes to the strconv, http, and exp/draw packages.
|
||||
|
||||
@@ -23,6 +23,17 @@ concepts: syntax, types, allocation, constants, I/O, sorting, printing,
|
||||
goroutines, and channels.
|
||||
</p>
|
||||
|
||||
<h3 id="course_notes">Course Notes</h3>
|
||||
<p>
|
||||
Slides from a 3-day course about the Go programming language.
|
||||
A more thorough introduction than the tutorial.
|
||||
</p>
|
||||
<ul>
|
||||
<li><a href="GoCourseDay1.pdf">Day 1: Basics</a> <small>[270KB PDF]</small>
|
||||
<li><a href="GoCourseDay2.pdf">Day 2: Types, Methods, Interfaces</a> <small>[270KB PDF]</small>
|
||||
<li><a href="GoCourseDay3.pdf">Day 3: Concurrency and Communication</a> <small>[180KB PDF]</small>
|
||||
</ul>
|
||||
|
||||
<h3 id="effective_go"><a href="effective_go.html">Effective Go</a></h3>
|
||||
<p>
|
||||
A document that gives tips for writing clear, idiomatic Go code.
|
||||
@@ -209,7 +220,7 @@ from Hoare’s 1978 paper to Go provides insight into how and why Go works as it
|
||||
does.
|
||||
</i></p>
|
||||
|
||||
<h3 id="emerging_go"><a href="talks/gofrontend-gcc-summit-2010.pdf">The Go frontend for GCC</a></h3>
|
||||
<h3 id="go_frontend_gcc"><a href="talks/gofrontend-gcc-summit-2010.pdf">The Go frontend for GCC</a></h3>
|
||||
<p>
|
||||
A description of the Go language frontend for gcc.
|
||||
Ian Lance Taylor's paper delivered at the GCC Summit 2010.
|
||||
|
||||
@@ -183,16 +183,6 @@ easier to understand what happens when things combine.
|
||||
|
||||
<h2 id="Usage">Usage</h2>
|
||||
|
||||
<h3 id="Who_should_use_the_language">
|
||||
Who should use the language?</h3>
|
||||
|
||||
<p>
|
||||
Go is an experiment. We hope adventurous users will give it a try and see
|
||||
if they enjoy it. Not every programmer
|
||||
will, but we hope enough will find satisfaction in the approach it
|
||||
offers to justify further development.
|
||||
</p>
|
||||
|
||||
<h3 id="Is_Google_using_go_internally"> Is Google using Go internally?</h3>
|
||||
|
||||
<p>
|
||||
@@ -598,6 +588,24 @@ the interface idea. Sometimes, though, they're necessary to resolve ambiguities
|
||||
among similar interfaces.
|
||||
</p>
|
||||
|
||||
<h3 id="convert_slice_of_interface">
|
||||
Can I convert a []T to an []interface{}?</h3>
|
||||
|
||||
<p>
|
||||
Not directly because they do not have the same representation in memory.
|
||||
It is necessary to copy the elements individually to the destination
|
||||
slice. This example converts a slice of <code>int</code> to a slice of
|
||||
<code>interface{}</code>:
|
||||
</p>
|
||||
|
||||
<pre>
|
||||
t := []int{1, 2, 3, 4}
|
||||
s := make([]interface{}, len(t))
|
||||
for i, v := range t {
|
||||
s[i] = v
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h2 id="values">Values</h2>
|
||||
|
||||
<h3 id="conversions">
|
||||
|
||||
@@ -10,8 +10,7 @@ After you've read this tutorial, you should look at
|
||||
which digs deeper into how the language is used and
|
||||
talks about the style and idioms of programming in Go.
|
||||
Also, slides from a 3-day course about Go are available.
|
||||
Although they're badly out of date, they provide some
|
||||
background and a lot of examples:
|
||||
They provide some background and a lot of examples:
|
||||
<a href='/doc/GoCourseDay1.pdf'>Day 1</a>,
|
||||
<a href='/doc/GoCourseDay2.pdf'>Day 2</a>,
|
||||
<a href='/doc/GoCourseDay3.pdf'>Day 3</a>.
|
||||
|
||||
@@ -11,8 +11,7 @@ After you've read this tutorial, you should look at
|
||||
which digs deeper into how the language is used and
|
||||
talks about the style and idioms of programming in Go.
|
||||
Also, slides from a 3-day course about Go are available.
|
||||
Although they're badly out of date, they provide some
|
||||
background and a lot of examples:
|
||||
They provide some background and a lot of examples:
|
||||
<a href='/doc/GoCourseDay1.pdf'>Day 1</a>,
|
||||
<a href='/doc/GoCourseDay2.pdf'>Day 2</a>,
|
||||
<a href='/doc/GoCourseDay3.pdf'>Day 3</a>.
|
||||
|
||||
@@ -124,6 +124,64 @@ newplist(void)
|
||||
return pl;
|
||||
}
|
||||
|
||||
void
|
||||
clearstk(void)
|
||||
{
|
||||
Plist *pl;
|
||||
Prog *p, *p1, *p2, *p3;
|
||||
Node dst, end, zero, con;
|
||||
|
||||
if(plast->firstpc->to.offset <= 0)
|
||||
return;
|
||||
|
||||
// reestablish context for inserting code
|
||||
// at beginning of function.
|
||||
pl = plast;
|
||||
p1 = pl->firstpc;
|
||||
p2 = p1->link;
|
||||
pc = mal(sizeof(*pc));
|
||||
clearp(pc);
|
||||
p1->link = pc;
|
||||
|
||||
// zero stack frame
|
||||
|
||||
// MOVW $4(SP), R1
|
||||
nodreg(&dst, types[tptr], 1);
|
||||
p = gins(AMOVW, N, &dst);
|
||||
p->from.type = D_CONST;
|
||||
p->from.reg = REGSP;
|
||||
p->from.offset = 4;
|
||||
|
||||
// MOVW $n(R1), R2
|
||||
nodreg(&end, types[tptr], 2);
|
||||
p = gins(AMOVW, N, &end);
|
||||
p->from.type = D_CONST;
|
||||
p->from.reg = 1;
|
||||
p->from.offset = p1->to.offset;
|
||||
|
||||
// MOVW $0, R3
|
||||
nodreg(&zero, types[TUINT32], 3);
|
||||
nodconst(&con, types[TUINT32], 0);
|
||||
gmove(&con, &zero);
|
||||
|
||||
// L:
|
||||
// MOVW.P R3, 0(R1) +4
|
||||
// CMP R1, R2
|
||||
// BNE L
|
||||
p = gins(AMOVW, &zero, &dst);
|
||||
p->to.type = D_OREG;
|
||||
p->to.offset = 4;
|
||||
p->scond |= C_PBIT;
|
||||
p3 = p;
|
||||
p = gins(ACMP, &dst, N);
|
||||
raddr(&end, p);
|
||||
patch(gbranch(ABNE, T), p3);
|
||||
|
||||
// continue with original code.
|
||||
gins(ANOP, N, N)->link = p2;
|
||||
pc = P;
|
||||
}
|
||||
|
||||
void
|
||||
gused(Node *n)
|
||||
{
|
||||
|
||||
@@ -120,6 +120,44 @@ newplist(void)
|
||||
return pl;
|
||||
}
|
||||
|
||||
void
|
||||
clearstk(void)
|
||||
{
|
||||
Plist *pl;
|
||||
Prog *p1, *p2;
|
||||
Node sp, di, cx, con, ax;
|
||||
|
||||
if((uint32)plast->firstpc->to.offset <= 0)
|
||||
return;
|
||||
|
||||
// reestablish context for inserting code
|
||||
// at beginning of function.
|
||||
pl = plast;
|
||||
p1 = pl->firstpc;
|
||||
p2 = p1->link;
|
||||
pc = mal(sizeof(*pc));
|
||||
clearp(pc);
|
||||
p1->link = pc;
|
||||
|
||||
// zero stack frame
|
||||
nodreg(&sp, types[tptr], D_SP);
|
||||
nodreg(&di, types[tptr], D_DI);
|
||||
nodreg(&cx, types[TUINT64], D_CX);
|
||||
nodconst(&con, types[TUINT64], (uint32)p1->to.offset / widthptr);
|
||||
gins(ACLD, N, N);
|
||||
gins(AMOVQ, &sp, &di);
|
||||
gins(AMOVQ, &con, &cx);
|
||||
nodconst(&con, types[TUINT64], 0);
|
||||
nodreg(&ax, types[TUINT64], D_AX);
|
||||
gins(AMOVQ, &con, &ax);
|
||||
gins(AREP, N, N);
|
||||
gins(ASTOSQ, N, N);
|
||||
|
||||
// continue with original code.
|
||||
gins(ANOP, N, N)->link = p2;
|
||||
pc = P;
|
||||
}
|
||||
|
||||
void
|
||||
gused(Node *n)
|
||||
{
|
||||
|
||||
@@ -122,6 +122,44 @@ newplist(void)
|
||||
return pl;
|
||||
}
|
||||
|
||||
void
|
||||
clearstk(void)
|
||||
{
|
||||
Plist *pl;
|
||||
Prog *p1, *p2;
|
||||
Node sp, di, cx, con, ax;
|
||||
|
||||
if(plast->firstpc->to.offset <= 0)
|
||||
return;
|
||||
|
||||
// reestablish context for inserting code
|
||||
// at beginning of function.
|
||||
pl = plast;
|
||||
p1 = pl->firstpc;
|
||||
p2 = p1->link;
|
||||
pc = mal(sizeof(*pc));
|
||||
clearp(pc);
|
||||
p1->link = pc;
|
||||
|
||||
// zero stack frame
|
||||
nodreg(&sp, types[tptr], D_SP);
|
||||
nodreg(&di, types[tptr], D_DI);
|
||||
nodreg(&cx, types[TUINT32], D_CX);
|
||||
nodconst(&con, types[TUINT32], p1->to.offset / widthptr);
|
||||
gins(ACLD, N, N);
|
||||
gins(AMOVL, &sp, &di);
|
||||
gins(AMOVL, &con, &cx);
|
||||
nodconst(&con, types[TUINT32], 0);
|
||||
nodreg(&ax, types[TUINT32], D_AX);
|
||||
gins(AMOVL, &con, &ax);
|
||||
gins(AREP, N, N);
|
||||
gins(ASTOSL, N, N);
|
||||
|
||||
// continue with original code.
|
||||
gins(ANOP, N, N)->link = p2;
|
||||
pc = P;
|
||||
}
|
||||
|
||||
void
|
||||
gused(Node *n)
|
||||
{
|
||||
|
||||
@@ -1241,9 +1241,14 @@ funccompile(Node *n, int isclosure)
|
||||
stksize = 0;
|
||||
dclcontext = PAUTO;
|
||||
funcdepth = n->funcdepth + 1;
|
||||
hasgoto = 0;
|
||||
compile(n);
|
||||
if(hasgoto)
|
||||
clearstk();
|
||||
curfn = nil;
|
||||
funcdepth = 0;
|
||||
dclcontext = PEXTERN;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -209,6 +209,7 @@ gen(Node *n)
|
||||
break;
|
||||
|
||||
case OGOTO:
|
||||
hasgoto = 1;
|
||||
newlab(OGOTO, n, N);
|
||||
gjmp(P);
|
||||
break;
|
||||
|
||||
@@ -1255,3 +1255,6 @@ void zhist(Biobuf *b, int line, vlong offset);
|
||||
void zname(Biobuf *b, Sym *s, int t);
|
||||
void data(void);
|
||||
void text(void);
|
||||
|
||||
EXTERN int hasgoto;
|
||||
void clearstk(void);
|
||||
|
||||
@@ -14,6 +14,7 @@ GOFILES=\
|
||||
httpserver.go\
|
||||
procattr.go\
|
||||
reflect.go\
|
||||
signal.go\
|
||||
typecheck.go\
|
||||
|
||||
include ../../Make.cmd
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"go/token"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type fix struct {
|
||||
@@ -258,13 +259,28 @@ func walkBeforeAfter(x interface{}, before, after func(interface{})) {
|
||||
|
||||
// imports returns true if f imports path.
|
||||
func imports(f *ast.File, path string) bool {
|
||||
return importSpec(f, path) != nil
|
||||
}
|
||||
|
||||
// importSpec returns the import spec if f imports path,
|
||||
// or nil otherwise.
|
||||
func importSpec(f *ast.File, path string) *ast.ImportSpec {
|
||||
for _, s := range f.Imports {
|
||||
t, err := strconv.Unquote(s.Path.Value)
|
||||
if err == nil && t == path {
|
||||
return true
|
||||
if importPath(s) == path {
|
||||
return s
|
||||
}
|
||||
}
|
||||
return false
|
||||
return nil
|
||||
}
|
||||
|
||||
// importPath returns the unquoted import path of s,
|
||||
// or "" if the path is not properly quoted.
|
||||
func importPath(s *ast.ImportSpec) string {
|
||||
t, err := strconv.Unquote(s.Path.Value)
|
||||
if err == nil {
|
||||
return t
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// isPkgDot returns true if t is the expression "pkg.name"
|
||||
@@ -420,3 +436,138 @@ func newPkgDot(pos token.Pos, pkg, name string) ast.Expr {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// addImport adds the import path to the file f, if absent.
|
||||
func addImport(f *ast.File, path string) {
|
||||
if imports(f, path) {
|
||||
return
|
||||
}
|
||||
|
||||
newImport := &ast.ImportSpec{
|
||||
Path: &ast.BasicLit{
|
||||
Kind: token.STRING,
|
||||
Value: strconv.Quote(path),
|
||||
},
|
||||
}
|
||||
|
||||
var impdecl *ast.GenDecl
|
||||
|
||||
// Find an import decl to add to.
|
||||
for _, decl := range f.Decls {
|
||||
gen, ok := decl.(*ast.GenDecl)
|
||||
|
||||
if ok && gen.Tok == token.IMPORT {
|
||||
impdecl = gen
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// No import decl found. Add one.
|
||||
if impdecl == nil {
|
||||
impdecl = &ast.GenDecl{
|
||||
Tok: token.IMPORT,
|
||||
}
|
||||
f.Decls = append(f.Decls, nil)
|
||||
copy(f.Decls[1:], f.Decls)
|
||||
f.Decls[0] = impdecl
|
||||
}
|
||||
|
||||
// Ensure the import decl has parentheses, if needed.
|
||||
if len(impdecl.Specs) > 0 && !impdecl.Lparen.IsValid() {
|
||||
impdecl.Lparen = impdecl.Pos()
|
||||
}
|
||||
|
||||
// Assume the import paths are alphabetically ordered.
|
||||
// If they are not, the result is ugly, but legal.
|
||||
insertAt := len(impdecl.Specs) // default to end of specs
|
||||
for i, spec := range impdecl.Specs {
|
||||
impspec := spec.(*ast.ImportSpec)
|
||||
if importPath(impspec) > path {
|
||||
insertAt = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
impdecl.Specs = append(impdecl.Specs, nil)
|
||||
copy(impdecl.Specs[insertAt+1:], impdecl.Specs[insertAt:])
|
||||
impdecl.Specs[insertAt] = newImport
|
||||
|
||||
f.Imports = append(f.Imports, newImport)
|
||||
}
|
||||
|
||||
// deleteImport deletes the import path from the file f, if present.
|
||||
func deleteImport(f *ast.File, path string) {
|
||||
oldImport := importSpec(f, path)
|
||||
|
||||
// Find the import node that imports path, if any.
|
||||
for i, decl := range f.Decls {
|
||||
gen, ok := decl.(*ast.GenDecl)
|
||||
if !ok || gen.Tok != token.IMPORT {
|
||||
continue
|
||||
}
|
||||
for j, spec := range gen.Specs {
|
||||
impspec := spec.(*ast.ImportSpec)
|
||||
|
||||
if oldImport != impspec {
|
||||
continue
|
||||
}
|
||||
|
||||
// We found an import spec that imports path.
|
||||
// Delete it.
|
||||
copy(gen.Specs[j:], gen.Specs[j+1:])
|
||||
gen.Specs = gen.Specs[:len(gen.Specs)-1]
|
||||
|
||||
// If this was the last import spec in this decl,
|
||||
// delete the decl, too.
|
||||
if len(gen.Specs) == 0 {
|
||||
copy(f.Decls[i:], f.Decls[i+1:])
|
||||
f.Decls = f.Decls[:len(f.Decls)-1]
|
||||
} else if len(gen.Specs) == 1 {
|
||||
gen.Lparen = token.NoPos // drop parens
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Delete it from f.Imports.
|
||||
for i, imp := range f.Imports {
|
||||
if imp == oldImport {
|
||||
copy(f.Imports[i:], f.Imports[i+1:])
|
||||
f.Imports = f.Imports[:len(f.Imports)-1]
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func usesImport(f *ast.File, path string) (used bool) {
|
||||
spec := importSpec(f, path)
|
||||
if spec == nil {
|
||||
return
|
||||
}
|
||||
|
||||
name := spec.Name.String()
|
||||
switch name {
|
||||
case "<nil>":
|
||||
// If the package name is not explicitly specified,
|
||||
// make an educated guess. This is not guaranteed to be correct.
|
||||
lastSlash := strings.LastIndex(path, "/")
|
||||
if lastSlash == -1 {
|
||||
name = path
|
||||
} else {
|
||||
name = path[lastSlash+1:]
|
||||
}
|
||||
case "_", ".":
|
||||
// Not sure if this import is used - err on the side of caution.
|
||||
return true
|
||||
}
|
||||
|
||||
walk(f, func(n interface{}) {
|
||||
sel, ok := n.(*ast.SelectorExpr)
|
||||
if ok && isTopName(sel.X, name) {
|
||||
used = true
|
||||
}
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
49
src/cmd/gofix/signal.go
Normal file
49
src/cmd/gofix/signal.go
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func init() {
|
||||
register(fix{
|
||||
"signal",
|
||||
signal,
|
||||
`Adapt code to types moved from os/signal to signal.
|
||||
|
||||
http://codereview.appspot.com/4437091
|
||||
`,
|
||||
})
|
||||
}
|
||||
|
||||
func signal(f *ast.File) (fixed bool) {
|
||||
if !imports(f, "os/signal") {
|
||||
return
|
||||
}
|
||||
|
||||
walk(f, func(n interface{}) {
|
||||
s, ok := n.(*ast.SelectorExpr)
|
||||
|
||||
if !ok || !isTopName(s.X, "signal") {
|
||||
return
|
||||
}
|
||||
|
||||
sel := s.Sel.String()
|
||||
if sel == "Signal" || sel == "UnixSignal" || strings.HasPrefix(sel, "SIG") {
|
||||
s.X = &ast.Ident{Name: "os"}
|
||||
fixed = true
|
||||
}
|
||||
})
|
||||
|
||||
if fixed {
|
||||
addImport(f, "os")
|
||||
if !usesImport(f, "os/signal") {
|
||||
deleteImport(f, "os/signal")
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
96
src/cmd/gofix/signal_test.go
Normal file
96
src/cmd/gofix/signal_test.go
Normal file
@@ -0,0 +1,96 @@
|
||||
// Copyright 2011 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.
|
||||
|
||||
package main
|
||||
|
||||
func init() {
|
||||
addTestCases(signalTests)
|
||||
}
|
||||
|
||||
var signalTests = []testCase{
|
||||
{
|
||||
Name: "signal.0",
|
||||
In: `package main
|
||||
|
||||
import (
|
||||
_ "a"
|
||||
"os/signal"
|
||||
_ "z"
|
||||
)
|
||||
|
||||
type T1 signal.UnixSignal
|
||||
type T2 signal.Signal
|
||||
|
||||
func f() {
|
||||
_ = signal.SIGHUP
|
||||
_ = signal.Incoming
|
||||
}
|
||||
`,
|
||||
Out: `package main
|
||||
|
||||
import (
|
||||
_ "a"
|
||||
"os"
|
||||
"os/signal"
|
||||
_ "z"
|
||||
)
|
||||
|
||||
type T1 os.UnixSignal
|
||||
type T2 os.Signal
|
||||
|
||||
func f() {
|
||||
_ = os.SIGHUP
|
||||
_ = signal.Incoming
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "signal.1",
|
||||
In: `package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
)
|
||||
|
||||
func f() {
|
||||
var _ os.Error
|
||||
_ = signal.SIGHUP
|
||||
}
|
||||
`,
|
||||
Out: `package main
|
||||
|
||||
import "os"
|
||||
|
||||
|
||||
func f() {
|
||||
var _ os.Error
|
||||
_ = os.SIGHUP
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "signal.2",
|
||||
In: `package main
|
||||
|
||||
import "os"
|
||||
import "os/signal"
|
||||
|
||||
func f() {
|
||||
var _ os.Error
|
||||
_ = signal.SIGHUP
|
||||
}
|
||||
`,
|
||||
Out: `package main
|
||||
|
||||
import "os"
|
||||
|
||||
|
||||
func f() {
|
||||
var _ os.Error
|
||||
_ = os.SIGHUP
|
||||
}
|
||||
`,
|
||||
},
|
||||
}
|
||||
@@ -1804,7 +1804,7 @@ mkvarname(char* name, int da)
|
||||
|
||||
// flush previous compilation unit.
|
||||
static void
|
||||
flushunit(DWDie *dwinfo, vlong pc, vlong unitstart)
|
||||
flushunit(DWDie *dwinfo, vlong pc, vlong unitstart, int32 header_length)
|
||||
{
|
||||
vlong here;
|
||||
|
||||
@@ -1820,7 +1820,9 @@ flushunit(DWDie *dwinfo, vlong pc, vlong unitstart)
|
||||
|
||||
here = cpos();
|
||||
seek(cout, unitstart, 0);
|
||||
LPUT(here - unitstart - sizeof(int32));
|
||||
LPUT(here - unitstart - sizeof(int32)); // unit_length
|
||||
WPUT(3); // dwarf version
|
||||
LPUT(header_length); // header lenght starting here
|
||||
cflush();
|
||||
seek(cout, here, 0);
|
||||
}
|
||||
@@ -1832,7 +1834,7 @@ writelines(void)
|
||||
Prog *q;
|
||||
Sym *s;
|
||||
Auto *a;
|
||||
vlong unitstart, offs;
|
||||
vlong unitstart, headerend, offs;
|
||||
vlong pc, epc, lc, llc, lline;
|
||||
int currfile;
|
||||
int i, lang, da, dt;
|
||||
@@ -1842,6 +1844,7 @@ writelines(void)
|
||||
char *n, *nn;
|
||||
|
||||
unitstart = -1;
|
||||
headerend = -1;
|
||||
pc = 0;
|
||||
epc = 0;
|
||||
lc = 1;
|
||||
@@ -1859,7 +1862,7 @@ writelines(void)
|
||||
// we're entering a new compilation unit
|
||||
|
||||
if (inithist(s->autom)) {
|
||||
flushunit(dwinfo, epc, unitstart);
|
||||
flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10);
|
||||
unitstart = cpos();
|
||||
|
||||
if(debug['v'] > 1) {
|
||||
@@ -1880,10 +1883,10 @@ writelines(void)
|
||||
|
||||
// Write .debug_line Line Number Program Header (sec 6.2.4)
|
||||
// Fields marked with (*) must be changed for 64-bit dwarf
|
||||
LPUT(0); // unit_length (*), will be filled in later.
|
||||
LPUT(0); // unit_length (*), will be filled in by flushunit.
|
||||
WPUT(3); // dwarf version (appendix F)
|
||||
LPUT(11); // header_length (*), starting here.
|
||||
|
||||
LPUT(0); // header_length (*), filled in by flushunit.
|
||||
// cpos == unitstart + 4 + 2 + 4
|
||||
cput(1); // minimum_instruction_length
|
||||
cput(1); // default_is_stmt
|
||||
cput(LINE_BASE); // line_base
|
||||
@@ -1894,17 +1897,15 @@ writelines(void)
|
||||
cput(1); // standard_opcode_lengths[3]
|
||||
cput(1); // standard_opcode_lengths[4]
|
||||
cput(0); // include_directories (empty)
|
||||
cput(0); // file_names (empty) (emitted by DW_LNE's below)
|
||||
// header_length ends here.
|
||||
|
||||
for (i=1; i < histfilesize; i++) {
|
||||
cput(0); // start extended opcode
|
||||
uleb128put(1 + strlen(histfile[i]) + 4);
|
||||
cput(DW_LNE_define_file);
|
||||
strnput(histfile[i], strlen(histfile[i]) + 4);
|
||||
// 4 zeros: the string termination + 3 fields.
|
||||
}
|
||||
|
||||
cput(0); // terminate file_names.
|
||||
headerend = cpos();
|
||||
|
||||
pc = s->text->pc;
|
||||
epc = pc;
|
||||
currfile = 1;
|
||||
@@ -2009,7 +2010,7 @@ writelines(void)
|
||||
dwfunc->hash = nil;
|
||||
}
|
||||
|
||||
flushunit(dwinfo, epc, unitstart);
|
||||
flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10);
|
||||
linesize = cpos() - lineo;
|
||||
}
|
||||
|
||||
|
||||
@@ -150,7 +150,8 @@ pprof [options] <profile>
|
||||
The /<service> can be $HEAP_PAGE, $PROFILE_PAGE, /pprof/pmuprofile,
|
||||
$GROWTH_PAGE, $CONTENTION_PAGE, /pprof/wall,
|
||||
or /pprof/filteredprofile.
|
||||
For instance: "pprof http://myserver.com:80$HEAP_PAGE".
|
||||
For instance:
|
||||
pprof http://myserver.com:80$HEAP_PAGE
|
||||
If /<service> is omitted, the service defaults to $PROFILE_PAGE (cpu profiling).
|
||||
pprof --symbols <program>
|
||||
Maps addresses to symbol names. In this mode, stdin should be a
|
||||
@@ -532,7 +533,7 @@ sub Init() {
|
||||
ConfigureObjTools($main::prog)
|
||||
}
|
||||
|
||||
# Break the opt_list_prefix into the prefix_list array
|
||||
# Break the opt_lib_prefix into the prefix_list array
|
||||
@prefix_list = split (',', $main::opt_lib_prefix);
|
||||
|
||||
# Remove trailing / from the prefixes, in the list to prevent
|
||||
@@ -626,7 +627,7 @@ sub Main() {
|
||||
if ($main::opt_disasm) {
|
||||
PrintDisassembly($libs, $flat, $cumulative, $main::opt_disasm, $total);
|
||||
} elsif ($main::opt_list) {
|
||||
PrintListing($libs, $flat, $cumulative, $main::opt_list);
|
||||
PrintListing($total, $libs, $flat, $cumulative, $main::opt_list, 0);
|
||||
} elsif ($main::opt_text) {
|
||||
# Make sure the output is empty when have nothing to report
|
||||
# (only matters when --heapcheck is given but we must be
|
||||
@@ -814,7 +815,7 @@ sub InteractiveCommand {
|
||||
my $ignore;
|
||||
($routine, $ignore) = ParseInteractiveArgs($3);
|
||||
|
||||
my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore);
|
||||
my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
|
||||
my $reduced = ReduceProfile($symbols, $profile);
|
||||
|
||||
# Get derived profiles
|
||||
@@ -841,21 +842,22 @@ sub InteractiveCommand {
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (m/^\s*list\s*(.+)/) {
|
||||
if (m/^\s*(web)?list\s*(.+)/) {
|
||||
my $html = (defined($1) && ($1 eq "web"));
|
||||
$main::opt_list = 1;
|
||||
|
||||
my $routine;
|
||||
my $ignore;
|
||||
($routine, $ignore) = ParseInteractiveArgs($1);
|
||||
($routine, $ignore) = ParseInteractiveArgs($2);
|
||||
|
||||
my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore);
|
||||
my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
|
||||
my $reduced = ReduceProfile($symbols, $profile);
|
||||
|
||||
# Get derived profiles
|
||||
my $flat = FlatProfile($reduced);
|
||||
my $cumulative = CumulativeProfile($reduced);
|
||||
|
||||
PrintListing($libs, $flat, $cumulative, $routine);
|
||||
PrintListing($total, $libs, $flat, $cumulative, $routine, $html);
|
||||
return 1;
|
||||
}
|
||||
if (m/^\s*disasm\s*(.+)/) {
|
||||
@@ -866,7 +868,7 @@ sub InteractiveCommand {
|
||||
($routine, $ignore) = ParseInteractiveArgs($1);
|
||||
|
||||
# Process current profile to account for various settings
|
||||
my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore);
|
||||
my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
|
||||
my $reduced = ReduceProfile($symbols, $profile);
|
||||
|
||||
# Get derived profiles
|
||||
@@ -890,7 +892,7 @@ sub InteractiveCommand {
|
||||
($focus, $ignore) = ParseInteractiveArgs($2);
|
||||
|
||||
# Process current profile to account for various settings
|
||||
my $profile = ProcessProfile($orig_profile, $symbols, $focus, $ignore);
|
||||
my $profile = ProcessProfile($total, $orig_profile, $symbols, $focus, $ignore);
|
||||
my $reduced = ReduceProfile($symbols, $profile);
|
||||
|
||||
# Get derived profiles
|
||||
@@ -916,6 +918,7 @@ sub InteractiveCommand {
|
||||
|
||||
|
||||
sub ProcessProfile {
|
||||
my $total_count = shift;
|
||||
my $orig_profile = shift;
|
||||
my $symbols = shift;
|
||||
my $focus = shift;
|
||||
@@ -923,7 +926,6 @@ sub ProcessProfile {
|
||||
|
||||
# Process current profile to account for various settings
|
||||
my $profile = $orig_profile;
|
||||
my $total_count = TotalProfile($profile);
|
||||
printf("Total: %s %s\n", Unparse($total_count), Units());
|
||||
if ($focus ne '') {
|
||||
$profile = FocusProfile($symbols, $profile, $focus);
|
||||
@@ -970,6 +972,11 @@ Commands:
|
||||
list [routine_regexp] [-ignore1] [-ignore2]
|
||||
Show source listing of routines whose names match "routine_regexp"
|
||||
|
||||
weblist [routine_regexp] [-ignore1] [-ignore2]
|
||||
Displays a source listing of routines whose names match "routine_regexp"
|
||||
in a web browser. You can click on source lines to view the
|
||||
corresponding disassembly.
|
||||
|
||||
top [--cum] [-ignore1] [-ignore2]
|
||||
top20 [--cum] [-ignore1] [-ignore2]
|
||||
top37 [--cum] [-ignore1] [-ignore2]
|
||||
@@ -1144,7 +1151,7 @@ sub PrintText {
|
||||
$sym);
|
||||
}
|
||||
$lines++;
|
||||
last if ($line_limit >= 0 && $lines > $line_limit);
|
||||
last if ($line_limit >= 0 && $lines >= $line_limit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1291,11 +1298,32 @@ sub ByName {
|
||||
|
||||
# Print source-listing for all all routines that match $main::opt_list
|
||||
sub PrintListing {
|
||||
my $total = shift;
|
||||
my $libs = shift;
|
||||
my $flat = shift;
|
||||
my $cumulative = shift;
|
||||
my $list_opts = shift;
|
||||
my $html = shift;
|
||||
|
||||
my $output = \*STDOUT;
|
||||
my $fname = "";
|
||||
|
||||
|
||||
if ($html) {
|
||||
# Arrange to write the output to a temporary file
|
||||
$fname = TempName($main::next_tmpfile, "html");
|
||||
$main::next_tmpfile++;
|
||||
if (!open(TEMP, ">$fname")) {
|
||||
print STDERR "$fname: $!\n";
|
||||
return;
|
||||
}
|
||||
$output = \*TEMP;
|
||||
print $output HtmlListingHeader();
|
||||
printf $output ("<div class=\"legend\">%s<br>Total: %s %s</div>\n",
|
||||
$main::prog, Unparse($total), Units());
|
||||
}
|
||||
|
||||
my $listed = 0;
|
||||
foreach my $lib (@{$libs}) {
|
||||
my $symbol_table = GetProcedureBoundaries($lib->[0], $list_opts);
|
||||
my $offset = AddressSub($lib->[1], $lib->[3]);
|
||||
@@ -1307,15 +1335,98 @@ sub PrintListing {
|
||||
my $addr = AddressAdd($start_addr, $offset);
|
||||
for (my $i = 0; $i < $length; $i++) {
|
||||
if (defined($cumulative->{$addr})) {
|
||||
PrintSource($lib->[0], $offset,
|
||||
$routine, $flat, $cumulative,
|
||||
$start_addr, $end_addr);
|
||||
$listed += PrintSource(
|
||||
$lib->[0], $offset,
|
||||
$routine, $flat, $cumulative,
|
||||
$start_addr, $end_addr,
|
||||
$html,
|
||||
$output);
|
||||
last;
|
||||
}
|
||||
$addr = AddressInc($addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($html) {
|
||||
if ($listed > 0) {
|
||||
print $output HtmlListingFooter();
|
||||
close($output);
|
||||
RunWeb($fname);
|
||||
} else {
|
||||
close($output);
|
||||
unlink($fname);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub HtmlListingHeader {
|
||||
return <<'EOF';
|
||||
<DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Pprof listing</title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.5em;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.legend {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
.line {
|
||||
color: #aaaaaa;
|
||||
}
|
||||
.livesrc {
|
||||
color: #0000ff;
|
||||
cursor: pointer;
|
||||
}
|
||||
.livesrc:hover {
|
||||
background-color: #cccccc;
|
||||
}
|
||||
.asm {
|
||||
color: #888888;
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
function pprof_toggle_asm(e) {
|
||||
var target;
|
||||
if (!e) e = window.event;
|
||||
if (e.target) target = e.target;
|
||||
else if (e.srcElement) target = e.srcElement;
|
||||
|
||||
if (target && target.className == "livesrc") {
|
||||
var asm = target.nextSibling;
|
||||
if (asm && asm.className == "asm") {
|
||||
asm.style.display = (asm.style.display == "block" ? "none" : "block");
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
EOF
|
||||
}
|
||||
|
||||
sub HtmlListingFooter {
|
||||
return <<'EOF';
|
||||
</body>
|
||||
</html>
|
||||
EOF
|
||||
}
|
||||
|
||||
sub HtmlEscape {
|
||||
my $text = shift;
|
||||
$text =~ s/&/&/g;
|
||||
$text =~ s/</</g;
|
||||
$text =~ s/>/>/g;
|
||||
return $text;
|
||||
}
|
||||
|
||||
# Returns the indentation of the line, if it has any non-whitespace
|
||||
@@ -1338,6 +1449,8 @@ sub PrintSource {
|
||||
my $cumulative = shift;
|
||||
my $start_addr = shift;
|
||||
my $end_addr = shift;
|
||||
my $html = shift;
|
||||
my $output = shift;
|
||||
|
||||
# Disassemble all instructions (just to get line numbers)
|
||||
my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
|
||||
@@ -1353,7 +1466,7 @@ sub PrintSource {
|
||||
}
|
||||
if (!defined($filename)) {
|
||||
print STDERR "no filename found in $routine\n";
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Hack 2: assume that the largest line number from $filename is the
|
||||
@@ -1386,7 +1499,7 @@ sub PrintSource {
|
||||
{
|
||||
if (!open(FILE, "<$filename")) {
|
||||
print STDERR "$filename: $!\n";
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
my $l = 0;
|
||||
my $first_indentation = -1;
|
||||
@@ -1414,12 +1527,21 @@ sub PrintSource {
|
||||
# Assign all samples to the range $firstline,$lastline,
|
||||
# Hack 4: If an instruction does not occur in the range, its samples
|
||||
# are moved to the next instruction that occurs in the range.
|
||||
my $samples1 = {};
|
||||
my $samples2 = {};
|
||||
my $running1 = 0; # Unassigned flat counts
|
||||
my $running2 = 0; # Unassigned cumulative counts
|
||||
my $total1 = 0; # Total flat counts
|
||||
my $total2 = 0; # Total cumulative counts
|
||||
my $samples1 = {}; # Map from line number to flat count
|
||||
my $samples2 = {}; # Map from line number to cumulative count
|
||||
my $running1 = 0; # Unassigned flat counts
|
||||
my $running2 = 0; # Unassigned cumulative counts
|
||||
my $total1 = 0; # Total flat counts
|
||||
my $total2 = 0; # Total cumulative counts
|
||||
my %disasm = (); # Map from line number to disassembly
|
||||
my $running_disasm = ""; # Unassigned disassembly
|
||||
my $skip_marker = "---\n";
|
||||
if ($html) {
|
||||
$skip_marker = "";
|
||||
for (my $l = $firstline; $l <= $lastline; $l++) {
|
||||
$disasm{$l} = "";
|
||||
}
|
||||
}
|
||||
foreach my $e (@instructions) {
|
||||
# Add up counts for all address that fall inside this instruction
|
||||
my $c1 = 0;
|
||||
@@ -1428,6 +1550,15 @@ sub PrintSource {
|
||||
$c1 += GetEntry($flat, $a);
|
||||
$c2 += GetEntry($cumulative, $a);
|
||||
}
|
||||
|
||||
if ($html) {
|
||||
$running_disasm .= sprintf(" %6s %6s \t\t%8s: %s\n",
|
||||
HtmlPrintNumber($c1),
|
||||
HtmlPrintNumber($c2),
|
||||
$e->[0],
|
||||
CleanDisassembly($e->[3]));
|
||||
}
|
||||
|
||||
$running1 += $c1;
|
||||
$running2 += $c2;
|
||||
$total1 += $c1;
|
||||
@@ -1442,6 +1573,10 @@ sub PrintSource {
|
||||
AddEntry($samples2, $line, $running2);
|
||||
$running1 = 0;
|
||||
$running2 = 0;
|
||||
if ($html) {
|
||||
$disasm{$line} .= $running_disasm;
|
||||
$running_disasm = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1449,16 +1584,28 @@ sub PrintSource {
|
||||
AddEntry($samples1, $lastline, $running1);
|
||||
AddEntry($samples2, $lastline, $running2);
|
||||
|
||||
printf("ROUTINE ====================== %s in %s\n" .
|
||||
"%6s %6s Total %s (flat / cumulative)\n",
|
||||
ShortFunctionName($routine),
|
||||
$filename,
|
||||
Units(),
|
||||
Unparse($total1),
|
||||
Unparse($total2));
|
||||
if ($html) {
|
||||
printf $output (
|
||||
"<h1>%s</h1>%s\n<pre onClick=\"pprof_toggle_asm()\">\n" .
|
||||
"Total:%6s %6s (flat / cumulative %s)\n",
|
||||
HtmlEscape(ShortFunctionName($routine)),
|
||||
HtmlEscape($filename),
|
||||
Unparse($total1),
|
||||
Unparse($total2),
|
||||
Units());
|
||||
} else {
|
||||
printf $output (
|
||||
"ROUTINE ====================== %s in %s\n" .
|
||||
"%6s %6s Total %s (flat / cumulative)\n",
|
||||
ShortFunctionName($routine),
|
||||
$filename,
|
||||
Unparse($total1),
|
||||
Unparse($total2),
|
||||
Units());
|
||||
}
|
||||
if (!open(FILE, "<$filename")) {
|
||||
print STDERR "$filename: $!\n";
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
my $l = 0;
|
||||
while (<FILE>) {
|
||||
@@ -1468,16 +1615,47 @@ sub PrintSource {
|
||||
(($l <= $oldlastline + 5) || ($l <= $lastline))) {
|
||||
chop;
|
||||
my $text = $_;
|
||||
if ($l == $firstline) { printf("---\n"); }
|
||||
printf("%6s %6s %4d: %s\n",
|
||||
UnparseAlt(GetEntry($samples1, $l)),
|
||||
UnparseAlt(GetEntry($samples2, $l)),
|
||||
$l,
|
||||
$text);
|
||||
if ($l == $lastline) { printf("---\n"); }
|
||||
if ($l == $firstline) { print $output $skip_marker; }
|
||||
my $n1 = GetEntry($samples1, $l);
|
||||
my $n2 = GetEntry($samples2, $l);
|
||||
if ($html) {
|
||||
my $dis = $disasm{$l};
|
||||
if (!defined($dis) || $n1 + $n2 == 0) {
|
||||
# No samples/disassembly for this source line
|
||||
printf $output (
|
||||
"<span class=\"line\">%5d</span> " .
|
||||
"<span class=\"deadsrc\">%6s %6s %s</span>\n",
|
||||
$l,
|
||||
HtmlPrintNumber($n1),
|
||||
HtmlPrintNumber($n2),
|
||||
HtmlEscape($text));
|
||||
} else {
|
||||
printf $output (
|
||||
"<span class=\"line\">%5d</span> " .
|
||||
"<span class=\"livesrc\">%6s %6s %s</span>" .
|
||||
"<span class=\"asm\">%s</span>\n",
|
||||
$l,
|
||||
HtmlPrintNumber($n1),
|
||||
HtmlPrintNumber($n2),
|
||||
HtmlEscape($text),
|
||||
HtmlEscape($dis));
|
||||
}
|
||||
} else {
|
||||
printf $output(
|
||||
"%6s %6s %4d: %s\n",
|
||||
UnparseAlt($n1),
|
||||
UnparseAlt($n2),
|
||||
$l,
|
||||
$text);
|
||||
}
|
||||
if ($l == $lastline) { print $output $skip_marker; }
|
||||
};
|
||||
}
|
||||
close(FILE);
|
||||
if ($html) {
|
||||
print $output "</pre>\n";
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Return the source line for the specified file/linenumber.
|
||||
@@ -1625,16 +1803,11 @@ sub PrintDisassembledFunction {
|
||||
$address =~ s/^0x//;
|
||||
$address =~ s/^0*//;
|
||||
|
||||
# Trim symbols
|
||||
my $d = $e->[3];
|
||||
while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax)
|
||||
while ($d =~ s/(\w+)<[^<>]*>/$1/g) { } # Remove template arguments
|
||||
|
||||
printf("%6s %6s %8s: %6s\n",
|
||||
UnparseAlt($flat_count[$x]),
|
||||
UnparseAlt($cum_count[$x]),
|
||||
$address,
|
||||
$d);
|
||||
CleanDisassembly($e->[3]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2254,6 +2427,16 @@ sub UnparseAlt {
|
||||
}
|
||||
}
|
||||
|
||||
# Alternate pretty-printed form: 0 maps to ""
|
||||
sub HtmlPrintNumber {
|
||||
my $num = shift;
|
||||
if ($num == 0) {
|
||||
return "";
|
||||
} else {
|
||||
return Unparse($num);
|
||||
}
|
||||
}
|
||||
|
||||
# Return output units
|
||||
sub Units {
|
||||
if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
|
||||
@@ -2415,6 +2598,8 @@ sub RemoveUninterestingFrames {
|
||||
'copyin',
|
||||
'gostring',
|
||||
'gostringsize',
|
||||
'growslice1',
|
||||
'appendslice1',
|
||||
'hash_init',
|
||||
'hash_subtable_new',
|
||||
'hash_conv',
|
||||
@@ -2422,6 +2607,8 @@ sub RemoveUninterestingFrames {
|
||||
'hash_insert_internal',
|
||||
'hash_insert',
|
||||
'mapassign',
|
||||
'runtime.mapassign',
|
||||
'runtime.appendslice',
|
||||
'runtime.mapassign1',
|
||||
'makechan',
|
||||
'makemap',
|
||||
@@ -2433,11 +2620,13 @@ sub RemoveUninterestingFrames {
|
||||
'unsafe.New',
|
||||
'runtime.mallocgc',
|
||||
'runtime.catstring',
|
||||
'runtime.growslice',
|
||||
'runtime.ifaceT2E',
|
||||
'runtime.ifaceT2I',
|
||||
'runtime.makechan',
|
||||
'runtime.makechan_c',
|
||||
'runtime.makemap',
|
||||
'runtime.makemap_c',
|
||||
'runtime.makeslice',
|
||||
'runtime.mal',
|
||||
'runtime.slicebytetostring',
|
||||
@@ -4302,6 +4491,14 @@ sub ShortFunctionName {
|
||||
return $function;
|
||||
}
|
||||
|
||||
# Trim overly long symbols found in disassembler output
|
||||
sub CleanDisassembly {
|
||||
my $d = shift;
|
||||
while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax)
|
||||
while ($d =~ s/(\w+)<[^<>]*>/$1/g) { } # Remove template arguments
|
||||
return $d;
|
||||
}
|
||||
|
||||
##### Miscellaneous #####
|
||||
|
||||
# Find the right versions of the above object tools to use. The
|
||||
|
||||
22
test/fixedbugs/bug344.go
Normal file
22
test/fixedbugs/bug344.go
Normal file
@@ -0,0 +1,22 @@
|
||||
// $G $D/$F.go && $L $F.$A && ./$A.out || echo BUG: bug344
|
||||
|
||||
// Copyright 2011 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.
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
// invalid use of goto.
|
||||
// do whatever you like, just don't crash.
|
||||
i := 42
|
||||
a := []*int{&i, &i, &i, &i}
|
||||
x := a[0]
|
||||
goto start
|
||||
for _, x = range a {
|
||||
start:
|
||||
fmt.Sprint(*x)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user