mirror of
https://github.com/golang/go.git
synced 2025-05-07 16:43:03 +00:00
- removed lots of unnecessary int(x) casts - removed parserline() - was inconsistently used anyway - minor simplifications in dcl.go Change-Id: Ibf7de679eea528a31c9692ef1c76a1d9b3239211 Reviewed-on: https://go-review.googlesource.com/20131 Reviewed-by: Matthew Dempsky <mdempsky@google.com>
676 lines
17 KiB
Go
676 lines
17 KiB
Go
// Copyright 2009 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 gc
|
|
|
|
import (
|
|
"cmd/internal/obj"
|
|
"fmt"
|
|
)
|
|
|
|
// function literals aka closures
|
|
func closurehdr(ntype *Node) {
|
|
var name *Node
|
|
var a *Node
|
|
|
|
n := Nod(OCLOSURE, nil, nil)
|
|
n.Func.Ntype = ntype
|
|
n.Func.Depth = Funcdepth
|
|
n.Func.Outerfunc = Curfn
|
|
|
|
funchdr(n)
|
|
|
|
// steal ntype's argument names and
|
|
// leave a fresh copy in their place.
|
|
// references to these variables need to
|
|
// refer to the variables in the external
|
|
// function declared below; see walkclosure.
|
|
n.List = ntype.List
|
|
|
|
n.Rlist = ntype.Rlist
|
|
ntype.List = nil
|
|
ntype.Rlist = nil
|
|
for l := n.List; l != nil; l = l.Next {
|
|
name = l.N.Left
|
|
if name != nil {
|
|
name = newname(name.Sym)
|
|
}
|
|
a = Nod(ODCLFIELD, name, l.N.Right)
|
|
a.Isddd = l.N.Isddd
|
|
if name != nil {
|
|
name.Isddd = a.Isddd
|
|
}
|
|
ntype.List = list(ntype.List, a)
|
|
}
|
|
|
|
for l := n.Rlist; l != nil; l = l.Next {
|
|
name = l.N.Left
|
|
if name != nil {
|
|
name = newname(name.Sym)
|
|
}
|
|
ntype.Rlist = list(ntype.Rlist, Nod(ODCLFIELD, name, l.N.Right))
|
|
}
|
|
}
|
|
|
|
func closurebody(body *NodeList) *Node {
|
|
if body == nil {
|
|
body = list1(Nod(OEMPTY, nil, nil))
|
|
}
|
|
|
|
func_ := Curfn
|
|
func_.Nbody.SetToNodeList(body)
|
|
func_.Func.Endlineno = lineno
|
|
funcbody(func_)
|
|
|
|
// closure-specific variables are hanging off the
|
|
// ordinary ones in the symbol table; see oldname.
|
|
// unhook them.
|
|
// make the list of pointers for the closure call.
|
|
for _, v := range func_.Func.Cvars.Slice() {
|
|
v.Name.Param.Closure.Name.Param.Closure = v.Name.Param.Outer
|
|
v.Name.Param.Outerexpr = oldname(v.Sym)
|
|
}
|
|
|
|
return func_
|
|
}
|
|
|
|
func typecheckclosure(func_ *Node, top int) {
|
|
for _, ln := range func_.Func.Cvars.Slice() {
|
|
n := ln.Name.Param.Closure
|
|
if !n.Name.Captured {
|
|
n.Name.Captured = true
|
|
if n.Name.Decldepth == 0 {
|
|
Fatalf("typecheckclosure: var %v does not have decldepth assigned", Nconv(n, obj.FmtShort))
|
|
}
|
|
|
|
// Ignore assignments to the variable in straightline code
|
|
// preceding the first capturing by a closure.
|
|
if n.Name.Decldepth == decldepth {
|
|
n.Assigned = false
|
|
}
|
|
}
|
|
}
|
|
|
|
for _, ln := range func_.Func.Dcl {
|
|
if ln.Op == ONAME && (ln.Class == PPARAM || ln.Class == PPARAMOUT) {
|
|
ln.Name.Decldepth = 1
|
|
}
|
|
}
|
|
|
|
oldfn := Curfn
|
|
typecheck(&func_.Func.Ntype, Etype)
|
|
func_.Type = func_.Func.Ntype.Type
|
|
func_.Func.Top = top
|
|
|
|
// Type check the body now, but only if we're inside a function.
|
|
// At top level (in a variable initialization: curfn==nil) we're not
|
|
// ready to type check code yet; we'll check it later, because the
|
|
// underlying closure function we create is added to xtop.
|
|
if Curfn != nil && func_.Type != nil {
|
|
Curfn = func_
|
|
olddd := decldepth
|
|
decldepth = 1
|
|
typecheckslice(func_.Nbody.Slice(), Etop)
|
|
decldepth = olddd
|
|
Curfn = oldfn
|
|
}
|
|
|
|
// Create top-level function
|
|
xtop = list(xtop, makeclosure(func_))
|
|
}
|
|
|
|
// closurename returns name for OCLOSURE n.
|
|
// It is not as simple as it ought to be, because we typecheck nested closures
|
|
// starting from the innermost one. So when we check the inner closure,
|
|
// we don't yet have name for the outer closure. This function uses recursion
|
|
// to generate names all the way up if necessary.
|
|
|
|
var closurename_closgen int
|
|
|
|
func closurename(n *Node) *Sym {
|
|
if n.Sym != nil {
|
|
return n.Sym
|
|
}
|
|
gen := 0
|
|
outer := ""
|
|
prefix := ""
|
|
if n.Func.Outerfunc == nil {
|
|
// Global closure.
|
|
outer = "glob"
|
|
|
|
prefix = "func"
|
|
closurename_closgen++
|
|
gen = closurename_closgen
|
|
} else if n.Func.Outerfunc.Op == ODCLFUNC {
|
|
// The outermost closure inside of a named function.
|
|
outer = n.Func.Outerfunc.Func.Nname.Sym.Name
|
|
|
|
prefix = "func"
|
|
|
|
// Yes, functions can be named _.
|
|
// Can't use function closgen in such case,
|
|
// because it would lead to name clashes.
|
|
if !isblank(n.Func.Outerfunc.Func.Nname) {
|
|
n.Func.Outerfunc.Func.Closgen++
|
|
gen = n.Func.Outerfunc.Func.Closgen
|
|
} else {
|
|
closurename_closgen++
|
|
gen = closurename_closgen
|
|
}
|
|
} else if n.Func.Outerfunc.Op == OCLOSURE {
|
|
// Nested closure, recurse.
|
|
outer = closurename(n.Func.Outerfunc).Name
|
|
|
|
prefix = ""
|
|
n.Func.Outerfunc.Func.Closgen++
|
|
gen = n.Func.Outerfunc.Func.Closgen
|
|
} else {
|
|
Fatalf("closurename called for %v", Nconv(n, obj.FmtShort))
|
|
}
|
|
n.Sym = Lookupf("%s.%s%d", outer, prefix, gen)
|
|
return n.Sym
|
|
}
|
|
|
|
func makeclosure(func_ *Node) *Node {
|
|
// wrap body in external function
|
|
// that begins by reading closure parameters.
|
|
xtype := Nod(OTFUNC, nil, nil)
|
|
|
|
xtype.List = func_.List
|
|
xtype.Rlist = func_.Rlist
|
|
|
|
// create the function
|
|
xfunc := Nod(ODCLFUNC, nil, nil)
|
|
|
|
xfunc.Func.Nname = newfuncname(closurename(func_))
|
|
xfunc.Func.Nname.Sym.Flags |= SymExported // disable export
|
|
xfunc.Func.Nname.Name.Param.Ntype = xtype
|
|
xfunc.Func.Nname.Name.Defn = xfunc
|
|
declare(xfunc.Func.Nname, PFUNC)
|
|
xfunc.Func.Nname.Name.Funcdepth = func_.Func.Depth
|
|
xfunc.Func.Depth = func_.Func.Depth
|
|
xfunc.Func.Endlineno = func_.Func.Endlineno
|
|
makefuncsym(xfunc.Func.Nname.Sym)
|
|
|
|
xfunc.Nbody.Set(func_.Nbody.Slice())
|
|
xfunc.Func.Dcl = append(func_.Func.Dcl, xfunc.Func.Dcl...)
|
|
func_.Func.Dcl = nil
|
|
if len(xfunc.Nbody.Slice()) == 0 {
|
|
Fatalf("empty body - won't generate any code")
|
|
}
|
|
typecheck(&xfunc, Etop)
|
|
|
|
xfunc.Func.Closure = func_
|
|
func_.Func.Closure = xfunc
|
|
|
|
func_.Nbody.Set(nil)
|
|
func_.List = nil
|
|
func_.Rlist = nil
|
|
|
|
return xfunc
|
|
}
|
|
|
|
// capturevars is called in a separate phase after all typechecking is done.
|
|
// It decides whether each variable captured by a closure should be captured
|
|
// by value or by reference.
|
|
// We use value capturing for values <= 128 bytes that are never reassigned
|
|
// after capturing (effectively constant).
|
|
func capturevars(xfunc *Node) {
|
|
var outer *Node
|
|
|
|
lno := int(lineno)
|
|
lineno = xfunc.Lineno
|
|
|
|
func_ := xfunc.Func.Closure
|
|
func_.Func.Enter.Set(nil)
|
|
for _, v := range func_.Func.Cvars.Slice() {
|
|
if v.Type == nil {
|
|
// if v->type is nil, it means v looked like it was
|
|
// going to be used in the closure but wasn't.
|
|
// this happens because when parsing a, b, c := f()
|
|
// the a, b, c gets parsed as references to older
|
|
// a, b, c before the parser figures out this is a
|
|
// declaration.
|
|
v.Op = OXXX
|
|
|
|
continue
|
|
}
|
|
|
|
// type check the & of closed variables outside the closure,
|
|
// so that the outer frame also grabs them and knows they escape.
|
|
dowidth(v.Type)
|
|
|
|
outer = v.Name.Param.Outerexpr
|
|
v.Name.Param.Outerexpr = nil
|
|
|
|
// out parameters will be assigned to implicitly upon return.
|
|
if outer.Class != PPARAMOUT && !v.Name.Param.Closure.Addrtaken && !v.Name.Param.Closure.Assigned && v.Type.Width <= 128 {
|
|
v.Name.Byval = true
|
|
} else {
|
|
v.Name.Param.Closure.Addrtaken = true
|
|
outer = Nod(OADDR, outer, nil)
|
|
}
|
|
|
|
if Debug['m'] > 1 {
|
|
var name *Sym
|
|
if v.Name.Curfn != nil && v.Name.Curfn.Func.Nname != nil {
|
|
name = v.Name.Curfn.Func.Nname.Sym
|
|
}
|
|
how := "ref"
|
|
if v.Name.Byval {
|
|
how = "value"
|
|
}
|
|
Warnl(v.Lineno, "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, v.Name.Param.Closure.Addrtaken, v.Name.Param.Closure.Assigned, int32(v.Type.Width))
|
|
}
|
|
|
|
typecheck(&outer, Erv)
|
|
func_.Func.Enter.Append(outer)
|
|
}
|
|
|
|
lineno = int32(lno)
|
|
}
|
|
|
|
// transformclosure is called in a separate phase after escape analysis.
|
|
// It transform closure bodies to properly reference captured variables.
|
|
func transformclosure(xfunc *Node) {
|
|
lno := int(lineno)
|
|
lineno = xfunc.Lineno
|
|
func_ := xfunc.Func.Closure
|
|
|
|
if func_.Func.Top&Ecall != 0 {
|
|
// If the closure is directly called, we transform it to a plain function call
|
|
// with variables passed as args. This avoids allocation of a closure object.
|
|
// Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE)
|
|
// will complete the transformation later.
|
|
// For illustration, the following closure:
|
|
// func(a int) {
|
|
// println(byval)
|
|
// byref++
|
|
// }(42)
|
|
// becomes:
|
|
// func(a int, byval int, &byref *int) {
|
|
// println(byval)
|
|
// (*&byref)++
|
|
// }(byval, &byref, 42)
|
|
|
|
// f is ONAME of the actual function.
|
|
f := xfunc.Func.Nname
|
|
|
|
// Get pointer to input arguments.
|
|
// We are going to insert captured variables before input args.
|
|
param := &getinargx(f.Type).Type
|
|
original_args := *param // old input args
|
|
original_dcl := xfunc.Func.Dcl
|
|
xfunc.Func.Dcl = nil
|
|
|
|
var addr *Node
|
|
var fld *Type
|
|
for _, v := range func_.Func.Cvars.Slice() {
|
|
if v.Op == OXXX {
|
|
continue
|
|
}
|
|
fld = typ(TFIELD)
|
|
fld.Funarg = true
|
|
if v.Name.Byval {
|
|
// If v is captured by value, we merely downgrade it to PPARAM.
|
|
v.Class = PPARAM
|
|
|
|
v.Ullman = 1
|
|
fld.Nname = v
|
|
} else {
|
|
// If v of type T is captured by reference,
|
|
// we introduce function param &v *T
|
|
// and v remains PPARAMREF with &v heapaddr
|
|
// (accesses will implicitly deref &v).
|
|
addr = newname(Lookupf("&%s", v.Sym.Name))
|
|
addr.Type = Ptrto(v.Type)
|
|
addr.Class = PPARAM
|
|
v.Name.Heapaddr = addr
|
|
fld.Nname = addr
|
|
}
|
|
|
|
fld.Type = fld.Nname.Type
|
|
fld.Sym = fld.Nname.Sym
|
|
|
|
// Declare the new param and add it the first part of the input arguments.
|
|
xfunc.Func.Dcl = append(xfunc.Func.Dcl, fld.Nname)
|
|
|
|
*param = fld
|
|
param = &fld.Down
|
|
}
|
|
*param = original_args
|
|
xfunc.Func.Dcl = append(xfunc.Func.Dcl, original_dcl...)
|
|
|
|
// Recalculate param offsets.
|
|
if f.Type.Width > 0 {
|
|
Fatalf("transformclosure: width is already calculated")
|
|
}
|
|
dowidth(f.Type)
|
|
xfunc.Type = f.Type // update type of ODCLFUNC
|
|
} else {
|
|
// The closure is not called, so it is going to stay as closure.
|
|
var body []*Node
|
|
offset := int64(Widthptr)
|
|
var addr *Node
|
|
var cv *Node
|
|
for _, v := range func_.Func.Cvars.Slice() {
|
|
if v.Op == OXXX {
|
|
continue
|
|
}
|
|
|
|
// cv refers to the field inside of closure OSTRUCTLIT.
|
|
cv = Nod(OCLOSUREVAR, nil, nil)
|
|
|
|
cv.Type = v.Type
|
|
if !v.Name.Byval {
|
|
cv.Type = Ptrto(v.Type)
|
|
}
|
|
offset = Rnd(offset, int64(cv.Type.Align))
|
|
cv.Xoffset = offset
|
|
offset += cv.Type.Width
|
|
|
|
if v.Name.Byval && v.Type.Width <= int64(2*Widthptr) {
|
|
// If it is a small variable captured by value, downgrade it to PAUTO.
|
|
v.Class = PAUTO
|
|
v.Ullman = 1
|
|
xfunc.Func.Dcl = append(xfunc.Func.Dcl, v)
|
|
body = append(body, Nod(OAS, v, cv))
|
|
} else {
|
|
// Declare variable holding addresses taken from closure
|
|
// and initialize in entry prologue.
|
|
addr = newname(Lookupf("&%s", v.Sym.Name))
|
|
addr.Name.Param.Ntype = Nod(OIND, typenod(v.Type), nil)
|
|
addr.Class = PAUTO
|
|
addr.Used = true
|
|
addr.Name.Curfn = xfunc
|
|
xfunc.Func.Dcl = append(xfunc.Func.Dcl, addr)
|
|
v.Name.Heapaddr = addr
|
|
if v.Name.Byval {
|
|
cv = Nod(OADDR, cv, nil)
|
|
}
|
|
body = append(body, Nod(OAS, addr, cv))
|
|
}
|
|
}
|
|
|
|
if len(body) > 0 {
|
|
typecheckslice(body, Etop)
|
|
walkstmtslice(body)
|
|
xfunc.Func.Enter.Set(body)
|
|
xfunc.Func.Needctxt = true
|
|
}
|
|
}
|
|
|
|
lineno = int32(lno)
|
|
}
|
|
|
|
func walkclosure(func_ *Node, init **NodeList) *Node {
|
|
// If no closure vars, don't bother wrapping.
|
|
if len(func_.Func.Cvars.Slice()) == 0 {
|
|
return func_.Func.Closure.Func.Nname
|
|
}
|
|
|
|
// Create closure in the form of a composite literal.
|
|
// supposing the closure captures an int i and a string s
|
|
// and has one float64 argument and no results,
|
|
// the generated code looks like:
|
|
//
|
|
// clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s}
|
|
//
|
|
// The use of the struct provides type information to the garbage
|
|
// collector so that it can walk the closure. We could use (in this case)
|
|
// [3]unsafe.Pointer instead, but that would leave the gc in the dark.
|
|
// The information appears in the binary in the form of type descriptors;
|
|
// the struct is unnamed so that closures in multiple packages with the
|
|
// same struct type can share the descriptor.
|
|
|
|
typ := Nod(OTSTRUCT, nil, nil)
|
|
|
|
typ.List = list1(Nod(ODCLFIELD, newname(Lookup(".F")), typenod(Types[TUINTPTR])))
|
|
var typ1 *Node
|
|
for _, v := range func_.Func.Cvars.Slice() {
|
|
if v.Op == OXXX {
|
|
continue
|
|
}
|
|
typ1 = typenod(v.Type)
|
|
if !v.Name.Byval {
|
|
typ1 = Nod(OIND, typ1, nil)
|
|
}
|
|
typ.List = list(typ.List, Nod(ODCLFIELD, newname(v.Sym), typ1))
|
|
}
|
|
|
|
clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
|
|
clos.Esc = func_.Esc
|
|
clos.Right.Implicit = true
|
|
clos.List = concat(list1(Nod(OCFUNC, func_.Func.Closure.Func.Nname, nil)), func_.Func.Enter.NodeList())
|
|
|
|
// Force type conversion from *struct to the func type.
|
|
clos = Nod(OCONVNOP, clos, nil)
|
|
|
|
clos.Type = func_.Type
|
|
|
|
typecheck(&clos, Erv)
|
|
|
|
// typecheck will insert a PTRLIT node under CONVNOP,
|
|
// tag it with escape analysis result.
|
|
clos.Left.Esc = func_.Esc
|
|
|
|
// non-escaping temp to use, if any.
|
|
// orderexpr did not compute the type; fill it in now.
|
|
if x := prealloc[func_]; x != nil {
|
|
x.Type = clos.Left.Left.Type
|
|
x.Orig.Type = x.Type
|
|
clos.Left.Right = x
|
|
delete(prealloc, func_)
|
|
}
|
|
|
|
walkexpr(&clos, init)
|
|
|
|
return clos
|
|
}
|
|
|
|
func typecheckpartialcall(fn *Node, sym *Node) {
|
|
switch fn.Op {
|
|
case ODOTINTER, ODOTMETH:
|
|
break
|
|
|
|
default:
|
|
Fatalf("invalid typecheckpartialcall")
|
|
}
|
|
|
|
// Create top-level function.
|
|
xfunc := makepartialcall(fn, fn.Type, sym)
|
|
fn.Func = xfunc.Func
|
|
fn.Right = sym
|
|
fn.Op = OCALLPART
|
|
fn.Type = xfunc.Type
|
|
}
|
|
|
|
var makepartialcall_gopkg *Pkg
|
|
|
|
func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
|
|
var p string
|
|
|
|
rcvrtype := fn.Left.Type
|
|
if exportname(meth.Sym.Name) {
|
|
p = fmt.Sprintf("(%v).%s-fm", Tconv(rcvrtype, obj.FmtLeft|obj.FmtShort), meth.Sym.Name)
|
|
} else {
|
|
p = fmt.Sprintf("(%v).(%v)-fm", Tconv(rcvrtype, obj.FmtLeft|obj.FmtShort), Sconv(meth.Sym, obj.FmtLeft))
|
|
}
|
|
basetype := rcvrtype
|
|
if Isptr[rcvrtype.Etype] {
|
|
basetype = basetype.Type
|
|
}
|
|
if basetype.Etype != TINTER && basetype.Sym == nil {
|
|
Fatalf("missing base type for %v", rcvrtype)
|
|
}
|
|
|
|
var spkg *Pkg
|
|
if basetype.Sym != nil {
|
|
spkg = basetype.Sym.Pkg
|
|
}
|
|
if spkg == nil {
|
|
if makepartialcall_gopkg == nil {
|
|
makepartialcall_gopkg = mkpkg("go")
|
|
}
|
|
spkg = makepartialcall_gopkg
|
|
}
|
|
|
|
sym := Pkglookup(p, spkg)
|
|
|
|
if sym.Flags&SymUniq != 0 {
|
|
return sym.Def
|
|
}
|
|
sym.Flags |= SymUniq
|
|
|
|
savecurfn := Curfn
|
|
Curfn = nil
|
|
|
|
xtype := Nod(OTFUNC, nil, nil)
|
|
i := 0
|
|
var l *NodeList
|
|
var callargs *NodeList
|
|
ddd := false
|
|
xfunc := Nod(ODCLFUNC, nil, nil)
|
|
Curfn = xfunc
|
|
var fld *Node
|
|
var n *Node
|
|
for t := getinargx(t0).Type; t != nil; t = t.Down {
|
|
n = newname(Lookupf("a%d", i))
|
|
i++
|
|
n.Class = PPARAM
|
|
xfunc.Func.Dcl = append(xfunc.Func.Dcl, n)
|
|
callargs = list(callargs, n)
|
|
fld = Nod(ODCLFIELD, n, typenod(t.Type))
|
|
if t.Isddd {
|
|
fld.Isddd = true
|
|
ddd = true
|
|
}
|
|
|
|
l = list(l, fld)
|
|
}
|
|
|
|
xtype.List = l
|
|
i = 0
|
|
l = nil
|
|
var retargs *NodeList
|
|
for t := getoutargx(t0).Type; t != nil; t = t.Down {
|
|
n = newname(Lookupf("r%d", i))
|
|
i++
|
|
n.Class = PPARAMOUT
|
|
xfunc.Func.Dcl = append(xfunc.Func.Dcl, n)
|
|
retargs = list(retargs, n)
|
|
l = list(l, Nod(ODCLFIELD, n, typenod(t.Type)))
|
|
}
|
|
|
|
xtype.Rlist = l
|
|
|
|
xfunc.Func.Dupok = true
|
|
xfunc.Func.Nname = newfuncname(sym)
|
|
xfunc.Func.Nname.Sym.Flags |= SymExported // disable export
|
|
xfunc.Func.Nname.Name.Param.Ntype = xtype
|
|
xfunc.Func.Nname.Name.Defn = xfunc
|
|
declare(xfunc.Func.Nname, PFUNC)
|
|
|
|
// Declare and initialize variable holding receiver.
|
|
|
|
xfunc.Func.Needctxt = true
|
|
cv := Nod(OCLOSUREVAR, nil, nil)
|
|
cv.Xoffset = int64(Widthptr)
|
|
cv.Type = rcvrtype
|
|
if int(cv.Type.Align) > Widthptr {
|
|
cv.Xoffset = int64(cv.Type.Align)
|
|
}
|
|
ptr := Nod(ONAME, nil, nil)
|
|
ptr.Sym = Lookup("rcvr")
|
|
ptr.Class = PAUTO
|
|
ptr.Addable = true
|
|
ptr.Ullman = 1
|
|
ptr.Used = true
|
|
ptr.Name.Curfn = xfunc
|
|
ptr.Xoffset = 0
|
|
xfunc.Func.Dcl = append(xfunc.Func.Dcl, ptr)
|
|
var body []*Node
|
|
if Isptr[rcvrtype.Etype] || Isinter(rcvrtype) {
|
|
ptr.Name.Param.Ntype = typenod(rcvrtype)
|
|
body = append(body, Nod(OAS, ptr, cv))
|
|
} else {
|
|
ptr.Name.Param.Ntype = typenod(Ptrto(rcvrtype))
|
|
body = append(body, Nod(OAS, ptr, Nod(OADDR, cv, nil)))
|
|
}
|
|
|
|
call := Nod(OCALL, Nod(OXDOT, ptr, meth), nil)
|
|
call.List = callargs
|
|
call.Isddd = ddd
|
|
if t0.Outtuple == 0 {
|
|
body = append(body, call)
|
|
} else {
|
|
n := Nod(OAS2, nil, nil)
|
|
n.List = retargs
|
|
n.Rlist = list1(call)
|
|
body = append(body, n)
|
|
n = Nod(ORETURN, nil, nil)
|
|
body = append(body, n)
|
|
}
|
|
|
|
xfunc.Nbody.Set(body)
|
|
|
|
typecheck(&xfunc, Etop)
|
|
sym.Def = xfunc
|
|
xtop = list(xtop, xfunc)
|
|
Curfn = savecurfn
|
|
|
|
return xfunc
|
|
}
|
|
|
|
func walkpartialcall(n *Node, init **NodeList) *Node {
|
|
// Create closure in the form of a composite literal.
|
|
// For x.M with receiver (x) type T, the generated code looks like:
|
|
//
|
|
// clos = &struct{F uintptr; R T}{M.T·f, x}
|
|
//
|
|
// Like walkclosure above.
|
|
|
|
if Isinter(n.Left.Type) {
|
|
// Trigger panic for method on nil interface now.
|
|
// Otherwise it happens in the wrapper and is confusing.
|
|
n.Left = cheapexpr(n.Left, init)
|
|
|
|
checknil(n.Left, init)
|
|
}
|
|
|
|
typ := Nod(OTSTRUCT, nil, nil)
|
|
typ.List = list1(Nod(ODCLFIELD, newname(Lookup("F")), typenod(Types[TUINTPTR])))
|
|
typ.List = list(typ.List, Nod(ODCLFIELD, newname(Lookup("R")), typenod(n.Left.Type)))
|
|
|
|
clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
|
|
clos.Esc = n.Esc
|
|
clos.Right.Implicit = true
|
|
clos.List = list1(Nod(OCFUNC, n.Func.Nname, nil))
|
|
clos.List = list(clos.List, n.Left)
|
|
|
|
// Force type conversion from *struct to the func type.
|
|
clos = Nod(OCONVNOP, clos, nil)
|
|
|
|
clos.Type = n.Type
|
|
|
|
typecheck(&clos, Erv)
|
|
|
|
// typecheck will insert a PTRLIT node under CONVNOP,
|
|
// tag it with escape analysis result.
|
|
clos.Left.Esc = n.Esc
|
|
|
|
// non-escaping temp to use, if any.
|
|
// orderexpr did not compute the type; fill it in now.
|
|
if x := prealloc[n]; x != nil {
|
|
x.Type = clos.Left.Left.Type
|
|
x.Orig.Type = x.Type
|
|
clos.Left.Right = x
|
|
delete(prealloc, n)
|
|
}
|
|
|
|
walkexpr(&clos, init)
|
|
|
|
return clos
|
|
}
|