summaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/gc/reflect.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/compile/internal/gc/reflect.go')
-rw-r--r--src/cmd/compile/internal/gc/reflect.go82
1 files changed, 81 insertions, 1 deletions
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
index 57302b50af..803bad6257 100644
--- a/src/cmd/compile/internal/gc/reflect.go
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -16,6 +16,15 @@ import (
type itabEntry struct {
t, itype *Type
sym *Sym
+
+ // symbol of the itab itself;
+ // filled in lazily after typecheck
+ lsym *obj.LSym
+
+ // symbols of each method in
+ // the itab, sorted by byte offset;
+ // filled in at the same time as lsym
+ entries []*obj.LSym
}
type ptabEntry struct {
@@ -415,7 +424,6 @@ func imethods(t *Type) []*Sig {
// Generate the method body, so that compiled
// code can refer to it.
isym := methodsym(method, t, 0)
-
if !isym.Siggen() {
isym.SetSiggen(true)
genwrapper(t, f, isym, 0)
@@ -1379,6 +1387,78 @@ ok:
return s
}
+// for each itabEntry, gather the methods on
+// the concrete type that implement the interface
+func peekitabs() {
+ for i := range itabs {
+ tab := &itabs[i]
+ methods := genfun(tab.t, tab.itype)
+ if len(methods) == 0 {
+ continue
+ }
+ tab.lsym = Linksym(tab.sym)
+ tab.entries = methods
+ }
+}
+
+// for the given concrete type and interface
+// type, return the (sorted) set of methods
+// on the concrete type that implement the interface
+func genfun(t, it *Type) []*obj.LSym {
+ if t == nil || it == nil {
+ return nil
+ }
+ sigs := imethods(it)
+ methods := methods(t)
+ out := make([]*obj.LSym, 0, len(sigs))
+ if len(sigs) == 0 {
+ return nil
+ }
+
+ // both sigs and methods are sorted by name,
+ // so we can find the intersect in a single pass
+ for _, m := range methods {
+ if m.name == sigs[0].name {
+ out = append(out, Linksym(m.isym))
+ sigs = sigs[1:]
+ if len(sigs) == 0 {
+ break
+ }
+ }
+ }
+
+ return out
+}
+
+// itabsym uses the information gathered in
+// peekitabs to de-virtualize interface methods.
+// Since this is called by the SSA backend, it shouldn't
+// generate additional Nodes, Syms, etc.
+func itabsym(it *obj.LSym, offset int64) *obj.LSym {
+ var syms []*obj.LSym
+ if it == nil {
+ return nil
+ }
+
+ for i := range itabs {
+ e := &itabs[i]
+ if e.lsym == it {
+ syms = e.entries
+ break
+ }
+ }
+ if syms == nil {
+ return nil
+ }
+
+ // keep this arithmetic in sync with *itab layout
+ methodnum := int((offset - 3*int64(Widthptr) - 8) / int64(Widthptr))
+ if methodnum >= len(syms) {
+ return nil
+ }
+ return syms[methodnum]
+}
+
func dumptypestructs() {
// copy types from externdcl list to signatlist
for _, n := range externdcl {