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