1
2
3
4
5
6
7
8
9 package gcimporter
10
11 import (
12 "bytes"
13 "encoding/binary"
14 "fmt"
15 "go/constant"
16 "go/token"
17 "go/types"
18 "io"
19 "math/big"
20 "reflect"
21 "sort"
22 "strconv"
23 "strings"
24
25 "golang.org/x/tools/go/types/objectpath"
26 "golang.org/x/tools/internal/aliases"
27 "golang.org/x/tools/internal/tokeninternal"
28 )
29
30
31
32
33
34
35
36
37
38
39
40
41 func IExportShallow(fset *token.FileSet, pkg *types.Package, reportf ReportFunc) ([]byte, error) {
42
43
44
45
46
47 const bundle, shallow = false, true
48 var out bytes.Buffer
49 err := iexportCommon(&out, fset, bundle, shallow, iexportVersion, []*types.Package{pkg})
50 return out.Bytes(), err
51 }
52
53
54
55
56
57
58
59
60
61
62
63
64
65 func IImportShallow(fset *token.FileSet, getPackages GetPackagesFunc, data []byte, path string, reportf ReportFunc) (*types.Package, error) {
66 const bundle = false
67 const shallow = true
68 pkgs, err := iimportCommon(fset, getPackages, data, bundle, path, shallow, reportf)
69 if err != nil {
70 return nil, err
71 }
72 return pkgs[0], nil
73 }
74
75
76 type ReportFunc = func(string, ...interface{})
77
78
79
80 const bundleVersion = 0
81
82
83
84
85
86
87 func IExportData(out io.Writer, fset *token.FileSet, pkg *types.Package) error {
88 const bundle, shallow = false, false
89 return iexportCommon(out, fset, bundle, shallow, iexportVersion, []*types.Package{pkg})
90 }
91
92
93 func IExportBundle(out io.Writer, fset *token.FileSet, pkgs []*types.Package) error {
94 const bundle, shallow = true, false
95 return iexportCommon(out, fset, bundle, shallow, iexportVersion, pkgs)
96 }
97
98 func iexportCommon(out io.Writer, fset *token.FileSet, bundle, shallow bool, version int, pkgs []*types.Package) (err error) {
99 if !debug {
100 defer func() {
101 if e := recover(); e != nil {
102 if ierr, ok := e.(internalError); ok {
103 err = ierr
104 return
105 }
106
107 panic(e)
108 }
109 }()
110 }
111
112 p := iexporter{
113 fset: fset,
114 version: version,
115 shallow: shallow,
116 allPkgs: map[*types.Package]bool{},
117 stringIndex: map[string]uint64{},
118 declIndex: map[types.Object]uint64{},
119 tparamNames: map[types.Object]string{},
120 typIndex: map[types.Type]uint64{},
121 }
122 if !bundle {
123 p.localpkg = pkgs[0]
124 }
125
126 for i, pt := range predeclared() {
127 p.typIndex[pt] = uint64(i)
128 }
129 if len(p.typIndex) > predeclReserved {
130 panic(internalErrorf("too many predeclared types: %d > %d", len(p.typIndex), predeclReserved))
131 }
132
133
134 for _, pkg := range pkgs {
135 scope := pkg.Scope()
136 for _, name := range scope.Names() {
137 if token.IsExported(name) {
138 p.pushDecl(scope.Lookup(name))
139 }
140 }
141
142 if bundle {
143
144 p.allPkgs[pkg] = true
145 for _, imp := range pkg.Imports() {
146 p.allPkgs[imp] = true
147 }
148 }
149 }
150
151
152 for !p.declTodo.empty() {
153 p.doDecl(p.declTodo.popHead())
154 }
155
156
157 var files intWriter
158 var fileOffset []uint64
159 if p.shallow {
160 fileOffset = make([]uint64, len(p.fileInfos))
161 for i, info := range p.fileInfos {
162 fileOffset[i] = uint64(files.Len())
163 p.encodeFile(&files, info.file, info.needed)
164 }
165 }
166
167
168 dataLen := uint64(p.data0.Len())
169 w := p.newWriter()
170 w.writeIndex(p.declIndex)
171
172 if bundle {
173 w.uint64(uint64(len(pkgs)))
174 for _, pkg := range pkgs {
175 w.pkg(pkg)
176 imps := pkg.Imports()
177 w.uint64(uint64(len(imps)))
178 for _, imp := range imps {
179 w.pkg(imp)
180 }
181 }
182 }
183 w.flush()
184
185
186 var hdr intWriter
187 if bundle {
188 hdr.uint64(bundleVersion)
189 }
190 hdr.uint64(uint64(p.version))
191 hdr.uint64(uint64(p.strings.Len()))
192 if p.shallow {
193 hdr.uint64(uint64(files.Len()))
194 hdr.uint64(uint64(len(fileOffset)))
195 for _, offset := range fileOffset {
196 hdr.uint64(offset)
197 }
198 }
199 hdr.uint64(dataLen)
200
201
202 io.Copy(out, &hdr)
203 io.Copy(out, &p.strings)
204 if p.shallow {
205 io.Copy(out, &files)
206 }
207 io.Copy(out, &p.data0)
208
209 return nil
210 }
211
212
213
214
215 func (p *iexporter) encodeFile(w *intWriter, file *token.File, needed []uint64) {
216 _ = needed[0]
217
218 w.uint64(p.stringOff(file.Name()))
219
220 size := uint64(file.Size())
221 w.uint64(size)
222
223
224 sort.Slice(needed, func(i, j int) bool { return needed[i] < needed[j] })
225
226 lines := tokeninternal.GetLines(file)
227 w.uint64(uint64(len(lines)))
228
229
230
231
232 var sparse [][2]int
233 outer:
234 for i, lineStart := range lines {
235 lineEnd := size
236 if i < len(lines)-1 {
237 lineEnd = uint64(lines[i+1])
238 }
239
240 if needed[0] < lineEnd {
241 sparse = append(sparse, [2]int{i, lineStart})
242 for needed[0] < lineEnd {
243 needed = needed[1:]
244 if len(needed) == 0 {
245 break outer
246 }
247 }
248 }
249 }
250
251
252 w.uint64(uint64(len(sparse)))
253 var prev [2]int
254 for _, pair := range sparse {
255 w.uint64(uint64(pair[0] - prev[0]))
256 w.uint64(uint64(pair[1] - prev[1]))
257 prev = pair
258 }
259 }
260
261
262
263
264
265 func (w *exportWriter) writeIndex(index map[types.Object]uint64) {
266 type pkgObj struct {
267 obj types.Object
268 name string
269 }
270
271 pkgObjs := map[*types.Package][]pkgObj{}
272
273
274
275
276 if w.p.localpkg != nil {
277 pkgObjs[w.p.localpkg] = nil
278 }
279 for pkg := range w.p.allPkgs {
280 pkgObjs[pkg] = nil
281 }
282
283 for obj := range index {
284 name := w.p.exportName(obj)
285 pkgObjs[obj.Pkg()] = append(pkgObjs[obj.Pkg()], pkgObj{obj, name})
286 }
287
288 var pkgs []*types.Package
289 for pkg, objs := range pkgObjs {
290 pkgs = append(pkgs, pkg)
291
292 sort.Slice(objs, func(i, j int) bool {
293 return objs[i].name < objs[j].name
294 })
295 }
296
297 sort.Slice(pkgs, func(i, j int) bool {
298 return w.exportPath(pkgs[i]) < w.exportPath(pkgs[j])
299 })
300
301 w.uint64(uint64(len(pkgs)))
302 for _, pkg := range pkgs {
303 w.string(w.exportPath(pkg))
304 w.string(pkg.Name())
305 w.uint64(uint64(0))
306
307 objs := pkgObjs[pkg]
308 w.uint64(uint64(len(objs)))
309 for _, obj := range objs {
310 w.string(obj.name)
311 w.uint64(index[obj.obj])
312 }
313 }
314 }
315
316
317
318 func (p *iexporter) exportName(obj types.Object) (res string) {
319 if name := p.tparamNames[obj]; name != "" {
320 return name
321 }
322 return obj.Name()
323 }
324
325 type iexporter struct {
326 fset *token.FileSet
327 out *bytes.Buffer
328 version int
329
330 shallow bool
331 objEncoder *objectpath.Encoder
332 localpkg *types.Package
333
334
335
336
337 allPkgs map[*types.Package]bool
338
339 declTodo objQueue
340
341 strings intWriter
342 stringIndex map[string]uint64
343
344
345
346
347 fileInfo map[*token.File]uint64
348 fileInfos []*filePositions
349
350 data0 intWriter
351 declIndex map[types.Object]uint64
352 tparamNames map[types.Object]string
353 typIndex map[types.Type]uint64
354
355 indent int
356 }
357
358 type filePositions struct {
359 file *token.File
360 needed []uint64
361 }
362
363 func (p *iexporter) trace(format string, args ...interface{}) {
364 if !trace {
365
366
367 return
368 }
369 fmt.Printf(strings.Repeat("..", p.indent)+format+"\n", args...)
370 }
371
372
373
374
375
376 func (p *iexporter) objectpathEncoder() *objectpath.Encoder {
377 if p.objEncoder == nil {
378 p.objEncoder = new(objectpath.Encoder)
379 }
380 return p.objEncoder
381 }
382
383
384
385 func (p *iexporter) stringOff(s string) uint64 {
386 off, ok := p.stringIndex[s]
387 if !ok {
388 off = uint64(p.strings.Len())
389 p.stringIndex[s] = off
390
391 p.strings.uint64(uint64(len(s)))
392 p.strings.WriteString(s)
393 }
394 return off
395 }
396
397
398 func (p *iexporter) fileIndexAndOffset(file *token.File, pos token.Pos) (uint64, uint64) {
399 index, ok := p.fileInfo[file]
400 if !ok {
401 index = uint64(len(p.fileInfo))
402 p.fileInfos = append(p.fileInfos, &filePositions{file: file})
403 if p.fileInfo == nil {
404 p.fileInfo = make(map[*token.File]uint64)
405 }
406 p.fileInfo[file] = index
407 }
408
409 info := p.fileInfos[index]
410 offset := uint64(file.Offset(pos))
411 info.needed = append(info.needed, offset)
412
413 return index, offset
414 }
415
416
417 func (p *iexporter) pushDecl(obj types.Object) {
418
419
420 if obj.Pkg() == types.Unsafe {
421 panic("cannot export package unsafe")
422 }
423
424
425 if p.shallow && obj.Pkg() != p.localpkg {
426 return
427 }
428
429 if _, ok := p.declIndex[obj]; ok {
430 return
431 }
432
433 p.declIndex[obj] = ^uint64(0)
434 p.declTodo.pushTail(obj)
435 }
436
437
438 type exportWriter struct {
439 p *iexporter
440
441 data intWriter
442 prevFile string
443 prevLine int64
444 prevColumn int64
445 }
446
447 func (w *exportWriter) exportPath(pkg *types.Package) string {
448 if pkg == w.p.localpkg {
449 return ""
450 }
451 return pkg.Path()
452 }
453
454 func (p *iexporter) doDecl(obj types.Object) {
455 if trace {
456 p.trace("exporting decl %v (%T)", obj, obj)
457 p.indent++
458 defer func() {
459 p.indent--
460 p.trace("=> %s", obj)
461 }()
462 }
463 w := p.newWriter()
464
465 switch obj := obj.(type) {
466 case *types.Var:
467 w.tag(varTag)
468 w.pos(obj.Pos())
469 w.typ(obj.Type(), obj.Pkg())
470
471 case *types.Func:
472 sig, _ := obj.Type().(*types.Signature)
473 if sig.Recv() != nil {
474
475
476
477
478 if sig.Recv().Type() != types.Typ[types.Invalid] {
479 panic(internalErrorf("unexpected method: %v", sig))
480 }
481 }
482
483
484 if sig.TypeParams().Len() == 0 {
485 w.tag(funcTag)
486 } else {
487 w.tag(genericFuncTag)
488 }
489 w.pos(obj.Pos())
490
491
492
493
494
495
496
497 if tparams := sig.TypeParams(); tparams.Len() > 0 {
498 w.tparamList(obj.Name(), tparams, obj.Pkg())
499 }
500 w.signature(sig)
501
502 case *types.Const:
503 w.tag(constTag)
504 w.pos(obj.Pos())
505 w.value(obj.Type(), obj.Val())
506
507 case *types.TypeName:
508 t := obj.Type()
509
510 if tparam, ok := aliases.Unalias(t).(*types.TypeParam); ok {
511 w.tag(typeParamTag)
512 w.pos(obj.Pos())
513 constraint := tparam.Constraint()
514 if p.version >= iexportVersionGo1_18 {
515 implicit := false
516 if iface, _ := aliases.Unalias(constraint).(*types.Interface); iface != nil {
517 implicit = iface.IsImplicit()
518 }
519 w.bool(implicit)
520 }
521 w.typ(constraint, obj.Pkg())
522 break
523 }
524
525 if obj.IsAlias() {
526 w.tag(aliasTag)
527 w.pos(obj.Pos())
528 if alias, ok := t.(*aliases.Alias); ok {
529
530
531 t = aliases.Rhs(alias)
532 }
533 w.typ(t, obj.Pkg())
534 break
535 }
536
537
538 named, ok := t.(*types.Named)
539 if !ok {
540 panic(internalErrorf("%s is not a defined type", t))
541 }
542
543 if named.TypeParams().Len() == 0 {
544 w.tag(typeTag)
545 } else {
546 w.tag(genericTypeTag)
547 }
548 w.pos(obj.Pos())
549
550 if named.TypeParams().Len() > 0 {
551
552
553 w.tparamList(obj.Name(), named.TypeParams(), obj.Pkg())
554 }
555
556 underlying := named.Underlying()
557 w.typ(underlying, obj.Pkg())
558
559 if types.IsInterface(t) {
560 break
561 }
562
563 n := named.NumMethods()
564 w.uint64(uint64(n))
565 for i := 0; i < n; i++ {
566 m := named.Method(i)
567 w.pos(m.Pos())
568 w.string(m.Name())
569 sig, _ := m.Type().(*types.Signature)
570
571
572
573 if rparams := sig.RecvTypeParams(); rparams.Len() > 0 {
574 prefix := obj.Name() + "." + m.Name()
575 for i := 0; i < rparams.Len(); i++ {
576 rparam := rparams.At(i)
577 name := tparamExportName(prefix, rparam)
578 w.p.tparamNames[rparam.Obj()] = name
579 }
580 }
581 w.param(sig.Recv())
582 w.signature(sig)
583 }
584
585 default:
586 panic(internalErrorf("unexpected object: %v", obj))
587 }
588
589 p.declIndex[obj] = w.flush()
590 }
591
592 func (w *exportWriter) tag(tag byte) {
593 w.data.WriteByte(tag)
594 }
595
596 func (w *exportWriter) pos(pos token.Pos) {
597 if w.p.shallow {
598 w.posV2(pos)
599 } else if w.p.version >= iexportVersionPosCol {
600 w.posV1(pos)
601 } else {
602 w.posV0(pos)
603 }
604 }
605
606
607
608
609
610 func (w *exportWriter) posV2(pos token.Pos) {
611 if pos == token.NoPos {
612 w.uint64(0)
613 return
614 }
615 file := w.p.fset.File(pos)
616 index, offset := w.p.fileIndexAndOffset(file, pos)
617 w.uint64(1 + index)
618 w.uint64(offset)
619 }
620
621 func (w *exportWriter) posV1(pos token.Pos) {
622 if w.p.fset == nil {
623 w.int64(0)
624 return
625 }
626
627 p := w.p.fset.Position(pos)
628 file := p.Filename
629 line := int64(p.Line)
630 column := int64(p.Column)
631
632 deltaColumn := (column - w.prevColumn) << 1
633 deltaLine := (line - w.prevLine) << 1
634
635 if file != w.prevFile {
636 deltaLine |= 1
637 }
638 if deltaLine != 0 {
639 deltaColumn |= 1
640 }
641
642 w.int64(deltaColumn)
643 if deltaColumn&1 != 0 {
644 w.int64(deltaLine)
645 if deltaLine&1 != 0 {
646 w.string(file)
647 }
648 }
649
650 w.prevFile = file
651 w.prevLine = line
652 w.prevColumn = column
653 }
654
655 func (w *exportWriter) posV0(pos token.Pos) {
656 if w.p.fset == nil {
657 w.int64(0)
658 return
659 }
660
661 p := w.p.fset.Position(pos)
662 file := p.Filename
663 line := int64(p.Line)
664
665
666
667
668
669
670
671
672
673
674 if file == w.prevFile {
675 delta := line - w.prevLine
676 w.int64(delta)
677 if delta == deltaNewFile {
678 w.int64(-1)
679 }
680 } else {
681 w.int64(deltaNewFile)
682 w.int64(line)
683 w.string(file)
684 w.prevFile = file
685 }
686 w.prevLine = line
687 }
688
689 func (w *exportWriter) pkg(pkg *types.Package) {
690
691 w.p.allPkgs[pkg] = true
692
693 w.string(w.exportPath(pkg))
694 }
695
696 func (w *exportWriter) qualifiedType(obj *types.TypeName) {
697 name := w.p.exportName(obj)
698
699
700 w.p.pushDecl(obj)
701 w.string(name)
702 w.pkg(obj.Pkg())
703 }
704
705
706
707
708 func (w *exportWriter) typ(t types.Type, pkg *types.Package) {
709 w.data.uint64(w.p.typOff(t, pkg))
710 }
711
712 func (p *iexporter) newWriter() *exportWriter {
713 return &exportWriter{p: p}
714 }
715
716 func (w *exportWriter) flush() uint64 {
717 off := uint64(w.p.data0.Len())
718 io.Copy(&w.p.data0, &w.data)
719 return off
720 }
721
722 func (p *iexporter) typOff(t types.Type, pkg *types.Package) uint64 {
723 off, ok := p.typIndex[t]
724 if !ok {
725 w := p.newWriter()
726 w.doTyp(t, pkg)
727 off = predeclReserved + w.flush()
728 p.typIndex[t] = off
729 }
730 return off
731 }
732
733 func (w *exportWriter) startType(k itag) {
734 w.data.uint64(uint64(k))
735 }
736
737 func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
738 if trace {
739 w.p.trace("exporting type %s (%T)", t, t)
740 w.p.indent++
741 defer func() {
742 w.p.indent--
743 w.p.trace("=> %s", t)
744 }()
745 }
746 switch t := t.(type) {
747 case *aliases.Alias:
748
749 w.startType(aliasType)
750 w.qualifiedType(t.Obj())
751
752 case *types.Named:
753 if targs := t.TypeArgs(); targs.Len() > 0 {
754 w.startType(instanceType)
755
756
757 w.pos(t.Obj().Pos())
758 w.typeList(targs, pkg)
759 w.typ(t.Origin(), pkg)
760 return
761 }
762 w.startType(definedType)
763 w.qualifiedType(t.Obj())
764
765 case *types.TypeParam:
766 w.startType(typeParamType)
767 w.qualifiedType(t.Obj())
768
769 case *types.Pointer:
770 w.startType(pointerType)
771 w.typ(t.Elem(), pkg)
772
773 case *types.Slice:
774 w.startType(sliceType)
775 w.typ(t.Elem(), pkg)
776
777 case *types.Array:
778 w.startType(arrayType)
779 w.uint64(uint64(t.Len()))
780 w.typ(t.Elem(), pkg)
781
782 case *types.Chan:
783 w.startType(chanType)
784
785 var dir uint64
786 switch t.Dir() {
787 case types.RecvOnly:
788 dir = 1
789 case types.SendOnly:
790 dir = 2
791 case types.SendRecv:
792 dir = 3
793 }
794 w.uint64(dir)
795 w.typ(t.Elem(), pkg)
796
797 case *types.Map:
798 w.startType(mapType)
799 w.typ(t.Key(), pkg)
800 w.typ(t.Elem(), pkg)
801
802 case *types.Signature:
803 w.startType(signatureType)
804 w.pkg(pkg)
805 w.signature(t)
806
807 case *types.Struct:
808 w.startType(structType)
809 n := t.NumFields()
810
811
812 fieldPkg := pkg
813 if n > 0 {
814 fieldPkg = t.Field(0).Pkg()
815 }
816 if fieldPkg == nil {
817
818
819
820
821
822
823
824
825
826
827 if w.p.shallow {
828 fieldPkg = w.p.localpkg
829 } else {
830 panic(internalErrorf("no package to set for empty struct"))
831 }
832 }
833 w.pkg(fieldPkg)
834 w.uint64(uint64(n))
835
836 for i := 0; i < n; i++ {
837 f := t.Field(i)
838 if w.p.shallow {
839 w.objectPath(f)
840 }
841 w.pos(f.Pos())
842 w.string(f.Name())
843 w.typ(f.Type(), fieldPkg)
844 w.bool(f.Anonymous())
845 w.string(t.Tag(i))
846 }
847
848 case *types.Interface:
849 w.startType(interfaceType)
850 w.pkg(pkg)
851
852 n := t.NumEmbeddeds()
853 w.uint64(uint64(n))
854 for i := 0; i < n; i++ {
855 ft := t.EmbeddedType(i)
856 tPkg := pkg
857 if named, _ := aliases.Unalias(ft).(*types.Named); named != nil {
858 w.pos(named.Obj().Pos())
859 } else {
860 w.pos(token.NoPos)
861 }
862 w.typ(ft, tPkg)
863 }
864
865
866
867
868 n = t.NumExplicitMethods()
869 w.uint64(uint64(n))
870 for i := 0; i < n; i++ {
871 m := t.ExplicitMethod(i)
872 if w.p.shallow {
873 w.objectPath(m)
874 }
875 w.pos(m.Pos())
876 w.string(m.Name())
877 sig, _ := m.Type().(*types.Signature)
878 w.signature(sig)
879 }
880
881 case *types.Union:
882 w.startType(unionType)
883 nt := t.Len()
884 w.uint64(uint64(nt))
885 for i := 0; i < nt; i++ {
886 term := t.Term(i)
887 w.bool(term.Tilde())
888 w.typ(term.Type(), pkg)
889 }
890
891 default:
892 panic(internalErrorf("unexpected type: %v, %v", t, reflect.TypeOf(t)))
893 }
894 }
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917 func (w *exportWriter) objectPath(obj types.Object) {
918 if obj.Pkg() == nil || obj.Pkg() == w.p.localpkg {
919
920
921
922 w.string("")
923 return
924 }
925 objectPath, err := w.p.objectpathEncoder().For(obj)
926 if err != nil {
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946 w.string("")
947 return
948 }
949 w.string(string(objectPath))
950 w.pkg(obj.Pkg())
951 }
952
953 func (w *exportWriter) signature(sig *types.Signature) {
954 w.paramList(sig.Params())
955 w.paramList(sig.Results())
956 if sig.Params().Len() > 0 {
957 w.bool(sig.Variadic())
958 }
959 }
960
961 func (w *exportWriter) typeList(ts *types.TypeList, pkg *types.Package) {
962 w.uint64(uint64(ts.Len()))
963 for i := 0; i < ts.Len(); i++ {
964 w.typ(ts.At(i), pkg)
965 }
966 }
967
968 func (w *exportWriter) tparamList(prefix string, list *types.TypeParamList, pkg *types.Package) {
969 ll := uint64(list.Len())
970 w.uint64(ll)
971 for i := 0; i < list.Len(); i++ {
972 tparam := list.At(i)
973
974 exportName := tparamExportName(prefix, tparam)
975 w.p.tparamNames[tparam.Obj()] = exportName
976 w.typ(list.At(i), pkg)
977 }
978 }
979
980 const blankMarker = "$"
981
982
983
984
985
986 func tparamExportName(prefix string, tparam *types.TypeParam) string {
987 assert(prefix != "")
988 name := tparam.Obj().Name()
989 if name == "_" {
990 name = blankMarker + strconv.Itoa(tparam.Index())
991 }
992 return prefix + "." + name
993 }
994
995
996
997
998 func tparamName(exportName string) string {
999
1000 ix := strings.LastIndex(exportName, ".")
1001 if ix < 0 {
1002 errorf("malformed type parameter export name %s: missing prefix", exportName)
1003 }
1004 name := exportName[ix+1:]
1005 if strings.HasPrefix(name, blankMarker) {
1006 return "_"
1007 }
1008 return name
1009 }
1010
1011 func (w *exportWriter) paramList(tup *types.Tuple) {
1012 n := tup.Len()
1013 w.uint64(uint64(n))
1014 for i := 0; i < n; i++ {
1015 w.param(tup.At(i))
1016 }
1017 }
1018
1019 func (w *exportWriter) param(obj types.Object) {
1020 w.pos(obj.Pos())
1021 w.localIdent(obj)
1022 w.typ(obj.Type(), obj.Pkg())
1023 }
1024
1025 func (w *exportWriter) value(typ types.Type, v constant.Value) {
1026 w.typ(typ, nil)
1027 if w.p.version >= iexportVersionGo1_18 {
1028 w.int64(int64(v.Kind()))
1029 }
1030
1031 if v.Kind() == constant.Unknown {
1032
1033
1034
1035
1036
1037
1038
1039 return
1040 }
1041
1042 switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType {
1043 case types.IsBoolean:
1044 w.bool(constant.BoolVal(v))
1045 case types.IsInteger:
1046 var i big.Int
1047 if i64, exact := constant.Int64Val(v); exact {
1048 i.SetInt64(i64)
1049 } else if ui64, exact := constant.Uint64Val(v); exact {
1050 i.SetUint64(ui64)
1051 } else {
1052 i.SetString(v.ExactString(), 10)
1053 }
1054 w.mpint(&i, typ)
1055 case types.IsFloat:
1056 f := constantToFloat(v)
1057 w.mpfloat(f, typ)
1058 case types.IsComplex:
1059 w.mpfloat(constantToFloat(constant.Real(v)), typ)
1060 w.mpfloat(constantToFloat(constant.Imag(v)), typ)
1061 case types.IsString:
1062 w.string(constant.StringVal(v))
1063 default:
1064 if b.Kind() == types.Invalid {
1065
1066 break
1067 }
1068 panic(internalErrorf("unexpected type %v (%v)", typ, typ.Underlying()))
1069 }
1070 }
1071
1072
1073
1074 func constantToFloat(x constant.Value) *big.Float {
1075 x = constant.ToFloat(x)
1076
1077
1078 const mpprec = 512
1079 var f big.Float
1080 f.SetPrec(mpprec)
1081 if v, exact := constant.Float64Val(x); exact {
1082
1083 f.SetFloat64(v)
1084 } else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int {
1085
1086 n := valueToRat(num)
1087 d := valueToRat(denom)
1088 f.SetRat(n.Quo(n, d))
1089 } else {
1090
1091
1092 _, ok := f.SetString(x.ExactString())
1093 assert(ok)
1094 }
1095 return &f
1096 }
1097
1098 func valueToRat(x constant.Value) *big.Rat {
1099
1100
1101 bytes := constant.Bytes(x)
1102 for i := 0; i < len(bytes)/2; i++ {
1103 bytes[i], bytes[len(bytes)-1-i] = bytes[len(bytes)-1-i], bytes[i]
1104 }
1105 return new(big.Rat).SetInt(new(big.Int).SetBytes(bytes))
1106 }
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128 func (w *exportWriter) mpint(x *big.Int, typ types.Type) {
1129 basic, ok := typ.Underlying().(*types.Basic)
1130 if !ok {
1131 panic(internalErrorf("unexpected type %v (%T)", typ.Underlying(), typ.Underlying()))
1132 }
1133
1134 signed, maxBytes := intSize(basic)
1135
1136 negative := x.Sign() < 0
1137 if !signed && negative {
1138 panic(internalErrorf("negative unsigned integer; type %v, value %v", typ, x))
1139 }
1140
1141 b := x.Bytes()
1142 if len(b) > 0 && b[0] == 0 {
1143 panic(internalErrorf("leading zeros"))
1144 }
1145 if uint(len(b)) > maxBytes {
1146 panic(internalErrorf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x))
1147 }
1148
1149 maxSmall := 256 - maxBytes
1150 if signed {
1151 maxSmall = 256 - 2*maxBytes
1152 }
1153 if maxBytes == 1 {
1154 maxSmall = 256
1155 }
1156
1157
1158 if len(b) <= 1 {
1159 var ux uint
1160 if len(b) == 1 {
1161 ux = uint(b[0])
1162 }
1163 if signed {
1164 ux <<= 1
1165 if negative {
1166 ux--
1167 }
1168 }
1169 if ux < maxSmall {
1170 w.data.WriteByte(byte(ux))
1171 return
1172 }
1173 }
1174
1175 n := 256 - uint(len(b))
1176 if signed {
1177 n = 256 - 2*uint(len(b))
1178 if negative {
1179 n |= 1
1180 }
1181 }
1182 if n < maxSmall || n >= 256 {
1183 panic(internalErrorf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n))
1184 }
1185
1186 w.data.WriteByte(byte(n))
1187 w.data.Write(b)
1188 }
1189
1190
1191
1192
1193
1194
1195
1196 func (w *exportWriter) mpfloat(f *big.Float, typ types.Type) {
1197 if f.IsInf() {
1198 panic("infinite constant")
1199 }
1200
1201
1202 var mant big.Float
1203 exp := int64(f.MantExp(&mant))
1204
1205
1206 prec := mant.MinPrec()
1207 mant.SetMantExp(&mant, int(prec))
1208 exp -= int64(prec)
1209
1210 manti, acc := mant.Int(nil)
1211 if acc != big.Exact {
1212 panic(internalErrorf("mantissa scaling failed for %f (%s)", f, acc))
1213 }
1214 w.mpint(manti, typ)
1215 if manti.Sign() != 0 {
1216 w.int64(exp)
1217 }
1218 }
1219
1220 func (w *exportWriter) bool(b bool) bool {
1221 var x uint64
1222 if b {
1223 x = 1
1224 }
1225 w.uint64(x)
1226 return b
1227 }
1228
1229 func (w *exportWriter) int64(x int64) { w.data.int64(x) }
1230 func (w *exportWriter) uint64(x uint64) { w.data.uint64(x) }
1231 func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) }
1232
1233 func (w *exportWriter) localIdent(obj types.Object) {
1234
1235 if obj == nil {
1236 w.string("")
1237 return
1238 }
1239
1240 name := obj.Name()
1241 if name == "_" {
1242 w.string("_")
1243 return
1244 }
1245
1246 w.string(name)
1247 }
1248
1249 type intWriter struct {
1250 bytes.Buffer
1251 }
1252
1253 func (w *intWriter) int64(x int64) {
1254 var buf [binary.MaxVarintLen64]byte
1255 n := binary.PutVarint(buf[:], x)
1256 w.Write(buf[:n])
1257 }
1258
1259 func (w *intWriter) uint64(x uint64) {
1260 var buf [binary.MaxVarintLen64]byte
1261 n := binary.PutUvarint(buf[:], x)
1262 w.Write(buf[:n])
1263 }
1264
1265 func assert(cond bool) {
1266 if !cond {
1267 panic("internal error: assertion failed")
1268 }
1269 }
1270
1271
1272
1273
1274
1275 type objQueue struct {
1276 ring []types.Object
1277 head, tail int
1278 }
1279
1280
1281 func (q *objQueue) empty() bool {
1282 return q.head == q.tail
1283 }
1284
1285
1286 func (q *objQueue) pushTail(obj types.Object) {
1287 if len(q.ring) == 0 {
1288 q.ring = make([]types.Object, 16)
1289 } else if q.head+len(q.ring) == q.tail {
1290
1291 nring := make([]types.Object, len(q.ring)*2)
1292
1293 part := q.ring[q.head%len(q.ring):]
1294 if q.tail-q.head <= len(part) {
1295 part = part[:q.tail-q.head]
1296 copy(nring, part)
1297 } else {
1298 pos := copy(nring, part)
1299 copy(nring[pos:], q.ring[:q.tail%len(q.ring)])
1300 }
1301 q.ring, q.head, q.tail = nring, 0, q.tail-q.head
1302 }
1303
1304 q.ring[q.tail%len(q.ring)] = obj
1305 q.tail++
1306 }
1307
1308
1309 func (q *objQueue) popHead() types.Object {
1310 if q.empty() {
1311 panic("dequeue empty")
1312 }
1313 obj := q.ring[q.head%len(q.ring)]
1314 q.head++
1315 return obj
1316 }
1317
1318
1319 type internalError string
1320
1321 func (e internalError) Error() string { return "gcimporter: " + string(e) }
1322
1323
1324
1325
1326
1327
1328
1329
1330 func internalErrorf(format string, args ...interface{}) error {
1331 return internalError(fmt.Sprintf(format, args...))
1332 }
1333
View as plain text