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