Home | History | Annotate | Download | only in gc
      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 }
    562