github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/cmd/compile/internal/gc/bimport.go (about)

     1  // Copyright 2015 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  // Binary package import.
     6  // Based loosely on x/tools/go/importer.
     7  
     8  package gc
     9  
    10  import (
    11  	"cmd/compile/internal/big"
    12  	"cmd/internal/obj"
    13  	"encoding/binary"
    14  )
    15  
    16  // The overall structure of Import is symmetric to Export: For each
    17  // export method in bexport.go there is a matching and symmetric method
    18  // in bimport.go. Changing the export format requires making symmetric
    19  // changes to bimport.go and bexport.go.
    20  
    21  // Import populates importpkg from the serialized package data.
    22  func Import(in *obj.Biobuf) {
    23  	p := importer{in: in}
    24  	p.buf = p.bufarray[:]
    25  
    26  	// read low-level encoding format
    27  	switch format := p.byte(); format {
    28  	case 'c':
    29  		// compact format - nothing to do
    30  	case 'd':
    31  		p.debugFormat = true
    32  	default:
    33  		Fatalf("invalid encoding format in export data: got %q; want 'c' or 'd'", format)
    34  	}
    35  
    36  	// --- generic export data ---
    37  
    38  	if v := p.string(); v != exportVersion {
    39  		Fatalf("unknown export data version: %s", v)
    40  	}
    41  
    42  	// populate typList with predeclared "known" types
    43  	p.typList = append(p.typList, predeclared()...)
    44  
    45  	// read package data
    46  	p.pkg()
    47  	if p.pkgList[0] != importpkg {
    48  		Fatalf("imported package not found in pkgList[0]")
    49  	}
    50  
    51  	// read compiler-specific flags
    52  	importpkg.Safe = p.string() == "safe"
    53  
    54  	// defer some type-checking until all types are read in completely
    55  	// (go.y:import_there)
    56  	tcok := typecheckok
    57  	typecheckok = true
    58  	defercheckwidth()
    59  
    60  	// read consts
    61  	for i := p.int(); i > 0; i-- {
    62  		sym := p.localname()
    63  		typ := p.typ()
    64  		val := p.value(typ)
    65  		if isideal(typ) {
    66  			// canonicalize ideal types
    67  			typ = Types[TIDEAL]
    68  		}
    69  		importconst(sym, typ, nodlit(val))
    70  	}
    71  
    72  	// read vars
    73  	for i := p.int(); i > 0; i-- {
    74  		sym := p.localname()
    75  		typ := p.typ()
    76  		importvar(sym, typ)
    77  	}
    78  
    79  	// read funcs
    80  	for i := p.int(); i > 0; i-- {
    81  		// go.y:hidden_fndcl
    82  		sym := p.localname()
    83  		typ := p.typ()
    84  		// TODO(gri) fix this
    85  		p.int() // read and discard index of inlined function body for now
    86  
    87  		importsym(sym, ONAME)
    88  		if sym.Def != nil && sym.Def.Op == ONAME && !Eqtype(typ, sym.Def.Type) {
    89  			Fatalf("inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, typ)
    90  		}
    91  
    92  		n := newfuncname(sym)
    93  		n.Type = typ
    94  		declare(n, PFUNC)
    95  		funchdr(n)
    96  
    97  		// go.y:hidden_import
    98  		n.Func.Inl = nil
    99  		funcbody(n)
   100  		importlist = append(importlist, n) // TODO(gri) do this only if body is inlineable?
   101  	}
   102  
   103  	// read types
   104  	for i := p.int(); i > 0; i-- {
   105  		// name is parsed as part of named type
   106  		p.typ()
   107  	}
   108  
   109  	// --- compiler-specific export data ---
   110  
   111  	for i := p.int(); i > 0; i-- {
   112  		p.body()
   113  	}
   114  
   115  	// --- end of export data ---
   116  
   117  	typecheckok = tcok
   118  	resumecheckwidth()
   119  
   120  	testdclstack() // debugging only
   121  }
   122  
   123  type importer struct {
   124  	in       *obj.Biobuf
   125  	buf      []byte   // for reading strings
   126  	bufarray [64]byte // initial underlying array for buf, large enough to avoid allocation when compiling std lib
   127  	pkgList  []*Pkg
   128  	typList  []*Type
   129  
   130  	debugFormat bool
   131  	read        int // bytes read
   132  }
   133  
   134  func (p *importer) pkg() *Pkg {
   135  	// if the package was seen before, i is its index (>= 0)
   136  	i := p.tagOrIndex()
   137  	if i >= 0 {
   138  		return p.pkgList[i]
   139  	}
   140  
   141  	// otherwise, i is the package tag (< 0)
   142  	if i != packageTag {
   143  		Fatalf("expected package tag, found tag = %d", i)
   144  	}
   145  
   146  	// read package data
   147  	name := p.string()
   148  	path := p.string()
   149  
   150  	// we should never see an empty package name
   151  	if name == "" {
   152  		Fatalf("empty package name in import")
   153  	}
   154  
   155  	// we should never see a bad import path
   156  	if isbadimport(path) {
   157  		Fatalf("bad path in import: %q", path)
   158  	}
   159  
   160  	// an empty path denotes the package we are currently importing
   161  	pkg := importpkg
   162  	if path != "" {
   163  		pkg = mkpkg(path)
   164  	}
   165  	if pkg.Name == "" {
   166  		pkg.Name = name
   167  	} else if pkg.Name != name {
   168  		Fatalf("inconsistent package names: got %s; want %s (path = %s)", pkg.Name, name, path)
   169  	}
   170  	p.pkgList = append(p.pkgList, pkg)
   171  
   172  	return pkg
   173  }
   174  
   175  func (p *importer) localname() *Sym {
   176  	// go.y:hidden_importsym
   177  	name := p.string()
   178  	if name == "" {
   179  		Fatalf("unexpected anonymous name")
   180  	}
   181  	structpkg = importpkg // go.y:hidden_pkg_importsym
   182  	return importpkg.Lookup(name)
   183  }
   184  
   185  func (p *importer) newtyp(etype EType) *Type {
   186  	t := typ(etype)
   187  	p.typList = append(p.typList, t)
   188  	return t
   189  }
   190  
   191  func (p *importer) typ() *Type {
   192  	// if the type was seen before, i is its index (>= 0)
   193  	i := p.tagOrIndex()
   194  	if i >= 0 {
   195  		return p.typList[i]
   196  	}
   197  
   198  	// otherwise, i is the type tag (< 0)
   199  	var t *Type
   200  	switch i {
   201  	case namedTag:
   202  		// go.y:hidden_importsym
   203  		tsym := p.qualifiedName()
   204  
   205  		// go.y:hidden_pkgtype
   206  		t = pkgtype(tsym)
   207  		importsym(tsym, OTYPE)
   208  		p.typList = append(p.typList, t)
   209  
   210  		// read underlying type
   211  		// go.y:hidden_type
   212  		t0 := p.typ()
   213  		importtype(t, t0) // go.y:hidden_import
   214  
   215  		// interfaces don't have associated methods
   216  		if t0.Etype == TINTER {
   217  			break
   218  		}
   219  
   220  		// read associated methods
   221  		for i := p.int(); i > 0; i-- {
   222  			// go.y:hidden_fndcl
   223  			name := p.string()
   224  			recv := p.paramList() // TODO(gri) do we need a full param list for the receiver?
   225  			params := p.paramList()
   226  			result := p.paramList()
   227  			// TODO(gri) fix this
   228  			p.int() // read and discard index of inlined function body for now
   229  
   230  			pkg := localpkg
   231  			if !exportname(name) {
   232  				pkg = tsym.Pkg
   233  			}
   234  			sym := pkg.Lookup(name)
   235  
   236  			n := methodname1(newname(sym), recv.N.Right)
   237  			n.Type = functype(recv.N, params, result)
   238  			checkwidth(n.Type)
   239  			// addmethod uses the global variable structpkg to verify consistency
   240  			{
   241  				saved := structpkg
   242  				structpkg = tsym.Pkg
   243  				addmethod(sym, n.Type, false, nointerface)
   244  				structpkg = saved
   245  			}
   246  			nointerface = false
   247  			funchdr(n)
   248  
   249  			// (comment from go.y)
   250  			// inl.C's inlnode in on a dotmeth node expects to find the inlineable body as
   251  			// (dotmeth's type).Nname.Inl, and dotmeth's type has been pulled
   252  			// out by typecheck's lookdot as this $$.ttype.  So by providing
   253  			// this back link here we avoid special casing there.
   254  			n.Type.Nname = n
   255  
   256  			// go.y:hidden_import
   257  			n.Func.Inl = nil
   258  			funcbody(n)
   259  			importlist = append(importlist, n) // TODO(gri) do this only if body is inlineable?
   260  		}
   261  
   262  	case arrayTag, sliceTag:
   263  		t = p.newtyp(TARRAY)
   264  		t.Bound = -1
   265  		if i == arrayTag {
   266  			t.Bound = p.int64()
   267  		}
   268  		t.Type = p.typ()
   269  
   270  	case dddTag:
   271  		t = p.newtyp(T_old_DARRAY)
   272  		t.Bound = -1
   273  		t.Type = p.typ()
   274  
   275  	case structTag:
   276  		t = p.newtyp(TSTRUCT)
   277  		tostruct0(t, p.fieldList())
   278  
   279  	case pointerTag:
   280  		t = p.newtyp(Tptr)
   281  		t.Type = p.typ()
   282  
   283  	case signatureTag:
   284  		t = p.newtyp(TFUNC)
   285  		params := p.paramList()
   286  		result := p.paramList()
   287  		functype0(t, nil, params, result)
   288  
   289  	case interfaceTag:
   290  		t = p.newtyp(TINTER)
   291  		if p.int() != 0 {
   292  			Fatalf("unexpected embedded interface")
   293  		}
   294  		tointerface0(t, p.methodList())
   295  
   296  	case mapTag:
   297  		t = p.newtyp(TMAP)
   298  		t.Down = p.typ() // key
   299  		t.Type = p.typ() // val
   300  
   301  	case chanTag:
   302  		t = p.newtyp(TCHAN)
   303  		t.Chan = uint8(p.int())
   304  		t.Type = p.typ()
   305  
   306  	default:
   307  		Fatalf("unexpected type (tag = %d)", i)
   308  	}
   309  
   310  	if t == nil {
   311  		Fatalf("nil type (type tag = %d)", i)
   312  	}
   313  
   314  	return t
   315  }
   316  
   317  func (p *importer) qualifiedName() *Sym {
   318  	name := p.string()
   319  	pkg := p.pkg()
   320  	return pkg.Lookup(name)
   321  }
   322  
   323  // go.y:hidden_structdcl_list
   324  func (p *importer) fieldList() *NodeList {
   325  	i := p.int()
   326  	if i == 0 {
   327  		return nil
   328  	}
   329  	n := list1(p.field())
   330  	for i--; i > 0; i-- {
   331  		n = list(n, p.field())
   332  	}
   333  	return n
   334  }
   335  
   336  // go.y:hidden_structdcl
   337  func (p *importer) field() *Node {
   338  	sym := p.fieldName()
   339  	typ := p.typ()
   340  	note := p.note()
   341  
   342  	var n *Node
   343  	if sym.Name != "" {
   344  		n = Nod(ODCLFIELD, newname(sym), typenod(typ))
   345  	} else {
   346  		// anonymous field - typ must be T or *T and T must be a type name
   347  		s := typ.Sym
   348  		if s == nil && Isptr[typ.Etype] {
   349  			s = typ.Type.Sym // deref
   350  		}
   351  		pkg := importpkg
   352  		if sym != nil {
   353  			pkg = sym.Pkg
   354  		}
   355  		n = embedded(s, pkg)
   356  		n.Right = typenod(typ)
   357  	}
   358  	n.SetVal(note)
   359  
   360  	return n
   361  }
   362  
   363  func (p *importer) note() (v Val) {
   364  	if s := p.string(); s != "" {
   365  		v.U = s
   366  	}
   367  	return
   368  }
   369  
   370  // go.y:hidden_interfacedcl_list
   371  func (p *importer) methodList() *NodeList {
   372  	i := p.int()
   373  	if i == 0 {
   374  		return nil
   375  	}
   376  	n := list1(p.method())
   377  	for i--; i > 0; i-- {
   378  		n = list(n, p.method())
   379  	}
   380  	return n
   381  }
   382  
   383  // go.y:hidden_interfacedcl
   384  func (p *importer) method() *Node {
   385  	sym := p.fieldName()
   386  	params := p.paramList()
   387  	result := p.paramList()
   388  	return Nod(ODCLFIELD, newname(sym), typenod(functype(fakethis(), params, result)))
   389  }
   390  
   391  // go.y:sym,hidden_importsym
   392  func (p *importer) fieldName() *Sym {
   393  	name := p.string()
   394  	pkg := localpkg
   395  	if name == "_" {
   396  		// During imports, unqualified non-exported identifiers are from builtinpkg
   397  		// (see go.y:sym). The binary exporter only exports blank as a non-exported
   398  		// identifier without qualification.
   399  		pkg = builtinpkg
   400  	} else if name == "?" || name != "" && !exportname(name) {
   401  		if name == "?" {
   402  			name = ""
   403  		}
   404  		pkg = p.pkg()
   405  	}
   406  	return pkg.Lookup(name)
   407  }
   408  
   409  // go.y:ohidden_funarg_list
   410  func (p *importer) paramList() *NodeList {
   411  	i := p.int()
   412  	if i == 0 {
   413  		return nil
   414  	}
   415  	// negative length indicates unnamed parameters
   416  	named := true
   417  	if i < 0 {
   418  		i = -i
   419  		named = false
   420  	}
   421  	// i > 0
   422  	n := list1(p.param(named))
   423  	i--
   424  	for ; i > 0; i-- {
   425  		n = list(n, p.param(named))
   426  	}
   427  	return n
   428  }
   429  
   430  // go.y:hidden_funarg
   431  func (p *importer) param(named bool) *Node {
   432  	typ := p.typ()
   433  
   434  	isddd := false
   435  	if typ.Etype == T_old_DARRAY {
   436  		// T_old_DARRAY indicates ... type
   437  		typ.Etype = TARRAY
   438  		isddd = true
   439  	}
   440  
   441  	n := Nod(ODCLFIELD, nil, typenod(typ))
   442  	n.Isddd = isddd
   443  
   444  	if named {
   445  		name := p.string()
   446  		if name == "" {
   447  			Fatalf("expected named parameter")
   448  		}
   449  		// The parameter package doesn't matter; it's never consulted.
   450  		// We use the builtinpkg per go.y:sym (line 1181).
   451  		n.Left = newname(builtinpkg.Lookup(name))
   452  	}
   453  
   454  	// TODO(gri) This is compiler-specific (escape info).
   455  	// Move into compiler-specific section eventually?
   456  	n.SetVal(p.note())
   457  
   458  	return n
   459  }
   460  
   461  func (p *importer) value(typ *Type) (x Val) {
   462  	switch tag := p.tagOrIndex(); tag {
   463  	case falseTag:
   464  		x.U = false
   465  	case trueTag:
   466  		x.U = true
   467  	case int64Tag:
   468  		u := new(Mpint)
   469  		Mpmovecfix(u, p.int64())
   470  		u.Rune = typ == idealrune
   471  		x.U = u
   472  	case floatTag:
   473  		f := newMpflt()
   474  		p.float(f)
   475  		if typ == idealint || Isint[typ.Etype] {
   476  			// uncommon case: large int encoded as float
   477  			u := new(Mpint)
   478  			mpmovefltfix(u, f)
   479  			x.U = u
   480  			break
   481  		}
   482  		x.U = f
   483  	case complexTag:
   484  		u := new(Mpcplx)
   485  		p.float(&u.Real)
   486  		p.float(&u.Imag)
   487  		x.U = u
   488  	case stringTag:
   489  		x.U = p.string()
   490  	default:
   491  		Fatalf("unexpected value tag %d", tag)
   492  	}
   493  
   494  	// verify ideal type
   495  	if isideal(typ) && untype(x.Ctype()) != typ {
   496  		Fatalf("value %v and type %v don't match", x, typ)
   497  	}
   498  
   499  	return
   500  }
   501  
   502  func (p *importer) float(x *Mpflt) {
   503  	sign := p.int()
   504  	if sign == 0 {
   505  		Mpmovecflt(x, 0)
   506  		return
   507  	}
   508  
   509  	exp := p.int()
   510  	mant := new(big.Int).SetBytes([]byte(p.string()))
   511  
   512  	m := x.Val.SetInt(mant)
   513  	m.SetMantExp(m, exp-mant.BitLen())
   514  	if sign < 0 {
   515  		m.Neg(m)
   516  	}
   517  }
   518  
   519  // ----------------------------------------------------------------------------
   520  // Inlined function bodies
   521  
   522  func (p *importer) body() {
   523  	p.int()
   524  	p.block()
   525  }
   526  
   527  func (p *importer) block() {
   528  	for i := p.int(); i > 0; i-- {
   529  		p.stmt()
   530  	}
   531  }
   532  
   533  func (p *importer) stmt() {
   534  	// TODO(gri) do something sensible here
   535  	p.string()
   536  }
   537  
   538  // ----------------------------------------------------------------------------
   539  // Low-level decoders
   540  
   541  func (p *importer) tagOrIndex() int {
   542  	if p.debugFormat {
   543  		p.marker('t')
   544  	}
   545  
   546  	return int(p.rawInt64())
   547  }
   548  
   549  func (p *importer) int() int {
   550  	x := p.int64()
   551  	if int64(int(x)) != x {
   552  		Fatalf("exported integer too large")
   553  	}
   554  	return int(x)
   555  }
   556  
   557  func (p *importer) int64() int64 {
   558  	if p.debugFormat {
   559  		p.marker('i')
   560  	}
   561  
   562  	return p.rawInt64()
   563  }
   564  
   565  func (p *importer) string() string {
   566  	if p.debugFormat {
   567  		p.marker('s')
   568  	}
   569  
   570  	if n := int(p.rawInt64()); n > 0 {
   571  		if cap(p.buf) < n {
   572  			p.buf = make([]byte, n)
   573  		} else {
   574  			p.buf = p.buf[:n]
   575  		}
   576  		for i := 0; i < n; i++ {
   577  			p.buf[i] = p.byte()
   578  		}
   579  		return string(p.buf)
   580  	}
   581  
   582  	return ""
   583  }
   584  
   585  func (p *importer) marker(want byte) {
   586  	if got := p.byte(); got != want {
   587  		Fatalf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
   588  	}
   589  
   590  	pos := p.read
   591  	if n := int(p.rawInt64()); n != pos {
   592  		Fatalf("incorrect position: got %d; want %d", n, pos)
   593  	}
   594  }
   595  
   596  // rawInt64 should only be used by low-level decoders
   597  func (p *importer) rawInt64() int64 {
   598  	i, err := binary.ReadVarint(p)
   599  	if err != nil {
   600  		Fatalf("read error: %v", err)
   601  	}
   602  	return i
   603  }
   604  
   605  // needed for binary.ReadVarint in rawInt64
   606  func (p *importer) ReadByte() (byte, error) {
   607  	return p.byte(), nil
   608  }
   609  
   610  // byte is the bottleneck interface for reading from p.in.
   611  // It unescapes '|' 'S' to '$' and '|' '|' to '|'.
   612  func (p *importer) byte() byte {
   613  	c := obj.Bgetc(p.in)
   614  	p.read++
   615  	if c < 0 {
   616  		Fatalf("read error")
   617  	}
   618  	if c == '|' {
   619  		c = obj.Bgetc(p.in)
   620  		p.read++
   621  		if c < 0 {
   622  			Fatalf("read error")
   623  		}
   624  		switch c {
   625  		case 'S':
   626  			c = '$'
   627  		case '|':
   628  			// nothing to do
   629  		default:
   630  			Fatalf("unexpected escape sequence in export data")
   631  		}
   632  	}
   633  	return byte(c)
   634  }