mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Squashed commit of the following: commite5a05ffe44Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Thu Jan 27 17:45:31 2022 +0900 cleanup commit1f751cea5aAuthor: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Thu Jan 27 14:50:33 2022 +0900 cleanups commitc632f3215dAuthor: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Thu Jan 27 14:01:09 2022 +0900 add test for generic from actor decl commit09b8bd50a7Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Thu Jan 27 14:00:58 2022 +0900 cleanups commit31f4d0cffdAuthor: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Thu Jan 27 11:40:51 2022 +0900 fix test commitad4db2fb6cMerge:97227edcca07e2dfda56Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Wed Jan 26 23:31:41 2022 +0900 Merge branch 'main' into wip-zzz commit97227edccaAuthor: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Wed Jan 26 21:01:25 2022 +0900 remove @_dynamic methods! fix tests commit1c79344dbbAuthor: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Wed Jan 19 12:51:09 2022 +0900 cleanup wip stuck fixed the stack cleanups cleanups pretty good now weird load rki works remove hack add take + throw + return fix test more tests fixed more tests fixed more tests fixed commit3ed494c175Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Tue Jan 18 21:09:28 2022 +0900 stack issues in SIL verification commit5cf43a7f86Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Tue Jan 18 09:19:51 2022 +0900 about to call the remoteCall goot to return, but missing subs commitdf8e47122aAuthor: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Thu Jan 13 14:09:49 2022 +0900 [Distributed] Refactor Invocation to Decoder/Encoder getting there done-recording working on the string init stuck trying to get String initializer SILFunction created the remote call target commitfc7bd62f32Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Wed Jan 12 23:01:14 2022 +0900 [Distributed] Pass arguments from Invocation to HBuffer commitcafc2cc058Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Wed Jan 12 22:08:47 2022 +0900 works commita7d01837ffAuthor: Pavel Yaskevich <pyaskevich@apple.com> Date: Tue Jan 11 15:48:58 2022 -0800 [Distributed] Adjust interface of `swift_distributed_execute_target` Since this is a special function, `calleeContext` doesn't point to a direct parent but instead both parent context (uninitialized) and resume function are passed as last arguments which means that `callContext` has to act as an intermediate context in call to accessor. commitc1f830be27Author: Pavel Yaskevich <pyaskevich@apple.com> Date: Tue Jan 11 17:00:08 2022 -0800 [Distributed] Drop optionality from result buffer in `_executeDistributedTarget` `RawPointer?` is lowered into a two arguments since it's a struct, to make it easy let's just allocate an empty pointer for `Void` result. commitc83c2c37b6Author: Pavel Yaskevich <pyaskevich@apple.com> Date: Tue Jan 11 17:02:45 2022 -0800 [Distributed] NFC: Update _remoteCall test-case to check multiple different result types commit29e7cf50e4Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Wed Jan 12 21:32:37 2022 +0900 wip commit9128ecc6f8Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Wed Jan 12 20:46:20 2022 +0900 wip commita6b2a62a67Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Wed Jan 12 20:38:22 2022 +0900 wip commit8b188f0d43Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Wed Jan 12 16:55:10 2022 +0900 wip commit3796bec2b9Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Wed Jan 12 16:55:02 2022 +0900 wip commit0ffc68b5efAuthor: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Tue Jan 11 21:44:58 2022 +0900 [Distributed] Implementing ad-hoc protocol requirements commit78862575e4Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Thu Jan 6 18:03:54 2022 +0900 cleanup commit5f4ab89e25Merge:24a628e7c0fdda6f2ee4Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Thu Jan 6 15:51:39 2022 +0900 Merge branch 'main' into wip-impl-execute-swift commit24a628e7c0Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Thu Jan 6 15:33:21 2022 +0900 wip commit69e7fed09dAuthor: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Wed Dec 22 06:36:45 2021 +0900 [Distributed] comment out distributed_actor_remoteCall for now commit376733a9f6Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Tue Dec 21 16:00:06 2021 +0900 reimplement distributed get type info impls commit74ab47886aAuthor: Konrad `ktoso` Malawski <konrad_malawski@apple.com> Date: Wed Dec 15 21:37:08 2021 +0900 [Distributed] Implement func metadata and executeDistributedTarget dont expose new entrypoints able to get all the way to calling _execute
375 lines
13 KiB
C++
375 lines
13 KiB
C++
//===-- DistributedActor.cpp - SIL utils for distributed actors -*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/SILOptimizer/Utils/DistributedActor.h"
|
|
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/SIL/SILBuilder.h"
|
|
#include "swift/SIL/SILLocation.h"
|
|
|
|
namespace swift {
|
|
|
|
SILArgument *findFirstDistributedActorSystemArg(SILFunction &F) {
|
|
auto *module = F.getModule().getSwiftModule();
|
|
auto &C = F.getASTContext();
|
|
|
|
auto *transportProto = C.getProtocol(KnownProtocolKind::DistributedActorSystem);
|
|
Type transportTy = transportProto->getDeclaredInterfaceType();
|
|
|
|
for (auto arg : F.getArguments()) {
|
|
// TODO(distributed): also be able to locate a generic transport
|
|
Type argTy = arg->getType().getASTType();
|
|
auto argDecl = arg->getDecl();
|
|
|
|
auto conformsToTransport =
|
|
module->lookupConformance(argDecl->getInterfaceType(), transportProto);
|
|
|
|
// Is it a protocol that conforms to DistributedActorSystem?
|
|
if (argTy->isEqual(transportTy) || conformsToTransport) {
|
|
return arg;
|
|
}
|
|
|
|
// Is it some specific DistributedActorSystem?
|
|
auto result = module->lookupConformance(argTy, transportProto);
|
|
if (!result.isInvalid()) {
|
|
return arg;
|
|
}
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
llvm_unreachable("Missing required DistributedActorSystem argument!");
|
|
#endif
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void emitDistributedActorSystemWitnessCall(
|
|
SILBuilder &B, SILLocation loc, DeclName methodName,
|
|
SILValue base,
|
|
// types to be passed through to SubstitutionMap:
|
|
SILType actorType,
|
|
// call arguments, except the base which will be passed last
|
|
ArrayRef<SILValue> args,
|
|
Optional<std::pair<SILBasicBlock *, SILBasicBlock *>> tryTargets) {
|
|
auto &F = B.getFunction();
|
|
auto &M = B.getModule();
|
|
auto &C = F.getASTContext();
|
|
|
|
// Dig out the conformance to DistributedActorSystem.
|
|
ProtocolDecl *systemProto = C.getProtocol(KnownProtocolKind::DistributedActorSystem);
|
|
assert(systemProto);
|
|
auto systemASTType = base->getType().getASTType();
|
|
auto *module = M.getSwiftModule();
|
|
ProtocolConformanceRef systemConfRef;
|
|
|
|
// If the base is an existential open it.
|
|
if (systemASTType->isAnyExistentialType()) {
|
|
OpenedArchetypeType *opened;
|
|
systemASTType =
|
|
systemASTType->openAnyExistentialType(opened)->getCanonicalType();
|
|
base = B.createOpenExistentialAddr(
|
|
loc, base, F.getLoweredType(systemASTType),
|
|
OpenedExistentialAccess::Immutable);
|
|
}
|
|
|
|
if (systemASTType->isTypeParameter() || systemASTType->is<ArchetypeType>()) {
|
|
systemConfRef = ProtocolConformanceRef(systemProto);
|
|
} else {
|
|
systemConfRef = module->lookupConformance(systemASTType, systemProto);
|
|
}
|
|
|
|
assert(!systemConfRef.isInvalid() &&
|
|
"Missing conformance to `DistributedActorSystem`");
|
|
|
|
// Dig out the method.
|
|
auto method = cast<FuncDecl>(systemProto->getSingleRequirement(methodName));
|
|
auto methodRef = SILDeclRef(method, SILDeclRef::Kind::Func);
|
|
auto methodSILTy =
|
|
M.Types.getConstantInfo(B.getTypeExpansionContext(), methodRef)
|
|
.getSILType();
|
|
|
|
auto witnessMethod = B.createWitnessMethod(
|
|
loc, systemASTType, systemConfRef, methodRef, methodSILTy);
|
|
|
|
// prepare conformance substitutions
|
|
SubstitutionMap subs;
|
|
{
|
|
auto genericSig = method->getGenericSignature();
|
|
SmallVector<Type, 2> subTypes;
|
|
SmallVector<ProtocolConformanceRef, 2> subConformances;
|
|
subTypes.push_back(systemASTType);
|
|
subConformances.push_back(systemConfRef);
|
|
if (actorType) {
|
|
ProtocolDecl *actorProto = C.getProtocol(
|
|
KnownProtocolKind::DistributedActor);
|
|
assert(actorProto);
|
|
|
|
ProtocolConformanceRef conformance;
|
|
auto distributedActorConfRef = module->lookupConformance(
|
|
actorType.getASTType(), actorProto);
|
|
assert(!distributedActorConfRef.isInvalid() &&
|
|
"Missing conformance to `DistributedActor`");
|
|
subTypes.push_back(actorType.getASTType());
|
|
subConformances.push_back(distributedActorConfRef);
|
|
}
|
|
|
|
subs = SubstitutionMap::get(genericSig, subTypes, subConformances);
|
|
}
|
|
|
|
Optional<SILValue> temporaryArgumentBuffer;
|
|
|
|
// If the self parameter is indirect but the base is a value, put it
|
|
// into a temporary allocation.
|
|
auto methodSILFnTy = methodSILTy.castTo<SILFunctionType>();
|
|
Optional<SILValue> temporaryActorSystemBuffer;
|
|
if (methodSILFnTy->getSelfParameter().isFormalIndirect() &&
|
|
!base->getType().isAddress()) {
|
|
auto buf = B.createAllocStack(loc, base->getType(), None);
|
|
base = B.emitCopyValueOperation(loc, base);
|
|
B.emitStoreValueOperation(
|
|
loc, base, buf, StoreOwnershipQualifier::Init);
|
|
temporaryActorSystemBuffer = SILValue(buf);
|
|
}
|
|
|
|
// === Call the method.
|
|
// --- Push the arguments
|
|
SmallVector<SILValue, 2> allArgs;
|
|
auto params = methodSILFnTy->getParameters();
|
|
for (size_t i = 0; i < args.size(); ++i) {
|
|
auto arg = args[i];
|
|
// FIXME(distributed): handle multiple ones (!!!!)
|
|
if (params[i].isFormalIndirect() &&
|
|
!arg->getType().isAddress() &&
|
|
!dyn_cast<AnyMetatypeType>(arg->getType().getASTType())) {
|
|
auto buf = B.createAllocStack(loc, arg->getType(), None);
|
|
auto argCopy = B.emitCopyValueOperation(loc, arg);
|
|
B.emitStoreValueOperation(
|
|
loc, argCopy, buf, StoreOwnershipQualifier::Init);
|
|
temporaryArgumentBuffer = SILValue(buf);
|
|
allArgs.push_back(*temporaryArgumentBuffer);
|
|
} else {
|
|
allArgs.push_back(arg);
|
|
}
|
|
}
|
|
// Push the self argument
|
|
auto selfArg = temporaryActorSystemBuffer ? *temporaryActorSystemBuffer : base;
|
|
allArgs.push_back(selfArg);
|
|
|
|
SILInstruction *apply;
|
|
if (tryTargets) {
|
|
apply = B.createTryApply(
|
|
loc, witnessMethod, subs, allArgs, tryTargets->first,
|
|
tryTargets->second);
|
|
} else {
|
|
apply = B.createApply(loc, witnessMethod, subs, allArgs);
|
|
}
|
|
|
|
// Local function to emit a cleanup after the call.
|
|
auto emitCleanup = [&](llvm::function_ref<void(SILBuilder &builder)> fn) {
|
|
if (tryTargets) {
|
|
{
|
|
SILBuilderWithScope normalBuilder(tryTargets->first, apply);
|
|
fn(normalBuilder);
|
|
}
|
|
{
|
|
SILBuilderWithScope errorBuilder(tryTargets->second, apply);
|
|
fn(errorBuilder);
|
|
}
|
|
} else {
|
|
fn(B);
|
|
}
|
|
};
|
|
|
|
// ==== If we had to create a buffers we need to clean them up
|
|
// --- Cleanup id buffer
|
|
if (temporaryArgumentBuffer) {
|
|
emitCleanup([&](SILBuilder & builder) {
|
|
auto value = builder.emitLoadValueOperation(
|
|
loc, *temporaryArgumentBuffer, LoadOwnershipQualifier::Take);
|
|
builder.emitDestroyValueOperation(loc, value);
|
|
builder.createDeallocStack(loc, *temporaryArgumentBuffer);
|
|
});
|
|
}
|
|
// --- Cleanup base buffer
|
|
if (temporaryActorSystemBuffer) {
|
|
emitCleanup([&](SILBuilder & builder) {
|
|
auto value = builder.emitLoadValueOperation(
|
|
loc, *temporaryActorSystemBuffer, LoadOwnershipQualifier::Take);
|
|
builder.emitDestroyValueOperation(loc, value);
|
|
builder.createDeallocStack(loc, *temporaryActorSystemBuffer);
|
|
});
|
|
}
|
|
}
|
|
|
|
void emitDistributedWitnessCall(
|
|
SILBuilder &B, SILLocation loc, DeclName methodName,
|
|
SILValue base, ProtocolDecl *proto, SILType actorType,
|
|
llvm::ArrayRef<SILValue> args,
|
|
llvm::Optional<std::pair<SILBasicBlock *, SILBasicBlock *>> tryTargets) {
|
|
auto &F = B.getFunction();
|
|
auto &M = B.getModule();
|
|
auto &C = F.getASTContext();
|
|
|
|
// Dig out the conformance to the passed in protocol.
|
|
auto astType = base->getType().getASTType();
|
|
auto *module = M.getSwiftModule();
|
|
ProtocolConformanceRef confRef;
|
|
|
|
// If the base is an existential open it.
|
|
if (astType->isAnyExistentialType()) {
|
|
OpenedArchetypeType *opened;
|
|
astType = astType->openAnyExistentialType(opened)->getCanonicalType();
|
|
base = B.createOpenExistentialAddr(
|
|
loc, base, F.getLoweredType(astType),
|
|
OpenedExistentialAccess::Immutable);
|
|
}
|
|
|
|
if (astType->isTypeParameter() || astType->is<ArchetypeType>()) {
|
|
confRef = ProtocolConformanceRef(proto);
|
|
} else {
|
|
confRef = module->lookupConformance(astType, proto);
|
|
}
|
|
|
|
assert(!confRef.isInvalid() &&
|
|
"Missing conformance to `DistributedActorSystem`");
|
|
|
|
// Dig out the method.
|
|
auto method = cast<FuncDecl>(proto->getSingleRequirement(methodName));
|
|
auto methodRef = SILDeclRef(method, SILDeclRef::Kind::Func);
|
|
auto methodSILTy =
|
|
M.Types.getConstantInfo(B.getTypeExpansionContext(), methodRef)
|
|
.getSILType();
|
|
|
|
auto witnessMethod = B.createWitnessMethod(
|
|
loc, astType, confRef, methodRef, methodSILTy);
|
|
|
|
// prepare conformance substitutions
|
|
SubstitutionMap subs;
|
|
{
|
|
auto genericSig = method->getGenericSignature();
|
|
SmallVector<Type, 2> subTypes;
|
|
SmallVector<ProtocolConformanceRef, 2> subConformances;
|
|
subTypes.push_back(astType);
|
|
subConformances.push_back(confRef);
|
|
if (actorType) {
|
|
ProtocolDecl *actorProto = C.getProtocol(
|
|
KnownProtocolKind::DistributedActor);
|
|
assert(actorProto);
|
|
|
|
ProtocolConformanceRef conformance;
|
|
auto distributedActorConfRef = module->lookupConformance(
|
|
actorType.getASTType(), actorProto);
|
|
assert(!distributedActorConfRef.isInvalid() &&
|
|
"Missing conformance to `DistributedActor`");
|
|
subTypes.push_back(actorType.getASTType());
|
|
subConformances.push_back(distributedActorConfRef);
|
|
}
|
|
|
|
subs = SubstitutionMap::get(genericSig, subTypes, subConformances);
|
|
}
|
|
|
|
Optional<SILValue> temporaryActorIDBuffer;
|
|
|
|
// If the self parameter is indirect but the actorSystem is a value, put it
|
|
// into a temporary allocation.
|
|
auto methodSILFnTy = methodSILTy.castTo<SILFunctionType>();
|
|
Optional<SILValue> temporaryInvocationBuffer;
|
|
if (methodSILFnTy->getSelfParameter().isFormalIndirect() &&
|
|
!base->getType().isAddress()) {
|
|
auto buf = B.createAllocStack(loc, base->getType(), None);
|
|
base = B.emitCopyValueOperation(loc, base);
|
|
B.emitStoreValueOperation(
|
|
loc, base, buf, StoreOwnershipQualifier::Init);
|
|
temporaryInvocationBuffer = SILValue(buf);
|
|
}
|
|
|
|
// === Call the method.
|
|
// --- Push the arguments
|
|
SmallVector<SILValue, 2> allArgs;
|
|
auto params = methodSILFnTy->getParameters();
|
|
for (size_t i = 0; i < args.size(); ++i) {
|
|
auto arg = args[i];
|
|
if (params[i].isFormalIndirect() &&
|
|
!arg->getType().isAddress() &&
|
|
!dyn_cast<AnyMetatypeType>(arg->getType().getASTType())) {
|
|
auto buf = B.createAllocStack(loc, arg->getType(), None);
|
|
auto argCopy = B.emitCopyValueOperation(loc, arg);
|
|
B.emitStoreValueOperation(
|
|
loc, argCopy, buf, StoreOwnershipQualifier::Init);
|
|
temporaryActorIDBuffer = SILValue(buf);
|
|
allArgs.push_back(*temporaryActorIDBuffer);
|
|
} else {
|
|
allArgs.push_back(arg);
|
|
}
|
|
}
|
|
// Push the self argument
|
|
auto selfArg = temporaryInvocationBuffer ? *temporaryInvocationBuffer : base;
|
|
allArgs.push_back(selfArg);
|
|
|
|
SILInstruction *apply;
|
|
if (tryTargets) {
|
|
apply = B.createTryApply(
|
|
loc, witnessMethod, subs, allArgs, tryTargets->first,
|
|
tryTargets->second);
|
|
} else {
|
|
apply = B.createApply(loc, witnessMethod, subs, allArgs);
|
|
}
|
|
|
|
// Local function to emit a cleanup after the call.
|
|
auto emitCleanup = [&](llvm::function_ref<void(SILBuilder &builder)> fn) {
|
|
if (tryTargets) {
|
|
{
|
|
SILBuilderWithScope normalBuilder(tryTargets->first, apply);
|
|
fn(normalBuilder);
|
|
}
|
|
{
|
|
SILBuilderWithScope errorBuilder(tryTargets->second, apply);
|
|
fn(errorBuilder);
|
|
}
|
|
} else {
|
|
fn(B);
|
|
}
|
|
};
|
|
|
|
// ==== If we had to create a buffers we need to clean them up
|
|
// --- Cleanup id buffer
|
|
if (temporaryActorIDBuffer) {
|
|
emitCleanup([&](SILBuilder & builder) {
|
|
auto value = builder.emitLoadValueOperation(
|
|
loc, *temporaryActorIDBuffer, LoadOwnershipQualifier::Take);
|
|
builder.emitDestroyValueOperation(loc, value);
|
|
builder.createDeallocStack(loc, *temporaryActorIDBuffer);
|
|
});
|
|
}
|
|
// --- Cleanup actorSystem buffer
|
|
if (temporaryInvocationBuffer) {
|
|
emitCleanup([&](SILBuilder & builder) {
|
|
auto value = builder.emitLoadValueOperation(
|
|
loc, *temporaryInvocationBuffer, LoadOwnershipQualifier::Take);
|
|
builder.emitDestroyValueOperation(loc, value);
|
|
builder.createDeallocStack(loc, *temporaryInvocationBuffer);
|
|
});
|
|
}
|
|
}
|
|
|
|
void emitActorReadyCall(SILBuilder &B, SILLocation loc, SILValue actor,
|
|
SILValue actorSystem) {
|
|
|
|
auto &F = B.getFunction();
|
|
auto &C = F.getASTContext();
|
|
emitDistributedActorSystemWitnessCall(
|
|
B, loc, C.Id_actorReady, actorSystem,
|
|
F.mapTypeIntoContext(actor->getType()), { actor });
|
|
}
|
|
|
|
} // namespace swift
|