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