Files
swift-mirror/lib/SILOptimizer/Utils/DistributedActor.cpp
Konrad `ktoso` Malawski 4bf2a92bda [Distributed] Remove @_dynamic replacements; impl remoteCall ad-hoc reqs
Squashed commit of the following:

commit e5a05ffe44
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Thu Jan 27 17:45:31 2022 +0900

    cleanup

commit 1f751cea5a
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Thu Jan 27 14:50:33 2022 +0900

    cleanups

commit c632f3215d
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Thu Jan 27 14:01:09 2022 +0900

    add test for generic from actor decl

commit 09b8bd50a7
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Thu Jan 27 14:00:58 2022 +0900

    cleanups

commit 31f4d0cffd
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Thu Jan 27 11:40:51 2022 +0900

    fix test

commit ad4db2fb6c
Merge: 97227edcca 07e2dfda56
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Wed Jan 26 23:31:41 2022 +0900

    Merge branch 'main' into wip-zzz

commit 97227edcca
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Wed Jan 26 21:01:25 2022 +0900

    remove @_dynamic methods!

    fix tests

commit 1c79344dbb
Author: 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

commit 3ed494c175
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Tue Jan 18 21:09:28 2022 +0900

    stack issues in SIL verification

commit 5cf43a7f86
Author: 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

commit df8e47122a
Author: 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

commit fc7bd62f32
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Wed Jan 12 23:01:14 2022 +0900

    [Distributed] Pass arguments from Invocation to HBuffer

commit cafc2cc058
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Wed Jan 12 22:08:47 2022 +0900

    works

commit a7d01837ff
Author: 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.

commit c1f830be27
Author: 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.

commit c83c2c37b6
Author: 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

commit 29e7cf50e4
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Wed Jan 12 21:32:37 2022 +0900

    wip

commit 9128ecc6f8
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Wed Jan 12 20:46:20 2022 +0900

    wip

commit a6b2a62a67
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Wed Jan 12 20:38:22 2022 +0900

    wip

commit 8b188f0d43
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Wed Jan 12 16:55:10 2022 +0900

    wip

commit 3796bec2b9
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Wed Jan 12 16:55:02 2022 +0900

    wip

commit 0ffc68b5ef
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Tue Jan 11 21:44:58 2022 +0900

    [Distributed] Implementing ad-hoc protocol requirements

commit 78862575e4
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Thu Jan 6 18:03:54 2022 +0900

    cleanup

commit 5f4ab89e25
Merge: 24a628e7c0 fdda6f2ee4
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Thu Jan 6 15:51:39 2022 +0900

    Merge branch 'main' into wip-impl-execute-swift

commit 24a628e7c0
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Thu Jan 6 15:33:21 2022 +0900

    wip

commit 69e7fed09d
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Wed Dec 22 06:36:45 2021 +0900

    [Distributed] comment out distributed_actor_remoteCall for now

commit 376733a9f6
Author: Konrad `ktoso` Malawski <konrad_malawski@apple.com>
Date:   Tue Dec 21 16:00:06 2021 +0900

    reimplement distributed get type info impls

commit 74ab47886a
Author: 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
2022-01-27 17:51:43 +09:00

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