| // 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/compile/internal/base" |
| "cmd/compile/internal/inline" |
| "cmd/compile/internal/ir" |
| "cmd/compile/internal/typecheck" |
| "cmd/compile/internal/types" |
| "cmd/internal/bio" |
| "fmt" |
| "go/constant" |
| ) |
| |
| func exportf(bout *bio.Writer, format string, args ...interface{}) { |
| fmt.Fprintf(bout, format, args...) |
| if base.Debug.Export != 0 { |
| fmt.Printf(format, args...) |
| } |
| } |
| |
| func dumpexport(bout *bio.Writer) { |
| p := &exporter{marked: make(map[*types.Type]bool)} |
| for _, n := range typecheck.Target.Exports { |
| // Must catch it here rather than Export(), because the type can be |
| // not fully set (still TFORW) when Export() is called. |
| if n.Type() != nil && n.Type().HasTParam() { |
| base.Fatalf("Cannot (yet) export a generic type: %v", n) |
| } |
| 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() |
| typecheck.WriteExports(bout.Writer) |
| size := bout.Offset() - off |
| exportf(bout, "\n$$\n") |
| |
| if base.Debug.Export != 0 { |
| fmt.Printf("BenchmarkExportSize:%s 1 %d bytes\n", base.Ctxt.Pkgpath, size) |
| } |
| } |
| |
| 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 typecheck.Target.Asms { |
| if n.Sym().IsBlank() { |
| continue |
| } |
| switch n.Op() { |
| case ir.OLITERAL: |
| t := n.Val().Kind() |
| if t == constant.Float || t == constant.Complex { |
| break |
| } |
| fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym().Name, n.Val()) |
| |
| case ir.OTYPE: |
| t := n.Type() |
| if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() { |
| break |
| } |
| fmt.Fprintf(b, "#define %s__size %d\n", n.Sym().Name, int(t.Width)) |
| for _, f := range t.Fields().Slice() { |
| if !f.Sym.IsBlank() { |
| fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym().Name, f.Sym.Name, int(f.Offset)) |
| } |
| } |
| } |
| } |
| |
| 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 { |
| inline.Inline_Flood(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.AllMethods().Slice() { |
| if types.IsExported(f.Sym.Name) { |
| p.markType(f.Type) |
| } |
| } |
| } |
| } |