MAXELEMSIZE = 128
)
-func structfieldSize() int { return 3 * Widthptr } // Sizeof(runtime.structfield{})
-func imethodSize() int { return 4 + 4 } // Sizeof(runtime.imethod{})
+func structfieldSize() int { return 3 * Widthptr } // Sizeof(runtime.structfield{})
+func imethodSize() int { return 4 + 4 } // Sizeof(runtime.imethod{})
+func commonSize() int { return 4*Widthptr + 8 + 8 } // Sizeof(runtime._type{})
func uncommonSize(t *types.Type) int { // Sizeof(runtime.uncommontype{})
if t.Sym == nil && len(methods(t)) == 0 {
return lsym
}
+// ifaceMethodOffset returns the offset of the i-th method in the interface
+// type descriptor, ityp.
+func ifaceMethodOffset(ityp *types.Type, i int64) int64 {
+ // interface type descriptor layout is struct {
+ // _type // commonSize
+ // pkgpath // 1 word
+ // []imethod // 3 words (pointing to [...]imethod below)
+ // uncommontype // uncommonSize
+ // [...]imethod
+ // }
+ // The size of imethod is 8.
+ return int64(commonSize()+4*Widthptr+uncommonSize(ityp)) + i*8
+}
+
// for each itabEntry, gather the methods on
// the concrete type that implement the interface
func peekitabs() {
case OCALLINTER, OCALLFUNC, OCALLMETH:
if n.Op == OCALLINTER {
usemethod(n)
+ markUsedIfaceMethod(n)
}
if n.Op == OCALLFUNC && n.Left.Op == OCLOSURE {
r.Type = objabi.R_USEIFACE
}
+// markUsedIfaceMethod marks that an interface method is used in the current
+// function. n is OCALLINTER node.
+func markUsedIfaceMethod(n *Node) {
+ ityp := n.Left.Left.Type
+ tsym := typenamesym(ityp).Linksym()
+ r := obj.Addrel(Curfn.Func.lsym)
+ r.Sym = tsym
+ // n.Left.Xoffset is the method index * Widthptr (the offset of code pointer
+ // in itab).
+ midx := n.Left.Xoffset / int64(Widthptr)
+ r.Add = ifaceMethodOffset(ityp, midx)
+ r.Type = objabi.R_USEIFACEMETHOD
+}
+
// rtconvfn returns the parameter and result types that will be used by a
// runtime function to convert from type src to type dst. The runtime function
// name can be derived from the names of the returned types.
// This is a marker relocation (0-sized), for the linker's reachabililty
// analysis.
R_USEIFACE
+ // R_USEIFACEMETHOD marks an interface method that is used in the function
+ // this relocation is applied to. The target is an interface type descriptor.
+ // The addend is the offset of the method in the type descriptor.
+ // This is a marker relocation (0-sized), for the linker's reachabililty
+ // analysis.
+ R_USEIFACEMETHOD
// R_METHODOFF resolves to a 32-bit offset from the beginning of the section
// holding the data being relocated to the referenced symbol.
// It is a variant of R_ADDROFF used when linking from the uncommonType of a
_ = x[R_USEFIELD-23]
_ = x[R_USETYPE-24]
_ = x[R_USEIFACE-25]
- _ = x[R_METHODOFF-26]
- _ = x[R_POWER_TOC-27]
- _ = x[R_GOTPCREL-28]
- _ = x[R_JMPMIPS-29]
- _ = x[R_DWARFSECREF-30]
- _ = x[R_DWARFFILEREF-31]
- _ = x[R_ARM64_TLS_LE-32]
- _ = x[R_ARM64_TLS_IE-33]
- _ = x[R_ARM64_GOTPCREL-34]
- _ = x[R_ARM64_GOT-35]
- _ = x[R_ARM64_PCREL-36]
- _ = x[R_ARM64_LDST8-37]
- _ = x[R_ARM64_LDST32-38]
- _ = x[R_ARM64_LDST64-39]
- _ = x[R_ARM64_LDST128-40]
- _ = x[R_POWER_TLS_LE-41]
- _ = x[R_POWER_TLS_IE-42]
- _ = x[R_POWER_TLS-43]
- _ = x[R_ADDRPOWER_DS-44]
- _ = x[R_ADDRPOWER_GOT-45]
- _ = x[R_ADDRPOWER_PCREL-46]
- _ = x[R_ADDRPOWER_TOCREL-47]
- _ = x[R_ADDRPOWER_TOCREL_DS-48]
- _ = x[R_RISCV_PCREL_ITYPE-49]
- _ = x[R_RISCV_PCREL_STYPE-50]
- _ = x[R_PCRELDBL-51]
- _ = x[R_ADDRMIPSU-52]
- _ = x[R_ADDRMIPSTLS-53]
- _ = x[R_ADDRCUOFF-54]
- _ = x[R_WASMIMPORT-55]
- _ = x[R_XCOFFREF-56]
+ _ = x[R_USEIFACEMETHOD-26]
+ _ = x[R_METHODOFF-27]
+ _ = x[R_POWER_TOC-28]
+ _ = x[R_GOTPCREL-29]
+ _ = x[R_JMPMIPS-30]
+ _ = x[R_DWARFSECREF-31]
+ _ = x[R_DWARFFILEREF-32]
+ _ = x[R_ARM64_TLS_LE-33]
+ _ = x[R_ARM64_TLS_IE-34]
+ _ = x[R_ARM64_GOTPCREL-35]
+ _ = x[R_ARM64_GOT-36]
+ _ = x[R_ARM64_PCREL-37]
+ _ = x[R_ARM64_LDST8-38]
+ _ = x[R_ARM64_LDST32-39]
+ _ = x[R_ARM64_LDST64-40]
+ _ = x[R_ARM64_LDST128-41]
+ _ = x[R_POWER_TLS_LE-42]
+ _ = x[R_POWER_TLS_IE-43]
+ _ = x[R_POWER_TLS-44]
+ _ = x[R_ADDRPOWER_DS-45]
+ _ = x[R_ADDRPOWER_GOT-46]
+ _ = x[R_ADDRPOWER_PCREL-47]
+ _ = x[R_ADDRPOWER_TOCREL-48]
+ _ = x[R_ADDRPOWER_TOCREL_DS-49]
+ _ = x[R_RISCV_PCREL_ITYPE-50]
+ _ = x[R_RISCV_PCREL_STYPE-51]
+ _ = x[R_PCRELDBL-52]
+ _ = x[R_ADDRMIPSU-53]
+ _ = x[R_ADDRMIPSTLS-54]
+ _ = x[R_ADDRCUOFF-55]
+ _ = x[R_WASMIMPORT-56]
+ _ = x[R_XCOFFREF-57]
}
-const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF"
+const _RelocType_name = "R_ADDRR_ADDRPOWERR_ADDRARM64R_ADDRMIPSR_ADDROFFR_WEAKADDROFFR_SIZER_CALLR_CALLARMR_CALLARM64R_CALLINDR_CALLPOWERR_CALLMIPSR_CALLRISCVR_CONSTR_PCRELR_TLS_LER_TLS_IER_GOTOFFR_PLT0R_PLT1R_PLT2R_USEFIELDR_USETYPER_USEIFACER_USEIFACEMETHODR_METHODOFFR_POWER_TOCR_GOTPCRELR_JMPMIPSR_DWARFSECREFR_DWARFFILEREFR_ARM64_TLS_LER_ARM64_TLS_IER_ARM64_GOTPCRELR_ARM64_GOTR_ARM64_PCRELR_ARM64_LDST8R_ARM64_LDST32R_ARM64_LDST64R_ARM64_LDST128R_POWER_TLS_LER_POWER_TLS_IER_POWER_TLSR_ADDRPOWER_DSR_ADDRPOWER_GOTR_ADDRPOWER_PCRELR_ADDRPOWER_TOCRELR_ADDRPOWER_TOCREL_DSR_RISCV_PCREL_ITYPER_RISCV_PCREL_STYPER_PCRELDBLR_ADDRMIPSUR_ADDRMIPSTLSR_ADDRCUOFFR_WASMIMPORTR_XCOFFREF"
-var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 133, 140, 147, 155, 163, 171, 177, 183, 189, 199, 208, 218, 229, 240, 250, 259, 272, 286, 300, 314, 330, 341, 354, 367, 381, 395, 410, 424, 438, 449, 463, 478, 495, 513, 534, 553, 572, 582, 593, 606, 617, 629, 639}
+var _RelocType_index = [...]uint16{0, 6, 17, 28, 38, 47, 60, 66, 72, 81, 92, 101, 112, 122, 133, 140, 147, 155, 163, 171, 177, 183, 189, 199, 208, 218, 234, 245, 256, 266, 275, 288, 302, 316, 330, 346, 357, 370, 383, 397, 411, 426, 440, 454, 465, 479, 494, 511, 529, 550, 569, 588, 598, 609, 622, 633, 645, 655}
func (i RelocType) String() string {
i -= 1
if isgotype {
usedInIface = d.ldr.AttrUsedInIface(symIdx)
- p := d.ldr.Data(symIdx)
- if len(p) != 0 && decodetypeKind(d.ctxt.Arch, p)&kindMask == kindInterface {
- for _, sig := range d.decodeIfaceMethods(d.ldr, d.ctxt.Arch, symIdx, &relocs) {
- if d.ctxt.Debugvlog > 1 {
- d.ctxt.Logf("reached iface method: %v\n", sig)
- }
- d.ifaceMethod[sig] = true
- }
- }
}
methods = methods[:0]
for i := 0; i < relocs.Count(); i++ {
r := relocs.At(i)
t := r.Type()
- if t == objabi.R_WEAKADDROFF {
+ switch t {
+ case objabi.R_WEAKADDROFF:
continue
- }
- if t == objabi.R_METHODOFF {
+ case objabi.R_METHODOFF:
if i+2 >= relocs.Count() {
panic("expect three consecutive R_METHODOFF relocs")
}
}
i += 2
continue
- }
- if t == objabi.R_USETYPE {
+ case objabi.R_USETYPE:
// type symbol used for DWARF. we need to load the symbol but it may not
// be otherwise reachable in the program.
// do nothing for now as we still load all type symbols.
continue
- }
- if t == objabi.R_USEIFACE {
+ case objabi.R_USEIFACE:
// R_USEIFACE is a marker relocation that tells the linker the type is
// converted to an interface, i.e. should have UsedInIface set. See the
// comment below for why we need to unset the Reachable bit and re-mark it.
}
}
continue
+ case objabi.R_USEIFACEMETHOD:
+ // R_USEIFACEMETHOD is a marker relocation that marks an interface
+ // method as used.
+ rs := r.Sym()
+ if d.ldr.SymType(rs) != sym.SDYNIMPORT { // don't decode DYNIMPORT symbol (we'll mark all exported methods anyway)
+ m := d.decodeIfaceMethod(d.ldr, d.ctxt.Arch, rs, r.Add())
+ if d.ctxt.Debugvlog > 1 {
+ d.ctxt.Logf("reached iface method: %v\n", m)
+ }
+ d.ifaceMethod[m] = true
+ }
+ continue
}
rs := r.Sym()
if isgotype && usedInIface && d.ldr.IsGoType(rs) && !d.ldr.AttrUsedInIface(rs) {
return methods
}
-func (d *deadcodePass) decodeIfaceMethods(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs) []methodsig {
+// Decode the method of interface type symbol symIdx at offset off.
+func (d *deadcodePass) decodeIfaceMethod(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, off int64) methodsig {
p := ldr.Data(symIdx)
if decodetypeKind(arch, p)&kindMask != kindInterface {
panic(fmt.Sprintf("symbol %q is not an interface", ldr.SymName(symIdx)))
}
- rel := decodeReloc(ldr, symIdx, relocs, int32(commonsize(arch)+arch.PtrSize))
- s := rel.Sym()
- if s == 0 {
- return nil
- }
- if s != symIdx {
- panic(fmt.Sprintf("imethod slice pointer in %q leads to a different symbol", ldr.SymName(symIdx)))
- }
- off := int(rel.Add()) // array of reflect.imethod values
- numMethods := int(decodetypeIfaceMethodCount(arch, p))
- sizeofIMethod := 4 + 4
- return d.decodeMethodSig(ldr, arch, symIdx, relocs, off, sizeofIMethod, numMethods)
+ relocs := ldr.Relocs(symIdx)
+ var m methodsig
+ m.name = decodetypeName(ldr, symIdx, &relocs, int(off))
+ m.typ = decodeRelocSym(ldr, symIdx, &relocs, int32(off+4))
+ return m
}
func (d *deadcodePass) decodetypeMethods(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, relocs *loader.Relocs) []methodsig {
{"ifacemethod", "", "main.T.M"},
{"ifacemethod2", "main.T.M", ""},
{"ifacemethod3", "main.S.M", ""},
+ {"ifacemethod4", "", "main.T.M"},
}
for _, test := range tests {
test := test
--- /dev/null
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Test that a live type's method is not live even if
+// it matches an interface method, as long as the interface
+// method is not used.
+
+package main
+
+type T int
+
+func (T) M() {}
+
+type I interface{ M() }
+
+var p *T
+var pp *I
+
+func main() {
+ p = new(T) // use type T
+ pp = new(I) // use type I
+}