github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/go/internal/gcimporter/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  package gcimporter
     6  
     7  import (
     8  	"encoding/binary"
     9  	"fmt"
    10  	"go/constant"
    11  	"go/token"
    12  	"go/types"
    13  	"sort"
    14  	"unicode"
    15  	"unicode/utf8"
    16  )
    17  
    18  type importer struct {
    19  	imports  map[string]*types.Package
    20  	data     []byte
    21  	buf      []byte   // for reading strings
    22  	bufarray [64]byte // initial underlying array for buf, large enough to avoid allocation when compiling std lib
    23  	pkgList  []*types.Package
    24  	typList  []types.Type
    25  
    26  	debugFormat bool
    27  	read        int // bytes read
    28  }
    29  
    30  // BImportData imports a package from the serialized package data
    31  // and returns the number of bytes consumed and a reference to the package.
    32  // If data is obviously malformed, an error is returned but in
    33  // general it is not recommended to call BImportData on untrusted data.
    34  func BImportData(imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) {
    35  	p := importer{
    36  		imports: imports,
    37  		data:    data,
    38  	}
    39  	p.buf = p.bufarray[:]
    40  
    41  	// read low-level encoding format
    42  	switch format := p.byte(); format {
    43  	case 'c':
    44  		// compact format - nothing to do
    45  	case 'd':
    46  		p.debugFormat = true
    47  	default:
    48  		return p.read, nil, fmt.Errorf("invalid encoding format in export data: got %q; want 'c' or 'd'", format)
    49  	}
    50  
    51  	// --- generic export data ---
    52  
    53  	if v := p.string(); v != "v0" {
    54  		return p.read, nil, fmt.Errorf("unknown export data version: %s", v)
    55  	}
    56  
    57  	// populate typList with predeclared "known" types
    58  	p.typList = append(p.typList, predeclared...)
    59  
    60  	// read package data
    61  	// TODO(gri) clean this up
    62  	i := p.tagOrIndex()
    63  	if i != packageTag {
    64  		panic(fmt.Sprintf("package tag expected, got %d", i))
    65  	}
    66  	name := p.string()
    67  	if s := p.string(); s != "" {
    68  		panic(fmt.Sprintf("empty path expected, got %s", s))
    69  	}
    70  	pkg := p.imports[path]
    71  	if pkg == nil {
    72  		pkg = types.NewPackage(path, name)
    73  		p.imports[path] = pkg
    74  	}
    75  	p.pkgList = append(p.pkgList, pkg)
    76  
    77  	if debug && p.pkgList[0] != pkg {
    78  		panic("imported packaged not found in pkgList[0]")
    79  	}
    80  
    81  	// read compiler-specific flags
    82  	p.string() // discard
    83  
    84  	// read objects of phase 1 only (see cmd/compiler/internal/gc/bexport.go)
    85  	objcount := 0
    86  	for {
    87  		tag := p.tagOrIndex()
    88  		if tag == endTag {
    89  			break
    90  		}
    91  		p.obj(tag)
    92  		objcount++
    93  	}
    94  
    95  	// self-verification
    96  	if count := p.int(); count != objcount {
    97  		panic(fmt.Sprintf("importer: got %d objects; want %d", objcount, count))
    98  	}
    99  
   100  	// ignore compiler-specific import data
   101  
   102  	// complete interfaces
   103  	for _, typ := range p.typList {
   104  		if it, ok := typ.(*types.Interface); ok {
   105  			it.Complete()
   106  		}
   107  	}
   108  
   109  	// record all referenced packages as imports
   110  	list := append(([]*types.Package)(nil), p.pkgList[1:]...)
   111  	sort.Sort(byPath(list))
   112  	pkg.SetImports(list)
   113  
   114  	// package was imported completely and without errors
   115  	pkg.MarkComplete()
   116  
   117  	return p.read, pkg, nil
   118  }
   119  
   120  func (p *importer) pkg() *types.Package {
   121  	// if the package was seen before, i is its index (>= 0)
   122  	i := p.tagOrIndex()
   123  	if i >= 0 {
   124  		return p.pkgList[i]
   125  	}
   126  
   127  	// otherwise, i is the package tag (< 0)
   128  	if i != packageTag {
   129  		panic(fmt.Sprintf("unexpected package tag %d", i))
   130  	}
   131  
   132  	// read package data
   133  	name := p.string()
   134  	path := p.string()
   135  
   136  	// we should never see an empty package name
   137  	if name == "" {
   138  		panic("empty package name in import")
   139  	}
   140  
   141  	// we should never see an empty import path
   142  	if path == "" {
   143  		panic("empty import path")
   144  	}
   145  
   146  	// if the package was imported before, use that one; otherwise create a new one
   147  	pkg := p.imports[path]
   148  	if pkg == nil {
   149  		pkg = types.NewPackage(path, name)
   150  		p.imports[path] = pkg
   151  	}
   152  	p.pkgList = append(p.pkgList, pkg)
   153  
   154  	return pkg
   155  }
   156  
   157  func (p *importer) declare(obj types.Object) {
   158  	pkg := obj.Pkg()
   159  	if alt := pkg.Scope().Insert(obj); alt != nil {
   160  		// This could only trigger if we import a (non-type) object a second time.
   161  		// This should never happen because 1) we only import a package once; and
   162  		// b) we ignore compiler-specific export data which may contain functions
   163  		// whose inlined function bodies refer to other functions that were already
   164  		// imported.
   165  		// (See also the comment in cmd/compile/internal/gc/bimport.go importer.obj,
   166  		// switch case importing functions).
   167  		panic(fmt.Sprintf("%s already declared", alt.Name()))
   168  	}
   169  }
   170  
   171  func (p *importer) obj(tag int) {
   172  	switch tag {
   173  	case constTag:
   174  		pkg, name := p.qualifiedName()
   175  		typ := p.typ(nil)
   176  		val := p.value()
   177  		p.declare(types.NewConst(token.NoPos, pkg, name, typ, val))
   178  
   179  	case typeTag:
   180  		_ = p.typ(nil)
   181  
   182  	case varTag:
   183  		pkg, name := p.qualifiedName()
   184  		typ := p.typ(nil)
   185  		p.declare(types.NewVar(token.NoPos, pkg, name, typ))
   186  
   187  	case funcTag:
   188  		pkg, name := p.qualifiedName()
   189  		params, isddd := p.paramList()
   190  		result, _ := p.paramList()
   191  		sig := types.NewSignature(nil, params, result, isddd)
   192  		p.int() // read and discard index of inlined function body
   193  		p.declare(types.NewFunc(token.NoPos, pkg, name, sig))
   194  
   195  	default:
   196  		panic("unexpected object tag")
   197  	}
   198  }
   199  
   200  func (p *importer) qualifiedName() (pkg *types.Package, name string) {
   201  	name = p.string()
   202  	pkg = p.pkg()
   203  	return
   204  }
   205  
   206  func (p *importer) record(t types.Type) {
   207  	p.typList = append(p.typList, t)
   208  }
   209  
   210  // A dddSlice is a types.Type representing ...T parameters.
   211  // It only appears for parameter types and does not escape
   212  // the importer.
   213  type dddSlice struct {
   214  	elem types.Type
   215  }
   216  
   217  func (t *dddSlice) Underlying() types.Type { return t }
   218  func (t *dddSlice) String() string         { return "..." + t.elem.String() }
   219  
   220  // parent is the package which declared the type; parent == nil means
   221  // the package currently imported. The parent package is needed for
   222  // exported struct fields and interface methods which don't contain
   223  // explicit package information in the export data.
   224  func (p *importer) typ(parent *types.Package) types.Type {
   225  	// if the type was seen before, i is its index (>= 0)
   226  	i := p.tagOrIndex()
   227  	if i >= 0 {
   228  		return p.typList[i]
   229  	}
   230  
   231  	// otherwise, i is the type tag (< 0)
   232  	switch i {
   233  	case namedTag:
   234  		// read type object
   235  		name := p.string()
   236  		parent = p.pkg()
   237  		scope := parent.Scope()
   238  		obj := scope.Lookup(name)
   239  
   240  		// if the object doesn't exist yet, create and insert it
   241  		if obj == nil {
   242  			obj = types.NewTypeName(token.NoPos, parent, name, nil)
   243  			scope.Insert(obj)
   244  		}
   245  
   246  		if _, ok := obj.(*types.TypeName); !ok {
   247  			panic(fmt.Sprintf("pkg = %s, name = %s => %s", parent, name, obj))
   248  		}
   249  
   250  		// associate new named type with obj if it doesn't exist yet
   251  		t0 := types.NewNamed(obj.(*types.TypeName), nil, nil)
   252  
   253  		// but record the existing type, if any
   254  		t := obj.Type().(*types.Named)
   255  		p.record(t)
   256  
   257  		// read underlying type
   258  		t0.SetUnderlying(p.typ(parent))
   259  
   260  		// interfaces don't have associated methods
   261  		if _, ok := t0.Underlying().(*types.Interface); ok {
   262  			return t
   263  		}
   264  
   265  		// read associated methods
   266  		for i := p.int(); i > 0; i-- {
   267  			// TODO(gri) replace this with something closer to fieldName
   268  			name := p.string()
   269  			if !exported(name) {
   270  				p.pkg()
   271  			}
   272  
   273  			recv, _ := p.paramList() // TODO(gri) do we need a full param list for the receiver?
   274  			params, isddd := p.paramList()
   275  			result, _ := p.paramList()
   276  			p.int() // read and discard index of inlined function body
   277  
   278  			sig := types.NewSignature(recv.At(0), params, result, isddd)
   279  			t0.AddMethod(types.NewFunc(token.NoPos, parent, name, sig))
   280  		}
   281  
   282  		return t
   283  
   284  	case arrayTag:
   285  		t := new(types.Array)
   286  		p.record(t)
   287  
   288  		n := p.int64()
   289  		*t = *types.NewArray(p.typ(parent), n)
   290  		return t
   291  
   292  	case sliceTag:
   293  		t := new(types.Slice)
   294  		p.record(t)
   295  
   296  		*t = *types.NewSlice(p.typ(parent))
   297  		return t
   298  
   299  	case dddTag:
   300  		t := new(dddSlice)
   301  		p.record(t)
   302  
   303  		t.elem = p.typ(parent)
   304  		return t
   305  
   306  	case structTag:
   307  		t := new(types.Struct)
   308  		p.record(t)
   309  
   310  		n := p.int()
   311  		fields := make([]*types.Var, n)
   312  		tags := make([]string, n)
   313  		for i := range fields {
   314  			fields[i] = p.field(parent)
   315  			tags[i] = p.string()
   316  		}
   317  		*t = *types.NewStruct(fields, tags)
   318  		return t
   319  
   320  	case pointerTag:
   321  		t := new(types.Pointer)
   322  		p.record(t)
   323  
   324  		*t = *types.NewPointer(p.typ(parent))
   325  		return t
   326  
   327  	case signatureTag:
   328  		t := new(types.Signature)
   329  		p.record(t)
   330  
   331  		params, isddd := p.paramList()
   332  		result, _ := p.paramList()
   333  		*t = *types.NewSignature(nil, params, result, isddd)
   334  		return t
   335  
   336  	case interfaceTag:
   337  		// Create a dummy entry in the type list. This is safe because we
   338  		// cannot expect the interface type to appear in a cycle, as any
   339  		// such cycle must contain a named type which would have been
   340  		// first defined earlier.
   341  		n := len(p.typList)
   342  		p.record(nil)
   343  
   344  		// no embedded interfaces with gc compiler
   345  		if p.int() != 0 {
   346  			panic("unexpected embedded interface")
   347  		}
   348  
   349  		// read methods
   350  		methods := make([]*types.Func, p.int())
   351  		for i := range methods {
   352  			pkg, name := p.fieldName(parent)
   353  			params, isddd := p.paramList()
   354  			result, _ := p.paramList()
   355  			sig := types.NewSignature(nil, params, result, isddd)
   356  			methods[i] = types.NewFunc(token.NoPos, pkg, name, sig)
   357  		}
   358  
   359  		t := types.NewInterface(methods, nil)
   360  		p.typList[n] = t
   361  		return t
   362  
   363  	case mapTag:
   364  		t := new(types.Map)
   365  		p.record(t)
   366  
   367  		key := p.typ(parent)
   368  		val := p.typ(parent)
   369  		*t = *types.NewMap(key, val)
   370  		return t
   371  
   372  	case chanTag:
   373  		t := new(types.Chan)
   374  		p.record(t)
   375  
   376  		var dir types.ChanDir
   377  		// tag values must match the constants in cmd/compile/internal/gc/go.go
   378  		switch d := p.int(); d {
   379  		case 1 /* Crecv */ :
   380  			dir = types.RecvOnly
   381  		case 2 /* Csend */ :
   382  			dir = types.SendOnly
   383  		case 3 /* Cboth */ :
   384  			dir = types.SendRecv
   385  		default:
   386  			panic(fmt.Sprintf("unexpected channel dir %d", d))
   387  		}
   388  		val := p.typ(parent)
   389  		*t = *types.NewChan(dir, val)
   390  		return t
   391  
   392  	default:
   393  		panic(fmt.Sprintf("unexpected type tag %d", i))
   394  	}
   395  }
   396  
   397  func (p *importer) field(parent *types.Package) *types.Var {
   398  	pkg, name := p.fieldName(parent)
   399  	typ := p.typ(parent)
   400  
   401  	anonymous := false
   402  	if name == "" {
   403  		// anonymous field - typ must be T or *T and T must be a type name
   404  		switch typ := deref(typ).(type) {
   405  		case *types.Basic: // basic types are named types
   406  			pkg = nil // // objects defined in Universe scope have no package
   407  			name = typ.Name()
   408  		case *types.Named:
   409  			name = typ.Obj().Name()
   410  		default:
   411  			panic("anonymous field expected")
   412  		}
   413  		anonymous = true
   414  	}
   415  
   416  	return types.NewField(token.NoPos, pkg, name, typ, anonymous)
   417  }
   418  
   419  func (p *importer) fieldName(parent *types.Package) (*types.Package, string) {
   420  	pkg := parent
   421  	if pkg == nil {
   422  		// use the imported package instead
   423  		pkg = p.pkgList[0]
   424  	}
   425  	name := p.string()
   426  	if name == "" {
   427  		return pkg, "" // anonymous
   428  	}
   429  	if name == "?" || name != "_" && !exported(name) {
   430  		// explicitly qualified field
   431  		if name == "?" {
   432  			name = "" // anonymous
   433  		}
   434  		pkg = p.pkg()
   435  	}
   436  	return pkg, name
   437  }
   438  
   439  func (p *importer) paramList() (*types.Tuple, bool) {
   440  	n := p.int()
   441  	if n == 0 {
   442  		return nil, false
   443  	}
   444  	// negative length indicates unnamed parameters
   445  	named := true
   446  	if n < 0 {
   447  		n = -n
   448  		named = false
   449  	}
   450  	// n > 0
   451  	params := make([]*types.Var, n)
   452  	isddd := false
   453  	for i := range params {
   454  		params[i], isddd = p.param(named)
   455  	}
   456  	return types.NewTuple(params...), isddd
   457  }
   458  
   459  func (p *importer) param(named bool) (*types.Var, bool) {
   460  	t := p.typ(nil)
   461  	td, isddd := t.(*dddSlice)
   462  	if isddd {
   463  		t = types.NewSlice(td.elem)
   464  	}
   465  
   466  	var pkg *types.Package
   467  	var name string
   468  	if named {
   469  		name = p.string()
   470  		if name == "" {
   471  			panic("expected named parameter")
   472  		}
   473  		pkg = p.pkg()
   474  	}
   475  
   476  	// read and discard compiler-specific info
   477  	p.string()
   478  
   479  	return types.NewVar(token.NoPos, pkg, name, t), isddd
   480  }
   481  
   482  func exported(name string) bool {
   483  	ch, _ := utf8.DecodeRuneInString(name)
   484  	return unicode.IsUpper(ch)
   485  }
   486  
   487  func (p *importer) value() constant.Value {
   488  	switch tag := p.tagOrIndex(); tag {
   489  	case falseTag:
   490  		return constant.MakeBool(false)
   491  	case trueTag:
   492  		return constant.MakeBool(true)
   493  	case int64Tag:
   494  		return constant.MakeInt64(p.int64())
   495  	case floatTag:
   496  		return p.float()
   497  	case complexTag:
   498  		re := p.float()
   499  		im := p.float()
   500  		return constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
   501  	case stringTag:
   502  		return constant.MakeString(p.string())
   503  	default:
   504  		panic(fmt.Sprintf("unexpected value tag %d", tag))
   505  	}
   506  }
   507  
   508  func (p *importer) float() constant.Value {
   509  	sign := p.int()
   510  	if sign == 0 {
   511  		return constant.MakeInt64(0)
   512  	}
   513  
   514  	exp := p.int()
   515  	mant := []byte(p.string()) // big endian
   516  
   517  	// remove leading 0's if any
   518  	for len(mant) > 0 && mant[0] == 0 {
   519  		mant = mant[1:]
   520  	}
   521  
   522  	// convert to little endian
   523  	// TODO(gri) go/constant should have a more direct conversion function
   524  	//           (e.g., once it supports a big.Float based implementation)
   525  	for i, j := 0, len(mant)-1; i < j; i, j = i+1, j-1 {
   526  		mant[i], mant[j] = mant[j], mant[i]
   527  	}
   528  
   529  	// adjust exponent (constant.MakeFromBytes creates an integer value,
   530  	// but mant represents the mantissa bits such that 0.5 <= mant < 1.0)
   531  	exp -= len(mant) << 3
   532  	if len(mant) > 0 {
   533  		for msd := mant[len(mant)-1]; msd&0x80 == 0; msd <<= 1 {
   534  			exp++
   535  		}
   536  	}
   537  
   538  	x := constant.MakeFromBytes(mant)
   539  	switch {
   540  	case exp < 0:
   541  		d := constant.Shift(constant.MakeInt64(1), token.SHL, uint(-exp))
   542  		x = constant.BinaryOp(x, token.QUO, d)
   543  	case exp > 0:
   544  		x = constant.Shift(x, token.SHL, uint(exp))
   545  	}
   546  
   547  	if sign < 0 {
   548  		x = constant.UnaryOp(token.SUB, x, 0)
   549  	}
   550  	return x
   551  }
   552  
   553  // ----------------------------------------------------------------------------
   554  // Low-level decoders
   555  
   556  func (p *importer) tagOrIndex() int {
   557  	if p.debugFormat {
   558  		p.marker('t')
   559  	}
   560  
   561  	return int(p.rawInt64())
   562  }
   563  
   564  func (p *importer) int() int {
   565  	x := p.int64()
   566  	if int64(int(x)) != x {
   567  		panic("exported integer too large")
   568  	}
   569  	return int(x)
   570  }
   571  
   572  func (p *importer) int64() int64 {
   573  	if p.debugFormat {
   574  		p.marker('i')
   575  	}
   576  
   577  	return p.rawInt64()
   578  }
   579  
   580  func (p *importer) string() string {
   581  	if p.debugFormat {
   582  		p.marker('s')
   583  	}
   584  
   585  	if n := int(p.rawInt64()); n > 0 {
   586  		if cap(p.buf) < n {
   587  			p.buf = make([]byte, n)
   588  		} else {
   589  			p.buf = p.buf[:n]
   590  		}
   591  		for i := 0; i < n; i++ {
   592  			p.buf[i] = p.byte()
   593  		}
   594  		return string(p.buf)
   595  	}
   596  
   597  	return ""
   598  }
   599  
   600  func (p *importer) marker(want byte) {
   601  	if got := p.byte(); got != want {
   602  		panic(fmt.Sprintf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read))
   603  	}
   604  
   605  	pos := p.read
   606  	if n := int(p.rawInt64()); n != pos {
   607  		panic(fmt.Sprintf("incorrect position: got %d; want %d", n, pos))
   608  	}
   609  }
   610  
   611  // rawInt64 should only be used by low-level decoders
   612  func (p *importer) rawInt64() int64 {
   613  	i, err := binary.ReadVarint(p)
   614  	if err != nil {
   615  		panic(fmt.Sprintf("read error: %v", err))
   616  	}
   617  	return i
   618  }
   619  
   620  // needed for binary.ReadVarint in rawInt64
   621  func (p *importer) ReadByte() (byte, error) {
   622  	return p.byte(), nil
   623  }
   624  
   625  // byte is the bottleneck interface for reading p.data.
   626  // It unescapes '|' 'S' to '$' and '|' '|' to '|'.
   627  func (p *importer) byte() byte {
   628  	b := p.data[0]
   629  	r := 1
   630  	if b == '|' {
   631  		b = p.data[1]
   632  		r = 2
   633  		switch b {
   634  		case 'S':
   635  			b = '$'
   636  		case '|':
   637  			// nothing to do
   638  		default:
   639  			panic("unexpected escape sequence in export data")
   640  		}
   641  	}
   642  	p.data = p.data[r:]
   643  	p.read += r
   644  	return b
   645  
   646  }
   647  
   648  // ----------------------------------------------------------------------------
   649  // Export format
   650  
   651  // Tags. Must be < 0.
   652  const (
   653  	// Objects
   654  	packageTag = -(iota + 1)
   655  	constTag
   656  	typeTag
   657  	varTag
   658  	funcTag
   659  	endTag
   660  
   661  	// Types
   662  	namedTag
   663  	arrayTag
   664  	sliceTag
   665  	dddTag
   666  	structTag
   667  	pointerTag
   668  	signatureTag
   669  	interfaceTag
   670  	mapTag
   671  	chanTag
   672  
   673  	// Values
   674  	falseTag
   675  	trueTag
   676  	int64Tag
   677  	floatTag
   678  	fractionTag // not used by gc
   679  	complexTag
   680  	stringTag
   681  	unknownTag // not used by gc (only appears in packages with errors)
   682  )
   683  
   684  var predeclared = []types.Type{
   685  	// basic types
   686  	types.Typ[types.Bool],
   687  	types.Typ[types.Int],
   688  	types.Typ[types.Int8],
   689  	types.Typ[types.Int16],
   690  	types.Typ[types.Int32],
   691  	types.Typ[types.Int64],
   692  	types.Typ[types.Uint],
   693  	types.Typ[types.Uint8],
   694  	types.Typ[types.Uint16],
   695  	types.Typ[types.Uint32],
   696  	types.Typ[types.Uint64],
   697  	types.Typ[types.Uintptr],
   698  	types.Typ[types.Float32],
   699  	types.Typ[types.Float64],
   700  	types.Typ[types.Complex64],
   701  	types.Typ[types.Complex128],
   702  	types.Typ[types.String],
   703  
   704  	// aliases
   705  	types.Universe.Lookup("byte").Type(),
   706  	types.Universe.Lookup("rune").Type(),
   707  
   708  	// error
   709  	types.Universe.Lookup("error").Type(),
   710  
   711  	// untyped types
   712  	types.Typ[types.UntypedBool],
   713  	types.Typ[types.UntypedInt],
   714  	types.Typ[types.UntypedRune],
   715  	types.Typ[types.UntypedFloat],
   716  	types.Typ[types.UntypedComplex],
   717  	types.Typ[types.UntypedString],
   718  	types.Typ[types.UntypedNil],
   719  
   720  	// package unsafe
   721  	types.Typ[types.UnsafePointer],
   722  
   723  	// invalid type
   724  	types.Typ[types.Invalid], // only appears in packages with errors
   725  
   726  	// TODO(mdempsky): Provide an actual Type value to represent "any"?
   727  	// (Why exactly does gc emit the "any" type?)
   728  	types.Typ[types.Invalid],
   729  }