github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/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  	if exportname(n.Sym.Name) || initname(n.Sym.Name) {
    86  		exportsym(n)
    87  	}
    88  	if asmhdr != "" && n.Sym.Pkg == localpkg && n.Sym.Flags&SymAsm == 0 {
    89  		n.Sym.Flags |= SymAsm
    90  		asmlist = append(asmlist, n)
    91  	}
    92  }
    93  
    94  // Look for anything we need for the inline body
    95  func reexportdeplist(ll Nodes) {
    96  	for _, n := range ll.Slice() {
    97  		reexportdep(n)
    98  	}
    99  }
   100  
   101  func reexportdep(n *Node) {
   102  	if n == nil {
   103  		return
   104  	}
   105  
   106  	//print("reexportdep %+hN\n", n);
   107  	switch n.Op {
   108  	case ONAME:
   109  		switch n.Class {
   110  		// methods will be printed along with their type
   111  		// nodes for T.Method expressions
   112  		case PFUNC:
   113  			if n.Left != nil && n.Left.Op == OTYPE {
   114  				break
   115  			}
   116  
   117  			// nodes for method calls.
   118  			if n.Type == nil || n.IsMethod() {
   119  				break
   120  			}
   121  			fallthrough
   122  
   123  		case PEXTERN:
   124  			if n.Sym != nil && !exportedsym(n.Sym) {
   125  				if Debug['E'] != 0 {
   126  					fmt.Printf("reexport name %v\n", n.Sym)
   127  				}
   128  				exportlist = append(exportlist, n)
   129  			}
   130  		}
   131  
   132  	// Local variables in the bodies need their type.
   133  	case ODCL:
   134  		t := n.Left.Type
   135  
   136  		if t != Types[t.Etype] && t != idealbool && t != idealstring {
   137  			if t.IsPtr() {
   138  				t = t.Elem()
   139  			}
   140  			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
   141  				if Debug['E'] != 0 {
   142  					fmt.Printf("reexport type %v from declaration\n", t.Sym)
   143  				}
   144  				exportlist = append(exportlist, t.Sym.Def)
   145  			}
   146  		}
   147  
   148  	case OLITERAL:
   149  		t := n.Type
   150  		if t != Types[n.Type.Etype] && t != idealbool && t != idealstring {
   151  			if t.IsPtr() {
   152  				t = t.Elem()
   153  			}
   154  			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
   155  				if Debug['E'] != 0 {
   156  					fmt.Printf("reexport literal type %v\n", t.Sym)
   157  				}
   158  				exportlist = append(exportlist, t.Sym.Def)
   159  			}
   160  		}
   161  		fallthrough
   162  
   163  	case OTYPE:
   164  		if n.Sym != nil && n.Sym.Def != nil && !exportedsym(n.Sym) {
   165  			if Debug['E'] != 0 {
   166  				fmt.Printf("reexport literal/type %v\n", n.Sym)
   167  			}
   168  			exportlist = append(exportlist, n)
   169  		}
   170  
   171  	// for operations that need a type when rendered, put the type on the export list.
   172  	case OCONV,
   173  		OCONVIFACE,
   174  		OCONVNOP,
   175  		ORUNESTR,
   176  		OARRAYBYTESTR,
   177  		OARRAYRUNESTR,
   178  		OSTRARRAYBYTE,
   179  		OSTRARRAYRUNE,
   180  		ODOTTYPE,
   181  		ODOTTYPE2,
   182  		OSTRUCTLIT,
   183  		OARRAYLIT,
   184  		OSLICELIT,
   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 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 %L\n", s, t)
   343  	}
   344  }
   345  
   346  func dumpasmhdr() {
   347  	b, err := bio.Create(asmhdr)
   348  	if err != nil {
   349  		Fatalf("%v", err)
   350  	}
   351  	fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", localpkg.Name)
   352  	for _, n := range asmlist {
   353  		if isblanksym(n.Sym) {
   354  			continue
   355  		}
   356  		switch n.Op {
   357  		case OLITERAL:
   358  			fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym.Name, n.Val())
   359  
   360  		case OTYPE:
   361  			t := n.Type
   362  			if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() {
   363  				break
   364  			}
   365  			fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width))
   366  			for _, t := range t.Fields().Slice() {
   367  				if !isblanksym(t.Sym) {
   368  					fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Offset))
   369  				}
   370  			}
   371  		}
   372  	}
   373  
   374  	b.Close()
   375  }