github.com/zxy12/golang151_with_comment@v0.0.0-20190507085033-721809559d3c/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  	"cmd/internal/obj"
     9  	"fmt"
    10  	"sort"
    11  	"unicode"
    12  	"unicode/utf8"
    13  )
    14  
    15  var asmlist *NodeList
    16  
    17  // Mark n's symbol as exported
    18  func exportsym(n *Node) {
    19  	if n == nil || n.Sym == nil {
    20  		return
    21  	}
    22  	if n.Sym.Flags&(SymExport|SymPackage) != 0 {
    23  		if n.Sym.Flags&SymPackage != 0 {
    24  			Yyerror("export/package mismatch: %v", n.Sym)
    25  		}
    26  		return
    27  	}
    28  
    29  	n.Sym.Flags |= SymExport
    30  
    31  	if Debug['E'] != 0 {
    32  		fmt.Printf("export symbol %v\n", n.Sym)
    33  	}
    34  	exportlist = list(exportlist, n)
    35  }
    36  
    37  func exportname(s string) bool {
    38  	if s[0] < utf8.RuneSelf {
    39  		return 'A' <= s[0] && s[0] <= 'Z'
    40  	}
    41  	r, _ := utf8.DecodeRuneInString(s)
    42  	return unicode.IsUpper(r)
    43  }
    44  
    45  func initname(s string) bool {
    46  	return s == "init"
    47  }
    48  
    49  // exportedsym reports whether a symbol will be visible
    50  // to files that import our package.
    51  func exportedsym(sym *Sym) bool {
    52  	// Builtins are visible everywhere.
    53  	if sym.Pkg == builtinpkg || sym.Origpkg == builtinpkg {
    54  		return true
    55  	}
    56  
    57  	return sym.Pkg == localpkg && exportname(sym.Name)
    58  }
    59  
    60  func autoexport(n *Node, ctxt uint8) {
    61  	if n == nil || n.Sym == nil {
    62  		return
    63  	}
    64  	if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN {
    65  		return
    66  	}
    67  	if n.Name.Param != nil && n.Name.Param.Ntype != nil && n.Name.Param.Ntype.Op == OTFUNC && n.Name.Param.Ntype.Left != nil { // method
    68  		return
    69  	}
    70  
    71  	// -A is for cmd/gc/mkbuiltin script, so export everything
    72  	if Debug['A'] != 0 || exportname(n.Sym.Name) || initname(n.Sym.Name) {
    73  		exportsym(n)
    74  	}
    75  	if asmhdr != "" && n.Sym.Pkg == localpkg && n.Sym.Flags&SymAsm == 0 {
    76  		n.Sym.Flags |= SymAsm
    77  		asmlist = list(asmlist, n)
    78  	}
    79  }
    80  
    81  func dumppkg(p *Pkg) {
    82  	if p == nil || p == localpkg || p.Exported != 0 || p == builtinpkg {
    83  		return
    84  	}
    85  	p.Exported = 1
    86  	suffix := ""
    87  	if p.Direct == 0 {
    88  		suffix = " // indirect"
    89  	}
    90  	fmt.Fprintf(bout, "\timport %s %q%s\n", p.Name, p.Path, suffix)
    91  }
    92  
    93  // Look for anything we need for the inline body
    94  func reexportdeplist(ll *NodeList) {
    95  	for ; ll != nil; ll = ll.Next {
    96  		reexportdep(ll.N)
    97  	}
    98  }
    99  
   100  func reexportdep(n *Node) {
   101  	if n == nil {
   102  		return
   103  	}
   104  
   105  	//print("reexportdep %+hN\n", n);
   106  	switch n.Op {
   107  	case ONAME:
   108  		switch n.Class &^ PHEAP {
   109  		// methods will be printed along with their type
   110  		// nodes for T.Method expressions
   111  		case PFUNC:
   112  			if n.Left != nil && n.Left.Op == OTYPE {
   113  				break
   114  			}
   115  
   116  			// nodes for method calls.
   117  			if n.Type == nil || n.Type.Thistuple > 0 {
   118  				break
   119  			}
   120  			fallthrough
   121  
   122  		case PEXTERN:
   123  			if n.Sym != nil && !exportedsym(n.Sym) {
   124  				if Debug['E'] != 0 {
   125  					fmt.Printf("reexport name %v\n", n.Sym)
   126  				}
   127  				exportlist = list(exportlist, n)
   128  			}
   129  		}
   130  
   131  		// Local variables in the bodies need their type.
   132  	case ODCL:
   133  		t := n.Left.Type
   134  
   135  		if t != Types[t.Etype] && t != idealbool && t != idealstring {
   136  			if Isptr[t.Etype] {
   137  				t = t.Type
   138  			}
   139  			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
   140  				if Debug['E'] != 0 {
   141  					fmt.Printf("reexport type %v from declaration\n", t.Sym)
   142  				}
   143  				exportlist = list(exportlist, t.Sym.Def)
   144  			}
   145  		}
   146  
   147  	case OLITERAL:
   148  		t := n.Type
   149  		if t != Types[n.Type.Etype] && t != idealbool && t != idealstring {
   150  			if Isptr[t.Etype] {
   151  				t = t.Type
   152  			}
   153  			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
   154  				if Debug['E'] != 0 {
   155  					fmt.Printf("reexport literal type %v\n", t.Sym)
   156  				}
   157  				exportlist = list(exportlist, t.Sym.Def)
   158  			}
   159  		}
   160  		fallthrough
   161  
   162  	case OTYPE:
   163  		if n.Sym != nil && !exportedsym(n.Sym) {
   164  			if Debug['E'] != 0 {
   165  				fmt.Printf("reexport literal/type %v\n", n.Sym)
   166  			}
   167  			exportlist = list(exportlist, n)
   168  		}
   169  
   170  		// for operations that need a type when rendered, put the type on the export list.
   171  	case OCONV,
   172  		OCONVIFACE,
   173  		OCONVNOP,
   174  		ORUNESTR,
   175  		OARRAYBYTESTR,
   176  		OARRAYRUNESTR,
   177  		OSTRARRAYBYTE,
   178  		OSTRARRAYRUNE,
   179  		ODOTTYPE,
   180  		ODOTTYPE2,
   181  		OSTRUCTLIT,
   182  		OARRAYLIT,
   183  		OPTRLIT,
   184  		OMAKEMAP,
   185  		OMAKESLICE,
   186  		OMAKECHAN:
   187  		t := n.Type
   188  
   189  		if t.Sym == nil && t.Type != nil {
   190  			t = t.Type
   191  		}
   192  		if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
   193  			if Debug['E'] != 0 {
   194  				fmt.Printf("reexport type for expression %v\n", t.Sym)
   195  			}
   196  			exportlist = list(exportlist, t.Sym.Def)
   197  		}
   198  	}
   199  
   200  	reexportdep(n.Left)
   201  	reexportdep(n.Right)
   202  	reexportdeplist(n.List)
   203  	reexportdeplist(n.Rlist)
   204  	reexportdeplist(n.Ninit)
   205  	reexportdeplist(n.Nbody)
   206  }
   207  
   208  func dumpexportconst(s *Sym) {
   209  	n := s.Def
   210  	typecheck(&n, Erv)
   211  	if n == nil || n.Op != OLITERAL {
   212  		Fatal("dumpexportconst: oconst nil: %v", s)
   213  	}
   214  
   215  	t := n.Type // may or may not be specified
   216  	dumpexporttype(t)
   217  
   218  	if t != nil && !isideal(t) {
   219  		fmt.Fprintf(bout, "\tconst %v %v = %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp), Vconv(n.Val(), obj.FmtSharp))
   220  	} else {
   221  		fmt.Fprintf(bout, "\tconst %v = %v\n", Sconv(s, obj.FmtSharp), Vconv(n.Val(), obj.FmtSharp))
   222  	}
   223  }
   224  
   225  func dumpexportvar(s *Sym) {
   226  	n := s.Def
   227  	typecheck(&n, Erv|Ecall)
   228  	if n == nil || n.Type == nil {
   229  		Yyerror("variable exported but not defined: %v", s)
   230  		return
   231  	}
   232  
   233  	t := n.Type
   234  	dumpexporttype(t)
   235  
   236  	if t.Etype == TFUNC && n.Class == PFUNC {
   237  		if n.Func != nil && n.Func.Inl != nil {
   238  			// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
   239  			// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
   240  			if Debug['l'] < 2 {
   241  				typecheckinl(n)
   242  			}
   243  
   244  			// NOTE: The space after %#S here is necessary for ld's export data parser.
   245  			fmt.Fprintf(bout, "\tfunc %v %v { %v }\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp), Hconv(n.Func.Inl, obj.FmtSharp))
   246  
   247  			reexportdeplist(n.Func.Inl)
   248  		} else {
   249  			fmt.Fprintf(bout, "\tfunc %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp))
   250  		}
   251  	} else {
   252  		fmt.Fprintf(bout, "\tvar %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp))
   253  	}
   254  }
   255  
   256  type methodbyname []*Type
   257  
   258  func (x methodbyname) Len() int {
   259  	return len(x)
   260  }
   261  
   262  func (x methodbyname) Swap(i, j int) {
   263  	x[i], x[j] = x[j], x[i]
   264  }
   265  
   266  func (x methodbyname) Less(i, j int) bool {
   267  	a := x[i]
   268  	b := x[j]
   269  	return stringsCompare(a.Sym.Name, b.Sym.Name) < 0
   270  }
   271  
   272  func dumpexporttype(t *Type) {
   273  	if t == nil {
   274  		return
   275  	}
   276  	if t.Printed != 0 || t == Types[t.Etype] || t == bytetype || t == runetype || t == errortype {
   277  		return
   278  	}
   279  	t.Printed = 1
   280  
   281  	if t.Sym != nil && t.Etype != TFIELD {
   282  		dumppkg(t.Sym.Pkg)
   283  	}
   284  
   285  	dumpexporttype(t.Type)
   286  	dumpexporttype(t.Down)
   287  
   288  	if t.Sym == nil || t.Etype == TFIELD {
   289  		return
   290  	}
   291  
   292  	n := 0
   293  	for f := t.Method; f != nil; f = f.Down {
   294  		dumpexporttype(f)
   295  		n++
   296  	}
   297  
   298  	m := make([]*Type, n)
   299  	i := 0
   300  	for f := t.Method; f != nil; f = f.Down {
   301  		m[i] = f
   302  		i++
   303  	}
   304  	sort.Sort(methodbyname(m[:n]))
   305  
   306  	fmt.Fprintf(bout, "\ttype %v %v\n", Sconv(t.Sym, obj.FmtSharp), Tconv(t, obj.FmtSharp|obj.FmtLong))
   307  	var f *Type
   308  	for i := 0; i < n; i++ {
   309  		f = m[i]
   310  		if f.Nointerface {
   311  			fmt.Fprintf(bout, "\t//go:nointerface\n")
   312  		}
   313  		if f.Type.Nname != nil && f.Type.Nname.Func.Inl != nil { // nname was set by caninl
   314  
   315  			// when lazily typechecking inlined bodies, some re-exported ones may not have been typechecked yet.
   316  			// currently that can leave unresolved ONONAMEs in import-dot-ed packages in the wrong package
   317  			if Debug['l'] < 2 {
   318  				typecheckinl(f.Type.Nname)
   319  			}
   320  			fmt.Fprintf(bout, "\tfunc (%v) %v %v { %v }\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp), Hconv(f.Type.Nname.Func.Inl, obj.FmtSharp))
   321  			reexportdeplist(f.Type.Nname.Func.Inl)
   322  		} else {
   323  			fmt.Fprintf(bout, "\tfunc (%v) %v %v\n", Tconv(getthisx(f.Type).Type, obj.FmtSharp), Sconv(f.Sym, obj.FmtShort|obj.FmtByte|obj.FmtSharp), Tconv(f.Type, obj.FmtShort|obj.FmtSharp))
   324  		}
   325  	}
   326  }
   327  
   328  func dumpsym(s *Sym) {
   329  	if s.Flags&SymExported != 0 {
   330  		return
   331  	}
   332  	s.Flags |= SymExported
   333  
   334  	if s.Def == nil {
   335  		Yyerror("unknown export symbol: %v", s)
   336  		return
   337  	}
   338  
   339  	//	print("dumpsym %O %+S\n", s->def->op, s);
   340  	dumppkg(s.Pkg)
   341  
   342  	switch s.Def.Op {
   343  	default:
   344  		Yyerror("unexpected export symbol: %v %v", Oconv(int(s.Def.Op), 0), s)
   345  
   346  	case OLITERAL:
   347  		dumpexportconst(s)
   348  
   349  	case OTYPE:
   350  		if s.Def.Type.Etype == TFORW {
   351  			Yyerror("export of incomplete type %v", s)
   352  		} else {
   353  			dumpexporttype(s.Def.Type)
   354  		}
   355  
   356  	case ONAME:
   357  		dumpexportvar(s)
   358  	}
   359  }
   360  
   361  func dumpexport() {
   362  	lno := lineno
   363  
   364  	if buildid != "" {
   365  		fmt.Fprintf(bout, "build id %q\n", buildid)
   366  	}
   367  	fmt.Fprintf(bout, "\n$$\npackage %s", localpkg.Name)
   368  	if safemode != 0 {
   369  		fmt.Fprintf(bout, " safe")
   370  	}
   371  	fmt.Fprintf(bout, "\n")
   372  
   373  	for _, p := range pkgs {
   374  		if p.Direct != 0 {
   375  			dumppkg(p)
   376  		}
   377  	}
   378  
   379  	for l := exportlist; l != nil; l = l.Next {
   380  		lineno = l.N.Lineno
   381  		dumpsym(l.N.Sym)
   382  	}
   383  
   384  	fmt.Fprintf(bout, "\n$$\n")
   385  	lineno = lno
   386  }
   387  
   388  /*
   389   * import
   390   */
   391  
   392  /*
   393   * return the sym for ss, which should match lexical
   394   */
   395  func importsym(s *Sym, op int) *Sym {
   396  	if s.Def != nil && int(s.Def.Op) != op {
   397  		pkgstr := fmt.Sprintf("during import %q", importpkg.Path)
   398  		redeclare(s, pkgstr)
   399  	}
   400  
   401  	// mark the symbol so it is not reexported
   402  	if s.Def == nil {
   403  		if exportname(s.Name) || initname(s.Name) {
   404  			s.Flags |= SymExport
   405  		} else {
   406  			s.Flags |= SymPackage // package scope
   407  		}
   408  	}
   409  
   410  	return s
   411  }
   412  
   413  /*
   414   * return the type pkg.name, forward declaring if needed
   415   */
   416  func pkgtype(s *Sym) *Type {
   417  	importsym(s, OTYPE)
   418  	if s.Def == nil || s.Def.Op != OTYPE {
   419  		t := typ(TFORW)
   420  		t.Sym = s
   421  		s.Def = typenod(t)
   422  		s.Def.Name = new(Name)
   423  	}
   424  
   425  	if s.Def.Type == nil {
   426  		Yyerror("pkgtype %v", s)
   427  	}
   428  	return s.Def.Type
   429  }
   430  
   431  var numImport = make(map[string]int)
   432  
   433  func importimport(s *Sym, path string) {
   434  	// Informational: record package name
   435  	// associated with import path, for use in
   436  	// human-readable messages.
   437  
   438  	if isbadimport(path) {
   439  		errorexit()
   440  	}
   441  	p := mkpkg(path)
   442  	if p.Name == "" {
   443  		p.Name = s.Name
   444  		numImport[s.Name]++
   445  	} else if p.Name != s.Name {
   446  		Yyerror("conflicting names %s and %s for package %q", p.Name, s.Name, p.Path)
   447  	}
   448  
   449  	if incannedimport == 0 && myimportpath != "" && path == myimportpath {
   450  		Yyerror("import %q: package depends on %q (import cycle)", importpkg.Path, path)
   451  		errorexit()
   452  	}
   453  }
   454  
   455  func importconst(s *Sym, t *Type, n *Node) {
   456  	importsym(s, OLITERAL)
   457  	Convlit(&n, t)
   458  
   459  	if s.Def != nil { // TODO: check if already the same.
   460  		return
   461  	}
   462  
   463  	if n.Op != OLITERAL {
   464  		Yyerror("expression must be a constant")
   465  		return
   466  	}
   467  
   468  	if n.Sym != nil {
   469  		n1 := Nod(OXXX, nil, nil)
   470  		*n1 = *n
   471  		n = n1
   472  	}
   473  
   474  	n.Orig = newname(s)
   475  	n.Sym = s
   476  	declare(n, PEXTERN)
   477  
   478  	if Debug['E'] != 0 {
   479  		fmt.Printf("import const %v\n", s)
   480  	}
   481  }
   482  
   483  func importvar(s *Sym, t *Type) {
   484  	importsym(s, ONAME)
   485  	if s.Def != nil && s.Def.Op == ONAME {
   486  		if Eqtype(t, s.Def.Type) {
   487  			return
   488  		}
   489  		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)
   490  	}
   491  
   492  	n := newname(s)
   493  	s.Importdef = importpkg
   494  	n.Type = t
   495  	declare(n, PEXTERN)
   496  
   497  	if Debug['E'] != 0 {
   498  		fmt.Printf("import var %v %v\n", s, Tconv(t, obj.FmtLong))
   499  	}
   500  }
   501  
   502  func importtype(pt *Type, t *Type) {
   503  	// override declaration in unsafe.go for Pointer.
   504  	// there is no way in Go code to define unsafe.Pointer
   505  	// so we have to supply it.
   506  	if incannedimport != 0 && importpkg.Name == "unsafe" && pt.Nod.Sym.Name == "Pointer" {
   507  		t = Types[TUNSAFEPTR]
   508  	}
   509  
   510  	if pt.Etype == TFORW {
   511  		n := pt.Nod
   512  		copytype(pt.Nod, t)
   513  		pt.Nod = n // unzero nod
   514  		pt.Sym.Importdef = importpkg
   515  		pt.Sym.Lastlineno = int32(parserline())
   516  		declare(n, PEXTERN)
   517  		checkwidth(pt)
   518  	} else if !Eqtype(pt.Orig, t) {
   519  		Yyerror("inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)", pt.Sym, Tconv(pt, obj.FmtLong), pt.Sym.Importdef.Path, Tconv(t, obj.FmtLong), importpkg.Path)
   520  	}
   521  
   522  	if Debug['E'] != 0 {
   523  		fmt.Printf("import type %v %v\n", pt, Tconv(t, obj.FmtLong))
   524  	}
   525  }
   526  
   527  func dumpasmhdr() {
   528  	var b *obj.Biobuf
   529  
   530  	b, err := obj.Bopenw(asmhdr)
   531  	if err != nil {
   532  		Fatal("%v", err)
   533  	}
   534  	fmt.Fprintf(b, "// generated by %cg -asmhdr from package %s\n\n", Thearch.Thechar, localpkg.Name)
   535  	var n *Node
   536  	var t *Type
   537  	for l := asmlist; l != nil; l = l.Next {
   538  		n = l.N
   539  		if isblanksym(n.Sym) {
   540  			continue
   541  		}
   542  		switch n.Op {
   543  		case OLITERAL:
   544  			fmt.Fprintf(b, "#define const_%s %v\n", n.Sym.Name, Vconv(n.Val(), obj.FmtSharp))
   545  
   546  		case OTYPE:
   547  			t = n.Type
   548  			if t.Etype != TSTRUCT || t.Map != nil || t.Funarg != 0 {
   549  				break
   550  			}
   551  			fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width))
   552  			for t = t.Type; t != nil; t = t.Down {
   553  				if !isblanksym(t.Sym) {
   554  					fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Width))
   555  				}
   556  			}
   557  		}
   558  	}
   559  
   560  	obj.Bterm(b)
   561  }