Skip to content

Commit 3bdd5cb

Browse files
committed
IRGen: async error ABI
Throwing functions pass the error result in `swiftself` to the resume partial function. Therefore, `() async -> ()` to `() async throws -> ()` is not ABI compatible. TODO: go through remaining failing IRGen async tests and replace the illegal convert_functions.
1 parent 5e68204 commit 3bdd5cb

File tree

51 files changed

+677
-274
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+677
-274
lines changed

include/swift/ABI/Task.h

+10-4
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ class AsyncTask : public Job {
390390
}
391391

392392
/// Retrieve the error.
393-
SwiftError *&getError() { return *&error; }
393+
SwiftError *&getError() { return error; }
394394

395395
/// Compute the offset of the storage from the base of the future
396396
/// fragment.
@@ -549,8 +549,6 @@ class YieldingAsyncContext : public AsyncContext {
549549
/// futures.
550550
class FutureAsyncContext : public AsyncContext {
551551
public:
552-
SwiftError **errorResult = nullptr;
553-
554552
using AsyncContext::AsyncContext;
555553
};
556554

@@ -565,13 +563,20 @@ using AsyncGenericClosureEntryPoint =
565563
void(OpaqueValue *,
566564
SWIFT_ASYNC_CONTEXT AsyncContext *, SWIFT_CONTEXT HeapObject *);
567565

566+
/// This matches the ABI of the resume function of a closure
567+
/// `() async throws -> ()`.
568+
using AsyncVoidClosureResumeEntryPoint =
569+
SWIFT_CC(swiftasync)
570+
void(SWIFT_ASYNC_CONTEXT AsyncContext *, SWIFT_CONTEXT SwiftError *);
571+
568572
class AsyncContextPrefix {
569573
public:
570574
// Async closure entry point adhering to compiler calling conv (e.g directly
571575
// passing the closure context instead of via the async context)
572576
AsyncVoidClosureEntryPoint *__ptrauth_swift_task_resume_function
573577
asyncEntryPoint;
574-
HeapObject *closureContext;
578+
HeapObject *closureContext;
579+
SwiftError *errorResult;
575580
};
576581

577582
/// Storage that is allocated before the AsyncContext to be used by an adapter
@@ -584,6 +589,7 @@ class FutureAsyncContextPrefix {
584589
AsyncGenericClosureEntryPoint *__ptrauth_swift_task_resume_function
585590
asyncEntryPoint;
586591
HeapObject *closureContext;
592+
SwiftError *errorResult;
587593
};
588594

589595
} // end namespace swift

lib/IRGen/GenCall.cpp

