]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.regabi] cmd/internal/obj: access Attribute atomically
authorCherry Zhang <cherryyz@google.com>
Wed, 3 Feb 2021 23:10:04 +0000 (18:10 -0500)
committerCherry Zhang <cherryyz@google.com>
Thu, 4 Feb 2021 20:25:59 +0000 (20:25 +0000)
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>
src/cmd/internal/obj/link.go

index 35cb53cbf6cc83dcdccdc2a7df79e61d300929b0..82069023280773ea8524f49905a920ced2793c7b 100644 (file)
@@ -39,6 +39,7 @@ import (
        "cmd/internal/sys"
        "fmt"
        "sync"
+       "sync/atomic"
 )
 
 // An Addr is an argument to an instruction.
@@ -647,37 +648,52 @@ const (
        attrABIBase
 )
 
-func (a Attribute) DuplicateOK() bool        { return a&AttrDuplicateOK != 0 }
-func (a Attribute) MakeTypelink() bool       { return a&AttrMakeTypelink != 0 }
-func (a Attribute) CFunc() bool              { return a&AttrCFunc != 0 }
-func (a Attribute) NoSplit() bool            { return a&AttrNoSplit != 0 }
-func (a Attribute) Leaf() bool               { return a&AttrLeaf != 0 }
-func (a Attribute) OnList() bool             { return a&AttrOnList != 0 }
-func (a Attribute) ReflectMethod() bool      { return a&AttrReflectMethod != 0 }
-func (a Attribute) Local() bool              { return a&AttrLocal != 0 }
-func (a Attribute) Wrapper() bool            { return a&AttrWrapper != 0 }
-func (a Attribute) NeedCtxt() bool           { return a&AttrNeedCtxt != 0 }
-func (a Attribute) NoFrame() bool            { return a&AttrNoFrame != 0 }
-func (a Attribute) Static() bool             { return a&AttrStatic != 0 }
-func (a Attribute) WasInlined() bool         { return a&AttrWasInlined != 0 }
-func (a Attribute) TopFrame() bool           { return a&AttrTopFrame != 0 }
-func (a Attribute) Indexed() bool            { return a&AttrIndexed != 0 }
-func (a Attribute) UsedInIface() bool        { return a&AttrUsedInIface != 0 }
-func (a Attribute) ContentAddressable() bool { return a&AttrContentAddressable != 0 }
-func (a Attribute) ABIWrapper() bool         { return a&AttrABIWrapper != 0 }
+func (a *Attribute) load() Attribute { return Attribute(atomic.LoadUint32((*uint32)(a))) }
+
+func (a *Attribute) DuplicateOK() bool        { return a.load()&AttrDuplicateOK != 0 }
+func (a *Attribute) MakeTypelink() bool       { return a.load()&AttrMakeTypelink != 0 }
+func (a *Attribute) CFunc() bool              { return a.load()&AttrCFunc != 0 }
+func (a *Attribute) NoSplit() bool            { return a.load()&AttrNoSplit != 0 }
+func (a *Attribute) Leaf() bool               { return a.load()&AttrLeaf != 0 }
+func (a *Attribute) OnList() bool             { return a.load()&AttrOnList != 0 }
+func (a *Attribute) ReflectMethod() bool      { return a.load()&AttrReflectMethod != 0 }
+func (a *Attribute) Local() bool              { return a.load()&AttrLocal != 0 }
+func (a *Attribute) Wrapper() bool            { return a.load()&AttrWrapper != 0 }
+func (a *Attribute) NeedCtxt() bool           { return a.load()&AttrNeedCtxt != 0 }
+func (a *Attribute) NoFrame() bool            { return a.load()&AttrNoFrame != 0 }
+func (a *Attribute) Static() bool             { return a.load()&AttrStatic != 0 }
+func (a *Attribute) WasInlined() bool         { return a.load()&AttrWasInlined != 0 }
+func (a *Attribute) TopFrame() bool           { return a.load()&AttrTopFrame != 0 }
+func (a *Attribute) Indexed() bool            { return a.load()&AttrIndexed != 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) {
-       if value {
-               *a |= flag
-       } else {
-               *a &^= flag
+       for {
+               v0 := a.load()
+               v := v0
+               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) {
        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 {