Skip to content

Commit 5b027ca

Browse files
committed
Back-deploy creation of global-actor-qualified function type metadata.
When back-deploying, create global-actor-qualified function types via a separate entrypoint (`swift_getFunctionTypeMetadataGlobalActorBackDeploy`) in the compatibility library, which checks whether it is running with a new-enough runtime to use `swift_getFunctionTypeMetadataGlobalActor`. Failing that, it calls into a separate copy of the implementation that exists only in the back-deployed concurrency library. Fixes rdar://79153988.
1 parent 8cd8ca0 commit 5b027ca

File tree

7 files changed

+376
-3
lines changed

7 files changed

+376
-3
lines changed

include/swift/Runtime/RuntimeFunctions.def

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,24 @@ FUNCTION(GetFunctionMetadataGlobalActor,
634634
TypeMetadataPtrTy),
635635
ATTRS(NoUnwind, ReadOnly))
636636

637+
// Metadata *
638+
// swift_getFunctionTypeMetadataGlobalActorBackDeploy(unsigned long flags,
639+
// unsigned long diffKind,
640+
// const Metadata **parameters,
641+
// const uint32_t *parameterFlags,
642+
// const Metadata *result,
643+
// const Metadata *globalActor);
644+
FUNCTION(GetFunctionMetadataGlobalActorBackDeploy,
645+
swift_getFunctionTypeMetadataGlobalActorBackDeploy,
646+
C_CC, OpaqueTypeAvailability,
647+
RETURNS(TypeMetadataPtrTy),
648+
ARGS(SizeTy,
649+
SizeTy,
650+
TypeMetadataPtrTy->getPointerTo(0),
651+
Int32Ty->getPointerTo(0),
652+
TypeMetadataPtrTy,
653+
TypeMetadataPtrTy),
654+
ATTRS(NoUnwind, ReadOnly))
637655

638656
// Metadata *swift_getFunctionTypeMetadata0(unsigned long flags,
639657
// const Metadata *resultMetadata);

lib/IRGen/MetadataRequest.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1230,6 +1230,13 @@ static MetadataResponse emitTupleTypeMetadataRef(IRGenFunction &IGF,
12301230
}
12311231
}
12321232

