|
36 | 36 | #include "swift/ABI/MetadataValues.h" |
37 | 37 | #include "swift/AST/ExtInfo.h" |
38 | 38 | #include "swift/AST/GenericEnvironment.h" |
| 39 | +#include "swift/AST/GenericSignature.h" |
39 | 40 | #include "swift/AST/ProtocolConformanceRef.h" |
40 | 41 | #include "swift/IRGen/Linking.h" |
41 | 42 | #include "swift/SIL/SILFunction.h" |
@@ -68,19 +69,44 @@ llvm::Value *irgen::emitDistributedActorInitializeRemote( |
68 | 69 | namespace { |
69 | 70 |
|
70 | 71 | struct ArgumentDecoderInfo { |
| 72 | + /// The instance of the decoder this information belongs to. |
71 | 73 | llvm::Value *Decoder; |
72 | 74 |
|
| 75 | + /// The type of `decodeNextArgument` method. |
73 | 76 | CanSILFunctionType MethodType; |
| 77 | + |
| 78 | + /// The pointer to `decodeNextArgument` method which |
| 79 | + /// could be used to form a call to it. |
74 | 80 | FunctionPointer MethodPtr; |
75 | 81 |
|
| 82 | + /// Protocol requirements associated with the generic |
| 83 | + /// parameter `Argument` of this decode method. |
| 84 | + GenericSignature::RequiredProtocols ProtocolRequirements; |
| 85 | + |
76 | 86 | ArgumentDecoderInfo(llvm::Value *decoder, CanSILFunctionType decodeMethodTy, |
77 | 87 | FunctionPointer decodePtr) |
78 | | - : Decoder(decoder), MethodType(decodeMethodTy), MethodPtr(decodePtr) {} |
| 88 | + : Decoder(decoder), MethodType(decodeMethodTy), MethodPtr(decodePtr), |
| 89 | + ProtocolRequirements(findProtocolRequirements(decodeMethodTy)) {} |
79 | 90 |
|
80 | 91 | CanSILFunctionType getMethodType() const { return MethodType; } |
81 | 92 |
|
| 93 | + ArrayRef<ProtocolDecl *> getProtocolRequirements() const { |
| 94 | + return ProtocolRequirements; |
| 95 | + } |
| 96 | + |
82 | 97 | /// Form a callee to a decode method - `decodeNextArgument`. |
83 | 98 | Callee getCallee() const; |
| 99 | + |
| 100 | +private: |
| 101 | + static GenericSignature::RequiredProtocols |
| 102 | + findProtocolRequirements(CanSILFunctionType decodeMethodTy) { |
| 103 | + auto signature = decodeMethodTy->getInvocationGenericSignature(); |
| 104 | + auto genericParams = signature.getGenericParams(); |
| 105 | + |
| 106 | + // func decodeNextArgument<Arg : #SerializationRequirement#>() throws -> Arg |
| 107 | + assert(genericParams.size() == 1); |
| 108 | + return signature->getRequiredProtocols(genericParams.front()); |
| 109 | + } |
84 | 110 | }; |
85 | 111 |
|
86 | 112 | class DistributedAccessor { |
@@ -115,6 +141,10 @@ class DistributedAccessor { |
115 | 141 | llvm::Value *argumentType, const SILParameterInfo ¶m, |
116 | 142 | Explosion &arguments); |
117 | 143 |
|
| 144 | + void lookupWitnessTables(llvm::Value *value, |
| 145 | + ArrayRef<ProtocolDecl *> protocols, |
| 146 | + Explosion &witnessTables); |
| 147 | + |
118 | 148 | /// Load witness table addresses (if any) from the given buffer |
119 | 149 | /// into the given argument explosion. |
120 | 150 | /// |
@@ -329,6 +359,10 @@ void DistributedAccessor::decodeArgument(unsigned argumentIdx, |
329 | 359 | // substitution Argument -> <argument metadata> |
330 | 360 | decodeArgs.add(argumentType); |
331 | 361 |
|
| 362 | + // Lookup witness tables for the requirement on the argument type. |
| 363 | + lookupWitnessTables(argumentType, decoder.getProtocolRequirements(), |
| 364 | + decodeArgs); |
| 365 | + |
332 | 366 | Address calleeErrorSlot; |
333 | 367 | llvm::Value *decodeError = nullptr; |
334 | 368 |
|
@@ -426,6 +460,37 @@ void DistributedAccessor::decodeArgument(unsigned argumentIdx, |
426 | 460 | } |
427 | 461 | } |
428 | 462 |
|
| 463 | +void DistributedAccessor::lookupWitnessTables( |
| 464 | + llvm::Value *value, ArrayRef<ProtocolDecl *> protocols, |
| 465 | + Explosion &witnessTables) { |
| 466 | + auto conformsToProtocol = IGM.getConformsToProtocolFn(); |
| 467 | + |
| 468 | + for (auto *protocol : protocols) { |
| 469 | + auto *protocolDescriptor = IGM.getAddrOfProtocolDescriptor(protocol); |
| 470 | + auto *witnessTable = |
| 471 | + IGF.Builder.CreateCall(conformsToProtocol, {value, protocolDescriptor}); |
| 472 | + |
| 473 | + auto failBB = IGF.createBasicBlock("missing-witness"); |
| 474 | + auto contBB = IGF.createBasicBlock(""); |
| 475 | + |
| 476 | + auto isNull = IGF.Builder.CreateICmpEQ( |
| 477 | + witnessTable, llvm::ConstantPointerNull::get(IGM.WitnessTablePtrTy)); |
| 478 | + IGF.Builder.CreateCondBr(isNull, failBB, contBB); |
| 479 | + |
| 480 | + // This operation shouldn't fail because runtime should have checked that |
| 481 | + // a particular argument type conforms to `SerializationRequirement` |
| 482 | + // of the distributed actor the decoder is used for. If it does fail |
| 483 | + // then accessor should trap. |
| 484 | + { |
| 485 | + IGF.Builder.emitBlock(failBB); |
| 486 | + IGF.emitTrap("missing witness table", /*EmitUnreachable=*/true); |
| 487 | + } |
| 488 | + |
| 489 | + IGF.Builder.emitBlock(contBB); |
| 490 | + witnessTables.add(witnessTable); |
| 491 | + } |
| 492 | +} |
| 493 | + |
429 | 494 | void DistributedAccessor::emitLoadOfWitnessTables(llvm::Value *witnessTables, |
430 | 495 | llvm::Value *numTables, |
431 | 496 | unsigned expectedWitnessTables, |
|
0 commit comments