19
19
#include " swift/Runtime/Exclusivity.h"
20
20
#include " swift/Runtime/Metadata.h"
21
21
#include < memory>
22
+ #include < stdio.h>
22
23
23
24
// Pick an implementation strategy.
24
25
#ifndef SWIFT_EXCLUSIVITY_USE_THREADLOCAL
41
42
#include < stdio.h>
42
43
#endif
43
44
45
+ // Pick a return-address strategy
46
+ #if __GNUC__
47
+ #define get_return_address () __builtin_return_address(0 )
48
+ #elif _MSC_VER
49
+ #include < intrin.h>
50
+ #define get_return_address () _ReturnAddress()
51
+ #else
52
+ #error missing implementation for get_return_address
53
+ #define get_return_address () ((void *) 0 )
54
+ #endif
55
+
56
+
44
57
using namespace swift ;
45
58
46
59
bool swift::_swift_disableExclusivityChecking = false ;
@@ -49,40 +62,70 @@ static const char *getAccessName(ExclusivityFlags flags) {
49
62
switch (flags) {
50
63
case ExclusivityFlags::Read: return " read" ;
51
64
case ExclusivityFlags::Modify: return " modify" ;
65
+ default : return " unknown" ;
66
+ }
67
+ }
68
+
69
+ static void reportExclusivityConflict (ExclusivityFlags oldAction, void *oldPC,
70
+ ExclusivityFlags newFlags, void *newPC,
71
+ void *pointer) {
72
+ // TODO: print something about where the pointer came from?
73
+ // TODO: if we do something more computationally intense here,
74
+ // suppress warnings if the total warning count exceeds some limit
75
+
76
+ if (isWarningOnly (newFlags)) {
77
+ fprintf (stderr,
78
+ " WARNING: %s/%s access conflict detected on address %p\n "
79
+ " first access started at PC=%p\n "
80
+ " second access started at PC=%p\n " ,
81
+ getAccessName (oldAction),
82
+ getAccessName (getAccessAction (newFlags)),
83
+ pointer, oldPC, newPC);
84
+ return ;
52
85
}
53
- return " unknown" ;
86
+
87
+ // TODO: try to recover source-location information from the return
88
+ // address.
89
+ fatalError (0 ,
90
+ " %s/%s access conflict detected on address %p, aborting\n "
91
+ " first access started at PC=%p\n "
92
+ " second access started at PC=%p\n " ,
93
+ getAccessName (oldAction),
94
+ getAccessName (getAccessAction (newFlags)),
95
+ pointer, oldPC, newPC);
54
96
}
55
97
56
98
namespace {
57
99
58
100
// / A single access that we're tracking.
59
101
struct Access {
60
102
void *Pointer;
61
- uintptr_t HereAndAction ;
62
- Access *Next ;
103
+ void *PC ;
104
+ uintptr_t NextAndAction ;
63
105
64
106
enum : uintptr_t {
65
107
ActionMask = (uintptr_t )ExclusivityFlags::ActionMask,
66
- HereMask = ~ActionMask
108
+ NextMask = ~ActionMask
67
109
};
68
110
69
- Access ** getHere () const {
70
- return reinterpret_cast <Access**>(HereAndAction & HereMask );
111
+ Access *getNext () const {
112
+ return reinterpret_cast <Access*>(NextAndAction & NextMask );
71
113
}
72
114
73
- void setHere (Access **newHere) {
74
- HereAndAction = reinterpret_cast <uintptr_t >(newHere) | uintptr_t (getAccessAction ());
115
+ void setNext (Access *next) {
116
+ NextAndAction =
117
+ reinterpret_cast <uintptr_t >(next) | (NextAndAction & NextMask);
75
118
}
76
119
77
120
ExclusivityFlags getAccessAction () const {
78
- return ExclusivityFlags (HereAndAction & ActionMask);
121
+ return ExclusivityFlags (NextAndAction & ActionMask);
79
122
}
80
123
81
- void initialize (void *pointer, Access **here, ExclusivityFlags action) {
82
- assert (*here == nullptr && " not inserting to end of list " );
124
+ void initialize (void *pc, void *pointer, Access *next,
125
+ ExclusivityFlags action) {
83
126
Pointer = pointer;
84
- HereAndAction = reinterpret_cast < uintptr_t >(here) | uintptr_t (action) ;
85
- Next = nullptr ;
127
+ PC = pc ;
128
+ NextAndAction = reinterpret_cast < uintptr_t >(next) | uintptr_t (action) ;
86
129
}
87
130
};
88
131
@@ -96,11 +139,10 @@ class AccessSet {
96
139
public:
97
140
constexpr AccessSet () {}
98
141
99
- void insert (Access *access, void *pointer, ExclusivityFlags flags) {
142
+ void insert (Access *access, void *pc, void * pointer, ExclusivityFlags flags) {
100
143
auto action = getAccessAction (flags);
101
144
102
- Access **curP = &Head;
103
- for (Access *cur = *curP; cur != nullptr ; curP = &cur->Next , cur = *curP) {
145
+ for (Access *cur = Head; cur != nullptr ; cur = cur->getNext ()) {
104
146
// Ignore accesses to different values.
105
147
if (cur->Pointer != pointer)
106
148
continue ;
@@ -111,22 +153,34 @@ class AccessSet {
111
153
continue ;
112
154
113
155
// Otherwise, it's a conflict.
114
- // TODO: try to recover source-location information from the return
115
- // address.
116
- fatalError ( 0 , " %s/%s access conflict detected on address %p, aborting \n " ,
117
- getAccessName (action), getAccessName (cur-> getAccessAction ()),
118
- pointer) ;
156
+ reportExclusivityConflict (cur-> getAccessAction (), cur-> PC ,
157
+ flags, pc, pointer);
158
+
159
+ // If we're only warning, don't report multiple conflicts.
160
+ break ;
119
161
}
120
162
121
- access->initialize (pointer, curP, action);
122
- *curP = access;
163
+ // Insert to the front of the array so that remove tends to find it faster.
164
+ access->initialize (pc, pointer, Head, action);
165
+ Head = access;
123
166
}
124
167
125
- static void remove (Access *access) {
126
- Access **here = access->getHere ();
127
- *here = access->Next ;
128
- if (access->Next != nullptr )
129
- access->Next ->setHere (here);
168
+ void remove (Access *access) {
169
+ auto cur = Head;
170
+ // Fast path: stack discipline.
171
+ if (cur == access) {
172
+ Head = cur->getNext ();
173
+ return ;
174
+ }
175
+
176
+ for (Access *last = cur; cur != nullptr ; last = cur, cur = cur->getNext ()) {
177
+ if (last == access) {
178
+ last->setNext (cur->getNext ());
179
+ return ;
180
+ }
181
+ }
182
+
183
+ swift_runtime_unreachable (" access not found in set" );
130
184
}
131
185
};
132
186
@@ -205,7 +259,7 @@ static AccessSet &getAccessSet(void *pointer) {
205
259
// / This may cause a runtime failure if an incompatible access is
206
260
// / already underway.
207
261
void swift::swift_beginAccess (void *pointer, ValueBuffer *buffer,
208
- ExclusivityFlags flags) {
262
+ ExclusivityFlags flags, void *pc ) {
209
263
assert (pointer && " beginning an access on a null pointer?" );
210
264
211
265
Access *access = reinterpret_cast <Access*>(buffer);
@@ -217,7 +271,9 @@ void swift::swift_beginAccess(void *pointer, ValueBuffer *buffer,
217
271
return ;
218
272
}
219
273
220
- getAccessSet (pointer).insert (access, pointer, flags);
274
+ if (!pc) pc = get_return_address ();
275
+
276
+ getAccessSet (pointer).insert (access, pc, pointer, flags);
221
277
}
222
278
223
279
// / End tracking a dynamic access.
@@ -231,5 +287,5 @@ void swift::swift_endAccess(ValueBuffer *buffer) {
231
287
return ;
232
288
}
233
289
234
- AccessSet:: remove (access);
290
+ getAccessSet (pointer). remove (access);
235
291
}
0 commit comments