From 632419ba6071b3a0d9bfad9cbdb931b6537a6c3b Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Thu, 9 Mar 2023 21:46:59 +0900 Subject: [PATCH 01/11] [Executors][Distributed] custom executors for distributed actor --- .../Mandatory/LowerHopToActor.cpp | 10 +- .../DerivedConformanceDistributedActor.cpp | 146 ++++++++++++++++++ lib/Sema/DerivedConformances.cpp | 9 +- stdlib/public/Concurrency/Actor.cpp | 6 +- .../public/Distributed/DistributedActor.swift | 15 ++ ...tributed_actor_custom_executor_basic.swift | 54 +++++++ 6 files changed, 232 insertions(+), 8 deletions(-) create mode 100644 test/Distributed/Runtime/distributed_actor_custom_executor_basic.swift diff --git a/lib/SILOptimizer/Mandatory/LowerHopToActor.cpp b/lib/SILOptimizer/Mandatory/LowerHopToActor.cpp index 798e26eea4d08..2e320e0db74c4 100644 --- a/lib/SILOptimizer/Mandatory/LowerHopToActor.cpp +++ b/lib/SILOptimizer/Mandatory/LowerHopToActor.cpp @@ -177,8 +177,7 @@ SILValue LowerHopToActor::emitGetExecutor(SILBuilderWithScope &B, // If the actor type is a default actor, go ahead and devirtualize here. auto module = F->getModule().getSwiftModule(); SILValue unmarkedExecutor; - if (isDefaultActorType(actorType, module, F->getResilienceExpansion()) || - actorType->isDistributedActor()) { + if (isDefaultActorType(actorType, module, F->getResilienceExpansion())) { auto builtinName = ctx.getIdentifier( getBuiltinName(BuiltinValueKind::BuildDefaultActorExecutorRef)); auto builtinDecl = cast(getBuiltinValueDecl(ctx, builtinName)); @@ -189,14 +188,17 @@ SILValue LowerHopToActor::emitGetExecutor(SILBuilderWithScope &B, // Otherwise, go through Actor.unownedExecutor. } else { - auto actorProtocol = ctx.getProtocol(KnownProtocolKind::Actor); + auto actorKind = actorType->isDistributedActor() ? + KnownProtocolKind::DistributedActor : + KnownProtocolKind::Actor; + auto actorProtocol = ctx.getProtocol(actorKind); auto req = getUnownedExecutorGetter(ctx, actorProtocol); assert(req && "Concurrency library broken"); SILDeclRef fn(req, SILDeclRef::Kind::Func); auto actorConf = module->lookupConformance(actorType, actorProtocol); assert(actorConf && - "hop_to_executor with actor that doesn't conform to Actor"); + "hop_to_executor with actor that doesn't conform to Actor or DistributedActor"); auto subs = SubstitutionMap::get(req->getGenericSignature(), {actorType}, {actorConf}); diff --git a/lib/Sema/DerivedConformanceDistributedActor.cpp b/lib/Sema/DerivedConformanceDistributedActor.cpp index 7178383a1d3af..0d570bb9efe1d 100644 --- a/lib/Sema/DerivedConformanceDistributedActor.cpp +++ b/lib/Sema/DerivedConformanceDistributedActor.cpp @@ -17,6 +17,7 @@ #include "CodeSynthesis.h" #include "DerivedConformances.h" #include "TypeChecker.h" +#include "swift/Strings.h" #include "TypeCheckDistributed.h" #include "swift/AST/NameLookupRequests.h" #include "swift/AST/ParameterList.h" @@ -571,6 +572,148 @@ deriveDistributedActorType_SerializationRequirement( return nullptr; } +/******************************************************************************/ + + +/// Turn a Builtin.Executor value into an UnownedSerialExecutor. +static Expr *constructDistributedUnownedSerialExecutor(ASTContext &ctx, + Expr *arg) { + auto executorDecl = ctx.getUnownedSerialExecutorDecl(); + if (!executorDecl) return nullptr; + + for (auto member: executorDecl->getAllMembers()) { + auto ctor = dyn_cast(member); + if (!ctor) continue; + auto params = ctor->getParameters(); + if (params->size() != 1 || + !params->get(0)->getInterfaceType()->is()) + continue; + + Type executorType = executorDecl->getDeclaredInterfaceType(); + + Type ctorType = ctor->getInterfaceType(); + + // We have the right initializer. Build a reference to it of type: + // (UnownedSerialExecutor.Type) + // -> (Builtin.Executor) -> UnownedSerialExecutor + auto initRef = new (ctx) DeclRefExpr(ctor, DeclNameLoc(), /*implicit*/true, + AccessSemantics::Ordinary, + ctorType); + + // Apply the initializer to the metatype, building an expression of type: + // (Builtin.Executor) -> UnownedSerialExecutor + auto metatypeRef = TypeExpr::createImplicit(executorType, ctx); + Type ctorAppliedType = ctorType->getAs()->getResult(); + auto selfApply = ConstructorRefCallExpr::create(ctx, initRef, metatypeRef, + ctorAppliedType); + selfApply->setImplicit(true); + selfApply->setThrows(false); + + // Call the constructor, building an expression of type + // UnownedSerialExecutor. + auto *argList = ArgumentList::forImplicitUnlabeled(ctx, {arg}); + auto call = CallExpr::createImplicit(ctx, selfApply, argList); + call->setType(executorType); + call->setThrows(false); + return call; + } + + return nullptr; +} + +static std::pair +deriveBodyDistributedActor_unownedExecutor(AbstractFunctionDecl *getter, void *) { + // var unownedExecutor: UnownedSerialExecutor { + // get { + // return Builtin.buildDefaultActorExecutorRef(self) + // } + // } + ASTContext &ctx = getter->getASTContext(); + + // Produce an empty brace statement on failure. + auto failure = [&]() -> std::pair { + auto body = BraceStmt::create( + ctx, SourceLoc(), { }, SourceLoc(), /*implicit=*/true); + return { body, /*isTypeChecked=*/true }; + }; + + // Build a reference to self. + Type selfType = getter->getImplicitSelfDecl()->getType(); + Expr *selfArg = DerivedConformance::createSelfDeclRef(getter); + selfArg->setType(selfType); + + // The builtin call gives us a Builtin.Executor. + auto builtinCall = + DerivedConformance::createBuiltinCall(ctx, + BuiltinValueKind::BuildDefaultActorExecutorRef, + {selfType}, {}, {selfArg}); + + // Turn that into an UnownedSerialExecutor. + auto initCall = constructDistributedUnownedSerialExecutor(ctx, builtinCall); + if (!initCall) return failure(); + + auto ret = new (ctx) ReturnStmt(SourceLoc(), initCall, /*implicit*/ true); + + auto body = BraceStmt::create( + ctx, SourceLoc(), { ret }, SourceLoc(), /*implicit=*/true); + return { body, /*isTypeChecked=*/true }; +} + +/// Derive the declaration of DistributedActor's unownedExecutor property. +static ValueDecl *deriveDistributedActor_unownedExecutor(DerivedConformance &derived) { + ASTContext &ctx = derived.Context; + + if (auto classDecl = dyn_cast(derived.Nominal)) { + if (auto existing = classDecl->getUnownedExecutorProperty()) { + return const_cast(existing); + } + } + + // Retrieve the types and declarations we'll need to form this operation. + auto executorDecl = ctx.getUnownedSerialExecutorDecl(); + if (!executorDecl) { + derived.Nominal->diagnose( + diag::concurrency_lib_missing, "UnownedSerialExecutor"); + return nullptr; + } + Type executorType = executorDecl->getDeclaredInterfaceType(); + + auto propertyPair = derived.declareDerivedProperty( + DerivedConformance::SynthesizedIntroducer::Var, ctx.Id_unownedExecutor, + executorType, executorType, + /*static*/ false, /*final*/ false); + auto property = propertyPair.first; + property->setSynthesized(true); + property->getAttrs().add(new (ctx) SemanticsAttr(SEMANTICS_DEFAULT_ACTOR, + SourceLoc(), SourceRange(), + /*implicit*/ true)); + property->getAttrs().add(new (ctx) NonisolatedAttr(/*IsImplicit=*/true)); + + // Make the property implicitly final. + property->getAttrs().add(new (ctx) FinalAttr(/*IsImplicit=*/true)); + if (property->getFormalAccess() == AccessLevel::Open) + property->overwriteAccess(AccessLevel::Public); + + // Infer availability. + SmallVector asAvailableAs; + asAvailableAs.push_back(executorDecl); + if (auto enclosingDecl = property->getInnermostDeclWithAvailability()) + asAvailableAs.push_back(enclosingDecl); + + AvailabilityInference::applyInferredAvailableAttrs( + property, asAvailableAs, ctx); + + auto getter = + derived.addGetterToReadOnlyDerivedProperty(property, executorType); + getter->setBodySynthesizer(deriveBodyDistributedActor_unownedExecutor); + + derived.addMembersToConformanceContext( + { property, propertyPair.second, }); + return property; +} + + + /******************************************************************************/ /**************************** ENTRY POINTS ************************************/ /******************************************************************************/ @@ -587,6 +730,9 @@ ValueDecl *DerivedConformance::deriveDistributedActor(ValueDecl *requirement) { if (var->getName() == Context.Id_actorSystem) return deriveDistributedActor_actorSystem(*this); + + if (var->getName() == Context.Id_unownedExecutor) + return deriveDistributedActor_unownedExecutor(*this); } if (auto func = dyn_cast(requirement)) { diff --git a/lib/Sema/DerivedConformances.cpp b/lib/Sema/DerivedConformances.cpp index fc5389c82522f..82d0c58f54b1c 100644 --- a/lib/Sema/DerivedConformances.cpp +++ b/lib/Sema/DerivedConformances.cpp @@ -334,8 +334,13 @@ ValueDecl *DerivedConformance::getDerivableRequirement(NominalTypeDecl *nominal, return getRequirement(KnownProtocolKind::AdditiveArithmetic); // Actor.unownedExecutor - if (name.isSimpleName(ctx.Id_unownedExecutor)) - return getRequirement(KnownProtocolKind::Actor); + if (name.isSimpleName(ctx.Id_unownedExecutor)) { + if (nominal->isDistributedActor()) { + return getRequirement(KnownProtocolKind::DistributedActor); + } else { + return getRequirement(KnownProtocolKind::Actor); + } + } // DistributedActor.id if (name.isSimpleName(ctx.Id_id)) diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index 2025bf2178839..e7d12bde592eb 100644 --- a/stdlib/public/Concurrency/Actor.cpp +++ b/stdlib/public/Concurrency/Actor.cpp @@ -1828,9 +1828,11 @@ static void swift_task_switchImpl(SWIFT_ASYNC_CONTEXT AsyncContext *resumeContex auto currentExecutor = (trackingInfo ? trackingInfo->getActiveExecutor() : ExecutorRef::generic()); - SWIFT_TASK_DEBUG_LOG("Task %p trying to switch from executor %p to %p", task, + SWIFT_TASK_DEBUG_LOG("Task %p trying to switch from executor %p to %p %s", task, currentExecutor.getIdentity(), - newExecutor.getIdentity()); + newExecutor.getIdentity(), + newExecutor.isMainExecutor() ? " (MainActorExecutor)" : + newExecutor.isGeneric() ? " (GenericExecutor)" : ""); // If the current executor is compatible with running the new executor, // we can just immediately continue running with the resume function diff --git a/stdlib/public/Distributed/DistributedActor.swift b/stdlib/public/Distributed/DistributedActor.swift index 10e0e5e6b6752..1d01b9015b5f5 100644 --- a/stdlib/public/Distributed/DistributedActor.swift +++ b/stdlib/public/Distributed/DistributedActor.swift @@ -257,6 +257,21 @@ public protocol DistributedActor: AnyActor, Identifiable, Hashable /// - Parameter id: identity uniquely identifying a, potentially remote, actor in the system /// - Parameter system: `system` which should be used to resolve the `identity`, and be associated with the returned actor static func resolve(id: ID, using system: ActorSystem) throws -> Self + + /// Retrieve the executor for this actor as an optimized, unowned + /// reference. + /// + /// This property must always evaluate to the same executor for a + /// given actor instance, and holding on to the actor must keep the + /// executor alive. + /// + /// This property will be implicitly accessed when work needs to be + /// scheduled onto this actor. These accesses may be merged, + /// eliminated, and rearranged with other work, and they may even + /// be introduced when not strictly required. Visible side effects + /// are therefore strongly discouraged within this property. + @available(SwiftStdlib 5.9, *) + nonisolated var unownedExecutor: UnownedSerialExecutor { get } } // ==== Hashable conformance --------------------------------------------------- diff --git a/test/Distributed/Runtime/distributed_actor_custom_executor_basic.swift b/test/Distributed/Runtime/distributed_actor_custom_executor_basic.swift new file mode 100644 index 0000000000000..bc8242e5a42a1 --- /dev/null +++ b/test/Distributed/Runtime/distributed_actor_custom_executor_basic.swift @@ -0,0 +1,54 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/../Inputs/FakeDistributedActorSystems.swift +// RUN: %target-build-swift -module-name main -Xfrontend -enable-experimental-distributed -Xfrontend -disable-availability-checking -j2 -parse-as-library -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift -o %t/a.out +// RUN: %target-codesign %t/a.out +// RUN: %target-run %t/a.out | %FileCheck %s --color + +// REQUIRES: executable_test +// REQUIRES: concurrency +// REQUIRES: distributed + +// rdar://76038845 +// UNSUPPORTED: use_os_stdlib +// UNSUPPORTED: back_deployment_runtime + +// FIXME(distributed): Distributed actors currently have some issues on windows rdar://82593574 +// UNSUPPORTED: OS=windows-msvc + + +import Distributed +import FakeDistributedActorSystems + +typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem + +distributed actor Worker { + nonisolated var unownedExecutor: UnownedSerialExecutor { + print("get unowned executor") + return MainActor.sharedUnownedExecutor + } + + distributed func test(x: Int) async throws { + print("executed: \(#function)") + assumeOnMainActorExecutor { + print("assume: this distributed actor shares executor with MainActor") + } + print("done executed: \(#function)") + } + +} + +@main struct Main { + static func main() async { + let worker = Worker(actorSystem: DefaultDistributedActorSystem()) + // CHECK: | assign id + // CHECK: | actor ready + + try! await worker.test(x: 42) + // CHECK: get unowned executor + // CHECK: executed: test(x:) + // CHECK: assume: this distributed actor shares executor with MainActor + // CHECK: done executed: test(x:) + + print("OK") // CHECK: OK + } +} From 341900bd02a150b625ac65181fa9c4499dd12573 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Tue, 14 Mar 2023 00:20:03 +0900 Subject: [PATCH 02/11] harden ordering guarantees of synthesised fields --- include/swift/AST/TypeCheckRequests.h | 2 +- .../DerivedConformanceDistributedActor.cpp | 145 +++++++++++++----- lib/Sema/DerivedConformances.cpp | 1 - .../public/Distributed/DistributedActor.swift | 29 ++-- ...tributed_actor_custom_executor_basic.swift | 8 +- 5 files changed, 127 insertions(+), 58 deletions(-) diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 6d8115377b117..46bbda6fed53d 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -1220,7 +1220,7 @@ class GetDistributedActorSystemPropertyRequest : public: // Caching - bool isCached() const { return true; } + bool isCached() const { return false; } }; /// Obtain the constructor of the 'RemoteCallTarget' type. diff --git a/lib/Sema/DerivedConformanceDistributedActor.cpp b/lib/Sema/DerivedConformanceDistributedActor.cpp index 0d570bb9efe1d..0e22a66e8e622 100644 --- a/lib/Sema/DerivedConformanceDistributedActor.cpp +++ b/lib/Sema/DerivedConformanceDistributedActor.cpp @@ -424,31 +424,32 @@ static FuncDecl *deriveDistributedActorSystem_invokeHandlerOnReturn( /******************************* PROPERTIES ***********************************/ /******************************************************************************/ -// TODO(distributed): make use of this after all, but FORCE it? -static ValueDecl *deriveDistributedActor_id(DerivedConformance &derived) { - assert(derived.Nominal->isDistributedActor()); - auto &C = derived.Context; - - // ``` - // nonisolated let id: Self.ID // Self.ActorSystem.ActorID - // ``` - auto propertyType = getDistributedActorIDType(derived.Nominal); - - VarDecl *propDecl; - PatternBindingDecl *pbDecl; - std::tie(propDecl, pbDecl) = derived.declareDerivedProperty( - DerivedConformance::SynthesizedIntroducer::Let, C.Id_id, propertyType, - propertyType, - /*isStatic=*/false, /*isFinal=*/true); - - // mark as nonisolated, allowing access to it from everywhere - propDecl->getAttrs().add( - new (C) NonisolatedAttr(/*IsImplicit=*/true)); - - derived.addMemberToConformanceContext(pbDecl, /*insertAtHead=*/true); - derived.addMemberToConformanceContext(propDecl, /*insertAtHead=*/true); - return propDecl; -} +//// TODO(distributed): make use of this after all, but FORCE it? +//static ValueDecl *deriveDistributedActor_id(DerivedConformance &derived) { +// assert(derived.Nominal->isDistributedActor()); +// auto &C = derived.Context; +// +// // ``` +// // nonisolated let id: Self.ID // Self.ActorSystem.ActorID +// // ``` +// auto propertyType = getDistributedActorIDType(derived.Nominal); +// +// VarDecl *propDecl; +// PatternBindingDecl *pbDecl; +// std::tie(propDecl, pbDecl) = derived.declareDerivedProperty( +// DerivedConformance::SynthesizedIntroducer::Let, C.Id_id, propertyType, +// propertyType, +// /*isStatic=*/false, /*isFinal=*/true); +// +// // mark as nonisolated, allowing access to it from everywhere +// propDecl->getAttrs().add( +// new (C) NonisolatedAttr(/*IsImplicit=*/true)); +// +// fprintf(stderr, "[%s:%d](%s) INSERT ID: FIRST\n", __FILE_NAME__, __LINE__, __FUNCTION__); +// derived.addMemberToConformanceContext(pbDecl, /*insertAtHead=*/true); +// derived.addMemberToConformanceContext(propDecl, /*insertAtHead=*/true); +// return propDecl; +//} static ValueDecl *deriveDistributedActor_actorSystem( DerivedConformance &derived) { @@ -479,15 +480,17 @@ static ValueDecl *deriveDistributedActor_actorSystem( // we don't allocate memory after those two fields, so their order is very // important. The `hint` below makes sure the system is inserted right after. if (auto id = derived.Nominal->getDistributedActorIDProperty()) { - derived.addMemberToConformanceContext(pbDecl, /*hint=*/id); + fprintf(stderr, "[%s:%d](%s) INSERT SYSTEM: AFTER ID\n", __FILE_NAME__, __LINE__, __FUNCTION__); derived.addMemberToConformanceContext(propDecl, /*hint=*/id); + derived.addMemberToConformanceContext(pbDecl, /*hint=*/id); } else { // `id` will be synthesized next, and will insert at head, // so in order for system to be SECOND (as it must be), // we'll insert at head right now and as id gets synthesized we'll get // the correct order: id, actorSystem. - derived.addMemberToConformanceContext(pbDecl, /*insertAtHead==*/true); + fprintf(stderr, "[%s:%d](%s) INSERT SYSTEM: FIRST\n", __FILE_NAME__, __LINE__, __FUNCTION__); derived.addMemberToConformanceContext(propDecl, /*insertAtHead=*/true); + derived.addMemberToConformanceContext(pbDecl, /*insertAtHead==*/true); } return propDecl; @@ -707,12 +710,34 @@ static ValueDecl *deriveDistributedActor_unownedExecutor(DerivedConformance &der derived.addGetterToReadOnlyDerivedProperty(property, executorType); getter->setBodySynthesizer(deriveBodyDistributedActor_unownedExecutor); - derived.addMembersToConformanceContext( - { property, propertyPair.second, }); - return property; -} + // IMPORTANT: MUST BE AFTER [id, actorSystem]. + if (auto id = derived.Nominal->getDistributedActorIDProperty()) { + if (auto system = derived.Nominal->getDistributedActorSystemProperty()) { + // good, we must be after the system; this is the final order + fprintf(stderr, "[%s:%d](%s) INSERT EXECUTOR: AFTER SYSTEM\n", __FILE_NAME__, __LINE__, __FUNCTION__); + system->dump(); + derived.addMemberToConformanceContext(propertyPair.second, /*hint=*/system); + derived.addMemberToConformanceContext(property, /*hint=*/system); + } else { + // system was not yet synthesized, it'll insert after id and we'll be okey + fprintf(stderr, "[%s:%d](%s) INSERT EXECUTOR: AFTER ID\n", __FILE_NAME__, __LINE__, __FUNCTION__); + derived.addMemberToConformanceContext(propertyPair.second, /*hint=*/id); + derived.addMemberToConformanceContext(property, /*hint=*/id); + } + } else { + // nor id or system synthesized yet, id will insert first and system will be after it + fprintf(stderr, "[%s:%d](%s) INSERT EXECUTOR: FIRST\n", __FILE_NAME__, __LINE__, __FUNCTION__); + derived.addMemberToConformanceContext(propertyPair.second, /*insertAtHead==*/true); + derived.addMemberToConformanceContext(property, /*insertAtHead==*/true); + } + fprintf(stderr, "[%s:%d](%s) ================================================\n", __FILE_NAME__, __LINE__, __FUNCTION__); + derived.Nominal->dump(); + fprintf(stderr, "[%s:%d](%s) ================================================\n", __FILE_NAME__, __LINE__, __FUNCTION__); + fprintf(stderr, "[%s:%d](%s) ================================================\n", __FILE_NAME__, __LINE__, __FUNCTION__); + return property; +} /******************************************************************************/ /**************************** ENTRY POINTS ************************************/ @@ -725,14 +750,57 @@ static ValueDecl *deriveDistributedActor_unownedExecutor(DerivedConformance &der ValueDecl *DerivedConformance::deriveDistributedActor(ValueDecl *requirement) { if (auto var = dyn_cast(requirement)) { - if (var->getName() == Context.Id_id) - return deriveDistributedActor_id(*this); - - if (var->getName() == Context.Id_actorSystem) - return deriveDistributedActor_actorSystem(*this); + ValueDecl *derivedValue = nullptr; +// if (var->getName() == Context.Id_id) { +// fprintf(stderr, "[%s:%d](%s) DERIVE ID\n", __FILE_NAME__, __LINE__, __FUNCTION__); +// derivedValue = deriveDistributedActor_id(*this); +// } else + // NOTE: `id` is implemented in addImplicitDistributedActorIDProperty + + if (var->getName() == Context.Id_actorSystem) { + fprintf(stderr, "[%s:%d](%s) DERIVE SYS\n", __FILE_NAME__, __LINE__, __FUNCTION__); + derivedValue = deriveDistributedActor_actorSystem(*this); + } else if (var->getName() == Context.Id_unownedExecutor) { + fprintf(stderr, "[%s:%d](%s) DERIVE EX\n", __FILE_NAME__, __LINE__, __FUNCTION__); + derivedValue = deriveDistributedActor_unownedExecutor(*this); + } - if (var->getName() == Context.Id_unownedExecutor) - return deriveDistributedActor_unownedExecutor(*this); + if (derivedValue) { + if (auto id = Nominal->getDistributedActorIDProperty()) { + if (auto system = Nominal->getDistributedActorSystemProperty()) { + if (auto classDecl = dyn_cast(Nominal)) { + if (auto unownedExecutor = classDecl->getUnownedExecutorProperty()) { + int idIdx, actorSystemIdx, unownedExecutorIdx = 0; + int idx = 0; + for (auto member : Nominal->getMembers()) { + if (auto binding = dyn_cast(member)) { + fprintf(stderr, "[%s:%d](%s) member = \n", __FILE_NAME__, __LINE__, __FUNCTION__); + member->dump(); + if (binding->getSingleVar()->getName() == Context.Id_id) { + idIdx = idx; + } else if (binding->getSingleVar()->getName() == Context.Id_actorSystem) { + actorSystemIdx = idx; + } else if (binding->getSingleVar()->getName() == Context.Id_unownedExecutor) { + unownedExecutorIdx = idx; + } + idx += 1; + } + } + if (idIdx + actorSystemIdx + unownedExecutorIdx >= 0 + 1 + 2) { + fprintf(stderr, "[%s:%d](%s) ******************************************************************************************\n", __FILE_NAME__, __LINE__, __FUNCTION__); + Nominal->dump(); + fprintf(stderr, "[%s:%d](%s) ******************************************************************************************\n", __FILE_NAME__, __LINE__, __FUNCTION__); + fprintf(stderr, "[%s:%d](%s) member == id = %d \n", __FILE_NAME__, __LINE__, __FUNCTION__, idIdx); + fprintf(stderr, "[%s:%d](%s) member == sys = %d \n", __FILE_NAME__, __LINE__, __FUNCTION__, actorSystemIdx); + fprintf(stderr, "[%s:%d](%s) member == ex = %d \n", __FILE_NAME__, __LINE__, __FUNCTION__, unownedExecutorIdx); +// assert(idIdx < actorSystemIdx < unownedExecutorIdx && "order of fields MUST be exact."); + } + } + } + } + } + return derivedValue; + } } if (auto func = dyn_cast(requirement)) { @@ -751,6 +819,7 @@ std::pair DerivedConformance::deriveDistributedActor( if (!canDeriveDistributedActor(Nominal, cast(ConformanceDecl))) return std::make_pair(Type(), nullptr); + if (assocType->getName() == Context.Id_ActorSystem) { return std::make_pair(deriveDistributedActorType_ActorSystem(*this), nullptr); diff --git a/lib/Sema/DerivedConformances.cpp b/lib/Sema/DerivedConformances.cpp index 82d0c58f54b1c..a1420b418ddd8 100644 --- a/lib/Sema/DerivedConformances.cpp +++ b/lib/Sema/DerivedConformances.cpp @@ -524,7 +524,6 @@ DerivedConformance::declareDerivedPropertyGetter(VarDecl *property, getterDecl->setIsTransparent(false); getterDecl->copyFormalAccessFrom(property); - return getterDecl; } diff --git a/stdlib/public/Distributed/DistributedActor.swift b/stdlib/public/Distributed/DistributedActor.swift index 1d01b9015b5f5..b8dd2784281bf 100644 --- a/stdlib/public/Distributed/DistributedActor.swift +++ b/stdlib/public/Distributed/DistributedActor.swift @@ -242,6 +242,21 @@ public protocol DistributedActor: AnyActor, Identifiable, Hashable /// the default initializer is not synthesized, and all the user-defined initializers must take care to initialize this property. nonisolated var actorSystem: ActorSystem { get } + /// Retrieve the executor for this actor as an optimized, unowned + /// reference. + /// + /// This property must always evaluate to the same executor for a + /// given actor instance, and holding on to the actor must keep the + /// executor alive. + /// + /// This property will be implicitly accessed when work needs to be + /// scheduled onto this actor. These accesses may be merged, + /// eliminated, and rearranged with other work, and they may even + /// be introduced when not strictly required. Visible side effects + /// are therefore strongly discouraged within this property. + @available(SwiftStdlib 5.9, *) + nonisolated var unownedExecutor: UnownedSerialExecutor { get } + /// Resolves the passed in `id` against the `system`, returning /// either a local or remote actor reference. /// @@ -258,20 +273,6 @@ public protocol DistributedActor: AnyActor, Identifiable, Hashable /// - Parameter system: `system` which should be used to resolve the `identity`, and be associated with the returned actor static func resolve(id: ID, using system: ActorSystem) throws -> Self - /// Retrieve the executor for this actor as an optimized, unowned - /// reference. - /// - /// This property must always evaluate to the same executor for a - /// given actor instance, and holding on to the actor must keep the - /// executor alive. - /// - /// This property will be implicitly accessed when work needs to be - /// scheduled onto this actor. These accesses may be merged, - /// eliminated, and rearranged with other work, and they may even - /// be introduced when not strictly required. Visible side effects - /// are therefore strongly discouraged within this property. - @available(SwiftStdlib 5.9, *) - nonisolated var unownedExecutor: UnownedSerialExecutor { get } } // ==== Hashable conformance --------------------------------------------------- diff --git a/test/Distributed/Runtime/distributed_actor_custom_executor_basic.swift b/test/Distributed/Runtime/distributed_actor_custom_executor_basic.swift index bc8242e5a42a1..30b1d83f694af 100644 --- a/test/Distributed/Runtime/distributed_actor_custom_executor_basic.swift +++ b/test/Distributed/Runtime/distributed_actor_custom_executor_basic.swift @@ -22,10 +22,10 @@ import FakeDistributedActorSystems typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem distributed actor Worker { - nonisolated var unownedExecutor: UnownedSerialExecutor { - print("get unowned executor") - return MainActor.sharedUnownedExecutor - } +// nonisolated var unownedExecutor: UnownedSerialExecutor { +// print("get unowned executor") +// return MainActor.sharedUnownedExecutor +// } distributed func test(x: Int) async throws { print("executed: \(#function)") From 329c9e56b9391f7635ab0603641a18e87688b5fb Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Tue, 14 Mar 2023 21:56:06 +0900 Subject: [PATCH 03/11] the issue was that a non-default actor must implement the is remote check differently --- include/swift/ABI/Metadata.h | 4 +++ include/swift/Runtime/Concurrency.h | 2 +- .../DerivedConformanceDistributedActor.cpp | 29 ++----------------- stdlib/public/Concurrency/Actor.cpp | 27 +++++++++++++---- ...tributed_actor_custom_executor_basic.swift | 10 ++++--- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index 7d7307140e9cf..09f2dc1d95436 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -4139,10 +4139,14 @@ class TargetClassDescriptor final } bool isActor() const { + fprintf(stderr, "[%s:%d](%s) is actor? %d\n", __FILE_NAME__, __LINE__, __FUNCTION__, + this->getTypeContextDescriptorFlags().class_isActor()); return this->getTypeContextDescriptorFlags().class_isActor(); } bool isDefaultActor() const { + fprintf(stderr, "[%s:%d](%s) is actor? %d\n", __FILE_NAME__, __LINE__, __FUNCTION__, + this->getTypeContextDescriptorFlags().class_isDefaultActor()); return this->getTypeContextDescriptorFlags().class_isDefaultActor(); } diff --git a/include/swift/Runtime/Concurrency.h b/include/swift/Runtime/Concurrency.h index fb34a38bbcf01..3f0c7d3e04a06 100644 --- a/include/swift/Runtime/Concurrency.h +++ b/include/swift/Runtime/Concurrency.h @@ -821,7 +821,7 @@ void swift_defaultActor_enqueue(Job *job, DefaultActor *actor); /// Check if the actor is a distributed 'remote' actor instance. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) -bool swift_distributed_actor_is_remote(DefaultActor *actor); +bool swift_distributed_actor_is_remote(HeapObject *actor); /// Do a primitive suspension of the current task, as if part of /// a continuation, although this does not provide any of the diff --git a/lib/Sema/DerivedConformanceDistributedActor.cpp b/lib/Sema/DerivedConformanceDistributedActor.cpp index 0e22a66e8e622..e927bed38a412 100644 --- a/lib/Sema/DerivedConformanceDistributedActor.cpp +++ b/lib/Sema/DerivedConformanceDistributedActor.cpp @@ -424,32 +424,9 @@ static FuncDecl *deriveDistributedActorSystem_invokeHandlerOnReturn( /******************************* PROPERTIES ***********************************/ /******************************************************************************/ -//// TODO(distributed): make use of this after all, but FORCE it? -//static ValueDecl *deriveDistributedActor_id(DerivedConformance &derived) { -// assert(derived.Nominal->isDistributedActor()); -// auto &C = derived.Context; -// -// // ``` -// // nonisolated let id: Self.ID // Self.ActorSystem.ActorID -// // ``` -// auto propertyType = getDistributedActorIDType(derived.Nominal); -// -// VarDecl *propDecl; -// PatternBindingDecl *pbDecl; -// std::tie(propDecl, pbDecl) = derived.declareDerivedProperty( -// DerivedConformance::SynthesizedIntroducer::Let, C.Id_id, propertyType, -// propertyType, -// /*isStatic=*/false, /*isFinal=*/true); -// -// // mark as nonisolated, allowing access to it from everywhere -// propDecl->getAttrs().add( -// new (C) NonisolatedAttr(/*IsImplicit=*/true)); -// -// fprintf(stderr, "[%s:%d](%s) INSERT ID: FIRST\n", __FILE_NAME__, __LINE__, __FUNCTION__); -// derived.addMemberToConformanceContext(pbDecl, /*insertAtHead=*/true); -// derived.addMemberToConformanceContext(propDecl, /*insertAtHead=*/true); -// return propDecl; -//} +// NOTE: There is no deriveDistributedActor_aid since it must be handled earlier +// due to the Identifiable Conformance it must fulfil as well. +// TODO(distributed): try to bring back `id` synthesis from addImplicitDistributedActorIDProperty to Derived infra static ValueDecl *deriveDistributedActor_actorSystem( DerivedConformance &derived) { diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index e7d12bde592eb..2f6d0df308c71 100644 --- a/stdlib/public/Concurrency/Actor.cpp +++ b/stdlib/public/Concurrency/Actor.cpp @@ -778,7 +778,7 @@ class alignas(sizeof(void *) * 2) ActiveActorStatus { } concurrency::trace::actor_state_changed( actor, getFirstJob().getRawJob(), getFirstJob().needsPreprocessing(), - traceState, swift_distributed_actor_is_remote((DefaultActor *) actor), + traceState, swift_distributed_actor_is_remote((HeapObject *) actor), isMaxPriorityEscalated(), static_cast(getMaxPriority())); } }; @@ -861,6 +861,7 @@ class DefaultActorImpl : public HeapObject { public: /// Properly construct an actor, except for the heap header. void initialize(bool isDistributedRemote = false) { + fprintf(stderr, "[%s:%d](%s) initialize DefaultActorImpl; remote = %d\n", __FILE_NAME__, __LINE__, __FUNCTION__, isDistributedRemote); this->isDistributedRemoteActor = isDistributedRemote; #if SWIFT_CONCURRENCY_ACTORS_AS_LOCKS new (&this->drainLock) Mutex(); @@ -1665,6 +1666,7 @@ static void swift_job_runImpl(Job *job, ExecutorRef executor) { } void swift::swift_defaultActor_initialize(DefaultActor *_actor) { + fprintf(stderr, "[%s:%d](%s) DefaultActor initialize!!!\n", __FILE_NAME__, __LINE__, __FUNCTION__); asImpl(_actor)->initialize(); } @@ -1685,17 +1687,24 @@ void swift::swift_defaultActor_deallocate(DefaultActor *_actor) { } static bool isDefaultActorClass(const ClassMetadata *metadata) { + fprintf(stderr, "[%s:%d](%s) is DefaultActor ???\n", __FILE_NAME__, __LINE__, __FUNCTION__); + assert(metadata->isTypeMetadata()); while (true) { // Trust the class descriptor if it says it's a default actor. - if (metadata->getDescription()->isDefaultActor()) + if (metadata->getDescription()->isDefaultActor()) { + fprintf(stderr, "[%s:%d](%s) is DefaultActor = YES\n", __FILE_NAME__, __LINE__, __FUNCTION__); return true; + } // Go to the superclass. metadata = metadata->Superclass; // If we run out of Swift classes, it's not a default actor. - if (!metadata || !metadata->isTypeMetadata()) return false; + if (!metadata || !metadata->isTypeMetadata()) { + fprintf(stderr, "[%s:%d](%s) is DefaultActor = NO IT IS NOT\n", __FILE_NAME__, __LINE__, __FUNCTION__); + return false; + } } } @@ -1965,8 +1974,16 @@ swift::swift_distributedActor_remote_initialize(const Metadata *actorType) { return reinterpret_cast(actor); } -bool swift::swift_distributed_actor_is_remote(DefaultActor *_actor) { - return asImpl(_actor)->isDistributedRemote(); +bool swift::swift_distributed_actor_is_remote(HeapObject *_actor) { + fprintf(stderr, "[%s:%d](%s) IS IT REMOTE?\n", __FILE_NAME__, __LINE__, __FUNCTION__); + auto metadata = cast(_actor->metadata); + if (isDefaultActorClass(metadata)) { + fprintf(stderr, "[%s:%d](%s) the distributed actor is DEFAULT\n", __FILE_NAME__, __LINE__, __FUNCTION__); + return asImpl((DefaultActor *) _actor)->isDistributedRemote(); + } else { + fprintf(stderr, "[%s:%d](%s) the distributed actor is CUSTOM\n", __FILE_NAME__, __LINE__, __FUNCTION__); + return false; // TODO: just a placeholder to verify logic on Linux + } } bool DefaultActorImpl::isDistributedRemote() { diff --git a/test/Distributed/Runtime/distributed_actor_custom_executor_basic.swift b/test/Distributed/Runtime/distributed_actor_custom_executor_basic.swift index 30b1d83f694af..7011334dec523 100644 --- a/test/Distributed/Runtime/distributed_actor_custom_executor_basic.swift +++ b/test/Distributed/Runtime/distributed_actor_custom_executor_basic.swift @@ -22,10 +22,10 @@ import FakeDistributedActorSystems typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem distributed actor Worker { -// nonisolated var unownedExecutor: UnownedSerialExecutor { -// print("get unowned executor") -// return MainActor.sharedUnownedExecutor -// } + nonisolated var unownedExecutor: UnownedSerialExecutor { + print("get unowned executor") + return MainActor.sharedUnownedExecutor + } distributed func test(x: Int) async throws { print("executed: \(#function)") @@ -43,6 +43,8 @@ distributed actor Worker { // CHECK: | assign id // CHECK: | actor ready + precondition(__isLocalActor(worker), "must be local") + try! await worker.test(x: 42) // CHECK: get unowned executor // CHECK: executed: test(x:) From 165eaf3b5e6cd04878af097661d74f2741e48a61 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 15 Mar 2023 00:20:06 +0900 Subject: [PATCH 04/11] NonDefaultDistributedActor to complete support and remote flag handling --- docs/ABI/Mangling.rst | 3 + include/swift/ABI/Actor.h | 16 +++++ include/swift/ABI/MetadataValues.h | 5 ++ include/swift/AST/Decl.h | 4 ++ include/swift/AST/TypeNodes.def | 2 + include/swift/AST/Types.h | 16 +++++ include/swift/Runtime/BuiltinTypes.def | 1 + include/swift/Strings.h | 6 ++ lib/AST/ASTDumper.cpp | 1 + lib/AST/ASTMangler.cpp | 2 + lib/AST/ASTPrinter.cpp | 1 + lib/AST/Builtins.cpp | 5 ++ lib/AST/Decl.cpp | 9 +++ lib/AST/Type.cpp | 2 + lib/Demangling/Demangler.cpp | 4 ++ lib/Demangling/Remangler.cpp | 2 + lib/IRGen/ClassMetadataVisitor.h | 4 ++ lib/IRGen/Field.h | 1 + lib/IRGen/GenClass.cpp | 23 +++++-- lib/IRGen/GenMeta.cpp | 6 ++ lib/IRGen/GenReflection.cpp | 3 + lib/IRGen/GenType.cpp | 14 +++++ lib/IRGen/IRGenDebugInfo.cpp | 1 + lib/IRGen/MetadataLayout.cpp | 7 +++ lib/IRGen/MetadataRequest.cpp | 1 + lib/IRGen/StructLayout.cpp | 49 +++++++++++++-- lib/IRGen/StructLayout.h | 6 +- lib/SIL/IR/TypeLowering.cpp | 11 ++++ lib/SILGen/SILGenConstructor.cpp | 6 +- lib/SILGen/SILGenDestructor.cpp | 1 - stdlib/public/Concurrency/Actor.cpp | 83 ++++++++++++++++++++----- stdlib/public/runtime/KnownMetadata.cpp | 7 +++ test/Runtime/demangleToMetadata.swift | 1 + 33 files changed, 276 insertions(+), 27 deletions(-) diff --git a/docs/ABI/Mangling.rst b/docs/ABI/Mangling.rst index 268cca8181e03..18b0e03e0149c 100644 --- a/docs/ABI/Mangling.rst +++ b/docs/ABI/Mangling.rst @@ -574,6 +574,9 @@ Types type ::= 'BD' // Builtin.DefaultActorStorage type ::= 'Be' // Builtin.Executor #endif + #if SWIFT_RUNTIME_VERSION >= 5.9 + type ::= 'Bd' // Builtin.NonDefaultDistributedActorStorage + #endif type ::= 'Bf' NATURAL '_' // Builtin.Float type ::= 'Bi' NATURAL '_' // Builtin.Int type ::= 'BI' // Builtin.IntLiteral diff --git a/include/swift/ABI/Actor.h b/include/swift/ABI/Actor.h index 3b17b7c381b5f..6c173bed09a4e 100644 --- a/include/swift/ABI/Actor.h +++ b/include/swift/ABI/Actor.h @@ -39,6 +39,22 @@ class alignas(Alignment_DefaultActor) DefaultActor : public HeapObject { void *PrivateData[NumWords_DefaultActor]; }; +/// The non-default distributed actor implementation. +class alignas(Alignment_NonDefaultDistributedActor) NonDefaultDistributedActor : public HeapObject { +public: + // These constructors do not initialize the actor instance, and the + // destructor does not destroy the actor instance; you must call + // swift_defaultActor_{initialize,destroy} yourself. + constexpr NonDefaultDistributedActor(const HeapMetadata *metadata) + : HeapObject(metadata), PrivateData{} {} + + constexpr NonDefaultDistributedActor(const HeapMetadata *metadata, + InlineRefCounts::Immortal_t immortal) + : HeapObject(metadata, immortal), PrivateData{} {} + + void *PrivateData[NumWords_NonDefaultDistributedActor]; +}; + } // end namespace swift #endif diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h index 552b2232abd7c..ace93d8b4f9fe 100644 --- a/include/swift/ABI/MetadataValues.h +++ b/include/swift/ABI/MetadataValues.h @@ -49,6 +49,10 @@ enum { /// in a default actor. NumWords_DefaultActor = 12, + /// The number of words (in addition to the heap-object header) + /// in a non-default distributed actor. + NumWords_NonDefaultDistributedActor = 12, + /// The number of words in a task. NumWords_AsyncTask = 24, @@ -138,6 +142,7 @@ const size_t MaximumAlignment = 16; /// The alignment of a DefaultActor. const size_t Alignment_DefaultActor = MaximumAlignment; +const size_t Alignment_NonDefaultDistributedActor = MaximumAlignment; /// The alignment of a TaskGroup. const size_t Alignment_TaskGroup = MaximumAlignment; diff --git a/include/swift/AST/Decl.h b/include/swift/AST/Decl.h index 899f965587304..7350ecc8ad80f 100644 --- a/include/swift/AST/Decl.h +++ b/include/swift/AST/Decl.h @@ -4499,6 +4499,10 @@ class ClassDecl final : public NominalTypeDecl { bool isRootDefaultActor() const; bool isRootDefaultActor(ModuleDecl *M, ResilienceExpansion expansion) const; + /// It is a `distributed actor` with a custom executor. + bool isNonDefaultExplicitDistributedActor() const; + bool isNonDefaultExplicitDistributedActor(ModuleDecl *M, ResilienceExpansion expansion) const; + /// Whether the class was explicitly declared with the `actor` keyword. bool isExplicitActor() const { return Bits.ClassDecl.IsActor; } diff --git a/include/swift/AST/TypeNodes.def b/include/swift/AST/TypeNodes.def index 22beab323a209..8389cb8945523 100644 --- a/include/swift/AST/TypeNodes.def +++ b/include/swift/AST/TypeNodes.def @@ -124,6 +124,7 @@ ABSTRACT_TYPE(Builtin, Type) BUILTIN_TYPE(BuiltinBridgeObject, BuiltinType) BUILTIN_TYPE(BuiltinUnsafeValueBuffer, BuiltinType) BUILTIN_TYPE(BuiltinDefaultActorStorage, BuiltinType) + BUILTIN_TYPE(BuiltinNonDefaultDistributedActorStorage, BuiltinType) BUILTIN_TYPE(BuiltinVector, BuiltinType) TYPE_RANGE(Builtin, BuiltinInteger, BuiltinVector) TYPE(Tuple, Type) @@ -213,6 +214,7 @@ SINGLETON_TYPE(NativeObject, BuiltinNativeObject) SINGLETON_TYPE(BridgeObject, BuiltinBridgeObject) SINGLETON_TYPE(UnsafeValueBuffer, BuiltinUnsafeValueBuffer) SINGLETON_TYPE(DefaultActorStorage, BuiltinDefaultActorStorage) +SINGLETON_TYPE(NonDefaultDistributedActorStorage, BuiltinNonDefaultDistributedActorStorage) SINGLETON_TYPE(SILToken, SILToken) #undef SINGLETON_TYPE #endif diff --git a/include/swift/AST/Types.h b/include/swift/AST/Types.h index 86669f698dc2b..fc831d776457d 100644 --- a/include/swift/AST/Types.h +++ b/include/swift/AST/Types.h @@ -1620,6 +1620,22 @@ class BuiltinDefaultActorStorageType : public BuiltinType { }; DEFINE_EMPTY_CAN_TYPE_WRAPPER(BuiltinDefaultActorStorageType, BuiltinType) +/// BuiltinNonDefaultDistributedActorStorageType - The type of the stored property +/// that's added implicitly to distributed actors. No C equivalent because +/// the C types all include a heap-object header. Similarly, this type +/// generally does not appear in the AST/SIL around default actors; +/// it's purely a convenience in IRGen. +class BuiltinNonDefaultDistributedActorStorageType : public BuiltinType { + friend class ASTContext; + BuiltinNonDefaultDistributedActorStorageType(const ASTContext &C) + : BuiltinType(TypeKind::BuiltinNonDefaultDistributedActorStorage, C) {} +public: + static bool classof(const TypeBase *T) { + return T->getKind() == TypeKind::BuiltinNonDefaultDistributedActorStorage; + } +}; +DEFINE_EMPTY_CAN_TYPE_WRAPPER(BuiltinNonDefaultDistributedActorStorageType, BuiltinType) + /// BuiltinPackIndexType - The type of an (untyped) index into a pack /// in SIL. Essentially a UInt32 with some structural restrictions /// about how it can be produced that ensures SIL maintains well-typed diff --git a/include/swift/Runtime/BuiltinTypes.def b/include/swift/Runtime/BuiltinTypes.def index 21875d7e5d5a9..b17347745ddd2 100644 --- a/include/swift/Runtime/BuiltinTypes.def +++ b/include/swift/Runtime/BuiltinTypes.def @@ -62,6 +62,7 @@ BUILTIN_POINTER_TYPE(BO, "Builtin.UnknownObject") BUILTIN_POINTER_TYPE(Bc, "Builtin.RawUnsafeContinuation") BUILTIN_TYPE(BD, "Builtin.DefaultActorStorage") +BUILTIN_TYPE(Bd, "Builtin.NonDefaultDistributedActorStorage") BUILTIN_TYPE(Be, "Builtin.Executor") BUILTIN_POINTER_TYPE(Bj, "Builtin.Job") diff --git a/include/swift/Strings.h b/include/swift/Strings.h index ddb8d4fb15796..c1a80dadace67 100644 --- a/include/swift/Strings.h +++ b/include/swift/Strings.h @@ -63,6 +63,9 @@ constexpr static const StringLiteral SEMANTICS_DEFAULT_ACTOR = constexpr static const StringLiteral DEFAULT_ACTOR_STORAGE_FIELD_NAME = "$defaultActor"; +constexpr static const StringLiteral NON_DEFAULT_DISTRIBUTED_ACTOR_STORAGE_FIELD_NAME = + "$nonDefaultDistributedActor"; + /// The name of the Builtin type prefix constexpr static const StringLiteral BUILTIN_TYPE_NAME_PREFIX = "Builtin."; @@ -149,6 +152,9 @@ constexpr static BuiltinNameStringLiteral BUILTIN_TYPE_NAME_EXECUTOR = { /// The name of the Builtin type for DefaultActorStorage constexpr static BuiltinNameStringLiteral BUILTIN_TYPE_NAME_DEFAULTACTORSTORAGE = { "Builtin.DefaultActorStorage"}; +/// The name of the Builtin type for NonDefaultDistributedActorStorage +constexpr static BuiltinNameStringLiteral BUILTIN_TYPE_NAME_NONDEFAULTDISTRIBUTEDACTORSTORAGE = { + "Builtin.NonDefaultDistributedActorStorage"}; /// The name of the Builtin type for UnknownObject /// /// This no longer exists as an AST-accessible type, but it's still used for diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index 14d70ba5c24cc..faf143d67be9a 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -3803,6 +3803,7 @@ namespace { TRIVIAL_TYPE_PRINTER(BuiltinJob, builtin_job) TRIVIAL_TYPE_PRINTER(BuiltinExecutor, builtin_executor_ref) TRIVIAL_TYPE_PRINTER(BuiltinDefaultActorStorage, builtin_default_actor_storage) + TRIVIAL_TYPE_PRINTER(BuiltinNonDefaultDistributedActorStorage, builtin_non_default_distributed_actor_storage) TRIVIAL_TYPE_PRINTER(BuiltinPackIndex, builtin_pack_index) TRIVIAL_TYPE_PRINTER(BuiltinRawPointer, builtin_raw_pointer) TRIVIAL_TYPE_PRINTER(BuiltinRawUnsafeContinuation, builtin_raw_unsafe_continuation) diff --git a/lib/AST/ASTMangler.cpp b/lib/AST/ASTMangler.cpp index 3ce20006c45fb..f604d807d883b 100644 --- a/lib/AST/ASTMangler.cpp +++ b/lib/AST/ASTMangler.cpp @@ -1210,6 +1210,8 @@ void ASTMangler::appendType(Type type, GenericSignature sig, return appendOperator("Be"); case TypeKind::BuiltinDefaultActorStorage: return appendOperator("BD"); + case TypeKind::BuiltinNonDefaultDistributedActorStorage: + return appendOperator("Bd"); case TypeKind::BuiltinPackIndex: return appendOperator("BP"); case TypeKind::BuiltinRawPointer: diff --git a/lib/AST/ASTPrinter.cpp b/lib/AST/ASTPrinter.cpp index 4f6e392d722ac..f1bc3efd0fa91 100644 --- a/lib/AST/ASTPrinter.cpp +++ b/lib/AST/ASTPrinter.cpp @@ -5856,6 +5856,7 @@ class TypePrinter : public TypeVisitor { ASTPRINTER_PRINT_BUILTINTYPE(BuiltinJobType) ASTPRINTER_PRINT_BUILTINTYPE(BuiltinExecutorType) ASTPRINTER_PRINT_BUILTINTYPE(BuiltinDefaultActorStorageType) + ASTPRINTER_PRINT_BUILTINTYPE(BuiltinNonDefaultDistributedActorStorageType) ASTPRINTER_PRINT_BUILTINTYPE(BuiltinPackIndexType) ASTPRINTER_PRINT_BUILTINTYPE(BuiltinNativeObjectType) ASTPRINTER_PRINT_BUILTINTYPE(BuiltinBridgeObjectType) diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index 22a95ce11072e..d55c9dc3602c2 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -85,6 +85,8 @@ Type swift::getBuiltinType(ASTContext &Context, StringRef Name) { return Context.TheJobType; if (Name == "DefaultActorStorage") return Context.TheDefaultActorStorageType; + if (Name == "NonDefaultDistributedActorStorage") + return Context.TheNonDefaultDistributedActorStorageType; if (Name == "Executor") return Context.TheExecutorType; if (Name == "NativeObject") @@ -3022,6 +3024,9 @@ StringRef BuiltinType::getTypeName(SmallVectorImpl &result, case BuiltinTypeKind::BuiltinDefaultActorStorage: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_DEFAULTACTORSTORAGE); break; + case BuiltinTypeKind::BuiltinNonDefaultDistributedActorStorage: + printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_NONDEFAULTDISTRIBUTEDACTORSTORAGE); + break; case BuiltinTypeKind::BuiltinPackIndex: printer << MAYBE_GET_NAMESPACED_BUILTIN(BUILTIN_TYPE_NAME_PACKINDEX); break; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 384c0450b1034..1cde7f868d815 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -9598,6 +9598,15 @@ bool ClassDecl::isRootDefaultActor(ModuleDecl *M, return (!superclass || superclass->isNSObject()); } +bool ClassDecl::isNonDefaultExplicitDistributedActor() const { + return isRootDefaultActor(getModuleContext(), ResilienceExpansion::Maximal); +} +bool ClassDecl::isNonDefaultExplicitDistributedActor(ModuleDecl *M, + ResilienceExpansion expansion) const { + return !isDefaultActor(M, expansion) && isExplicitDistributedActor(); +} + + bool ClassDecl::isNativeNSObjectSubclass() const { // @objc actors implicitly inherit from NSObject. if (isActor()) { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 94d9965fb68b7..e68f946bad76d 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -250,6 +250,7 @@ bool CanType::isReferenceTypeImpl(CanType type, const GenericSignatureImpl *sig, case TypeKind::BuiltinJob: case TypeKind::BuiltinExecutor: case TypeKind::BuiltinDefaultActorStorage: + case TypeKind::BuiltinNonDefaultDistributedActorStorage: case TypeKind::BuiltinPackIndex: case TypeKind::BuiltinUnsafeValueBuffer: case TypeKind::BuiltinVector: @@ -6187,6 +6188,7 @@ ReferenceCounting TypeBase::getReferenceCounting() { case TypeKind::BuiltinJob: case TypeKind::BuiltinExecutor: case TypeKind::BuiltinDefaultActorStorage: + case TypeKind::BuiltinNonDefaultDistributedActorStorage: case TypeKind::BuiltinPackIndex: case TypeKind::BuiltinUnsafeValueBuffer: case TypeKind::BuiltinVector: diff --git a/lib/Demangling/Demangler.cpp b/lib/Demangling/Demangler.cpp index f7494d28c0b30..d9b881e06803d 100644 --- a/lib/Demangling/Demangler.cpp +++ b/lib/Demangling/Demangler.cpp @@ -1298,6 +1298,10 @@ NodePointer Demangler::demangleBuiltinType() { Ty = createNode(Node::Kind::BuiltinTypeName, BUILTIN_TYPE_NAME_DEFAULTACTORSTORAGE); break; + case 'd': + Ty = createNode(Node::Kind::BuiltinTypeName, + BUILTIN_TYPE_NAME_NONDEFAULTDISTRIBUTEDACTORSTORAGE); + break; case 'c': Ty = createNode(Node::Kind::BuiltinTypeName, BUILTIN_TYPE_NAME_RAWUNSAFECONTINUATION); diff --git a/lib/Demangling/Remangler.cpp b/lib/Demangling/Remangler.cpp index 96796839d3db5..be3000115f7db 100644 --- a/lib/Demangling/Remangler.cpp +++ b/lib/Demangling/Remangler.cpp @@ -857,6 +857,8 @@ ManglingError Remangler::mangleBuiltinTypeName(Node *node, unsigned depth) { Buffer << 'j'; } else if (text == BUILTIN_TYPE_NAME_DEFAULTACTORSTORAGE) { Buffer << 'D'; + } else if (text == BUILTIN_TYPE_NAME_NONDEFAULTDISTRIBUTEDACTORSTORAGE) { + Buffer << 'd'; } else if (text == BUILTIN_TYPE_NAME_EXECUTOR) { Buffer << 'e'; } else if (text == BUILTIN_TYPE_NAME_SILTOKEN) { diff --git a/lib/IRGen/ClassMetadataVisitor.h b/lib/IRGen/ClassMetadataVisitor.h index 10126d52baaf2..948c44ac2fe8e 100644 --- a/lib/IRGen/ClassMetadataVisitor.h +++ b/lib/IRGen/ClassMetadataVisitor.h @@ -207,6 +207,9 @@ template class ClassMetadataVisitor case Field::DefaultActorStorage: asImpl().addDefaultActorStorageFieldOffset(); return; + case Field::NonDefaultDistributedActorStorage: + asImpl().addNonDefaultDistributedActorStorageFieldOffset(); + return; } } }; @@ -245,6 +248,7 @@ class ClassMetadataScanner : public ClassMetadataVisitor { } void addMethodOverride(SILDeclRef baseRef, SILDeclRef declRef) {} void addDefaultActorStorageFieldOffset() { addPointer(); } + void addNonDefaultDistributedActorStorageFieldOffset() { addPointer(); } void addFieldOffset(VarDecl *var) { addPointer(); } void addFieldOffsetPlaceholders(MissingMemberDecl *mmd) { for (unsigned i = 0, e = mmd->getNumberOfFieldOffsetVectorEntries(); diff --git a/lib/IRGen/Field.h b/lib/IRGen/Field.h index f2f6f5eea8d31..0b6eba19a2a53 100644 --- a/lib/IRGen/Field.h +++ b/lib/IRGen/Field.h @@ -45,6 +45,7 @@ struct Field { Var, MissingMember, DefaultActorStorage, + NonDefaultDistributedActorStorage, FirstArtificial = DefaultActorStorage }; enum : uintptr_t { KindMask = 0x3 }; diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index fd1f08724b317..81f4042d81a92 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -388,8 +388,12 @@ namespace { }; auto classDecl = dyn_cast(theClass); - if (classDecl && classDecl->isRootDefaultActor()) { - fn(Field::DefaultActorStorage); + if (classDecl) { + if (classDecl->isRootDefaultActor()) { + fn(Field::DefaultActorStorage); + } else if (classDecl->isNonDefaultExplicitDistributedActor()) { + fn(Field::NonDefaultDistributedActorStorage); + } } for (auto decl : @@ -1090,7 +1094,7 @@ namespace { TaggedUnion TheEntity; ExtensionDecl *TheExtension; const ClassLayout *FieldLayout; - + ClassDecl *getClass() const { const ClassUnion *classUnion; if (!(classUnion = TheEntity.dyn_cast())) { @@ -1194,7 +1198,7 @@ namespace { SmallVector Protocols; SmallVector InstanceProperties; SmallVector ClassProperties; - + llvm::Constant *Name = nullptr; SmallVectorImpl &getMethodList(ValueDecl *decl) { @@ -1226,8 +1230,11 @@ namespace { FieldLayout(&fieldLayout) { visitConformances(getClass()->getImplementationContext()); - if (getClass()->isRootDefaultActor()) + if (getClass()->isRootDefaultActor()) { Ivars.push_back(Field::DefaultActorStorage); + } else if (getClass()->isNonDefaultExplicitDistributedActor()) { + Ivars.push_back(Field::NonDefaultDistributedActorStorage); + } visitImplementationMembers(getClass()); if (Lowering::usesObjCAllocator(getClass())) { @@ -2020,6 +2027,9 @@ namespace { if (field.getKind() == Field::DefaultActorStorage) { offsetPtr = nullptr; break; + } else if (field.getKind() == Field::NonDefaultDistributedActorStorage) { + offsetPtr = nullptr; + break; } // Otherwise, we should have a normal stored property. @@ -2436,6 +2446,9 @@ namespace { case Field::Kind::DefaultActorStorage: os << "default_actor_storage"; break; + case Field::Kind::NonDefaultDistributedActorStorage: + os << "non_default_distributed_actor_storage"; + break; } os << ")"; } diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 7855efc3bc2d8..4848b17cbb4ab 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -3464,6 +3464,8 @@ static void emitFieldOffsetGlobals(IRGenModule &IGM, // storage, which is never accessed directly. case Field::DefaultActorStorage: return; + case Field::NonDefaultDistributedActorStorage: + return; } auto prop = field.getVarDecl(); @@ -3919,6 +3921,10 @@ namespace { B.addInt(IGM.SizeTy, getDefaultActorStorageFieldOffset(IGM).getValue()); } + void addNonDefaultDistributedActorStorageFieldOffset() { + B.addInt(IGM.SizeTy, getNonDefaultDistributedActorStorageFieldOffset(IGM).getValue()); + } + void addReifiedVTableEntry(SILDeclRef fn) { // Find the vtable entry. assert(VTable && "no vtable?!"); diff --git a/lib/IRGen/GenReflection.cpp b/lib/IRGen/GenReflection.cpp index be0aa71d7e627..25a268376eb5d 100644 --- a/lib/IRGen/GenReflection.cpp +++ b/lib/IRGen/GenReflection.cpp @@ -822,6 +822,9 @@ class FieldTypeMetadataBuilder : public ReflectionMetadataBuilder { case Field::DefaultActorStorage: flags.setIsArtificial(); break; + case Field::NonDefaultDistributedActorStorage: + flags.setIsArtificial(); + break; } flags.setIsVar(!isLet); diff --git a/lib/IRGen/GenType.cpp b/lib/IRGen/GenType.cpp index a4c7f9b945595..db9d31c5d0c70 100644 --- a/lib/IRGen/GenType.cpp +++ b/lib/IRGen/GenType.cpp @@ -2290,6 +2290,20 @@ const TypeInfo *TypeConverter::convertType(CanType ty) { auto spareBits = SpareBitVector::getConstant(size.getValueInBits(), false); return new PrimitiveTypeInfo(ty, size, std::move(spareBits), align); } + case TypeKind::BuiltinNonDefaultDistributedActorStorage: { + // Builtin.NonDefaultDistributedActorStorage represents the extra storage + // (beyond the heap header) of a distributed actor that is not a default actor. + // It is fixed-size and totally opaque. + auto numWords = NumWords_NonDefaultDistributedActor; + + auto ty = llvm::StructType::create(IGM.getLLVMContext(), + llvm::ArrayType::get(IGM.Int8PtrTy, numWords), + "swift.nondefaultdistributedactor"); + auto size = IGM.getPointerSize() * numWords; + auto align = Alignment(2 * IGM.getPointerAlignment().getValue()); + auto spareBits = SpareBitVector::getConstant(size.getValueInBits(), false); + return new PrimitiveTypeInfo(ty, size, std::move(spareBits), align); + } case TypeKind::PrimaryArchetype: case TypeKind::OpenedArchetype: diff --git a/lib/IRGen/IRGenDebugInfo.cpp b/lib/IRGen/IRGenDebugInfo.cpp index 06e0f7b119e7f..a68b3ac98cd92 100644 --- a/lib/IRGen/IRGenDebugInfo.cpp +++ b/lib/IRGen/IRGenDebugInfo.cpp @@ -1741,6 +1741,7 @@ class IRGenDebugInfoImpl : public IRGenDebugInfo { case TypeKind::SILToken: case TypeKind::BuiltinUnsafeValueBuffer: case TypeKind::BuiltinDefaultActorStorage: + case TypeKind::BuiltinNonDefaultDistributedActorStorage: case TypeKind::SILMoveOnlyWrapped: LLVM_DEBUG(llvm::dbgs() << "Unhandled type: "; DbgTy.getType()->dump(llvm::dbgs()); llvm::dbgs() << "\n"); diff --git a/lib/IRGen/MetadataLayout.cpp b/lib/IRGen/MetadataLayout.cpp index f7d8dab8fc2ca..221f794e172de 100644 --- a/lib/IRGen/MetadataLayout.cpp +++ b/lib/IRGen/MetadataLayout.cpp @@ -415,6 +415,13 @@ ClassMetadataLayout::ClassMetadataLayout(IRGenModule &IGM, ClassDecl *decl) super::addDefaultActorStorageFieldOffset(); } + void addNonDefaultDistributedActorStorageFieldOffset() { + if (IsInTargetFields) { + ++Layout.NumImmediateMembers; + } + super::addNonDefaultDistributedActorStorageFieldOffset(); + } + void addFieldOffsetPlaceholders(MissingMemberDecl *placeholder) { if (placeholder->getDeclContext()->getImplementedObjCContext() == Target) { Layout.NumImmediateMembers += diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index 44268026d2d28..b8179a1c9957f 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -1996,6 +1996,7 @@ namespace { } INTERNAL_ONLY_TYPE(SILBlockStorage) INTERNAL_ONLY_TYPE(BuiltinDefaultActorStorage) + INTERNAL_ONLY_TYPE(BuiltinNonDefaultDistributedActorStorage) #undef INTERNAL_ONLY_TYPE MetadataResponse visitSILBoxType(CanSILBoxType type, diff --git a/lib/IRGen/StructLayout.cpp b/lib/IRGen/StructLayout.cpp index fafb5bb7015f0..d832124ed9d31 100644 --- a/lib/IRGen/StructLayout.cpp +++ b/lib/IRGen/StructLayout.cpp @@ -208,7 +208,7 @@ void StructLayoutBuilder::addNSObjectHeader() { headerSize = CurSize; } -void StructLayoutBuilder::addDefaultActorHeader(ElementLayout &elt) { +void StructLayoutBuilder::addDefaultActorHeader(ElementLayout &elt) { // FIXME: !!!! make sure we call this equivalent for distributed assert(StructFields.size() == 1 && StructFields[0] == IGM.RefCountedStructTy && "adding default actor header at wrong offset"); @@ -231,10 +231,37 @@ void StructLayoutBuilder::addDefaultActorHeader(ElementLayout &elt) { headerSize = CurSize; } +void StructLayoutBuilder::addNonDefaultDistributedActorHeader(ElementLayout &elt) { + assert(StructFields.size() == 1 && + StructFields[0] == IGM.RefCountedStructTy && + "adding default actor header at wrong offset"); + + // These must match the NonDefaultDistributedActor class in Actor.h. // FIXME: !!!! make such class + auto size = NumWords_NonDefaultDistributedActor * IGM.getPointerSize(); + auto align = Alignment(Alignment_NonDefaultDistributedActor); + auto ty = llvm::ArrayType::get(IGM.Int8PtrTy, NumWords_NonDefaultDistributedActor); + + // Note that we align the *entire structure* to the new alignment, + // not the storage we're adding. Otherwise we would potentially + // get internal padding. + assert(CurSize.isMultipleOf(IGM.getPointerSize())); + assert(align >= CurAlignment); + assert(CurSize == getNonDefaultDistributedActorStorageFieldOffset(IGM)); + elt.completeFixed(IsNotTriviallyDestroyable, CurSize, /*struct index*/ 1); + CurSize += size; + CurAlignment = align; + StructFields.push_back(ty); + headerSize = CurSize; +} + Size irgen::getDefaultActorStorageFieldOffset(IRGenModule &IGM) { return IGM.RefCountedStructSize; } +Size irgen::getNonDefaultDistributedActorStorageFieldOffset(IRGenModule &IGM) { + return IGM.RefCountedStructSize; +} + bool StructLayoutBuilder::addFields(llvm::MutableArrayRef elts, LayoutStrategy strategy) { // Track whether we've added any storage to our layout. @@ -417,8 +444,11 @@ unsigned irgen::getNumFields(const NominalTypeDecl *target) { auto numFields = target->getStoredPropertiesAndMissingMemberPlaceholders().size(); if (auto cls = dyn_cast(target)) { - if (cls->isRootDefaultActor()) + if (cls->isRootDefaultActor()) { + numFields++; + } else if (cls->isRootDefaultActor()) { numFields++; + } } return numFields; } @@ -426,8 +456,12 @@ unsigned irgen::getNumFields(const NominalTypeDecl *target) { void irgen::forEachField(IRGenModule &IGM, const NominalTypeDecl *typeDecl, llvm::function_ref fn) { auto classDecl = dyn_cast(typeDecl); - if (classDecl && classDecl->isRootDefaultActor()) { - fn(Field::DefaultActorStorage); + if (classDecl) { + if (classDecl->isRootDefaultActor()) { + fn(Field::DefaultActorStorage); + } else if (classDecl->isNonDefaultExplicitDistributedActor()) { + fn(Field::NonDefaultDistributedActorStorage); + } } for (auto decl : @@ -450,6 +484,9 @@ SILType Field::getType(IRGenModule &IGM, SILType baseType) const { case Field::DefaultActorStorage: return SILType::getPrimitiveObjectType( IGM.Context.TheDefaultActorStorageType); + case Field::NonDefaultDistributedActorStorage: + return SILType::getPrimitiveObjectType( + IGM.Context.TheNonDefaultDistributedActorStorageType); } llvm_unreachable("bad field kind"); } @@ -462,6 +499,8 @@ Type Field::getInterfaceType(IRGenModule &IGM) const { llvm_unreachable("cannot ask for type of missing member"); case Field::DefaultActorStorage: return IGM.Context.TheDefaultActorStorageType; + case Field::NonDefaultDistributedActorStorage: + return IGM.Context.TheNonDefaultDistributedActorStorageType; } llvm_unreachable("bad field kind"); } @@ -474,6 +513,8 @@ StringRef Field::getName() const { llvm_unreachable("cannot ask for type of missing member"); case Field::DefaultActorStorage: return DEFAULT_ACTOR_STORAGE_FIELD_NAME; + case Field::NonDefaultDistributedActorStorage: + return NON_DEFAULT_DISTRIBUTED_ACTOR_STORAGE_FIELD_NAME; } llvm_unreachable("bad field kind"); } diff --git a/lib/IRGen/StructLayout.h b/lib/IRGen/StructLayout.h index 218529404c447..f3fcdaf6dcce3 100644 --- a/lib/IRGen/StructLayout.h +++ b/lib/IRGen/StructLayout.h @@ -299,7 +299,10 @@ class StructLayoutBuilder { /// Add the default-actor header to the layout. This must be the second /// thing added to the layout, following the Swift heap header. void addDefaultActorHeader(ElementLayout &elt); - + /// Add the non-default distributed actor header to the layout. + /// This must be the second thing added to the layout, following the Swift heap header. + void addNonDefaultDistributedActorHeader(ElementLayout &elt); + /// Add a number of fields to the layout. The field layouts need /// only have the TypeInfo set; the rest will be filled out. /// @@ -473,6 +476,7 @@ class StructLayout { }; Size getDefaultActorStorageFieldOffset(IRGenModule &IGM); +Size getNonDefaultDistributedActorStorageFieldOffset(IRGenModule &IGM); } // end namespace irgen } // end namespace swift diff --git a/lib/SIL/IR/TypeLowering.cpp b/lib/SIL/IR/TypeLowering.cpp index b18c1b72f82ee..8d20fec031fb3 100644 --- a/lib/SIL/IR/TypeLowering.cpp +++ b/lib/SIL/IR/TypeLowering.cpp @@ -370,6 +370,17 @@ namespace { IsLexical}); } + RetTy visitBuiltinNonDefaultDistributedActorStorageType( + CanBuiltinNonDefaultDistributedActorStorageType type, + AbstractionPattern origType, + IsTypeExpansionSensitive_t isSensitive) { + return asImpl().handleAddressOnly(type, {IsNotTrivial, IsFixedABI, + IsAddressOnly, IsNotResilient, + isSensitive, + DoesNotHaveRawPointer, + IsLexical}); + } + RetTy visitAnyFunctionType(CanAnyFunctionType type, AbstractionPattern origType, IsTypeExpansionSensitive_t isSensitive) { diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index 4fc286b0265dc..776ba7ca51542 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -831,11 +831,15 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) { B.createDebugValue(PrologueLoc, selfArg.getValue(), DbgVar); } - // Initialize the default-actor instance. if (selfClassDecl->isRootDefaultActor() && !isDelegating) { + // Initialize the default-actor instance. SILLocation PrologueLoc(selfDecl); PrologueLoc.markAsPrologue(); emitDefaultActorInitialization(*this, PrologueLoc, selfArg); + } else if (selfClassDecl->isNonDefaultExplicitDistributedActor() && !isDelegating) { + // Initialize the distributed local actor with custom executor, + // with additional storage such that we can store the local/remote bit + assert(false && "FIXME not implemented initializing the local one"); // FIXME: !!!! } if (!ctor->hasStubImplementation()) { diff --git a/lib/SILGen/SILGenDestructor.cpp b/lib/SILGen/SILGenDestructor.cpp index 32f55734cfde4..61735e36d7741 100644 --- a/lib/SILGen/SILGenDestructor.cpp +++ b/lib/SILGen/SILGenDestructor.cpp @@ -476,7 +476,6 @@ void SILGenFunction::emitClassMemberDestruction(ManagedValue selfValue, B.emitBlock(finishBB); if (cd->isRootDefaultActor()) { - // TODO(distributed): we may need to call the distributed destroy here instead? auto builtinName = getASTContext().getIdentifier( getBuiltinName(BuiltinValueKind::DestroyDefaultActor)); auto resultTy = SGM.Types.getEmptyTupleType(); diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index 2f6d0df308c71..774de81ca649a 100644 --- a/stdlib/public/Concurrency/Actor.cpp +++ b/stdlib/public/Concurrency/Actor.cpp @@ -936,6 +936,40 @@ class DefaultActorImpl : public HeapObject { void deallocateUnconditional(); }; +class NonDefaultDistributedActorImpl : public HeapObject { + // TODO (rokhinip): Make this a flagset + bool isDistributedRemoteActor; + +public: + /// Properly construct an actor, except for the heap header. + void initialize(bool isDistributedRemote = false) { + fprintf(stderr, "[%s:%d](%s) initialize NonDefaultDistributedActorImpl; remote = %d\n", __FILE_NAME__, __LINE__, __FUNCTION__, isDistributedRemote); + this->isDistributedRemoteActor = isDistributedRemote; + SWIFT_TASK_DEBUG_LOG("Creating non-default distributed actor %p", this); + // concurrency::trace::actor_create(this); // FIXME: !!!! + } + + /// Properly destruct an actor, except for the heap header. + void destroy() { + // empty + } + + /// Properly respond to the last release of a default actor. Note + /// that the actor will have been completely torn down by the time + /// we reach this point. + void deallocate() { + // empty + } + + /// Check if the actor is actually a distributed *remote* actor. + /// + /// Note that a distributed *local* actor instance is the same as any other + /// ordinary default (local) actor, and no special handling is needed for them. + bool isDistributedRemote() { + return isDistributedRemoteActor; + } +}; + } /// end anonymous namespace // We can't use sizeof(DefaultActor) since the alignment requirement on the @@ -950,6 +984,12 @@ static_assert(DefaultActorImpl::offsetOfActiveActorStatus() % ACTIVE_ACTOR_STATU "ActiveActorStatus is aligned to the right size"); #endif +static_assert(sizeof(DefaultActor) == sizeof(NonDefaultDistributedActor), + "NonDefaultDistributedActor size should be the same as DefaultActor"); +static_assert(sizeof(NonDefaultDistributedActorImpl) <= ((sizeof(void *) * NumWords_NonDefaultDistributedActor) + sizeof(HeapObject)) && + alignof(NonDefaultDistributedActorImpl) <= alignof(NonDefaultDistributedActor), + "NonDefaultDistributedActorImpl doesn't fit in NonDefaultDistributedActor"); + static DefaultActorImpl *asImpl(DefaultActor *actor) { return reinterpret_cast(actor); } @@ -958,6 +998,13 @@ static DefaultActor *asAbstract(DefaultActorImpl *actor) { return reinterpret_cast(actor); } +static NonDefaultDistributedActorImpl *asImpl(NonDefaultDistributedActor *actor) { + return reinterpret_cast(actor); +} +static NonDefaultDistributedActor *asAbstract(NonDefaultDistributedActorImpl *actor) { + return reinterpret_cast(actor); +} + /*****************************************************************************/ /******************** NEW DEFAULT ACTOR IMPLEMENTATION ***********************/ /*****************************************************************************/ @@ -1949,40 +1996,46 @@ void swift::swift_executor_escalate(ExecutorRef executor, AsyncTask *task, OpaqueValue* swift::swift_distributedActor_remote_initialize(const Metadata *actorType) { - auto *classMetadata = actorType->getClassObject(); + auto *metadata = actorType->getClassObject(); // TODO(distributed): make this allocation smaller // ==== Allocate the memory for the remote instance - HeapObject *alloc = swift_allocObject(classMetadata, - classMetadata->getInstanceSize(), - classMetadata->getInstanceAlignMask()); + HeapObject *alloc = swift_allocObject(metadata, + metadata->getInstanceSize(), + metadata->getInstanceAlignMask()); // TODO: remove this memset eventually, today we only do this to not have // to modify the destructor logic, as releasing zeroes is no-op - memset(alloc + 1, 0, classMetadata->getInstanceSize() - sizeof(HeapObject)); + memset(alloc + 1, 0, metadata->getInstanceSize() - sizeof(HeapObject)); // TODO(distributed): a remote one does not have to have the "real" // default actor body, e.g. we don't need an executor at all; so // we can allocate more efficiently and only share the flags/status field // between the both memory representations - // --- Currently we ride on the DefaultActorImpl to reuse the memory layout - // of the flags etc. So initialize the default actor into the allocation. - auto actor = asImpl(reinterpret_cast(alloc)); - actor->initialize(/*remote*/true); - assert(actor->isDistributedRemote()); + // If it is a default actor, we reuse the same layout as DefaultActorImpl, + // and store flags in the allocation directly as we initialize it. + if (isDefaultActorClass(metadata)) { + fprintf(stderr, "[%s:%d](%s) IS DEFAULT\n", __FILE_NAME__, __LINE__, __FUNCTION__); + auto actor = asImpl(reinterpret_cast(alloc)); + actor->initialize(/*remote*/true); + return reinterpret_cast(actor); + } else { + fprintf(stderr, "[%s:%d](%s) initialize NOT DEFAULT [REMOTE] DISTRIBUTED ACTOR\n", __FILE_NAME__, __LINE__, __FUNCTION__); + auto actor = asImpl(reinterpret_cast(alloc)); + actor->initialize(/*remote*/true); + } + assert(swift_distributed_actor_is_remote(alloc)); - return reinterpret_cast(actor); } bool swift::swift_distributed_actor_is_remote(HeapObject *_actor) { - fprintf(stderr, "[%s:%d](%s) IS IT REMOTE?\n", __FILE_NAME__, __LINE__, __FUNCTION__); + fprintf(stderr, "[%s:%d](%s) CHECK: swift_distributed_actor_is_remote\n", __FILE_NAME__, __LINE__, __FUNCTION__); auto metadata = cast(_actor->metadata); if (isDefaultActorClass(metadata)) { - fprintf(stderr, "[%s:%d](%s) the distributed actor is DEFAULT\n", __FILE_NAME__, __LINE__, __FUNCTION__); return asImpl((DefaultActor *) _actor)->isDistributedRemote(); } else { - fprintf(stderr, "[%s:%d](%s) the distributed actor is CUSTOM\n", __FILE_NAME__, __LINE__, __FUNCTION__); - return false; // TODO: just a placeholder to verify logic on Linux + fprintf(stderr, "[%s:%d](%s) NEW PATH swift_distributed_actor_is_remote\n", __FILE_NAME__, __LINE__, __FUNCTION__); + return asImpl((NonDefaultDistributedActor *) _actor)->isDistributedRemote(); // NEW } } diff --git a/stdlib/public/runtime/KnownMetadata.cpp b/stdlib/public/runtime/KnownMetadata.cpp index fe41a28be8377..a73ab000d0abd 100644 --- a/stdlib/public/runtime/KnownMetadata.cpp +++ b/stdlib/public/runtime/KnownMetadata.cpp @@ -98,6 +98,13 @@ namespace ctypes { HeapObject *Identity; uintptr_t Implementation; }; + + // Types that are defined in the Distributed library + + // Non-default distributed actor storage type. + struct alignas(2 * alignof(void*)) Bd { + void *storage[NumWords_NonDefaultDistributedActor]; + }; } } diff --git a/test/Runtime/demangleToMetadata.swift b/test/Runtime/demangleToMetadata.swift index 5143f9a330c7b..085672a6917ff 100644 --- a/test/Runtime/demangleToMetadata.swift +++ b/test/Runtime/demangleToMetadata.swift @@ -275,6 +275,7 @@ DemangleToMetadataTests.test("demangle built-in types") { expectEqual(Builtin.RawUnsafeContinuation.self, _typeByName("Bc")!) expectEqual(Builtin.Executor.self, _typeByName("Be")!) expectNotNil(_typeByName("BD")) + // FIXME: !!!! test for Bd expectEqual(Builtin.Job.self, _typeByName("Bj")!) } From 9b49b4a1ecc1fe69d17d7bbf71c37ae3407d00d1 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 15 Mar 2023 09:07:34 +0900 Subject: [PATCH 05/11] invoke nonDefaultDistributedActorInitialize when necessary in SILGen --- include/swift/AST/Builtins.def | 6 ++++- include/swift/Runtime/Concurrency.h | 6 ++++- include/swift/Runtime/RuntimeFunctions.def | 9 +++++++ lib/AST/Builtins.cpp | 1 + lib/AST/Decl.cpp | 4 +-- lib/IRGen/GenBuiltin.cpp | 18 ++++++++++--- lib/SIL/IR/OperandOwnership.cpp | 1 + lib/SIL/IR/ValueOwnership.cpp | 1 + lib/SIL/Utils/MemAccessUtils.cpp | 1 + lib/SILGen/SILGenConstructor.cpp | 23 +++++++++++++++-- .../AccessEnforcementReleaseSinking.cpp | 1 + stdlib/public/Concurrency/Actor.cpp | 8 +++++- stdlib/public/Concurrency/Actor.swift | 4 +++ ...tributed_actor_initialize_nondefault.swift | 25 +++++++++++++++++++ 14 files changed, 98 insertions(+), 10 deletions(-) create mode 100644 test/Distributed/SIL/distributed_actor_initialize_nondefault.swift diff --git a/include/swift/AST/Builtins.def b/include/swift/AST/Builtins.def index a452dfb1f4679..c04d09773f633 100644 --- a/include/swift/AST/Builtins.def +++ b/include/swift/AST/Builtins.def @@ -774,7 +774,11 @@ BUILTIN_MISC_OPERATION(InitializeDefaultActor, "initializeDefaultActor", "", Spe /// Destroy the default-actor instance in a default actor object. BUILTIN_MISC_OPERATION(DestroyDefaultActor, "destroyDefaultActor", "", Special) -/// Allocate a "proxy" for a distributed remote actor. TODO(distributed) change the name of this to create throughout. +/// Initialize the default-actor instance in a non-default distributed actor object. +BUILTIN_MISC_OPERATION(InitializeNonDefaultDistributedActor, + "initializeNonDefaultDistributedActor", "", Special) + +/// Allocate a "proxy" for a distributed remote actor. BUILTIN_MISC_OPERATION(InitializeDistributedRemoteActor, "initializeDistributedRemoteActor", "", Special) diff --git a/include/swift/Runtime/Concurrency.h b/include/swift/Runtime/Concurrency.h index 3f0c7d3e04a06..ee8a4bdcc46d8 100644 --- a/include/swift/Runtime/Concurrency.h +++ b/include/swift/Runtime/Concurrency.h @@ -799,7 +799,11 @@ void swift_defaultActor_deallocate(DefaultActor *actor); SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) void swift_defaultActor_deallocateResilient(HeapObject *actor); -/// Initialize the runtime storage for a distributed remote actor. +/// Initialize the runtime storage for a non-default distributed actor. +SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) +void swift_nonDefaultDistributedActor_initialize(NonDefaultDistributedActor *actor); + +/// Create and initialize the runtime storage for a distributed remote actor. SWIFT_EXPORT_FROM(swift_Concurrency) SWIFT_CC(swift) OpaqueValue* swift_distributedActor_remote_initialize(const Metadata *actorType); diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def index 1cde2a50a3113..3cd238890df42 100644 --- a/include/swift/Runtime/RuntimeFunctions.def +++ b/include/swift/Runtime/RuntimeFunctions.def @@ -2037,6 +2037,15 @@ FUNCTION(DefaultActorDeallocateResilient, ATTRS(NoUnwind), EFFECT(Concurrency)) +// void swift_nonDefaultDistributedActor_initialize(NonDefaultDistributedActor *actor); +FUNCTION(NonDefaultDistributedActorInitialize, + swift_nonDefaultDistributedActor_initialize, SwiftCC, + ConcurrencyAvailability, + RETURNS(VoidTy), + ARGS(RefCountedPtrTy), + ATTRS(NoUnwind), + EFFECT(Concurrency)) + // OpaqueValue* swift_distributedActor_remote_initialize( // const Metadata *actorType // ); diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp index d55c9dc3602c2..fcbd6bd1f8a24 100644 --- a/lib/AST/Builtins.cpp +++ b/lib/AST/Builtins.cpp @@ -2915,6 +2915,7 @@ ValueDecl *swift::getBuiltinValueDecl(ASTContext &Context, Identifier Id) { return getTriggerFallbackDiagnosticOperation(Context, Id); case BuiltinValueKind::InitializeDefaultActor: + case BuiltinValueKind::InitializeNonDefaultDistributedActor: case BuiltinValueKind::DestroyDefaultActor: return getDefaultActorInitDestroy(Context, Id); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 1cde7f868d815..efa9488b3cb2a 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -9599,10 +9599,10 @@ bool ClassDecl::isRootDefaultActor(ModuleDecl *M, } bool ClassDecl::isNonDefaultExplicitDistributedActor() const { - return isRootDefaultActor(getModuleContext(), ResilienceExpansion::Maximal); + return isNonDefaultExplicitDistributedActor(getModuleContext(), ResilienceExpansion::Maximal); } bool ClassDecl::isNonDefaultExplicitDistributedActor(ModuleDecl *M, - ResilienceExpansion expansion) const { + ResilienceExpansion expansion) const { return !isDefaultActor(M, expansion) && isExplicitDistributedActor(); } diff --git a/lib/IRGen/GenBuiltin.cpp b/lib/IRGen/GenBuiltin.cpp index 785c3a75fac35..141e42c4c9112 100644 --- a/lib/IRGen/GenBuiltin.cpp +++ b/lib/IRGen/GenBuiltin.cpp @@ -347,10 +347,22 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin, } if (Builtin.ID == BuiltinValueKind::InitializeDefaultActor || + Builtin.ID == BuiltinValueKind::InitializeNonDefaultDistributedActor || Builtin.ID == BuiltinValueKind::DestroyDefaultActor) { - auto fn = Builtin.ID == BuiltinValueKind::InitializeDefaultActor - ? IGF.IGM.getDefaultActorInitializeFunctionPointer() - : IGF.IGM.getDefaultActorDestroyFunctionPointer(); + irgen::FunctionPointer fn; + switch (Builtin.ID) { + case BuiltinValueKind::InitializeDefaultActor: + fn = IGF.IGM.getDefaultActorInitializeFunctionPointer(); + break; + case BuiltinValueKind::InitializeNonDefaultDistributedActor: + fn = IGF.IGM.getNonDefaultDistributedActorInitializeFunctionPointer(); + break; + case BuiltinValueKind::DestroyDefaultActor: + fn = IGF.IGM.getDefaultActorDestroyFunctionPointer(); + break; + default: + llvm_unreachable("unhandled builtin id!"); + } auto actor = args.claimNext(); actor = IGF.Builder.CreateBitCast(actor, IGF.IGM.RefCountedPtrTy); auto call = IGF.Builder.CreateCall(fn, {actor}); diff --git a/lib/SIL/IR/OperandOwnership.cpp b/lib/SIL/IR/OperandOwnership.cpp index 2056bfcc23ba9..9ee373660956c 100644 --- a/lib/SIL/IR/OperandOwnership.cpp +++ b/lib/SIL/IR/OperandOwnership.cpp @@ -931,6 +931,7 @@ BUILTIN_OPERAND_OWNERSHIP(InteriorPointer, InitializeDefaultActor) BUILTIN_OPERAND_OWNERSHIP(InteriorPointer, DestroyDefaultActor) BUILTIN_OPERAND_OWNERSHIP(InteriorPointer, InitializeDistributedRemoteActor) +BUILTIN_OPERAND_OWNERSHIP(InteriorPointer, InitializeNonDefaultDistributedActor) BUILTIN_OPERAND_OWNERSHIP(PointerEscape, AutoDiffAllocateSubcontext) BUILTIN_OPERAND_OWNERSHIP(PointerEscape, AutoDiffProjectTopLevelSubcontext) diff --git a/lib/SIL/IR/ValueOwnership.cpp b/lib/SIL/IR/ValueOwnership.cpp index de387858f3ac6..0facc49ef7f7c 100644 --- a/lib/SIL/IR/ValueOwnership.cpp +++ b/lib/SIL/IR/ValueOwnership.cpp @@ -558,6 +558,7 @@ CONSTANT_OWNERSHIP_BUILTIN(None, ConvertTaskToJob) CONSTANT_OWNERSHIP_BUILTIN(None, InitializeDefaultActor) CONSTANT_OWNERSHIP_BUILTIN(None, DestroyDefaultActor) CONSTANT_OWNERSHIP_BUILTIN(None, InitializeDistributedRemoteActor) +CONSTANT_OWNERSHIP_BUILTIN(None, InitializeNonDefaultDistributedActor) CONSTANT_OWNERSHIP_BUILTIN(Owned, AutoDiffCreateLinearMapContext) CONSTANT_OWNERSHIP_BUILTIN(None, AutoDiffProjectTopLevelSubcontext) CONSTANT_OWNERSHIP_BUILTIN(None, AutoDiffAllocateSubcontext) diff --git a/lib/SIL/Utils/MemAccessUtils.cpp b/lib/SIL/Utils/MemAccessUtils.cpp index 09c1c842a2d6c..5ee2f63741552 100644 --- a/lib/SIL/Utils/MemAccessUtils.cpp +++ b/lib/SIL/Utils/MemAccessUtils.cpp @@ -2538,6 +2538,7 @@ static void visitBuiltinAddress(BuiltinInst *builtin, case BuiltinValueKind::AutoDiffAllocateSubcontext: case BuiltinValueKind::InitializeDefaultActor: case BuiltinValueKind::InitializeDistributedRemoteActor: + case BuiltinValueKind::InitializeNonDefaultDistributedActor: case BuiltinValueKind::DestroyDefaultActor: case BuiltinValueKind::GetCurrentExecutor: case BuiltinValueKind::StartAsyncLet: diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index 776ba7ca51542..8ae124f8f65cf 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -729,6 +729,18 @@ static void emitDefaultActorInitialization( { self.borrow(SGF, loc).getValue() }); } +static void emitNonDefaultDistributedActorInitialization( + SILGenFunction &SGF, SILLocation loc, ManagedValue self) { + auto &ctx = SGF.getASTContext(); + auto builtinName = ctx.getIdentifier( + getBuiltinName(BuiltinValueKind::InitializeNonDefaultDistributedActor)); + auto resultTy = SGF.SGM.Types.getEmptyTupleType(); + + FullExpr scope(SGF.Cleanups, CleanupLocation(loc)); + SGF.B.createBuiltin(loc, builtinName, resultTy, /*subs*/{}, + { self.borrow(SGF, loc).getValue() }); +} + void SILGenFunction::emitConstructorPrologActorHop( SILLocation loc, Optional maybeIso) { @@ -832,14 +844,21 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) { } if (selfClassDecl->isRootDefaultActor() && !isDelegating) { + fprintf(stderr, "[%s:%d](%s) EMIT DEFAULT INIT!!!! initialize\n", __FILE_NAME__, __LINE__, __FUNCTION__); // Initialize the default-actor instance. SILLocation PrologueLoc(selfDecl); PrologueLoc.markAsPrologue(); emitDefaultActorInitialization(*this, PrologueLoc, selfArg); } else if (selfClassDecl->isNonDefaultExplicitDistributedActor() && !isDelegating) { // Initialize the distributed local actor with custom executor, - // with additional storage such that we can store the local/remote bit - assert(false && "FIXME not implemented initializing the local one"); // FIXME: !!!! + // with additional storage such that we can store the local/remote bit. + // + // We do this because normally non-default actors do not get any synthesized storage, + // as their executor is provided via user implementation. However, a distributed actor + // always needs additional storage for e.g. the isRemote/isLocal information. + SILLocation PrologueLoc(selfDecl); + PrologueLoc.markAsPrologue(); + emitNonDefaultDistributedActorInitialization(*this, PrologueLoc, selfArg); } if (!ctor->hasStubImplementation()) { diff --git a/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp b/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp index ed163dc9cef3b..cbf9f870da6fc 100644 --- a/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp +++ b/lib/SILOptimizer/Transforms/AccessEnforcementReleaseSinking.cpp @@ -190,6 +190,7 @@ static bool isBarrier(SILInstruction *inst) { case BuiltinValueKind::InitializeDefaultActor: case BuiltinValueKind::DestroyDefaultActor: case BuiltinValueKind::InitializeDistributedRemoteActor: + case BuiltinValueKind::InitializeNonDefaultDistributedActor: case BuiltinValueKind::BuildOrdinarySerialExecutorRef: case BuiltinValueKind::BuildDefaultActorExecutorRef: case BuiltinValueKind::BuildMainActorExecutorRef: diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index 774de81ca649a..c958cbda67cb6 100644 --- a/stdlib/public/Concurrency/Actor.cpp +++ b/stdlib/public/Concurrency/Actor.cpp @@ -946,7 +946,7 @@ class NonDefaultDistributedActorImpl : public HeapObject { fprintf(stderr, "[%s:%d](%s) initialize NonDefaultDistributedActorImpl; remote = %d\n", __FILE_NAME__, __LINE__, __FUNCTION__, isDistributedRemote); this->isDistributedRemoteActor = isDistributedRemote; SWIFT_TASK_DEBUG_LOG("Creating non-default distributed actor %p", this); - // concurrency::trace::actor_create(this); // FIXME: !!!! + concurrency::trace::actor_create(this); // FIXME: !!!! } /// Properly destruct an actor, except for the heap header. @@ -1994,6 +1994,12 @@ void swift::swift_executor_escalate(ExecutorRef executor, AsyncTask *task, /***************************** DISTRIBUTED ACTOR *****************************/ /*****************************************************************************/ +void swift::swift_nonDefaultDistributedActor_initialize(NonDefaultDistributedActor *_actor) { + fprintf(stderr, "[%s:%d](%s) NON DEFAULT DefaultActor initialize!!!\n", __FILE_NAME__, __LINE__, __FUNCTION__); + asImpl(_actor)->initialize(); +} + + OpaqueValue* swift::swift_distributedActor_remote_initialize(const Metadata *actorType) { auto *metadata = actorType->getClassObject(); diff --git a/stdlib/public/Concurrency/Actor.swift b/stdlib/public/Concurrency/Actor.swift index 0b38837e155cd..15b7606ab061c 100644 --- a/stdlib/public/Concurrency/Actor.swift +++ b/stdlib/public/Concurrency/Actor.swift @@ -58,6 +58,10 @@ public protocol Actor: AnyActor { @_silgen_name("swift_defaultActor_initialize") public func _defaultActorInitialize(_ actor: AnyObject) +@available(SwiftStdlib 5.9, *) +@_silgen_name("swift_nonDefaultDistributedActor_initialize") +public func _nonDefaultDistributedActorInitialize(_ actor: AnyObject) + /// Called to destroy the default actor instance in an actor. /// The implementation will call this within the actor's deinit. @available(SwiftStdlib 5.1, *) diff --git a/test/Distributed/SIL/distributed_actor_initialize_nondefault.swift b/test/Distributed/SIL/distributed_actor_initialize_nondefault.swift new file mode 100644 index 0000000000000..7d1e97798e72c --- /dev/null +++ b/test/Distributed/SIL/distributed_actor_initialize_nondefault.swift @@ -0,0 +1,25 @@ +// RUN: %empty-directory(%t) +// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -disable-availability-checking %S/../Inputs/FakeDistributedActorSystems.swift +// RUN: %target-swift-frontend -module-name default_deinit -primary-file %s -emit-sil -verify -disable-availability-checking -I %t | %FileCheck %s --enable-var-scope --dump-input=fail +// REQUIRES: concurrency +// REQUIRES: distributed + +/// The convention in this test is that the Swift declaration comes before its FileCheck lines. + +import Distributed +import FakeDistributedActorSystems + +typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem + +// ==== ---------------------------------------------------------------------------------------------------------------- + +distributed actor MyDistActor { + nonisolated var unownedExecutor: UnownedSerialExecutor { + return MainActor.sharedUnownedExecutor + } + +// CHECK: sil hidden @$s14default_deinit11MyDistActorC11actorSystemAC015FakeDistributedE7Systems0h9RoundtripeG0C_tcfc : $@convention(method) (@owned FakeRoundtripActorSystem, @owned MyDistActor) -> @owned MyDistActor +// CHECK-NOT: [[BAD:%[0-9]+]] = builtin "initializeDefaultActor"(%1 : $MyDistActor) : $() +// CHECK: [[ACTOR_INSTANCE:%[0-9]+]] = builtin "initializeNonDefaultDistributedActor"(%1 : $MyDistActor) : $() +} + From 23e7a22b7374210c0f6395950f74fdc4eab6fe70 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 15 Mar 2023 09:40:16 +0900 Subject: [PATCH 06/11] refactor inline assertion into method --- .../DerivedConformanceDistributedActor.cpp | 91 ++++++++++--------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/lib/Sema/DerivedConformanceDistributedActor.cpp b/lib/Sema/DerivedConformanceDistributedActor.cpp index e927bed38a412..b5f47c6d3fc1a 100644 --- a/lib/Sema/DerivedConformanceDistributedActor.cpp +++ b/lib/Sema/DerivedConformanceDistributedActor.cpp @@ -457,7 +457,6 @@ static ValueDecl *deriveDistributedActor_actorSystem( // we don't allocate memory after those two fields, so their order is very // important. The `hint` below makes sure the system is inserted right after. if (auto id = derived.Nominal->getDistributedActorIDProperty()) { - fprintf(stderr, "[%s:%d](%s) INSERT SYSTEM: AFTER ID\n", __FILE_NAME__, __LINE__, __FUNCTION__); derived.addMemberToConformanceContext(propDecl, /*hint=*/id); derived.addMemberToConformanceContext(pbDecl, /*hint=*/id); } else { @@ -465,7 +464,6 @@ static ValueDecl *deriveDistributedActor_actorSystem( // so in order for system to be SECOND (as it must be), // we'll insert at head right now and as id gets synthesized we'll get // the correct order: id, actorSystem. - fprintf(stderr, "[%s:%d](%s) INSERT SYSTEM: FIRST\n", __FILE_NAME__, __LINE__, __FUNCTION__); derived.addMemberToConformanceContext(propDecl, /*insertAtHead=*/true); derived.addMemberToConformanceContext(pbDecl, /*insertAtHead==*/true); } @@ -720,6 +718,51 @@ static ValueDecl *deriveDistributedActor_unownedExecutor(DerivedConformance &der /**************************** ENTRY POINTS ************************************/ /******************************************************************************/ +/// Asserts that the synthesized fields appear in the expected order. +/// +/// The `id` and `actorSystem` MUST be the first two fields of a distributed actor, +/// because we assume their location in IRGen, and also when we allocate a distributed remote actor, +/// we're able to allocate memory ONLY for those and without allocating any of the storage for the actor's +/// properties. +/// [id, actorSystem] +/// followed by the executor fields for a default distributed actor. +/// +static void assertRequiredSynthesizedPropertyOrder(DerivedConformance &derived, ValueDecl *derivedValue) { +#ifndef NDEBUG + if (derivedValue) { + auto Nominal = derived.Nominal; + auto &Context = derived.Context; + if (auto id = Nominal->getDistributedActorIDProperty()) { + if (auto system = Nominal->getDistributedActorSystemProperty()) { + if (auto classDecl = dyn_cast(derived.Nominal)) { + if (auto unownedExecutor = classDecl->getUnownedExecutorProperty()) { + int idIdx, actorSystemIdx, unownedExecutorIdx = 0; + int idx = 0; + for (auto member: Nominal->getMembers()) { + if (auto binding = dyn_cast(member)) { + fprintf(stderr, "[%s:%d](%s) member = \n", __FILE_NAME__, __LINE__, __FUNCTION__); + member->dump(); + if (binding->getSingleVar()->getName() == Context.Id_id) { + idIdx = idx; + } else if (binding->getSingleVar()->getName() == Context.Id_actorSystem) { + actorSystemIdx = idx; + } else if (binding->getSingleVar()->getName() == Context.Id_unownedExecutor) { + unownedExecutorIdx = idx; + } + idx += 1; + } + } + if (idIdx + actorSystemIdx + unownedExecutorIdx >= 0 + 1 + 2) { + assert(idIdx < actorSystemIdx < unownedExecutorIdx && "order of fields MUST be exact."); + } + } + } + } + } + } +#endif +} + // !!!!!!!!!!!!! IMPORTANT WHEN MAKING CHANGES TO REQUIREMENTS !!!!!!!!!!!!!!!!! // !! Remember to update DerivedConformance::getDerivableRequirement !! // !! any time the signatures or list of derived requirements change. !! @@ -728,12 +771,6 @@ static ValueDecl *deriveDistributedActor_unownedExecutor(DerivedConformance &der ValueDecl *DerivedConformance::deriveDistributedActor(ValueDecl *requirement) { if (auto var = dyn_cast(requirement)) { ValueDecl *derivedValue = nullptr; -// if (var->getName() == Context.Id_id) { -// fprintf(stderr, "[%s:%d](%s) DERIVE ID\n", __FILE_NAME__, __LINE__, __FUNCTION__); -// derivedValue = deriveDistributedActor_id(*this); -// } else - // NOTE: `id` is implemented in addImplicitDistributedActorIDProperty - if (var->getName() == Context.Id_actorSystem) { fprintf(stderr, "[%s:%d](%s) DERIVE SYS\n", __FILE_NAME__, __LINE__, __FUNCTION__); derivedValue = deriveDistributedActor_actorSystem(*this); @@ -742,42 +779,8 @@ ValueDecl *DerivedConformance::deriveDistributedActor(ValueDecl *requirement) { derivedValue = deriveDistributedActor_unownedExecutor(*this); } - if (derivedValue) { - if (auto id = Nominal->getDistributedActorIDProperty()) { - if (auto system = Nominal->getDistributedActorSystemProperty()) { - if (auto classDecl = dyn_cast(Nominal)) { - if (auto unownedExecutor = classDecl->getUnownedExecutorProperty()) { - int idIdx, actorSystemIdx, unownedExecutorIdx = 0; - int idx = 0; - for (auto member : Nominal->getMembers()) { - if (auto binding = dyn_cast(member)) { - fprintf(stderr, "[%s:%d](%s) member = \n", __FILE_NAME__, __LINE__, __FUNCTION__); - member->dump(); - if (binding->getSingleVar()->getName() == Context.Id_id) { - idIdx = idx; - } else if (binding->getSingleVar()->getName() == Context.Id_actorSystem) { - actorSystemIdx = idx; - } else if (binding->getSingleVar()->getName() == Context.Id_unownedExecutor) { - unownedExecutorIdx = idx; - } - idx += 1; - } - } - if (idIdx + actorSystemIdx + unownedExecutorIdx >= 0 + 1 + 2) { - fprintf(stderr, "[%s:%d](%s) ******************************************************************************************\n", __FILE_NAME__, __LINE__, __FUNCTION__); - Nominal->dump(); - fprintf(stderr, "[%s:%d](%s) ******************************************************************************************\n", __FILE_NAME__, __LINE__, __FUNCTION__); - fprintf(stderr, "[%s:%d](%s) member == id = %d \n", __FILE_NAME__, __LINE__, __FUNCTION__, idIdx); - fprintf(stderr, "[%s:%d](%s) member == sys = %d \n", __FILE_NAME__, __LINE__, __FUNCTION__, actorSystemIdx); - fprintf(stderr, "[%s:%d](%s) member == ex = %d \n", __FILE_NAME__, __LINE__, __FUNCTION__, unownedExecutorIdx); -// assert(idIdx < actorSystemIdx < unownedExecutorIdx && "order of fields MUST be exact."); - } - } - } - } - } - return derivedValue; - } + assertRequiredSynthesizedPropertyOrder(*this, derivedValue); + return derivedValue; } if (auto func = dyn_cast(requirement)) { From fd8ffdcfdf9dc0149e45d8526a527c1eb80d91f4 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 15 Mar 2023 11:22:26 +0900 Subject: [PATCH 07/11] cleanup --- include/swift/ABI/Metadata.h | 4 ---- lib/SILGen/SILGenConstructor.cpp | 1 - lib/Sema/DerivedConformanceDistributedActor.cpp | 14 +------------- stdlib/public/Concurrency/Actor.cpp | 15 +-------------- 4 files changed, 2 insertions(+), 32 deletions(-) diff --git a/include/swift/ABI/Metadata.h b/include/swift/ABI/Metadata.h index 09f2dc1d95436..7d7307140e9cf 100644 --- a/include/swift/ABI/Metadata.h +++ b/include/swift/ABI/Metadata.h @@ -4139,14 +4139,10 @@ class TargetClassDescriptor final } bool isActor() const { - fprintf(stderr, "[%s:%d](%s) is actor? %d\n", __FILE_NAME__, __LINE__, __FUNCTION__, - this->getTypeContextDescriptorFlags().class_isActor()); return this->getTypeContextDescriptorFlags().class_isActor(); } bool isDefaultActor() const { - fprintf(stderr, "[%s:%d](%s) is actor? %d\n", __FILE_NAME__, __LINE__, __FUNCTION__, - this->getTypeContextDescriptorFlags().class_isDefaultActor()); return this->getTypeContextDescriptorFlags().class_isDefaultActor(); } diff --git a/lib/SILGen/SILGenConstructor.cpp b/lib/SILGen/SILGenConstructor.cpp index 8ae124f8f65cf..1584feca4eff9 100644 --- a/lib/SILGen/SILGenConstructor.cpp +++ b/lib/SILGen/SILGenConstructor.cpp @@ -844,7 +844,6 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) { } if (selfClassDecl->isRootDefaultActor() && !isDelegating) { - fprintf(stderr, "[%s:%d](%s) EMIT DEFAULT INIT!!!! initialize\n", __FILE_NAME__, __LINE__, __FUNCTION__); // Initialize the default-actor instance. SILLocation PrologueLoc(selfDecl); PrologueLoc.markAsPrologue(); diff --git a/lib/Sema/DerivedConformanceDistributedActor.cpp b/lib/Sema/DerivedConformanceDistributedActor.cpp index b5f47c6d3fc1a..96e0992b8fcb6 100644 --- a/lib/Sema/DerivedConformanceDistributedActor.cpp +++ b/lib/Sema/DerivedConformanceDistributedActor.cpp @@ -689,28 +689,19 @@ static ValueDecl *deriveDistributedActor_unownedExecutor(DerivedConformance &der if (auto id = derived.Nominal->getDistributedActorIDProperty()) { if (auto system = derived.Nominal->getDistributedActorSystemProperty()) { // good, we must be after the system; this is the final order - fprintf(stderr, "[%s:%d](%s) INSERT EXECUTOR: AFTER SYSTEM\n", __FILE_NAME__, __LINE__, __FUNCTION__); - system->dump(); derived.addMemberToConformanceContext(propertyPair.second, /*hint=*/system); derived.addMemberToConformanceContext(property, /*hint=*/system); } else { // system was not yet synthesized, it'll insert after id and we'll be okey - fprintf(stderr, "[%s:%d](%s) INSERT EXECUTOR: AFTER ID\n", __FILE_NAME__, __LINE__, __FUNCTION__); derived.addMemberToConformanceContext(propertyPair.second, /*hint=*/id); derived.addMemberToConformanceContext(property, /*hint=*/id); } } else { // nor id or system synthesized yet, id will insert first and system will be after it - fprintf(stderr, "[%s:%d](%s) INSERT EXECUTOR: FIRST\n", __FILE_NAME__, __LINE__, __FUNCTION__); derived.addMemberToConformanceContext(propertyPair.second, /*insertAtHead==*/true); derived.addMemberToConformanceContext(property, /*insertAtHead==*/true); } - fprintf(stderr, "[%s:%d](%s) ================================================\n", __FILE_NAME__, __LINE__, __FUNCTION__); - derived.Nominal->dump(); - fprintf(stderr, "[%s:%d](%s) ================================================\n", __FILE_NAME__, __LINE__, __FUNCTION__); - fprintf(stderr, "[%s:%d](%s) ================================================\n", __FILE_NAME__, __LINE__, __FUNCTION__); - return property; } @@ -740,8 +731,6 @@ static void assertRequiredSynthesizedPropertyOrder(DerivedConformance &derived, int idx = 0; for (auto member: Nominal->getMembers()) { if (auto binding = dyn_cast(member)) { - fprintf(stderr, "[%s:%d](%s) member = \n", __FILE_NAME__, __LINE__, __FUNCTION__); - member->dump(); if (binding->getSingleVar()->getName() == Context.Id_id) { idIdx = idx; } else if (binding->getSingleVar()->getName() == Context.Id_actorSystem) { @@ -753,6 +742,7 @@ static void assertRequiredSynthesizedPropertyOrder(DerivedConformance &derived, } } if (idIdx + actorSystemIdx + unownedExecutorIdx >= 0 + 1 + 2) { + // we have found all the necessary fields, let's assert their order assert(idIdx < actorSystemIdx < unownedExecutorIdx && "order of fields MUST be exact."); } } @@ -772,10 +762,8 @@ ValueDecl *DerivedConformance::deriveDistributedActor(ValueDecl *requirement) { if (auto var = dyn_cast(requirement)) { ValueDecl *derivedValue = nullptr; if (var->getName() == Context.Id_actorSystem) { - fprintf(stderr, "[%s:%d](%s) DERIVE SYS\n", __FILE_NAME__, __LINE__, __FUNCTION__); derivedValue = deriveDistributedActor_actorSystem(*this); } else if (var->getName() == Context.Id_unownedExecutor) { - fprintf(stderr, "[%s:%d](%s) DERIVE EX\n", __FILE_NAME__, __LINE__, __FUNCTION__); derivedValue = deriveDistributedActor_unownedExecutor(*this); } diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index c958cbda67cb6..177e915687496 100644 --- a/stdlib/public/Concurrency/Actor.cpp +++ b/stdlib/public/Concurrency/Actor.cpp @@ -861,7 +861,6 @@ class DefaultActorImpl : public HeapObject { public: /// Properly construct an actor, except for the heap header. void initialize(bool isDistributedRemote = false) { - fprintf(stderr, "[%s:%d](%s) initialize DefaultActorImpl; remote = %d\n", __FILE_NAME__, __LINE__, __FUNCTION__, isDistributedRemote); this->isDistributedRemoteActor = isDistributedRemote; #if SWIFT_CONCURRENCY_ACTORS_AS_LOCKS new (&this->drainLock) Mutex(); @@ -943,10 +942,9 @@ class NonDefaultDistributedActorImpl : public HeapObject { public: /// Properly construct an actor, except for the heap header. void initialize(bool isDistributedRemote = false) { - fprintf(stderr, "[%s:%d](%s) initialize NonDefaultDistributedActorImpl; remote = %d\n", __FILE_NAME__, __LINE__, __FUNCTION__, isDistributedRemote); this->isDistributedRemoteActor = isDistributedRemote; SWIFT_TASK_DEBUG_LOG("Creating non-default distributed actor %p", this); - concurrency::trace::actor_create(this); // FIXME: !!!! + concurrency::trace::actor_create(this); } /// Properly destruct an actor, except for the heap header. @@ -1713,7 +1711,6 @@ static void swift_job_runImpl(Job *job, ExecutorRef executor) { } void swift::swift_defaultActor_initialize(DefaultActor *_actor) { - fprintf(stderr, "[%s:%d](%s) DefaultActor initialize!!!\n", __FILE_NAME__, __LINE__, __FUNCTION__); asImpl(_actor)->initialize(); } @@ -1734,13 +1731,10 @@ void swift::swift_defaultActor_deallocate(DefaultActor *_actor) { } static bool isDefaultActorClass(const ClassMetadata *metadata) { - fprintf(stderr, "[%s:%d](%s) is DefaultActor ???\n", __FILE_NAME__, __LINE__, __FUNCTION__); - assert(metadata->isTypeMetadata()); while (true) { // Trust the class descriptor if it says it's a default actor. if (metadata->getDescription()->isDefaultActor()) { - fprintf(stderr, "[%s:%d](%s) is DefaultActor = YES\n", __FILE_NAME__, __LINE__, __FUNCTION__); return true; } @@ -1749,7 +1743,6 @@ static bool isDefaultActorClass(const ClassMetadata *metadata) { // If we run out of Swift classes, it's not a default actor. if (!metadata || !metadata->isTypeMetadata()) { - fprintf(stderr, "[%s:%d](%s) is DefaultActor = NO IT IS NOT\n", __FILE_NAME__, __LINE__, __FUNCTION__); return false; } } @@ -1995,11 +1988,9 @@ void swift::swift_executor_escalate(ExecutorRef executor, AsyncTask *task, /*****************************************************************************/ void swift::swift_nonDefaultDistributedActor_initialize(NonDefaultDistributedActor *_actor) { - fprintf(stderr, "[%s:%d](%s) NON DEFAULT DefaultActor initialize!!!\n", __FILE_NAME__, __LINE__, __FUNCTION__); asImpl(_actor)->initialize(); } - OpaqueValue* swift::swift_distributedActor_remote_initialize(const Metadata *actorType) { auto *metadata = actorType->getClassObject(); @@ -2021,12 +2012,10 @@ swift::swift_distributedActor_remote_initialize(const Metadata *actorType) { // If it is a default actor, we reuse the same layout as DefaultActorImpl, // and store flags in the allocation directly as we initialize it. if (isDefaultActorClass(metadata)) { - fprintf(stderr, "[%s:%d](%s) IS DEFAULT\n", __FILE_NAME__, __LINE__, __FUNCTION__); auto actor = asImpl(reinterpret_cast(alloc)); actor->initialize(/*remote*/true); return reinterpret_cast(actor); } else { - fprintf(stderr, "[%s:%d](%s) initialize NOT DEFAULT [REMOTE] DISTRIBUTED ACTOR\n", __FILE_NAME__, __LINE__, __FUNCTION__); auto actor = asImpl(reinterpret_cast(alloc)); actor->initialize(/*remote*/true); } @@ -2035,12 +2024,10 @@ swift::swift_distributedActor_remote_initialize(const Metadata *actorType) { } bool swift::swift_distributed_actor_is_remote(HeapObject *_actor) { - fprintf(stderr, "[%s:%d](%s) CHECK: swift_distributed_actor_is_remote\n", __FILE_NAME__, __LINE__, __FUNCTION__); auto metadata = cast(_actor->metadata); if (isDefaultActorClass(metadata)) { return asImpl((DefaultActor *) _actor)->isDistributedRemote(); } else { - fprintf(stderr, "[%s:%d](%s) NEW PATH swift_distributed_actor_is_remote\n", __FILE_NAME__, __LINE__, __FUNCTION__); return asImpl((NonDefaultDistributedActor *) _actor)->isDistributedRemote(); // NEW } } From 5f43075f5ad0f3c23f57d9d181b925b658cb786f Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 15 Mar 2023 11:37:02 +0900 Subject: [PATCH 08/11] [Executors][Distributed] Update module version for NonDefaultDistributedActor --- lib/Serialization/ModuleFormat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index da758c2b389bc..447b5ff15c01b 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -58,7 +58,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0; /// describe what change you made. The content of this comment isn't important; /// it just ensures a conflict if two people change the module format. /// Don't worry about adhering to the 80-column limit for this line. -const uint16_t SWIFTMODULE_VERSION_MINOR = 752; // mark_unresolved_ref_binding +const uint16_t SWIFTMODULE_VERSION_MINOR = 753; // distributed actor support for custom executors (NonDefaultDistributedActor type and mangling) /// A standard hash seed used for all string hashes in a serialized module. /// From c38c896234db4cd528e8435f9c84aca68d952e28 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 15 Mar 2023 19:01:55 +0900 Subject: [PATCH 09/11] Minor docs cleanup --- include/swift/ABI/Actor.h | 2 +- include/swift/AST/Builtins.def | 2 +- include/swift/AST/TypeCheckRequests.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/swift/ABI/Actor.h b/include/swift/ABI/Actor.h index 6c173bed09a4e..e8b4a945b7b34 100644 --- a/include/swift/ABI/Actor.h +++ b/include/swift/ABI/Actor.h @@ -44,7 +44,7 @@ class alignas(Alignment_NonDefaultDistributedActor) NonDefaultDistributedActor : public: // These constructors do not initialize the actor instance, and the // destructor does not destroy the actor instance; you must call - // swift_defaultActor_{initialize,destroy} yourself. + // swift_nonDefaultDistributedActor_initialize yourself. constexpr NonDefaultDistributedActor(const HeapMetadata *metadata) : HeapObject(metadata), PrivateData{} {} diff --git a/include/swift/AST/Builtins.def b/include/swift/AST/Builtins.def index c04d09773f633..948126e0abd8d 100644 --- a/include/swift/AST/Builtins.def +++ b/include/swift/AST/Builtins.def @@ -774,7 +774,7 @@ BUILTIN_MISC_OPERATION(InitializeDefaultActor, "initializeDefaultActor", "", Spe /// Destroy the default-actor instance in a default actor object. BUILTIN_MISC_OPERATION(DestroyDefaultActor, "destroyDefaultActor", "", Special) -/// Initialize the default-actor instance in a non-default distributed actor object. +/// Initialize the extra storage state of a non-default distributed actor object. BUILTIN_MISC_OPERATION(InitializeNonDefaultDistributedActor, "initializeNonDefaultDistributedActor", "", Special) diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 46bbda6fed53d..6d8115377b117 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -1220,7 +1220,7 @@ class GetDistributedActorSystemPropertyRequest : public: // Caching - bool isCached() const { return false; } + bool isCached() const { return true; } }; /// Obtain the constructor of the 'RemoteCallTarget' type. From 13d2e50a2bcbbaef155248be671820672b7e853b Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 15 Mar 2023 19:06:48 +0900 Subject: [PATCH 10/11] we solved those fixme's --- lib/IRGen/StructLayout.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/IRGen/StructLayout.cpp b/lib/IRGen/StructLayout.cpp index d832124ed9d31..eeb8096bf9662 100644 --- a/lib/IRGen/StructLayout.cpp +++ b/lib/IRGen/StructLayout.cpp @@ -208,7 +208,7 @@ void StructLayoutBuilder::addNSObjectHeader() { headerSize = CurSize; } -void StructLayoutBuilder::addDefaultActorHeader(ElementLayout &elt) { // FIXME: !!!! make sure we call this equivalent for distributed +void StructLayoutBuilder::addDefaultActorHeader(ElementLayout &elt) { assert(StructFields.size() == 1 && StructFields[0] == IGM.RefCountedStructTy && "adding default actor header at wrong offset"); @@ -236,7 +236,7 @@ void StructLayoutBuilder::addNonDefaultDistributedActorHeader(ElementLayout &elt StructFields[0] == IGM.RefCountedStructTy && "adding default actor header at wrong offset"); - // These must match the NonDefaultDistributedActor class in Actor.h. // FIXME: !!!! make such class + // These must match the NonDefaultDistributedActor class in Actor.h. auto size = NumWords_NonDefaultDistributedActor * IGM.getPointerSize(); auto align = Alignment(Alignment_NonDefaultDistributedActor); auto ty = llvm::ArrayType::get(IGM.Int8PtrTy, NumWords_NonDefaultDistributedActor); From 349df21d34efbace48147d87fdaf556e28b54275 Mon Sep 17 00:00:00 2001 From: Konrad `ktoso` Malawski Date: Wed, 15 Mar 2023 19:30:28 +0900 Subject: [PATCH 11/11] add mangling test for non-def-dist-actor --- .../SIL/distributed_actor_initialize_nondefault.swift | 1 + test/Runtime/demangleToMetadata.swift | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/test/Distributed/SIL/distributed_actor_initialize_nondefault.swift b/test/Distributed/SIL/distributed_actor_initialize_nondefault.swift index 7d1e97798e72c..6c99a2c9efe41 100644 --- a/test/Distributed/SIL/distributed_actor_initialize_nondefault.swift +++ b/test/Distributed/SIL/distributed_actor_initialize_nondefault.swift @@ -18,6 +18,7 @@ distributed actor MyDistActor { return MainActor.sharedUnownedExecutor } +// // MyDistActor.init(actorSystem:) // CHECK: sil hidden @$s14default_deinit11MyDistActorC11actorSystemAC015FakeDistributedE7Systems0h9RoundtripeG0C_tcfc : $@convention(method) (@owned FakeRoundtripActorSystem, @owned MyDistActor) -> @owned MyDistActor // CHECK-NOT: [[BAD:%[0-9]+]] = builtin "initializeDefaultActor"(%1 : $MyDistActor) : $() // CHECK: [[ACTOR_INSTANCE:%[0-9]+]] = builtin "initializeNonDefaultDistributedActor"(%1 : $MyDistActor) : $() diff --git a/test/Runtime/demangleToMetadata.swift b/test/Runtime/demangleToMetadata.swift index 085672a6917ff..f904757d3543d 100644 --- a/test/Runtime/demangleToMetadata.swift +++ b/test/Runtime/demangleToMetadata.swift @@ -275,7 +275,7 @@ DemangleToMetadataTests.test("demangle built-in types") { expectEqual(Builtin.RawUnsafeContinuation.self, _typeByName("Bc")!) expectEqual(Builtin.Executor.self, _typeByName("Be")!) expectNotNil(_typeByName("BD")) - // FIXME: !!!! test for Bd + expectNotNil(_typeByName("Bd")) // NonDefaultDistributedActor storage expectEqual(Builtin.Job.self, _typeByName("Bj")!) }