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