Args: int64(info.Args),
Frame: int64(info.Locals),
NoSplit: info.NoSplit != 0,
- Leaf: info.Flags&goobj2.FuncFlagLeaf != 0,
- TopFrame: info.Flags&goobj2.FuncFlagTopFrame != 0,
+ Leaf: osym.Flag&goobj2.SymFlagLeaf != 0,
+ TopFrame: osym.Flag&goobj2.SymFlagTopFrame != 0,
PCSP: Data{int64(pcdataBase + info.Pcsp), int64(info.Pcfile - info.Pcsp)},
PCFile: Data{int64(pcdataBase + info.Pcfile), int64(info.Pcline - info.Pcfile)},
PCLine: Data{int64(pcdataBase + info.Pcline), int64(info.Pcinline - info.Pcline)},
// TODO: make each pcdata a separate symbol?
type FuncInfo struct {
NoSplit uint8
- Flags uint8
Args uint32
Locals uint32
// TODO: InlTree
}
-const (
- FuncFlagLeaf = 1 << iota
- FuncFlagCFunc
- FuncFlagReflectMethod
- FuncFlagShared // This is really silly
- FuncFlagTopFrame
-)
-
func (a *FuncInfo) Write(w *bytes.Buffer) {
w.WriteByte(a.NoSplit)
- w.WriteByte(a.Flags)
var b [4]byte
writeUint32 := func(x uint32) {
func (a *FuncInfo) Read(b []byte) {
a.NoSplit = b[0]
- a.Flags = b[1]
- b = b[2:]
+ b = b[1:]
readUint32 := func() uint32 {
x := binary.LittleEndian.Uint32(b)
SymFlagDupok = 1 << iota
SymFlagLocal
SymFlagTypelink
+ SymFlagLeaf
+ SymFlagCFunc
+ SymFlagReflectMethod
+ SymFlagShared // This is really silly
+ SymFlagTopFrame
)
func (s *Sym) Write(w *Writer) {
if s.MakeTypelink() {
flag |= goobj2.SymFlagTypelink
}
+ if s.Leaf() {
+ flag |= goobj2.SymFlagLeaf
+ }
+ if s.CFunc() {
+ flag |= goobj2.SymFlagCFunc
+ }
+ if s.ReflectMethod() {
+ flag |= goobj2.SymFlagReflectMethod
+ }
+ if w.ctxt.Flag_shared { // This is really silly
+ flag |= goobj2.SymFlagShared
+ }
+ if s.TopFrame() {
+ flag |= goobj2.SymFlagTopFrame
+ }
o := goobj2.Sym{
Name: s.Name,
ABI: abi,
if s.NoSplit() {
nosplit = 1
}
- flags := uint8(0)
- if s.Leaf() {
- flags |= goobj2.FuncFlagLeaf
- }
- if s.CFunc() {
- flags |= goobj2.FuncFlagCFunc
- }
- if s.ReflectMethod() {
- flags |= goobj2.FuncFlagReflectMethod
- }
- if ctxt.Flag_shared { // This is really silly
- flags |= goobj2.FuncFlagShared
- }
- if s.TopFrame() {
- flags |= goobj2.FuncFlagTopFrame
- }
o := goobj2.FuncInfo{
NoSplit: nosplit,
- Flags: flags,
Args: uint32(s.Func.Args),
Locals: uint32(s.Func.Locals),
}
var _ = fmt.Print
// TODO:
-// - Live method tracking:
-// The special handling of reflect.Type.Method has not
-// been implemented.
// - Shared object support:
// It basically marks everything. We could consider using
// a different mechanism to represent it.
ifaceMethod map[methodsig]bool // methods declared in reached interfaces
markableMethods []methodref2 // methods of reached types
- reflectMethod bool // TODO: this is not set for now
+ reflectSeen bool // whether we have seen a reflect method call
}
func (d *deadcodePass2) init() {
for !d.wq.empty() {
symIdx := d.wq.pop()
+ d.reflectSeen = d.reflectSeen || d.loader.IsReflectMethod(symIdx)
+
name := d.loader.RawSymName(symIdx)
if strings.HasPrefix(name, "type.") && name[5] != '.' { // TODO: use an attribute instead of checking name
p := d.loader.Data(symIdx)
callSym := loader.Lookup("reflect.Value.Call", sym.SymVerABIInternal)
methSym := loader.Lookup("reflect.Value.Method", sym.SymVerABIInternal)
- reflectSeen := false
if ctxt.DynlinkingGo() {
// Exported methods may satisfy interfaces we don't know
// about yet when dynamically linking.
- reflectSeen = true
+ d.reflectSeen = true
}
for {
- if !reflectSeen {
- if d.reflectMethod || (callSym != 0 && loader.Reachable.Has(callSym)) || (methSym != 0 && loader.Reachable.Has(methSym)) {
- // Methods might be called via reflection. Give up on
- // static analysis, mark all exported methods of
- // all reachable types as reachable.
- reflectSeen = true
- }
- }
+ // Methods might be called via reflection. Give up on
+ // static analysis, mark all exported methods of
+ // all reachable types as reachable.
+ d.reflectSeen = d.reflectSeen || (callSym != 0 && loader.Reachable.Has(callSym)) || (methSym != 0 && loader.Reachable.Has(methSym))
// Mark all methods that could satisfy a discovered
// interface as reachable. We recheck old marked interfaces
// in the last pass.
rem := d.markableMethods[:0]
for _, m := range d.markableMethods {
- if (reflectSeen && m.isExported()) || d.ifaceMethod[m.m] {
+ if (d.reflectSeen && m.isExported()) || d.ifaceMethod[m.m] {
d.markMethod(m)
} else {
rem = append(rem, m)
return sym.AbiSymKindToSymKind[objabi.SymKind(osym.Type)]
}
+// Returns the attributes of the i-th symbol.
+func (l *Loader) SymAttr(i Sym) uint8 {
+ if l.extStart != 0 && i >= l.extStart {
+ return 0
+ }
+ r, li := l.ToLocal(i)
+ osym := goobj2.Sym{}
+ osym.Read(r.Reader, r.SymOff(li))
+ return osym.Flag
+}
+
+// Returns whether the i-th symbol has ReflectMethod attribute set.
+func (l *Loader) IsReflectMethod(i Sym) bool {
+ return l.SymAttr(i)&goobj2.SymFlagReflectMethod != 0
+}
+
// Returns the symbol content of the i-th symbol. i is global index.
func (l *Loader) Data(i Sym) []byte {
if l.extStart != 0 && i >= l.extStart {
if info.NoSplit != 0 {
s.Attr |= sym.AttrNoSplit
}
- if info.Flags&goobj2.FuncFlagReflectMethod != 0 {
+ if osym.Flag&goobj2.SymFlagReflectMethod != 0 {
s.Attr |= sym.AttrReflectMethod
}
- if info.Flags&goobj2.FuncFlagShared != 0 {
+ if osym.Flag&goobj2.SymFlagShared != 0 {
s.Attr |= sym.AttrShared
}
- if info.Flags&goobj2.FuncFlagTopFrame != 0 {
+ if osym.Flag&goobj2.SymFlagTopFrame != 0 {
s.Attr |= sym.AttrTopFrame
}