github.com/euank/go@v0.0.0-20160829210321-495514729181/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  
    45  	if Debug['E'] != 0 {
    46  		fmt.Printf("export symbol %v\n", n.Sym)
    47  	}
    48  	exportlist = append(exportlist, n)
    49  }
    50  
    51  func exportname(s string) bool {
    52  	if r := s[0]; r < utf8.RuneSelf {
    53  		return 'A' <= r && r <= 'Z'
    54  	}
    55  	r, _ := utf8.DecodeRuneInString(s)
    56  	return unicode.IsUpper(r)
    57  }
    58  
    59  func initname(s string) bool {
    60  	return s == "init"
    61  }
    62  
    63  // exportedsym reports whether a symbol will be visible
    64  // to files that import our package.
    65  func exportedsym(sym *Sym) bool {
    66  	// Builtins are visible everywhere.
    67  	if sym.Pkg == builtinpkg || sym.Origpkg == builtinpkg {
    68  		return true
    69  	}
    70  
    71  	return sym.Pkg == localpkg && exportname(sym.Name)
    72  }
    73  
    74  func autoexport(n *Node, ctxt Class) {
    75  	if n == nil || n.Sym == nil {
    76  		return
    77  	}
    78  	if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN {
    79  		return
    80  	}
    81  	if n.Name.Param != nil && n.Name.Param.Ntype != nil && n.Name.Param.Ntype.Op == OTFUNC && n.Name.Param.Ntype.Left != nil { // method
    82  		return
    83  	}
    84  
    85  	// -A is for cmd/gc/mkbuiltin script, so export everything
    86  	if Debug['A'] != 0 || exportname(n.Sym.Name) || initname(n.Sym.Name) {
    87  		exportsym(n)
    88  	}
    89  	if asmhdr != "" && n.Sym.Pkg == localpkg && n.Sym.Flags&SymAsm == 0 {
    90  		n.Sym.Flags |= SymAsm
    91  		asmlist = append(asmlist, n)
    92  	}
    93  }
    94  
    95  // Look for anything we need for the inline body
    96  func reexportdeplist(ll Nodes) {
    97  	for _, n := range ll.Slice() {
    98  		reexportdep(n)
    99  	}
   100  }
   101  
   102  func reexportdep(n *Node) {
   103  	if n == nil {
   104  		return
   105  	}
   106  
   107  	//print("reexportdep %+hN\n", n);
   108  	switch n.Op {
   109  	case ONAME:
   110  		switch n.Class {
   111  		// methods will be printed along with their type
   112  		// nodes for T.Method expressions
   113  		case PFUNC:
   114  			if n.Left != nil && n.Left.Op == OTYPE {
   115  				break
   116  			}
   117  
   118  			// nodes for method calls.
   119  			if n.Type == nil || n.Type.Recv() != nil {
   120  				break
   121  			}
   122  			fallthrough
   123  
   124  		case PEXTERN:
   125  			if n.Sym != nil && !exportedsym(n.Sym) {
   126  				if Debug['E'] != 0 {
   127  					fmt.Printf("reexport name %v\n", n.Sym)
   128  				}
   129  				exportlist = append(exportlist, n)
   130  			}
   131  		}
   132  
   133  	// Local variables in the bodies need their type.
   134  	case ODCL:
   135  		t := n.Left.Type
   136  
   137  		if t != Types[t.Etype] && t != idealbool && t != idealstring {
   138  			if t.IsPtr() {
   139  				t = t.Elem()
   140  			}
   141  			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
   142  				if Debug['E'] != 0 {
   143  					fmt.Printf("reexport type %v from declaration\n", t.Sym)
   144  				}
   145  				exportlist = append(exportlist, t.Sym.Def)
   146  			}
   147  		}
   148  
   149  	case OLITERAL:
   150  		t := n.Type
   151  		if t != Types[n.Type.Etype] && t != idealbool && t != idealstring {
   152  			if t.IsPtr() {
   153  				t = t.Elem()
   154  			}
   155  			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
   156  				if Debug['E'] != 0 {
   157  					fmt.Printf("reexport literal type %v\n", t.Sym)
   158  				}
   159  				exportlist = append(exportlist, t.Sym.Def)
   160  			}
   161  		}
   162  		fallthrough
   163  
   164  	case OTYPE:
   165  		if n.Sym != nil && n.Sym.Def != nil && !exportedsym(n.Sym) {
   166  			if Debug['E'] != 0 {
   167  				fmt.Printf("reexport literal/type %v\n", n.Sym)
   168  			}
   169  			exportlist = append(exportlist, n)
   170  		}
   171  
   172  	// for operations that need a type when rendered, put the type on the export list.
   173  	case OCONV,
   174  		OCONVIFACE,
   175  		OCONVNOP,
   176  		ORUNESTR,
   177  		OARRAYBYTESTR,
   178  		OARRAYRUNESTR,
   179  		OSTRARRAYBYTE,
   180  		OSTRARRAYRUNE,
   181  		ODOTTYPE,
   182  		ODOTTYPE2,
   183  		OSTRUCTLIT,
   184  		OARRAYLIT,
   185  		OPTRLIT,
   186  		OMAKEMAP,
   187  		OMAKESLICE,
   188  		OMAKECHAN:
   189  		t := n.Type
   190  
   191  		switch t.Etype {
   192  		case TARRAY, TCHAN, TPTR32, TPTR64, TSLICE:
   193  			if t.Sym == nil {
   194  				t = t.Elem()
   195  			}
   196  		}
   197  		if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
   198  			if Debug['E'] != 0 {
   199  				fmt.Printf("reexport type for expression %v\n", t.Sym)
   200  			}
   201  			exportlist = append(exportlist, t.Sym.Def)
   202  		}
   203  	}
   204  
   205  	reexportdep(n.Left)
   206  	reexportdep(n.Right)
   207  	reexportdeplist(n.List)
   208  	reexportdeplist(n.Rlist)
   209  	reexportdeplist(n.Ninit)
   210  	reexportdeplist(n.Nbody)
   211  }
   212  
   213  // methodbyname sorts types by symbol name.
   214  type methodbyname []*Field
   215  
   216  func (x methodbyname) Len() int           { return len(x) }
   217  func (x methodbyname) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
   218  func (x methodbyname) Less(i, j int) bool { return x[i].Sym.Name < x[j].Sym.Name }
   219  
   220  func dumpexport() {
   221  	if buildid != "" {
   222  		exportf("build id %q\n", buildid)
   223  	}
   224  
   225  	size := 0 // size of export section without enclosing markers
   226  	// The linker also looks for the $$ marker - use char after $$ to distinguish format.
   227  	exportf("\n$$B\n") // indicate binary export format
   228  	if debugFormat {
   229  		// save a copy of the export data
   230  		var copy bytes.Buffer
   231  		bcopy := bufio.NewWriter(&copy)
   232  		size = export(bcopy, Debug_export != 0)
   233  		bcopy.Flush() // flushing to bytes.Buffer cannot fail
   234  		if n, err := bout.Write(copy.Bytes()); n != size || err != nil {
   235  			Fatalf("error writing export data: got %d bytes, want %d bytes, err = %v", n, size, err)
   236  		}
   237  		// export data must contain no '$' so that we can find the end by searching for "$$"
   238  		// TODO(gri) is this still needed?
   239  		if bytes.IndexByte(copy.Bytes(), '$') >= 0 {
   240  			Fatalf("export data contains $")
   241  		}
   242  
   243  		// verify that we can read the copied export data back in
   244  		// (use empty package map to avoid collisions)
   245  		savedPkgMap := pkgMap
   246  		savedPkgs := pkgs
   247  		pkgMap = make(map[string]*Pkg)
   248  		pkgs = nil
   249  		importpkg = mkpkg("")
   250  		Import(bufio.NewReader(&copy)) // must not die
   251  		importpkg = nil
   252  		pkgs = savedPkgs
   253  		pkgMap = savedPkgMap
   254  	} else {
   255  		size = export(bout.Writer, Debug_export != 0)
   256  	}
   257  	exportf("\n$$\n")
   258  
   259  	if Debug_export != 0 {
   260  		fmt.Printf("export data size = %d bytes\n", size)
   261  	}
   262  }
   263  
   264  // importsym declares symbol s as an imported object representable by op.
   265  func importsym(s *Sym, op Op) {
   266  	if s.Def != nil && s.Def.Op != op {
   267  		pkgstr := fmt.Sprintf("during import %q", importpkg.Path)
   268  		redeclare(s, pkgstr)
   269  	}
   270  
   271  	// mark the symbol so it is not reexported
   272  	if s.Def == nil {
   273  		if Debug['A'] != 0 || exportname(s.Name) || initname(s.Name) {
   274  			s.Flags |= SymExport
   275  		} else {
   276  			s.Flags |= SymPackage // 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  func pkgtype(s *Sym) *Type {
   284  	importsym(s, OTYPE)
   285  	if s.Def == nil || s.Def.Op != OTYPE {
   286  		t := typ(TFORW)
   287  		t.Sym = s
   288  		s.Def = typenod(t)
   289  		s.Def.Name = new(Name)
   290  	}
   291  
   292  	if s.Def.Type == nil {
   293  		Yyerror("pkgtype %v", s)
   294  	}
   295  	return s.Def.Type
   296  }
   297  
   298  // importconst declares symbol s as an imported constant with type t and value n.
   299  func importconst(s *Sym, t *Type, n *Node) {
   300  	importsym(s, OLITERAL)
   301  	n = convlit(n, t)
   302  
   303  	if s.Def != nil { // TODO: check if already the same.
   304  		return
   305  	}
   306  
   307  	if n.Op != OLITERAL {
   308  		Yyerror("expression must be a constant")
   309  		return
   310  	}
   311  
   312  	if n.Sym != nil {
   313  		n1 := *n
   314  		n = &n1
   315  	}
   316  
   317  	n.Orig = newname(s)
   318  	n.Sym = s
   319  	declare(n, PEXTERN)
   320  
   321  	if Debug['E'] != 0 {
   322  		fmt.Printf("import const %v\n", s)
   323  	}
   324  }
   325  
   326  // importvar declares symbol s as an imported variable with type t.
   327  func importvar(s *Sym, t *Type) {
   328  	importsym(s, ONAME)
   329  	if s.Def != nil && s.Def.Op == ONAME {
   330  		if Eqtype(t, s.Def.Type) {
   331  			return
   332  		}
   333  		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)
   334  	}
   335  
   336  	n := newname(s)
   337  	s.Importdef = importpkg
   338  	n.Type = t
   339  	declare(n, PEXTERN)
   340  
   341  	if Debug['E'] != 0 {
   342  		fmt.Printf("import var %v %v\n", s, Tconv(t, FmtLong))
   343  	}
   344  }
   345  
   346  // importtype and importer.importtype (bimport.go) need to remain in sync.
   347  func importtype(pt *Type, t *Type) {
   348  	// override declaration in unsafe.go for Pointer.
   349  	// there is no way in Go code to define unsafe.Pointer
   350  	// so we have to supply it.
   351  	if incannedimport != 0 && importpkg.Name == "unsafe" && pt.Nod.Sym.Name == "Pointer" {
   352  		t = Types[TUNSAFEPTR]
   353  	}
   354  
   355  	if pt.Etype == TFORW {
   356  		n := pt.Nod
   357  		copytype(pt.Nod, t)
   358  		pt.Nod = n // unzero nod
   359  		pt.Sym.Importdef = importpkg
   360  		pt.Sym.Lastlineno = lineno
   361  		declare(n, PEXTERN)
   362  		checkwidth(pt)
   363  	} else if !Eqtype(pt.Orig, t) {
   364  		Yyerror("inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)", pt.Sym, Tconv(pt, FmtLong), pt.Sym.Importdef.Path, Tconv(t, FmtLong), importpkg.Path)
   365  	}
   366  
   367  	if Debug['E'] != 0 {
   368  		fmt.Printf("import type %v %v\n", pt, Tconv(t, FmtLong))
   369  	}
   370  }
   371  
   372  func dumpasmhdr() {
   373  	b, err := bio.Create(asmhdr)
   374  	if err != nil {
   375  		Fatalf("%v", err)
   376  	}
   377  	fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", localpkg.Name)
   378  	for _, n := range asmlist {
   379  		if isblanksym(n.Sym) {
   380  			continue
   381  		}
   382  		switch n.Op {
   383  		case OLITERAL:
   384  			fmt.Fprintf(b, "#define const_%s %v\n", n.Sym.Name, vconv(n.Val(), FmtSharp))
   385  
   386  		case OTYPE:
   387  			t := n.Type
   388  			if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() {
   389  				break
   390  			}
   391  			fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width))
   392  			for _, t := range t.Fields().Slice() {
   393  				if !isblanksym(t.Sym) {
   394  					fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Offset))
   395  				}
   396  			}
   397  		}
   398  	}
   399  
   400  	b.Close()
   401  }