...

Source file src/pkg/go/internal/gcimporter/iimport.go

     1	// Copyright 2018 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	// Indexed package import.
     6	// See cmd/compile/internal/gc/iexport.go for the export data format.
     7	
     8	package gcimporter
     9	
    10	import (
    11		"bytes"
    12		"encoding/binary"
    13		"fmt"
    14		"go/constant"
    15		"go/token"
    16		"go/types"
    17		"io"
    18		"sort"
    19	)
    20	
    21	type intReader struct {
    22		*bytes.Reader
    23		path string
    24	}
    25	
    26	func (r *intReader) int64() int64 {
    27		i, err := binary.ReadVarint(r.Reader)
    28		if err != nil {
    29			errorf("import %q: read varint error: %v", r.path, err)
    30		}
    31		return i
    32	}
    33	
    34	func (r *intReader) uint64() uint64 {
    35		i, err := binary.ReadUvarint(r.Reader)
    36		if err != nil {
    37			errorf("import %q: read varint error: %v", r.path, err)
    38		}
    39		return i
    40	}
    41	
    42	const predeclReserved = 32
    43	
    44	type itag uint64
    45	
    46	const (
    47		// Types
    48		definedType itag = iota
    49		pointerType
    50		sliceType
    51		arrayType
    52		chanType
    53		mapType
    54		signatureType
    55		structType
    56		interfaceType
    57	)
    58	
    59	// iImportData imports a package from the serialized package data
    60	// and returns the number of bytes consumed and a reference to the package.
    61	// If the export data version is not recognized or the format is otherwise
    62	// compromised, an error is returned.
    63	func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
    64		const currentVersion = 0
    65		version := -1
    66		defer func() {
    67			if e := recover(); e != nil {
    68				if version > currentVersion {
    69					err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e)
    70				} else {
    71					err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e)
    72				}
    73			}
    74		}()
    75	
    76		r := &intReader{bytes.NewReader(data), path}
    77	
    78		version = int(r.uint64())
    79		switch version {
    80		case currentVersion:
    81		default:
    82			errorf("unknown iexport format version %d", version)
    83		}
    84	
    85		sLen := int64(r.uint64())
    86		dLen := int64(r.uint64())
    87	
    88		whence, _ := r.Seek(0, io.SeekCurrent)
    89		stringData := data[whence : whence+sLen]
    90		declData := data[whence+sLen : whence+sLen+dLen]
    91		r.Seek(sLen+dLen, io.SeekCurrent)
    92	
    93		p := iimporter{
    94			ipath: path,
    95	
    96			stringData:  stringData,
    97			stringCache: make(map[uint64]string),
    98			pkgCache:    make(map[uint64]*types.Package),
    99	
   100			declData: declData,
   101			pkgIndex: make(map[*types.Package]map[string]uint64),
   102			typCache: make(map[uint64]types.Type),
   103	
   104			fake: fakeFileSet{
   105				fset:  fset,
   106				files: make(map[string]*token.File),
   107			},
   108		}
   109	
   110		for i, pt := range predeclared {
   111			p.typCache[uint64(i)] = pt
   112		}
   113	
   114		pkgList := make([]*types.Package, r.uint64())
   115		for i := range pkgList {
   116			pkgPathOff := r.uint64()
   117			pkgPath := p.stringAt(pkgPathOff)
   118			pkgName := p.stringAt(r.uint64())
   119			_ = r.uint64() // package height; unused by go/types
   120	
   121			if pkgPath == "" {
   122				pkgPath = path
   123			}
   124			pkg := imports[pkgPath]
   125			if pkg == nil {
   126				pkg = types.NewPackage(pkgPath, pkgName)
   127				imports[pkgPath] = pkg
   128			} else if pkg.Name() != pkgName {
   129				errorf("conflicting names %s and %s for package %q", pkg.Name(), pkgName, path)
   130			}
   131	
   132			p.pkgCache[pkgPathOff] = pkg
   133	
   134			nameIndex := make(map[string]uint64)
   135			for nSyms := r.uint64(); nSyms > 0; nSyms-- {
   136				name := p.stringAt(r.uint64())
   137				nameIndex[name] = r.uint64()
   138			}
   139	
   140			p.pkgIndex[pkg] = nameIndex
   141			pkgList[i] = pkg
   142		}
   143	
   144		localpkg := pkgList[0]
   145	
   146		names := make([]string, 0, len(p.pkgIndex[localpkg]))
   147		for name := range p.pkgIndex[localpkg] {
   148			names = append(names, name)
   149		}
   150		sort.Strings(names)
   151		for _, name := range names {
   152			p.doDecl(localpkg, name)
   153		}
   154	
   155		for _, typ := range p.interfaceList {
   156			typ.Complete()
   157		}
   158	
   159		// record all referenced packages as imports
   160		list := append(([]*types.Package)(nil), pkgList[1:]...)
   161		sort.Sort(byPath(list))
   162		localpkg.SetImports(list)
   163	
   164		// package was imported completely and without errors
   165		localpkg.MarkComplete()
   166	
   167		consumed, _ := r.Seek(0, io.SeekCurrent)
   168		return int(consumed), localpkg, nil
   169	}
   170	
   171	type iimporter struct {
   172		ipath string
   173	
   174		stringData  []byte
   175		stringCache map[uint64]string
   176		pkgCache    map[uint64]*types.Package
   177	
   178		declData []byte
   179		pkgIndex map[*types.Package]map[string]uint64
   180		typCache map[uint64]types.Type
   181	
   182		fake          fakeFileSet
   183		interfaceList []*types.Interface
   184	}
   185	
   186	func (p *iimporter) doDecl(pkg *types.Package, name string) {
   187		// See if we've already imported this declaration.
   188		if obj := pkg.Scope().Lookup(name); obj != nil {
   189			return
   190		}
   191	
   192		off, ok := p.pkgIndex[pkg][name]
   193		if !ok {
   194			errorf("%v.%v not in index", pkg, name)
   195		}
   196	
   197		r := &importReader{p: p, currPkg: pkg}
   198		r.declReader.Reset(p.declData[off:])
   199	
   200		r.obj(name)
   201	}
   202	
   203	func (p *iimporter) stringAt(off uint64) string {
   204		if s, ok := p.stringCache[off]; ok {
   205			return s
   206		}
   207	
   208		slen, n := binary.Uvarint(p.stringData[off:])
   209		if n <= 0 {
   210			errorf("varint failed")
   211		}
   212		spos := off + uint64(n)
   213		s := string(p.stringData[spos : spos+slen])
   214		p.stringCache[off] = s
   215		return s
   216	}
   217	
   218	func (p *iimporter) pkgAt(off uint64) *types.Package {
   219		if pkg, ok := p.pkgCache[off]; ok {
   220			return pkg
   221		}
   222		path := p.stringAt(off)
   223		errorf("missing package %q in %q", path, p.ipath)
   224		return nil
   225	}
   226	
   227	func (p *iimporter) typAt(off uint64, base *types.Named) types.Type {
   228		if t, ok := p.typCache[off]; ok && (base == nil || !isInterface(t)) {
   229			return t
   230		}
   231	
   232		if off < predeclReserved {
   233			errorf("predeclared type missing from cache: %v", off)
   234		}
   235	
   236		r := &importReader{p: p}
   237		r.declReader.Reset(p.declData[off-predeclReserved:])
   238		t := r.doType(base)
   239	
   240		if base == nil || !isInterface(t) {
   241			p.typCache[off] = t
   242		}
   243		return t
   244	}
   245	
   246	type importReader struct {
   247		p          *iimporter
   248		declReader bytes.Reader
   249		currPkg    *types.Package
   250		prevFile   string
   251		prevLine   int64
   252	}
   253	
   254	func (r *importReader) obj(name string) {
   255		tag := r.byte()
   256		pos := r.pos()
   257	
   258		switch tag {
   259		case 'A':
   260			typ := r.typ()
   261	
   262			r.declare(types.NewTypeName(pos, r.currPkg, name, typ))
   263	
   264		case 'C':
   265			typ, val := r.value()
   266	
   267			r.declare(types.NewConst(pos, r.currPkg, name, typ, val))
   268	
   269		case 'F':
   270			sig := r.signature(nil)
   271	
   272			r.declare(types.NewFunc(pos, r.currPkg, name, sig))
   273	
   274		case 'T':
   275			// Types can be recursive. We need to setup a stub
   276			// declaration before recursing.
   277			obj := types.NewTypeName(pos, r.currPkg, name, nil)
   278			named := types.NewNamed(obj, nil, nil)
   279			r.declare(obj)
   280	
   281			underlying := r.p.typAt(r.uint64(), named).Underlying()
   282			named.SetUnderlying(underlying)
   283	
   284			if !isInterface(underlying) {
   285				for n := r.uint64(); n > 0; n-- {
   286					mpos := r.pos()
   287					mname := r.ident()
   288					recv := r.param()
   289					msig := r.signature(recv)
   290	
   291					named.AddMethod(types.NewFunc(mpos, r.currPkg, mname, msig))
   292				}
   293			}
   294	
   295		case 'V':
   296			typ := r.typ()
   297	
   298			r.declare(types.NewVar(pos, r.currPkg, name, typ))
   299	
   300		default:
   301			errorf("unexpected tag: %v", tag)
   302		}
   303	}
   304	
   305	func (r *importReader) declare(obj types.Object) {
   306		obj.Pkg().Scope().Insert(obj)
   307	}
   308	
   309	func (r *importReader) value() (typ types.Type, val constant.Value) {
   310		typ = r.typ()
   311	
   312		switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType {
   313		case types.IsBoolean:
   314			val = constant.MakeBool(r.bool())
   315	
   316		case types.IsString:
   317			val = constant.MakeString(r.string())
   318	
   319		case types.IsInteger:
   320			val = r.mpint(b)
   321	
   322		case types.IsFloat:
   323			val = r.mpfloat(b)
   324	
   325		case types.IsComplex:
   326			re := r.mpfloat(b)
   327			im := r.mpfloat(b)
   328			val = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
   329	
   330		default:
   331			errorf("unexpected type %v", typ) // panics
   332			panic("unreachable")
   333		}
   334	
   335		return
   336	}
   337	
   338	func intSize(b *types.Basic) (signed bool, maxBytes uint) {
   339		if (b.Info() & types.IsUntyped) != 0 {
   340			return true, 64
   341		}
   342	
   343		switch b.Kind() {
   344		case types.Float32, types.Complex64:
   345			return true, 3
   346		case types.Float64, types.Complex128:
   347			return true, 7
   348		}
   349	
   350		signed = (b.Info() & types.IsUnsigned) == 0
   351		switch b.Kind() {
   352		case types.Int8, types.Uint8:
   353			maxBytes = 1
   354		case types.Int16, types.Uint16:
   355			maxBytes = 2
   356		case types.Int32, types.Uint32:
   357			maxBytes = 4
   358		default:
   359			maxBytes = 8
   360		}
   361	
   362		return
   363	}
   364	
   365	func (r *importReader) mpint(b *types.Basic) constant.Value {
   366		signed, maxBytes := intSize(b)
   367	
   368		maxSmall := 256 - maxBytes
   369		if signed {
   370			maxSmall = 256 - 2*maxBytes
   371		}
   372		if maxBytes == 1 {
   373			maxSmall = 256
   374		}
   375	
   376		n, _ := r.declReader.ReadByte()
   377		if uint(n) < maxSmall {
   378			v := int64(n)
   379			if signed {
   380				v >>= 1
   381				if n&1 != 0 {
   382					v = ^v
   383				}
   384			}
   385			return constant.MakeInt64(v)
   386		}
   387	
   388		v := -n
   389		if signed {
   390			v = -(n &^ 1) >> 1
   391		}
   392		if v < 1 || uint(v) > maxBytes {
   393			errorf("weird decoding: %v, %v => %v", n, signed, v)
   394		}
   395	
   396		buf := make([]byte, v)
   397		io.ReadFull(&r.declReader, buf)
   398	
   399		// convert to little endian
   400		// TODO(gri) go/constant should have a more direct conversion function
   401		//           (e.g., once it supports a big.Float based implementation)
   402		for i, j := 0, len(buf)-1; i < j; i, j = i+1, j-1 {
   403			buf[i], buf[j] = buf[j], buf[i]
   404		}
   405	
   406		x := constant.MakeFromBytes(buf)
   407		if signed && n&1 != 0 {
   408			x = constant.UnaryOp(token.SUB, x, 0)
   409		}
   410		return x
   411	}
   412	
   413	func (r *importReader) mpfloat(b *types.Basic) constant.Value {
   414		x := r.mpint(b)
   415		if constant.Sign(x) == 0 {
   416			return x
   417		}
   418	
   419		exp := r.int64()
   420		switch {
   421		case exp > 0:
   422			x = constant.Shift(x, token.SHL, uint(exp))
   423		case exp < 0:
   424			d := constant.Shift(constant.MakeInt64(1), token.SHL, uint(-exp))
   425			x = constant.BinaryOp(x, token.QUO, d)
   426		}
   427		return x
   428	}
   429	
   430	func (r *importReader) ident() string {
   431		return r.string()
   432	}
   433	
   434	func (r *importReader) qualifiedIdent() (*types.Package, string) {
   435		name := r.string()
   436		pkg := r.pkg()
   437		return pkg, name
   438	}
   439	
   440	func (r *importReader) pos() token.Pos {
   441		delta := r.int64()
   442		if delta != deltaNewFile {
   443			r.prevLine += delta
   444		} else if l := r.int64(); l == -1 {
   445			r.prevLine += deltaNewFile
   446		} else {
   447			r.prevFile = r.string()
   448			r.prevLine = l
   449		}
   450	
   451		if r.prevFile == "" && r.prevLine == 0 {
   452			return token.NoPos
   453		}
   454	
   455		return r.p.fake.pos(r.prevFile, int(r.prevLine))
   456	}
   457	
   458	func (r *importReader) typ() types.Type {
   459		return r.p.typAt(r.uint64(), nil)
   460	}
   461	
   462	func isInterface(t types.Type) bool {
   463		_, ok := t.(*types.Interface)
   464		return ok
   465	}
   466	
   467	func (r *importReader) pkg() *types.Package { return r.p.pkgAt(r.uint64()) }
   468	func (r *importReader) string() string      { return r.p.stringAt(r.uint64()) }
   469	
   470	func (r *importReader) doType(base *types.Named) types.Type {
   471		switch k := r.kind(); k {
   472		default:
   473			errorf("unexpected kind tag in %q: %v", r.p.ipath, k)
   474			return nil
   475	
   476		case definedType:
   477			pkg, name := r.qualifiedIdent()
   478			r.p.doDecl(pkg, name)
   479			return pkg.Scope().Lookup(name).(*types.TypeName).Type()
   480		case pointerType:
   481			return types.NewPointer(r.typ())
   482		case sliceType:
   483			return types.NewSlice(r.typ())
   484		case arrayType:
   485			n := r.uint64()
   486			return types.NewArray(r.typ(), int64(n))
   487		case chanType:
   488			dir := chanDir(int(r.uint64()))
   489			return types.NewChan(dir, r.typ())
   490		case mapType:
   491			return types.NewMap(r.typ(), r.typ())
   492		case signatureType:
   493			r.currPkg = r.pkg()
   494			return r.signature(nil)
   495	
   496		case structType:
   497			r.currPkg = r.pkg()
   498	
   499			fields := make([]*types.Var, r.uint64())
   500			tags := make([]string, len(fields))
   501			for i := range fields {
   502				fpos := r.pos()
   503				fname := r.ident()
   504				ftyp := r.typ()
   505				emb := r.bool()
   506				tag := r.string()
   507	
   508				fields[i] = types.NewField(fpos, r.currPkg, fname, ftyp, emb)
   509				tags[i] = tag
   510			}
   511			return types.NewStruct(fields, tags)
   512	
   513		case interfaceType:
   514			r.currPkg = r.pkg()
   515	
   516			embeddeds := make([]types.Type, r.uint64())
   517			for i := range embeddeds {
   518				_ = r.pos()
   519				embeddeds[i] = r.typ()
   520			}
   521	
   522			methods := make([]*types.Func, r.uint64())
   523			for i := range methods {
   524				mpos := r.pos()
   525				mname := r.ident()
   526	
   527				// TODO(mdempsky): Matches bimport.go, but I
   528				// don't agree with this.
   529				var recv *types.Var
   530				if base != nil {
   531					recv = types.NewVar(token.NoPos, r.currPkg, "", base)
   532				}
   533	
   534				msig := r.signature(recv)
   535				methods[i] = types.NewFunc(mpos, r.currPkg, mname, msig)
   536			}
   537	
   538			typ := types.NewInterfaceType(methods, embeddeds)
   539			r.p.interfaceList = append(r.p.interfaceList, typ)
   540			return typ
   541		}
   542	}
   543	
   544	func (r *importReader) kind() itag {
   545		return itag(r.uint64())
   546	}
   547	
   548	func (r *importReader) signature(recv *types.Var) *types.Signature {
   549		params := r.paramList()
   550		results := r.paramList()
   551		variadic := params.Len() > 0 && r.bool()
   552		return types.NewSignature(recv, params, results, variadic)
   553	}
   554	
   555	func (r *importReader) paramList() *types.Tuple {
   556		xs := make([]*types.Var, r.uint64())
   557		for i := range xs {
   558			xs[i] = r.param()
   559		}
   560		return types.NewTuple(xs...)
   561	}
   562	
   563	func (r *importReader) param() *types.Var {
   564		pos := r.pos()
   565		name := r.ident()
   566		typ := r.typ()
   567		return types.NewParam(pos, r.currPkg, name, typ)
   568	}
   569	
   570	func (r *importReader) bool() bool {
   571		return r.uint64() != 0
   572	}
   573	
   574	func (r *importReader) int64() int64 {
   575		n, err := binary.ReadVarint(&r.declReader)
   576		if err != nil {
   577			errorf("readVarint: %v", err)
   578		}
   579		return n
   580	}
   581	
   582	func (r *importReader) uint64() uint64 {
   583		n, err := binary.ReadUvarint(&r.declReader)
   584		if err != nil {
   585			errorf("readUvarint: %v", err)
   586		}
   587		return n
   588	}
   589	
   590	func (r *importReader) byte() byte {
   591		x, err := r.declReader.ReadByte()
   592		if err != nil {
   593			errorf("declReader.ReadByte: %v", err)
   594		}
   595		return x
   596	}
   597	

View as plain text