Skip to content

Commit e2a8abc

Browse files
committed
[Async CC] Make error indirect.
Previously, the error stored in the async context was of type SwiftError *. In order to enable the context to be callee released, make it indirect and change its type to SwiftError **. rdar://71378532
1 parent 1d13550 commit e2a8abc

File tree

13 files changed

+251
-62
lines changed

13 files changed

+251
-62
lines changed

include/swift/ABI/Task.h

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -600,8 +600,10 @@ class AsyncTask : public HeapObject, public Job {
600600
/// The type of the result that will be produced by the future.
601601
const Metadata *resultType;
602602

603-
// Trailing storage for the result itself. The storage will be uninitialized,
604-
// contain an instance of \c resultType, or contain an an \c Error.
603+
SwiftError *error = nullptr;
604+
605+
// Trailing storage for the result itself. The storage will be
606+
// uninitialized, contain an instance of \c resultType.
605607

606608
friend class AsyncTask;
607609

@@ -620,25 +622,20 @@ class AsyncTask : public HeapObject, public Job {
620622
}
621623

622624
/// Retrieve the error.
623-
SwiftError *&getError() {
624-
return *reinterpret_cast<SwiftError **>(
625-
reinterpret_cast<char *>(this) + storageOffset(resultType));
626-
}
625+
SwiftError *&getError() { return *&error; }
627626

628627
/// Compute the offset of the storage from the base of the future
629628
/// fragment.
630629
static size_t storageOffset(const Metadata *resultType) {
631630
size_t offset = sizeof(FutureFragment);
632-
size_t alignment =
633-
std::max(resultType->vw_alignment(), alignof(SwiftError *));
631+
size_t alignment = resultType->vw_alignment();
634632
return (offset + alignment - 1) & ~(alignment - 1);
635633
}
636634

637635
/// Determine the size of the future fragment given a particular future
638636
/// result type.
639637
static size_t fragmentSize(const Metadata *resultType) {
640-
return storageOffset(resultType) +
641-
std::max(resultType->vw_size(), sizeof(SwiftError *));
638+
return storageOffset(resultType) + resultType->vw_size();
642639
}
643640
};
644641

