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