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