1
2
3
4
5 package reflectdata
6
7 import (
8 "encoding/binary"
9 "fmt"
10 "internal/abi"
11 "internal/buildcfg"
12 "slices"
13 "sort"
14 "strings"
15 "sync"
16
17 "cmd/compile/internal/base"
18 "cmd/compile/internal/bitvec"
19 "cmd/compile/internal/compare"
20 "cmd/compile/internal/ir"
21 "cmd/compile/internal/objw"
22 "cmd/compile/internal/rttype"
23 "cmd/compile/internal/staticdata"
24 "cmd/compile/internal/typebits"
25 "cmd/compile/internal/typecheck"
26 "cmd/compile/internal/types"
27 "cmd/internal/obj"
28 "cmd/internal/objabi"
29 "cmd/internal/src"
30 )
31
32 type ptabEntry struct {
33 s *types.Sym
34 t *types.Type
35 }
36
37
38 var (
39
40 signatmu sync.Mutex
41
42 signatset = make(map[*types.Type]struct{})
43
44 signatslice []typeAndStr
45
46 gcsymmu sync.Mutex
47 gcsymset = make(map[*types.Type]struct{})
48 )
49
50 type typeSig struct {
51 name *types.Sym
52 isym *obj.LSym
53 tsym *obj.LSym
54 type_ *types.Type
55 mtype *types.Type
56 }
57
58 func commonSize() int { return int(rttype.Type.Size()) }
59
60 func uncommonSize(t *types.Type) int {
61 if t.Sym() == nil && len(methods(t)) == 0 {
62 return 0
63 }
64 return int(rttype.UncommonType.Size())
65 }
66
67 func makefield(name string, t *types.Type) *types.Field {
68 sym := (*types.Pkg)(nil).Lookup(name)
69 return types.NewField(src.NoXPos, sym, t)
70 }
71
72
73
74 func methods(t *types.Type) []*typeSig {
75 if t.HasShape() {
76
77 return nil
78 }
79
80 mt := types.ReceiverBaseType(t)
81
82 if mt == nil {
83 return nil
84 }
85 typecheck.CalcMethods(mt)
86
87
88
89 var ms []*typeSig
90 for _, f := range mt.AllMethods() {
91 if f.Sym == nil {
92 base.Fatalf("method with no sym on %v", mt)
93 }
94 if !f.IsMethod() {
95 base.Fatalf("non-method on %v method %v %v", mt, f.Sym, f)
96 }
97 if f.Type.Recv() == nil {
98 base.Fatalf("receiver with no type on %v method %v %v", mt, f.Sym, f)
99 }
100 if f.Nointerface() && !t.IsFullyInstantiated() {
101
102
103
104
105 continue
106 }
107
108
109
110
111
112 if !types.IsMethodApplicable(t, f) {
113 continue
114 }
115
116 sig := &typeSig{
117 name: f.Sym,
118 isym: methodWrapper(t, f, true),
119 tsym: methodWrapper(t, f, false),
120 type_: typecheck.NewMethodType(f.Type, t),
121 mtype: typecheck.NewMethodType(f.Type, nil),
122 }
123 if f.Nointerface() {
124
125
126 continue
127 }
128 ms = append(ms, sig)
129 }
130
131 return ms
132 }
133
134
135 func imethods(t *types.Type) []*typeSig {
136 var methods []*typeSig
137 for _, f := range t.AllMethods() {
138 if f.Type.Kind() != types.TFUNC || f.Sym == nil {
139 continue
140 }
141 if f.Sym.IsBlank() {
142 base.Fatalf("unexpected blank symbol in interface method set")
143 }
144 if n := len(methods); n > 0 {
145 last := methods[n-1]
146 if types.CompareSyms(last.name, f.Sym) >= 0 {
147 base.Fatalf("sigcmp vs sortinter %v %v", last.name, f.Sym)
148 }
149 }
150
151 sig := &typeSig{
152 name: f.Sym,
153 mtype: f.Type,
154 type_: typecheck.NewMethodType(f.Type, nil),
155 }
156 methods = append(methods, sig)
157
158
159
160
161
162 methodWrapper(t, f, false)
163 }
164
165 return methods
166 }
167
168 func dimportpath(p *types.Pkg) {
169 if p.Pathsym != nil {
170 return
171 }
172
173 if p == types.LocalPkg && base.Ctxt.Pkgpath == "" {
174 panic("missing pkgpath")
175 }
176
177
178
179
180 if base.Ctxt.Pkgpath == "runtime" && p == ir.Pkgs.Runtime {
181 return
182 }
183
184 s := base.Ctxt.Lookup("type:.importpath." + p.Prefix + ".")
185 ot := dnameData(s, 0, p.Path, "", nil, false, false)
186 objw.Global(s, int32(ot), obj.DUPOK|obj.RODATA)
187 s.Set(obj.AttrContentAddressable, true)
188 p.Pathsym = s
189 }
190
191 func dgopkgpath(c rttype.Cursor, pkg *types.Pkg) {
192 c = c.Field("Bytes")
193 if pkg == nil {
194 c.WritePtr(nil)
195 return
196 }
197
198 dimportpath(pkg)
199 c.WritePtr(pkg.Pathsym)
200 }
201
202
203 func dgopkgpathOff(c rttype.Cursor, pkg *types.Pkg) {
204 if pkg == nil {
205 c.WriteInt32(0)
206 return
207 }
208
209 dimportpath(pkg)
210 c.WriteSymPtrOff(pkg.Pathsym, false)
211 }
212
213
214 func dnameField(c rttype.Cursor, spkg *types.Pkg, ft *types.Field) {
215 if !types.IsExported(ft.Sym.Name) && ft.Sym.Pkg != spkg {
216 base.Fatalf("package mismatch for %v", ft.Sym)
217 }
218 nsym := dname(ft.Sym.Name, ft.Note, nil, types.IsExported(ft.Sym.Name), ft.Embedded != 0)
219 c.Field("Bytes").WritePtr(nsym)
220 }
221
222
223 func dnameData(s *obj.LSym, ot int, name, tag string, pkg *types.Pkg, exported, embedded bool) int {
224 if len(name) >= 1<<29 {
225 base.Fatalf("name too long: %d %s...", len(name), name[:1024])
226 }
227 if len(tag) >= 1<<29 {
228 base.Fatalf("tag too long: %d %s...", len(tag), tag[:1024])
229 }
230 var nameLen [binary.MaxVarintLen64]byte
231 nameLenLen := binary.PutUvarint(nameLen[:], uint64(len(name)))
232 var tagLen [binary.MaxVarintLen64]byte
233 tagLenLen := binary.PutUvarint(tagLen[:], uint64(len(tag)))
234
235
236 var bits byte
237 l := 1 + nameLenLen + len(name)
238 if exported {
239 bits |= 1 << 0
240 }
241 if len(tag) > 0 {
242 l += tagLenLen + len(tag)
243 bits |= 1 << 1
244 }
245 if pkg != nil {
246 bits |= 1 << 2
247 }
248 if embedded {
249 bits |= 1 << 3
250 }
251 b := make([]byte, l)
252 b[0] = bits
253 copy(b[1:], nameLen[:nameLenLen])
254 copy(b[1+nameLenLen:], name)
255 if len(tag) > 0 {
256 tb := b[1+nameLenLen+len(name):]
257 copy(tb, tagLen[:tagLenLen])
258 copy(tb[tagLenLen:], tag)
259 }
260
261 ot = int(s.WriteBytes(base.Ctxt, int64(ot), b))
262
263 if pkg != nil {
264 c := rttype.NewCursor(s, int64(ot), types.Types[types.TUINT32])
265 dgopkgpathOff(c, pkg)
266 ot += 4
267 }
268
269 return ot
270 }
271
272 var dnameCount int
273
274
275 func dname(name, tag string, pkg *types.Pkg, exported, embedded bool) *obj.LSym {
276
277
278
279
280 sname := "type:.namedata."
281 if pkg == nil {
282
283 if name == "" {
284 if exported {
285 sname += "-noname-exported." + tag
286 } else {
287 sname += "-noname-unexported." + tag
288 }
289 } else {
290 if exported {
291 sname += name + "." + tag
292 } else {
293 sname += name + "-" + tag
294 }
295 }
296 } else {
297
298
299 sname = fmt.Sprintf("%s%s.%d", sname, types.LocalPkg.Prefix, dnameCount)
300 dnameCount++
301 }
302 if embedded {
303 sname += ".embedded"
304 }
305 s := base.Ctxt.Lookup(sname)
306 if len(s.P) > 0 {
307 return s
308 }
309 ot := dnameData(s, 0, name, tag, pkg, exported, embedded)
310 objw.Global(s, int32(ot), obj.DUPOK|obj.RODATA)
311 s.Set(obj.AttrContentAddressable, true)
312 return s
313 }
314
315
316
317
318 func dextratype(lsym *obj.LSym, off int64, t *types.Type, dataAdd int) {
319 m := methods(t)
320 if t.Sym() == nil && len(m) == 0 {
321 base.Fatalf("extra requested of type with no extra info %v", t)
322 }
323 noff := types.RoundUp(off, int64(types.PtrSize))
324 if noff != off {
325 base.Fatalf("unexpected alignment in dextratype for %v", t)
326 }
327
328 for _, a := range m {
329 writeType(a.type_)
330 }
331
332 c := rttype.NewCursor(lsym, off, rttype.UncommonType)
333 dgopkgpathOff(c.Field("PkgPath"), typePkg(t))
334
335 dataAdd += uncommonSize(t)
336 mcount := len(m)
337 if mcount != int(uint16(mcount)) {
338 base.Fatalf("too many methods on %v: %d", t, mcount)
339 }
340 xcount := sort.Search(mcount, func(i int) bool { return !types.IsExported(m[i].name.Name) })
341 if dataAdd != int(uint32(dataAdd)) {
342 base.Fatalf("methods are too far away on %v: %d", t, dataAdd)
343 }
344
345 c.Field("Mcount").WriteUint16(uint16(mcount))
346 c.Field("Xcount").WriteUint16(uint16(xcount))
347 c.Field("Moff").WriteUint32(uint32(dataAdd))
348
349
350
351 array := rttype.NewArrayCursor(lsym, off+int64(dataAdd), rttype.Method, mcount)
352 for i, a := range m {
353 exported := types.IsExported(a.name.Name)
354 var pkg *types.Pkg
355 if !exported && a.name.Pkg != typePkg(t) {
356 pkg = a.name.Pkg
357 }
358 nsym := dname(a.name.Name, "", pkg, exported, false)
359
360 e := array.Elem(i)
361 e.Field("Name").WriteSymPtrOff(nsym, false)
362 dmethodptrOff(e.Field("Mtyp"), writeType(a.mtype))
363 dmethodptrOff(e.Field("Ifn"), a.isym)
364 dmethodptrOff(e.Field("Tfn"), a.tsym)
365 }
366 }
367
368 func typePkg(t *types.Type) *types.Pkg {
369 tsym := t.Sym()
370 if tsym == nil {
371 switch t.Kind() {
372 case types.TARRAY, types.TSLICE, types.TPTR, types.TCHAN:
373 if t.Elem() != nil {
374 tsym = t.Elem().Sym()
375 }
376 }
377 }
378 if tsym != nil && tsym.Pkg != types.BuiltinPkg {
379 return tsym.Pkg
380 }
381 return nil
382 }
383
384 func dmethodptrOff(c rttype.Cursor, x *obj.LSym) {
385 c.WriteInt32(0)
386 c.Reloc(obj.Reloc{Type: objabi.R_METHODOFF, Sym: x})
387 }
388
389 var kinds = []abi.Kind{
390 types.TINT: abi.Int,
391 types.TUINT: abi.Uint,
392 types.TINT8: abi.Int8,
393 types.TUINT8: abi.Uint8,
394 types.TINT16: abi.Int16,
395 types.TUINT16: abi.Uint16,
396 types.TINT32: abi.Int32,
397 types.TUINT32: abi.Uint32,
398 types.TINT64: abi.Int64,
399 types.TUINT64: abi.Uint64,
400 types.TUINTPTR: abi.Uintptr,
401 types.TFLOAT32: abi.Float32,
402 types.TFLOAT64: abi.Float64,
403 types.TBOOL: abi.Bool,
404 types.TSTRING: abi.String,
405 types.TPTR: abi.Pointer,
406 types.TSTRUCT: abi.Struct,
407 types.TINTER: abi.Interface,
408 types.TCHAN: abi.Chan,
409 types.TMAP: abi.Map,
410 types.TARRAY: abi.Array,
411 types.TSLICE: abi.Slice,
412 types.TFUNC: abi.Func,
413 types.TCOMPLEX64: abi.Complex64,
414 types.TCOMPLEX128: abi.Complex128,
415 types.TUNSAFEPTR: abi.UnsafePointer,
416 }
417
418 var (
419 memhashvarlen *obj.LSym
420 memequalvarlen *obj.LSym
421 )
422
423
424 func dcommontype(c rttype.Cursor, t *types.Type) {
425 types.CalcSize(t)
426 eqfunc := geneq(t)
427
428 sptrWeak := true
429 var sptr *obj.LSym
430 if !t.IsPtr() || t.IsPtrElem() {
431 tptr := types.NewPtr(t)
432 if t.Sym() != nil || methods(tptr) != nil {
433 sptrWeak = false
434 }
435 sptr = writeType(tptr)
436 }
437
438 gcsym, onDemand, ptrdata := dgcsym(t, true, true)
439 if !onDemand {
440 delete(gcsymset, t)
441 }
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458 c.Field("Size_").WriteUintptr(uint64(t.Size()))
459 c.Field("PtrBytes").WriteUintptr(uint64(ptrdata))
460 c.Field("Hash").WriteUint32(types.TypeHash(t))
461
462 var tflag abi.TFlag
463 if uncommonSize(t) != 0 {
464 tflag |= abi.TFlagUncommon
465 }
466 if t.Sym() != nil && t.Sym().Name != "" {
467 tflag |= abi.TFlagNamed
468 }
469 if compare.IsRegularMemory(t) {
470 tflag |= abi.TFlagRegularMemory
471 }
472 if onDemand {
473 tflag |= abi.TFlagGCMaskOnDemand
474 }
475
476 exported := false
477 p := t.NameString()
478
479
480
481
482
483 if !strings.HasPrefix(p, "*") {
484 p = "*" + p
485 tflag |= abi.TFlagExtraStar
486 if t.Sym() != nil {
487 exported = types.IsExported(t.Sym().Name)
488 }
489 } else {
490 if t.Elem() != nil && t.Elem().Sym() != nil {
491 exported = types.IsExported(t.Elem().Sym().Name)
492 }
493 }
494
495 if tflag != abi.TFlag(uint8(tflag)) {
496
497 panic("Unexpected change in size of abi.TFlag")
498 }
499 c.Field("TFlag").WriteUint8(uint8(tflag))
500
501
502 i := int(uint8(t.Alignment()))
503
504 if i == 0 {
505 i = 1
506 }
507 if i&(i-1) != 0 {
508 base.Fatalf("invalid alignment %d for %v", uint8(t.Alignment()), t)
509 }
510 c.Field("Align_").WriteUint8(uint8(t.Alignment()))
511 c.Field("FieldAlign_").WriteUint8(uint8(t.Alignment()))
512
513 kind := kinds[t.Kind()]
514 if types.IsDirectIface(t) {
515 kind |= abi.KindDirectIface
516 }
517 c.Field("Kind_").WriteUint8(uint8(kind))
518
519 c.Field("Equal").WritePtr(eqfunc)
520 c.Field("GCData").WritePtr(gcsym)
521
522 nsym := dname(p, "", nil, exported, false)
523 c.Field("Str").WriteSymPtrOff(nsym, false)
524 c.Field("PtrToThis").WriteSymPtrOff(sptr, sptrWeak)
525 }
526
527
528
529 func TrackSym(t *types.Type, f *types.Field) *obj.LSym {
530 return base.PkgLinksym("go:track", t.LinkString()+"."+f.Sym.Name, obj.ABI0)
531 }
532
533 func TypeSymPrefix(prefix string, t *types.Type) *types.Sym {
534 p := prefix + "." + t.LinkString()
535 s := types.TypeSymLookup(p)
536
537
538
539 signatmu.Lock()
540 NeedRuntimeType(t)
541 signatmu.Unlock()
542
543
544
545 return s
546 }
547
548 func TypeSym(t *types.Type) *types.Sym {
549 if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() {
550 base.Fatalf("TypeSym %v", t)
551 }
552 if t.Kind() == types.TFUNC && t.Recv() != nil {
553 base.Fatalf("misuse of method type: %v", t)
554 }
555 s := types.TypeSym(t)
556 signatmu.Lock()
557 NeedRuntimeType(t)
558 signatmu.Unlock()
559 return s
560 }
561
562 func TypeLinksymPrefix(prefix string, t *types.Type) *obj.LSym {
563 return TypeSymPrefix(prefix, t).Linksym()
564 }
565
566 func TypeLinksymLookup(name string) *obj.LSym {
567 return types.TypeSymLookup(name).Linksym()
568 }
569
570 func TypeLinksym(t *types.Type) *obj.LSym {
571 lsym := TypeSym(t).Linksym()
572 signatmu.Lock()
573 if lsym.Extra == nil {
574 ti := lsym.NewTypeInfo()
575 ti.Type = t
576 }
577 signatmu.Unlock()
578 return lsym
579 }
580
581
582
583 func TypePtrAt(pos src.XPos, t *types.Type) *ir.AddrExpr {
584 return typecheck.LinksymAddr(pos, TypeLinksym(t), types.Types[types.TUINT8])
585 }
586
587
588
589
590
591
592
593
594 func ITabLsym(typ, iface *types.Type) *obj.LSym {
595 s, existed := ir.Pkgs.Itab.LookupOK(typ.LinkString() + "," + iface.LinkString())
596 lsym := s.Linksym()
597
598 if !existed {
599 writeITab(lsym, typ, iface, true)
600 }
601 return lsym
602 }
603
604
605
606
607 func ITabAddrAt(pos src.XPos, typ, iface *types.Type) *ir.AddrExpr {
608 s, existed := ir.Pkgs.Itab.LookupOK(typ.LinkString() + "," + iface.LinkString())
609 lsym := s.Linksym()
610
611 if !existed {
612 writeITab(lsym, typ, iface, false)
613 }
614
615 return typecheck.LinksymAddr(pos, lsym, types.Types[types.TUINT8])
616 }
617
618
619
620 func needkeyupdate(t *types.Type) bool {
621 switch t.Kind() {
622 case types.TBOOL, types.TINT, types.TUINT, types.TINT8, types.TUINT8, types.TINT16, types.TUINT16, types.TINT32, types.TUINT32,
623 types.TINT64, types.TUINT64, types.TUINTPTR, types.TPTR, types.TUNSAFEPTR, types.TCHAN:
624 return false
625
626 case types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128,
627 types.TINTER,
628 types.TSTRING:
629 return true
630
631 case types.TARRAY:
632 return needkeyupdate(t.Elem())
633
634 case types.TSTRUCT:
635 for _, t1 := range t.Fields() {
636 if needkeyupdate(t1.Type) {
637 return true
638 }
639 }
640 return false
641
642 default:
643 base.Fatalf("bad type for map key: %v", t)
644 return true
645 }
646 }
647
648
649 func hashMightPanic(t *types.Type) bool {
650 switch t.Kind() {
651 case types.TINTER:
652 return true
653
654 case types.TARRAY:
655 return hashMightPanic(t.Elem())
656
657 case types.TSTRUCT:
658 for _, t1 := range t.Fields() {
659 if hashMightPanic(t1.Type) {
660 return true
661 }
662 }
663 return false
664
665 default:
666 return false
667 }
668 }
669
670
671
672
673 func formalType(t *types.Type) *types.Type {
674 switch t {
675 case types.AnyType, types.ByteType, types.RuneType:
676 return types.Types[t.Kind()]
677 }
678 return t
679 }
680
681 func writeType(t *types.Type) *obj.LSym {
682 t = formalType(t)
683 if t.IsUntyped() {
684 base.Fatalf("writeType %v", t)
685 }
686
687 s := types.TypeSym(t)
688 lsym := s.Linksym()
689
690
691
692
693 tbase := t
694 if t.IsPtr() && t.Sym() == nil && t.Elem().Sym() != nil {
695 tbase = t.Elem()
696 }
697 if tbase.Kind() == types.TFORW {
698 base.Fatalf("unresolved defined type: %v", tbase)
699 }
700
701
702
703
704
705 if sym := tbase.Sym(); sym != nil && sym.Pkg == ir.Pkgs.Runtime {
706 return lsym
707 }
708
709 if s.Siggen() {
710 return lsym
711 }
712 s.SetSiggen(true)
713
714 if !NeedEmit(tbase) {
715 if i := typecheck.BaseTypeIndex(t); i >= 0 {
716 lsym.Pkg = tbase.Sym().Pkg.Prefix
717 lsym.SymIdx = int32(i)
718 lsym.Set(obj.AttrIndexed, true)
719 }
720
721
722
723
724
725 return lsym
726 }
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750 extra := t.Sym() != nil || len(methods(t)) != 0
751
752
753
754 var rt *types.Type
755 dataAdd := 0
756 switch t.Kind() {
757 default:
758 rt = rttype.Type
759 case types.TARRAY:
760 rt = rttype.ArrayType
761 case types.TSLICE:
762 rt = rttype.SliceType
763 case types.TCHAN:
764 rt = rttype.ChanType
765 case types.TFUNC:
766 rt = rttype.FuncType
767 dataAdd = (t.NumRecvs() + t.NumParams() + t.NumResults()) * types.PtrSize
768 case types.TINTER:
769 rt = rttype.InterfaceType
770 dataAdd = len(imethods(t)) * int(rttype.IMethod.Size())
771 case types.TMAP:
772 if buildcfg.Experiment.SwissMap {
773 rt = rttype.SwissMapType
774 } else {
775 rt = rttype.OldMapType
776 }
777 case types.TPTR:
778 rt = rttype.PtrType
779
780 case types.TSTRUCT:
781 rt = rttype.StructType
782 dataAdd = t.NumFields() * int(rttype.StructField.Size())
783 }
784
785
786 B := rt.Size()
787 C := B
788 if extra {
789 C = B + rttype.UncommonType.Size()
790 }
791 D := C + int64(dataAdd)
792 E := D + int64(len(methods(t)))*rttype.Method.Size()
793
794
795 c := rttype.NewCursor(lsym, 0, rt)
796 if rt == rttype.Type {
797 dcommontype(c, t)
798 } else {
799 dcommontype(c.Field("Type"), t)
800 }
801
802
803
804 switch t.Kind() {
805 case types.TARRAY:
806
807 s1 := writeType(t.Elem())
808 t2 := types.NewSlice(t.Elem())
809 s2 := writeType(t2)
810 c.Field("Elem").WritePtr(s1)
811 c.Field("Slice").WritePtr(s2)
812 c.Field("Len").WriteUintptr(uint64(t.NumElem()))
813
814 case types.TSLICE:
815
816 s1 := writeType(t.Elem())
817 c.Field("Elem").WritePtr(s1)
818
819 case types.TCHAN:
820
821 s1 := writeType(t.Elem())
822 c.Field("Elem").WritePtr(s1)
823 c.Field("Dir").WriteInt(int64(t.ChanDir()))
824
825 case types.TFUNC:
826
827 for _, t1 := range t.RecvParamsResults() {
828 writeType(t1.Type)
829 }
830 inCount := t.NumRecvs() + t.NumParams()
831 outCount := t.NumResults()
832 if t.IsVariadic() {
833 outCount |= 1 << 15
834 }
835
836 c.Field("InCount").WriteUint16(uint16(inCount))
837 c.Field("OutCount").WriteUint16(uint16(outCount))
838
839
840 typs := t.RecvParamsResults()
841 array := rttype.NewArrayCursor(lsym, C, types.Types[types.TUNSAFEPTR], len(typs))
842 for i, t1 := range typs {
843 array.Elem(i).WritePtr(writeType(t1.Type))
844 }
845
846 case types.TINTER:
847
848 m := imethods(t)
849 n := len(m)
850 for _, a := range m {
851 writeType(a.type_)
852 }
853
854 var tpkg *types.Pkg
855 if t.Sym() != nil && t != types.Types[t.Kind()] && t != types.ErrorType {
856 tpkg = t.Sym().Pkg
857 }
858 dgopkgpath(c.Field("PkgPath"), tpkg)
859 c.Field("Methods").WriteSlice(lsym, C, int64(n), int64(n))
860
861 array := rttype.NewArrayCursor(lsym, C, rttype.IMethod, n)
862 for i, a := range m {
863 exported := types.IsExported(a.name.Name)
864 var pkg *types.Pkg
865 if !exported && a.name.Pkg != tpkg {
866 pkg = a.name.Pkg
867 }
868 nsym := dname(a.name.Name, "", pkg, exported, false)
869
870 e := array.Elem(i)
871 e.Field("Name").WriteSymPtrOff(nsym, false)
872 e.Field("Typ").WriteSymPtrOff(writeType(a.type_), false)
873 }
874
875 case types.TMAP:
876 if buildcfg.Experiment.SwissMap {
877 writeSwissMapType(t, lsym, c)
878 } else {
879 writeOldMapType(t, lsym, c)
880 }
881
882 case types.TPTR:
883
884 if t.Elem().Kind() == types.TANY {
885 base.Fatalf("bad pointer base type")
886 }
887
888 s1 := writeType(t.Elem())
889 c.Field("Elem").WritePtr(s1)
890
891 case types.TSTRUCT:
892
893 fields := t.Fields()
894 for _, t1 := range fields {
895 writeType(t1.Type)
896 }
897
898
899
900
901
902
903 var spkg *types.Pkg
904 for _, f := range fields {
905 if !types.IsExported(f.Sym.Name) {
906 spkg = f.Sym.Pkg
907 break
908 }
909 }
910
911 dgopkgpath(c.Field("PkgPath"), spkg)
912 c.Field("Fields").WriteSlice(lsym, C, int64(len(fields)), int64(len(fields)))
913
914 array := rttype.NewArrayCursor(lsym, C, rttype.StructField, len(fields))
915 for i, f := range fields {
916 e := array.Elem(i)
917 dnameField(e.Field("Name"), spkg, f)
918 e.Field("Typ").WritePtr(writeType(f.Type))
919 e.Field("Offset").WriteUintptr(uint64(f.Offset))
920 }
921 }
922
923
924 if extra {
925 dextratype(lsym, B, t, dataAdd)
926 }
927
928
929
930
931
932 dupok := 0
933 if tbase.Sym() == nil || tbase.IsFullyInstantiated() || tbase.HasShape() {
934 dupok = obj.DUPOK
935 }
936
937 objw.Global(lsym, int32(E), int16(dupok|obj.RODATA))
938
939
940
941
942
943
944 keep := base.Ctxt.Flag_dynlink
945 if !keep && t.Sym() == nil {
946
947
948
949
950
951 switch t.Kind() {
952 case types.TPTR, types.TARRAY, types.TCHAN, types.TFUNC, types.TMAP, types.TSLICE, types.TSTRUCT:
953 keep = true
954 }
955 }
956
957 if types.TypeHasNoAlg(t) {
958 keep = false
959 }
960 lsym.Set(obj.AttrMakeTypelink, keep)
961
962 return lsym
963 }
964
965
966
967 func InterfaceMethodOffset(ityp *types.Type, i int64) int64 {
968
969
970
971
972
973
974
975
976 return int64(commonSize()+4*types.PtrSize+uncommonSize(ityp)) + i*8
977 }
978
979
980 func NeedRuntimeType(t *types.Type) {
981 if _, ok := signatset[t]; !ok {
982 signatset[t] = struct{}{}
983 signatslice = append(signatslice, typeAndStr{t: t, short: types.TypeSymName(t), regular: t.String()})
984 }
985 }
986
987 func WriteRuntimeTypes() {
988
989
990 for len(signatslice) > 0 {
991 signats := signatslice
992
993 slices.SortFunc(signats, typesStrCmp)
994 for _, ts := range signats {
995 t := ts.t
996 writeType(t)
997 if t.Sym() != nil {
998 writeType(types.NewPtr(t))
999 }
1000 }
1001 signatslice = signatslice[len(signats):]
1002 }
1003 }
1004
1005 func WriteGCSymbols() {
1006
1007 gcsyms := make([]typeAndStr, 0, len(gcsymset))
1008 for t := range gcsymset {
1009 gcsyms = append(gcsyms, typeAndStr{t: t, short: types.TypeSymName(t), regular: t.String()})
1010 }
1011 slices.SortFunc(gcsyms, typesStrCmp)
1012 for _, ts := range gcsyms {
1013 dgcsym(ts.t, true, false)
1014 }
1015 }
1016
1017
1018
1019
1020 func writeITab(lsym *obj.LSym, typ, iface *types.Type, allowNonImplement bool) {
1021
1022
1023 oldpos, oldfn := base.Pos, ir.CurFunc
1024 defer func() { base.Pos, ir.CurFunc = oldpos, oldfn }()
1025
1026 if typ == nil || (typ.IsPtr() && typ.Elem() == nil) || typ.IsUntyped() || iface == nil || !iface.IsInterface() || iface.IsEmptyInterface() {
1027 base.Fatalf("writeITab(%v, %v)", typ, iface)
1028 }
1029
1030 sigs := iface.AllMethods()
1031 entries := make([]*obj.LSym, 0, len(sigs))
1032
1033
1034
1035 for _, m := range methods(typ) {
1036 if m.name == sigs[0].Sym {
1037 entries = append(entries, m.isym)
1038 if m.isym == nil {
1039 panic("NO ISYM")
1040 }
1041 sigs = sigs[1:]
1042 if len(sigs) == 0 {
1043 break
1044 }
1045 }
1046 }
1047 completeItab := len(sigs) == 0
1048 if !allowNonImplement && !completeItab {
1049 base.Fatalf("incomplete itab")
1050 }
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060 c := rttype.NewCursor(lsym, 0, rttype.ITab)
1061 c.Field("Inter").WritePtr(writeType(iface))
1062 c.Field("Type").WritePtr(writeType(typ))
1063 c.Field("Hash").WriteUint32(types.TypeHash(typ))
1064
1065 var delta int64
1066 c = c.Field("Fun")
1067 if !completeItab {
1068
1069 c.Elem(0).WriteUintptr(0)
1070 } else {
1071 var a rttype.ArrayCursor
1072 a, delta = c.ModifyArray(len(entries))
1073 for i, fn := range entries {
1074 a.Elem(i).WritePtrWeak(fn)
1075 }
1076 }
1077
1078 objw.Global(lsym, int32(rttype.ITab.Size()+delta), int16(obj.DUPOK|obj.RODATA))
1079 lsym.Set(obj.AttrContentAddressable, true)
1080 }
1081
1082 func WritePluginTable() {
1083 ptabs := typecheck.Target.PluginExports
1084 if len(ptabs) == 0 {
1085 return
1086 }
1087
1088 lsym := base.Ctxt.Lookup("go:plugin.tabs")
1089 ot := 0
1090 for _, p := range ptabs {
1091
1092
1093
1094
1095
1096
1097 nsym := dname(p.Sym().Name, "", nil, true, false)
1098 t := p.Type()
1099 if p.Class != ir.PFUNC {
1100 t = types.NewPtr(t)
1101 }
1102 tsym := writeType(t)
1103 ot = objw.SymPtrOff(lsym, ot, nsym)
1104 ot = objw.SymPtrOff(lsym, ot, tsym)
1105
1106
1107 tsym.Set(obj.AttrUsedInIface, true)
1108 }
1109 objw.Global(lsym, int32(ot), int16(obj.RODATA))
1110
1111 lsym = base.Ctxt.Lookup("go:plugin.exports")
1112 ot = 0
1113 for _, p := range ptabs {
1114 ot = objw.SymPtr(lsym, ot, p.Linksym(), 0)
1115 }
1116 objw.Global(lsym, int32(ot), int16(obj.RODATA))
1117 }
1118
1119
1120
1121 func writtenByWriteBasicTypes(typ *types.Type) bool {
1122 if typ.Sym() == nil && typ.Kind() == types.TFUNC {
1123
1124 if typ.NumRecvs() == 0 &&
1125 typ.NumParams() == 1 && typ.NumResults() == 1 &&
1126 typ.Param(0).Type == types.ErrorType &&
1127 typ.Result(0).Type == types.Types[types.TSTRING] {
1128 return true
1129 }
1130 }
1131
1132
1133
1134 if typ.Sym() == nil && typ.IsSlice() {
1135 typ = typ.Elem()
1136 }
1137
1138
1139 sym := typ.Sym()
1140 if sym != nil && (sym.Pkg == types.BuiltinPkg || sym.Pkg == types.UnsafePkg) {
1141 return true
1142 }
1143
1144 return (sym == nil && typ.IsEmptyInterface()) || typ == types.ErrorType
1145 }
1146
1147 func WriteBasicTypes() {
1148
1149
1150
1151
1152
1153
1154
1155 if base.Ctxt.Pkgpath != "runtime" {
1156 return
1157 }
1158
1159
1160 var list []*types.Type
1161 for i := types.Kind(1); i <= types.TBOOL; i++ {
1162 list = append(list, types.Types[i])
1163 }
1164 list = append(list,
1165 types.Types[types.TSTRING],
1166 types.Types[types.TUNSAFEPTR],
1167 types.AnyType,
1168 types.ErrorType)
1169 for _, t := range list {
1170 writeType(types.NewPtr(t))
1171 writeType(types.NewPtr(types.NewSlice(t)))
1172 }
1173
1174
1175
1176 writeType(types.NewPtr(types.NewSignature(nil, []*types.Field{
1177 types.NewField(base.Pos, nil, types.ErrorType),
1178 }, []*types.Field{
1179 types.NewField(base.Pos, nil, types.Types[types.TSTRING]),
1180 })))
1181 }
1182
1183 type typeAndStr struct {
1184 t *types.Type
1185 short string
1186 regular string
1187 }
1188
1189 func typesStrCmp(a, b typeAndStr) int {
1190
1191 if a.t.Sym() != nil && b.t.Sym() == nil {
1192 return -1
1193 }
1194 if a.t.Sym() == nil && b.t.Sym() != nil {
1195 return +1
1196 }
1197
1198 if r := strings.Compare(a.short, b.short); r != 0 {
1199 return r
1200 }
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210 if r := strings.Compare(a.regular, b.regular); r != 0 {
1211 return r
1212 }
1213
1214
1215
1216
1217 if a.t.Kind() == types.TINTER && len(a.t.AllMethods()) > 0 {
1218 if a.t.AllMethods()[0].Pos.Before(b.t.AllMethods()[0].Pos) {
1219 return -1
1220 }
1221 return +1
1222 }
1223 return 0
1224 }
1225
1226
1227
1228
1229
1230 func GCSym(t *types.Type) (lsym *obj.LSym, ptrdata int64) {
1231
1232 gcsymmu.Lock()
1233 if _, ok := gcsymset[t]; !ok {
1234 gcsymset[t] = struct{}{}
1235 }
1236 gcsymmu.Unlock()
1237
1238 lsym, _, ptrdata = dgcsym(t, false, false)
1239 return
1240 }
1241
1242
1243
1244
1245
1246 func dgcsym(t *types.Type, write, onDemandAllowed bool) (lsym *obj.LSym, onDemand bool, ptrdata int64) {
1247 ptrdata = types.PtrDataSize(t)
1248 if !onDemandAllowed || ptrdata/int64(types.PtrSize) <= abi.MaxPtrmaskBytes*8 {
1249 lsym = dgcptrmask(t, write)
1250 return
1251 }
1252
1253 onDemand = true
1254 lsym = dgcptrmaskOnDemand(t, write)
1255 return
1256 }
1257
1258
1259 func dgcptrmask(t *types.Type, write bool) *obj.LSym {
1260
1261 n := (types.PtrDataSize(t)/int64(types.PtrSize) + 7) / 8
1262
1263 n = (n + int64(types.PtrSize) - 1) &^ (int64(types.PtrSize) - 1)
1264 ptrmask := make([]byte, n)
1265 fillptrmask(t, ptrmask)
1266 p := fmt.Sprintf("runtime.gcbits.%x", ptrmask)
1267
1268 lsym := base.Ctxt.Lookup(p)
1269 if write && !lsym.OnList() {
1270 for i, x := range ptrmask {
1271 objw.Uint8(lsym, i, x)
1272 }
1273 objw.Global(lsym, int32(len(ptrmask)), obj.DUPOK|obj.RODATA|obj.LOCAL)
1274 lsym.Set(obj.AttrContentAddressable, true)
1275 }
1276 return lsym
1277 }
1278
1279
1280
1281
1282 func fillptrmask(t *types.Type, ptrmask []byte) {
1283 for i := range ptrmask {
1284 ptrmask[i] = 0
1285 }
1286 if !t.HasPointers() {
1287 return
1288 }
1289
1290 vec := bitvec.New(8 * int32(len(ptrmask)))
1291 typebits.Set(t, 0, vec)
1292
1293 nptr := types.PtrDataSize(t) / int64(types.PtrSize)
1294 for i := int64(0); i < nptr; i++ {
1295 if vec.Get(int32(i)) {
1296 ptrmask[i/8] |= 1 << (uint(i) % 8)
1297 }
1298 }
1299 }
1300
1301
1302
1303 func dgcptrmaskOnDemand(t *types.Type, write bool) *obj.LSym {
1304 lsym := TypeLinksymPrefix(".gcmask", t)
1305 if write && !lsym.OnList() {
1306
1307
1308 objw.Uintptr(lsym, 0, 0)
1309 objw.Global(lsym, int32(types.PtrSize), obj.DUPOK|obj.NOPTR|obj.LOCAL)
1310 }
1311 return lsym
1312 }
1313
1314
1315
1316 func ZeroAddr(size int64) ir.Node {
1317 if size >= 1<<31 {
1318 base.Fatalf("map elem too big %d", size)
1319 }
1320 if ZeroSize < size {
1321 ZeroSize = size
1322 }
1323 lsym := base.PkgLinksym("go:map", "zero", obj.ABI0)
1324 x := ir.NewLinksymExpr(base.Pos, lsym, types.Types[types.TUINT8])
1325 return typecheck.Expr(typecheck.NodAddr(x))
1326 }
1327
1328
1329
1330 func NeedEmit(typ *types.Type) bool {
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340 switch sym := typ.Sym(); {
1341 case writtenByWriteBasicTypes(typ):
1342 return base.Ctxt.Pkgpath == "runtime"
1343
1344 case sym == nil:
1345
1346
1347 return true
1348
1349 case sym.Pkg == types.LocalPkg:
1350
1351 return true
1352
1353 case typ.IsFullyInstantiated():
1354
1355
1356 return true
1357
1358 case typ.HasShape():
1359
1360
1361 return true
1362
1363 default:
1364
1365 return false
1366 }
1367 }
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405 func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSym {
1406 if forItab && !types.IsDirectIface(rcvr) {
1407 rcvr = rcvr.PtrTo()
1408 }
1409
1410 newnam := ir.MethodSym(rcvr, method.Sym)
1411 lsym := newnam.Linksym()
1412
1413
1414 return lsym
1415 }
1416
1417 var ZeroSize int64
1418
1419
1420
1421 func MarkTypeUsedInInterface(t *types.Type, from *obj.LSym) {
1422 if t.HasShape() {
1423
1424 base.Fatalf("shape types have no methods %+v", t)
1425 }
1426 MarkTypeSymUsedInInterface(TypeLinksym(t), from)
1427 }
1428 func MarkTypeSymUsedInInterface(tsym *obj.LSym, from *obj.LSym) {
1429
1430
1431 from.AddRel(base.Ctxt, obj.Reloc{Type: objabi.R_USEIFACE, Sym: tsym})
1432 }
1433
1434
1435
1436 func MarkUsedIfaceMethod(n *ir.CallExpr) {
1437
1438 if ir.CurFunc.LSym == nil {
1439 return
1440 }
1441 dot := n.Fun.(*ir.SelectorExpr)
1442 ityp := dot.X.Type()
1443 if ityp.HasShape() {
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463 ir.CurFunc.LSym.AddRel(base.Ctxt, obj.Reloc{
1464 Type: objabi.R_USENAMEDMETHOD,
1465 Sym: staticdata.StringSymNoCommon(dot.Sel.Name),
1466 })
1467 return
1468 }
1469
1470
1471 midx := dot.Offset() / int64(types.PtrSize)
1472 ir.CurFunc.LSym.AddRel(base.Ctxt, obj.Reloc{
1473 Type: objabi.R_USEIFACEMETHOD,
1474 Sym: TypeLinksym(ityp),
1475 Add: InterfaceMethodOffset(ityp, midx),
1476 })
1477 }
1478
1479 func deref(t *types.Type) *types.Type {
1480 if t.IsPtr() {
1481 return t.Elem()
1482 }
1483 return t
1484 }
1485
View as plain text