Skip to content

Commit 3706644

Browse files
authored
Merge pull request swiftlang#34816 from rjmccall/actor-runtime
Implement a basic actor runtime, including queuing and switching
2 parents 8595bd6 + a53d83f commit 3706644

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+2787
-305
lines changed

cmake/modules/AddSwift.cmake

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,18 @@ function(_add_host_variant_c_compile_flags target)
248248
endif()
249249
endif()
250250

251+
# The concurrency library uses double-word atomics. MSVC's std::atomic
252+
# uses a spin lock for this, so to get reasonable behavior we have to
253+
# implement it ourselves using _InterlockedCompareExchange128.
254+
# clang-cl requires us to enable the `cx16` feature to use this intrinsic.
255+
if(SWIFT_HOST_VARIANT_SDK STREQUAL WINDOWS)
256+
if(SWIFT_HOST_VARIANT_ARCH STREQUAL x86_64)
257+
if(CMAKE_C_COMPILER_ID MATCHES Clang)
258+
target_compile_options(${target} PRIVATE -mcx16)
259+
endif()
260+
endif()
261+
endif()
262+
251263
if(LLVM_ENABLE_ASSERTIONS)
252264
target_compile_options(${target} PRIVATE -UNDEBUG)
253265
else()

include/swift/ABI/Actor.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
//===--- Actor.h - ABI structures for actors --------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Swift ABI describing actors.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_ABI_ACTOR_H
18+
#define SWIFT_ABI_ACTOR_H
19+
20+
#include "swift/ABI/HeapObject.h"
21+
#include "swift/ABI/MetadataValues.h"
22+
23+
namespace swift {
24+
25+
/// The default actor implementation. This is the layout of both
26+
/// the DefaultActor and NSDefaultActor classes.
27+
class alignas(Alignment_DefaultActor) DefaultActor : public HeapObject {
28+
public:
29+
// These constructors do not initialize the actor instance, and the
30+
// destructor does not destroy the actor instance; you must call
31+
// swift_defaultActor_{initialize,destroy} yourself.
32+
constexpr DefaultActor(const HeapMetadata *metadata)
33+
: HeapObject(metadata), PrivateData{} {}
34+
35+
constexpr DefaultActor(const HeapMetadata *metadata,
36+
InlineRefCounts::Immortal_t immortal)
37+
: HeapObject(metadata, immortal), PrivateData{} {}
38+
39+
void *PrivateData[NumWords_DefaultActor];
40+
};
41+
42+
} // end namespace swift
43+
44+
#endif

include/swift/ABI/Executor.h

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
//===--- Executor.h - ABI structures for executors --------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// Swift ABI describing executors.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#ifndef SWIFT_ABI_EXECUTOR_H
18+
#define SWIFT_ABI_EXECUTOR_H
19+
20+
#include <inttypes.h>
21+
22+
namespace swift {
23+
class AsyncContext;
24+
class AsyncTask;
25+
class DefaultActor;
26+
class Job;
27+
28+
/// An ExecutorRef isn't necessarily just a pointer to an executor
29+
/// object; it may have other bits set.
30+
class ExecutorRef {
31+
static constexpr uintptr_t IsDefaultActor = 1;
32+
static constexpr uintptr_t PointerMask = 7;
33+
34+
uintptr_t Value;
35+
36+
constexpr ExecutorRef(uintptr_t value) : Value(value) {}
37+
38+
public:
39+
/// A generic execution environment. When running in a generic
40+
/// environment, it's presumed to be okay to switch synchronously
41+
/// to an actor. As an executor request, this represents a request
42+
/// to drop whatever the current actor is.
43+
constexpr static ExecutorRef generic() {
44+
return ExecutorRef(0);
45+
}
46+
47+
/// Given a pointer to a default actor, return an executor reference
48+
/// for it.
49+
static ExecutorRef forDefaultActor(DefaultActor *actor) {
50+
assert(actor);
51+
return ExecutorRef(reinterpret_cast<uintptr_t>(actor) | IsDefaultActor);
52+
}
53+
54+
/// Is this the generic executor reference?
55+
bool isGeneric() const {
56+
return Value == 0;
57+
}
58+
59+
/// Is this a default-actor executor reference?
60+
bool isDefaultActor() const {
61+
return Value & IsDefaultActor;
62+
}
63+
DefaultActor *getDefaultActor() const {
64+
assert(isDefaultActor());
65+
return reinterpret_cast<DefaultActor*>(Value & ~PointerMask);
66+
}
67+
68+
/// Do we have to do any work to start running as the requested
69+
/// executor?
70+
bool mustSwitchToRun(ExecutorRef newExecutor) const {
71+
return *this != newExecutor;
72+
}
73+
74+
bool operator==(ExecutorRef other) const {
75+
return Value == other.Value;
76+
}
77+
bool operator!=(ExecutorRef other) const {
78+
return Value != other.Value;
79+
}
80+
};
81+
82+
using JobInvokeFunction =
83+
SWIFT_CC(swiftasync)
84+
void (Job *, ExecutorRef);
85+
86+
using TaskContinuationFunction =
87+
SWIFT_CC(swiftasync)
88+
void (AsyncTask *, ExecutorRef, AsyncContext *);
89+
90+
template <class Fn>
91+
struct AsyncFunctionTypeImpl;
92+
template <class Result, class... Params>
93+
struct AsyncFunctionTypeImpl<Result(Params...)> {
94+
// TODO: expand and include the arguments in the parameters.
95+
using type = TaskContinuationFunction;
96+
};
97+
98+
template <class Fn>
99+
using AsyncFunctionType = typename AsyncFunctionTypeImpl<Fn>::type;
100+
101+
/// A "function pointer" for an async function.
102+
///
103+
/// Eventually, this will always be signed with the data key
104+
/// using a type-specific discriminator.
105+
template <class FnType>
106+
class AsyncFunctionPointer {
107+
public:
108+
/// The function to run.
109+
RelativeDirectPointer<AsyncFunctionType<FnType>,
110+
/*nullable*/ false,
111+
int32_t> Function;
112+
113+
/// The expected size of the context.
114+
uint32_t ExpectedContextSize;
115+
};
116+
117+
}
118+
119+
#endif