1233+
/// Determine whether concurrency support is available in the runtime.
1234+
static bool isConcurrencyAvailable(ASTContext &ctx) {
1235+
auto deploymentAvailability =
1236+
AvailabilityContext::forDeploymentTarget(ctx);
1237+
return deploymentAvailability.isContainedIn(ctx.getConcurrencyAvailability());
1238+
}
1239+
12331240
namespace {
12341241
/// A visitor class for emitting a reference to a metatype object.
12351242
/// This implements a "raw" access, useful for implementing cache
@@ -1591,7 +1598,9 @@ namespace {
15911598
}
15921599

15931600
auto *getMetadataFn = type->getGlobalActor()
1594-
? IGF.IGM.getGetFunctionMetadataGlobalActorFn()
1601+
? (isConcurrencyAvailable(IGF.getSwiftModule()->getASTContext())
1602+
? IGF.IGM.getGetFunctionMetadataGlobalActorFn()
1603+
: IGF.IGM.getGetFunctionMetadataGlobalActorBackDeployFn())
15951604
: type->isDifferentiable()
15961605
? IGF.IGM.getGetFunctionMetadataDifferentiableFn()
15971606
: IGF.IGM.getGetFunctionMetadataFn();

stdlib/public/BackDeployConcurrency/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ set(swift_concurrency_install_component back-deployment)
4343
set(swift_concurrency_options
4444
BACK_DEPLOYMENT_LIBRARY 5.5
4545
DARWIN_INSTALL_NAME_DIR "@rpath")
46-
set(swift_concurrency_extra_sources "../BackDeployConcurrency/Exclusivity.cpp")
46+
set(swift_concurrency_extra_sources
47+
"../BackDeployConcurrency/Exclusivity.cpp"
48+
"../BackDeployConcurrency/Metadata.cpp")
4749

4850
add_subdirectory(../Concurrency stdlib/public/BackDeployConcurrency)
Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
//===--- Metadata.cpp - Exclusivity tracking ------------------------------===//
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 implements the runtime support for metadata accessors that aren't
14+
// available in Swift runtimes prior to macOS 12/iOS 15 era.
15+
//
16+
//===----------------------------------------------------------------------===//
17+
#include <cinttypes>
18+
19+
#include "swift/Runtime/Concurrent.h"
20+
#include "swift/Runtime/Metadata.h"
21+
22+
using namespace swift;
23+
24+
namespace swift {
25+
26+
SWIFT_EXPORT_FROM(swift_Concurrency)
27+
const FunctionTypeMetadata *
28+
swift_getFunctionTypeMetadataGlobalActorStandalone(
29+
FunctionTypeFlags flags, FunctionMetadataDifferentiabilityKind diffKind,
30+
const Metadata *const *parameters, const uint32_t *parameterFlags,
31+
const Metadata *result, const Metadata *globalActor);
32+
33+
}
34+
35+
namespace {
36+
37+
constexpr size_t roundUpToAlignment(size_t offset, size_t alignment) {
38+
return ((offset + alignment - 1) & ~(alignment - 1));
39+
}
40+
41+
class MetadataAllocator : public llvm::AllocatorBase<MetadataAllocator> {
42+
private:
43+
uint16_t Tag;
44+
45+
public:
46+
constexpr MetadataAllocator(uint16_t tag) : Tag(tag) {}
47+
MetadataAllocator() = delete;
48+
49+
void Reset() {}
50+
51+
LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t size, size_t alignment) {
52+
return malloc(size);
53+
}
54+
using AllocatorBase<MetadataAllocator>::Allocate;
55+
56+
void Deallocate(const void *Ptr, size_t size, size_t Alignment) {
57+
free(const_cast<void *>(Ptr));
58+
}
59+
using AllocatorBase<MetadataAllocator>::Deallocate;
60+
61+
void PrintStats() const {}
62+
63+
MetadataAllocator withTag(uint16_t Tag) {
64+
MetadataAllocator Allocator = *this;
65+
Allocator.Tag = Tag;
66+
return Allocator;
67+
}
68+
};
69+
70+
template <uint16_t StaticTag>
71+
class TaggedMetadataAllocator : public MetadataAllocator {
72+
public:
73+
constexpr TaggedMetadataAllocator() : MetadataAllocator(StaticTag) {}
74+
};
75+
76+
template <class EntryTy, uint16_t Tag>
77+
using SimpleGlobalCache =
78+
StableAddressConcurrentReadableHashMap<EntryTy,
79+
TaggedMetadataAllocator<Tag>>;
80+
81+
class FunctionCacheEntry {
82+
public:
83+
FullMetadata<FunctionTypeMetadata> Data;
84+
85+
struct Key {
86+
const FunctionTypeFlags Flags;
87+
const FunctionMetadataDifferentiabilityKind DifferentiabilityKind;
88+
const Metadata *const *Parameters;
89+
const uint32_t *ParameterFlags;
90+
const Metadata *Result;
91+
const Metadata *GlobalActor;
92+
93+
FunctionTypeFlags getFlags() const { return Flags; }
94+
95+
FunctionMetadataDifferentiabilityKind getDifferentiabilityKind() const {
96+
return DifferentiabilityKind;
97+
}
98+
99+
const Metadata *getParameter(unsigned index) const {
100+
assert(index < Flags.getNumParameters());
101+
return Parameters[index];
102+
}
103+
const Metadata *getResult() const { return Result; }
104+
105+
const uint32_t *getParameterFlags() const {
106+
return ParameterFlags;
107+
}
108+
109+
::ParameterFlags getParameterFlags(unsigned index) const {
110+
assert(index < Flags.getNumParameters());
111+
auto flags = Flags.hasParameterFlags() ? ParameterFlags[index] : 0;
112+
return ParameterFlags::fromIntValue(flags);
113+
}
114+
115+
const Metadata *getGlobalActor() const { return GlobalActor; }
116+
117+
friend llvm::hash_code hash_value(const Key &key) {
118+
auto hash = llvm::hash_combine(
119+
key.Flags.getIntValue(),
120+
key.DifferentiabilityKind.getIntValue(),
121+
key.Result, key.GlobalActor);
122+
for (unsigned i = 0, e = key.getFlags().getNumParameters(); i != e; ++i) {
123+
hash = llvm::hash_combine(hash, key.getParameter(i));
124+
hash = llvm::hash_combine(hash, key.getParameterFlags(i).getIntValue());
125+
}
126+
return hash;
127+
}
128+
};
129+
130+
FunctionCacheEntry(const Key &key);
131+
132+
intptr_t getKeyIntValueForDump() {
133+
return 0; // No single meaningful value here.
134+
}
135+
136+
bool matchesKey(const Key &key) const {
137+
if (key.getFlags().getIntValue() != Data.Flags.getIntValue())
138+
return false;
139+
if (key.getDifferentiabilityKind().Value !=
140+
Data.getDifferentiabilityKind().Value)
141+
return false;
142+
if (key.getResult() != Data.ResultType)
143+
return false;
144+
if (key.getGlobalActor() != Data.getGlobalActor())
145+
return false;
146+
for (unsigned i = 0, e = key.getFlags().getNumParameters(); i != e; ++i) {
147+
if (key.getParameter(i) != Data.getParameter(i))
148+
return false;
149+
if (key.getParameterFlags(i).getIntValue() !=
150+
Data.getParameterFlags(i).getIntValue())
151+
return false;
152+
}
153+
return true;
154+
}
155+
156+
friend llvm::hash_code hash_value(const FunctionCacheEntry &value) {
157+
Key key = {value.Data.Flags, value.Data.getDifferentiabilityKind(),
158+
value.Data.getParameters(), value.Data.getParameterFlags(),
159+
value.Data.ResultType, value.Data.getGlobalActor()};
160+
return hash_value(key);
161+
}
162+
163+
static size_t getExtraAllocationSize(const Key &key) {
164+
return getExtraAllocationSize(key.Flags);
165+
}
166+
167+
size_t getExtraAllocationSize() const {
168+
return getExtraAllocationSize(Data.Flags);
169+
}
170+
171+
static size_t getExtraAllocationSize(const FunctionTypeFlags &flags) {
172+
const auto numParams = flags.getNumParameters();
173+
auto size = numParams * sizeof(FunctionTypeMetadata::Parameter);
174+
if (flags.hasParameterFlags())
175+
size += numParams * sizeof(uint32_t);
176+
if (flags.isDifferentiable())
177+
size = roundUpToAlignment(size, sizeof(void *)) +
178+
sizeof(FunctionMetadataDifferentiabilityKind);
179+
if (flags.hasGlobalActor())
180+
size = roundUpToAlignment(size, sizeof(void *)) + sizeof(Metadata *);
181+
return roundUpToAlignment(size, sizeof(void *));
182+
}
183+
};
184+
185+
} // end anonymous namespace
186+
187+
FunctionCacheEntry::FunctionCacheEntry(const Key &key) {
188+
auto flags = key.getFlags();
189+
190+
// Pick a value witness table appropriate to the function convention.
191+
// All function types of a given convention have the same value semantics,
192+
// so they share a value witness table.
193+
switch (flags.getConvention()) {
194+
case FunctionMetadataConvention::Swift:
195+
if (!flags.isEscaping()) {
196+
Data.ValueWitnesses = &VALUE_WITNESS_SYM(NOESCAPE_FUNCTION_MANGLING);
197+
} else {
198+
Data.ValueWitnesses = &VALUE_WITNESS_SYM(FUNCTION_MANGLING);
199+
}
200+
break;
201+
202+
case FunctionMetadataConvention::Thin:
203+
case FunctionMetadataConvention::CFunctionPointer:
204+
Data.ValueWitnesses = &VALUE_WITNESS_SYM(THIN_FUNCTION_MANGLING);
205+
break;
206+
207+
case FunctionMetadataConvention::Block:
208+
#if SWIFT_OBJC_INTEROP
209+
// Blocks are ObjC objects, so can share the AnyObject value
210+
// witnesses (stored as "BO" rather than "yXl" for ABI compat).
211+
Data.ValueWitnesses = &VALUE_WITNESS_SYM(BO);
212+
#else
213+
assert(false && "objc block without objc interop?");
214+
#endif
215+
break;
216+
}
217+
218+
unsigned numParameters = flags.getNumParameters();
219+
220+
Data.setKind(MetadataKind::Function);
221+
Data.Flags = flags;
222+
Data.ResultType = key.getResult();
223+
if (flags.hasGlobalActor())
224+
*Data.getGlobalActorAddr() = key.getGlobalActor();
225+
if (flags.isDifferentiable())
226+
*Data.getDifferentiabilityKindAddress() = key.getDifferentiabilityKind();
227+
228+
for (unsigned i = 0; i < numParameters; ++i) {
229+
Data.getParameters()[i] = key.getParameter(i);
230+
if (flags.hasParameterFlags())
231+
Data.getParameterFlags()[i] = key.getParameterFlags(i).getIntValue();
232+
}
233+
}
234+
235+
// Provide a definition and static initializer for the fixed seed. This
236+
// initializer should always be zero to ensure its value can never appear to be
237+
// non-zero, even during dynamic initialization.
238+
uint64_t llvm::hashing::detail::fixed_seed_override = 0;
239+
240+
/// The uniquing structure for function type metadata with a global actor.
241+
static SimpleGlobalCache<FunctionCacheEntry, FunctionTypesTag> FunctionTypes;
242+
243+
const FunctionTypeMetadata *
244+
swift::swift_getFunctionTypeMetadataGlobalActorStandalone(
245+
FunctionTypeFlags flags, FunctionMetadataDifferentiabilityKind diffKind,
246+
const Metadata *const *parameters, const uint32_t *parameterFlags,
247+
const Metadata *result, const Metadata *globalActor) {
248+
assert(flags.hasGlobalActor());
249+
assert(flags.hasGlobalActor());
250+
FunctionCacheEntry::Key key = {
251+
flags, diffKind, parameters, parameterFlags, result, globalActor
252+
};
253+
return &FunctionTypes.getOrInsert(key).first->Data;
254+
255+
}

