@@ -72,21 +72,31 @@ struct ArgumentDecoderInfo {
72
72
// / The instance of the decoder this information belongs to.
73
73
llvm::Value *Decoder;
74
74
75
- // / The type of `decodeNextArgument` method.
76
- CanSILFunctionType MethodType;
77
-
78
75
// / The pointer to `decodeNextArgument` method which
79
76
// / could be used to form a call to it.
80
77
FunctionPointer MethodPtr;
81
78
79
+ // / The type of `decodeNextArgument` method.
80
+ CanSILFunctionType MethodType;
81
+
82
82
// / Protocol requirements associated with the generic
83
83
// / parameter `Argument` of this decode method.
84
84
GenericSignature::RequiredProtocols ProtocolRequirements;
85
85
86
- ArgumentDecoderInfo (llvm::Value *decoder, CanSILFunctionType decodeMethodTy,
87
- FunctionPointer decodePtr)
88
- : Decoder(decoder), MethodType(decodeMethodTy), MethodPtr(decodePtr),
89
- ProtocolRequirements (findProtocolRequirements(decodeMethodTy)) {}
86
+ // Witness metadata for conformance to DistributedTargetInvocationDecoder
87
+ // protocol.
88
+ WitnessMetadata Witness;
89
+
90
+ ArgumentDecoderInfo (llvm::Value *decoder, llvm::Value *decoderType,
91
+ llvm::Value *decoderWitnessTable,
92
+ FunctionPointer decodeNextArgumentPtr,
93
+ CanSILFunctionType decodeNextArgumentTy)
94
+ : Decoder(decoder), MethodPtr(decodeNextArgumentPtr),
95
+ MethodType (decodeNextArgumentTy),
96
+ ProtocolRequirements(findProtocolRequirements(decodeNextArgumentTy)) {
97
+ Witness.SelfMetadata = decoderType;
98
+ Witness.SelfWitnessTable = decoderWitnessTable;
99
+ }
90
100
91
101
CanSILFunctionType getMethodType () const { return MethodType; }
92
102
@@ -131,8 +141,8 @@ class DistributedAccessor {
131
141
void emit ();
132
142
133
143
private:
134
- void decodeArguments (llvm::Value *decoder, llvm::Value *argumentTypes ,
135
- Explosion &arguments);
144
+ void decodeArguments (const ArgumentDecoderInfo &decoder ,
145
+ llvm::Value *argumentTypes, Explosion &arguments);
136
146
137
147
// / Load an argument value from the given decoder \c decoder
138
148
// / to the given explosion \c arguments. Information describing
@@ -163,8 +173,11 @@ class DistributedAccessor {
163
173
164
174
Callee getCalleeForDistributedTarget (llvm::Value *self) const ;
165
175
166
- // / Given an instance of argument decoder, find `decodeNextArgument`.
167
- ArgumentDecoderInfo findArgumentDecoder (llvm::Value *decoder);
176
+ // / Given an instance of invocation decoder, its type metadata,
177
+ // / and protocol witness table, find `decodeNextArgument`.
178
+ ArgumentDecoderInfo findArgumentDecoder (llvm::Value *decoder,
179
+ llvm::Value *decoderTy,
180
+ llvm::Value *witnessTable);
168
181
169
182
// / The result type of the accessor.
170
183
SILType getResultType () const ;
@@ -183,61 +196,80 @@ static NominalTypeDecl *getDistributedActorOf(SILFunction *thunk) {
183
196
}
184
197
185
198
// / Compute a type of a distributed method accessor function based
186
- // / on the provided distributed method .
199
+ // / on the provided distributed target .
187
200
static CanSILFunctionType getAccessorType (IRGenModule &IGM,
188
201
SILFunction *Target) {
189
202
auto &Context = IGM.Context ;
190
203
191
- auto getInvocationDecoderParameter = [&]() {
192
- auto *actor = getDistributedActorOf (Target);
193
- auto *decoder = Context.getDistributedActorInvocationDecoder (actor);
194
- auto decoderTy = decoder->getInterfaceType ()->getMetatypeInstanceType ();
195
- auto paramType = IGM.getLoweredType (decoderTy);
196
- return SILParameterInfo (paramType.getASTType (),
197
- ParameterConvention::Direct_Guaranteed);
198
- };
199
-
200
- auto getRawPointerParameter = [&]() {
201
- auto ptrType = Context.getUnsafeRawPointerType ();
202
- return SILParameterInfo (ptrType->getCanonicalType (),
203
- ParameterConvention::Direct_Unowned);
204
- };
205
-
206
- auto getUIntParameter = [&]() {
207
- return SILParameterInfo (Context.getUIntType ()->getCanonicalType (),
208
- ParameterConvention::Direct_Unowned);
209
- };
210
-
211
- // `self` of the distributed actor is going to be passed as an argument
212
- // to this accessor function.
213
- auto extInfo = SILExtInfoBuilder ()
214
- .withRepresentation (SILFunctionTypeRepresentation::Thin)
215
- .withAsync ()
216
- .build ();
204
+ // func __accessor__<D: DistributedTargetInvocationDecoder>(
205
+ // inout D, <- invocation decoder
206
+ // UnsafeRawPointer, <- argument types
207
+ // UnsafeRawPointer, <- result buffer
208
+ // UnsafeRawPointer?, <- generic parameter substitutions
209
+ // UnsafeRawPointer?, <- witness tables
210
+ // UInt, <- number of witness tables
211
+ // <actor>
212
+ // ) async throws
213
+
214
+ SmallVector<GenericFunctionType::Param, 8 > parameters;
215
+
216
+ // A generic parameter that represents instance of invocation decoder.
217
+ auto *decoderType =
218
+ GenericTypeParamType::get (/* isTypeSequence=*/ false ,
219
+ /* depth=*/ 0 , /* index=*/ 0 , Context);
220
+
221
+ // decoder
222
+ parameters.push_back (GenericFunctionType::Param (
223
+ decoderType,
224
+ /* label=*/ Identifier (),
225
+ /* flags=*/ ParameterTypeFlags ().withInOut (true )));
226
+
227
+ // argument type buffer
228
+ parameters.push_back (
229
+ GenericFunctionType::Param (Context.getUnsafeRawPointerType ()));
230
+
231
+ // result buffer
232
+ parameters.push_back (
233
+ GenericFunctionType::Param (Context.getUnsafeRawPointerType ()));
234
+
235
+ // generic parameter substitutions
236
+ parameters.push_back (
237
+ GenericFunctionType::Param (Context.getUnsafeRawPointerType ()));
238
+
239
+ // witness tables
240
+ parameters.push_back (
241
+ GenericFunctionType::Param (Context.getUnsafeRawPointerType ()));
242
+
243
+ // number of witness tables
244
+ parameters.push_back (GenericFunctionType::Param (Context.getUIntType ()));
245
+
246
+ // actor
247
+ {
248
+ auto targetTy = Target->getLoweredFunctionType ();
249
+ auto actorLoc = targetTy->getParameters ().back ();
217
250
218
- auto targetTy = Target->getLoweredFunctionType ();
251
+ parameters.push_back (
252
+ GenericFunctionType::Param (actorLoc.getInterfaceType ()));
253
+ }
254
+
255
+ auto decoderProtocolTy =
256
+ Context
257
+ .getProtocol (KnownProtocolKind::DistributedTargetInvocationDecoder)
258
+ ->getDeclaredInterfaceType ();
219
259
220
- assert (targetTy->isAsync ());
221
- assert (targetTy->hasErrorResult ());
222
-
223
- // Accessor gets argument/result value buffer and a reference to `self` of
224
- // the actor and produces a call to the distributed thunk forwarding
225
- // its result(s) out.
226
- return SILFunctionType::get (
227
- /* genericSignature=*/ nullptr , extInfo, SILCoroutineKind::None,
228
- ParameterConvention::Direct_Guaranteed,
229
- {/* argumentDecoder=*/ getInvocationDecoderParameter (),
230
- /* argumentTypes=*/ getRawPointerParameter (),
231
- /* resultBuffer=*/ getRawPointerParameter (),
232
- /* substitutions=*/ getRawPointerParameter (),
233
- /* witnessTables=*/ getRawPointerParameter (),
234
- /* numWitnessTables=*/ getUIntParameter (),
235
- /* actor=*/ targetTy->getParameters ().back ()},
236
- /* Yields=*/ {},
237
- /* Results=*/ {},
238
- /* ErrorResult=*/ targetTy->getErrorResult (),
239
- /* patternSubs=*/ SubstitutionMap (),
240
- /* invocationSubs=*/ SubstitutionMap (), Context);
260
+ auto signature = GenericSignature::get (
261
+ {decoderType},
262
+ {{RequirementKind::Conformance, decoderType, decoderProtocolTy}});
263
+
264
+ auto accessorTy = GenericFunctionType::get (
265
+ signature, parameters, Context.TheEmptyTupleType ,
266
+ ASTExtInfoBuilder ()
267
+ .withRepresentation (FunctionTypeRepresentation::Thin)
268
+ .withAsync ()
269
+ .withThrows ()
270
+ .build ());
271
+
272
+ return IGM.getLoweredType (accessorTy).castTo <SILFunctionType>();
241
273
}
242
274
243
275
llvm::Function *
@@ -279,7 +311,7 @@ DistributedAccessor::DistributedAccessor(IRGenFunction &IGF,
279
311
IGM.DebugInfo ->emitArtificialFunction (IGF, IGF.CurFn );
280
312
}
281
313
282
- void DistributedAccessor::decodeArguments (llvm::Value * decoder,
314
+ void DistributedAccessor::decodeArguments (const ArgumentDecoderInfo & decoder,
283
315
llvm::Value *argumentTypes,
284
316
Explosion &arguments) {
285
317
auto fnType = Target->getLoweredFunctionType ();
@@ -295,10 +327,6 @@ void DistributedAccessor::decodeArguments(llvm::Value *decoder,
295
327
argumentTypes =
296
328
IGF.Builder .CreateBitCast (argumentTypes, IGM.TypeMetadataPtrPtrTy );
297
329
298
- // / The argument decoder associated with the distributed actor
299
- // / this accessor belong to.
300
- ArgumentDecoderInfo decoderInfo = findArgumentDecoder (decoder);
301
-
302
330
for (unsigned i = 0 , n = parameters.size (); i != n; ++i) {
303
331
const auto ¶m = parameters[i];
304
332
auto paramTy = param.getSILStorageInterfaceType ();
@@ -326,7 +354,7 @@ void DistributedAccessor::decodeArguments(llvm::Value *decoder,
326
354
auto *argumentTy = IGF.Builder .CreateLoad (typeLoc, " arg_type" );
327
355
328
356
// Decode and load argument value using loaded type metadata.
329
- decodeArgument (i, decoderInfo , argumentTy, param, arguments);
357
+ decodeArgument (i, decoder , argumentTy, param, arguments);
330
358
}
331
359
}
332
360
@@ -574,6 +602,10 @@ void DistributedAccessor::emit() {
574
602
auto *numWitnessTables = params.claimNext ();
575
603
// Reference to a `self` of the actor to be called.
576
604
auto *actorSelf = params.claimNext ();
605
+ // Metadata that represents passed in the invocation decoder.
606
+ auto *decoderType = params.claimNext ();
607
+ // Witness table for decoder conformance to DistributedTargetInvocationDecoder
608
+ auto *decoderProtocolWitness = params.claimNext ();
577
609
578
610
GenericContextScope scope (IGM, targetTy->getInvocationGenericSignature ());
579
611
@@ -600,9 +632,18 @@ void DistributedAccessor::emit() {
600
632
arguments.add (typedResultBuffer);
601
633
}
602
634
603
- // Step one is to load all of the data from argument buffer,
604
- // so it could be forwarded to the distributed method.
605
- decodeArguments (argDecoder, argTypes, arguments);
635
+ // There is always at least one parameter associated with accessor - `self`
636
+ // of the distributed actor.
637
+ if (targetTy->getNumParameters () > 1 ) {
638
+ // / The argument decoder associated with the distributed actor
639
+ // / this accessor belong to.
640
+ ArgumentDecoderInfo decoder =
641
+ findArgumentDecoder (argDecoder, decoderType, decoderProtocolWitness);
642
+
643
+ // Step one is to load all of the data from argument buffer,
644
+ // so it could be forwarded to the distributed method.
645
+ decodeArguments (decoder, argTypes, arguments);
646
+ }
606
647
607
648
// Add all of the substitutions to the explosion
608
649
if (auto *genericEnvironment = Target->getGenericEnvironment ()) {
@@ -700,23 +741,48 @@ DistributedAccessor::getCalleeForDistributedTarget(llvm::Value *self) const {
700
741
return {std::move (info), getPointerToTarget (), self};
701
742
}
702
743
703
- ArgumentDecoderInfo
704
- DistributedAccessor::findArgumentDecoder ( llvm::Value *decoder ) {
744
+ ArgumentDecoderInfo DistributedAccessor::findArgumentDecoder (
745
+ llvm::Value *decoder, llvm::Value *decoderTy, llvm::Value *witnessTable ) {
705
746
auto *actor = getDistributedActorOf (Target);
706
747
auto expansionContext = IGM.getMaximalTypeExpansionContext ();
707
748
708
749
auto *decodeFn = IGM.Context .getDistributedActorArgumentDecodingMethod (actor);
709
750
assert (decodeFn && " no suitable decoder?" );
710
751
711
- auto *decoderDecl = decodeFn->getDeclContext ()->getSelfNominalTypeDecl ();
712
752
auto methodTy = IGM.getSILTypes ().getConstantFunctionType (
713
753
expansionContext, SILDeclRef (decodeFn));
714
754
715
755
auto fpKind = FunctionPointerKind::defaultAsync ();
716
756
auto signature = IGM.getSignature (methodTy, fpKind);
717
757
718
758
// If the decoder class is `final`, let's emit a direct reference.
719
- if (decoderDecl->isFinal ()) {
759
+ auto *decoderDecl = decodeFn->getDeclContext ()->getSelfNominalTypeDecl ();
760
+
761
+ // If decoder is a class, need to load it first because generic parameter
762
+ // is passed indirectly. This is good for structs and enums because
763
+ // `decodeNextArgument` is a mutating method, but not for classes because
764
+ // in that case heap object is mutated directly.
765
+ if (isa<ClassDecl>(decoderDecl)) {
766
+ auto selfTy = methodTy->getSelfParameter ().getSILStorageType (
767
+ IGM.getSILModule (), methodTy, expansionContext);
768
+
769
+ auto &classTI = IGM.getTypeInfo (selfTy).as <ClassTypeInfo>();
770
+ auto &classLayout = classTI.getClassLayout (IGM, selfTy,
771
+ /* forBackwardDeployment=*/ false );
772
+
773
+ llvm::Value *typedDecoderPtr = IGF.Builder .CreateBitCast (
774
+ decoder, classLayout.getType ()->getPointerTo ()->getPointerTo ());
775
+
776
+ Explosion instance;
777
+
778
+ classTI.loadAsTake (IGF, {typedDecoderPtr, classTI.getBestKnownAlignment ()},
779
+ instance);
780
+
781
+ decoder = instance.claimNext ();
782
+ }
783
+
784
+ if (isa<StructDecl>(decoderDecl) || isa<EnumDecl>(decoderDecl) ||
785
+ decoderDecl->isFinal ()) {
720
786
auto *decodeSIL = IGM.getSILModule ().lookUpFunction (SILDeclRef (decodeFn));
721
787
auto *fnPtr = IGM.getAddrOfSILFunction (decodeSIL, NotForDefinition,
722
788
/* isDynamicallyReplacible=*/ false );
@@ -725,19 +791,13 @@ DistributedAccessor::findArgumentDecoder(llvm::Value *decoder) {
725
791
classifyFunctionPointerKind (decodeSIL), fnPtr,
726
792
/* secondaryValue=*/ nullptr , signature);
727
793
728
- return {decoder, methodTy, methodPtr};
794
+ return {decoder, decoderTy, witnessTable, methodPtr, methodTy };
729
795
}
730
796
731
- auto selfTy = methodTy->getSelfParameter ().getSILStorageType (
732
- IGM.getSILModule (), methodTy, expansionContext);
733
-
734
- auto *metadata = emitHeapMetadataRefForHeapObject (IGF, decoder, selfTy,
735
- /* suppress cast*/ true );
736
-
737
797
auto methodPtr =
738
- emitVirtualMethodValue (IGF, metadata , SILDeclRef (decodeFn), methodTy);
798
+ emitVirtualMethodValue (IGF, decoderTy , SILDeclRef (decodeFn), methodTy);
739
799
740
- return {decoder, methodTy, methodPtr};
800
+ return {decoder, decoderTy, witnessTable, methodPtr, methodTy };
741
801
}
742
802
743
803
SILType DistributedAccessor::getResultType () const {
0 commit comments