Skip to content

Commit 156264f

Browse files
committed
Make ExecutorRef two words.
1 parent 1370ec0 commit 156264f

File tree

16 files changed

+317
-77
lines changed

16 files changed

+317
-77
lines changed

include/swift/ABI/Executor.h

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define SWIFT_ABI_EXECUTOR_H
1919

2020
#include <inttypes.h>
21+
#include "swift/ABI/Actor.h"
2122
#include "swift/ABI/HeapObject.h"
2223
#include "swift/Runtime/Casting.h"
2324

@@ -31,79 +32,89 @@ class Job;
3132
SWIFT_EXPORT_FROM(swift_Concurrency)
3233
Metadata* MainActorMetadata;
3334

34-
/// An ExecutorRef isn't necessarily just a pointer to an executor
35-
/// object; it may have other bits set.
35+
/// An unmanaged reference to an executor.
36+
///
37+
/// The representation is two words: identity and implementation.
38+
/// The identity word is a reference to the executor object; for
39+
/// default actors, this is the actor object. The implementation
40+
/// word describes how the executor works; it carries a witness table
41+
/// as well as a small number of bits indicating various special
42+
/// implementation properties. As an exception to both of these
43+
/// rules, a null identity represents a generic executor and
44+
/// implies a null implementation word.
3645
class ExecutorRef {
37-
static constexpr uintptr_t IsDefaultActor = 1;
38-
static constexpr uintptr_t PointerMask = 7;
39-
40-
uintptr_t Value;
46+
HeapObject *Identity; // Not necessarily Swift reference-countable
47+
uintptr_t Implementation;
4148

42-
constexpr ExecutorRef(uintptr_t value) : Value(value) {}
49+
constexpr ExecutorRef(HeapObject *identity, uintptr_t implementation)
50+
: Identity(identity), Implementation(implementation) {}
4351

4452
public:
4553
/// A generic execution environment. When running in a generic
4654
/// environment, it's presumed to be okay to switch synchronously
4755
/// to an actor. As an executor request, this represents a request
4856
/// to drop whatever the current actor is.
4957
constexpr static ExecutorRef generic() {
50-
return ExecutorRef(0);
58+
return ExecutorRef(nullptr, 0);
5159
}
5260

5361
/// FIXME: only exists for the quick-and-dirty MainActor implementation.
5462
/// NOTE: I didn't go with Executor::forMainActor(DefaultActor*) because
5563
/// __swift_run_job_main_executor can't take more than one argument.
56-
constexpr static ExecutorRef mainExecutor() {
57-
return ExecutorRef(2);
64+
static ExecutorRef mainExecutor() {
65+
auto identity = getMainActorIdentity();
66+
return ExecutorRef(identity, 0);
67+
}
68+
static HeapObject *getMainActorIdentity() {
69+
return reinterpret_cast<HeapObject*>(
70+
ExecutorRefFlags::MainActorIdentity);
5871
}
5972

6073
/// Given a pointer to a default actor, return an executor reference
6174
/// for it.
6275
static ExecutorRef forDefaultActor(DefaultActor *actor) {
6376
assert(actor);
64-
return ExecutorRef(reinterpret_cast<uintptr_t>(actor) | IsDefaultActor);
77+
return ExecutorRef(actor, unsigned(ExecutorRefFlags::DefaultActor));
78+
}
79+
80+
HeapObject *getIdentity() const {
81+
return Identity;
6582
}
6683

6784
/// Is this the generic executor reference?
6885
bool isGeneric() const {
69-
return Value == 0;
86+
return Identity == 0;
7087
}
7188

7289
/// FIXME: only exists for the quick-and-dirty MainActor implementation.
7390
bool isMainExecutor() const {
74-
if (Value == ExecutorRef::mainExecutor().Value)
91+
if (Identity == getMainActorIdentity())
7592
return true;
7693

77-
HeapObject *heapObj = reinterpret_cast<HeapObject*>(Value & ~PointerMask);
78-
79-
if (heapObj == nullptr || MainActorMetadata == nullptr)
94+
if (Identity == nullptr || MainActorMetadata == nullptr)
8095
return false;
8196

82-
Metadata const* metadata = swift_getObjectType(heapObj);
97+
Metadata const* metadata = swift_getObjectType(Identity);
8398
return metadata == MainActorMetadata;
8499
}
85100

86101
/// Is this a default-actor executor reference?
87102
bool isDefaultActor() const {
88-
return Value & IsDefaultActor;
103+
return Implementation & unsigned(ExecutorRefFlags::DefaultActor);
89104
}
90105
DefaultActor *getDefaultActor() const {
91106
assert(isDefaultActor());
92-
return reinterpret_cast<DefaultActor*>(Value & ~PointerMask);
93-
}
94-
95-
uintptr_t getRawValue() const {
96-
return Value;
107+
return reinterpret_cast<DefaultActor*>(Identity);
97108
}
98109

99110
/// Do we have to do any work to start running as the requested
100111
/// executor?
101112
bool mustSwitchToRun(ExecutorRef newExecutor) const {
102-
return *this != newExecutor;
113+
return Identity != newExecutor.Identity;
103114
}
104115

105116
bool operator==(ExecutorRef other) const {
106-
return Value == other.Value
117+
return Identity == other.Identity
107118
/// FIXME: only exists for the quick-and-dirty MainActor implementation.
108119
|| (isMainExecutor() && other.isMainExecutor());
109120
}

include/swift/ABI/MetadataValues.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2166,6 +2166,20 @@ enum class ContinuationStatus : size_t {
21662166
Resumed = 2
21672167
};
21682168

2169+
/// Flags describing the executor implementation that are stored
2170+
/// in the ExecutorRef.
2171+
enum class ExecutorRefFlags : size_t {
2172+
// The number of bits available here is very limited because it's
2173+
// potentially just the alignment bits of a protocol witness table
2174+
// pointer
2175+
2176+
/// The executor is a default actor.
2177+
DefaultActor = 0x1,
2178+
2179+
/// TODO: remove this
2180+
MainActorIdentity = 0x2,
2181+
};
2182+
21692183
} // end namespace swift
21702184

21712185
#endif // SWIFT_ABI_METADATAVALUES_H

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,7 +1595,7 @@ FUNCTION(TaskSwitchFunc,
15951595
swift_task_switch, SwiftAsyncCC,
15961596
ConcurrencyAvailability,
15971597
RETURNS(VoidTy),
1598-
ARGS(SwiftContextPtrTy, Int8PtrTy, SwiftExecutorPtrTy),
1598+
ARGS(SwiftContextPtrTy, Int8PtrTy, ExecutorFirstTy, ExecutorSecondTy),
15991599
ATTRS(NoUnwind))
16001600

16011601
// AsyncTask *swift_continuation_init(AsyncContext *continuationContext,
@@ -1636,7 +1636,7 @@ FUNCTION(ContinuationThrowingResumeWithError,
16361636
FUNCTION(TaskGetCurrentExecutor,
16371637
swift_task_getCurrentExecutor, SwiftCC,
16381638
ConcurrencyAvailability,
1639-
RETURNS(IntPtrTy),
1639+
RETURNS(SwiftExecutorTy),
16401640
ARGS(),
16411641
ATTRS(NoUnwind, ArgMemOnly))
16421642

lib/IRGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ add_swift_host_library(swiftIRGen STATIC
1616
GenConstant.cpp
1717
GenControl.cpp
1818
GenCoverage.cpp
19+
GenConcurrency.cpp
1920
GenDecl.cpp
2021
GenDiffFunc.cpp
2122
GenDiffWitness.cpp

lib/IRGen/GenBuiltin.cpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "Explosion.h"
2929
#include "GenCall.h"
3030
#include "GenCast.h"
31+
#include "GenConcurrency.h"
3132
#include "GenPointerAuth.h"
3233
#include "GenIntegerLiteral.h"
3334
#include "IRGenFunction.h"
@@ -221,11 +222,7 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
221222

222223
// getCurrentActor has no arguments.
223224
if (Builtin.ID == BuiltinValueKind::GetCurrentExecutor) {
224-
auto *call = IGF.Builder.CreateCall(IGF.IGM.getTaskGetCurrentExecutorFn(),
225-
{});
226-
call->setDoesNotThrow();
227-
call->setCallingConv(IGF.IGM.SwiftCC);
228-
out.add(call);
225+
emitGetCurrentExecutor(IGF, out);
229226
return;
230227
}
231228

@@ -307,10 +304,8 @@ void irgen::emitBuiltinCall(IRGenFunction &IGF, const BuiltinInfo &Builtin,
307304
}
308305

309306
if (Builtin.ID == BuiltinValueKind::BuildSerialExecutorRef) {
310-
auto executor = args.claimNext();
311-
executor = IGF.Builder.CreateBitCast(executor,
312-
IGF.IGM.SwiftExecutorPtrTy);
313-
out.add(executor);
307+
auto actor = args.claimNext();
308+
emitBuildSerialExecutorRef(IGF, actor, argTypes[0], out);
314309
return;
315310
}
316311

lib/IRGen/GenCall.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1971,12 +1971,19 @@ void irgen::extractScalarResults(IRGenFunction &IGF, llvm::Type *bodyType,
19711971
returned = IGF.coerceValue(returned, bodyType, IGF.IGM.DataLayout);
19721972

19731973
if (auto *structType = dyn_cast<llvm::StructType>(bodyType))
1974-
for (unsigned i = 0, e = structType->getNumElements(); i != e; ++i)
1975-
out.add(IGF.Builder.CreateExtractValue(returned, i));
1974+
IGF.emitAllExtractValues(returned, structType, out);
19761975
else
19771976
out.add(returned);
19781977
}
19791978

1979+
void IRGenFunction::emitAllExtractValues(llvm::Value *value,
1980+
llvm::StructType *structType,
1981+
Explosion &out) {
1982+
assert(value->getType() == structType);
1983+
for (unsigned i = 0, e = structType->getNumElements(); i != e; ++i)
1984+
out.add(Builder.CreateExtractValue(value, i));
1985+
}
1986+
19801987
std::pair<llvm::Value *, llvm::Value *> irgen::getAsyncFunctionAndSize(
19811988
IRGenFunction &IGF, SILFunctionTypeRepresentation representation,
19821989
FunctionPointer functionPointer, llvm::Value *thickContext,

lib/IRGen/GenConcurrency.cpp

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
//===--- GenConcurrency.cpp - IRGen for concurrency features --------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 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+
// This file implements IR generation for concurrency features (other than
14+
// basic async function lowering, which is more spread out).
15+
//
16+
//===----------------------------------------------------------------------===//
17+
18+
#include "GenConcurrency.h"
19+
20+
#include "BitPatternBuilder.h"
21+
#include "ExtraInhabitants.h"
22+
#include "GenType.h"
23+
#include "IRGenFunction.h"
24+
#include "IRGenModule.h"
25+
#include "LoadableTypeInfo.h"
26+
#include "ScalarPairTypeInfo.h"
27+
#include "swift/ABI/MetadataValues.h"
28+
29+
using namespace swift;
30+
using namespace irgen;
31+
32+
namespace {
33+
34+
/// A TypeInfo implementation for Builtin.Executor.
35+
class ExecutorTypeInfo :
36+
public TrivialScalarPairTypeInfo<ExecutorTypeInfo, LoadableTypeInfo> {
37+
38+
public:
39+
ExecutorTypeInfo(llvm::StructType *storageType,
40+
Size size, Alignment align, SpareBitVector &&spareBits)
41+
: TrivialScalarPairTypeInfo(storageType, size, std::move(spareBits),
42+
align, IsPOD, IsFixedSize) {}
43+
44+
static Size getFirstElementSize(IRGenModule &IGM) {
45+
return IGM.getPointerSize();
46+
}
47+
static StringRef getFirstElementLabel() {
48+
return ".identity";
49+
}
50+
51+
TypeLayoutEntry *buildTypeLayoutEntry(IRGenModule &IGM,
52+
SILType T) const override {
53+
return IGM.typeLayoutCache.getOrCreateScalarEntry(*this, T);
54+
}
55+
56+
static Size getSecondElementOffset(IRGenModule &IGM) {
57+
return IGM.getPointerSize();
58+
}
59+
static Size getSecondElementSize(IRGenModule &IGM) {
60+
return IGM.getPointerSize();
61+
}
62+
static StringRef getSecondElementLabel() {
63+
return ".impl";
64+
}
65+
66+
// The identity pointer is a heap object reference, but it's
67+
// nullable because of the generic executor.
68+
bool mayHaveExtraInhabitants(IRGenModule &IGM) const override {
69+
return true;
70+
}
71+
72+
PointerInfo getPointerInfo(IRGenModule &IGM) const {
73+
return PointerInfo::forHeapObject(IGM).withNullable(IsNullable);
74+
}
75+
unsigned getFixedExtraInhabitantCount(IRGenModule &IGM) const override {
76+
return getPointerInfo(IGM).getExtraInhabitantCount(IGM);
77+
}
78+
APInt getFixedExtraInhabitantValue(IRGenModule &IGM,
79+
unsigned bits,
80+
unsigned index) const override {
81+
return getPointerInfo(IGM)
82+
.getFixedExtraInhabitantValue(IGM, bits, index, 0);
83+
}
84+
llvm::Value *getExtraInhabitantIndex(IRGenFunction &IGF, Address src,
85+
SILType T,
86+
bool isOutlined) const override {
87+
src = projectFirstElement(IGF, src);
88+
return getPointerInfo(IGF.IGM).getExtraInhabitantIndex(IGF, src);
89+
}
90+
APInt getFixedExtraInhabitantMask(IRGenModule &IGM) const override {
91+
auto pointerSize = IGM.getPointerSize();
92+
auto mask = BitPatternBuilder(IGM.Triple.isLittleEndian());
93+
mask.appendSetBits(pointerSize.getValueInBits());
94+
mask.appendClearBits(pointerSize.getValueInBits());
95+
return mask.build().getValue();
96+
}
97+
void storeExtraInhabitant(IRGenFunction &IGF, llvm::Value *index,
98+
Address dest, SILType T,
99+
bool isOutlined) const override {
100+
dest = projectFirstElement(IGF, dest);
101+
getPointerInfo(IGF.IGM).storeExtraInhabitant(IGF, index, dest);
102+
}
103+
};
104+
105+
} // end anonymous namespace
106+
107+
const LoadableTypeInfo &IRGenModule::getExecutorTypeInfo() {
108+
return Types.getExecutorTypeInfo();
109+
}
110+
111+
const LoadableTypeInfo &TypeConverter::getExecutorTypeInfo() {
112+
if (ExecutorTI) return *ExecutorTI;
113+
114+
auto ty = IGM.SwiftExecutorTy;
115+
116+
SpareBitVector spareBits;
117+
spareBits.append(IGM.getHeapObjectSpareBits());
118+
spareBits.appendClearBits(IGM.getPointerSize().getValueInBits());
119+
120+
ExecutorTI =
121+
new ExecutorTypeInfo(ty, IGM.getPointerSize() * 2,
122+
IGM.getPointerAlignment(),
123+
std::move(spareBits));
124+
ExecutorTI->NextConverted = FirstType;
125+
FirstType = ExecutorTI;
126+
return *ExecutorTI;
127+
}
128+
129+
void irgen::emitBuildSerialExecutorRef(IRGenFunction &IGF,
130+
llvm::Value *actor,
131+
SILType actorType,
132+
Explosion &out) {
133+
auto cls = actorType.getClassOrBoundGenericClass();
134+
135+
// HACK: if the actor type is Swift.MainActor, treat it specially.
136+
if (cls && cls->getNameStr() == "MainActor" &&
137+
cls->getDeclContext()->isModuleScopeContext() &&
138+
cls->getModuleContext()->getName().str() == SWIFT_CONCURRENCY_NAME) {
139+
llvm::Value *identity = llvm::ConstantInt::get(IGF.IGM.SizeTy,
140+
unsigned(ExecutorRefFlags::MainActorIdentity));
141+
identity = IGF.Builder.CreateIntToPtr(identity, IGF.IGM.ExecutorFirstTy);
142+
out.add(identity);
143+
144+
llvm::Value *impl = IGF.IGM.getSize(Size(0));
145+
out.add(impl);
146+
return;
147+
}
148+
149+
llvm::Value *identity =
150+
IGF.Builder.CreateBitCast(actor, IGF.IGM.ExecutorFirstTy);
151+
llvm::Value *impl = IGF.IGM.getSize(Size(0));
152+
153+
unsigned flags = 0;
154+
155+
// FIXME: this isn't how we should be doing any of this
156+
flags |= unsigned(ExecutorRefFlags::DefaultActor);
157+
158+
if (flags) {
159+
impl = IGF.Builder.CreateOr(impl, IGF.IGM.getSize(Size(flags)));
160+
}
161+
out.add(identity);
162+
out.add(impl);
163+
}
164+
165+
void irgen::emitGetCurrentExecutor(IRGenFunction &IGF, Explosion &out) {
166+
auto *call = IGF.Builder.CreateCall(IGF.IGM.getTaskGetCurrentExecutorFn(),
167+
{});
168+
call->setDoesNotThrow();
169+
call->setCallingConv(IGF.IGM.SwiftCC);
170+
171+
IGF.emitAllExtractValues(call, IGF.IGM.SwiftExecutorTy, out);
172+
}

0 commit comments

Comments
 (0)