@@ -16,6 +16,11 @@ import (
16
16
type itabEntry struct {
17
17
t , itype * Type
18
18
sym * Sym
19
+ lsym * obj.LSym
20
+
21
+ // symbols of each method in
22
+ // the itab, sorted by byte offset
23
+ entries []* obj.LSym
19
24
}
20
25
21
26
type ptabEntry struct {
@@ -78,7 +83,7 @@ const (
78
83
func structfieldSize () int { return 3 * Widthptr } // Sizeof(runtime.structfield{})
79
84
func imethodSize () int { return 4 + 4 } // Sizeof(runtime.imethod{})
80
85
func uncommonSize (t * Type ) int { // Sizeof(runtime.uncommontype{})
81
- if t .Sym == nil && len (methods (t )) == 0 {
86
+ if t .Sym == nil && len (methods (t , true )) == 0 {
82
87
return 0
83
88
}
84
89
return 4 + 2 + 2 + 4 + 4
@@ -287,8 +292,8 @@ func methodfunc(f *Type, receiver *Type) *Type {
287
292
}
288
293
289
294
// methods returns the methods of the non-interface type t, sorted by name.
290
- // Generates stub functions as needed.
291
- func methods (t * Type ) []* Sig {
295
+ // If gen is true, generates stub functions as needed.
296
+ func methods (t * Type , gen bool ) []* Sig {
292
297
// method type
293
298
mt := methtype (t )
294
299
@@ -352,7 +357,7 @@ func methods(t *Type) []*Sig {
352
357
sig .type_ = methodfunc (f .Type , t )
353
358
sig .mtype = methodfunc (f .Type , nil )
354
359
355
- if ! sig .isym .Siggen () {
360
+ if gen && ! sig .isym .Siggen () {
356
361
sig .isym .SetSiggen (true )
357
362
if ! eqtype (this , it ) || this .Width < Types [Tptr ].Width {
358
363
compiling_wrappers = 1
@@ -361,7 +366,7 @@ func methods(t *Type) []*Sig {
361
366
}
362
367
}
363
368
364
- if ! sig .tsym .Siggen () {
369
+ if gen && ! sig .tsym .Siggen () {
365
370
sig .tsym .SetSiggen (true )
366
371
if ! eqtype (this , t ) {
367
372
compiling_wrappers = 1
@@ -376,7 +381,8 @@ func methods(t *Type) []*Sig {
376
381
}
377
382
378
383
// imethods returns the methods of the interface type t, sorted by name.
379
- func imethods (t * Type ) []* Sig {
384
+ // If gen is false, then wrappers are not eagerly generated.
385
+ func imethods (t * Type , gen bool ) []* Sig {
380
386
var methods []* Sig
381
387
for _ , f := range t .Fields ().Slice () {
382
388
if f .Type .Etype != TFUNC || f .Sym == nil {
@@ -416,7 +422,7 @@ func imethods(t *Type) []*Sig {
416
422
// code can refer to it.
417
423
isym := methodsym (method , t , 0 )
418
424
419
- if ! isym .Siggen () {
425
+ if gen && ! isym .Siggen () {
420
426
isym .SetSiggen (true )
421
427
genwrapper (t , f , isym , 0 )
422
428
}
@@ -602,7 +608,7 @@ func dname(name, tag string, pkg *Pkg, exported bool) *obj.LSym {
602
608
// dataAdd is the offset in bytes after the header where the
603
609
// backing array of the []method field is written (by dextratypeData).
604
610
func dextratype (s * Sym , ot int , t * Type , dataAdd int ) int {
605
- m := methods (t )
611
+ m := methods (t , true )
606
612
if t .Sym == nil && len (m ) == 0 {
607
613
return ot
608
614
}
@@ -653,7 +659,7 @@ func typePkg(t *Type) *Pkg {
653
659
// runtime.uncommontype.
654
660
func dextratypeData (s * Sym , ot int , t * Type ) int {
655
661
lsym := Linksym (s )
656
- for _ , a := range methods (t ) {
662
+ for _ , a := range methods (t , true ) {
657
663
// ../../../../runtime/type.go:/method
658
664
exported := exportname (a .name )
659
665
var pkg * Pkg
@@ -838,7 +844,7 @@ func dcommontype(s *Sym, ot int, t *Type) int {
838
844
var sptr * Sym
839
845
if ! t .IsPtr () || t .ptrTo != nil {
840
846
tptr := ptrto (t )
841
- if t .Sym != nil || methods (tptr ) != nil {
847
+ if t .Sym != nil || methods (tptr , true ) != nil {
842
848
sptrWeak = false
843
849
}
844
850
sptr = dtypesym (tptr )
@@ -992,7 +998,7 @@ func typename(t *Type) *Node {
992
998
return n
993
999
}
994
1000
995
- func itabname (t , itype * Type ) * Node {
1001
+ func itabname (t , itype * Type , genimpl bool ) * Node {
996
1002
if t == nil || (t .IsPtr () && t .Elem () == nil ) || t .IsUntyped () || ! itype .IsInterface () || itype .IsEmptyInterface () {
997
1003
Fatalf ("itabname(%v, %v)" , t , itype )
998
1004
}
@@ -1004,7 +1010,18 @@ func itabname(t, itype *Type) *Node {
1004
1010
n .Typecheck = 1
1005
1011
s .Def = n
1006
1012
1007
- itabs = append (itabs , itabEntry {t : t , itype : itype , sym : s })
1013
+ var methods []* obj.LSym
1014
+ if genimpl {
1015
+ methods = genfun (t , itype )
1016
+ }
1017
+
1018
+ itabs = append (itabs , itabEntry {
1019
+ t : t ,
1020
+ itype : itype ,
1021
+ sym : s ,
1022
+ lsym : Linksym (s ),
1023
+ entries : methods ,
1024
+ })
1008
1025
}
1009
1026
1010
1027
n := nod (OADDR , s .Def , nil )
@@ -1224,7 +1241,7 @@ ok:
1224
1241
}
1225
1242
1226
1243
case TINTER :
1227
- m := imethods (t )
1244
+ m := imethods (t , true )
1228
1245
n := len (m )
1229
1246
for _ , a := range m {
1230
1247
dtypesym (a .type_ )
@@ -1379,6 +1396,64 @@ ok:
1379
1396
return s
1380
1397
}
1381
1398
1399
+ // calculate the set of concrete implementations
1400
+ // for each entry in the itab
1401
+ // given by the type/interface pair
1402
+ func genfun (t , it * Type ) []* obj.LSym {
1403
+ if t == nil || it == nil {
1404
+ return nil
1405
+ }
1406
+ sigs := imethods (it , false )
1407
+ methods := methods (t , false )
1408
+ out := make ([]* obj.LSym , 0 , len (sigs ))
1409
+ if len (sigs ) == 0 {
1410
+ return nil
1411
+ }
1412
+
1413
+ // both sigs and methods are sorted by name,
1414
+ // so we can find the intersect in a single pass
1415
+ for _ , m := range methods {
1416
+ if m .name == sigs [0 ].name {
1417
+ out = append (out , Linksym (m .isym ))
1418
+ sigs = sigs [1 :]
1419
+ if len (sigs ) == 0 {
1420
+ break
1421
+ }
1422
+ }
1423
+ }
1424
+
1425
+ return out
1426
+ }
1427
+
1428
+ // itabsym is used by the SSA backend
1429
+ // to convert interface calls into static calls;
1430
+ // it deliberately doesn't create any additional Nodes, Syms, etc.
1431
+ func itabsym (it * obj.LSym , offset int64 ) * obj.LSym {
1432
+ var syms []* obj.LSym
1433
+
1434
+ // TODO: something that isn't O(itabs)?
1435
+ // We expect this lookup to occur
1436
+ // infrequently in practice; perhaps
1437
+ // this is offset by O(1) itab creation.
1438
+ for i := range itabs {
1439
+ e := & itabs [i ]
1440
+ if e .lsym == it {
1441
+ syms = e .entries
1442
+ break
1443
+ }
1444
+ }
1445
+ if syms == nil {
1446
+ return nil
1447
+ }
1448
+
1449
+ // keep this arithmetic in sync with *itab layout
1450
+ methodnum := int ((offset - 3 * int64 (Widthptr ) - 8 ) / int64 (Widthptr ))
1451
+ if methodnum >= len (syms ) {
1452
+ return nil
1453
+ }
1454
+ return syms [methodnum ]
1455
+ }
1456
+
1382
1457
func dumptypestructs () {
1383
1458
// copy types from externdcl list to signatlist
1384
1459
for _ , n := range externdcl {
@@ -1417,10 +1492,10 @@ func dumptypestructs() {
1417
1492
// }
1418
1493
o := dsymptr (i .sym , 0 , dtypesym (i .itype ), 0 )
1419
1494
o = dsymptr (i .sym , o , dtypesym (i .t ), 0 )
1420
- o += Widthptr // skip link field
1421
- o = duint32 (i .sym , o , typehash (i .t )) // copy of type hash
1422
- o += 4 // skip bad/inhash/unused fields
1423
- o += len (imethods (i .itype )) * Widthptr // skip fun method pointers
1495
+ o += Widthptr // skip link field
1496
+ o = duint32 (i .sym , o , typehash (i .t )) // copy of type hash
1497
+ o += 4 // skip bad/inhash/unused fields
1498
+ o += len (imethods (i .itype , true )) * Widthptr // skip fun method pointers
1424
1499
// at runtime the itab will contain pointers to types, other itabs and
1425
1500
// method functions. None are allocated on heap, so we can use obj.NOPTR.
1426
1501
ggloblsym (i .sym , int32 (o ), int16 (obj .DUPOK | obj .NOPTR ))
0 commit comments