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
761
762
763 extra := t.Sym() != nil || len(methods(t)) != 0
764
765
766
767 var rt *types.Type
768 dataAdd := 0
769 switch t.Kind() {
770 default:
771 rt = rttype.Type
772 case types.TARRAY:
773 rt = rttype.ArrayType
774 case types.TSLICE:
775 rt = rttype.SliceType
776 case types.TCHAN:
777 rt = rttype.ChanType
778 case types.TFUNC:
779 rt = rttype.FuncType
780 dataAdd = (t.NumRecvs() + t.NumParams() + t.NumResults()) * types.PtrSize
781 case types.TINTER:
782 rt = rttype.InterfaceType
783 dataAdd = len(imethods(t)) * int(rttype.IMethod.Size())
784 case types.TMAP:
785 rt = rttype.MapType
786 case types.TPTR:
787 rt = rttype.PtrType
788
789 case types.TSTRUCT:
790 rt = rttype.StructType
791 dataAdd = t.NumFields() * int(rttype.StructField.Size())
792 }
793
794
795 B := rt.Size()
796 C := B
797 if extra {
798 C = B + rttype.UncommonType.Size()
799 }
800 D := C + int64(dataAdd)
801 E := D + int64(len(methods(t)))*rttype.Method.Size()
802
803
804 c := rttype.NewCursor(lsym, 0, rt)
805 if rt == rttype.Type {
806 dcommontype(c, t)
807 } else {
808 dcommontype(c.Field("Type"), t)
809 }
810
811
812
813 switch t.Kind() {
814 case types.TARRAY:
815
816 s1 := writeType(t.Elem())
817 t2 := types.NewSlice(t.Elem())
818 s2 := writeType(t2)
819 c.Field("Elem").WritePtr(s1)
820 c.Field("Slice").WritePtr(s2)
821 c.Field("Len").WriteUintptr(uint64(t.NumElem()))
822
823 case types.TSLICE:
824
825 s1 := writeType(t.Elem())
826 c.Field("Elem").WritePtr(s1)
827
828 case types.TCHAN:
829
830 s1 := writeType(t.Elem())
831 c.Field("Elem").WritePtr(s1)
832 c.Field("Dir").WriteInt(int64(t.ChanDir()))
833
834 case types.TFUNC:
835
836 for _, t1 := range t.RecvParamsResults() {
837 writeType(t1.Type)
838 }
839 inCount := t.NumRecvs() + t.NumParams()
840 outCount := t.NumResults()
841 if t.IsVariadic() {
842 outCount |= 1 << 15
843 }
844
845 c.Field("InCount").WriteUint16(uint16(inCount))
846 c.Field("OutCount").WriteUint16(uint16(outCount))
847
848
849 typs := t.RecvParamsResults()
850 array := rttype.NewArrayCursor(lsym, C, types.Types[types.TUNSAFEPTR], len(typs))
851 for i, t1 := range typs {
852 array.Elem(i).WritePtr(writeType(t1.Type))
853 }
854
855 case types.TINTER:
856
857 m := imethods(t)
858 n := len(m)
859 for _, a := range m {
860 writeType(a.type_)
861 }
862
863 var tpkg *types.Pkg
864 if t.Sym() != nil && t != types.Types[t.Kind()] && t != types.ErrorType {
865 tpkg = t.Sym().Pkg
866 }
867 dgopkgpath(c.Field("PkgPath"), tpkg)
868 c.Field("Methods").WriteSlice(lsym, C, int64(n), int64(n))
869
870 array := rttype.NewArrayCursor(lsym, C, rttype.IMethod, n)
871 for i, a := range m {
872 exported := types.IsExported(a.name.Name)
873 var pkg *types.Pkg
874 if !exported && a.name.Pkg != tpkg {
875 pkg = a.name.Pkg
876 }
877 nsym := dname(a.name.Name, "", pkg, exported, false)
878
879 e := array.Elem(i)
880 e.Field("Name").WriteSymPtrOff(nsym, false)
881 e.Field("Typ").WriteSymPtrOff(writeType(a.type_), false)
882 }
883
884 case types.TMAP:
885 writeMapType(t, lsym, c)
886
887 case types.TPTR:
888
889 if t.Elem().Kind() == types.TANY {
890 base.Fatalf("bad pointer base type")
891 }
892
893 s1 := writeType(t.Elem())
894 c.Field("Elem").WritePtr(s1)
895
896 case types.TSTRUCT:
897
898 fields := t.Fields()
899 for _, t1 := range fields {
900 writeType(t1.Type)
901 }
902
903
904
905
906
907
908 var spkg *types.Pkg
909 for _, f := range fields {
910 if !types.IsExported(f.Sym.Name) {
911 spkg = f.Sym.Pkg
912 break
913 }
914 }
915
916 dgopkgpath(c.Field("PkgPath"), spkg)
917 c.Field("Fields").WriteSlice(lsym, C, int64(len(fields)), int64(len(fields)))
918
919 array := rttype.NewArrayCursor(lsym, C, rttype.StructField, len(fields))
920 for i, f := range fields {
921 e := array.Elem(i)
922 dnameField(e.Field("Name"), spkg, f)
923 e.Field("Typ").WritePtr(writeType(f.Type))
924 e.Field("Offset").WriteUintptr(uint64(f.Offset))
925 }
926 }
927
928
929 if extra {
930 dextratype(lsym, B, t, dataAdd)
931 }
932
933
934
935
936
937 dupok := 0
938 if tbase.Sym() == nil || tbase.IsFullyInstantiated() || tbase.HasShape() {
939 dupok = obj.DUPOK
940 }
941
942 objw.Global(lsym, int32(E), int16(dupok|obj.RODATA))
943
944
945
946
947
948
949 keep := base.Ctxt.Flag_dynlink
950 if !keep && t.Sym() == nil {
951
952
953
954
955
956 switch t.Kind() {
957 case types.TPTR, types.TARRAY, types.TCHAN, types.TFUNC, types.TMAP, types.TSLICE, types.TSTRUCT:
958 keep = true
959 }
960 }
961
962 if types.TypeHasNoAlg(t) {
963 keep = false
964 }
965 lsym.Set(obj.AttrMakeTypelink, keep)
966
967 return lsym
968 }
969
970
971
972 func InterfaceMethodOffset(ityp *types.Type, i int64) int64 {
973
974
975
976
977
978
979
980
981 return int64(commonSize()+4*types.PtrSize+uncommonSize(ityp)) + i*8
982 }
983
984
985 func NeedRuntimeType(t *types.Type) {
986 if _, ok := signatset[t]; !ok {
987 signatset[t] = struct{}{}
988 signatslice = append(signatslice, typeAndStr{t: t, short: types.TypeSymName(t), regular: t.String()})
989 }
990 }
991
992 func WriteRuntimeTypes() {
993
994
995 for len(signatslice) > 0 {
996 signats := signatslice
997
998 slices.SortFunc(signats, typesStrCmp)
999 for _, ts := range signats {
1000 t := ts.t
1001 writeType(t)
1002 if t.Sym() != nil {
1003 writeType(types.NewPtr(t))
1004 }
1005 }
1006 signatslice = signatslice[len(signats):]
1007 }
1008 }
1009
1010 func WriteGCSymbols() {
1011
1012 gcsyms := make([]typeAndStr, 0, len(gcsymset))
1013 for t := range gcsymset {
1014 gcsyms = append(gcsyms, typeAndStr{t: t, short: types.TypeSymName(t), regular: t.String()})
1015 }
1016 slices.SortFunc(gcsyms, typesStrCmp)
1017 for _, ts := range gcsyms {
1018 dgcsym(ts.t, true, false)
1019 }
1020 }
1021
1022
1023
1024
1025 func writeITab(lsym *obj.LSym, typ, iface *types.Type, allowNonImplement bool) {
1026
1027
1028 oldpos, oldfn := base.Pos, ir.CurFunc
1029 defer func() { base.Pos, ir.CurFunc = oldpos, oldfn }()
1030
1031 if typ == nil || (typ.IsPtr() && typ.Elem() == nil) || typ.IsUntyped() || iface == nil || !iface.IsInterface() || iface.IsEmptyInterface() {
1032 base.Fatalf("writeITab(%v, %v)", typ, iface)
1033 }
1034
1035 sigs := iface.AllMethods()
1036 entries := make([]*obj.LSym, 0, len(sigs))
1037
1038
1039
1040 for _, m := range methods(typ) {
1041 if m.name == sigs[0].Sym {
1042 entries = append(entries, m.isym)
1043 if m.isym == nil {
1044 panic("NO ISYM")
1045 }
1046 sigs = sigs[1:]
1047 if len(sigs) == 0 {
1048 break
1049 }
1050 }
1051 }
1052 completeItab := len(sigs) == 0
1053 if !allowNonImplement && !completeItab {
1054 base.Fatalf("incomplete itab")
1055 }
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065 c := rttype.NewCursor(lsym, 0, rttype.ITab)
1066 c.Field("Inter").WritePtr(writeType(iface))
1067 c.Field("Type").WritePtr(writeType(typ))
1068 c.Field("Hash").WriteUint32(types.TypeHash(typ))
1069
1070 var delta int64
1071 c = c.Field("Fun")
1072 if !completeItab {
1073
1074 c.Elem(0).WriteUintptr(0)
1075 } else {
1076 var a rttype.ArrayCursor
1077 a, delta = c.ModifyArray(len(entries))
1078 for i, fn := range entries {
1079 a.Elem(i).WritePtrWeak(fn)
1080 }
1081 }
1082
1083 objw.Global(lsym, int32(rttype.ITab.Size()+delta), int16(obj.DUPOK|obj.RODATA))
1084 lsym.Set(obj.AttrContentAddressable, true)
1085 }
1086
1087 func WritePluginTable() {
1088 ptabs := typecheck.Target.PluginExports
1089 if len(ptabs) == 0 {
1090 return
1091 }
1092
1093 lsym := base.Ctxt.Lookup("go:plugin.tabs")
1094 ot := 0
1095 for _, p := range ptabs {
1096
1097
1098
1099
1100
1101
1102 nsym := dname(p.Sym().Name, "", nil, true, false)
1103 t := p.Type()
1104 if p.Class != ir.PFUNC {
1105 t = types.NewPtr(t)
1106 }
1107 tsym := writeType(t)
1108 ot = objw.SymPtrOff(lsym, ot, nsym)
1109 ot = objw.SymPtrOff(lsym, ot, tsym)
1110
1111
1112 tsym.Set(obj.AttrUsedInIface, true)
1113 }
1114 objw.Global(lsym, int32(ot), int16(obj.RODATA))
1115
1116 lsym = base.Ctxt.Lookup("go:plugin.exports")
1117 ot = 0
1118 for _, p := range ptabs {
1119 ot = objw.SymPtr(lsym, ot, p.Linksym(), 0)
1120 }
1121 objw.Global(lsym, int32(ot), int16(obj.RODATA))
1122 }
1123
1124
1125
1126 func writtenByWriteBasicTypes(typ *types.Type) bool {
1127 if typ.Sym() == nil && typ.Kind() == types.TFUNC {
1128
1129 if typ.NumRecvs() == 0 &&
1130 typ.NumParams() == 1 && typ.NumResults() == 1 &&
1131 typ.Param(0).Type == types.ErrorType &&
1132 typ.Result(0).Type == types.Types[types.TSTRING] {
1133 return true
1134 }
1135 }
1136
1137
1138
1139 if typ.Sym() == nil && typ.IsSlice() {
1140 typ = typ.Elem()
1141 }
1142
1143
1144 sym := typ.Sym()
1145 if sym != nil && (sym.Pkg == types.BuiltinPkg || sym.Pkg == types.UnsafePkg) {
1146 return true
1147 }
1148
1149 return (sym == nil && typ.IsEmptyInterface()) || typ == types.ErrorType
1150 }
1151
1152 func WriteBasicTypes() {
1153
1154
1155
1156
1157
1158
1159
1160 if base.Ctxt.Pkgpath != "runtime" {
1161 return
1162 }
1163
1164
1165 var list []*types.Type
1166 for i := types.Kind(1); i <= types.TBOOL; i++ {
1167 list = append(list, types.Types[i])
1168 }
1169 list = append(list,
1170 types.Types[types.TSTRING],
1171 types.Types[types.TUNSAFEPTR],
1172 types.AnyType,
1173 types.ErrorType)
1174 for _, t := range list {
1175 writeType(types.NewPtr(t))
1176 writeType(types.NewPtr(types.NewSlice(t)))
1177 }
1178
1179
1180
1181 writeType(types.NewPtr(types.NewSignature(nil, []*types.Field{
1182 types.NewField(base.Pos, nil, types.ErrorType),
1183 }, []*types.Field{
1184 types.NewField(base.Pos, nil, types.Types[types.TSTRING]),
1185 })))
1186 }
1187
1188 type typeAndStr struct {
1189 t *types.Type
1190 short string
1191 regular string
1192 }
1193
1194 func typesStrCmp(a, b typeAndStr) int {
1195
1196 if a.t.Sym() != nil && b.t.Sym() == nil {
1197 return -1
1198 }
1199 if a.t.Sym() == nil && b.t.Sym() != nil {
1200 return +1
1201 }
1202
1203 if r := strings.Compare(a.short, b.short); r != 0 {
1204 return r
1205 }
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215 if r := strings.Compare(a.regular, b.regular); r != 0 {
1216 return r
1217 }
1218
1219
1220
1221
1222 if a.t.Kind() == types.TINTER && len(a.t.AllMethods()) > 0 {
1223 if a.t.AllMethods()[0].Pos.Before(b.t.AllMethods()[0].Pos) {
1224 return -1
1225 }
1226 return +1
1227 }
1228 return 0
1229 }
1230
1231
1232
1233
1234
1235 func GCSym(t *types.Type, onDemandAllowed bool) (lsym *obj.LSym, ptrdata int64) {
1236
1237 gcsymmu.Lock()
1238 if _, ok := gcsymset[t]; !ok {
1239 gcsymset[t] = struct{}{}
1240 }
1241 gcsymmu.Unlock()
1242
1243 lsym, _, ptrdata = dgcsym(t, false, onDemandAllowed)
1244 return
1245 }
1246
1247
1248
1249
1250
1251 func dgcsym(t *types.Type, write, onDemandAllowed bool) (lsym *obj.LSym, onDemand bool, ptrdata int64) {
1252 ptrdata = types.PtrDataSize(t)
1253 if !onDemandAllowed || ptrdata/int64(types.PtrSize) <= abi.MaxPtrmaskBytes*8 {
1254 lsym = dgcptrmask(t, write)
1255 return
1256 }
1257
1258 onDemand = true
1259 lsym = dgcptrmaskOnDemand(t, write)
1260 return
1261 }
1262
1263
1264 func dgcptrmask(t *types.Type, write bool) *obj.LSym {
1265
1266 n := (types.PtrDataSize(t)/int64(types.PtrSize) + 7) / 8
1267
1268 n = (n + int64(types.PtrSize) - 1) &^ (int64(types.PtrSize) - 1)
1269 ptrmask := make([]byte, n)
1270 fillptrmask(t, ptrmask)
1271 p := fmt.Sprintf("runtime.gcbits.%x", ptrmask)
1272
1273 lsym := base.Ctxt.Lookup(p)
1274 if write && !lsym.OnList() {
1275 for i, x := range ptrmask {
1276 objw.Uint8(lsym, i, x)
1277 }
1278 objw.Global(lsym, int32(len(ptrmask)), obj.DUPOK|obj.RODATA|obj.LOCAL)
1279 lsym.Set(obj.AttrContentAddressable, true)
1280 }
1281 return lsym
1282 }
1283
1284
1285
1286
1287 func fillptrmask(t *types.Type, ptrmask []byte) {
1288 if !t.HasPointers() {
1289 return
1290 }
1291
1292 vec := bitvec.New(8 * int32(len(ptrmask)))
1293 typebits.Set(t, 0, vec)
1294
1295 nptr := types.PtrDataSize(t) / int64(types.PtrSize)
1296 for i := int64(0); i < nptr; i++ {
1297 if vec.Get(int32(i)) {
1298 ptrmask[i/8] |= 1 << (uint(i) % 8)
1299 }
1300 }
1301 }
1302
1303
1304
1305 func dgcptrmaskOnDemand(t *types.Type, write bool) *obj.LSym {
1306 lsym := TypeLinksymPrefix(".gcmask", t)
1307 if write && !lsym.OnList() {
1308
1309
1310 objw.Uintptr(lsym, 0, 0)
1311 objw.Global(lsym, int32(types.PtrSize), obj.DUPOK|obj.NOPTR|obj.LOCAL)
1312 }
1313 return lsym
1314 }
1315
1316
1317
1318 func ZeroAddr(size int64) ir.Node {
1319 if size >= 1<<31 {
1320 base.Fatalf("map elem too big %d", size)
1321 }
1322 if ZeroSize < size {
1323 ZeroSize = size
1324 }
1325 lsym := base.PkgLinksym("go:map", "zero", obj.ABI0)
1326 x := ir.NewLinksymExpr(base.Pos, lsym, types.Types[types.TUINT8])
1327 return typecheck.Expr(typecheck.NodAddr(x))
1328 }
1329
1330
1331
1332 func NeedEmit(typ *types.Type) bool {
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342 switch sym := typ.Sym(); {
1343 case writtenByWriteBasicTypes(typ):
1344 return base.Ctxt.Pkgpath == "runtime"
1345
1346 case sym == nil:
1347
1348
1349 return true
1350
1351 case sym.Pkg == types.LocalPkg:
1352
1353 return true
1354
1355 case typ.IsFullyInstantiated():
1356
1357
1358 return true
1359
1360 case typ.HasShape():
1361
1362
1363 return true
1364
1365 default:
1366
1367 return false
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
1406
1407 func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSym {
1408 if forItab && !types.IsDirectIface(rcvr) {
1409 rcvr = rcvr.PtrTo()
1410 }
1411
1412 newnam := ir.MethodSym(rcvr, method.Sym)
1413 lsym := newnam.Linksym()
1414
1415
1416 return lsym
1417 }
1418
1419 var ZeroSize int64
1420
1421
1422
1423 func MarkTypeUsedInInterface(t *types.Type, from *obj.LSym) {
1424 if t.HasShape() {
1425
1426 base.Fatalf("shape types have no methods %+v", t)
1427 }
1428 MarkTypeSymUsedInInterface(TypeLinksym(t), from)
1429 }
1430 func MarkTypeSymUsedInInterface(tsym *obj.LSym, from *obj.LSym) {
1431
1432
1433 from.AddRel(base.Ctxt, obj.Reloc{Type: objabi.R_USEIFACE, Sym: tsym})
1434 }
1435
1436
1437
1438 func MarkUsedIfaceMethod(n *ir.CallExpr) {
1439
1440 if ir.CurFunc.LSym == nil {
1441 return
1442 }
1443 dot := n.Fun.(*ir.SelectorExpr)
1444 ityp := dot.X.Type()
1445 if ityp.HasShape() {
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465 ir.CurFunc.LSym.AddRel(base.Ctxt, obj.Reloc{
1466 Type: objabi.R_USENAMEDMETHOD,
1467 Sym: staticdata.StringSymNoCommon(dot.Sel.Name),
1468 })
1469 return
1470 }
1471
1472
1473 midx := dot.Offset() / int64(types.PtrSize)
1474 ir.CurFunc.LSym.AddRel(base.Ctxt, obj.Reloc{
1475 Type: objabi.R_USEIFACEMETHOD,
1476 Sym: TypeLinksym(ityp),
1477 Add: InterfaceMethodOffset(ityp, midx),
1478 })
1479 }
1480
View as plain text