@@ -51,7 +51,6 @@ namespace {
51
51
// / inserts the derivations, turning those hops into hops to executors.
52
52
// / IRGen expects hops to be to executors before it runs.
53
53
class LowerHopToActor {
54
- SILFunction *F;
55
54
DominanceInfo *Dominance;
56
55
57
56
// / A map from an actor value to the dominating instruction that
@@ -194,6 +193,118 @@ static AccessorDecl *getUnownedExecutorGetter(ASTContext &ctx,
194
193
return nullptr ;
195
194
}
196
195
196
+ // / Emit the instructions to derive an executor value from an actor value.
197
+ static SILValue getExecutorForActor (SILBuilder &B, SILLocation loc,
198
+ SILValue actor) {
199
+ auto *F = actor->getFunction ();
200
+ auto &ctx = F->getASTContext ();
201
+ auto executorType = SILType::getPrimitiveObjectType (ctx.TheExecutorType );
202
+
203
+ // If the actor type is a default actor, go ahead and devirtualize here.
204
+ auto module = F->getModule ().getSwiftModule ();
205
+ CanType actorType = actor->getType ().getASTType ();
206
+
207
+ // Determine if the actor is a "default actor" in which case we'll build a
208
+ // default actor executor ref inline, rather than calling out to the
209
+ // user-provided executor function.
210
+ if (isDefaultActorType (actorType, module , F->getResilienceExpansion ())) {
211
+ auto builtinName = ctx.getIdentifier (
212
+ getBuiltinName (BuiltinValueKind::BuildDefaultActorExecutorRef));
213
+ auto builtinDecl = cast<FuncDecl>(getBuiltinValueDecl (ctx, builtinName));
214
+ auto subs = SubstitutionMap::get (builtinDecl->getGenericSignature (),
215
+ {actorType}, LookUpConformanceInModule ());
216
+ return B.createBuiltin (loc, builtinName, executorType, subs, {actor});
217
+ }
218
+
219
+ // Otherwise, go through (Distributed)Actor.unownedExecutor.
220
+ auto actorKind = actorType->isDistributedActor ()
221
+ ? KnownProtocolKind::DistributedActor
222
+ : KnownProtocolKind::Actor;
223
+ auto actorProtocol = ctx.getProtocol (actorKind);
224
+ auto req = getUnownedExecutorGetter (ctx, actorProtocol);
225
+ assert (req && " Concurrency library broken" );
226
+ SILDeclRef fn (req, SILDeclRef::Kind::Func);
227
+
228
+ // Open an existential actor type.
229
+ if (actorType->isExistentialType ()) {
230
+ actorType = ExistentialArchetypeType::get (actorType)->getCanonicalType ();
231
+ SILType loweredActorType = F->getLoweredType (actorType);
232
+ actor = B.createOpenExistentialRef (loc, actor, loweredActorType);
233
+ }
234
+
235
+ auto actorConf = lookupConformance (actorType, actorProtocol);
236
+ assert (actorConf && " hop_to_executor with actor that doesn't conform to "
237
+ " Actor or DistributedActor" );
238
+
239
+ auto subs = SubstitutionMap::get (req->getGenericSignature (), {actorType},
240
+ {actorConf});
241
+ auto fnType = F->getModule ().Types .getConstantFunctionType (*F, fn);
242
+
243
+ auto witness = B.createWitnessMethod (loc, actorType, actorConf, fn,
244
+ SILType::getPrimitiveObjectType (fnType));
245
+ auto witnessCall = B.createApply (loc, witness, subs, {actor});
246
+
247
+ // The protocol requirement returns an UnownedSerialExecutor; extract
248
+ // the Builtin.Executor from it.
249
+ auto executorDecl = ctx.getUnownedSerialExecutorDecl ();
250
+ auto executorProps = executorDecl->getStoredProperties ();
251
+ assert (executorProps.size () == 1 );
252
+ return B.createStructExtract (loc, witnessCall, executorProps[0 ]);
253
+ }
254
+
255
+ static SILValue getExecutorForOptionalActor (SILBuilder &B, SILLocation loc,
256
+ SILValue actor) {
257
+ auto &ctx = B.getASTContext ();
258
+ auto executorType = SILType::getPrimitiveObjectType (ctx.TheExecutorType );
259
+ auto optionalExecutorType = SILType::getOptionalType (executorType);
260
+
261
+ // Unwrap the optional and call 'unownedExecutor'.
262
+ auto *someDecl = ctx.getOptionalSomeDecl ();
263
+ auto *curBB = B.getInsertionBB ();
264
+ auto *contBB = B.getInsertionPoint () == curBB->end ()
265
+ ? B.getFunction ().createBasicBlockAfter (curBB)
266
+ : curBB->split (B.getInsertionPoint ());
267
+ auto *someBB = B.getFunction ().createBasicBlockAfter (curBB);
268
+ auto *noneBB = B.getFunction ().createBasicBlockAfter (someBB);
269
+
270
+ // unmarked executor
271
+ SILValue result = contBB->createPhiArgument (optionalExecutorType,
272
+ actor->getOwnershipKind ());
273
+
274
+ SmallVector<std::pair<EnumElementDecl *, SILBasicBlock *>, 1 > caseBBs;
275
+ caseBBs.push_back (std::make_pair (someDecl, someBB));
276
+ B.setInsertionPoint (curBB);
277
+ auto *switchEnum = B.createSwitchEnum (loc, actor, noneBB, caseBBs);
278
+
279
+ SILValue unwrappedActor;
280
+ if (B.hasOwnership ()) {
281
+ unwrappedActor = switchEnum->createOptionalSomeResult ();
282
+ B.setInsertionPoint (someBB);
283
+ } else {
284
+ B.setInsertionPoint (someBB);
285
+ unwrappedActor = B.createUncheckedEnumData (loc, actor, someDecl);
286
+ }
287
+
288
+ // Call 'unownedExecutor' in the some block and wrap the result into
289
+ // an optional.
290
+ SILValue unwrappedExecutor = getExecutorForActor (B, loc, unwrappedActor);
291
+ SILValue someValue =
292
+ B.createOptionalSome (loc, unwrappedExecutor, optionalExecutorType);
293
+ B.createBranch (loc, contBB, {someValue});
294
+
295
+ // In the none case, create a nil executor value, which represents
296
+ // the generic executor.
297
+ B.setInsertionPoint (noneBB);
298
+ SILValue noneValue = B.createOptionalNone (loc, optionalExecutorType);
299
+ B.createBranch (loc, contBB, {noneValue});
300
+ if (contBB->begin () == contBB->end ()) {
301
+ B.setInsertionPoint (contBB);
302
+ } else {
303
+ B.setInsertionPoint (contBB->begin ());
304
+ }
305
+ return result;
306
+ }
307
+
197
308
SILValue LowerHopToActor::emitGetExecutor (SILBuilderWithScope &B,
198
309
SILLocation loc, SILValue actor,
199
310
bool makeOptional) {
@@ -204,125 +315,31 @@ SILValue LowerHopToActor::emitGetExecutor(SILBuilderWithScope &B,
204
315
// If the operand is already a BuiltinExecutorType, just wrap it
205
316
// in an optional.
206
317
if (makeOptional && actor->getType ().is <BuiltinExecutorType>()) {
207
- return B.createOptionalSome (
208
- loc, actor,
209
- SILType::getOptionalType (actor->getType ()));
318
+ return B.createOptionalSome (loc, actor,
319
+ SILType::getOptionalType (actor->getType ()));
210
320
}
211
321
212
- auto &ctx = F->getASTContext ();
213
- auto executorType = SILType::getPrimitiveObjectType (ctx.TheExecutorType );
214
- auto optionalExecutorType = SILType::getOptionalType (executorType);
215
-
216
- // / Emit the instructions to derive an executor value from an actor value.
217
- auto getExecutorFor = [&](SILValue actor) -> SILValue {
218
- // If the actor type is a default actor, go ahead and devirtualize here.
219
- auto module = F->getModule ().getSwiftModule ();
220
- CanType actorType = actor->getType ().getASTType ();
221
-
222
- // Determine if the actor is a "default actor" in which case we'll build a default
223
- // actor executor ref inline, rather than calling out to the user-provided executor function.
224
- if (isDefaultActorType (actorType, module , F->getResilienceExpansion ())) {
225
- auto builtinName = ctx.getIdentifier (
226
- getBuiltinName (BuiltinValueKind::BuildDefaultActorExecutorRef));
227
- auto builtinDecl = cast<FuncDecl>(getBuiltinValueDecl (ctx, builtinName));
228
- auto subs = SubstitutionMap::get (builtinDecl->getGenericSignature (),
229
- {actorType},
230
- LookUpConformanceInModule ());
231
- return B.createBuiltin (loc, builtinName, executorType, subs, {actor});
232
- }
233
-
234
- // Otherwise, go through (Distributed)Actor.unownedExecutor.
235
- auto actorKind = actorType->isDistributedActor () ?
236
- KnownProtocolKind::DistributedActor :
237
- KnownProtocolKind::Actor;
238
- auto actorProtocol = ctx.getProtocol (actorKind);
239
- auto req = getUnownedExecutorGetter (ctx, actorProtocol);
240
- assert (req && " Concurrency library broken" );
241
- SILDeclRef fn (req, SILDeclRef::Kind::Func);
242
-
243
- // Open an existential actor type.
244
- if (actorType->isExistentialType ()) {
245
- actorType = ExistentialArchetypeType::get (actorType)->getCanonicalType ();
246
- SILType loweredActorType = F->getLoweredType (actorType);
247
- actor = B.createOpenExistentialRef (loc, actor, loweredActorType);
248
- }
249
-
250
- auto actorConf = lookupConformance (actorType, actorProtocol);
251
- assert (actorConf &&
252
- " hop_to_executor with actor that doesn't conform to Actor or DistributedActor" );
253
-
254
- auto subs = SubstitutionMap::get (req->getGenericSignature (),
255
- {actorType}, {actorConf});
256
- auto fnType = F->getModule ().Types .getConstantFunctionType (*F, fn);
257
-
258
- auto witness =
259
- B.createWitnessMethod (loc, actorType, actorConf, fn,
260
- SILType::getPrimitiveObjectType (fnType));
261
- auto witnessCall = B.createApply (loc, witness, subs, {actor});
262
-
263
- // The protocol requirement returns an UnownedSerialExecutor; extract
264
- // the Builtin.Executor from it.
265
- auto executorDecl = ctx.getUnownedSerialExecutorDecl ();
266
- auto executorProps = executorDecl->getStoredProperties ();
267
- assert (executorProps.size () == 1 );
268
- return B.createStructExtract (loc, witnessCall, executorProps[0 ]);
269
- };
270
-
271
322
bool needEndBorrow = false ;
272
323
SILValue unmarkedExecutor;
273
324
if (auto wrappedActor = actorType->getOptionalObjectType ()) {
274
325
assert (makeOptional);
275
-
276
- if (B. hasOwnership () && actor->getOwnershipKind () != OwnershipKind::Guaranteed) {
326
+ if (B. hasOwnership () &&
327
+ actor->getOwnershipKind () != OwnershipKind::Guaranteed) {
277
328
actor = B.createBeginBorrow (loc, actor);
278
329
needEndBorrow = true ;
279
330
}
280
331
281
- // Unwrap the optional and call 'unownedExecutor'.
282
- auto *someDecl = B.getASTContext ().getOptionalSomeDecl ();
283
- auto *curBB = B.getInsertionPoint ()->getParent ();
284
- auto *contBB = curBB->split (B.getInsertionPoint ());
285
- auto *someBB = B.getFunction ().createBasicBlockAfter (curBB);
286
- auto *noneBB = B.getFunction ().createBasicBlockAfter (someBB);
287
-
288
- unmarkedExecutor = contBB->createPhiArgument (
289
- optionalExecutorType, actor->getOwnershipKind ());
290
-
291
- SmallVector<std::pair<EnumElementDecl *, SILBasicBlock *>, 1 > caseBBs;
292
- caseBBs.push_back (std::make_pair (someDecl, someBB));
293
- B.setInsertionPoint (curBB);
294
- auto *switchEnum = B.createSwitchEnum (loc, actor, noneBB, caseBBs);
295
-
296
- SILValue unwrappedActor;
297
- if (B.hasOwnership ()) {
298
- unwrappedActor = switchEnum->createOptionalSomeResult ();
299
- B.setInsertionPoint (someBB);
300
- } else {
301
- B.setInsertionPoint (someBB);
302
- unwrappedActor = B.createUncheckedEnumData (loc, actor, someDecl);
303
- }
304
-
305
- // Call 'unownedExecutor' in the some block and wrap the result into
306
- // an optional.
307
- SILValue unwrappedExecutor = getExecutorFor (unwrappedActor);
308
- SILValue someValue =
309
- B.createOptionalSome (loc, unwrappedExecutor, optionalExecutorType);
310
- B.createBranch (loc, contBB, {someValue});
311
-
312
- // In the none case, create a nil executor value, which represents
313
- // the generic executor.
314
- B.setInsertionPoint (noneBB);
315
- SILValue noneValue = B.createOptionalNone (loc, optionalExecutorType);
316
- B.createBranch (loc, contBB, {noneValue});
317
- B.setInsertionPoint (contBB->begin ());
332
+ unmarkedExecutor = getExecutorForOptionalActor (B, loc, actor);
318
333
} else {
319
- unmarkedExecutor = getExecutorFor (actor);
334
+ unmarkedExecutor = getExecutorForActor (B, loc, actor);
335
+ }
320
336
321
- // Inject the result into an optional if requested.
322
- if (makeOptional) {
323
- unmarkedExecutor = B.createOptionalSome (loc, unmarkedExecutor,
324
- SILType::getOptionalType (unmarkedExecutor->getType ()));
325
- }
337
+ // Inject the result into an optional if requested and if our executor is not
338
+ // yet optional.
339
+ if (makeOptional && !unmarkedExecutor->getType ().getOptionalObjectType ()) {
340
+ unmarkedExecutor = B.createOptionalSome (
341
+ loc, unmarkedExecutor,
342
+ SILType::getOptionalType (unmarkedExecutor->getType ()));
326
343
}
327
344
328
345
// Mark the dependence of the resulting value on the actor value to
0 commit comments