@@ -791,7 +788,7 @@ class YieldingAsyncContext : public AsyncContext {
791788
/// futures.
792789
class FutureAsyncContext : public AsyncContext {
793790
public:
794-
SwiftError *errorResult = nullptr;
791+
SwiftError **errorResult = nullptr;
795792
OpaqueValue *indirectResult;
796793

797794
using AsyncContext::AsyncContext;

lib/IRGen/CallEmission.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ class CallEmission {
9595
/// Set the arguments to the function from an explosion.
9696
virtual void setArgs(Explosion &arg, bool isOutlined,
9797
WitnessMetadata *witnessMetadata);
98-
virtual Address getCalleeErrorSlot(SILType errorType) = 0;
98+
virtual Address getCalleeErrorSlot(SILType errorType, bool isCalleeAsync) = 0;
9999

100100
void addAttribute(unsigned Index, llvm::Attribute::AttrKind Attr);
101101

lib/IRGen/GenCall.cpp

Lines changed: 61 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,11 @@ irgen::getAsyncContextLayout(IRGenModule &IGM, CanSILFunctionType originalType,
150150
addTaskContinuationFunction();
151151
}
152152

153-
// SwiftError *errorResult;
153+
// SwiftError **errorResult;
154154
auto errorCanType = IGM.Context.getExceptionType();
155155
auto errorType = SILType::getPrimitiveObjectType(errorCanType);
156-
auto &errorTypeInfo = IGM.getTypeInfoForLowered(errorCanType);
156+
auto &errorTypeInfo =
157+
IGM.getTypeInfoForLowered(CanInOutType::get(errorCanType));
157158
typeInfos.push_back(&errorTypeInfo);
158159
valTypes.push_back(errorType);
159160

@@ -2320,7 +2321,7 @@ class SyncCallEmission final : public CallEmission {
23202321

23212322
out = nativeSchema.mapFromNative(IGF.IGM, IGF, nativeExplosion, resultType);
23222323
}
2323-
Address getCalleeErrorSlot(SILType errorType) override {
2324+
Address getCalleeErrorSlot(SILType errorType, bool isCalleeAsync) override {
23242325
return IGF.getCalleeErrorResultSlot(errorType);
23252326
};
23262327
};
@@ -2378,10 +2379,10 @@ class AsyncCallEmission final : public CallEmission {
23782379
context = layout.emitCastTo(IGF, contextBuffer.getAddress());
23792380
if (layout.canHaveError()) {
23802381
auto fieldLayout = layout.getErrorLayout();
2381-
auto addr = fieldLayout.project(IGF, context, /*offsets*/ llvm::None);
2382-
auto &ti = fieldLayout.getType();
2383-
auto nullError = llvm::Constant::getNullValue(ti.getStorageType());
2384-
IGF.Builder.CreateStore(nullError, addr);
2382+
auto ptrToAddr =
2383+
fieldLayout.project(IGF, context, /*offsets*/ llvm::None);
2384+
auto errorSlot = IGF.getAsyncCalleeErrorResultSlot(layout.getErrorType());
2385+
IGF.Builder.CreateStore(errorSlot.getAddress(), ptrToAddr);
23852386
}
23862387
}
23872388
void end() override {
@@ -2504,11 +2505,18 @@ class AsyncCallEmission final : public CallEmission {
25042505
loadValue(fieldLayout, out);
25052506
}
25062507
}
2507-
Address getCalleeErrorSlot(SILType errorType) override {
2508-
auto layout = getAsyncContextLayout();
2509-
auto errorLayout = layout.getErrorLayout();
2510-
auto address = errorLayout.project(IGF, context, /*offsets*/ llvm::None);
2511-
return address;
2508+
Address getCalleeErrorSlot(SILType errorType, bool isCalleeAsync) override {
2509+
if (isCalleeAsync) {
2510+
auto layout = getAsyncContextLayout();
2511+
auto errorLayout = layout.getErrorLayout();
2512+
auto pointerToAddress =
2513+
errorLayout.project(IGF, context, /*offsets*/ llvm::None);
2514+
auto load = IGF.Builder.CreateLoad(pointerToAddress);
2515+
auto address = Address(load, IGF.IGM.getPointerAlignment());
2516+
return address;
2517+
} else {
2518+
return IGF.getCalleeErrorResultSlot(errorType);
2519+
}
25122520
};
25132521

25142522
llvm::CallInst *createCall(const FunctionPointer &fn,
@@ -3931,42 +3939,60 @@ Explosion IRGenFunction::collectParameters() {
39313939
return params;
39323940
}
39333941

3934-
/// Fetch the error result slot.
3935-
Address IRGenFunction::getCalleeErrorResultSlot(SILType errorType) {
3936-
if (!CalleeErrorResultSlot) {
3937-
auto &errorTI = cast<FixedTypeInfo>(getTypeInfo(errorType));
3942+
Address IRGenFunction::createErrorResultSlot(SILType errorType, bool isAsync) {
3943+
auto &errorTI = cast<FixedTypeInfo>(getTypeInfo(errorType));
39383944

3939-
IRBuilder builder(IGM.getLLVMContext(), IGM.DebugInfo != nullptr);
3940-
builder.SetInsertPoint(AllocaIP->getParent(), AllocaIP->getIterator());
3945+
IRBuilder builder(IGM.getLLVMContext(), IGM.DebugInfo != nullptr);
3946+
builder.SetInsertPoint(AllocaIP->getParent(), AllocaIP->getIterator());
39413947

3942-
// Create the alloca. We don't use allocateStack because we're
3943-
// not allocating this in stack order.
3944-
auto addr = createAlloca(errorTI.getStorageType(),
3945-
errorTI.getFixedAlignment(),
3946-
"swifterror");
3948+
// Create the alloca. We don't use allocateStack because we're
3949+
// not allocating this in stack order.
3950+
auto addr = createAlloca(errorTI.getStorageType(),
3951+
errorTI.getFixedAlignment(), "swifterror");
39473952

3948-
// Only add the swifterror attribute on ABIs that pass it in a register.
3949-
// We create a shadow stack location of the swifterror parameter for the
3950-
// debugger on platforms that pass swifterror by reference and so we can't
3951-
// mark the parameter with a swifterror attribute for these.
3952-
if (IGM.IsSwiftErrorInRegister)
3953-
cast<llvm::AllocaInst>(addr.getAddress())->setSwiftError(true);
3953+
// Only add the swifterror attribute on ABIs that pass it in a register.
3954+
// We create a shadow stack location of the swifterror parameter for the
3955+
// debugger on platforms that pass swifterror by reference and so we can't
3956+
// mark the parameter with a swifterror attribute for these.
3957+
// The slot for async callees cannot be annotated swifterror because those
3958+
// errors are never passed in registers but rather are always passed
3959+
// indirectly in the async context.
3960+
if (IGM.IsSwiftErrorInRegister && !isAsync)
3961+
cast<llvm::AllocaInst>(addr.getAddress())->setSwiftError(true);
3962+
3963+
// Initialize at the alloca point.
3964+
auto nullError = llvm::ConstantPointerNull::get(
3965+
cast<llvm::PointerType>(errorTI.getStorageType()));
3966+
builder.CreateStore(nullError, addr);
39543967

3955-
// Initialize at the alloca point.
3956-
auto nullError = llvm::ConstantPointerNull::get(
3957-
cast<llvm::PointerType>(errorTI.getStorageType()));
3958-
builder.CreateStore(nullError, addr);
3968+
return addr;
3969+
}
39593970

3960-
CalleeErrorResultSlot = addr.getAddress();
3971+
/// Fetch the error result slot.
3972+
Address IRGenFunction::getCalleeErrorResultSlot(SILType errorType) {
3973+
if (!CalleeErrorResultSlot) {
3974+
CalleeErrorResultSlot =
3975+
createErrorResultSlot(errorType, /*isAsync=*/false).getAddress();
39613976
}
39623977
return Address(CalleeErrorResultSlot, IGM.getPointerAlignment());
39633978
}
39643979

3980+
/// Fetch the error result slot.
3981+
Address IRGenFunction::getAsyncCalleeErrorResultSlot(SILType errorType) {
3982+
assert(isAsync() &&
3983+
"throwing async functions must be called from async functions");
3984+
if (!AsyncCalleeErrorResultSlot) {
3985+
AsyncCalleeErrorResultSlot =
3986+
createErrorResultSlot(errorType, /*isAsync=*/true).getAddress();
3987+
}
3988+
return Address(AsyncCalleeErrorResultSlot, IGM.getPointerAlignment());
3989+
}
3990+
39653991
/// Fetch the error result slot received from the caller.
39663992
Address IRGenFunction::getCallerErrorResultSlot() {
39673993
assert(CallerErrorResultSlot && "no error result slot!");
39683994
assert(isa<llvm::Argument>(CallerErrorResultSlot) && !isAsync() ||
3969-
isa<llvm::GetElementPtrInst>(CallerErrorResultSlot) && isAsync() &&
3995+
isa<llvm::LoadInst>(CallerErrorResultSlot) && isAsync() &&
39703996
"error result slot is local!");
39713997
return Address(CallerErrorResultSlot, IGM.getPointerAlignment());
39723998
}

lib/IRGen/GenCall.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ namespace irgen {
7070
// SwiftPartialFunction * __ptrauth(...) returnToCaller;
7171
// SwiftActor * __ptrauth(...) callerActor;
7272
// SwiftPartialFunction * __ptrauth(...) yieldToCaller?;
73-
// SwiftError *errorResult;
73+
// SwiftError **errorResult;
7474
// IndirectResultTypes *indirectResults...;
7575
// union {
7676
// struct {

lib/IRGen/GenThunk.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,11 @@ void IRGenThunk::prepareArguments() {
153153
}
154154

155155
if (origTy->hasErrorResult()) {
156-
Address addr = asyncLayout->getErrorLayout().project(
157-
IGF, context, llvm::None);
156+
auto errorLayout = asyncLayout->getErrorLayout();
157+
Address pointerToAddress =
158+
errorLayout.project(IGF, context, /*offsets*/ llvm::None);
159+
auto load = IGF.Builder.CreateLoad(pointerToAddress);
160+
auto addr = Address(load, IGF.IGM.getPointerAlignment());
158161
IGF.setCallerErrorResultSlot(addr.getAddress());
159162
}
160163

@@ -334,7 +337,8 @@ void IRGenThunk::emit() {
334337

335338
if (isAsync && origTy->hasErrorResult()) {
336339
SILType errorType = conv.getSILErrorType(expansionContext);
337-
Address calleeErrorSlot = emission->getCalleeErrorSlot(errorType);
340+
Address calleeErrorSlot = emission->getCalleeErrorSlot(
341+
errorType, /*isCalleeAsync=*/origTy->isAsync());
338342
errorValue = IGF.Builder.CreateLoad(calleeErrorSlot);
339343
}
340344

lib/IRGen/IRGenFunction.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,10 @@ class IRGenFunction {
8989

9090
friend class Scope;
9191

92-
//--- Function prologue and epilogue -------------------------------------------
92+
Address createErrorResultSlot(SILType errorType, bool isAsync);
93+
94+
//--- Function prologue and epilogue
95+
//-------------------------------------------
9396
public:
9497
Explosion collectParameters();
9598
void emitScalarReturn(SILType returnResultType, SILType funcResultType,
@@ -106,6 +109,7 @@ class IRGenFunction {
106109
/// For async functions, this is different from the caller result slot because
107110
/// that is a gep into the %swift.context.
108111
Address getCalleeErrorResultSlot(SILType errorType);
112+
Address getAsyncCalleeErrorResultSlot(SILType errorType);
109113

110114
/// Return the error result slot provided by the caller.
111115
Address getCallerErrorResultSlot();
@@ -165,6 +169,7 @@ class IRGenFunction {
165169
Address ReturnSlot;
166170
llvm::BasicBlock *ReturnBB;
167171
llvm::Value *CalleeErrorResultSlot = nullptr;
172+
llvm::Value *AsyncCalleeErrorResultSlot = nullptr;
168173
llvm::Value *CallerErrorResultSlot = nullptr;
169174
llvm::Value *CoroutineHandle = nullptr;
170175
llvm::Value *AsyncCoroutineCurrentResume = nullptr;

lib/IRGen/IRGenSIL.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,7 +1295,10 @@ class AsyncNativeCCEntryPointArgumentEmission final
12951295

12961296
llvm::Value *getCallerErrorResultArgument() override {
12971297
auto errorLayout = layout.getErrorLayout();
1298-
Address addr = errorLayout.project(IGF, dataAddr, /*offsets*/ llvm::None);
1298+
Address pointerToAddress =
1299+
errorLayout.project(IGF, dataAddr, /*offsets*/ llvm::None);
1300+
auto load = IGF.Builder.CreateLoad(pointerToAddress);
1301+
auto addr = Address(load, IGF.IGM.getPointerAlignment());
12991302
return addr.getAddress();
13001303
}
13011304
llvm::Value *getContext() override {
@@ -2837,7 +2840,8 @@ void IRGenSILFunction::visitFullApplySite(FullApplySite site) {
28372840
SILFunctionConventions substConv(substCalleeType, getSILModule());
28382841
SILType errorType =
28392842
substConv.getSILErrorType(IGM.getMaximalTypeExpansionContext());
2840-
Address calleeErrorSlot = emission->getCalleeErrorSlot(errorType);
2843+
Address calleeErrorSlot = emission->getCalleeErrorSlot(
2844+
errorType, /*isCalleeAsync=*/site.getOrigCalleeType()->isAsync());
28412845
auto errorValue = Builder.CreateLoad(calleeErrorSlot);
28422846
emission->end();
28432847

stdlib/public/Concurrency/AsyncCall.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,12 @@ struct AsyncFrameLayout;
6363

6464
template <class... ArgTys, bool HasErrorResult>
6565
struct AsyncFrameLayout<AsyncSignature<void(ArgTys...), HasErrorResult>> {
66-
using BasicLayout = BasicLayout<0, SwiftError*, ArgTys...>;
66+
using BasicLayout = BasicLayout<0, SwiftError **, ArgTys...>;
6767
static constexpr size_t firstArgIndex = 1;
6868
};
6969
template <class ResultTy, class... ArgTys, bool HasErrorResult>
7070
struct AsyncFrameLayout<AsyncSignature<ResultTy(ArgTys...), HasErrorResult>> {
71-
using BasicLayout = BasicLayout<0, SwiftError*, ResultTy, ArgTys...>;
71+
using BasicLayout = BasicLayout<0, SwiftError **, ResultTy, ArgTys...>;
7272
static constexpr size_t firstArgIndex = 2;
7373
};
7474

stdlib/public/Concurrency/Task.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ void AsyncTask::completeFuture(AsyncContext *context, ExecutorRef executor) {
9494
// If an error was thrown, save it in the future fragment.
9595
auto futureContext = static_cast<FutureAsyncContext *>(context);
9696
bool hadErrorResult = false;
97-
if (auto errorObject = futureContext->errorResult) {
97+
if (auto errorObject = *futureContext->errorResult) {
9898
fragment->getError() = errorObject;
9999
hadErrorResult = true;
100100
}
@@ -283,7 +283,7 @@ AsyncTaskAndContext swift::swift_task_create_future_f(
283283
// Set up the context for the future so there is no error, and a successful
284284
// result will be written into the future fragment's storage.
285285
auto futureContext = static_cast<FutureAsyncContext *>(initialContext);
286-
futureContext->errorResult = nullptr;
286+
futureContext->errorResult = &futureFragment->getError();
287287
futureContext->indirectResult = futureFragment->getStoragePtr();
288288
}
289289

stdlib/public/Concurrency/TaskGroup.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ void AsyncTask::groupOffer(AsyncTask *completedTask, AsyncContext *context,
7474
// If an error was thrown, save it in the future fragment.
7575
auto futureContext = static_cast<FutureAsyncContext *>(context);
7676
bool hadErrorResult = false;
77-
if (auto errorObject = futureContext->errorResult) {
77+
if (auto errorObject = *futureContext->errorResult) {
7878
// instead we need to enqueue this result:
7979
hadErrorResult = true;
8080
}

stdlib/public/Concurrency/TaskPrivate.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ namespace {
6060
class TaskFutureWaitAsyncContext : public AsyncContext {
6161
public:
6262
// Error result is always present.
63-
SwiftError *errorResult = nullptr;
63+
SwiftError **errorResult = nullptr;
6464

6565
// No indirect results.
6666

test/IRGen/async/hop_to_executor.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ final actor MyActor {
1414
// CHECK-LABEL: define{{.*}} void @test_simple(%swift.task* %0, %swift.executor* %1, %swift.context* swiftasync %2)
1515
// CHECK: [[TASK_LOC:%[0-9]+]] = alloca %swift.task*
1616
// CHECK: [[CTX:%[0-9]+]] = bitcast %swift.context* %2
17-
// CHECK-32: [[ACTOR_ADDR:%[0-9]+]] = getelementptr inbounds <{ %swift.context*, void (%swift.task*, %swift.executor*, %swift.context*)*, %swift.executor*, i32, %swift.error*, %T4test7MyActorC* }>, {{.*}} [[CTX]], i32 0, i32 5
18-
// CHECK-64: [[ACTOR_ADDR:%[0-9]+]] = getelementptr inbounds <{ %swift.context*, void (%swift.task*, %swift.executor*, %swift.context*)*, %swift.executor*, i32, [4 x i8], %swift.error*, %T4test7MyActorC* }>, {{.*}} [[CTX]], i32 0, i32 6
17+
// CHECK-32: [[ACTOR_ADDR:%[0-9]+]] = getelementptr inbounds <{ %swift.context*, void (%swift.task*, %swift.executor*, %swift.context*)*, %swift.executor*, i32, %swift.error**, %T4test7MyActorC* }>, {{.*}} [[CTX]], i32 0, i32 5
18+
// CHECK-64: [[ACTOR_ADDR:%[0-9]+]] = getelementptr inbounds <{ %swift.context*, void (%swift.task*, %swift.executor*, %swift.context*)*, %swift.executor*, i32, [4 x i8], %swift.error**, %T4test7MyActorC* }>, {{.*}} [[CTX]], i32 0, i32 6
1919
// CHECK: [[ACTOR:%[0-9]+]] = load %T4test7MyActorC*, %T4test7MyActorC** [[ACTOR_ADDR]]
2020
// CHECK: [[RESUME:%[0-9]+]] = call i8* @llvm.coro.async.resume()
2121
// CHECK: [[TASK:%[0-9]+]] = load %swift.task*, %swift.task** [[TASK_LOC]]

0 commit comments

Comments
 (0)