diff options
Diffstat (limited to 'src/cmd/compile/internal/gc/export.go')
-rw-r--r-- | src/cmd/compile/internal/gc/export.go | 191 |
1 files changed, 84 insertions, 107 deletions
diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go index 2855f815be..a414962431 100644 --- a/src/cmd/compile/internal/gc/export.go +++ b/src/cmd/compile/internal/gc/export.go @@ -7,9 +7,9 @@ package gc import ( "cmd/compile/internal/base" "cmd/compile/internal/ir" + "cmd/compile/internal/typecheck" "cmd/compile/internal/types" "cmd/internal/bio" - "cmd/internal/src" "fmt" "go/constant" ) @@ -21,54 +21,16 @@ func exportf(bout *bio.Writer, format string, args ...interface{}) { } } -// exportsym marks n for export (or reexport). -func exportsym(n *ir.Name) { - if n.Sym().OnExportList() { - return - } - n.Sym().SetOnExportList(true) - - if base.Flag.E != 0 { - fmt.Printf("export symbol %v\n", n.Sym()) - } - - Target.Exports = append(Target.Exports, n) -} - -func initname(s string) bool { - return s == "init" -} - -func autoexport(n *ir.Name, ctxt ir.Class) { - if n.Sym().Pkg != types.LocalPkg { - return - } - if (ctxt != ir.PEXTERN && ctxt != ir.PFUNC) || dclcontext != ir.PEXTERN { - return - } - if n.Type() != nil && n.Type().IsKind(types.TFUNC) && ir.IsMethod(n) { - return - } - - if types.IsExported(n.Sym().Name) || initname(n.Sym().Name) { - exportsym(n) - } - if base.Flag.AsmHdr != "" && !n.Sym().Asm() { - n.Sym().SetAsm(true) - Target.Asms = append(Target.Asms, n) - } -} - func dumpexport(bout *bio.Writer) { p := &exporter{marked: make(map[*types.Type]bool)} - for _, n := range Target.Exports { + for _, n := range typecheck.Target.Exports { p.markObject(n) } // The linker also looks for the $$ marker - use char after $$ to distinguish format. exportf(bout, "\n$$B\n") // indicate binary export format off := bout.Offset() - iexport(bout.Writer) + typecheck.WriteExports(bout.Writer) size := bout.Offset() - off exportf(bout, "\n$$\n") @@ -77,78 +39,13 @@ func dumpexport(bout *bio.Writer) { } } -func importsym(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Class) *ir.Name { - if n := s.PkgDef(); n != nil { - base.Fatalf("importsym of symbol that already exists: %v", n) - } - - n := ir.NewDeclNameAt(pos, op, s) - n.Class_ = ctxt // TODO(mdempsky): Move this into NewDeclNameAt too? - s.SetPkgDef(n) - s.Importdef = ipkg - return n -} - -// importtype returns the named type declared by symbol s. -// If no such type has been declared yet, a forward declaration is returned. -// ipkg is the package being imported -func importtype(ipkg *types.Pkg, pos src.XPos, s *types.Sym) *ir.Name { - n := importsym(ipkg, pos, s, ir.OTYPE, ir.PEXTERN) - n.SetType(types.NewNamed(n)) - return n -} - -// importobj declares symbol s as an imported object representable by op. -// ipkg is the package being imported -func importobj(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Class, t *types.Type) *ir.Name { - n := importsym(ipkg, pos, s, op, ctxt) - n.SetType(t) - if ctxt == ir.PFUNC { - n.Sym().SetFunc(true) - } - return n -} - -// importconst declares symbol s as an imported constant with type t and value val. -// ipkg is the package being imported -func importconst(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type, val constant.Value) *ir.Name { - n := importobj(ipkg, pos, s, ir.OLITERAL, ir.PEXTERN, t) - n.SetVal(val) - return n -} - -// importfunc declares symbol s as an imported function with type t. -// ipkg is the package being imported -func importfunc(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name { - n := importobj(ipkg, pos, s, ir.ONAME, ir.PFUNC, t) - - fn := ir.NewFunc(pos) - fn.SetType(t) - n.SetFunc(fn) - fn.Nname = n - - return n -} - -// importvar declares symbol s as an imported variable with type t. -// ipkg is the package being imported -func importvar(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name { - return importobj(ipkg, pos, s, ir.ONAME, ir.PEXTERN, t) -} - -// importalias declares symbol s as an imported type alias with type t. -// ipkg is the package being imported -func importalias(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name { - return importobj(ipkg, pos, s, ir.OTYPE, ir.PEXTERN, t) -} - func dumpasmhdr() { b, err := bio.Create(base.Flag.AsmHdr) if err != nil { base.Fatalf("%v", err) } fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", types.LocalPkg.Name) - for _, n := range Target.Asms { + for _, n := range typecheck.Target.Asms { if n.Sym().IsBlank() { continue } @@ -176,3 +73,83 @@ func dumpasmhdr() { b.Close() } + +type exporter struct { + marked map[*types.Type]bool // types already seen by markType +} + +// markObject visits a reachable object. +func (p *exporter) markObject(n ir.Node) { + if n.Op() == ir.ONAME { + n := n.(*ir.Name) + if n.Class_ == ir.PFUNC { + inlFlood(n, typecheck.Export) + } + } + + p.markType(n.Type()) +} + +// markType recursively visits types reachable from t to identify +// functions whose inline bodies may be needed. +func (p *exporter) markType(t *types.Type) { + if p.marked[t] { + return + } + p.marked[t] = true + + // If this is a named type, mark all of its associated + // methods. Skip interface types because t.Methods contains + // only their unexpanded method set (i.e., exclusive of + // interface embeddings), and the switch statement below + // handles their full method set. + if t.Sym() != nil && t.Kind() != types.TINTER { + for _, m := range t.Methods().Slice() { + if types.IsExported(m.Sym.Name) { + p.markObject(ir.AsNode(m.Nname)) + } + } + } + + // Recursively mark any types that can be produced given a + // value of type t: dereferencing a pointer; indexing or + // iterating over an array, slice, or map; receiving from a + // channel; accessing a struct field or interface method; or + // calling a function. + // + // Notably, we don't mark function parameter types, because + // the user already needs some way to construct values of + // those types. + switch t.Kind() { + case types.TPTR, types.TARRAY, types.TSLICE: + p.markType(t.Elem()) + + case types.TCHAN: + if t.ChanDir().CanRecv() { + p.markType(t.Elem()) + } + + case types.TMAP: + p.markType(t.Key()) + p.markType(t.Elem()) + + case types.TSTRUCT: + for _, f := range t.FieldSlice() { + if types.IsExported(f.Sym.Name) || f.Embedded != 0 { + p.markType(f.Type) + } + } + + case types.TFUNC: + for _, f := range t.Results().FieldSlice() { + p.markType(f.Type) + } + + case types.TINTER: + for _, f := range t.FieldSlice() { + if types.IsExported(f.Sym.Name) { + p.markType(f.Type) + } + } + } +} |