|
26 | 26 | #include "IRGenModule.h"
|
27 | 27 | #include "LoadableTypeInfo.h"
|
28 | 28 | #include "ScalarPairTypeInfo.h"
|
| 29 | +#include "swift/AST/ASTContext.h" |
29 | 30 | #include "swift/AST/ProtocolConformanceRef.h"
|
30 | 31 | #include "swift/ABI/MetadataValues.h"
|
31 | 32 |
|
@@ -192,6 +193,44 @@ llvm::Value *irgen::emitBuiltinStartAsyncLet(IRGenFunction &IGF,
|
192 | 193 | auto futureResultType = subs.getReplacementTypes()[0]->getCanonicalType();
|
193 | 194 | auto futureResultTypeMetadata = IGF.emitAbstractTypeMetadataRef(futureResultType);
|
194 | 195 |
|
| 196 | + // The concurrency runtime for older Apple OSes has a bug in task formation |
| 197 | + // for `async let`s that may manifest when trying to use room in the |
| 198 | + // parent task's preallocated `async let` buffer for the child task's |
| 199 | + // initial task allocator slab. If targeting those older OSes, pad the |
| 200 | + // context size for async let entry points to never fit in the preallocated |
| 201 | + // space, so that we don't run into that bug. We leave a note on the |
| 202 | + // declaration so that coroutine splitting can pad out the final context |
| 203 | + // size after splitting. |
| 204 | + auto deploymentAvailability |
| 205 | + = AvailabilityContext::forDeploymentTarget(IGF.IGM.Context); |
| 206 | + if (!deploymentAvailability.isContainedIn( |
| 207 | + IGF.IGM.Context.getSwift57Availability())) { |
| 208 | + auto taskAsyncFunctionPointer |
| 209 | + = cast<llvm::GlobalVariable>(taskFunction->stripPointerCasts()); |
| 210 | + |
| 211 | + auto taskAsyncIDIter = IGF.IGM.AsyncCoroIDs.find(taskAsyncFunctionPointer); |
| 212 | + assert(taskAsyncIDIter != IGF.IGM.AsyncCoroIDs.end() |
| 213 | + && "async let entry point not emitted locally"); |
| 214 | + auto taskAsyncID = taskAsyncIDIter->second; |
| 215 | + |
| 216 | + // Pad out the initial context size in the async function pointer record |
| 217 | + // and ID intrinsic so that it will never fit in the preallocated space. |
| 218 | + uint64_t origSize = cast<llvm::ConstantInt>(taskAsyncID->getArgOperand(0)) |
| 219 | + ->getValue().getLimitedValue(); |
| 220 | + |
| 221 | + uint64_t paddedSize = std::max(origSize, |
| 222 | + (NumWords_AsyncLet * IGF.IGM.getPointerSize()).getValue()); |
| 223 | + auto paddedSizeVal = llvm::ConstantInt::get(IGF.IGM.Int32Ty, paddedSize); |
| 224 | + taskAsyncID->setArgOperand(0, paddedSizeVal); |
| 225 | + |
| 226 | + auto origInit = taskAsyncFunctionPointer->getInitializer(); |
| 227 | + auto newInit = llvm::ConstantStruct::get( |
| 228 | + cast<llvm::StructType>(origInit->getType()), |
| 229 | + origInit->getAggregateElement(0u), |
| 230 | + paddedSizeVal); |
| 231 | + taskAsyncFunctionPointer->setInitializer(newInit); |
| 232 | + } |
| 233 | + |
195 | 234 | llvm::CallInst *call;
|
196 | 235 | if (localResultBuffer) {
|
197 | 236 | // This is @_silgen_name("swift_asyncLet_begin")
|
|
0 commit comments