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