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