1
2
3
4
5 package reflectdata
6
7 import (
8 "fmt"
9 "go/constant"
10 "strconv"
11 "strings"
12
13 "cmd/compile/internal/base"
14 "cmd/compile/internal/ir"
15 "cmd/compile/internal/objw"
16 "cmd/compile/internal/typecheck"
17 "cmd/compile/internal/types"
18 "cmd/internal/obj"
19 )
20
21
22
23 func genhash(t *types.Type) *obj.LSym {
24 return genhashSig(eqSignature(t))
25 }
26
27 func genhashSig(sig string) *obj.LSym {
28 if len(sig) > 0 && sig[0] == sigAlign {
29 _, sig = parseNum(sig[1:])
30 }
31 switch sig {
32 case "":
33 return sysClosure("memhash0")
34 case string(sigMemory) + "1":
35 return sysClosure("memhash8")
36 case string(sigMemory) + "2":
37 return sysClosure("memhash16")
38 case string(sigMemory) + "4":
39 return sysClosure("memhash32")
40 case string(sigMemory) + "8":
41 return sysClosure("memhash64")
42 case string(sigMemory) + "16":
43 return sysClosure("memhash128")
44 case string(sigString):
45 return sysClosure("strhash")
46 case string(sigIface):
47 return sysClosure("interhash")
48 case string(sigEface):
49 return sysClosure("nilinterhash")
50 case string(sigFloat32):
51 return sysClosure("f32hash")
52 case string(sigFloat64):
53 return sysClosure("f64hash")
54 case string(sigFloat32) + string(sigFloat32):
55 return sysClosure("c64hash")
56 case string(sigFloat64) + string(sigFloat64):
57 return sysClosure("c128hash")
58 }
59
60 closure := TypeLinksymLookup(".hashfunc." + sig)
61 if len(closure.P) > 0 {
62 return closure
63 }
64
65 if sig[0] == sigMemory {
66 n, rest := parseNum(sig[1:])
67 if rest == "" {
68
69
70 if memhashvarlen == nil {
71 memhashvarlen = typecheck.LookupRuntimeFunc("memhash_varlen")
72 }
73 ot := 0
74 ot = objw.SymPtr(closure, ot, memhashvarlen, 0)
75 ot = objw.Uintptr(closure, ot, uint64(n))
76 objw.Global(closure, int32(ot), obj.DUPOK|obj.RODATA)
77 return closure
78 }
79 }
80
81 if base.Flag.LowerR != 0 {
82 fmt.Printf("genhash %s\n", sig)
83 }
84
85 fn := hashFunc(sig)
86
87
88
89 objw.SymPtr(closure, 0, fn.Linksym(), 0)
90 objw.Global(closure, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
91 return closure
92 }
93
94 func hashFunc(sig string) *ir.Func {
95 sym := types.TypeSymLookup(".hash." + sig)
96 if sym.Def != nil {
97 return sym.Def.(*ir.Name).Func
98 }
99
100 pos := base.AutogeneratedPos
101 base.Pos = pos
102
103
104 fn := ir.NewFunc(pos, pos, sym, types.NewSignature(nil,
105 []*types.Field{
106 types.NewField(pos, typecheck.Lookup("p"), types.Types[types.TUNSAFEPTR]),
107 types.NewField(pos, typecheck.Lookup("h"), types.Types[types.TUINTPTR]),
108 },
109 []*types.Field{
110 types.NewField(pos, nil, types.Types[types.TUINTPTR]),
111 },
112 ))
113 sym.Def = fn.Nname
114 fn.Pragma |= ir.Noinline
115 typecheck.DeclFunc(fn)
116 np := fn.Dcl[0]
117 nh := fn.Dcl[1]
118
119
120 if len(sig) > 0 && sig[0] == sigAlign {
121 _, sig = parseNum(sig[1:])
122 }
123
124
125 var off int64
126
127
128 ptr := func() ir.Node {
129 c := ir.NewBasicLit(pos, types.Types[types.TUINTPTR], constant.MakeInt64(off))
130 return ir.NewBinaryExpr(pos, ir.OUNSAFEADD, np, c)
131 }
132
133
134 hash := func(name string, size int64) {
135 p := ptr()
136 hashFn := typecheck.LookupRuntime(name)
137 call := ir.NewCallExpr(pos, ir.OCALL, hashFn, []ir.Node{p, nh})
138 fn.Body.Append(ir.NewAssignStmt(pos, nh, call))
139 off += size
140 }
141
142 for len(sig) > 0 {
143 kind := sig[0]
144 sig = sig[1:]
145 switch kind {
146 case sigMemory:
147 var n int64
148 n, sig = parseNum(sig)
149 switch {
150 case n == 4:
151 p := ptr()
152 memhash := typecheck.LookupRuntime("memhash32")
153 call := ir.NewCallExpr(pos, ir.OCALL, memhash, []ir.Node{p, nh})
154 fn.Body.Append(ir.NewAssignStmt(pos, nh, call))
155 case n == 8:
156 p := ptr()
157 memhash := typecheck.LookupRuntime("memhash64")
158 call := ir.NewCallExpr(pos, ir.OCALL, memhash, []ir.Node{p, nh})
159 fn.Body.Append(ir.NewAssignStmt(pos, nh, call))
160 default:
161 p := ptr()
162 memhash := typecheck.LookupRuntime("memhash")
163 size := ir.NewBasicLit(pos, types.Types[types.TUINTPTR], constant.MakeInt64(n))
164 call := ir.NewCallExpr(pos, ir.OCALL, memhash, []ir.Node{p, nh, size})
165 fn.Body.Append(ir.NewAssignStmt(pos, nh, call))
166 }
167 off += n
168 case sigFloat32:
169 hash("f32hash", 4)
170 case sigFloat64:
171 hash("f64hash", 8)
172 case sigString:
173 hash("strhash", 2*int64(types.PtrSize))
174 case sigEface:
175 hash("nilinterhash", 2*int64(types.PtrSize))
176 case sigIface:
177 hash("interhash", 2*int64(types.PtrSize))
178 case sigSkip:
179 var n int64
180 n, sig = parseNum(sig)
181 off += n
182 case sigArrayStart:
183 var n int64
184 var elemSig string
185 n, elemSig, sig = parseArray(sig)
186 elemSize := sigSize(elemSig)
187
188
189
190
191
192 elemFn := hashFunc(elemSig).Nname
193 idx := typecheck.TempAt(pos, ir.CurFunc, types.Types[types.TUINTPTR])
194 init := ir.NewAssignStmt(pos, idx, ir.NewInt(pos, off))
195 cond := ir.NewBinaryExpr(pos, ir.OLT, idx, ir.NewInt(pos, off+n*elemSize))
196 post := ir.NewAssignStmt(pos, idx, ir.NewBinaryExpr(pos, ir.OADD, idx, ir.NewInt(pos, elemSize)))
197
198 p := ir.NewBinaryExpr(pos, ir.OUNSAFEADD, np, idx)
199 call := typecheck.Call(pos, elemFn, []ir.Node{p, nh}, false)
200 as := ir.NewAssignStmt(pos, nh, call)
201 loop := ir.NewForStmt(pos, init, cond, post, []ir.Node{as}, false)
202 fn.Body.Append(loop)
203 off += n * elemSize
204 }
205 }
206
207 fn.Body.Append(ir.NewReturnStmt(pos, []ir.Node{nh}))
208
209 if base.Flag.LowerR != 0 {
210 ir.DumpList("genhash body", fn.Body)
211 }
212
213 typecheck.FinishFuncBody()
214
215 fn.SetDupok(true)
216
217 ir.WithFunc(fn, func() {
218 typecheck.Stmts(fn.Body)
219 })
220
221 fn.SetNilCheckDisabled(true)
222 return fn
223 }
224
225
226
227 func sysClosure(name string) *obj.LSym {
228 s := typecheck.LookupRuntimeVar(name + "·f")
229 if len(s.P) == 0 {
230 f := typecheck.LookupRuntimeFunc(name)
231 objw.SymPtr(s, 0, f, 0)
232 objw.Global(s, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
233 }
234 return s
235 }
236
237
238
239 func geneq(t *types.Type) *obj.LSym {
240 switch types.AlgType(t) {
241 case types.ANOEQ, types.ANOALG:
242
243
244 return nil
245 }
246 return geneqSig(eqSignature(t))
247 }
248
249
250
251 func geneqSig(sig string) *obj.LSym {
252 align := int64(types.PtrSize)
253 if len(sig) > 0 && sig[0] == sigAlign {
254 align, sig = parseNum(sig[1:])
255 }
256 if base.Ctxt.Arch.CanMergeLoads {
257 align = 8
258 }
259 switch sig {
260 case "":
261 return sysClosure("memequal0")
262 case string(sigMemory) + "1":
263 return sysClosure("memequal8")
264 case string(sigMemory) + "2":
265 if align >= 2 {
266 return sysClosure("memequal16")
267 }
268 case string(sigMemory) + "4":
269 if align >= 4 {
270 return sysClosure("memequal32")
271 }
272 case string(sigMemory) + "8":
273 if align >= 8 {
274 return sysClosure("memequal64")
275 }
276 case string(sigMemory) + "16":
277 if align >= 8 {
278 return sysClosure("memequal128")
279 }
280 case string(sigString):
281 return sysClosure("strequal")
282 case string(sigIface):
283 return sysClosure("interequal")
284 case string(sigEface):
285 return sysClosure("nilinterequal")
286 case string(sigFloat32):
287 return sysClosure("f32equal")
288 case string(sigFloat64):
289 return sysClosure("f64equal")
290 case string(sigFloat32) + string(sigFloat32):
291 return sysClosure("c64equal")
292 case string(sigFloat64) + string(sigFloat64):
293 return sysClosure("c128equal")
294 }
295
296 closure := TypeLinksymLookup(".eqfunc." + sig)
297 if len(closure.P) > 0 {
298 return closure
299 }
300
301 if sig[0] == sigMemory {
302 n, rest := parseNum(sig[1:])
303 if rest == "" {
304
305
306 if memequalvarlen == nil {
307 memequalvarlen = typecheck.LookupRuntimeFunc("memequal_varlen")
308 }
309 ot := 0
310 ot = objw.SymPtr(closure, ot, memequalvarlen, 0)
311 ot = objw.Uintptr(closure, ot, uint64(n))
312 objw.Global(closure, int32(ot), obj.DUPOK|obj.RODATA)
313 return closure
314 }
315 }
316
317 if base.Flag.LowerR != 0 {
318 fmt.Printf("geneqSig %s\n", sig)
319 }
320
321 fn := eqFunc(sig)
322
323
324 objw.SymPtr(closure, 0, fn.Linksym(), 0)
325 objw.Global(closure, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
326 return closure
327 }
328
329 func eqFunc(sig string) *ir.Func {
330 sym := types.TypeSymLookup(".eq." + sig)
331 if sym.Def != nil {
332 return sym.Def.(*ir.Name).Func
333 }
334
335 pos := base.AutogeneratedPos
336 base.Pos = pos
337
338
339 fn := ir.NewFunc(pos, pos, sym, types.NewSignature(nil,
340 []*types.Field{
341 types.NewField(pos, typecheck.Lookup("p"), types.Types[types.TUNSAFEPTR]),
342 types.NewField(pos, typecheck.Lookup("q"), types.Types[types.TUNSAFEPTR]),
343 },
344 []*types.Field{
345 types.NewField(pos, typecheck.Lookup("r"), types.Types[types.TBOOL]),
346 },
347 ))
348 sym.Def = fn.Nname
349 fn.Pragma |= ir.Noinline
350 typecheck.DeclFunc(fn)
351 np := fn.Dcl[0]
352 nq := fn.Dcl[1]
353 nr := fn.Dcl[2]
354
355
356 neq := typecheck.AutoLabel(".neq")
357
358
359 align := int64(types.PtrSize)
360 if len(sig) > 0 && sig[0] == sigAlign {
361 sig = sig[1:]
362 align, sig = parseNum(sig)
363 }
364 unalignedOk := base.Ctxt.Arch.CanMergeLoads
365
366
367 var off int64
368 var hasCall bool
369
370
371
372 var lastTest ir.Node
373 test := func(eq ir.Node) {
374
375
376 if lastTest != nil {
377 nif := ir.NewIfStmt(pos, lastTest, nil, []ir.Node{ir.NewBranchStmt(pos, ir.OGOTO, neq)})
378 fn.Body.Append(nif)
379 }
380 lastTest = eq
381 }
382
383
384 load := func(t *types.Type) (ir.Node, ir.Node) {
385 c := ir.NewBasicLit(pos, types.Types[types.TUINTPTR], constant.MakeInt64(off))
386 p := ir.NewBinaryExpr(pos, ir.OUNSAFEADD, np, c)
387 q := ir.NewBinaryExpr(pos, ir.OUNSAFEADD, nq, c)
388 x := ir.NewStarExpr(pos, ir.NewConvExpr(pos, ir.OCONVNOP, t.PtrTo(), p))
389 y := ir.NewStarExpr(pos, ir.NewConvExpr(pos, ir.OCONVNOP, t.PtrTo(), q))
390 off += t.Size()
391 return x, y
392 }
393
394 compare := func(x, y ir.Node) {
395 test(ir.NewBinaryExpr(pos, ir.OEQ, x, y))
396 }
397
398
399
400
401 var pendingStrings []int64
402 flushStrings := func() {
403 defer func(saveOff int64) {
404 off = saveOff
405 }(off)
406 for _, x := range pendingStrings {
407 off = x
408 ptrA, ptrB := load(types.Types[types.TUNSAFEPTR])
409 len, _ := load(types.Types[types.TUINTPTR])
410
411 memeq := typecheck.LookupRuntime("memequal")
412 test(typecheck.Call(pos, memeq, []ir.Node{ptrA, ptrB, len}, false))
413 hasCall = true
414 }
415 pendingStrings = pendingStrings[:0]
416 }
417
418 for len(sig) > 0 {
419 kind := sig[0]
420 sig = sig[1:]
421 switch kind {
422 case sigMemory:
423 var n int64
424 n, sig = parseNum(sig)
425 if n > 64 {
426
427 c := ir.NewBasicLit(pos, types.Types[types.TUINTPTR], constant.MakeInt64(off))
428 p := ir.NewBinaryExpr(pos, ir.OUNSAFEADD, np, c)
429 q := ir.NewBinaryExpr(pos, ir.OUNSAFEADD, nq, c)
430 len := ir.NewBasicLit(pos, types.Types[types.TUINTPTR], constant.MakeInt64(n))
431 memeq := typecheck.LookupRuntime("memequal")
432 test(typecheck.Call(pos, memeq, []ir.Node{p, q, len}, false))
433 hasCall = true
434 off += n
435 n = 0
436 }
437 n0 := n
438 for n != 0 {
439 switch {
440 case n >= 8 && (unalignedOk || align >= 8 && off%8 == 0):
441 compare(load(types.Types[types.TUINT64]))
442 n -= 8
443 case (n == 5 || n == 6 || n == 7) && unalignedOk && n0 >= 8:
444 off -= 8 - n
445 compare(load(types.Types[types.TUINT64]))
446 n = 0
447 case n >= 4 && (unalignedOk || align >= 4 && off%4 == 0):
448 compare(load(types.Types[types.TUINT32]))
449 n -= 4
450 case n == 3 && unalignedOk && n0 >= 4:
451 off--
452 compare(load(types.Types[types.TUINT32]))
453 n = 0
454 case n >= 2 && (unalignedOk || align >= 2 && off%2 == 0):
455 compare(load(types.Types[types.TUINT16]))
456 n -= 2
457 default:
458 compare(load(types.Types[types.TUINT8]))
459 n--
460 }
461 }
462 case sigFloat32:
463 compare(load(types.Types[types.TFLOAT32]))
464 case sigFloat64:
465 compare(load(types.Types[types.TFLOAT64]))
466 case sigString:
467
468
469 pendingStrings = append(pendingStrings, off)
470 off += int64(types.PtrSize)
471 compare(load(types.Types[types.TUINTPTR]))
472 case sigEface, sigIface:
473
474
475 flushStrings()
476 typeX, typeY := load(types.Types[types.TUINTPTR].PtrTo())
477 compare(typeX, typeY)
478 dataX, dataY := load(types.Types[types.TUNSAFEPTR])
479 var eqFn *ir.Name
480 if kind == sigEface {
481 eqFn = typecheck.LookupRuntime("efaceeq")
482 } else {
483 eqFn = typecheck.LookupRuntime("ifaceeq")
484 }
485 test(typecheck.Call(pos, eqFn, []ir.Node{typeX, dataX, dataY}, false))
486 hasCall = true
487 case sigSkip:
488 var n int64
489 n, sig = parseNum(sig)
490 off += n
491 case sigArrayStart:
492
493 flushStrings()
494
495
496
497
498 if lastTest != nil {
499 nif := ir.NewIfStmt(pos, lastTest, nil, []ir.Node{ir.NewBranchStmt(pos, ir.OGOTO, neq)})
500 fn.Body.Append(nif)
501 lastTest = nil
502 }
503
504 var n int64
505 var elemSig string
506 n, elemSig, sig = parseArray(sig)
507 elemSize := sigSize(elemSig)
508
509
510
511
512
513 elemFn := eqFunc(sigTrimSkip(elemSig)).Nname
514 idx := typecheck.TempAt(pos, ir.CurFunc, types.Types[types.TUINTPTR])
515 init := ir.NewAssignStmt(pos, idx, ir.NewInt(pos, off))
516 cond := ir.NewBinaryExpr(pos, ir.OLT, idx, ir.NewInt(pos, off+n*elemSize))
517 post := ir.NewAssignStmt(pos, idx, ir.NewBinaryExpr(pos, ir.OADD, idx, ir.NewInt(pos, elemSize)))
518
519 p := ir.NewBinaryExpr(pos, ir.OUNSAFEADD, np, idx)
520 q := ir.NewBinaryExpr(pos, ir.OUNSAFEADD, nq, idx)
521 call := typecheck.Call(pos, elemFn, []ir.Node{p, q}, false)
522 nif := ir.NewIfStmt(pos, call, nil, []ir.Node{ir.NewBranchStmt(pos, ir.OGOTO, neq)})
523 loop := ir.NewForStmt(pos, init, cond, post, []ir.Node{nif}, false)
524 fn.Body.Append(loop)
525 off += n * elemSize
526
527
528
529
530
531
532 }
533 }
534
535
536 flushStrings()
537 if lastTest == nil {
538 lastTest = ir.NewBool(pos, true)
539 }
540 as := ir.NewAssignStmt(pos, nr, lastTest)
541 fn.Body.Append(as)
542
543
544
545 ret := typecheck.AutoLabel(".ret")
546 fn.Body.Append(ir.NewLabelStmt(pos, ret))
547 fn.Body.Append(ir.NewReturnStmt(pos, nil))
548
549
550
551
552 fn.Body.Append(ir.NewLabelStmt(pos, neq))
553 fn.Body.Append(ir.NewAssignStmt(pos, nr, ir.NewBool(pos, false)))
554 if hasCall {
555
556 fn.Body.Append(ir.NewBranchStmt(pos, ir.OGOTO, ret))
557 } else {
558
559 fn.Body.Append(ir.NewReturnStmt(pos, nil))
560 }
561
562
563
564
565 if base.Flag.LowerR != 0 {
566 ir.DumpList("geneq body", fn.Body)
567 }
568
569 typecheck.FinishFuncBody()
570
571 fn.SetDupok(true)
572
573 ir.WithFunc(fn, func() {
574 typecheck.Stmts(fn.Body)
575 })
576
577
578
579
580
581 fn.SetNilCheckDisabled(true)
582 return fn
583 }
584
585
586
587 func EqFor(t *types.Type) (ir.Node, bool) {
588 switch types.AlgType(t) {
589 case types.AMEM:
590 return typecheck.LookupRuntime("memequal"), true
591 case types.ASPECIAL:
592 fn := eqFunc(eqSignature(t))
593 return fn.Nname, false
594 }
595 base.Fatalf("EqFor %v", t)
596 return nil, false
597 }
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639 func eqSignature(t *types.Type) string {
640 var e eqSigBuilder
641 if !base.Ctxt.Arch.CanMergeLoads {
642 if a := t.Alignment(); a != int64(types.PtrSize) {
643 e.r.WriteString(fmt.Sprintf("%c%d", sigAlign, a))
644 }
645 }
646 e.build(t)
647 e.flush(true)
648 return e.r.String()
649 }
650
651 const (
652 sigMemory = 'M'
653 sigSkip = 'K'
654 sigFloat32 = 'F'
655 sigFloat64 = 'G'
656 sigString = 'S'
657 sigIface = 'I'
658 sigEface = 'E'
659 sigArrayStart = '['
660 sigArrayEnd = ']'
661 sigAlign = 'A'
662 )
663
664 type eqSigBuilder struct {
665 r strings.Builder
666 regMem int64
667 skipMem int64
668 }
669
670 func (e *eqSigBuilder) flush(atEnd bool) {
671 if e.regMem > 0 {
672 e.r.WriteString(fmt.Sprintf("%c%d", sigMemory, e.regMem))
673 e.regMem = 0
674 }
675 if e.skipMem > 0 {
676 if !atEnd {
677 e.r.WriteString(fmt.Sprintf("%c%d", sigSkip, e.skipMem))
678 }
679 e.skipMem = 0
680 }
681 }
682 func (e *eqSigBuilder) regular(n int64) {
683 if e.regMem == 0 {
684 e.flush(false)
685 }
686 e.regMem += n
687 }
688 func (e *eqSigBuilder) skip(n int64) {
689 if e.skipMem == 0 {
690 e.flush(false)
691 }
692 e.skipMem += n
693 }
694 func (e *eqSigBuilder) float32() {
695 e.flush(false)
696 e.r.WriteByte(sigFloat32)
697 }
698 func (e *eqSigBuilder) float64() {
699 e.flush(false)
700 e.r.WriteByte(sigFloat64)
701 }
702 func (e *eqSigBuilder) string() {
703 e.flush(false)
704 e.r.WriteByte(sigString)
705 }
706 func (e *eqSigBuilder) eface() {
707 e.flush(false)
708 e.r.WriteByte(sigEface)
709 }
710 func (e *eqSigBuilder) iface() {
711 e.flush(false)
712 e.r.WriteByte(sigIface)
713 }
714
715 func (e *eqSigBuilder) build(t *types.Type) {
716 switch t.Kind() {
717 case types.TINT8, types.TUINT8, types.TBOOL:
718 e.regular(1)
719 case types.TINT16, types.TUINT16:
720 e.regular(2)
721 case types.TINT32, types.TUINT32:
722 e.regular(4)
723 case types.TINT64, types.TUINT64:
724 e.regular(8)
725 case types.TINT, types.TUINT, types.TUINTPTR, types.TPTR, types.TUNSAFEPTR, types.TCHAN:
726 e.regular(int64(types.PtrSize))
727 case types.TFLOAT32:
728 e.float32()
729 case types.TFLOAT64:
730 e.float64()
731 case types.TCOMPLEX64:
732 e.float32()
733 e.float32()
734 case types.TCOMPLEX128:
735 e.float64()
736 e.float64()
737 case types.TSTRING:
738 e.string()
739 case types.TINTER:
740 if t.IsEmptyInterface() {
741 e.eface()
742 } else {
743 e.iface()
744 }
745 case types.TSTRUCT:
746 var off int64
747 for _, f := range t.Fields() {
748 if f.Sym.IsBlank() {
749 continue
750 }
751 if off < f.Offset {
752 e.skip(f.Offset - off)
753 }
754 e.build(f.Type)
755 off = f.Offset + f.Type.Size()
756 }
757 if off < t.Size() {
758 e.skip(t.Size() - off)
759 }
760 case types.TARRAY:
761 if types.AlgType(t) == types.AMEM {
762
763
764
765
766 e.regular(t.Size())
767 break
768 }
769 et := t.Elem()
770 n := t.NumElem()
771 switch n {
772 case 0:
773 case 1:
774 e.build(et)
775 default:
776
777
778
779
780
781
782
783
784
785
786
787 const unrollSize = 32
788 if et.Size() == 0 {
789 break
790 }
791 unroll := max(1, unrollSize/et.Size())
792
793 for n%unroll != 0 {
794 e.build(et)
795 n--
796 }
797 if n == 0 {
798 break
799 }
800
801 if n == unroll {
802 for range n {
803 e.build(et)
804 }
805 break
806 }
807 e.flush(false)
808 e.r.WriteString(fmt.Sprintf("%c%d", sigArrayStart, n/unroll))
809 for range unroll {
810 e.build(et)
811 }
812 e.flush(false)
813 e.r.WriteByte(sigArrayEnd)
814 }
815 default:
816 base.Fatalf("eqSigBuilder %v", t)
817 }
818 }
819
820
821 func parseNum(s string) (int64, string) {
822 n := 0
823 for n < len(s) && s[n] >= '0' && s[n] <= '9' {
824 n++
825 }
826 x, err := strconv.ParseInt(s[:n], 10, 64)
827 if err != nil {
828 base.Fatalf("bad integer: %s", s[:n])
829 }
830 return x, s[n:]
831 }
832
833
834
835
836 func parseArray(sig string) (int64, string, string) {
837 var n int64
838 n, sig = parseNum(sig)
839
840 i := 0
841 depth := 1
842 for {
843 if i == len(sig) {
844 base.Fatalf("mismatched brackets in %s", sig)
845 }
846 switch sig[i] {
847 case sigArrayStart:
848 depth++
849 case sigArrayEnd:
850 depth--
851 if depth == 0 {
852 return n, sig[:i], sig[i+1:]
853 }
854 }
855 i++
856 }
857 }
858
859
860 func sigSize(sig string) int64 {
861 var size int64
862 for len(sig) > 0 {
863 kind := sig[0]
864 sig = sig[1:]
865 switch kind {
866 case sigMemory, sigSkip:
867 var n int64
868 n, sig = parseNum(sig)
869 size += n
870 case sigFloat32:
871 size += 4
872 case sigFloat64:
873 size += 8
874 case sigString, sigIface, sigEface:
875 size += 2 * int64(types.PtrSize)
876 case sigArrayStart:
877 var n int64
878 var elemSig string
879 n, elemSig, sig = parseArray(sig)
880 size += n * sigSize(elemSig)
881 }
882 }
883 return size
884 }
885
886 func sigTrimSkip(s string) string {
887 i := strings.LastIndexByte(s, sigSkip)
888 if i < 0 {
889 return s
890 }
891 for j := i + 1; j < len(s); j++ {
892 if s[j] < '0' || s[j] > '9' {
893 return s
894 }
895 }
896 return s[:i]
897 }
898
View as plain text