Skip to content

Commit ed9a548

Browse files
committed
[Concurrency] Return getCurrentAsyncTask() as owned.
Rather than produce an "unowned" result from `getCurrentAsyncTask()`, take advantage of the fact that the task is effectively guaranteed in the scope. Do so be returning it as "unowned", and push an end_lifetime cleanup to end the lifetime. This eliminates unnecessary ref-count traffic as well as introducing another use of unowned. Approach is thanks to Michael Gottesman, bugs are mine.
1 parent 9566d2e commit ed9a548

File tree

8 files changed

+41
-13
lines changed

8 files changed

+41
-13
lines changed

include/swift/AST/Builtins.def

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -492,12 +492,6 @@ BUILTIN_SIL_OPERATION(ConvertStrongToUnownedUnsafe, "convertStrongToUnownedUnsaf
492492
/// now.
493493
BUILTIN_SIL_OPERATION(ConvertUnownedUnsafeToGuaranteed, "convertUnownedUnsafeToGuaranteed", Special)
494494

495-
// getCurrentAsyncTask: () -> Builtin.NativeObject
496-
//
497-
// Retrieve the pointer to the task in which the current asynchronous
498-
// function is executing.
499-
BUILTIN_SIL_OPERATION(GetCurrentAsyncTask, "getCurrentAsyncTask", Special)
500-
501495
/// applyDerivative
502496
BUILTIN_SIL_OPERATION(ApplyDerivative, "applyDerivative", Special)
503497

@@ -723,6 +717,12 @@ BUILTIN_MISC_OPERATION(IntInstrprofIncrement, "int_instrprof_increment", "", Spe
723717
BUILTIN_MISC_OPERATION(Id, Name, Attrs, Overload)
724718
#endif
725719

720+
// getCurrentAsyncTask: () -> Builtin.NativeObject
721+
//
722+
// Retrieve the pointer to the task in which the current asynchronous
723+
// function is executing.
724+
BUILTIN_MISC_OPERATION_WITH_SILGEN(GetCurrentAsyncTask, "getCurrentAsyncTask", "n", Special)
725+
726726
/// globalStringTablePointer has type String -> Builtin.RawPointer.
727727
/// It returns an immortal, global string table pointer for strings constructed
728728
/// from string literals. We consider it effects as readnone meaning that it

lib/SIL/IR/OperandOwnership.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,7 @@ ANY_OWNERSHIP_BUILTIN(IntInstrprofIncrement)
10331033
}
10341034
CONSTANT_OWNERSHIP_BUILTIN(Owned, MustBeInvalidated, COWBufferForReading)
10351035
CONSTANT_OWNERSHIP_BUILTIN(Owned, MustBeInvalidated, UnsafeGuaranteed)
1036+
CONSTANT_OWNERSHIP_BUILTIN(Owned, MustBeInvalidated, GetCurrentAsyncTask)
10361037
#undef CONSTANT_OWNERSHIP_BUILTIN
10371038

10381039
// Builtins that should be lowered to SIL instructions so we should never see

lib/SIL/IR/ValueOwnership.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,7 @@ CONSTANT_OWNERSHIP_BUILTIN(None, PoundAssert)
541541
CONSTANT_OWNERSHIP_BUILTIN(None, TypePtrAuthDiscriminator)
542542
CONSTANT_OWNERSHIP_BUILTIN(None, IntInstrprofIncrement)
543543
CONSTANT_OWNERSHIP_BUILTIN(None, GlobalStringTablePointer)
544+
CONSTANT_OWNERSHIP_BUILTIN(Owned, GetCurrentAsyncTask)
544545

545546
#undef CONSTANT_OWNERSHIP_BUILTIN
546547

@@ -570,12 +571,6 @@ UNOWNED_OR_NONE_DEPENDING_ON_RESULT(ZeroInitializer)
570571

571572
ValueOwnershipKind
572573
ValueOwnershipKindClassifier::visitBuiltinInst(BuiltinInst *BI) {
573-
if (auto kind = BI->getBuiltinKind()) {
574-
// The current async task is kept alive by the caller.
575-
if (*kind == BuiltinValueKind::GetCurrentAsyncTask)
576-
return ValueOwnershipKind::Unowned;
577-
}
578-
579574
// For now, just conservatively say builtins are None. We need to use a
580575
// builtin in here to guarantee correctness.
581576
return ValueOwnershipKindBuiltinVisitor().visit(BI);

lib/SILGen/SILGenBuiltin.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,6 +1402,7 @@ static ManagedValue emitBuiltinGetCurrentAsyncTask(
14021402
loc,
14031403
ctx.getIdentifier(getBuiltinName(BuiltinValueKind::GetCurrentAsyncTask)),
14041404
SGF.getLoweredType(ctx.TheNativeObjectType), SubstitutionMap(), { });
1405+
SGF.enterEndLifetimeCleanup(apply);
14051406
return ManagedValue::forUnmanaged(apply);
14061407
}
14071408

lib/SILGen/SILGenDecl.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,32 @@ CleanupHandle SILGenFunction::enterDestroyCleanup(SILValue valueOrAddr) {
13261326
return Cleanups.getTopCleanup();
13271327
}
13281328

1329+
namespace {
1330+
class EndLifetimeCleanup : public Cleanup {
1331+
SILValue v;
1332+
public:
1333+
EndLifetimeCleanup(SILValue v) : v(v) {}
1334+
1335+
void emit(SILGenFunction &SGF, CleanupLocation l,
1336+
ForUnwind_t forUnwind) override {
1337+
SGF.B.createEndLifetime(l, v);
1338+
}
1339+
1340+
void dump(SILGenFunction &) const override {
1341+
#ifndef NDEBUG
1342+
llvm::errs() << "EndLifetimeCleanup\n"
1343+
<< "State:" << getState() << "\n"
1344+
<< "Value:" << v << "\n";
1345+
#endif
1346+
}
1347+
};
1348+
} // end anonymous namespace
1349+
1350+
CleanupHandle SILGenFunction::enterEndLifetimeCleanup(SILValue value) {
1351+
Cleanups.pushCleanup<EndLifetimeCleanup>(value);
1352+
return Cleanups.getTopCleanup();
1353+
}
1354+
13291355
namespace {
13301356
/// A cleanup that deinitializes an opaque existential container
13311357
/// before a value has been stored into it, or after its value was taken.

lib/SILGen/SILGenFunction.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2000,7 +2000,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
20002000

20012001
/// Enter a cleanup to emit a ReleaseValue/DestroyAddr of the specified value.
20022002
CleanupHandle enterDestroyCleanup(SILValue valueOrAddr);
2003-
2003+
2004+
/// Enter cleanup to emit an EndLifetime operation for the given value.
2005+
CleanupHandle enterEndLifetimeCleanup(SILValue value);
2006+
20042007
/// Enter a cleanup to emit a DeinitExistentialAddr or DeinitExistentialBox
20052008
/// of the specified value.
20062009
CleanupHandle enterDeinitExistentialCleanup(CleanupState state,

lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ static bool isBarrier(SILInstruction *inst) {
140140
case BuiltinValueKind::GlobalStringTablePointer:
141141
case BuiltinValueKind::COWBufferForReading:
142142
case BuiltinValueKind::IntInstrprofIncrement:
143+
case BuiltinValueKind::GetCurrentAsyncTask:
143144
return false;
144145

145146
// Handle some rare builtins that may be sensitive to object lifetime

test/IRGen/async/builtins.sil

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@ bb0:
1414
%0 = builtin "getCurrentAsyncTask"() : $Builtin.NativeObject
1515
// CHECK-NEXT: [[TASK_COPY:%.*]] = call %swift.refcounted* @swift_retain(%swift.refcounted* returned [[TASK]])
1616
%1 = copy_value %0 : $Builtin.NativeObject
17+
end_lifetime %0 : $Builtin.NativeObject
1718
return %1 : $Builtin.NativeObject
1819
}

0 commit comments

Comments
 (0)