include/swift/ABI/MetadataValues.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ enum {
4242

4343
/// The number of words in a yield-many coroutine buffer.
4444
NumWords_YieldManyBuffer = 8,
45+
46+
/// The number of words (in addition to the heap-object header)
47+
/// in a default actor.
48+
NumWords_DefaultActor = 10,
4549
};
4650

4751
struct InProcess;
@@ -114,6 +118,9 @@ enum class NominalTypeKind : uint32_t {
114118
/// The maximum supported type alignment.
115119
const size_t MaximumAlignment = 16;
116120

121+
/// The alignment of a DefaultActor.
122+
const size_t Alignment_DefaultActor = MaximumAlignment;
123+
117124
/// Flags stored in the value-witness table.
118125
template <typename int_type>
119126
class TargetValueWitnessFlags {
@@ -1885,7 +1892,11 @@ enum class JobKind : size_t {
18851892
Task = 0,
18861893

18871894
/// Job kinds >= 192 are private to the implementation.
1888-
First_Reserved = 192
1895+
First_Reserved = 192,
1896+
1897+
DefaultActorInline = First_Reserved,
1898+
DefaultActorSeparate,
1899+
DefaultActorOverride
18891900
};
18901901

18911902
/// The priority of a job. Higher priorities are larger values.
@@ -1920,6 +1931,10 @@ class JobFlags : public FlagSet<size_t> {
19201931

19211932
explicit JobFlags(size_t bits) : FlagSet(bits) {}
19221933
JobFlags(JobKind kind) { setKind(kind); }
1934+
JobFlags(JobKind kind, JobPriority priority) {
1935+
setKind(kind);
1936+
setPriority(priority);
1937+
}
19231938
constexpr JobFlags() {}
19241939

19251940
FLAGSET_DEFINE_FIELD_ACCESSORS(Kind, Kind_width, JobKind,

include/swift/ABI/Task.h

Lines changed: 11 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -18,75 +18,21 @@
1818
#define SWIFT_ABI_TASK_H
1919

2020
#include "swift/Basic/RelativePointer.h"
21+
#include "swift/ABI/Executor.h"
2122
#include "swift/ABI/HeapObject.h"
2223
#include "swift/ABI/Metadata.h"
2324
#include "swift/ABI/MetadataValues.h"
2425
#include "swift/Runtime/Config.h"
2526
#include "swift/Basic/STLExtras.h"
2627

2728
namespace swift {
28-
2929
class AsyncTask;
3030
class AsyncContext;
31-
class Executor;
3231
class Job;
3332
struct OpaqueValue;
3433
struct SwiftError;
3534
class TaskStatusRecord;
3635

37-
/// An ExecutorRef isn't necessarily just a pointer to an executor
38-
/// object; it may have other bits set.
39-
struct ExecutorRef {
40-
Executor *Pointer;
41-
42-
/// Get an executor ref that represents a lack of preference about
43-
/// where execution resumes. This is only valid in continuations,
44-
/// return contexts, and so on; it is not generally passed to
45-
/// executing functions.
46-
static ExecutorRef noPreference() {
47-
return { nullptr };
48-
}
49-
50-
bool operator==(ExecutorRef other) const {
51-
return Pointer == other.Pointer;
52-
}
53-
};
54-
55-
using JobInvokeFunction =
56-
SWIFT_CC(swift)
57-
void (Job *, ExecutorRef);
58-
59-
using TaskContinuationFunction =
60-
SWIFT_CC(swift)
61-
void (AsyncTask *, ExecutorRef, AsyncContext *);
62-
63-
template <class Fn>
64-
struct AsyncFunctionTypeImpl;
65-
template <class Result, class... Params>
66-
struct AsyncFunctionTypeImpl<Result(Params...)> {
67-
// TODO: expand and include the arguments in the parameters.
68-
using type = TaskContinuationFunction;
69-
};
70-
71-
template <class Fn>
72-
using AsyncFunctionType = typename AsyncFunctionTypeImpl<Fn>::type;
73-
74-
/// A "function pointer" for an async function.
75-
///
76-
/// Eventually, this will always be signed with the data key
77-
/// using a type-specific discriminator.
78-
template <class FnType>
79-
class AsyncFunctionPointer {
80-
public:
81-
/// The function to run.
82-
RelativeDirectPointer<AsyncFunctionType<FnType>,
83-
/*nullable*/ false,
84-
int32_t> Function;
85-
86-
/// The expected size of the context.
87-
uint32_t ExpectedContextSize;
88-
};
89-
9036
/// A schedulable job.
9137
class alignas(2 * alignof(void*)) Job {
9238
protected:
@@ -436,6 +382,16 @@ class alignas(MaximumAlignment) AsyncContext {
436382

437383
AsyncContext(const AsyncContext &) = delete;
438384
AsyncContext &operator=(const AsyncContext &) = delete;
385+
386+
/// Perform a return from this context.
387+
///
388+
/// Generally this should be tail-called.
389+
SWIFT_CC(swiftasync)
390+
void resumeParent(AsyncTask *task, ExecutorRef executor) {
391+
// TODO: destroy context before returning?
392+
// FIXME: force tail call
393+
return ResumeParent(task, executor, Parent);
394+
}
439395
};
440396

441397
/// An async context that supports yielding.

include/swift/AST/ASTContext.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ class ASTContext final {
580580

581581
// Retrieve the declaration of Swift._stdlib_isOSVersionAtLeast.
582582
FuncDecl *getIsOSVersionAtLeastDecl() const;
583-
583+
584584
/// Look for the declaration with the given name within the
585585
/// Swift module.
586586
void lookupInSwiftModule(StringRef name,

include/swift/AST/Decl.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3459,6 +3459,10 @@ enum class AncestryFlags : uint8_t {
34593459

34603460
/// The class or one of its superclasses requires stored property initializers.
34613461
RequiresStoredPropertyInits = (1<<6),
3462+
3463+
/// The class uses the ObjC object model (reference counting,
3464+
/// isa encoding, etc.).
3465+
ObjCObjectModel = (1<<7),
34623466
};
34633467

34643468
/// Return type of ClassDecl::checkAncestry(). Describes a set of interesting
@@ -3625,6 +3629,30 @@ class ClassDecl final : public NominalTypeDecl {
36253629
/// Whether the class is an actor.
36263630
bool isActor() const;
36273631

3632+
/// Whether the class is (known to be) a default actor.
3633+
bool isDefaultActor() const;
3634+
3635+
/// Whether the class is known to be a *root* default actor,
3636+
/// i.e. the first class in its hierarchy that is a default actor.
3637+
bool isRootDefaultActor() const;
3638+
3639+
/// Does this class explicitly declare any of the methods that
3640+
/// would prevent it from being a default actor?
3641+
bool hasExplicitCustomActorMethods() const;
3642+
3643+
/// Is this the NSObject class type?
3644+
bool isNSObject() const;
3645+
3646+
/// Whether the class directly inherits from NSObject but should use
3647+
/// Swift's native object model.
3648+
bool isNativeNSObjectSubclass() const;
3649+
3650+
/// Whether the class uses the ObjC object model (reference counting,
3651+
/// allocation, etc.) instead of the Swift model.
3652+
bool usesObjCObjectModel() const {
3653+
return checkAncestry(AncestryFlags::ObjCObjectModel);
3654+
}
3655+
36283656
/// Returns true if the class has designated initializers that are not listed
36293657
/// in its members.
36303658
///

include/swift/AST/DiagnosticsCommon.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ ERROR(generic_signature_not_equal,none,
103103
"generic signature %0 is not equal to new signature %1",
104104
(StringRef, StringRef))
105105

106+
// Used in diagnostics that are split across requests implemented in several places.
107+
ERROR(concurrency_default_actor_not_found,none,
108+
"broken standard library: cannot find default actor type '%0'", (StringRef))
109+
106110
// FIXME: Used by swift-api-digester. Don't want to set up a separate diagnostics
107111
// file just for a few errors.
108112
ERROR(sdk_node_unrecognized_key,none,

0 commit comments

Comments
 (0)