@@ -34,62 +34,69 @@ class TaskLocal {
34
34
public:
35
35
class Storage ;
36
36
37
- // / Type of the pointed at `next` task local item.
38
- enum class NextLinkType : uintptr_t {
39
- // / The storage pointer points at the next TaskLocal::Item in this task.
40
- IsNext = 0b00 ,
41
- // / The storage pointer points at a item stored by another AsyncTask.
37
+ // / Type of item in the task local item linked list.
38
+ enum class ItemKind : intptr_t {
39
+ // / Regular value item.
40
+ // / Has @c valueType and @c key .
41
+ // / Value is stored in the trailing storage.
42
+ // / @c next pointer points to another item owned by the same task as current item.
43
+ Value = -1 ,
44
+
45
+ // / Item that marks end of sequence of items owned by the current task.
46
+ // / @c next pointer points to an item owned by another AsyncTask.
42
47
// /
43
48
// / Note that this may not necessarily be the same as the task's parent
44
49
// / task -- we may point to a super-parent if we know / that the parent
45
50
// / does not "contribute" any task local values. This is to speed up
46
- // / lookups by skipping empty parent tasks during get(), and explained
47
- // / in depth in `createParentLink`.
48
- IsParent = 0b01 ,
51
+ // / lookups by skipping empty parent tasks during @c get() , and explained
52
+ // / in depth in @c createParentLink() .
53
+ ParentLink = 0 ,
54
+
55
+ // / Stop-item that blocks further lookup.
56
+ // / Inserting stop-node allows to temporary disable all inserted task-local values in O(1),
57
+ // / while maintaining immutable linked list nature of the task-local values implementation.
58
+ Stop = 1 ,
49
59
};
50
60
51
61
class Item {
52
62
private:
53
- // / Mask used for the low status bits in a task local chain item.
54
- static const uintptr_t statusMask = 0x03 ;
55
-
56
- // / Pointer to one of the following:
57
- // / - next task local item as OpaqueValue* if it is task-local allocated
58
- // / - next task local item as HeapObject* if it is heap allocated "heavy"
59
- // / - the parent task's TaskLocal::Storage
60
- // /
61
- // / Low bits encode `NextLinkType`, based on which the type of the pointer
62
- // / is determined.
63
- uintptr_t next;
64
-
65
- public:
66
- // / The type of the key with which this value is associated.
67
- const HeapObject *key;
63
+ // / Pointer to the next item in the chain.
64
+ Item * const next;
65
+
66
+ union KeyOrKind {
67
+ // / The type of the key with which this value is associated.
68
+ // / Set if valueType is not null
69
+ const HeapObject *key;
70
+
71
+ // / Kind of the node
72
+ // / Set if valueType is null
73
+ ItemKind kind;
74
+
75
+ KeyOrKind (const HeapObject *key) : key (key) {}
76
+ KeyOrKind (ItemKind kind) : kind (kind) {}
77
+ } const keyOrKind;
78
+
68
79
// / The type of the value stored by this item.
69
- const Metadata *valueType;
70
-
71
- // Trailing storage for the value itself. The storage will be
72
- // uninitialized or contain an instance of \c valueType.
73
-
74
- // / Returns true if this item is a 'parent pointer'.
75
- // /
76
- // / A parent pointer is special kind of `Item` is created when pointing at
77
- // / the parent storage, forming a chain of task local items spanning multiple
78
- // / tasks.
79
- bool isParentPointer () const {
80
- return !valueType;
81
- }
80
+ const Metadata * const valueType;
82
81
82
+ // Trailing storage for an instance of \c valueType if kind is ItemKind::Value
83
+
83
84
protected:
84
- explicit Item ()
85
- : next(0 ),
86
- key(nullptr ),
87
- valueType(nullptr ) {}
88
-
89
- explicit Item (const HeapObject *key, const Metadata *valueType)
90
- : next(0 ),
91
- key(key),
92
- valueType(valueType) {}
85
+ explicit Item (Item *next, ItemKind kind)
86
+ : next(next),
87
+ keyOrKind(kind),
88
+ valueType(nullptr )
89
+ {}
90
+
91
+ explicit Item (Item *next, const HeapObject *key, const Metadata *valueType)
92
+ : next(next),
93
+ keyOrKind(key),
94
+ valueType(valueType)
95
+ {
96
+ assert (valueType != nullptr );
97
+ }
98
+
99
+ static void *allocate (size_t amountToAllocate, AsyncTask *task);
93
100
94
101
public:
95
102
// / Item which does not by itself store any value, but only points
@@ -103,29 +110,42 @@ class TaskLocal {
103
110
// / the Item linked list into the appropriate parent.
104
111
static Item *createParentLink (AsyncTask *task, AsyncTask *parent);
105
112
106
- static Item *createLink (Item *next, AsyncTask *task, const HeapObject *key,
113
+ static Item *createValue (Item *next, AsyncTask *task, const HeapObject *key,
107
114
const Metadata *valueType);
115
+
116
+ static Item *createStop (Item *next, AsyncTask *task);
108
117
109
118
// / Destroys value and frees memory using specified task for deallocation.
110
119
// / If task is null, then th
111
120
void destroy (AsyncTask *task);
112
121
113
122
Item *getNext () {
114
- return reinterpret_cast <Item *>( next & ~statusMask) ;
123
+ return next;
115
124
}
116
-
117
- NextLinkType getNextLinkType () const {
118
- return static_cast <NextLinkType>(next & statusMask);
125
+
126
+ // / Returns kind of this item.
127
+ ItemKind getKind () const {
128
+ return valueType ? ItemKind::Value : keyOrKind.kind ;
119
129
}
120
130
121
- // / Item does not contain any actual value, and is only used to point at
122
- // / a specific parent item.
123
- bool isEmpty () const {
124
- return !valueType;
131
+ // / Returns key of the value item.
132
+ // / Available only if @c getKind() is @c ItemKind::Value .
133
+ const HeapObject *getKey () const {
134
+ assert (getKind () == ItemKind::Value);
135
+ return keyOrKind.key ;
136
+ }
137
+
138
+ // / Returns value type of the value item.
139
+ // / Available only if @c getKind() is @c ItemKind::Value .
140
+ const Metadata *getValueType () const {
141
+ assert (getKind () == ItemKind::Value);
142
+ return valueType;
125
143
}
126
144
127
145
// / Retrieve a pointer to the storage of the value.
146
+ // / Available only if @c getKind() is @c ItemKind::Value .
128
147
OpaqueValue *getStoragePtr () {
148
+ assert (getKind () == ItemKind::Value);
129
149
return reinterpret_cast <OpaqueValue *>(
130
150
reinterpret_cast <char *>(this ) + storageOffset (valueType));
131
151
}
@@ -179,10 +199,10 @@ class TaskLocal {
179
199
// / The stack is only pushed/popped by the owning task, at the beginning and
180
200
// / end a `body` block of `withLocal(_:boundTo:body:)` respectively.
181
201
// /
182
- // / Correctness of the stack strongly relies on the guarantee that tasks
183
- // / never outline a scope in which they are created. Thanks to this, if
184
- // / tasks are created inside the `body` of `withLocal(_:,boundTo:body:)`
185
- // / all tasks created inside the `withLocal` body must complete before it
202
+ // / Correctness of the stack strongly relies on the guarantee that child tasks
203
+ // / never outlive a scope in which they are created. Thanks to this, if
204
+ // / child tasks are created inside the `body` of `withLocal(_:,boundTo:body:)`
205
+ // / all child tasks created inside the `withLocal` body must complete before it
186
206
// / returns, as such, any child tasks potentially accessing the value stack
187
207
// / are guaranteed to be completed by the time we pop values off the stack
188
208
// / (after the body has completed).
@@ -196,12 +216,14 @@ class TaskLocal {
196
216
const HeapObject *key,
197
217
/* +1 */ OpaqueValue *value, const Metadata *valueType);
198
218
219
+ void pushStop (AsyncTask *task);
220
+
199
221
OpaqueValue* getValue (AsyncTask *task, const HeapObject *key);
200
222
201
- // / Returns `true` of more bindings remain in this storage,
223
+ // / Returns `true` if more bindings remain in this storage,
202
224
// / and `false` if the just popped value was the last one and the storage
203
225
// / can be safely disposed of.
204
- bool popValue (AsyncTask *task);
226
+ bool pop (AsyncTask *task);
205
227
206
228
// / Copy all task-local bindings to the target task.
207
229
// /
@@ -227,9 +249,9 @@ class TaskLocal {
227
249
// / Copy all task locals from the current context to the target storage.
228
250
// / To prevent data races, there should be no other accesses to the target
229
251
// / storage, while copying. Target storage is asserted to be empty, as a proxy
230
- // / for being not in use. If task is specified, it will be used for memory
231
- // / management. If task is nil, items will be allocated using malloc(). The
232
- // / same value of task should be passed to TaskLocal::Storage::destroy().
252
+ // / for being not in use. If @c task is specified, it will be used for memory
253
+ // / management. If @c task is nil, items will be allocated using malloc(). The
254
+ // / same value of @c task should be passed to @c TaskLocal::Storage::destroy() .
233
255
static void copyTo (Storage *target, AsyncTask *task);
234
256
235
257
class AdHocScope {
@@ -239,6 +261,13 @@ class TaskLocal {
239
261
AdHocScope (Storage *storage);
240
262
~AdHocScope ();
241
263
};
264
+
265
+ class WithResetValuesScope {
266
+ bool didPush;
267
+ public:
268
+ WithResetValuesScope ();
269
+ ~WithResetValuesScope ();
270
+ };
242
271
};
243
272
244
273
} // end namespace swift
0 commit comments