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