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..e8b4a945b7b34 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_nonDefaultDistributedActor_initialize 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/Builtins.def b/include/swift/AST/Builtins.def index a452dfb1f4679..948126e0abd8d 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 extra storage state of 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/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/Runtime/Concurrency.h b/include/swift/Runtime/Concurrency.h index fb34a38bbcf01..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); @@ -821,7 +825,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/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/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..fcbd6bd1f8a24 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") @@ -2913,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); @@ -3022,6 +3025,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..efa9488b3cb2a 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 isNonDefaultExplicitDistributedActor(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/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/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..eeb8096bf9662 100644 --- a/lib/IRGen/StructLayout.cpp +++ b/lib/IRGen/StructLayout.cpp @@ -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. + 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/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/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/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 4fc286b0265dc..1584feca4eff9 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) { @@ -831,11 +843,21 @@ 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. + // + // 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/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/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/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/lib/Sema/DerivedConformanceDistributedActor.cpp b/lib/Sema/DerivedConformanceDistributedActor.cpp index 7178383a1d3af..96e0992b8fcb6 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" @@ -423,31 +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)); - - 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) { @@ -478,15 +457,15 @@ 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); 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); derived.addMemberToConformanceContext(propDecl, /*insertAtHead=*/true); + derived.addMemberToConformanceContext(pbDecl, /*insertAtHead==*/true); } return propDecl; @@ -571,10 +550,209 @@ 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); + + // 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 + 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 + 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 + derived.addMemberToConformanceContext(propertyPair.second, /*insertAtHead==*/true); + derived.addMemberToConformanceContext(property, /*insertAtHead==*/true); + } + + return property; +} + /******************************************************************************/ /**************************** 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)) { + 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) { + // we have found all the necessary fields, let's assert their order + 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. !! @@ -582,11 +760,15 @@ deriveDistributedActorType_SerializationRequirement( ValueDecl *DerivedConformance::deriveDistributedActor(ValueDecl *requirement) { if (auto var = dyn_cast(requirement)) { - if (var->getName() == Context.Id_id) - return deriveDistributedActor_id(*this); + ValueDecl *derivedValue = nullptr; + if (var->getName() == Context.Id_actorSystem) { + derivedValue = deriveDistributedActor_actorSystem(*this); + } else if (var->getName() == Context.Id_unownedExecutor) { + derivedValue = deriveDistributedActor_unownedExecutor(*this); + } - if (var->getName() == Context.Id_actorSystem) - return deriveDistributedActor_actorSystem(*this); + assertRequiredSynthesizedPropertyOrder(*this, derivedValue); + return derivedValue; } if (auto func = dyn_cast(requirement)) { @@ -605,6 +787,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 fc5389c82522f..a1420b418ddd8 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)) @@ -519,7 +524,6 @@ DerivedConformance::declareDerivedPropertyGetter(VarDecl *property, getterDecl->setIsTransparent(false); getterDecl->copyFormalAccessFrom(property); - return getterDecl; } 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. /// diff --git a/stdlib/public/Concurrency/Actor.cpp b/stdlib/public/Concurrency/Actor.cpp index 2025bf2178839..177e915687496 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())); } }; @@ -935,6 +935,39 @@ 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) { + this->isDistributedRemoteActor = isDistributedRemote; + SWIFT_TASK_DEBUG_LOG("Creating non-default distributed actor %p", this); + concurrency::trace::actor_create(this); + } + + /// 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 @@ -949,6 +982,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); } @@ -957,6 +996,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 ***********************/ /*****************************************************************************/ @@ -1688,14 +1734,17 @@ static bool isDefaultActorClass(const ClassMetadata *metadata) { 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()) { 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()) { + return false; + } } } @@ -1828,9 +1877,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 @@ -1936,35 +1987,49 @@ void swift::swift_executor_escalate(ExecutorRef executor, AsyncTask *task, /***************************** DISTRIBUTED ACTOR *****************************/ /*****************************************************************************/ +void swift::swift_nonDefaultDistributedActor_initialize(NonDefaultDistributedActor *_actor) { + asImpl(_actor)->initialize(); +} + 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)) { + auto actor = asImpl(reinterpret_cast(alloc)); + actor->initialize(/*remote*/true); + return reinterpret_cast(actor); + } else { + 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(DefaultActor *_actor) { - return asImpl(_actor)->isDistributedRemote(); +bool swift::swift_distributed_actor_is_remote(HeapObject *_actor) { + auto metadata = cast(_actor->metadata); + if (isDefaultActorClass(metadata)) { + return asImpl((DefaultActor *) _actor)->isDistributedRemote(); + } else { + return asImpl((NonDefaultDistributedActor *) _actor)->isDistributedRemote(); // NEW + } } bool DefaultActorImpl::isDistributedRemote() { 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/stdlib/public/Distributed/DistributedActor.swift b/stdlib/public/Distributed/DistributedActor.swift index 10e0e5e6b6752..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. /// @@ -257,6 +272,7 @@ 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 + } // ==== Hashable conformance --------------------------------------------------- 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/Distributed/Runtime/distributed_actor_custom_executor_basic.swift b/test/Distributed/Runtime/distributed_actor_custom_executor_basic.swift new file mode 100644 index 0000000000000..7011334dec523 --- /dev/null +++ b/test/Distributed/Runtime/distributed_actor_custom_executor_basic.swift @@ -0,0 +1,56 @@ +// 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 + + precondition(__isLocalActor(worker), "must be local") + + 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 + } +} 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..6c99a2c9efe41 --- /dev/null +++ b/test/Distributed/SIL/distributed_actor_initialize_nondefault.swift @@ -0,0 +1,26 @@ +// 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 + } + +// // 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 5143f9a330c7b..f904757d3543d 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")) + expectNotNil(_typeByName("Bd")) // NonDefaultDistributedActor storage expectEqual(Builtin.Job.self, _typeByName("Bj")!) }