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 	"bufio"
      9 	"bytes"
     10 	"cmd/compile/internal/types"
     11 	"cmd/internal/bio"
     12 	"cmd/internal/src"
     13 	"fmt"
     14 	"unicode"
     15 	"unicode/utf8"
     16 )
     17 
     18 var (
     19 	Debug_export int // if set, print debugging information about export data
     20 )
     21 
     22 func exportf(bout *bio.Writer, format string, args ...interface{}) {
     23 	fmt.Fprintf(bout, format, args...)
     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.Export() || n.Sym.Package() {
     37 		if n.Sym.Package() {
     38 			Fatalf("export/package mismatch: %v", n.Sym)
     39 		}
     40 		return
     41 	}
     42 
     43 	n.Sym.SetExport(true)
     44 	if Debug['E'] != 0 {
     45 		fmt.Printf("export symbol %v\n", n.Sym)
     46 	}
     47 
     48 	// Ensure original types are on exportlist before type aliases.
     49 	if IsAlias(n.Sym) {
     50 		exportlist = append(exportlist, asNode(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 *types.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.Type != nil && n.Type.IsKind(TFUNC) && n.IsMethod() {
     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.Asm() {
     94 		n.Sym.SetAsm(true)
     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 		case PFUNC:
    116 			// methods will be printed along with their type
    117 			// nodes for T.Method expressions
    118 			if n.isMethodExpression() {
    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.Types[t.Etype] && t != types.Idealbool && t != types.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, asNode(t.Sym.Def))
    150 			}
    151 		}
    152 
    153 	case OLITERAL:
    154 		t := n.Type
    155 		if t != types.Types[n.Type.Etype] && t != types.Idealbool && t != types.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, asNode(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, asNode(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 []*types.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(bout *bio.Writer) {
    226 	if buildid != "" {
    227 		exportf(bout, "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(bout, "\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 		types.CleanroomDo(func() {
    251 			Import(types.NewPkg("", ""), bufio.NewReader(&copy)) // must not die
    252 		})
    253 	} else {
    254 		size = export(bout.Writer, Debug_export != 0)
    255 	}
    256 	exportf(bout, "\n$$\n")
    257 
    258 	if Debug_export != 0 {
    259 		fmt.Printf("export data size = %d bytes\n", size)
    260 	}
    261 }
    262 
    263 // importsym declares symbol s as an imported object representable by op.
    264 // pkg is the package being imported
    265 func importsym(pkg *types.Pkg, s *types.Sym, op Op) {
    266 	if asNode(s.Def) != nil && asNode(s.Def).Op != op {
    267 		pkgstr := fmt.Sprintf("during import %q", pkg.Path)
    268 		redeclare(s, pkgstr)
    269 	}
    270 
    271 	// mark the symbol so it is not reexported
    272 	if asNode(s.Def) == nil {
    273 		if exportname(s.Name) || initname(s.Name) {
    274 			s.SetExport(true)
    275 		} else {
    276 			s.SetPackage(true) // 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 // pkg is the package being imported
    284 func pkgtype(pos src.XPos, pkg *types.Pkg, s *types.Sym) *types.Type {
    285 	importsym(pkg, s, OTYPE)
    286 	if asNode(s.Def) == nil || asNode(s.Def).Op != OTYPE {
    287 		t := types.New(TFORW)
    288 		t.Sym = s
    289 		s.Def = asTypesNode(typenodl(pos, t))
    290 		asNode(s.Def).Name = new(Name)
    291 	}
    292 
    293 	if asNode(s.Def).Type == nil {
    294 		Fatalf("pkgtype %v", s)
    295 	}
    296 	return asNode(s.Def).Type
    297 }
    298 
    299 // importconst declares symbol s as an imported constant with type t and value n.
    300 // pkg is the package being imported
    301 func importconst(pkg *types.Pkg, s *types.Sym, t *types.Type, n *Node) {
    302 	importsym(pkg, s, OLITERAL)
    303 	n = convlit(n, t)
    304 
    305 	if asNode(s.Def) != nil { // TODO: check if already the same.
    306 		return
    307 	}
    308 
    309 	if n.Op != OLITERAL {
    310 		yyerror("expression must be a constant")
    311 		return
    312 	}
    313 
    314 	if n.Sym != nil {
    315 		n1 := *n
    316 		n = &n1
    317 	}
    318 
    319 	n.Orig = newname(s)
    320 	n.Sym = s
    321 	declare(n, PEXTERN)
    322 
    323 	if Debug['E'] != 0 {
    324 		fmt.Printf("import const %v\n", s)
    325 	}
    326 }
    327 
    328 // importvar declares symbol s as an imported variable with type t.
    329 // pkg is the package being imported
    330 func importvar(pos src.XPos, pkg *types.Pkg, s *types.Sym, t *types.Type) {
    331 	importsym(pkg, s, ONAME)
    332 	if asNode(s.Def) != nil && asNode(s.Def).Op == ONAME {
    333 		if eqtype(t, asNode(s.Def).Type) {
    334 			return
    335 		}
    336 		yyerror("inconsistent definition for var %v during import\n\t%v (in %q)\n\t%v (in %q)", s, asNode(s.Def).Type, s.Importdef.Path, t, pkg.Path)
    337 	}
    338 
    339 	n := newnamel(pos, s)
    340 	s.Importdef = pkg
    341 	n.Type = t
    342 	declare(n, PEXTERN)
    343 
    344 	if Debug['E'] != 0 {
    345 		fmt.Printf("import var %v %L\n", s, t)
    346 	}
    347 }
    348 
    349 // importalias declares symbol s as an imported type alias with type t.
    350 // pkg is the package being imported
    351 func importalias(pos src.XPos, pkg *types.Pkg, s *types.Sym, t *types.Type) {
    352 	importsym(pkg, s, OTYPE)
    353 	if asNode(s.Def) != nil && asNode(s.Def).Op == OTYPE {
    354 		if eqtype(t, asNode(s.Def).Type) {
    355 			return
    356 		}
    357 		yyerror("inconsistent definition for type alias %v during import\n\t%v (in %q)\n\t%v (in %q)", s, asNode(s.Def).Type, s.Importdef.Path, t, pkg.Path)
    358 	}
    359 
    360 	n := newnamel(pos, s)
    361 	n.Op = OTYPE
    362 	s.Importdef = pkg
    363 	n.Type = t
    364 	declare(n, PEXTERN)
    365 
    366 	if Debug['E'] != 0 {
    367 		fmt.Printf("import type %v = %L\n", s, t)
    368 	}
    369 }
    370 
    371 func dumpasmhdr() {
    372 	b, err := bio.Create(asmhdr)
    373 	if err != nil {
    374 		Fatalf("%v", err)
    375 	}
    376 	fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", localpkg.Name)
    377 	for _, n := range asmlist {
    378 		if n.Sym.IsBlank() {
    379 			continue
    380 		}
    381 		switch n.Op {
    382 		case OLITERAL:
    383 			fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym.Name, n.Val())
    384 
    385 		case OTYPE:
    386 			t := n.Type
    387 			if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() {
    388 				break
    389 			}
    390 			fmt.Fprintf(b, "#define %s__size %d\n", n.Sym.Name, int(t.Width))
    391 			for _, f := range t.Fields().Slice() {
    392 				if !f.Sym.IsBlank() {
    393 					fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, f.Sym.Name, int(f.Offset))
    394 				}
    395 			}
    396 		}
    397 	}
    398 
    399 	b.Close()
    400 }
    401