@@ -123,6 +123,10 @@ class DistributedAccessor {
123
123
unsigned expectedWitnessTables,
124
124
Explosion &arguments);
125
125
126
+ // / Emit an async return from accessor which does cleanup of
127
+ // / all the argument allocations.
128
+ void emitReturn (llvm::Value *errorValue);
129
+
126
130
FunctionPointer getPointerToTarget () const ;
127
131
128
132
Callee getCalleeForDistributedTarget (llvm::Value *self) const ;
@@ -131,6 +135,12 @@ class DistributedAccessor {
131
135
// / could be used to decode argument values to pass to its invocation.
132
136
static ArgumentDecoderInfo findArgumentDecoder (IRGenModule &IGM,
133
137
SILFunction *thunk);
138
+
139
+ // / The result type of the accessor.
140
+ SILType getResultType () const ;
141
+
142
+ // / The error type of this accessor.
143
+ SILType getErrorType () const ;
134
144
};
135
145
136
146
} // end namespace
@@ -316,6 +326,9 @@ void DistributedAccessor::decodeArgument(unsigned argumentIdx,
316
326
// substitution Argument -> <argument metadata>
317
327
decodeArgs.add (argumentType);
318
328
329
+ Address calleeErrorSlot;
330
+ llvm::Value *decodeError = nullptr ;
331
+
319
332
emission->begin ();
320
333
{
321
334
emission->setArgs (decodeArgs, /* isOutlined=*/ false ,
@@ -325,14 +338,43 @@ void DistributedAccessor::decodeArgument(unsigned argumentIdx,
325
338
emission->emitToExplosion (result, /* isOutlined=*/ false );
326
339
assert (result.empty ());
327
340
328
- // TODO: Add error handling a new block that uses `emitAsyncReturn`
329
- // if error slot is non-null.
341
+ // Load error from the slot to emit an early return if necessary.
342
+ {
343
+ SILFunctionConventions conv (ArgumentDecoder.Type , IGM.getSILModule ());
344
+ SILType errorType =
345
+ conv.getSILErrorType (IGM.getMaximalTypeExpansionContext ());
346
+
347
+ calleeErrorSlot =
348
+ emission->getCalleeErrorSlot (errorType, /* isCalleeAsync=*/ true );
349
+ decodeError = IGF.Builder .CreateLoad (calleeErrorSlot);
350
+ }
330
351
}
331
352
emission->end ();
332
353
333
354
// Remember to deallocate later.
334
355
AllocatedArguments.push_back (resultValue);
335
356
357
+ // Check whether the error slot has been set and if so
358
+ // emit an early return from accessor.
359
+ {
360
+ auto contBB = IGF.createBasicBlock (" " );
361
+ auto errorBB = IGF.createBasicBlock (" on-error" );
362
+
363
+ auto nullError = llvm::Constant::getNullValue (decodeError->getType ());
364
+ auto hasError = IGF.Builder .CreateICmpNE (decodeError, nullError);
365
+
366
+ IGF.Builder .CreateCondBr (hasError, errorBB, contBB);
367
+ {
368
+ IGF.Builder .emitBlock (errorBB);
369
+ // Emit an early return if argument decoding failed.
370
+ emitReturn (decodeError);
371
+ }
372
+
373
+ IGF.Builder .emitBlock (contBB);
374
+ // Reset value of the slot back to `null`
375
+ IGF.Builder .CreateStore (nullError, calleeErrorSlot);
376
+ }
377
+
336
378
switch (param.getConvention ()) {
337
379
case ParameterConvention::Indirect_In:
338
380
case ParameterConvention::Indirect_In_Constant: {
@@ -412,10 +454,28 @@ void DistributedAccessor::emitLoadOfWitnessTables(llvm::Value *witnessTables,
412
454
}
413
455
}
414
456
457
+ void DistributedAccessor::emitReturn (llvm::Value *errorValue) {
458
+ // Deallocate all of the copied arguments. Since allocations happened
459
+ // on stack they have to be deallocated in reverse order.
460
+ {
461
+ for (auto alloca = AllocatedArguments.rbegin ();
462
+ alloca != AllocatedArguments.rend (); ++alloca) {
463
+ IGF.emitDeallocateDynamicAlloca (*alloca);
464
+ }
465
+ }
466
+
467
+ Explosion voidResult;
468
+
469
+ Explosion error;
470
+ error.add (errorValue);
471
+
472
+ emitAsyncReturn (IGF, AsyncLayout, getResultType (), AccessorType, voidResult,
473
+ error);
474
+ }
475
+
415
476
void DistributedAccessor::emit () {
416
477
auto targetTy = Target->getLoweredFunctionType ();
417
478
SILFunctionConventions targetConv (targetTy, IGF.getSILModule ());
418
- SILFunctionConventions accessorConv (AccessorType, IGF.getSILModule ());
419
479
TypeExpansionContext expansionContext = IGM.getMaximalTypeExpansionContext ();
420
480
421
481
auto params = IGF.collectParameters ();
@@ -510,7 +570,7 @@ void DistributedAccessor::emit() {
510
570
// using computed argument explosion.
511
571
{
512
572
Explosion result;
513
- Explosion error ;
573
+ llvm::Value *targetError = nullptr ;
514
574
515
575
auto callee = getCalleeForDistributedTarget (actorSelf);
516
576
auto emission =
@@ -536,27 +596,16 @@ void DistributedAccessor::emit() {
536
596
{
537
597
assert (targetTy->hasErrorResult ());
538
598
539
- SILType errorType = accessorConv.getSILErrorType (expansionContext);
540
599
Address calleeErrorSlot =
541
- emission->getCalleeErrorSlot (errorType , /* isCalleeAsync=*/ true );
542
- error. add ( IGF.Builder .CreateLoad (calleeErrorSlot) );
600
+ emission->getCalleeErrorSlot (getErrorType () , /* isCalleeAsync=*/ true );
601
+ targetError = IGF.Builder .CreateLoad (calleeErrorSlot);
543
602
}
544
603
545
604
emission->end ();
546
605
547
- // Deallocate all of the copied arguments. Since allocations happened
548
- // on stack they have to be deallocated in reverse order.
549
- {
550
- while (!AllocatedArguments.empty ()) {
551
- auto argument = AllocatedArguments.pop_back_val ();
552
- IGF.emitDeallocateDynamicAlloca (argument);
553
- }
554
- }
555
-
556
- Explosion voidResult;
557
- emitAsyncReturn (IGF, AsyncLayout,
558
- accessorConv.getSILResultType (expansionContext),
559
- AccessorType, voidResult, error);
606
+ // Emit an async return that does allocation cleanup and propagates error
607
+ // (if any) back to the caller.
608
+ emitReturn (targetError);
560
609
}
561
610
}
562
611
@@ -604,6 +653,16 @@ DistributedAccessor::findArgumentDecoder(IRGenModule &IGM, SILFunction *thunk) {
604
653
return {.Type = methodTy, .Fn = methodPtr};
605
654
}
606
655
656
+ SILType DistributedAccessor::getResultType () const {
657
+ SILFunctionConventions conv (AccessorType, IGF.getSILModule ());
658
+ return conv.getSILResultType (IGM.getMaximalTypeExpansionContext ());
659
+ }
660
+
661
+ SILType DistributedAccessor::getErrorType () const {
662
+ SILFunctionConventions conv (AccessorType, IGF.getSILModule ());
663
+ return conv.getSILErrorType (IGM.getMaximalTypeExpansionContext ());
664
+ }
665
+
607
666
Callee ArgumentDecoderInfo::getCallee (llvm::Value *decoder) const {
608
667
CalleeInfo info (Type, Type, SubstitutionMap ());
609
668
return {std::move (info), Fn, decoder};
0 commit comments