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