Skip to content

Commit e4498b2

Browse files
authored
Merge pull request #37158 from ktoso/pick-tasklocals
[cherry-pick 5.5] Task locals revisions
2 parents cce9259 + d86a618 commit e4498b2

25 files changed

+853
-430
lines changed

include/swift/ABI/Task.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class alignas(2 * alignof(void*)) Job : public HeapObject {
4747
NextWaitingTaskIndex = 0,
4848

4949
// The Dispatch object header is one pointer and two ints, which is
50-
// equvialent to three pointers on 32-bit and two pointers 64-bit. Set the
50+
// equivalent to three pointers on 32-bit and two pointers 64-bit. Set the
5151
// indexes accordingly so that DispatchLinkageIndex points to where Dispatch
5252
// expects.
5353
DispatchHasLongObjectHeader = sizeof(void *) == sizeof(int),
@@ -217,14 +217,13 @@ class AsyncTask : public Job {
217217

218218
// ==== Task Local Values ----------------------------------------------------
219219

220-
void localValuePush(const Metadata *keyType,
220+
void localValuePush(const HeapObject *key,
221221
/* +1 */ OpaqueValue *value, const Metadata *valueType) {
222-
Local.pushValue(this, keyType, value, valueType);
222+
Local.pushValue(this, key, value, valueType);
223223
}
224224

225-
OpaqueValue* localValueGet(const Metadata *keyType,
226-
TaskLocal::TaskLocalInheritance inherit) {
227-
return Local.getValue(this, keyType, inherit);
225+
OpaqueValue* localValueGet(const HeapObject *key) {
226+
return Local.getValue(this, key);
228227
}
229228

230229
void localValuePop() {

include/swift/ABI/TaskLocal.h

Lines changed: 20 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -34,73 +34,50 @@ class TaskLocal {
3434
public:
3535
/// Type of the pointed at `next` task local item.
3636
enum class NextLinkType : uintptr_t {
37-
/// This task is known to be a "terminal" node in the lookup of task locals.
38-
/// In other words, even if it had a parent, the parent (and its parents)
39-
/// are known to not contain any any more task locals, and thus any further
40-
/// search beyond this task.
41-
IsTerminal = 0b00,
4237
/// The storage pointer points at the next TaskLocal::Item in this task.
43-
IsNext = 0b01,
38+
IsNext = 0b00,
4439
/// The storage pointer points at a item stored by another AsyncTask.
4540
///
4641
/// Note that this may not necessarily be the same as the task's parent
4742
/// task -- we may point to a super-parent if we know / that the parent
4843
/// does not "contribute" any task local values. This is to speed up
4944
/// lookups by skipping empty parent tasks during get(), and explained
5045
/// in depth in `createParentLink`.
51-
IsParent = 0b11
52-
};
53-
54-
/// Values must match `TaskLocalInheritance` declared in `TaskLocal.swift`.
55-
enum class TaskLocalInheritance : uint8_t {
56-
/// Default task local value behavior
57-
///
58-
/// Values declared with a default-inherited key are accessible from:
59-
/// - the current task that has bound the value,
60-
/// - any child task of the current task (e.g. created by async let or groups)
61-
///
62-
/// Such values are *not* carried through detached tasks.
63-
Default = 0,
64-
65-
/// Special semantics which confine a task's local value to *only* the current
66-
/// task. In other words, they ave never inherited by any child task created
67-
/// by the current task.
68-
///
69-
/// Values declared with a never-inherited key only accessible:
70-
/// - specifically from the current task itself
71-
///
72-
/// Such values are *not* accessible from child tasks or detached tasks.
73-
Never = 1
46+
IsParent = 0b01,
7447
};
7548

7649
class Item {
7750
private:
7851
/// Mask used for the low status bits in a task local chain item.
7952
static const uintptr_t statusMask = 0x03;
8053

81-
/// Pointer to the next task local item; be it in this task or in a parent.
82-
/// Low bits encode `NextLinkType`.
83-
/// Item *next = nullptr;
54+
/// Pointer to one of the following:
55+
/// - next task local item as OpaqueValue* if it is task-local allocated
56+
/// - next task local item as HeapObject* if it is heap allocated "heavy"
57+
/// - the parent task's TaskLocal::Storage
58+
///
59+
/// Low bits encode `NextLinkType`, based on which the type of the pointer
60+
/// is determined.
8461
uintptr_t next;
8562

8663
public:
8764
/// The type of the key with which this value is associated.
88-
const Metadata *keyType;
65+
const HeapObject *key;
8966
/// The type of the value stored by this item.
9067
const Metadata *valueType;
9168

9269
// Trailing storage for the value itself. The storage will be
9370
// uninitialized or contain an instance of \c valueType.
9471

95-
private:
72+
protected:
9673
explicit Item()
9774
: next(0),
98-
keyType(nullptr),
75+
key(nullptr),
9976
valueType(nullptr) {}
10077

101-
explicit Item(const Metadata *keyType, const Metadata *valueType)
78+
explicit Item(const HeapObject *key, const Metadata *valueType)
10279
: next(0),
103-
keyType(keyType),
80+
key(key),
10481
valueType(valueType) {}
10582

10683
public:
@@ -116,7 +93,7 @@ class TaskLocal {
11693
static Item *createParentLink(AsyncTask *task, AsyncTask *parent);
11794

11895
static Item *createLink(AsyncTask *task,
119-
const Metadata *keyType,
96+
const HeapObject *key,
12097
const Metadata *valueType);
12198

12299
void destroy(AsyncTask *task);
@@ -125,13 +102,13 @@ class TaskLocal {
125102
return reinterpret_cast<Item *>(next & ~statusMask);
126103
}
127104

128-
NextLinkType getNextLinkType() {
105+
NextLinkType getNextLinkType() const {
129106
return static_cast<NextLinkType>(next & statusMask);
130107
}
131108

132109
/// Item does not contain any actual value, and is only used to point at
133110
/// a specific parent item.
134-
bool isEmpty() {
111+
bool isEmpty() const {
135112
return !valueType;
136113
}
137114

@@ -144,6 +121,7 @@ class TaskLocal {
144121
/// Compute the offset of the storage from the base of the item.
145122
static size_t storageOffset(const Metadata *valueType) {
146123
size_t offset = sizeof(Item);
124+
147125
if (valueType) {
148126
size_t alignment = valueType->vw_alignment();
149127
return (offset + alignment - 1) & ~(alignment - 1);
@@ -162,7 +140,6 @@ class TaskLocal {
162140
}
163141
};
164142

165-
166143
class Storage {
167144
friend class TaskLocal::Item;
168145
private:
@@ -202,12 +179,10 @@ class TaskLocal {
202179
void initializeLinkParent(AsyncTask *task, AsyncTask *parent);
203180

204181
void pushValue(AsyncTask *task,
205-
const Metadata *keyType,
182+
const HeapObject *key,
206183
/* +1 */ OpaqueValue *value, const Metadata *valueType);
207184

208-
OpaqueValue* getValue(AsyncTask *task,
209-
const Metadata *keyType,
210-
TaskLocalInheritance inheritance);
185+
OpaqueValue* getValue(AsyncTask *task, const HeapObject *key);
211186

212187
void popValue(AsyncTask *task);
213188

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5609,6 +5609,11 @@ ERROR(property_wrapper_dynamic_self_type, none,
56095609
"property wrapper %select{wrapped value|projected value}0 cannot have "
56105610
"dynamic Self type", (bool))
56115611

5612+
ERROR(property_wrapper_var_must_be_static, none,
5613+
"property %0, must be static because property wrapper %1 can only "
5614+
"be applied to static properties",
5615+
(Identifier, Type))
5616+
56125617
ERROR(property_wrapper_attribute_not_on_property, none,
56135618
"property wrapper attribute %0 can only be applied to a property",
56145619
(Identifier))

include/swift/AST/KnownSDKTypes.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,6 @@ KNOWN_SDK_TYPE_DECL(ObjectiveC, ObjCBool, StructDecl, 0)
4040
KNOWN_SDK_TYPE_DECL(Concurrency, UnsafeContinuation, NominalTypeDecl, 2)
4141
KNOWN_SDK_TYPE_DECL(Concurrency, MainActor, NominalTypeDecl, 0)
4242

43+
KNOWN_SDK_TYPE_DECL(Concurrency, TaskLocal, ClassDecl, 1)
44+
4345
#undef KNOWN_SDK_TYPE_DECL

include/swift/AST/PropertyWrappers.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ struct PropertyWrapperTypeInfo {
8888
/// ability to reason about the enclosing "self".
8989
SubscriptDecl *enclosingInstanceProjectedSubscript = nullptr;
9090

91+
/// Forces that the property wrapper must be declared on a static, or
92+
/// global–once supported–property.
93+
bool requireNoEnclosingInstance = false;
94+
9195
///
9296
/// Whether this is a valid property wrapper.
9397
bool isValid() const {

include/swift/Runtime/Concurrency.h

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -303,11 +303,20 @@ bool swift_task_tryAddStatusRecord(TaskStatusRecord *record);
303303
///
304304
/// The given record need not be the last record added to
305305
/// the task, but the operation may be less efficient if not.
306-
///s
306+
///
307307
/// Returns false if the task has been cancelled.
308308
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
309309
bool swift_task_removeStatusRecord(TaskStatusRecord *record);
310310

311+
/// Signifies whether the current task is in the middle of executing the
312+
/// operation block of a `with(Throwing)TaskGroup(...) { <operation> }`.
313+
///
314+
/// Task local values must use un-structured allocation for values bound in this
315+
/// scope, as they may be referred to by `group.spawn`-ed tasks and therefore
316+
/// out-life the scope of a task-local value binding.
317+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
318+
bool swift_task_hasTaskGroupStatusRecord();
319+
311320
/// Attach a child task to its parent task and return the newly created
312321
/// `ChildTaskStatusRecord`.
313322
///
@@ -339,20 +348,23 @@ SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
339348
void swift_task_removeCancellationHandler(
340349
CancellationNotificationStatusRecord *record);
341350

351+
/// Report error about attempting to bind a task-local value from an illegal context.
352+
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
353+
void swift_task_reportIllegalTaskLocalBindingWithinWithTaskGroup(
354+
const unsigned char *file, uintptr_t fileLength,
355+
bool fileIsASCII, uintptr_t line);
356+
342357
/// Get a task local value from the passed in task. Its Swift signature is
343358
///
344359
/// \code
345360
/// func _taskLocalValueGet<Key>(
346361
/// _ task: Builtin.NativeObject,
347-
/// keyType: Any.Type /*Key.Type*/,
348-
/// inheritance: UInt8/*TaskLocalInheritance*/
362+
/// keyType: Any.Type /*Key.Type*/
349363
/// ) -> UnsafeMutableRawPointer? where Key: TaskLocalKey
350364
/// \endcode
351365
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
352366
OpaqueValue*
353-
swift_task_localValueGet(AsyncTask* task,
354-
const Metadata *keyType,
355-
TaskLocal::TaskLocalInheritance inheritance);
367+
swift_task_localValueGet(AsyncTask* task, const HeapObject *key);
356368

357369
/// Add a task local value to the passed in task.
358370
///
@@ -369,7 +381,7 @@ swift_task_localValueGet(AsyncTask* task,
369381
/// \endcode
370382
SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift)
371383
void swift_task_localValuePush(AsyncTask* task,
372-
const Metadata *keyType,
384+
const HeapObject *key,
373385
/* +1 */ OpaqueValue *value,
374386
const Metadata *valueType);
375387

lib/Sema/TypeCheckPropertyWrapper.cpp

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,24 @@ findSuitableWrapperInit(ASTContext &ctx, NominalTypeDecl *nominal,
244244
return viableInitializers.empty() ? nullptr : viableInitializers.front();
245245
}
246246

247+
/// Returns true if the enclosingInstance parameter is `Never`,
248+
/// implying that there should be NO enclosing instance.
249+
static bool enclosingInstanceTypeIsNever(ASTContext &ctx, SubscriptDecl *subscript) {
250+
if (!subscript)
251+
return false;
252+
253+
ParameterList *indices = subscript->getIndices();
254+
assert(indices && indices->size() > 0);
255+
256+
ParamDecl *param = indices->get(0);
257+
if (param->getArgumentName() != ctx.Id_enclosingInstance)
258+
return false;
259+
260+
auto paramTy = param->getType();
261+
auto neverTy = ctx.getNeverType();
262+
return neverTy->isEqual(paramTy);
263+
}
264+
247265
/// Determine whether we have a suitable static subscript to which we
248266
/// can pass along the enclosing self + key-paths.
249267
static SubscriptDecl *findEnclosingSelfSubscript(ASTContext &ctx,
@@ -385,6 +403,16 @@ PropertyWrapperTypeInfoRequest::evaluate(
385403
}
386404
}
387405

406+
result.requireNoEnclosingInstance =
407+
enclosingInstanceTypeIsNever(ctx, result.enclosingInstanceWrappedSubscript);
408+
// if (requireNoEnclosingInstance) { // && !valueVar->isStatic()) {
409+
// // this means that the property wrapper must be declared on a static property
410+
// valueVar->diagnose(
411+
// diag::property_wrapper_var_must_be_static, valueVar->getName());
412+
// return PropertyWrapperTypeInfo();
413+
// result
414+
// }
415+
388416
bool hasInvalidDynamicSelf = false;
389417
if (result.projectedValueVar &&
390418
result.projectedValueVar->getValueInterfaceType()->hasDynamicSelfType()) {
@@ -439,6 +467,18 @@ AttachedPropertyWrappersRequest::evaluate(Evaluator &evaluator,
439467
continue;
440468
}
441469

470+
// // If the property wrapper requested an `_enclosingInstance: Never`
471+
// // it must be declared as static. TODO: or global once we allow wrappers on top-level code
472+
// auto wrappedInfo = var->getPropertyWrapperTypeInfo();
473+
// if (wrappedInfo.requireNoEnclosingInstance) {
474+
// if (!var->isStatic()) {
475+
// ctx.Diags.diagnose(var->getLocation(),
476+
// diag::property_wrapper_var_must_be_static,
477+
// var->getName());
478+
// continue;
479+
// }
480+
// }
481+
442482
// Check that the variable is part of a single-variable pattern.
443483
auto binding = var->getParentPatternBinding();
444484
if (binding && binding->getSingleVar() != var) {
@@ -508,7 +548,7 @@ AttachedPropertyWrappersRequest::evaluate(Evaluator &evaluator,
508548
continue;
509549
}
510550
}
511-
551+
512552
result.push_back(mutableAttr);
513553
}
514554

@@ -601,6 +641,20 @@ PropertyWrapperBackingPropertyTypeRequest::evaluate(
601641
wrappedValue->setInterfaceType(computeWrappedValueType(var, type));
602642
}
603643

644+
{
645+
auto *nominal = type->getDesugaredType()->getAnyNominal();
646+
if (auto wrappedInfo = nominal->getPropertyWrapperTypeInfo()) {
647+
if (wrappedInfo.requireNoEnclosingInstance &&
648+
!var->isStatic()) {
649+
ctx.Diags.diagnose(var->getNameLoc(),
650+
diag::property_wrapper_var_must_be_static,
651+
var->getName(), type);
652+
// TODO: fixit insert static?
653+
return Type();
654+
}
655+
}
656+
}
657+
604658
return type;
605659
}
606660

stdlib/public/CompatibilityOverride/CompatibilityOverrideConcurrency.def

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,19 +183,25 @@ OVERRIDE_TASK_GROUP(taskGroup_addPending, bool,
183183
swift::, (TaskGroup *group, bool unconditionally),
184184
(group, unconditionally))
185185

186+
187+
OVERRIDE_TASK_LOCAL(task_reportIllegalTaskLocalBindingWithinWithTaskGroup, void,
188+
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift), swift::,
189+
(const unsigned char *file, uintptr_t fileLength,
190+
bool fileIsASCII, uintptr_t line),
191+
(file, fileLength, fileIsASCII, line))
192+
186193
OVERRIDE_TASK_LOCAL(task_localValuePush, void,
187194
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
188195
swift::,
189-
(AsyncTask *task, const Metadata *keyType,
196+
(AsyncTask *task, const HeapObject *key,
190197
OpaqueValue *value, const Metadata *valueType),
191-
(task, keyType, value, valueType))
198+
(task, key, value, valueType))
192199

193200
OVERRIDE_TASK_LOCAL(task_localValueGet, OpaqueValue *,
194201
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
195202
swift::,
196-
(AsyncTask *task, const Metadata *keyType,
197-
TaskLocal::TaskLocalInheritance inheritance),
198-
(task, keyType, inheritance))
203+
(AsyncTask *task, const HeapObject *key),
204+
(task, key))
199205

200206
OVERRIDE_TASK_LOCAL(task_localValuePop, void,
201207
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
@@ -213,6 +219,10 @@ OVERRIDE_TASK_STATUS(task_removeStatusRecord, bool,
213219
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
214220
swift::, (TaskStatusRecord *record), (record))
215221

222+
OVERRIDE_TASK_STATUS(task_hasTaskGroupStatusRecord, bool,
223+
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
224+
swift::, , )
225+
216226
OVERRIDE_TASK_STATUS(task_attachChild, ChildTaskStatusRecord *,
217227
SWIFT_EXPORT_FROM(swift_Concurrency), SWIFT_CC(swift),
218228
swift::, (AsyncTask *child), (child))

0 commit comments

Comments
 (0)