+103-25
Original file line numberDiff line numberDiff line change
@@ -159,27 +159,38 @@ irgen::getAsyncContextLayout(IRGenModule &IGM, CanSILFunctionType originalType,
159159
switch (kind.getSpecialKind()) {
160160
case FunctionPointer::SpecialKind::TaskFutureWait:
161161
case FunctionPointer::SpecialKind::TaskFutureWaitThrowing: {
162+
// This needs to match the layout of TaskFutureWaitAsyncContext.
162163
// Add storage for the waiting future's result pointer (OpaqueValue *).
163164
auto ty = SILType();
164165
auto &ti = IGM.getSwiftContextPtrTypeInfo();
166+
// SwiftError *
167+
valTypes.push_back(ty);
168+
typeInfos.push_back(&ti);
165169
// OpaqueValue *successResultPointer
166170
valTypes.push_back(ty);
167171
typeInfos.push_back(&ti);
168-
// AsyncTask *task;
169-
//valTypes.push_back(ty);
170-
//typeInfos.push_back(&ti);
172+
// void (*, *) async *asyncResumeEntryPoint;
173+
valTypes.push_back(ty);
174+
typeInfos.push_back(&ti);
171175
} break;
172176
case FunctionPointer::SpecialKind::TaskGroupWaitNext: {
177+
// This needs to match the layout of TaskGroupNextAsyncContext.
173178
// Add storage for the waiting future's result pointer (OpaqueValue *).
174179
auto ty = SILType();
175180
auto &ti = IGM.getSwiftContextPtrTypeInfo();
176-
// OpaqueValue *successResultPointer
181+
// SwiftError * errorResult;
182+
valTypes.push_back(ty);
183+
typeInfos.push_back(&ti);
184+
// OpaqueValue *successResultPointer;
185+
valTypes.push_back(ty);
186+
typeInfos.push_back(&ti);
187+
// void (*, *) async *asyncResumeEntryPoint;
177188
valTypes.push_back(ty);
178189
typeInfos.push_back(&ti);
179190
// TaskGroup *group;
180191
valTypes.push_back(ty);
181192
typeInfos.push_back(&ti);
182-
// const Metadata *successType;
193+
// Metata *successType;
183194
valTypes.push_back(ty);
184195
typeInfos.push_back(&ti);
185196
} break;
@@ -427,6 +438,7 @@ namespace {
427438
bool CanUseSelf = true;
428439
bool SuppressGenerics;
429440
unsigned AsyncContextIdx;
441+
unsigned AsyncResumeFunctionSwiftSelfIdx = 0;
430442

431443
SignatureExpansion(IRGenModule &IGM, CanSILFunctionType fnType,
432444
bool suppressGenerics)
@@ -1722,24 +1734,41 @@ void SignatureExpansion::expandCoroutineContinuationType() {
17221734
void SignatureExpansion::expandAsyncReturnType() {
17231735
// Build up the signature of the return continuation function.
17241736
// void (AsyncTask *, ExecutorRef, AsyncContext *, DirectResult0, ...,
1725-
// DirectResultN);
1737+
// DirectResultN, Error*);
17261738
ResultIRType = IGM.VoidTy;
17271739
addAsyncParameters();
17281740
SmallVector<llvm::Type *, 8> components;
1741+
1742+
auto addErrorResult = [&]() {
1743+
// Add the error pointer at the end.
1744+
if (FnType->hasErrorResult()) {
1745+
llvm::Type *errorType =
1746+
IGM.getStorageType(getSILFuncConventions().getSILType(
1747+
FnType->getErrorResult(), IGM.getMaximalTypeExpansionContext()));
1748+
claimSelf();
1749+
auto selfIdx = ParamIRTypes.size();
1750+
IGM.addSwiftSelfAttributes(Attrs, selfIdx);
1751+
AsyncResumeFunctionSwiftSelfIdx = selfIdx;
1752+
ParamIRTypes.push_back(errorType);
1753+
}
1754+
};
1755+
17291756
auto resultType = getSILFuncConventions().getSILResultType(
17301757
IGM.getMaximalTypeExpansionContext());
17311758
auto &ti = IGM.getTypeInfo(resultType);
17321759
auto &native = ti.nativeReturnValueSchema(IGM);
1733-
if (native.requiresIndirect())
1734-
return;
1735-
if (native.empty())
1760+
if (native.requiresIndirect() || native.empty()) {
1761+
addErrorResult();
17361762
return;
1763+
}
17371764

17381765
// Add the result type components as trailing parameters.
17391766
native.enumerateComponents(
17401767
[&](clang::CharUnits offset, clang::CharUnits end, llvm::Type *type) {
17411768
ParamIRTypes.push_back(type);
17421769
});
1770+
1771+
addErrorResult();
17431772
}
17441773

17451774
void SignatureExpansion::expandAsyncEntryType() {
@@ -1834,12 +1863,24 @@ void SignatureExpansion::expandAsyncAwaitType() {
18341863
AsyncContextIdx = 0;
18351864
components.push_back(IGM.Int8PtrTy);
18361865

1866+
auto addErrorResult = [&]() {
1867+
if (FnType->hasErrorResult()) {
1868+
llvm::Type *errorType =
1869+
IGM.getStorageType(getSILFuncConventions().getSILType(
1870+
FnType->getErrorResult(), IGM.getMaximalTypeExpansionContext()));
1871+
auto selfIdx = components.size();
1872+
AsyncResumeFunctionSwiftSelfIdx = selfIdx;
1873+
components.push_back(errorType);
1874+
}
1875+
};
1876+
18371877
// Direct result type as arguments.
18381878
auto resultType = getSILFuncConventions().getSILResultType(
18391879
IGM.getMaximalTypeExpansionContext());
18401880
auto &ti = IGM.getTypeInfo(resultType);
18411881
auto &native = ti.nativeReturnValueSchema(IGM);
18421882
if (native.requiresIndirect() || native.empty()) {
1883+
addErrorResult();
18431884
ResultIRType = llvm::StructType::get(IGM.getLLVMContext(), components);
18441885
return;
18451886
}
@@ -1849,6 +1890,9 @@ void SignatureExpansion::expandAsyncAwaitType() {
18491890
[&](clang::CharUnits offset, clang::CharUnits end, llvm::Type *type) {
18501891
components.push_back(type);
18511892
});
1893+
1894+
addErrorResult();
1895+
18521896
ResultIRType = llvm::StructType::get(IGM.getLLVMContext(), components);
18531897
}
18541898

@@ -1881,6 +1925,7 @@ Signature SignatureExpansion::getSignature() {
18811925
result.ExtraDataKind = ExtraData::kindForMember<AsyncInfo>();
18821926
AsyncInfo info;
18831927
info.AsyncContextIdx = AsyncContextIdx;
1928+
info.AsyncResumeFunctionSwiftSelfIdx = AsyncResumeFunctionSwiftSelfIdx;
18841929
result.ExtraDataStorage.emplace<AsyncInfo>(result.ExtraDataKind, info);
18851930
} else {
18861931
result.ExtraDataKind = ExtraData::kindForMember<void>();
@@ -2451,16 +2496,43 @@ class AsyncCallEmission final : public CallEmission {
24512496
auto resultTys =
24522497
makeArrayRef(suspendResultTy->element_begin() + numAsyncContextParams,
24532498
suspendResultTy->element_end());
2499+
2500+
auto substCalleeType = getCallee().getSubstFunctionType();
2501+
SILFunctionConventions substConv(substCalleeType, IGF.getSILModule());
2502+
auto hasError = substCalleeType->hasErrorResult();
2503+
SILType errorType;
2504+
if (hasError)
2505+
errorType =
2506+
substConv.getSILErrorType(IGM.getMaximalTypeExpansionContext());
2507+
24542508
if (resultTys.size() == 1) {
24552509
result = Builder.CreateExtractValue(result, numAsyncContextParams);
2510+
if (hasError) {
2511+
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType);
2512+
Builder.CreateStore(result, errorAddr);
2513+
return;
2514+
}
2515+
} else if (resultTys.size() == 2 && hasError) {
2516+
auto tmp = result;
2517+
result = Builder.CreateExtractValue(result, numAsyncContextParams);
2518+
auto errorResult = Builder.CreateExtractValue(tmp, numAsyncContextParams + 1);
2519+
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType);
2520+
Builder.CreateStore(errorResult, errorAddr);
24562521
} else {
2457-
auto resultTy = llvm::StructType::get(IGM.getLLVMContext(), resultTys);
2522+
auto directResultTys = hasError ? resultTys.drop_back() : resultTys;
2523+
auto resultTy = llvm::StructType::get(IGM.getLLVMContext(), directResultTys);
24582524
llvm::Value *resultAgg = llvm::UndefValue::get(resultTy);
2459-
for (unsigned i = 0, e = resultTys.size(); i != e; ++i) {
2525+
for (unsigned i = 0, e = directResultTys.size(); i != e; ++i) {
24602526
llvm::Value *elt =
24612527
Builder.CreateExtractValue(result, numAsyncContextParams + i);
24622528
resultAgg = Builder.CreateInsertValue(resultAgg, elt, i);
24632529
}
2530+
if (hasError) {
2531+
auto errorResult = Builder.CreateExtractValue(
2532+
result, numAsyncContextParams + directResultTys.size());
2533+
Address errorAddr = IGF.getCalleeErrorResultSlot(errorType);
2534+
Builder.CreateStore(errorResult, errorAddr);
2535+
}
24642536
result = resultAgg;
24652537
}
24662538

@@ -2496,17 +2568,7 @@ class AsyncCallEmission final : public CallEmission {
24962568
out = nativeSchema.mapFromNative(IGF.IGM, IGF, nativeExplosion, resultType);
24972569
}
24982570
Address getCalleeErrorSlot(SILType errorType, bool isCalleeAsync) override {
2499-
if (isCalleeAsync) {
2500-
auto layout = getAsyncContextLayout();
2501-
auto errorLayout = layout.getErrorLayout();
2502-
auto pointerToAddress =
2503-
errorLayout.project(IGF, context, /*offsets*/ llvm::None);
2504-
auto load = IGF.Builder.CreateLoad(pointerToAddress);
2505-
auto address = Address(load, IGF.IGM.getPointerAlignment());
2506-
return address;
2507-
} else {
2508-
return IGF.getCalleeErrorResultSlot(errorType);
2509-
}
2571+
return IGF.getCalleeErrorResultSlot(errorType);
25102572
}
25112573

25122574
FunctionPointer getFunctionPointerForDispatchCall(const FunctionPointer &fn) {
@@ -2530,9 +2592,14 @@ class AsyncCallEmission final : public CallEmission {
25302592
// Setup the suspend point.
25312593
SmallVector<llvm::Value *, 8> arguments;
25322594
auto signature = fn.getSignature();
2533-
auto asyncContextIndex = signature.getAsyncContextIndex();
2595+
auto asyncContextIndex =
2596+
signature.getAsyncContextIndex();
2597+
auto paramAttributeFlags =
2598+
asyncContextIndex |
2599+
(signature.getAsyncResumeFunctionSwiftSelfIndex() << 8);
2600+
// Index of swiftasync context | ((index of swiftself) << 8).
25342601
arguments.push_back(
2535-
IGM.getInt32(asyncContextIndex)); // Index of swiftasync context.
2602+
IGM.getInt32(paramAttributeFlags));
25362603
arguments.push_back(currentResumeFn);
25372604
auto resumeProjFn = IGF.getOrCreateResumePrjFn();
25382605
arguments.push_back(
@@ -4750,7 +4817,11 @@ void irgen::emitAsyncReturn(
47504817

47514818
void irgen::emitAsyncReturn(IRGenFunction &IGF, AsyncContextLayout &asyncLayout,
47524819
SILType funcResultTypeInContext,
4753-
CanSILFunctionType fnType, Explosion &result) {
4820+
CanSILFunctionType fnType, Explosion &result,
4821+
Explosion &error) {
4822+
assert((fnType->hasErrorResult() && !error.empty()) ||
4823+
(!fnType->hasErrorResult() && error.empty()));
4824+
47544825
auto &IGM = IGF.IGM;
47554826

47564827
// Map the explosion to the native result type.
@@ -4766,6 +4837,8 @@ void irgen::emitAsyncReturn(IRGenFunction &IGF, AsyncContextLayout &asyncLayout,
47664837
llvm::Type *componentTy) {
47674838
nativeResultsStorage.push_back(llvm::UndefValue::get(componentTy));
47684839
});
4840+
if (!error.empty())
4841+
nativeResultsStorage.push_back(error.claimNext());
47694842
nativeResults = nativeResultsStorage;
47704843
} else if (!result.empty()) {
47714844
assert(!nativeSchema.empty());
@@ -4775,6 +4848,11 @@ void irgen::emitAsyncReturn(IRGenFunction &IGF, AsyncContextLayout &asyncLayout,
47754848
while (!native.empty()) {
47764849
nativeResultsStorage.push_back(native.claimNext());
47774850
}
4851+
if (!error.empty())
4852+
nativeResultsStorage.push_back(error.claimNext());
4853+
nativeResults = nativeResultsStorage;
4854+
} else if (!error.empty()) {
4855+
nativeResultsStorage.push_back(error.claimNext());
47784856
nativeResults = nativeResultsStorage;
47794857
}
47804858
emitAsyncReturn(IGF, asyncLayout, fnType, nativeResults);

lib/IRGen/GenCall.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,8 @@ namespace irgen {
283283

284284
void emitAsyncReturn(IRGenFunction &IGF, AsyncContextLayout &layout,
285285
SILType funcResultTypeInContext,
286-
CanSILFunctionType fnType, Explosion &result);
286+
CanSILFunctionType fnType, Explosion &result,
287+
Explosion &error);
287288

288289
Address emitAutoDiffCreateLinearMapContext(
289290
IRGenFunction &IGF, llvm::Value *topLevelSubcontextSize);

lib/IRGen/GenThunk.cpp

+5-12
Original file line numberDiff line numberDiff line change
@@ -138,13 +138,7 @@ void IRGenThunk::prepareArguments() {
138138

139139
if (origTy->hasErrorResult()) {
140140
if (isAsync) {
141-
auto context = asyncLayout->emitCastTo(IGF, IGF.getAsyncContext());
142-
auto errorLayout = asyncLayout->getErrorLayout();
143-
Address pointerToAddress =
144-
errorLayout.project(IGF, context, /*offsets*/ llvm::None);
145-
auto load = IGF.Builder.CreateLoad(pointerToAddress);
146-
auto addr = Address(load, IGF.IGM.getPointerAlignment());
147-
IGF.setCallerErrorResultSlot(addr.getAddress());
141+
// nothing to do.
148142
} else {
149143
errorResult = original.takeLast();
150144
IGF.setCallerErrorResultSlot(errorResult);
@@ -316,12 +310,11 @@ void IRGenThunk::emit() {
316310

317311
emission->end();
318312

319-
if (isAsync && errorValue) {
320-
IGF.Builder.CreateStore(errorValue, IGF.getCallerErrorResultSlot());
321-
}
322-
323313
if (isAsync) {
324-
emitAsyncReturn(IGF, *asyncLayout, directResultType, origTy, result);
314+
Explosion error;
315+
if (errorValue)
316+
error.add(errorValue);
317+
emitAsyncReturn(IGF, *asyncLayout, directResultType, origTy, result, error);
325318
return;
326319
}
327320

0 commit comments

Comments
 (0)