stdlib/toolchain/CompatibilityConcurrency/CompatibilityConcurrency.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,74 @@
99
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010
//
1111
//===----------------------------------------------------------------------===//
12+
#include "swift/Runtime/Metadata.h"
13+
#include <dispatch/dispatch.h>
14+
#include <dlfcn.h>
1215

1316
// Allow this library to get force-loaded by autolinking
1417
__attribute__((weak, visibility("hidden"))) extern "C" char
1518
_swift_FORCE_LOAD_$_swiftCompatibilityConcurrency = 0;
19+
using namespace swift;
20+
21+
namespace swift {
22+
23+
// Entrypoint provided by the runtime in the OS that first contains support for
24+
// concurrency. Explicitly redeclared as "weak" because this code will run on
25+
// systems where it is not present.
26+
const FunctionTypeMetadata *
27+
swift_getFunctionTypeMetadataGlobalActor(
28+
FunctionTypeFlags flags, FunctionMetadataDifferentiabilityKind diffKind,
29+
const Metadata *const *parameters, const uint32_t *parameterFlags,
30+
const Metadata *result, const Metadata *globalActor
31+
) SWIFT_RUNTIME_WEAK_IMPORT;
32+
33+
// Entrypoint provided only in the back-deployed concurrency library, which
34+
// has a separate allocation area for global-actor-qualified function types.
35+
extern "C"
36+
const FunctionTypeMetadata *
37+
swift_getFunctionTypeMetadataGlobalActorStandalone(
38+
FunctionTypeFlags flags, FunctionMetadataDifferentiabilityKind diffKind,
39+
const Metadata *const *parameters, const uint32_t *parameterFlags,
40+
const Metadata *result, const Metadata *globalActor
41+
) SWIFT_RUNTIME_WEAK_IMPORT;
42+
43+
// Entrypoint called by the compiler when back-deploying concurrency, which
44+
// switches between the real implementation of
45+
// swift_getFunctionTypeMetadataGlobalActor and
46+
// swift_getFunctionTypeMetadataGlobalActorStandalone depending on what system
47+
// it is running on.
48+
SWIFT_RUNTIME_STDLIB_INTERNAL
49+
const FunctionTypeMetadata *
50+
swift_getFunctionTypeMetadataGlobalActorBackDeploy(
51+
FunctionTypeFlags flags, FunctionMetadataDifferentiabilityKind diffKind,
52+
const Metadata *const *parameters, const uint32_t *parameterFlags,
53+
const Metadata *result, const Metadata *globalActor);
54+
55+
} // end namespace swift
56+
57+
const FunctionTypeMetadata *
58+
swift::swift_getFunctionTypeMetadataGlobalActorBackDeploy(
59+
FunctionTypeFlags flags, FunctionMetadataDifferentiabilityKind diffKind,
60+
const Metadata *const *parameters, const uint32_t *parameterFlags,
61+
const Metadata *result, const Metadata *globalActor) {
62+
using BuilderFn = const FunctionTypeMetadata *(*)(
63+
FunctionTypeFlags, FunctionMetadataDifferentiabilityKind,
64+
const Metadata *const *, const uint32_t *,
65+
const Metadata *, const Metadata *);
66+
static BuilderFn builderFn;
67+
static dispatch_once_t builderToken;
68+
dispatch_once(&builderToken, ^{
69+
if (swift_getFunctionTypeMetadataGlobalActor) {
70+
builderFn = swift_getFunctionTypeMetadataGlobalActor;
71+
return;
72+
}
73+
74+
builderFn = reinterpret_cast<BuilderFn>(
75+
dlsym(RTLD_DEFAULT,
76+
"swift_getFunctionTypeMetadataGlobalActorStandalone"));
77+
});
78+
79+
assert(builderFn && "No way to build global-actor-qualified function type");
80+
return builderFn(
81+
flags, diffKind, parameters, parameterFlags, result, globalActor);
82+
}

