Instead, cmd/compile can directly emit R_USEFIELD relocations.
Manually verified rsc.io/tmp/fieldtrack still passes.
Change-Id: Ib1fb5ab902ff0ad17ef6a862a9a5692caf7f87d1
Reviewed-on: https://go-review.googlesource.com/37871
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
obj.AFUNCDATA: {Flags: gc.Pseudo},
obj.APCDATA: {Flags: gc.Pseudo},
obj.AUNDEF: {Flags: gc.Break},
- obj.AUSEFIELD: {Flags: gc.OK},
obj.AVARDEF: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARKILL: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARLIVE: {Flags: gc.Pseudo | gc.LeftRead},
obj.AFUNCDATA: {Flags: gc.Pseudo},
obj.APCDATA: {Flags: gc.Pseudo},
obj.AUNDEF: {Flags: gc.Break},
- obj.AUSEFIELD: {Flags: gc.OK},
obj.AVARDEF: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARKILL: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARLIVE: {Flags: gc.Pseudo | gc.LeftRead},
obj.AFUNCDATA: {Flags: gc.Pseudo},
obj.APCDATA: {Flags: gc.Pseudo},
obj.AUNDEF: {Flags: gc.Break},
- obj.AUSEFIELD: {Flags: gc.OK},
obj.AVARDEF: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARKILL: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARLIVE: {Flags: gc.Pseudo | gc.LeftRead},
Ctxt.Globl(s, int64(width), int(flags))
}
-func gtrack(s *Sym) {
- p := Gins(obj.AUSEFIELD, nil, nil)
- p.From.Type = obj.TYPE_MEM
- p.From.Name = obj.NAME_EXTERN
- p.From.Sym = Linksym(s)
-}
-
func isfat(t *Type) bool {
if t != nil {
switch t.Etype {
// Gins inserts instruction as. f is from, t is to.
func Gins(as obj.As, f, t *Node) *obj.Prog {
switch as {
- case obj.AVARKILL, obj.AVARLIVE, obj.AVARDEF,
- obj.ATEXT, obj.AFUNCDATA, obj.AUSEFIELD:
+ case obj.AVARKILL, obj.AVARLIVE, obj.AVARDEF, obj.ATEXT, obj.AFUNCDATA:
default:
Fatalf("unhandled gins op %v", as)
}
nam = nil
}
ptxt := Gins(obj.ATEXT, nam, nil)
+ fnsym := ptxt.From.Sym
+
ptxt.From3 = new(obj.Addr)
if fn.Func.Dupok() {
ptxt.From3.Offset |= obj.DUPOK
gcargs := makefuncdatasym("gcargs·", obj.FUNCDATA_ArgsPointerMaps)
gclocals := makefuncdatasym("gclocals·", obj.FUNCDATA_LocalsPointerMaps)
- if obj.Fieldtrack_enabled != 0 && len(Curfn.Func.FieldTrack) > 0 {
- trackSyms := make([]*Sym, 0, len(Curfn.Func.FieldTrack))
- for sym := range Curfn.Func.FieldTrack {
- trackSyms = append(trackSyms, sym)
- }
- sort.Sort(symByName(trackSyms))
- for _, sym := range trackSyms {
- gtrack(sym)
- }
- }
-
- gendebug(ptxt.From.Sym, fn.Func.Dcl)
+ gendebug(fnsym, fn.Func.Dcl)
genssa(ssafn, ptxt, gcargs, gclocals)
ssafn.Free()
+
obj.Flushplist(Ctxt, plist) // convert from Prog list to machine code
+ ptxt = nil // nil to prevent misuse; Prog may have been freed by Flushplist
+
+ fieldtrack(fnsym, fn.Func.FieldTrack)
}
-func gendebug(fn *obj.LSym, decls []*Node) {
- if fn == nil {
+func gendebug(fnsym *obj.LSym, decls []*Node) {
+ if fnsym == nil {
return
}
Gotype: Linksym(ngotype(n)),
}
- a.Link = fn.Autom
- fn.Autom = a
+ a.Link = fnsym.Autom
+ fnsym.Autom = a
+ }
+}
+
+// fieldtrack adds R_USEFIELD relocations to fnsym to record any
+// struct fields that it used.
+func fieldtrack(fnsym *obj.LSym, tracked map[*Sym]struct{}) {
+ if fnsym == nil {
+ return
+ }
+ if obj.Fieldtrack_enabled == 0 || len(tracked) == 0 {
+ return
+ }
+
+ trackSyms := make([]*Sym, 0, len(tracked))
+ for sym := range tracked {
+ trackSyms = append(trackSyms, sym)
+ }
+ sort.Sort(symByName(trackSyms))
+ for _, sym := range trackSyms {
+ r := obj.Addrel(fnsym)
+ r.Sym = Linksym(sym)
+ r.Type = obj.R_USEFIELD
}
}
obj.AFUNCDATA: {Flags: gc.Pseudo},
obj.APCDATA: {Flags: gc.Pseudo},
obj.AUNDEF: {Flags: gc.Break},
- obj.AUSEFIELD: {Flags: gc.OK},
obj.AVARDEF: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARKILL: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARLIVE: {Flags: gc.Pseudo | gc.LeftRead},
obj.AFUNCDATA: {Flags: gc.Pseudo},
obj.APCDATA: {Flags: gc.Pseudo},
obj.AUNDEF: {Flags: gc.Break},
- obj.AUSEFIELD: {Flags: gc.OK},
obj.AVARDEF: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARKILL: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARLIVE: {Flags: gc.Pseudo | gc.LeftRead},
obj.AFUNCDATA: {Flags: gc.Pseudo},
obj.APCDATA: {Flags: gc.Pseudo},
obj.AUNDEF: {Flags: gc.Break},
- obj.AUSEFIELD: {Flags: gc.OK},
obj.AVARDEF: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARKILL: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARLIVE: {Flags: gc.Pseudo | gc.LeftRead},
obj.AFUNCDATA & obj.AMask: {Flags: gc.Pseudo},
obj.APCDATA & obj.AMask: {Flags: gc.Pseudo},
obj.AUNDEF & obj.AMask: {Flags: gc.Break},
- obj.AUSEFIELD & obj.AMask: {Flags: gc.OK},
obj.AVARDEF & obj.AMask: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARKILL & obj.AMask: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARLIVE & obj.AMask: {Flags: gc.Pseudo | gc.LeftRead},
obj.AFUNCDATA: {Flags: gc.Pseudo},
obj.APCDATA: {Flags: gc.Pseudo},
obj.AUNDEF: {Flags: gc.Break},
- obj.AUSEFIELD: {Flags: gc.OK},
obj.AVARDEF: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARKILL: {Flags: gc.Pseudo | gc.RightWrite},
obj.AVARLIVE: {Flags: gc.Pseudo | gc.LeftRead},
{ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0, 0, 0},
{AMULWT, C_REG, C_REG, C_REG, 98, 4, 0, 0, 0},
{AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0, 0, 0},
- {obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0, 0, 0},
{obj.APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0, 0, 0},
{obj.AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0, 0, 0},
{obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0},
}
}
- if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP && p.As != obj.AUSEFIELD) {
+ if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP) {
ctxt.Diag("zero-width instruction\n%v", p)
continue
}
if m/4 > len(out) {
ctxt.Diag("instruction size too large: %d > %d", m/4, len(out))
}
- if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP && p.As != obj.AUSEFIELD) {
+ if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP) {
if p.As == obj.ATEXT {
ctxt.Autosize = int32(p.To.Offset + 4)
continue
AWORD,
AMOVM,
ARFE,
- obj.ATEXT,
- obj.AUSEFIELD:
+ obj.ATEXT:
break
case AADDF:
{ASHA1C, C_VREG, C_REG, C_VREG, 1, 4, 0, 0, 0},
{obj.AUNDEF, C_NONE, C_NONE, C_NONE, 90, 4, 0, 0, 0},
- {obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0, 0, 0},
{obj.APCDATA, C_VCON, C_NONE, C_VCON, 0, 0, 0, 0, 0},
{obj.AFUNCDATA, C_VCON, C_NONE, C_ADDR, 0, 0, 0, 0, 0},
{obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0},
o = oplook(ctxt, p)
m = int(o.size)
if m == 0 {
- if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.AUSEFIELD {
+ if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
ctxt.Diag("zero-width instruction\n%v", p)
}
continue
m = int(o.size)
if m == 0 {
- if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.AUSEFIELD {
+ if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
ctxt.Diag("zero-width instruction\n%v", p)
}
continue
case obj.ANOP,
obj.AUNDEF,
- obj.AUSEFIELD,
obj.AFUNCDATA,
obj.APCDATA,
obj.ADUFFZERO,
// TODO(gri) Should this use relative or absolute line number?
return Linklookup(ctxt, pos.SymFilename(), 0), int32(pos.RelLine())
}
-
-func fieldtrack(ctxt *Link, cursym *LSym) {
- p := cursym.Text
- if p == nil || p.Link == nil { // handle external functions and ELF section symbols
- return
- }
- ctxt.Cursym = cursym
-
- for ; p != nil; p = p.Link {
- if p.As == AUSEFIELD {
- r := Addrel(ctxt.Cursym)
- r.Off = 0
- r.Siz = 0
- r.Sym = p.From.Sym
- r.Type = R_USEFIELD
- }
- }
-}
ARET
ATEXT
AUNDEF
- AUSEFIELD
AVARDEF
AVARKILL
AVARLIVE
{ABREAK, C_NONE, C_NONE, C_NONE, 5, 4, 0, 0},
{obj.AUNDEF, C_NONE, C_NONE, C_NONE, 49, 4, 0, 0},
- {obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0, 0},
{obj.APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0, 0},
{obj.AFUNCDATA, C_SCON, C_NONE, C_ADDR, 0, 0, 0, 0},
{obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0},
o = oplook(ctxt, p)
m = int(o.size)
if m == 0 {
- if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.AUSEFIELD {
+ if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
ctxt.Diag("zero-width instruction\n%v", p)
}
continue
m = int(o.size)
if m == 0 {
- if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.AUSEFIELD {
+ if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
ctxt.Diag("zero-width instruction\n%v", p)
}
continue
obj.ANOP,
obj.ATEXT,
obj.AUNDEF,
- obj.AUSEFIELD,
obj.AFUNCDATA,
obj.APCDATA,
obj.ADUFFZERO,
// Because p.Pos applies to p, phase == 0 (before p)
// takes care of the update.
func pctofileline(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
- if p.As == ATEXT || p.As == ANOP || p.As == AUSEFIELD || p.Pos.Line() == 0 || phase == 1 {
+ if p.As == ATEXT || p.As == ANOP || p.Pos.Line() == 0 || phase == 1 {
return oldval
}
f, l := linkgetlineFromPos(ctxt, p.Pos)
linkpatch(ctxt, s)
ctxt.Arch.Preprocess(ctxt, s)
ctxt.Arch.Assemble(ctxt, s)
- fieldtrack(ctxt, s)
linkpcln(ctxt, s)
if freeProgs {
s.Text = nil
{ALSW, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0},
{ALSW, C_ZOREG, C_NONE, C_LCON, C_REG, 42, 4, 0},
{obj.AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, 78, 4, 0},
- {obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, C_NONE, 0, 0, 0},
{obj.APCDATA, C_LCON, C_NONE, C_NONE, C_LCON, 0, 0, 0},
{obj.AFUNCDATA, C_SCON, C_NONE, C_NONE, C_ADDR, 0, 0, 0},
{obj.ANOP, C_NONE, C_NONE, C_NONE, C_NONE, 0, 0, 0},
o = oplook(ctxt, p)
m = int(o.size)
if m == 0 {
- if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.AUSEFIELD {
+ if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
ctxt.Diag("zero-width instruction\n%v", p)
}
continue
m = int(o.size)
if m == 0 {
- if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != obj.AUSEFIELD {
+ if p.As != obj.ANOP && p.As != obj.AFUNCDATA && p.As != obj.APCDATA {
ctxt.Diag("zero-width instruction\n%v", p)
}
continue
obj.ANOP,
obj.ATEXT,
obj.AUNDEF,
- obj.AUSEFIELD,
obj.AFUNCDATA,
obj.APCDATA,
obj.ADUFFZERO,
"RET",
"TEXT",
"UNDEF",
- "USEFIELD",
"VARDEF",
"VARKILL",
"VARLIVE",
{AXEND, ynone, Px, [23]uint8{0x0f, 01, 0xd5}},
{AXTEST, ynone, Px, [23]uint8{0x0f, 01, 0xd6}},
{AXGETBV, ynone, Pm, [23]uint8{01, 0xd0}},
- {obj.AUSEFIELD, ynop, Px, [23]uint8{0, 0}},
{obj.AFUNCDATA, yfuncdata, Px, [23]uint8{0, 0}},
{obj.APCDATA, ypcdata, Px, [23]uint8{0, 0}},
{obj.AVARDEF, nil, 0, [23]uint8{}},