Commit eb4d1be2 authored by Robert Griesemer's avatar Robert Griesemer

cmd/compile: keep variable numbering for inlineable exported functions

Another step towards hooking up exported inlined function bodies.

Change-Id: Ib8094b03ac7970fee0e51b5826b5f8aa232e23fb
Reviewed-on: https://go-review.googlesource.com/20605Reviewed-by: default avatarAlan Donovan <adonovan@google.com>
Run-TryBot: Robert Griesemer <gri@golang.org>
parent 2e936906
......@@ -276,12 +276,16 @@ func Export(out *obj.Biobuf, trace bool) int {
}
for _, sym := range funcs {
p.string(sym.Name)
// The type can only be a signature for functions. However, by always
// writing the complete type specification (rather than just a signature)
// we keep the option open of sharing common signatures across multiple
// functions as a means to further compress the export data.
p.typ(sym.Def.Type)
p.inlinedBody(sym.Def)
sig := sym.Def.Type
inlineable := p.isInlineable(sym.Def)
p.paramList(sig.Params(), inlineable)
p.paramList(sig.Results(), inlineable)
index := -1
if inlineable {
index = len(p.inlined)
p.inlined = append(p.inlined, sym.Def.Func)
}
p.int(index)
if p.trace {
p.tracef("\n")
}
......@@ -476,10 +480,17 @@ func (p *exporter) typ(t *Type) {
p.tracef("\n")
}
p.string(m.Sym.Name)
p.paramList(m.Type.Recvs())
p.paramList(m.Type.Params())
p.paramList(m.Type.Results())
p.inlinedBody(m.Type.Nname)
sig := m.Type
inlineable := p.isInlineable(sig.Nname)
p.paramList(sig.Recvs(), inlineable)
p.paramList(sig.Params(), inlineable)
p.paramList(sig.Results(), inlineable)
index := -1
if inlineable {
index = len(p.inlined)
p.inlined = append(p.inlined, sig.Nname.Func)
}
p.int(index)
}
if p.trace && len(methods) > 0 {
......@@ -516,8 +527,8 @@ func (p *exporter) typ(t *Type) {
case TFUNC:
p.tag(signatureTag)
p.paramList(t.Params())
p.paramList(t.Results())
p.paramList(t.Params(), false)
p.paramList(t.Results(), false)
case TINTER:
p.tag(interfaceTag)
......@@ -596,8 +607,8 @@ func (p *exporter) method(m *Field) {
// TODO(gri) For functions signatures, we use p.typ() to export
// so we could share the same type with multiple functions. Do
// the same here, or never try to do this for functions.
p.paramList(m.Type.Params())
p.paramList(m.Type.Results())
p.paramList(m.Type.Params(), false)
p.paramList(m.Type.Results(), false)
}
// fieldName is like qualifiedName but it doesn't record the package
......@@ -631,7 +642,7 @@ func basetypeName(t *Type) string {
return ""
}
func (p *exporter) paramList(params *Type) {
func (p *exporter) paramList(params *Type, numbered bool) {
if params.Etype != TSTRUCT || !params.Funarg {
Fatalf("exporter: parameter list expected")
}
......@@ -640,16 +651,16 @@ func (p *exporter) paramList(params *Type) {
// (look at the first parameter only since either all
// names are present or all are absent)
n := countfield(params)
if n > 0 && parName(params.Field(0)) == "" {
if n > 0 && parName(params.Field(0), numbered) == "" {
n = -n
}
p.int(n)
for q, it := IterFields(params); q != nil; q = it.Next() {
p.param(q, n)
p.param(q, n, numbered)
}
}
func (p *exporter) param(q *Field, n int) {
func (p *exporter) param(q *Field, n int, numbered bool) {
t := q.Type
if q.Isddd {
// create a fake type to encode ... just for the p.typ call
......@@ -659,7 +670,7 @@ func (p *exporter) param(q *Field, n int) {
}
p.typ(t)
if n > 0 {
p.string(parName(q))
p.string(parName(q, numbered))
}
// TODO(gri) This is compiler-specific (escape info).
// Move into compiler-specific section eventually?
......@@ -670,7 +681,7 @@ func (p *exporter) param(q *Field, n int) {
p.note(q.Note)
}
func parName(q *Field) string {
func parName(q *Field, numbered bool) string {
if q.Sym == nil {
return ""
}
......@@ -687,9 +698,11 @@ func parName(q *Field) string {
Fatalf("exporter: unexpected parameter name: %s", name)
}
}
// undo gc-internal name specialization
if i := strings.Index(name, "·"); i > 0 {
name = name[:i] // cut off numbering
// undo gc-internal name specialization unless required
if !numbered {
if i := strings.Index(name, "·"); i > 0 {
name = name[:i] // cut off numbering
}
}
return name
}
......@@ -775,18 +788,16 @@ func (p *exporter) float(x *Mpflt) {
// ----------------------------------------------------------------------------
// Inlined function bodies
func (p *exporter) inlinedBody(n *Node) {
index := -1 // index < 0 => not inlined
func (p *exporter) isInlineable(n *Node) bool {
if n != nil && n.Func != nil && len(n.Func.Inl.Slice()) != 0 {
// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
if Debug['l'] < 2 {
typecheckinl(n)
}
index = len(p.inlined) // index >= 0 => inlined
p.inlined = append(p.inlined, n.Func)
return true
}
p.int(index)
return false
}
func (p *exporter) nodeList(list Nodes) {
......
......@@ -77,16 +77,18 @@ func Import(in *bufio.Reader) {
for i := p.int(); i > 0; i-- {
// parser.go:hidden_fndcl
sym := p.localname()
typ := p.typ()
params := p.paramList()
result := p.paramList()
inl := p.int()
sig := functype(nil, params, result)
importsym(sym, ONAME)
if sym.Def != nil && sym.Def.Op == ONAME && !Eqtype(typ, sym.Def.Type) {
Fatalf("importer: inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, typ)
if sym.Def != nil && sym.Def.Op == ONAME && !Eqtype(sig, sym.Def.Type) {
Fatalf("importer: inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, sig)
}
n := newfuncname(sym)
n.Type = typ
n.Type = sig
declare(n, PFUNC)
funchdr(n)
......@@ -94,7 +96,7 @@ func Import(in *bufio.Reader) {
n.Func.Inl.Set(nil)
if inl >= 0 {
if inl != len(p.inlined) {
panic("inlined body list inconsistent")
panic(fmt.Sprintf("inlined body list inconsistent: %d != %d", inl, len(p.inlined)))
}
p.inlined = append(p.inlined, n.Func)
}
......@@ -113,7 +115,7 @@ func Import(in *bufio.Reader) {
// read inlined functions bodies
n := p.int()
for i := 0; i < n; i++ {
body := p.nodeList()
body := p.block()
const hookup = false // TODO(gri) enable and remove this condition
if hookup {
p.inlined[i].Inl.Set(body)
......@@ -265,7 +267,7 @@ func (p *importer) typ() *Type {
n.Func.Inl.Set(nil)
if inl >= 0 {
if inl != len(p.inlined) {
panic("inlined body list inconsistent")
panic(fmt.Sprintf("inlined body list inconsistent: %d != %d", inl, len(p.inlined)))
}
p.inlined = append(p.inlined, n.Func)
}
......@@ -542,6 +544,15 @@ func (p *importer) float(x *Mpflt) {
// ----------------------------------------------------------------------------
// Inlined function bodies
func (p *importer) block() []*Node {
markdcl()
// TODO(gri) populate "scope" with function parameters so they can be found
// inside the function body
list := p.nodeList()
popdcl()
return list
}
// parser.go:stmt_list
func (p *importer) nodeList() []*Node {
c := p.int()
......
......@@ -87,7 +87,9 @@ func BImportData(imports map[string]*types.Package, data []byte, path string) (i
// read funcs
for i := p.int(); i > 0; i-- {
name := p.string()
sig := p.typ(nil).(*types.Signature)
params, isddd := p.paramList()
result, _ := p.paramList()
sig := types.NewSignature(nil, params, result, isddd)
p.int() // read and discard index of inlined function body
p.declare(types.NewFunc(token.NoPos, pkg, name, sig))
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment