mirror of
https://github.com/golang/go
synced 2024-11-19 11:14:47 -07:00
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/20605 Reviewed-by: Alan Donovan <adonovan@google.com> Run-TryBot: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
2e9369067b
commit
eb4d1be285
@ -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) {
|
|||||||
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) {
|
|||||||
|
|
||||||
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) {
|
|||||||
// 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 {
|
|||||||
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) {
|
|||||||
// (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) {
|
|||||||
}
|
}
|
||||||
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) {
|
|||||||
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,9 +698,11 @@ 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 i := strings.Index(name, "·"); i > 0 {
|
if !numbered {
|
||||||
name = name[:i] // cut off numbering
|
if i := strings.Index(name, "·"); i > 0 {
|
||||||
|
name = name[:i] // cut off numbering
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
@ -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) {
|
|||||||
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) {
|
|||||||
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) {
|
|||||||
// 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 {
|
|||||||
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) {
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// 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
|
|||||||
// 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))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user