mirror of
https://github.com/golang/go
synced 2024-07-21 01:55:06 +00:00
cmd/compile: hide init functions in tracebacks
Treat compiler-generated init functions as wrappers, so they will not be shown in tracebacks. The exception to this rule is that we'd like to show the line number of initializers for global variables in tracebacks. In order to preserve line numbers for those cases, separate out the code for those initializers into a separate function (which is not marked as autogenerated). This CL makes the go binary 0.2% bigger. Fixes #29919 Change-Id: I0f1fbfc03d10d764ce3a8ddb48fb387ca8453386 Reviewed-on: https://go-review.googlesource.com/c/159717 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
d585f04fd3
commit
eafe9a186c
|
@ -57,6 +57,9 @@ func anyinit(n []*Node) bool {
|
|||
|
||||
// fninit hand-crafts package initialization code.
|
||||
//
|
||||
// func init.ializers() { (0)
|
||||
// <init stmts>
|
||||
// }
|
||||
// var initdone· uint8 (1)
|
||||
// func init() { (2)
|
||||
// if initdone· > 1 { (3)
|
||||
|
@ -68,7 +71,7 @@ func anyinit(n []*Node) bool {
|
|||
// initdone· = 1 (5)
|
||||
// // over all matching imported symbols
|
||||
// <pkg>.init() (6)
|
||||
// { <init stmts> } (7)
|
||||
// init.ializers() (7)
|
||||
// init.<n>() // if any (8)
|
||||
// initdone· = 2 (9)
|
||||
// return (10)
|
||||
|
@ -80,6 +83,27 @@ func fninit(n []*Node) {
|
|||
return
|
||||
}
|
||||
|
||||
// (0)
|
||||
// Make a function that contains all the initialization statements.
|
||||
// This is a separate function because we want it to appear in
|
||||
// stack traces, where the init function itself does not.
|
||||
var initializers *types.Sym
|
||||
if len(nf) > 0 {
|
||||
lineno = nf[0].Pos // prolog/epilog gets line number of first init stmt
|
||||
initializers = lookup("init.ializers")
|
||||
disableExport(initializers)
|
||||
fn := dclfunc(initializers, nod(OTFUNC, nil, nil))
|
||||
fn.Nbody.Set(nf)
|
||||
funcbody()
|
||||
|
||||
fn = typecheck(fn, ctxStmt)
|
||||
Curfn = fn
|
||||
typecheckslice(nf, ctxStmt)
|
||||
Curfn = nil
|
||||
funccompile(fn)
|
||||
lineno = autogeneratedPos
|
||||
}
|
||||
|
||||
var r []*Node
|
||||
|
||||
// (1)
|
||||
|
@ -130,7 +154,11 @@ func fninit(n []*Node) {
|
|||
}
|
||||
|
||||
// (7)
|
||||
r = append(r, nf...)
|
||||
if initializers != nil {
|
||||
n := newname(initializers)
|
||||
addvar(n, functype(nil, nil, nil), PFUNC)
|
||||
r = append(r, nod(OCALL, n, nil))
|
||||
}
|
||||
|
||||
// (8)
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ func GetFuncID(name, file string) FuncID {
|
|||
case "runtime.panicwrap":
|
||||
return FuncID_panicwrap
|
||||
}
|
||||
if file == "<autogenerated>" && !strings.HasSuffix(name, ".init") {
|
||||
if file == "<autogenerated>" {
|
||||
return FuncID_wrapper
|
||||
}
|
||||
if strings.HasPrefix(name, "runtime.call") {
|
||||
|
|
75
test/fixedbugs/issue29919.dir/a.go
Normal file
75
test/fixedbugs/issue29919.dir/a.go
Normal file
|
@ -0,0 +1,75 @@
|
|||
// Copyright 2019 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.
|
||||
|
||||
// Make sure tracebacks from initialization code are reported correctly.
|
||||
|
||||
package a
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var x = f() // line 15
|
||||
|
||||
func f() int {
|
||||
var b [4096]byte
|
||||
n := runtime.Stack(b[:], false) // line 19
|
||||
s := string(b[:n])
|
||||
var pcs [10]uintptr
|
||||
n = runtime.Callers(1, pcs[:]) // line 22
|
||||
|
||||
// Check the Stack results.
|
||||
if debug {
|
||||
println(s)
|
||||
}
|
||||
if strings.Contains(s, "autogenerated") {
|
||||
panic("autogenerated code in traceback")
|
||||
}
|
||||
if !strings.Contains(s, "a.go:15") {
|
||||
panic("missing a.go:15")
|
||||
}
|
||||
if !strings.Contains(s, "a.go:19") {
|
||||
panic("missing a.go:19")
|
||||
}
|
||||
if !strings.Contains(s, "a.init.ializers") {
|
||||
panic("missing a.init.ializers")
|
||||
}
|
||||
|
||||
// Check the CallersFrames results.
|
||||
if debug {
|
||||
iter := runtime.CallersFrames(pcs[:n])
|
||||
for {
|
||||
f, more := iter.Next()
|
||||
fmt.Printf("%s %s:%d\n", f.Function, f.File, f.Line)
|
||||
if !more {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
iter := runtime.CallersFrames(pcs[:n])
|
||||
f, more := iter.Next()
|
||||
if f.Function != "a.f" || !strings.HasSuffix(f.File, "a.go") || f.Line != 22 {
|
||||
panic(fmt.Sprintf("bad f %v\n", f))
|
||||
}
|
||||
if !more {
|
||||
panic("traceback truncated after f")
|
||||
}
|
||||
f, more = iter.Next()
|
||||
if f.Function != "a.init.ializers" || !strings.HasSuffix(f.File, "a.go") || f.Line != 15 {
|
||||
panic(fmt.Sprintf("bad init.ializers %v\n", f))
|
||||
}
|
||||
if !more {
|
||||
panic("traceback truncated after init.ializers")
|
||||
}
|
||||
f, _ = iter.Next()
|
||||
if f.Function != "runtime.main" {
|
||||
panic("runtime.main missing")
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
const debug = false
|
10
test/fixedbugs/issue29919.dir/main.go
Normal file
10
test/fixedbugs/issue29919.dir/main.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Copyright 2019 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 _ "./a"
|
||||
|
||||
func main() {
|
||||
}
|
9
test/fixedbugs/issue29919.go
Normal file
9
test/fixedbugs/issue29919.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
// rundir
|
||||
|
||||
// Copyright 2019 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.
|
||||
|
||||
// Make sure tracebacks from initialization code are reported correctly.
|
||||
|
||||
package ignored
|
Loading…
Reference in a new issue