github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/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  	//print("reexportdep %+hN\n", n);
   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  	// Local variables in the bodies need their type.
   137  	case ODCL:
   138  		t := n.Left.Type
   139  
   140  		if t != types.Types[t.Etype] && t != types.Idealbool && t != types.Idealstring {
   141  			if t.IsPtr() {
   142  				t = t.Elem()
   143  			}
   144  			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
   145  				if Debug['E'] != 0 {
   146  					fmt.Printf("reexport type %v from declaration\n", t.Sym)
   147  				}
   148  				exportlist = append(exportlist, asNode(t.Sym.Def))
   149  			}
   150  		}
   151  
   152  	case OLITERAL:
   153  		t := n.Type
   154  		if t != types.Types[n.Type.Etype] && t != types.Idealbool && t != types.Idealstring {
   155  			if t.IsPtr() {
   156  				t = t.Elem()
   157  			}
   158  			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
   159  				if Debug['E'] != 0 {
   160  					fmt.Printf("reexport literal type %v\n", t.Sym)
   161  				}
   162  				exportlist = append(exportlist, asNode(t.Sym.Def))
   163  			}
   164  		}
   165  		fallthrough
   166  
   167  	case OTYPE:
   168  		if n.Sym != nil && n.Sym.Def != nil && !exportedsym(n.Sym) {
   169  			if Debug['E'] != 0 {
   170  				fmt.Printf("reexport literal/type %v\n", n.Sym)
   171  			}
   172  			exportlist = append(exportlist, n)
   173  		}
   174  
   175  	// for operations that need a type when rendered, put the type on the export list.
   176  	case OCONV,
   177  		OCONVIFACE,
   178  		OCONVNOP,
   179  		ORUNESTR,
   180  		OARRAYBYTESTR,
   181  		OARRAYRUNESTR,
   182  		OSTRARRAYBYTE,
   183  		OSTRARRAYRUNE,
   184  		ODOTTYPE,
   185  		ODOTTYPE2,
   186  		OSTRUCTLIT,
   187  		OARRAYLIT,
   188  		OSLICELIT,
   189  		OPTRLIT,
   190  		OMAKEMAP,
   191  		OMAKESLICE,
   192  		OMAKECHAN:
   193  		t := n.Type
   194  
   195  		switch t.Etype {
   196  		case TARRAY, TCHAN, TPTR32, TPTR64, TSLICE:
   197  			if t.Sym == nil {
   198  				t = t.Elem()
   199  			}
   200  		}
   201  		if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
   202  			if Debug['E'] != 0 {
   203  				fmt.Printf("reexport type for expression %v\n", t.Sym)
   204  			}
   205  			exportlist = append(exportlist, asNode(t.Sym.Def))
   206  		}
   207  	}
   208  
   209  	reexportdep(n.Left)
   210  	reexportdep(n.Right)
   211  	reexportdeplist(n.List)
   212  	reexportdeplist(n.Rlist)
   213  	reexportdeplist(n.Ninit)
   214  	reexportdeplist(n.Nbody)
   215  }
   216  
   217  // methodbyname sorts types by symbol name.
   218  type methodbyname []*types.Field
   219  
   220  func (x methodbyname) Len() int           { return len(x) }
   221  func (x methodbyname) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
   222  func (x methodbyname) Less(i, j int) bool { return x[i].Sym.Name < x[j].Sym.Name }
   223  
   224  func dumpexport() {
   225  	if buildid != "" {
   226  		exportf("build id %q\n", buildid)
   227  	}
   228  
   229  	size := 0 // size of export section without enclosing markers
   230  	// The linker also looks for the $$ marker - use char after $$ to distinguish format.
   231  	exportf("\n$$B\n") // indicate binary export format
   232  	if debugFormat {
   233  		// save a copy of the export data
   234  		var copy bytes.Buffer
   235  		bcopy := bufio.NewWriter(&copy)
   236  		size = export(bcopy, Debug_export != 0)
   237  		bcopy.Flush() // flushing to bytes.Buffer cannot fail
   238  		if n, err := bout.Write(copy.Bytes()); n != size || err != nil {
   239  			Fatalf("error writing export data: got %d bytes, want %d bytes, err = %v", n, size, err)
   240  		}
   241  		// export data must contain no '$' so that we can find the end by searching for "$$"
   242  		// TODO(gri) is this still needed?
   243  		if bytes.IndexByte(copy.Bytes(), '$') >= 0 {
   244  			Fatalf("export data contains $")
   245  		}
   246  
   247  		// verify that we can read the copied export data back in
   248  		// (use empty package map to avoid collisions)
   249  		types.CleanroomDo(func() {
   250  			Import(types.NewPkg("", ""), bufio.NewReader(&copy)) // must not die
   251  		})
   252  	} else {
   253  		size = export(bout.Writer, Debug_export != 0)
   254  	}
   255  	exportf("\n$$\n")
   256  
   257  	if Debug_export != 0 {
   258  		fmt.Printf("export data size = %d bytes\n", size)
   259  	}
   260  }
   261  
   262  // importsym declares symbol s as an imported object representable by op.
   263  // pkg is the package being imported
   264  func importsym(pkg *types.Pkg, s *types.Sym, op Op) {
   265  	if asNode(s.Def) != nil && asNode(s.Def).Op != op {
   266  		pkgstr := fmt.Sprintf("during import %q", pkg.Path)
   267  		redeclare(s, pkgstr)
   268  	}
   269  
   270  	// mark the symbol so it is not reexported
   271  	if asNode(s.Def) == nil {
   272  		if exportname(s.Name) || initname(s.Name) {
   273  			s.SetExport(true)
   274  		} else {
   275  			s.SetPackage(true) // package scope
   276  		}
   277  	}
   278  }
   279  
   280  // pkgtype returns the named type declared by symbol s.
   281  // If no such type has been declared yet, a forward declaration is returned.
   282  // pkg is the package being imported
   283  func pkgtype(pkg *types.Pkg, s *types.Sym) *types.Type {
   284  	importsym(pkg, s, OTYPE)
   285  	if asNode(s.Def) == nil || asNode(s.Def).Op != OTYPE {
   286  		t := types.New(TFORW)
   287  		t.Sym = s
   288  		s.Def = asTypesNode(typenod(t))
   289  		asNode(s.Def).Name = new(Name)
   290  	}
   291  
   292  	if asNode(s.Def).Type == nil {
   293  		Fatalf("pkgtype %v", s)
   294  	}
   295  	return asNode(s.Def).Type
   296  }
   297  
   298  // importconst declares symbol s as an imported constant with type t and value n.
   299  // pkg is the package being imported
   300  func importconst(pkg *types.Pkg, s *types.Sym, t *types.Type, n *Node) {
   301  	importsym(pkg, s, OLITERAL)
   302  	n = convlit(n, t)
   303  
   304  	if asNode(s.Def) != nil { // TODO: check if already the same.
   305  		return
   306  	}
   307  
   308  	if n.Op != OLITERAL {
   309  		yyerror("expression must be a constant")
   310  		return
   311  	}
   312  
   313  	if n.Sym != nil {
   314  		n1 := *n
   315  		n = &n1
   316  	}
   317  
   318  	n.Orig = newname(s)
   319  	n.Sym = s
   320  	declare(n, PEXTERN)
   321  
   322  	if Debug['E'] != 0 {
   323  		fmt.Printf("import const %v\n", s)
   324  	}
   325  }
   326  
   327  // importvar declares symbol s as an imported variable with type t.
   328  // pkg is the package being imported
   329  func importvar(pkg *types.Pkg, s *types.Sym, t *types.Type) {
   330  	importsym(pkg, s, ONAME)
   331  	if asNode(s.Def) != nil && asNode(s.Def).Op == ONAME {
   332  		if eqtype(t, asNode(s.Def).Type) {
   333  			return
   334  		}
   335  		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)
   336  	}
   337  
   338  	n := newname(s)
   339  	s.Importdef = pkg
   340  	n.Type = t
   341  	declare(n, PEXTERN)
   342  
   343  	if Debug['E'] != 0 {
   344  		fmt.Printf("import var %v %L\n", s, t)
   345  	}
   346  }
   347  
   348  // importalias declares symbol s as an imported type alias with type t.
   349  // pkg is the package being imported
   350  func importalias(pkg *types.Pkg, s *types.Sym, t *types.Type) {
   351  	importsym(pkg, s, OTYPE)
   352  	if asNode(s.Def) != nil && asNode(s.Def).Op == OTYPE {
   353  		if eqtype(t, asNode(s.Def).Type) {
   354  			return
   355  		}
   356  		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)
   357  	}
   358  
   359  	n := newname(s)
   360  	n.Op = OTYPE
   361  	s.Importdef = pkg
   362  	n.Type = t
   363  	declare(n, PEXTERN)
   364  
   365  	if Debug['E'] != 0 {
   366  		fmt.Printf("import type %v = %L\n", s, t)
   367  	}
   368  }
   369  
   370  func dumpasmhdr() {
   371  	b, err := bio.Create(asmhdr)
   372  	if err != nil {
   373  		Fatalf("%v", err)
   374  	}
   375  	fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", localpkg.Name)
   376  	for _, n := range asmlist {
   377  		if n.Sym.IsBlank() {
   378  			continue
   379  		}
   380  		switch n.Op {
   381  		case OLITERAL:
   382  			fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym.Name, n.Val())
   383  
   384  		case OTYPE:
   385  			t := n.Type
   386  			if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() {
   387  				break
   388  			}
   389  			fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width))
   390  			for _, t := range t.Fields().Slice() {
   391  				if !t.Sym.IsBlank() {
   392  					fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Offset))
   393  				}
   394  			}
   395  		}
   396  	}
   397  
   398  	b.Close()
   399  }