Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/compile/internal/gc/export.go

Documentation: cmd/compile/internal/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/compile/internal/base"
     9  	"cmd/compile/internal/inline"
    10  	"cmd/compile/internal/ir"
    11  	"cmd/compile/internal/typecheck"
    12  	"cmd/compile/internal/types"
    13  	"cmd/internal/bio"
    14  	"fmt"
    15  	"go/constant"
    16  )
    17  
    18  func exportf(bout *bio.Writer, format string, args ...interface{}) {
    19  	fmt.Fprintf(bout, format, args...)
    20  	if base.Debug.Export != 0 {
    21  		fmt.Printf(format, args...)
    22  	}
    23  }
    24  
    25  func dumpexport(bout *bio.Writer) {
    26  	p := &exporter{marked: make(map[*types.Type]bool)}
    27  	for _, n := range typecheck.Target.Exports {
    28  		// Must catch it here rather than Export(), because the type can be
    29  		// not fully set (still TFORW) when Export() is called.
    30  		if n.Type() != nil && n.Type().HasTParam() {
    31  			base.Fatalf("Cannot (yet) export a generic type: %v", n)
    32  		}
    33  		p.markObject(n)
    34  	}
    35  
    36  	// The linker also looks for the $$ marker - use char after $$ to distinguish format.
    37  	exportf(bout, "\n$$B\n") // indicate binary export format
    38  	off := bout.Offset()
    39  	typecheck.WriteExports(bout.Writer)
    40  	size := bout.Offset() - off
    41  	exportf(bout, "\n$$\n")
    42  
    43  	if base.Debug.Export != 0 {
    44  		fmt.Printf("BenchmarkExportSize:%s 1 %d bytes\n", base.Ctxt.Pkgpath, size)
    45  	}
    46  }
    47  
    48  func dumpasmhdr() {
    49  	b, err := bio.Create(base.Flag.AsmHdr)
    50  	if err != nil {
    51  		base.Fatalf("%v", err)
    52  	}
    53  	fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", types.LocalPkg.Name)
    54  	for _, n := range typecheck.Target.Asms {
    55  		if n.Sym().IsBlank() {
    56  			continue
    57  		}
    58  		switch n.Op() {
    59  		case ir.OLITERAL:
    60  			t := n.Val().Kind()
    61  			if t == constant.Float || t == constant.Complex {
    62  				break
    63  			}
    64  			fmt.Fprintf(b, "#define const_%s %#v\n", n.Sym().Name, n.Val())
    65  
    66  		case ir.OTYPE:
    67  			t := n.Type()
    68  			if !t.IsStruct() || t.StructType().Map != nil || t.IsFuncArgStruct() {
    69  				break
    70  			}
    71  			fmt.Fprintf(b, "#define %s__size %d\n", n.Sym().Name, int(t.Width))
    72  			for _, f := range t.Fields().Slice() {
    73  				if !f.Sym.IsBlank() {
    74  					fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym().Name, f.Sym.Name, int(f.Offset))
    75  				}
    76  			}
    77  		}
    78  	}
    79  
    80  	b.Close()
    81  }
    82  
    83  type exporter struct {
    84  	marked map[*types.Type]bool // types already seen by markType
    85  }
    86  
    87  // markObject visits a reachable object.
    88  func (p *exporter) markObject(n ir.Node) {
    89  	if n.Op() == ir.ONAME {
    90  		n := n.(*ir.Name)
    91  		if n.Class == ir.PFUNC {
    92  			inline.Inline_Flood(n, typecheck.Export)
    93  		}
    94  	}
    95  
    96  	p.markType(n.Type())
    97  }
    98  
    99  // markType recursively visits types reachable from t to identify
   100  // functions whose inline bodies may be needed.
   101  func (p *exporter) markType(t *types.Type) {
   102  	if p.marked[t] {
   103  		return
   104  	}
   105  	p.marked[t] = true
   106  
   107  	// If this is a named type, mark all of its associated
   108  	// methods. Skip interface types because t.Methods contains
   109  	// only their unexpanded method set (i.e., exclusive of
   110  	// interface embeddings), and the switch statement below
   111  	// handles their full method set.
   112  	if t.Sym() != nil && t.Kind() != types.TINTER {
   113  		for _, m := range t.Methods().Slice() {
   114  			if types.IsExported(m.Sym.Name) {
   115  				p.markObject(ir.AsNode(m.Nname))
   116  			}
   117  		}
   118  	}
   119  
   120  	// Recursively mark any types that can be produced given a
   121  	// value of type t: dereferencing a pointer; indexing or
   122  	// iterating over an array, slice, or map; receiving from a
   123  	// channel; accessing a struct field or interface method; or
   124  	// calling a function.
   125  	//
   126  	// Notably, we don't mark function parameter types, because
   127  	// the user already needs some way to construct values of
   128  	// those types.
   129  	switch t.Kind() {
   130  	case types.TPTR, types.TARRAY, types.TSLICE:
   131  		p.markType(t.Elem())
   132  
   133  	case types.TCHAN:
   134  		if t.ChanDir().CanRecv() {
   135  			p.markType(t.Elem())
   136  		}
   137  
   138  	case types.TMAP:
   139  		p.markType(t.Key())
   140  		p.markType(t.Elem())
   141  
   142  	case types.TSTRUCT:
   143  		for _, f := range t.FieldSlice() {
   144  			if types.IsExported(f.Sym.Name) || f.Embedded != 0 {
   145  				p.markType(f.Type)
   146  			}
   147  		}
   148  
   149  	case types.TFUNC:
   150  		for _, f := range t.Results().FieldSlice() {
   151  			p.markType(f.Type)
   152  		}
   153  
   154  	case types.TINTER:
   155  		for _, f := range t.AllMethods().Slice() {
   156  			if types.IsExported(f.Sym.Name) {
   157  				p.markType(f.Type)
   158  			}
   159  		}
   160  	}
   161  }
   162  

View as plain text