[dev.regabi] cmd/internal/obj: access Attribute atomically

Symbol's Attributes and ABI are in the same word. In the
concurrent backend, we may read one symbol's ABI (the callee)
while setting its attributes in another goroutine.

Fix racecompile build.

Change-Id: I500e869bafdd72080119ab243db94eee3afcf926
Reviewed-on: https://go-review.googlesource.com/c/go/+/289290
Trust: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
Cherry Zhang 2021-02-03 18:10:04 -05:00
parent bc451b5770
commit 52d5cb2822

View file

@ -39,6 +39,7 @@ import (
"cmd/internal/sys" "cmd/internal/sys"
"fmt" "fmt"
"sync" "sync"
"sync/atomic"
) )
// An Addr is an argument to an instruction. // An Addr is an argument to an instruction.
@ -647,37 +648,52 @@ const (
attrABIBase attrABIBase
) )
func (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 } func (a *Attribute) load() Attribute { return Attribute(atomic.LoadUint32((*uint32)(a))) }
func (a Attribute) MakeTypelink() bool { return a&AttrMakeTypelink != 0 }
func (a Attribute) CFunc() bool { return a&AttrCFunc != 0 } func (a *Attribute) DuplicateOK() bool { return a.load()&AttrDuplicateOK != 0 }
func (a Attribute) NoSplit() bool { return a&AttrNoSplit != 0 } func (a *Attribute) MakeTypelink() bool { return a.load()&AttrMakeTypelink != 0 }
func (a Attribute) Leaf() bool { return a&AttrLeaf != 0 } func (a *Attribute) CFunc() bool { return a.load()&AttrCFunc != 0 }
func (a Attribute) OnList() bool { return a&AttrOnList != 0 } func (a *Attribute) NoSplit() bool { return a.load()&AttrNoSplit != 0 }
func (a Attribute) ReflectMethod() bool { return a&AttrReflectMethod != 0 } func (a *Attribute) Leaf() bool { return a.load()&AttrLeaf != 0 }
func (a Attribute) Local() bool { return a&AttrLocal != 0 } func (a *Attribute) OnList() bool { return a.load()&AttrOnList != 0 }
func (a Attribute) Wrapper() bool { return a&AttrWrapper != 0 } func (a *Attribute) ReflectMethod() bool { return a.load()&AttrReflectMethod != 0 }
func (a Attribute) NeedCtxt() bool { return a&AttrNeedCtxt != 0 } func (a *Attribute) Local() bool { return a.load()&AttrLocal != 0 }
func (a Attribute) NoFrame() bool { return a&AttrNoFrame != 0 } func (a *Attribute) Wrapper() bool { return a.load()&AttrWrapper != 0 }
func (a Attribute) Static() bool { return a&AttrStatic != 0 } func (a *Attribute) NeedCtxt() bool { return a.load()&AttrNeedCtxt != 0 }
func (a Attribute) WasInlined() bool { return a&AttrWasInlined != 0 } func (a *Attribute) NoFrame() bool { return a.load()&AttrNoFrame != 0 }
func (a Attribute) TopFrame() bool { return a&AttrTopFrame != 0 } func (a *Attribute) Static() bool { return a.load()&AttrStatic != 0 }
func (a Attribute) Indexed() bool { return a&AttrIndexed != 0 } func (a *Attribute) WasInlined() bool { return a.load()&AttrWasInlined != 0 }
func (a Attribute) UsedInIface() bool { return a&AttrUsedInIface != 0 } func (a *Attribute) TopFrame() bool { return a.load()&AttrTopFrame != 0 }
func (a Attribute) ContentAddressable() bool { return a&AttrContentAddressable != 0 } func (a *Attribute) Indexed() bool { return a.load()&AttrIndexed != 0 }
func (a Attribute) ABIWrapper() bool { return a&AttrABIWrapper != 0 } func (a *Attribute) UsedInIface() bool { return a.load()&AttrUsedInIface != 0 }
func (a *Attribute) ContentAddressable() bool { return a.load()&AttrContentAddressable != 0 }
func (a *Attribute) ABIWrapper() bool { return a.load()&AttrABIWrapper != 0 }
func (a *Attribute) Set(flag Attribute, value bool) { func (a *Attribute) Set(flag Attribute, value bool) {
if value { for {
*a |= flag v0 := a.load()
} else { v := v0
*a &^= flag if value {
v |= flag
} else {
v &^= flag
}
if atomic.CompareAndSwapUint32((*uint32)(a), uint32(v0), uint32(v)) {
break
}
} }
} }
func (a Attribute) ABI() ABI { return ABI(a / attrABIBase) } func (a *Attribute) ABI() ABI { return ABI(a.load() / attrABIBase) }
func (a *Attribute) SetABI(abi ABI) { func (a *Attribute) SetABI(abi ABI) {
const mask = 1 // Only one ABI bit for now. const mask = 1 // Only one ABI bit for now.
*a = (*a &^ (mask * attrABIBase)) | Attribute(abi)*attrABIBase for {
v0 := a.load()
v := (v0 &^ (mask * attrABIBase)) | Attribute(abi)*attrABIBase
if atomic.CompareAndSwapUint32((*uint32)(a), uint32(v0), uint32(v)) {
break
}
}
} }
var textAttrStrings = [...]struct { var textAttrStrings = [...]struct {