test/IRGen/global_actor_function_types.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ func globalActorMetatype<T>(_: T.Type) -> Any.Type {
1212
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc %swift.type* @"$s4test19globalActorMetatypeyypXpxmlF"
1313
// CHECK: [[MAIN_ACTOR_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$sScMMa"(i{{32|64}} 255)
1414
// CHECK-NEXT: [[MAIN_ACTOR_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[MAIN_ACTOR_RESPONSE]], 0
15-
// CHECK: call %swift.type* @swift_getFunctionTypeMetadataGlobalActor(i{{32|64}} 335544320, i{{32|64}} 0, %swift.type** null, i32* null, %swift.type* %T, %swift.type* [[MAIN_ACTOR_METADATA]])
15+
// CHECK: call %swift.type* @swift_getFunctionTypeMetadataGlobalActor{{.*}}(i{{32|64}} 335544320, i{{32|64}} 0, %swift.type** null, i32* null, %swift.type* %T, %swift.type* [[MAIN_ACTOR_METADATA]])
1616
sil [ossa] @$s4test19globalActorMetatypeyypXpxmlF : $@convention(thin) <T> (@thick T.Type) -> @thick Any.Type {
1717
bb0(%0 : $@thick T.Type):
1818
%2 = metatype $@thin (@MainActor () -> T).Type

0 commit comments

Comments
 (0)