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/compare"
19 "cmd/compile/internal/ir"
20 "cmd/compile/internal/objw"
21 "cmd/compile/internal/rttype"
22 "cmd/compile/internal/staticdata"
23 "cmd/compile/internal/typebits"
24 "cmd/compile/internal/typecheck"
25 "cmd/compile/internal/types"
26 "cmd/internal/obj"
27 "cmd/internal/objabi"
28 "cmd/internal/src"
29 )
30
31 type ptabEntry struct {
32 s *types.Sym
33 t *types.Type
34 }
35
36
37 var (
38
39 signatmu sync.Mutex
40
41 signatset = make(map[*types.Type]struct{})
42
43 signatslice []typeAndStr
44
45 gcsymmu sync.Mutex
46 gcsymset = make(map[*types.Type]struct{})
47 )
48
49 type typeSig struct {
50 name *types.Sym
51 isym *obj.LSym
52 tsym *obj.LSym
53 type_ *types.Type
54 mtype *types.Type
55 }
56
57 func commonSize() int { return int(rttype.Type.Size()) }
58
59 func uncommonSize(t *types.Type) int {
60 if t.Sym() == nil && len(methods(t)) == 0 {
61 return 0
62 }
63 return int(rttype.UncommonType.Size())
64 }
65
66 func makefield(name string, t *types.Type) *types.Field {
67 sym := (*types.Pkg)(nil).Lookup(name)
68 return types.NewField(src.NoXPos, sym, t)
69 }
70
71
72
73 func methods(t *types.Type) []*typeSig {
74 if t.HasShape() {
75
76 return nil
77 }
78
79 mt := types.ReceiverBaseType(t)
80
81 if mt == nil {
82 return nil
83 }
84 typecheck.CalcMethods(mt)
85
86
87
88 var ms []*typeSig
89 for _, f := range mt.AllMethods() {
90 if f.Sym == nil {
91 base.Fatalf("method with no sym on %v", mt)
92 }
93 if !f.IsMethod() {
94 base.Fatalf("non-method on %v method %v %v", mt, f.Sym, f)
95 }
96 if f.Type.Recv() == nil {
97 base.Fatalf("receiver with no type on %v method %v %v", mt, f.Sym, f)
98 }
99 if f.Nointerface() && !t.IsFullyInstantiated() {
100
101
102
103
104 continue
105 }
106
107
108
109
110
111 if !types.IsMethodApplicable(t, f) {
112 continue
113 }
114
115 sig := &typeSig{
116 name: f.Sym,
117 isym: methodWrapper(t, f, true),
118 tsym: methodWrapper(t, f, false),
119 type_: typecheck.NewMethodType(f.Type, t),
120 mtype: typecheck.NewMethodType(f.Type, nil),
121 }
122 if f.Nointerface() {
123
124
125 continue
126 }
127 ms = append(ms, sig)
128 }
129
130 return ms
131 }
132
133
134 func imethods(t *types.Type) []*typeSig {
135 var methods []*typeSig
136 for _, f := range t.AllMethods() {
137 if f.Type.Kind() != types.TFUNC || f.Sym == nil {
138 continue
139 }
140 if f.Sym.IsBlank() {
141 base.Fatalf("unexpected blank symbol in interface method set")
142 }
143 if n := len(methods); n > 0 {
144 last := methods[n-1]
145 if types.CompareSyms(last.name, f.Sym) >= 0 {
146 base.Fatalf("sigcmp vs sortinter %v %v", last.name, f.Sym)
147 }
148 }
149
150 sig := &typeSig{
151 name: f.Sym,
152 mtype: f.Type,
153 type_: typecheck.NewMethodType(f.Type, nil),
154 }
155 methods = append(methods, sig)
156
157
158
159
160
161 methodWrapper(t, f, false)
162 }
163
164 return methods
165 }
166
167 func dimportpath(p *types.Pkg) {
168 if p.Pathsym != nil {
169 return
170 }
171
172 if p == types.LocalPkg && base.Ctxt.Pkgpath == "" {
173 panic("missing pkgpath")
174 }
175
176
177
178
179 if base.Ctxt.Pkgpath == "runtime" && p == ir.Pkgs.Runtime {
180 return
181 }
182
183 s := base.Ctxt.Lookup("type:.importpath." + p.Prefix + ".")
184 ot := dnameData(s, 0, p.Path, "", nil, false, false)
185 objw.Global(s, int32(ot), obj.DUPOK|obj.RODATA)
186 s.Set(obj.AttrContentAddressable, true)
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 return s
312 }
313
314
315
316
317 func dextratype(lsym *obj.LSym, off int64, t *types.Type, dataAdd int) {
318 m := methods(t)
319 if t.Sym() == nil && len(m) == 0 {
320 base.Fatalf("extra requested of type with no extra info %v", t)
321 }
322 noff := types.RoundUp(off, int64(types.PtrSize))
323 if noff != off {
324 base.Fatalf("unexpected alignment in dextratype for %v", t)
325 }
326
327 for _, a := range m {
328 writeType(a.type_)
329 }
330
331 c := rttype.NewCursor(lsym, off, rttype.UncommonType)
332 dgopkgpathOff(c.Field("PkgPath"), typePkg(t))
333
334 dataAdd += uncommonSize(t)
335 mcount := len(m)
336 if mcount != int(uint16(mcount)) {
337 base.Fatalf("too many methods on %v: %d", t, mcount)
338 }
339 xcount := sort.Search(mcount, func(i int) bool { return !types.IsExported(m[i].name.Name) })
340 if dataAdd != int(uint32(dataAdd)) {
341 base.Fatalf("methods are too far away on %v: %d", t, dataAdd)
342 }
343
344 c.Field("Mcount").WriteUint16(uint16(mcount))
345 c.Field("Xcount").WriteUint16(uint16(xcount))
346 c.Field("Moff").WriteUint32(uint32(dataAdd))
347
348
349
350 array := rttype.NewArrayCursor(lsym, off+int64(dataAdd), rttype.Method, mcount)
351 for i, a := range m {
352 exported := types.IsExported(a.name.Name)
353 var pkg *types.Pkg
354 if !exported && a.name.Pkg != typePkg(t) {
355 pkg = a.name.Pkg
356 }
357 nsym := dname(a.name.Name, "", pkg, exported, false)
358
359 e := array.Elem(i)
360 e.Field("Name").WriteSymPtrOff(nsym, false)
361 dmethodptrOff(e.Field("Mtyp"), writeType(a.mtype))
362 dmethodptrOff(e.Field("Ifn"), a.isym)
363 dmethodptrOff(e.Field("Tfn"), a.tsym)
364 }
365 }
366
367 func typePkg(t *types.Type) *types.Pkg {
368 tsym := t.Sym()
369 if tsym == nil {
370 switch t.Kind() {
371 case types.TARRAY, types.TSLICE, types.TPTR, types.TCHAN:
372 if t.Elem() != nil {
373 tsym = t.Elem().Sym()
374 }
375 }
376 }
377 if tsym != nil && tsym.Pkg != types.BuiltinPkg {
378 return tsym.Pkg
379 }
380 return nil
381 }
382
383 func dmethodptrOff(c rttype.Cursor, x *obj.LSym) {
384 c.WriteInt32(0)
385 c.Reloc(obj.Reloc{Type: objabi.R_METHODOFF, Sym: x})
386 }
387
388 var kinds = []abi.Kind{
389 types.TINT: abi.Int,
390 types.TUINT: abi.Uint,
391 types.TINT8: abi.Int8,
392 types.TUINT8: abi.Uint8,
393 types.TINT16: abi.Int16,
394 types.TUINT16: abi.Uint16,
395 types.TINT32: abi.Int32,
396 types.TUINT32: abi.Uint32,
397 types.TINT64: abi.Int64,
398 types.TUINT64: abi.Uint64,
399 types.TUINTPTR: abi.Uintptr,
400 types.TFLOAT32: abi.Float32,
401 types.TFLOAT64: abi.Float64,
402 types.TBOOL: abi.Bool,
403 types.TSTRING: abi.String,
404 types.TPTR: abi.Pointer,
405 types.TSTRUCT: abi.Struct,
406 types.TINTER: abi.Interface,
407 types.TCHAN: abi.Chan,
408 types.TMAP: abi.Map,
409 types.TARRAY: abi.Array,
410 types.TSLICE: abi.Slice,
411 types.TFUNC: abi.Func,
412 types.TCOMPLEX64: abi.Complex64,
413 types.TCOMPLEX128: abi.Complex128,
414 types.TUNSAFEPTR: abi.UnsafePointer,
415 }
416
417 func ABIKindOfType(t *types.Type) abi.Kind {
418 return kinds[t.Kind()]
419 }
420
421 var (
422 memhashvarlen *obj.LSym
423 memequalvarlen *obj.LSym
424 )
425
426
427 func dcommontype(c rttype.Cursor, t *types.Type) {
428 types.CalcSize(t)
429 eqfunc := geneq(t)
430
431 sptrWeak := true
432 var sptr *obj.LSym
433 if !t.IsPtr() || t.IsPtrElem() {
434 tptr := types.NewPtr(t)
435 if t.Sym() != nil || methods(tptr) != nil {
436 sptrWeak = false
437 }
438 sptr = writeType(tptr)
439 }
440
441 gcsym, onDemand, ptrdata := dgcsym(t, true, true)
442 if !onDemand {
443 delete(gcsymset, t)
444 }
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461 c.Field("Size_").WriteUintptr(uint64(t.Size()))
462 c.Field("PtrBytes").WriteUintptr(uint64(ptrdata))
463 c.Field("Hash").WriteUint32(types.TypeHash(t))
464
465 var tflag abi.TFlag
466 if uncommonSize(t) != 0 {
467 tflag |= abi.TFlagUncommon
468 }
469 if t.Sym() != nil && t.Sym().Name != "" {
470 tflag |= abi.TFlagNamed
471 }
472 if compare.IsRegularMemory(t) {
473 tflag |= abi.TFlagRegularMemory
474 }
475 if onDemand {
476 tflag |= abi.TFlagGCMaskOnDemand
477 }
478
479 exported := false
480 p := t.NameString()
481
482
483
484
485
486 if !strings.HasPrefix(p, "*") {
487 p = "*" + p
488 tflag |= abi.TFlagExtraStar
489 if t.Sym() != nil {
490 exported = types.IsExported(t.Sym().Name)
491 }
492 } else {
493 if t.Elem() != nil && t.Elem().Sym() != nil {
494 exported = types.IsExported(t.Elem().Sym().Name)
495 }
496 }
497 if types.IsDirectIface(t) {
498 tflag |= abi.TFlagDirectIface
499 }
500
501 if tflag != abi.TFlag(uint8(tflag)) {
502
503 panic("Unexpected change in size of abi.TFlag")
504 }
505 c.Field("TFlag").WriteUint8(uint8(tflag))
506
507
508 i := int(uint8(t.Alignment()))
509
510 if i == 0 {
511 i = 1
512 }
513 if i&(i-1) != 0 {
514 base.Fatalf("invalid alignment %d for %v", uint8(t.Alignment()), t)
515 }
516 c.Field("Align_").WriteUint8(uint8(t.Alignment()))
517 c.Field("FieldAlign_").WriteUint8(uint8(t.Alignment()))
518
519 c.Field("Kind_").WriteUint8(uint8(ABIKindOfType(t)))
520
521 c.Field("Equal").WritePtr(eqfunc)
522 c.Field("GCData").WritePtr(gcsym)
523
524 nsym := dname(p, "", nil, exported, false)
525 c.Field("Str").WriteSymPtrOff(nsym, false)
526 c.Field("PtrToThis").WriteSymPtrOff(sptr, sptrWeak)
527 }
528
529
530
531 func TrackSym(t *types.Type, f *types.Field) *obj.LSym {
532 return base.PkgLinksym("go:track", t.LinkString()+"."+f.Sym.Name, obj.ABI0)
533 }
534
535 func TypeSymPrefix(prefix string, t *types.Type) *types.Sym {
536 p := prefix + "." + t.LinkString()
537 s := types.TypeSymLookup(p)
538
539
540
541 signatmu.Lock()
542 NeedRuntimeType(t)
543 signatmu.Unlock()
544
545
546
547 return s
548 }
549
550 func TypeSym(t *types.Type) *types.Sym {
551 if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() {
552 base.Fatalf("TypeSym %v", t)
553 }
554 if t.Kind() == types.TFUNC && t.Recv() != nil {
555 base.Fatalf("misuse of method type: %v", t)
556 }
557 s := types.TypeSym(t)
558 signatmu.Lock()
559 NeedRuntimeType(t)
560 signatmu.Unlock()
561 return s
562 }
563
564 func TypeLinksymPrefix(prefix string, t *types.Type) *obj.LSym {
565 return TypeSymPrefix(prefix, t).Linksym()
566 }
567
568 func TypeLinksymLookup(name string) *obj.LSym {
569 return types.TypeSymLookup(name).Linksym()
570 }
571
572 func TypeLinksym(t *types.Type) *obj.LSym {
573 lsym := TypeSym(t).Linksym()
574 signatmu.Lock()
575 if lsym.Extra == nil {
576 ti := lsym.NewTypeInfo()
577 ti.Type = t
578 }
579 signatmu.Unlock()
580 return lsym
581 }
582
583
584
585 func TypePtrAt(pos src.XPos, t *types.Type) *ir.AddrExpr {
586 return typecheck.LinksymAddr(pos, TypeLinksym(t), types.Types[types.TUINT8])
587 }
588
589
590
591
592
593
594
595
596 func ITabLsym(typ, iface *types.Type) *obj.LSym {
597 return itabLsym(typ, iface, true)
598 }
599
600 func itabLsym(typ, iface *types.Type, allowNonImplement bool) *obj.LSym {
601 s, existed := ir.Pkgs.Itab.LookupOK(typ.LinkString() + "," + iface.LinkString())
602 lsym := s.Linksym()
603 signatmu.Lock()
604 if lsym.Extra == nil {
605 ii := lsym.NewItabInfo()
606 ii.Type = typ
607 }
608 signatmu.Unlock()
609
610 if !existed {
611 writeITab(lsym, typ, iface, allowNonImplement)
612 }
613 return lsym
614 }
615
616
617
618
619 func ITabAddrAt(pos src.XPos, typ, iface *types.Type) *ir.AddrExpr {
620 lsym := itabLsym(typ, iface, false)
621 return typecheck.LinksymAddr(pos, lsym, types.Types[types.TUINT8])
622 }
623
624
625
626 func needkeyupdate(t *types.Type) bool {
627 switch t.Kind() {
628 case types.TBOOL, types.TINT, types.TUINT, types.TINT8, types.TUINT8, types.TINT16, types.TUINT16, types.TINT32, types.TUINT32,
629 types.TINT64, types.TUINT64, types.TUINTPTR, types.TPTR, types.TUNSAFEPTR, types.TCHAN:
630 return false
631
632 case types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128,
633 types.TINTER,
634 types.TSTRING:
635 return true
636
637 case types.TARRAY:
638 return needkeyupdate(t.Elem())
639
640 case types.TSTRUCT:
641 for _, t1 := range t.Fields() {
642 if needkeyupdate(t1.Type) {
643 return true
644 }
645 }
646 return false
647
648 default:
649 base.Fatalf("bad type for map key: %v", t)
650 return true
651 }
652 }
653
654
655 func hashMightPanic(t *types.Type) bool {
656 switch t.Kind() {
657 case types.TINTER:
658 return true
659
660 case types.TARRAY:
661 return hashMightPanic(t.Elem())
662
663 case types.TSTRUCT:
664 for _, t1 := range t.Fields() {
665 if hashMightPanic(t1.Type) {
666 return true
667 }
668 }
669 return false
670
671 default:
672 return false
673 }
674 }
675
676
677
678
679 func formalType(t *types.Type) *types.Type {
680 switch t {
681 case types.AnyType, types.ByteType, types.RuneType:
682 return types.Types[t.Kind()]
683 }
684 return t
685 }
686
687 func writeType(t *types.Type) *obj.LSym {
688 t = formalType(t)
689 if t.IsUntyped() {
690 base.Fatalf("writeType %v", t)
691 }
692
693 s := types.TypeSym(t)
694 lsym := s.Linksym()
695
696
697
698
699 tbase := t
700 if t.IsPtr() && t.Sym() == nil && t.Elem().Sym() != nil {
701 tbase = t.Elem()
702 }
703 if tbase.Kind() == types.TFORW {
704 base.Fatalf("unresolved defined type: %v", tbase)
705 }
706
707
708
709
710
711 if sym := tbase.Sym(); sym != nil && sym.Pkg == ir.Pkgs.Runtime {
712 return lsym
713 }
714
715 if s.Siggen() {
716 return lsym
717 }
718 s.SetSiggen(true)
719
720 if !tbase.HasShape() {
721 TypeLinksym(t)
722 }
723
724 if !NeedEmit(tbase) {
725 if i := typecheck.BaseTypeIndex(t); i >= 0 {
726 lsym.Pkg = tbase.Sym().Pkg.Prefix
727 lsym.SymIdx = int32(i)
728 lsym.Set(obj.AttrIndexed, true)
729 }
730
731
732
733
734
735 return lsym
736 }
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760 extra := t.Sym() != nil || len(methods(t)) != 0
761
762
763
764 var rt *types.Type
765 dataAdd := 0
766 switch t.Kind() {
767 default:
768 rt = rttype.Type
769 case types.TARRAY:
770 rt = rttype.ArrayType
771 case types.TSLICE:
772 rt = rttype.SliceType
773 case types.TCHAN:
774 rt = rttype.ChanType
775 case types.TFUNC:
776 rt = rttype.FuncType
777 dataAdd = (t.NumRecvs() + t.NumParams() + t.NumResults()) * types.PtrSize
778 case types.TINTER:
779 rt = rttype.InterfaceType
780 dataAdd = len(imethods(t)) * int(rttype.IMethod.Size())
781 case types.TMAP:
782 rt = rttype.MapType
783 case types.TPTR:
784 rt = rttype.PtrType
785
786 case types.TSTRUCT:
787 rt = rttype.StructType
788 dataAdd = t.NumFields() * int(rttype.StructField.Size())
789 }
790
791
792 B := rt.Size()
793 C := B
794 if extra {
795 C = B + rttype.UncommonType.Size()
796 }
797 D := C + int64(dataAdd)
798 E := D + int64(len(methods(t)))*rttype.Method.Size()
799
800
801 c := rttype.NewCursor(lsym, 0, rt)
802 if rt == rttype.Type {
803 dcommontype(c, t)
804 } else {
805 dcommontype(c.Field("Type"), t)
806 }
807
808
809
810 switch t.Kind() {
811 case types.TARRAY:
812
813 s1 := writeType(t.Elem())
814 t2 := types.NewSlice(t.Elem())
815 s2 := writeType(t2)
816 c.Field("Elem").WritePtr(s1)
817 c.Field("Slice").WritePtr(s2)
818 c.Field("Len").WriteUintptr(uint64(t.NumElem()))
819
820 case types.TSLICE:
821
822 s1 := writeType(t.Elem())
823 c.Field("Elem").WritePtr(s1)
824
825 case types.TCHAN:
826
827 s1 := writeType(t.Elem())
828 c.Field("Elem").WritePtr(s1)
829 c.Field("Dir").WriteInt(int64(t.ChanDir()))
830
831 case types.TFUNC:
832
833 for _, t1 := range t.RecvParamsResults() {
834 writeType(t1.Type)
835 }
836 inCount := t.NumRecvs() + t.NumParams()
837 outCount := t.NumResults()
838 if t.IsVariadic() {
839 outCount |= 1 << 15
840 }
841
842 c.Field("InCount").WriteUint16(uint16(inCount))
843 c.Field("OutCount").WriteUint16(uint16(outCount))
844
845
846 typs := t.RecvParamsResults()
847 array := rttype.NewArrayCursor(lsym, C, types.Types[types.TUNSAFEPTR], len(typs))
848 for i, t1 := range typs {
849 array.Elem(i).WritePtr(writeType(t1.Type))
850 }
851
852 case types.TINTER:
853
854 m := imethods(t)
855 n := len(m)
856 for _, a := range m {
857 writeType(a.type_)
858 }
859
860 var tpkg *types.Pkg
861 if t.Sym() != nil && t != types.Types[t.Kind()] && t != types.ErrorType {
862 tpkg = t.Sym().Pkg
863 }
864 dgopkgpath(c.Field("PkgPath"), tpkg)
865 c.Field("Methods").WriteSlice(lsym, C, int64(n), int64(n))
866
867 array := rttype.NewArrayCursor(lsym, C, rttype.IMethod, n)
868 for i, a := range m {
869 exported := types.IsExported(a.name.Name)
870 var pkg *types.Pkg
871 if !exported && a.name.Pkg != tpkg {
872 pkg = a.name.Pkg
873 }
874 nsym := dname(a.name.Name, "", pkg, exported, false)
875
876 e := array.Elem(i)
877 e.Field("Name").WriteSymPtrOff(nsym, false)
878 e.Field("Typ").WriteSymPtrOff(writeType(a.type_), false)
879 }
880
881 case types.TMAP:
882 writeMapType(t, lsym, c)
883
884 case types.TPTR:
885
886 if t.Elem().Kind() == types.TANY {
887 base.Fatalf("bad pointer base type")
888 }
889
890 s1 := writeType(t.Elem())
891 c.Field("Elem").WritePtr(s1)
892
893 case types.TSTRUCT:
894
895 fields := t.Fields()
896 for _, t1 := range fields {
897 writeType(t1.Type)
898 }
899
900
901
902
903
904
905 var spkg *types.Pkg
906 for _, f := range fields {
907 if !types.IsExported(f.Sym.Name) {
908 spkg = f.Sym.Pkg
909 break
910 }
911 }
912
913 dgopkgpath(c.Field("PkgPath"), spkg)
914 c.Field("Fields").WriteSlice(lsym, C, int64(len(fields)), int64(len(fields)))
915
916 array := rttype.NewArrayCursor(lsym, C, rttype.StructField, len(fields))
917 for i, f := range fields {
918 e := array.Elem(i)
919 dnameField(e.Field("Name"), spkg, f)
920 e.Field("Typ").WritePtr(writeType(f.Type))
921 e.Field("Offset").WriteUintptr(uint64(f.Offset))
922 }
923 }
924
925
926 if extra {
927 dextratype(lsym, B, t, dataAdd)
928 }
929
930
931
932
933
934 dupok := 0
935 if tbase.Sym() == nil || tbase.IsFullyInstantiated() || tbase.HasShape() {
936 dupok = obj.DUPOK
937 }
938
939 objw.Global(lsym, int32(E), int16(dupok|obj.RODATA))
940
941
942
943
944
945
946 keep := base.Ctxt.Flag_dynlink
947 if !keep && t.Sym() == nil {
948
949
950
951
952
953 switch t.Kind() {
954 case types.TPTR, types.TARRAY, types.TCHAN, types.TFUNC, types.TMAP, types.TSLICE, types.TSTRUCT:
955 keep = true
956 }
957 }
958
959 if types.TypeHasNoAlg(t) {
960 keep = false
961 }
962 lsym.Set(obj.AttrMakeTypelink, keep)
963
964 return lsym
965 }
966
967
968
969 func InterfaceMethodOffset(ityp *types.Type, i int64) int64 {
970
971
972
973
974
975
976
977
978 return int64(commonSize()+4*types.PtrSize+uncommonSize(ityp)) + i*8
979 }
980
981
982 func NeedRuntimeType(t *types.Type) {
983 if _, ok := signatset[t]; !ok {
984 signatset[t] = struct{}{}
985 signatslice = append(signatslice, typeAndStr{t: t, short: types.TypeSymName(t), regular: t.String()})
986 }
987 }
988
989 func WriteRuntimeTypes() {
990
991
992 for len(signatslice) > 0 {
993 signats := signatslice
994
995 slices.SortFunc(signats, typesStrCmp)
996 for _, ts := range signats {
997 t := ts.t
998 writeType(t)
999 if t.Sym() != nil {
1000 writeType(types.NewPtr(t))
1001 }
1002 }
1003 signatslice = signatslice[len(signats):]
1004 }
1005 }
1006
1007 func WriteGCSymbols() {
1008
1009 gcsyms := make([]typeAndStr, 0, len(gcsymset))
1010 for t := range gcsymset {
1011 gcsyms = append(gcsyms, typeAndStr{t: t, short: types.TypeSymName(t), regular: t.String()})
1012 }
1013 slices.SortFunc(gcsyms, typesStrCmp)
1014 for _, ts := range gcsyms {
1015 dgcsym(ts.t, true, false)
1016 }
1017 }
1018
1019
1020
1021
1022 func writeITab(lsym *obj.LSym, typ, iface *types.Type, allowNonImplement bool) {
1023
1024
1025 oldpos, oldfn := base.Pos, ir.CurFunc
1026 defer func() { base.Pos, ir.CurFunc = oldpos, oldfn }()
1027
1028 if typ == nil || (typ.IsPtr() && typ.Elem() == nil) || typ.IsUntyped() || iface == nil || !iface.IsInterface() || iface.IsEmptyInterface() {
1029 base.Fatalf("writeITab(%v, %v)", typ, iface)
1030 }
1031
1032 sigs := iface.AllMethods()
1033 entries := make([]*obj.LSym, 0, len(sigs))
1034
1035
1036
1037 for _, m := range methods(typ) {
1038 if m.name == sigs[0].Sym {
1039 entries = append(entries, m.isym)
1040 if m.isym == nil {
1041 panic("NO ISYM")
1042 }
1043 sigs = sigs[1:]
1044 if len(sigs) == 0 {
1045 break
1046 }
1047 }
1048 }
1049 completeItab := len(sigs) == 0
1050 if !allowNonImplement && !completeItab {
1051 base.Fatalf("incomplete itab")
1052 }
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062 c := rttype.NewCursor(lsym, 0, rttype.ITab)
1063 c.Field("Inter").WritePtr(writeType(iface))
1064 c.Field("Type").WritePtr(writeType(typ))
1065 c.Field("Hash").WriteUint32(types.TypeHash(typ))
1066
1067 var delta int64
1068 c = c.Field("Fun")
1069 if !completeItab {
1070
1071 c.Elem(0).WriteUintptr(0)
1072 } else {
1073 var a rttype.ArrayCursor
1074 a, delta = c.ModifyArray(len(entries))
1075 for i, fn := range entries {
1076 a.Elem(i).WritePtrWeak(fn)
1077 }
1078 }
1079
1080 objw.Global(lsym, int32(rttype.ITab.Size()+delta), int16(obj.DUPOK|obj.RODATA))
1081 lsym.Set(obj.AttrContentAddressable, true)
1082 }
1083
1084 func WritePluginTable() {
1085 ptabs := typecheck.Target.PluginExports
1086 if len(ptabs) == 0 {
1087 return
1088 }
1089
1090 lsym := base.Ctxt.Lookup("go:plugin.tabs")
1091 ot := 0
1092 for _, p := range ptabs {
1093
1094
1095
1096
1097
1098
1099 nsym := dname(p.Sym().Name, "", nil, true, false)
1100 t := p.Type()
1101 if p.Class != ir.PFUNC {
1102 t = types.NewPtr(t)
1103 }
1104 tsym := writeType(t)
1105 ot = objw.SymPtrOff(lsym, ot, nsym)
1106 ot = objw.SymPtrOff(lsym, ot, tsym)
1107
1108
1109 tsym.Set(obj.AttrUsedInIface, true)
1110 }
1111 objw.Global(lsym, int32(ot), int16(obj.RODATA))
1112
1113 lsym = base.Ctxt.Lookup("go:plugin.exports")
1114 ot = 0
1115 for _, p := range ptabs {
1116 ot = objw.SymPtr(lsym, ot, p.Linksym(), 0)
1117 }
1118 objw.Global(lsym, int32(ot), int16(obj.RODATA))
1119 }
1120
1121
1122
1123 func writtenByWriteBasicTypes(typ *types.Type) bool {
1124 if typ.Sym() == nil && typ.Kind() == types.TFUNC {
1125
1126 if typ.NumRecvs() == 0 &&
1127 typ.NumParams() == 1 && typ.NumResults() == 1 &&
1128 typ.Param(0).Type == types.ErrorType &&
1129 typ.Result(0).Type == types.Types[types.TSTRING] {
1130 return true
1131 }
1132 }
1133
1134
1135
1136 if typ.Sym() == nil && typ.IsSlice() {
1137 typ = typ.Elem()
1138 }
1139
1140
1141 sym := typ.Sym()
1142 if sym != nil && (sym.Pkg == types.BuiltinPkg || sym.Pkg == types.UnsafePkg) {
1143 return true
1144 }
1145
1146 return (sym == nil && typ.IsEmptyInterface()) || typ == types.ErrorType
1147 }
1148
1149 func WriteBasicTypes() {
1150
1151
1152
1153
1154
1155
1156
1157 if base.Ctxt.Pkgpath != "runtime" {
1158 return
1159 }
1160
1161
1162 var list []*types.Type
1163 for i := types.Kind(1); i <= types.TBOOL; i++ {
1164 list = append(list, types.Types[i])
1165 }
1166 list = append(list,
1167 types.Types[types.TSTRING],
1168 types.Types[types.TUNSAFEPTR],
1169 types.AnyType,
1170 types.ErrorType)
1171 for _, t := range list {
1172 writeType(types.NewPtr(t))
1173 writeType(types.NewPtr(types.NewSlice(t)))
1174 }
1175
1176
1177
1178 writeType(types.NewPtr(types.NewSignature(nil, []*types.Field{
1179 types.NewField(base.Pos, nil, types.ErrorType),
1180 }, []*types.Field{
1181 types.NewField(base.Pos, nil, types.Types[types.TSTRING]),
1182 })))
1183 }
1184
1185 type typeAndStr struct {
1186 t *types.Type
1187 short string
1188 regular string
1189 }
1190
1191 func typesStrCmp(a, b typeAndStr) int {
1192
1193 if a.t.Sym() != nil && b.t.Sym() == nil {
1194 return -1
1195 }
1196 if a.t.Sym() == nil && b.t.Sym() != nil {
1197 return +1
1198 }
1199
1200 if r := strings.Compare(a.short, b.short); r != 0 {
1201 return r
1202 }
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212 if r := strings.Compare(a.regular, b.regular); r != 0 {
1213 return r
1214 }
1215
1216
1217
1218
1219 if a.t.Kind() == types.TINTER && len(a.t.AllMethods()) > 0 {
1220 if a.t.AllMethods()[0].Pos.Before(b.t.AllMethods()[0].Pos) {
1221 return -1
1222 }
1223 return +1
1224 }
1225 return 0
1226 }
1227
1228
1229
1230
1231
1232 func GCSym(t *types.Type, onDemandAllowed bool) (lsym *obj.LSym, ptrdata int64) {
1233
1234 gcsymmu.Lock()
1235 if _, ok := gcsymset[t]; !ok {
1236 gcsymset[t] = struct{}{}
1237 }
1238 gcsymmu.Unlock()
1239
1240 lsym, _, ptrdata = dgcsym(t, false, onDemandAllowed)
1241 return
1242 }
1243
1244
1245
1246
1247
1248 func dgcsym(t *types.Type, write, onDemandAllowed bool) (lsym *obj.LSym, onDemand bool, ptrdata int64) {
1249 ptrdata = types.PtrDataSize(t)
1250 if !onDemandAllowed || ptrdata/int64(types.PtrSize) <= abi.MaxPtrmaskBytes*8 {
1251 lsym = dgcptrmask(t, write)
1252 return
1253 }
1254
1255 onDemand = true
1256 lsym = dgcptrmaskOnDemand(t, write)
1257 return
1258 }
1259
1260
1261 func dgcptrmask(t *types.Type, write bool) *obj.LSym {
1262
1263 n := (types.PtrDataSize(t)/int64(types.PtrSize) + 7) / 8
1264
1265 n = (n + int64(types.PtrSize) - 1) &^ (int64(types.PtrSize) - 1)
1266 ptrmask := make([]byte, n)
1267 fillptrmask(t, ptrmask)
1268 p := fmt.Sprintf("runtime.gcbits.%x", ptrmask)
1269
1270 lsym := base.Ctxt.Lookup(p)
1271 if write && !lsym.OnList() {
1272 for i, x := range ptrmask {
1273 objw.Uint8(lsym, i, x)
1274 }
1275 objw.Global(lsym, int32(len(ptrmask)), obj.DUPOK|obj.RODATA|obj.LOCAL)
1276 lsym.Set(obj.AttrContentAddressable, true)
1277 }
1278 return lsym
1279 }
1280
1281
1282
1283
1284 func fillptrmask(t *types.Type, ptrmask []byte) {
1285 clear(ptrmask)
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
View as plain text