github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/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 object is on exportlist before aliases.
    49  	if n.Sym.Flags&SymAlias != 0 {
    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.Name.Param != nil && n.Name.Param.Ntype != nil && n.Name.Param.Ntype.Op == OTFUNC && n.Name.Param.Ntype.Left != 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  	//print("reexportdep %+hN\n", n);
   112  	switch n.Op {
   113  	case ONAME:
   114  		switch n.Class {
   115  		// methods will be printed along with their type
   116  		// nodes for T.Method expressions
   117  		case PFUNC:
   118  			if n.Left != nil && n.Left.Op == OTYPE {
   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[t.Etype] && t != idealbool && t != 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, t.Sym.Def)
   150  			}
   151  		}
   152  
   153  	case OLITERAL:
   154  		t := n.Type
   155  		if t != Types[n.Type.Etype] && t != idealbool && t != 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, 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, 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 []*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() {
   226  	if buildid != "" {
   227  		exportf("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("\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  		savedPkgMap := pkgMap
   251  		savedPkgs := pkgs
   252  		pkgMap = make(map[string]*Pkg)
   253  		pkgs = nil
   254  		importpkg = mkpkg("")
   255  		Import(bufio.NewReader(&copy)) // must not die
   256  		importpkg = nil
   257  		pkgs = savedPkgs
   258  		pkgMap = savedPkgMap
   259  	} else {
   260  		size = export(bout.Writer, Debug_export != 0)
   261  	}
   262  	exportf("\n$$\n")
   263  
   264  	if Debug_export != 0 {
   265  		fmt.Printf("export data size = %d bytes\n", size)
   266  	}
   267  }
   268  
   269  // importsym declares symbol s as an imported object representable by op.
   270  func importsym(s *Sym, op Op) {
   271  	if s.Def != nil && s.Def.Op != op {
   272  		pkgstr := fmt.Sprintf("during import %q", importpkg.Path)
   273  		redeclare(s, pkgstr)
   274  	}
   275  
   276  	// mark the symbol so it is not reexported
   277  	if s.Def == nil {
   278  		if exportname(s.Name) || initname(s.Name) {
   279  			s.Flags |= SymExport
   280  		} else {
   281  			s.Flags |= SymPackage // package scope
   282  		}
   283  	}
   284  }
   285  
   286  // pkgtype returns the named type declared by symbol s.
   287  // If no such type has been declared yet, a forward declaration is returned.
   288  func pkgtype(s *Sym) *Type {
   289  	importsym(s, OTYPE)
   290  	if s.Def == nil || s.Def.Op != OTYPE {
   291  		t := typ(TFORW)
   292  		t.Sym = s
   293  		s.Def = typenod(t)
   294  		s.Def.Name = new(Name)
   295  	}
   296  
   297  	if s.Def.Type == nil {
   298  		yyerror("pkgtype %v", s)
   299  	}
   300  	return s.Def.Type
   301  }
   302  
   303  // importconst declares symbol s as an imported constant with type t and value n.
   304  func importconst(s *Sym, t *Type, n *Node) {
   305  	importsym(s, OLITERAL)
   306  	n = convlit(n, t)
   307  
   308  	if s.Def != nil { // TODO: check if already the same.
   309  		return
   310  	}
   311  
   312  	if n.Op != OLITERAL {
   313  		yyerror("expression must be a constant")
   314  		return
   315  	}
   316  
   317  	if n.Sym != nil {
   318  		n1 := *n
   319  		n = &n1
   320  	}
   321  
   322  	n.Orig = newname(s)
   323  	n.Sym = s
   324  	declare(n, PEXTERN)
   325  
   326  	if Debug['E'] != 0 {
   327  		fmt.Printf("import const %v\n", s)
   328  	}
   329  }
   330  
   331  // importvar declares symbol s as an imported variable with type t.
   332  func importvar(s *Sym, t *Type) {
   333  	importsym(s, ONAME)
   334  	if s.Def != nil && s.Def.Op == ONAME {
   335  		if eqtype(t, s.Def.Type) {
   336  			return
   337  		}
   338  		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)
   339  	}
   340  
   341  	n := newname(s)
   342  	s.Importdef = importpkg
   343  	n.Type = t
   344  	declare(n, PEXTERN)
   345  
   346  	if Debug['E'] != 0 {
   347  		fmt.Printf("import var %v %L\n", s, t)
   348  	}
   349  }
   350  
   351  func dumpasmhdr() {
   352  	b, err := bio.Create(asmhdr)
   353  	if err != nil {
   354  		Fatalf("%v", err)
   355  	}
   356  	fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", localpkg.Name)
   357  	for _, n := range asmlist {
   358  		if isblanksym(n.Sym) {
   359  			continue
   360  		}
   361  		switch n.Op {
   362  		case OLITERAL:
   363  			fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym.Name, n.Val())
   364  
   365  		case OTYPE:
   366  			t := n.Type
   367  			if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() {
   368  				break
   369  			}
   370  			fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width))
   371  			for _, t := range t.Fields().Slice() {
   372  				if !isblanksym(t.Sym) {
   373  					fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Offset))
   374  				}
   375  			}
   376  		}
   377  	}
   378  
   379  	b.Close()
   380  }