github.com/rakyll/go@v0.0.0-20170216000551-64c02460d703/src/cmd/compile/internal/gc/export.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package gc
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"cmd/internal/bio"
    11  	"fmt"
    12  	"unicode"
    13  	"unicode/utf8"
    14  )
    15  
    16  var (
    17  	Debug_export int // if set, print debugging information about export data
    18  	exportsize   int
    19  )
    20  
    21  func exportf(format string, args ...interface{}) {
    22  	n, _ := fmt.Fprintf(bout, format, args...)
    23  	exportsize += n
    24  	if Debug_export != 0 {
    25  		fmt.Printf(format, args...)
    26  	}
    27  }
    28  
    29  var asmlist []*Node
    30  
    31  // Mark n's symbol as exported
    32  func exportsym(n *Node) {
    33  	if n == nil || n.Sym == nil {
    34  		return
    35  	}
    36  	if n.Sym.Flags&(SymExport|SymPackage) != 0 {
    37  		if n.Sym.Flags&SymPackage != 0 {
    38  			yyerror("export/package mismatch: %v", n.Sym)
    39  		}
    40  		return
    41  	}
    42  
    43  	n.Sym.Flags |= SymExport
    44  	if Debug['E'] != 0 {
    45  		fmt.Printf("export symbol %v\n", n.Sym)
    46  	}
    47  
    48  	// Ensure original types are on exportlist before type aliases.
    49  	if n.Sym.isAlias() {
    50  		exportlist = append(exportlist, n.Sym.Def)
    51  	}
    52  
    53  	exportlist = append(exportlist, n)
    54  }
    55  
    56  func exportname(s string) bool {
    57  	if r := s[0]; r < utf8.RuneSelf {
    58  		return 'A' <= r && r <= 'Z'
    59  	}
    60  	r, _ := utf8.DecodeRuneInString(s)
    61  	return unicode.IsUpper(r)
    62  }
    63  
    64  func initname(s string) bool {
    65  	return s == "init"
    66  }
    67  
    68  // exportedsym reports whether a symbol will be visible
    69  // to files that import our package.
    70  func exportedsym(sym *Sym) bool {
    71  	// Builtins are visible everywhere.
    72  	if sym.Pkg == builtinpkg || sym.Origpkg == builtinpkg {
    73  		return true
    74  	}
    75  
    76  	return sym.Pkg == localpkg && exportname(sym.Name)
    77  }
    78  
    79  func autoexport(n *Node, ctxt Class) {
    80  	if n == nil || n.Sym == nil {
    81  		return
    82  	}
    83  	if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN {
    84  		return
    85  	}
    86  	if n.Type != nil && n.Type.IsKind(TFUNC) && n.Type.Recv() != nil { // method
    87  		return
    88  	}
    89  
    90  	if exportname(n.Sym.Name) || initname(n.Sym.Name) {
    91  		exportsym(n)
    92  	}
    93  	if asmhdr != "" && n.Sym.Pkg == localpkg && n.Sym.Flags&SymAsm == 0 {
    94  		n.Sym.Flags |= SymAsm
    95  		asmlist = append(asmlist, n)
    96  	}
    97  }
    98  
    99  // Look for anything we need for the inline body
   100  func reexportdeplist(ll Nodes) {
   101  	for _, n := range ll.Slice() {
   102  		reexportdep(n)
   103  	}
   104  }
   105  
   106  func reexportdep(n *Node) {
   107  	if n == nil {
   108  		return
   109  	}
   110  
   111  	switch n.Op {
   112  	case ONAME:
   113  		switch n.Class {
   114  		// methods will be printed along with their type
   115  		// nodes for T.Method expressions
   116  		case PFUNC:
   117  			if n.Left != nil && n.Left.Op == OTYPE {
   118  				break
   119  			}
   120  
   121  			// nodes for method calls.
   122  			if n.Type == nil || n.IsMethod() {
   123  				break
   124  			}
   125  			fallthrough
   126  
   127  		case PEXTERN:
   128  			if n.Sym != nil && !exportedsym(n.Sym) {
   129  				if Debug['E'] != 0 {
   130  					fmt.Printf("reexport name %v\n", n.Sym)
   131  				}
   132  				exportlist = append(exportlist, n)
   133  			}
   134  		}
   135  	}
   136  
   137  	reexportdep(n.Left)
   138  	reexportdep(n.Right)
   139  	reexportdeplist(n.List)
   140  	reexportdeplist(n.Rlist)
   141  	reexportdeplist(n.Ninit)
   142  	reexportdeplist(n.Nbody)
   143  }
   144  
   145  // methodbyname sorts types by symbol name.
   146  type methodbyname []*Field
   147  
   148  func (x methodbyname) Len() int           { return len(x) }
   149  func (x methodbyname) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
   150  func (x methodbyname) Less(i, j int) bool { return x[i].Sym.Name < x[j].Sym.Name }
   151  
   152  func dumpexport() {
   153  	if buildid != "" {
   154  		exportf("build id %q\n", buildid)
   155  	}
   156  
   157  	size := 0 // size of export section without enclosing markers
   158  	// The linker also looks for the $$ marker - use char after $$ to distinguish format.
   159  	exportf("\n$$B\n") // indicate binary export format
   160  	if debugFormat {
   161  		// save a copy of the export data
   162  		var copy bytes.Buffer
   163  		bcopy := bufio.NewWriter(&copy)
   164  		size = export(bcopy, Debug_export != 0)
   165  		bcopy.Flush() // flushing to bytes.Buffer cannot fail
   166  		if n, err := bout.Write(copy.Bytes()); n != size || err != nil {
   167  			Fatalf("error writing export data: got %d bytes, want %d bytes, err = %v", n, size, err)
   168  		}
   169  		// export data must contain no '$' so that we can find the end by searching for "$$"
   170  		// TODO(gri) is this still needed?
   171  		if bytes.IndexByte(copy.Bytes(), '$') >= 0 {
   172  			Fatalf("export data contains $")
   173  		}
   174  
   175  		// verify that we can read the copied export data back in
   176  		// (use empty package map to avoid collisions)
   177  		savedPkgMap := pkgMap
   178  		savedPkgs := pkgs
   179  		pkgMap = make(map[string]*Pkg)
   180  		pkgs = nil
   181  		importpkg = mkpkg("")
   182  		Import(bufio.NewReader(&copy)) // must not die
   183  		importpkg = nil
   184  		pkgs = savedPkgs
   185  		pkgMap = savedPkgMap
   186  	} else {
   187  		size = export(bout.Writer, Debug_export != 0)
   188  	}
   189  	exportf("\n$$\n")
   190  
   191  	if Debug_export != 0 {
   192  		fmt.Printf("export data size = %d bytes\n", size)
   193  	}
   194  }
   195  
   196  // importsym declares symbol s as an imported object representable by op.
   197  func importsym(s *Sym, op Op) {
   198  	if s.Def != nil && s.Def.Op != op {
   199  		pkgstr := fmt.Sprintf("during import %q", importpkg.Path)
   200  		redeclare(s, pkgstr)
   201  	}
   202  
   203  	// mark the symbol so it is not reexported
   204  	if s.Def == nil {
   205  		if exportname(s.Name) || initname(s.Name) {
   206  			s.Flags |= SymExport
   207  		} else {
   208  			s.Flags |= SymPackage // package scope
   209  		}
   210  	}
   211  }
   212  
   213  // pkgtype returns the named type declared by symbol s.
   214  // If no such type has been declared yet, a forward declaration is returned.
   215  func pkgtype(s *Sym) *Type {
   216  	importsym(s, OTYPE)
   217  	if s.Def == nil || s.Def.Op != OTYPE {
   218  		t := typ(TFORW)
   219  		t.Sym = s
   220  		s.Def = typenod(t)
   221  		s.Def.Name = new(Name)
   222  	}
   223  
   224  	if s.Def.Type == nil {
   225  		yyerror("pkgtype %v", s)
   226  	}
   227  	return s.Def.Type
   228  }
   229  
   230  // importconst declares symbol s as an imported constant with type t and value n.
   231  func importconst(s *Sym, t *Type, n *Node) {
   232  	importsym(s, OLITERAL)
   233  	n = convlit(n, t)
   234  
   235  	if s.Def != nil { // TODO: check if already the same.
   236  		return
   237  	}
   238  
   239  	if n.Op != OLITERAL {
   240  		yyerror("expression must be a constant")
   241  		return
   242  	}
   243  
   244  	if n.Sym != nil {
   245  		n1 := *n
   246  		n = &n1
   247  	}
   248  
   249  	n.Orig = newname(s)
   250  	n.Sym = s
   251  	declare(n, PEXTERN)
   252  
   253  	if Debug['E'] != 0 {
   254  		fmt.Printf("import const %v\n", s)
   255  	}
   256  }
   257  
   258  // importvar declares symbol s as an imported variable with type t.
   259  func importvar(s *Sym, t *Type) {
   260  	importsym(s, ONAME)
   261  	if s.Def != nil && s.Def.Op == ONAME {
   262  		if eqtype(t, s.Def.Type) {
   263  			return
   264  		}
   265  		yyerror("inconsistent definition for var %v during import\n\t%v (in %q)\n\t%v (in %q)", s, s.Def.Type, s.Importdef.Path, t, importpkg.Path)
   266  	}
   267  
   268  	n := newname(s)
   269  	s.Importdef = importpkg
   270  	n.Type = t
   271  	declare(n, PEXTERN)
   272  
   273  	if Debug['E'] != 0 {
   274  		fmt.Printf("import var %v %L\n", s, t)
   275  	}
   276  }
   277  
   278  // importalias declares symbol s as an imported type alias with type t.
   279  func importalias(s *Sym, t *Type) {
   280  	importsym(s, OTYPE)
   281  	if s.Def != nil && s.Def.Op == OTYPE {
   282  		if eqtype(t, s.Def.Type) {
   283  			return
   284  		}
   285  		yyerror("inconsistent definition for type alias %v during import\n\t%v (in %q)\n\t%v (in %q)", s, s.Def.Type, s.Importdef.Path, t, importpkg.Path)
   286  	}
   287  
   288  	n := newname(s)
   289  	n.Op = OTYPE
   290  	s.Importdef = importpkg
   291  	n.Type = t
   292  	declare(n, PEXTERN)
   293  
   294  	if Debug['E'] != 0 {
   295  		fmt.Printf("import type %v = %L\n", s, t)
   296  	}
   297  }
   298  
   299  func dumpasmhdr() {
   300  	b, err := bio.Create(asmhdr)
   301  	if err != nil {
   302  		Fatalf("%v", err)
   303  	}
   304  	fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", localpkg.Name)
   305  	for _, n := range asmlist {
   306  		if isblanksym(n.Sym) {
   307  			continue
   308  		}
   309  		switch n.Op {
   310  		case OLITERAL:
   311  			fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym.Name, n.Val())
   312  
   313  		case OTYPE:
   314  			t := n.Type
   315  			if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() {
   316  				break
   317  			}
   318  			fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width))
   319  			for _, t := range t.Fields().Slice() {
   320  				if !isblanksym(t.Sym) {
   321  					fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Offset))
   322  				}
   323  			}
   324  		}
   325  	}
   326  
   327  	b.Close()
   328  }