mirror of
https://github.com/golang/go
synced 2024-10-05 20:31:20 -06:00
[dev.ssa] cmd/compile: fixed heap-escaped-paramout
Changed tree generation to correctly use PARAMOUT instead of PARAM. Emit Func.Exit before any returns. Change-Id: I2fa53cc7fad05fb4eea21081ba33d1f66db4ed49 Reviewed-on: https://go-review.googlesource.com/15610 Reviewed-by: Keith Randall <khr@golang.org> Run-TryBot: David Chase <drchase@google.com>
This commit is contained in:
parent
808d7c70d5
commit
8824dccc28
@ -507,6 +507,16 @@ func newplist() *obj.Plist {
|
|||||||
return pl
|
return pl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nodarg does something that depends on the value of
|
||||||
|
// fp (this was previously completely undocumented).
|
||||||
|
//
|
||||||
|
// fp=1 corresponds to input args
|
||||||
|
// fp=0 corresponds to output args
|
||||||
|
// fp=-1 is a special case of output args for a
|
||||||
|
// specific call from walk that previously (and
|
||||||
|
// incorrectly) passed a 1; the behavior is exactly
|
||||||
|
// the same as it is for 1, except that PARAMOUT is
|
||||||
|
// generated instead of PARAM.
|
||||||
func nodarg(t *Type, fp int) *Node {
|
func nodarg(t *Type, fp int) *Node {
|
||||||
var n *Node
|
var n *Node
|
||||||
|
|
||||||
@ -532,7 +542,7 @@ func nodarg(t *Type, fp int) *Node {
|
|||||||
Fatalf("nodarg: not field %v", t)
|
Fatalf("nodarg: not field %v", t)
|
||||||
}
|
}
|
||||||
|
|
||||||
if fp == 1 {
|
if fp == 1 || fp == -1 {
|
||||||
var n *Node
|
var n *Node
|
||||||
for l := Curfn.Func.Dcl; l != nil; l = l.Next {
|
for l := Curfn.Func.Dcl; l != nil; l = l.Next {
|
||||||
n = l.N
|
n = l.N
|
||||||
@ -573,6 +583,9 @@ fp:
|
|||||||
case 1: // input arg
|
case 1: // input arg
|
||||||
n.Class = PPARAM
|
n.Class = PPARAM
|
||||||
|
|
||||||
|
case -1: // output arg from paramstoheap
|
||||||
|
n.Class = PPARAMOUT
|
||||||
|
|
||||||
case 2: // offset output arg
|
case 2: // offset output arg
|
||||||
Fatalf("shouldn't be used")
|
Fatalf("shouldn't be used")
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
|
|||||||
fmt.Println("generating SSA for", name)
|
fmt.Println("generating SSA for", name)
|
||||||
dumplist("buildssa-enter", fn.Func.Enter)
|
dumplist("buildssa-enter", fn.Func.Enter)
|
||||||
dumplist("buildssa-body", fn.Nbody)
|
dumplist("buildssa-body", fn.Nbody)
|
||||||
|
dumplist("buildssa-exit", fn.Func.Exit)
|
||||||
}
|
}
|
||||||
|
|
||||||
var s state
|
var s state
|
||||||
@ -43,6 +44,7 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
|
|||||||
s.config = ssa.NewConfig(Thearch.Thestring, &e)
|
s.config = ssa.NewConfig(Thearch.Thestring, &e)
|
||||||
s.f = s.config.NewFunc()
|
s.f = s.config.NewFunc()
|
||||||
s.f.Name = name
|
s.f.Name = name
|
||||||
|
s.exitCode = fn.Func.Exit
|
||||||
|
|
||||||
if name == os.Getenv("GOSSAFUNC") {
|
if name == os.Getenv("GOSSAFUNC") {
|
||||||
// TODO: tempfile? it is handy to have the location
|
// TODO: tempfile? it is handy to have the location
|
||||||
@ -97,8 +99,8 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
|
|||||||
// TODO this looks wrong for PAUTO|PHEAP, no vardef, but also no definition
|
// TODO this looks wrong for PAUTO|PHEAP, no vardef, but also no definition
|
||||||
aux := &ssa.AutoSymbol{Typ: n.Type, Node: n}
|
aux := &ssa.AutoSymbol{Typ: n.Type, Node: n}
|
||||||
s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
|
s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
|
||||||
case PPARAM | PHEAP: // PPARAMOUT | PHEAP seems to not occur
|
case PPARAM | PHEAP, PPARAMOUT | PHEAP:
|
||||||
// This ends up wrong, have to do it at the PARAM node instead.
|
// This ends up wrong, have to do it at the PARAM node instead.
|
||||||
case PAUTO, PPARAMOUT:
|
case PAUTO, PPARAMOUT:
|
||||||
// processed at each use, to prevent Addr coming
|
// processed at each use, to prevent Addr coming
|
||||||
// before the decl.
|
// before the decl.
|
||||||
@ -122,6 +124,7 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
|
|||||||
|
|
||||||
// fallthrough to exit
|
// fallthrough to exit
|
||||||
if s.curBlock != nil {
|
if s.curBlock != nil {
|
||||||
|
s.stmtList(s.exitCode)
|
||||||
m := s.mem()
|
m := s.mem()
|
||||||
b := s.endBlock()
|
b := s.endBlock()
|
||||||
b.Kind = ssa.BlockRet
|
b.Kind = ssa.BlockRet
|
||||||
@ -156,6 +159,9 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
|
|||||||
// Link up variable uses to variable definitions
|
// Link up variable uses to variable definitions
|
||||||
s.linkForwardReferences()
|
s.linkForwardReferences()
|
||||||
|
|
||||||
|
// Don't carry reference this around longer than necessary
|
||||||
|
s.exitCode = nil
|
||||||
|
|
||||||
// Main call to ssa package to compile function
|
// Main call to ssa package to compile function
|
||||||
ssa.Compile(s.f)
|
ssa.Compile(s.f)
|
||||||
|
|
||||||
@ -207,6 +213,9 @@ type state struct {
|
|||||||
|
|
||||||
// gotos that jump forward; required for deferred checkgoto calls
|
// gotos that jump forward; required for deferred checkgoto calls
|
||||||
fwdGotos []*Node
|
fwdGotos []*Node
|
||||||
|
// Code that must precede any return
|
||||||
|
// (e.g., copying value of heap-escaped paramout back to true paramout)
|
||||||
|
exitCode *NodeList
|
||||||
|
|
||||||
// unlabeled break and continue statement tracking
|
// unlabeled break and continue statement tracking
|
||||||
breakTo *ssa.Block // current target for plain break statement
|
breakTo *ssa.Block // current target for plain break statement
|
||||||
@ -641,12 +650,14 @@ func (s *state) stmt(n *Node) {
|
|||||||
|
|
||||||
case ORETURN:
|
case ORETURN:
|
||||||
s.stmtList(n.List)
|
s.stmtList(n.List)
|
||||||
|
s.stmtList(s.exitCode)
|
||||||
m := s.mem()
|
m := s.mem()
|
||||||
b := s.endBlock()
|
b := s.endBlock()
|
||||||
b.Kind = ssa.BlockRet
|
b.Kind = ssa.BlockRet
|
||||||
b.Control = m
|
b.Control = m
|
||||||
case ORETJMP:
|
case ORETJMP:
|
||||||
s.stmtList(n.List)
|
s.stmtList(n.List)
|
||||||
|
s.stmtList(s.exitCode)
|
||||||
m := s.mem()
|
m := s.mem()
|
||||||
b := s.endBlock()
|
b := s.endBlock()
|
||||||
b.Kind = ssa.BlockRetJmp
|
b.Kind = ssa.BlockRetJmp
|
||||||
|
@ -2674,7 +2674,7 @@ func paramstoheap(argin **Type, out int) *NodeList {
|
|||||||
// Defer might stop a panic and show the
|
// Defer might stop a panic and show the
|
||||||
// return values as they exist at the time of panic.
|
// return values as they exist at the time of panic.
|
||||||
// Make sure to zero them on entry to the function.
|
// Make sure to zero them on entry to the function.
|
||||||
nn = list(nn, Nod(OAS, nodarg(t, 1), nil))
|
nn = list(nn, Nod(OAS, nodarg(t, -1), nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
if v == nil || v.Class&PHEAP == 0 {
|
if v == nil || v.Class&PHEAP == 0 {
|
||||||
|
Loading…
Reference in New Issue
Block a user