mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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.
This commit is contained in:
@@ -634,6 +634,24 @@ FUNCTION(GetFunctionMetadataGlobalActor,
|
||||
TypeMetadataPtrTy),
|
||||
ATTRS(NoUnwind, ReadOnly))
|
||||
|
||||
// Metadata *
|
||||
// swift_getFunctionTypeMetadataGlobalActorBackDeploy(unsigned long flags,
|
||||
// unsigned long diffKind,
|
||||
// const Metadata **parameters,
|
||||
// const uint32_t *parameterFlags,
|
||||
// const Metadata *result,
|
||||
// const Metadata *globalActor);
|
||||
FUNCTION(GetFunctionMetadataGlobalActorBackDeploy,
|
||||
swift_getFunctionTypeMetadataGlobalActorBackDeploy,
|
||||
C_CC, OpaqueTypeAvailability,
|
||||
RETURNS(TypeMetadataPtrTy),
|
||||
ARGS(SizeTy,
|
||||
SizeTy,
|
||||
TypeMetadataPtrTy->getPointerTo(0),
|
||||
Int32Ty->getPointerTo(0),
|
||||
TypeMetadataPtrTy,
|
||||
TypeMetadataPtrTy),
|
||||
ATTRS(NoUnwind, ReadOnly))
|
||||
|
||||
// Metadata *swift_getFunctionTypeMetadata0(unsigned long flags,
|
||||
// const Metadata *resultMetadata);
|
||||
|
||||
@@ -1230,6 +1230,13 @@ static MetadataResponse emitTupleTypeMetadataRef(IRGenFunction &IGF,
|
||||
}
|
||||
}
|
||||
|
||||
/// Determine whether concurrency support is available in the runtime.
|
||||
static bool isConcurrencyAvailable(ASTContext &ctx) {
|
||||
auto deploymentAvailability =
|
||||
AvailabilityContext::forDeploymentTarget(ctx);
|
||||
return deploymentAvailability.isContainedIn(ctx.getConcurrencyAvailability());
|
||||
}
|
||||
|
||||
namespace {
|
||||
/// A visitor class for emitting a reference to a metatype object.
|
||||
/// This implements a "raw" access, useful for implementing cache
|
||||
@@ -1591,7 +1598,9 @@ namespace {
|
||||
}
|
||||
|
||||
auto *getMetadataFn = type->getGlobalActor()
|
||||
? IGF.IGM.getGetFunctionMetadataGlobalActorFn()
|
||||
? (isConcurrencyAvailable(IGF.getSwiftModule()->getASTContext())
|
||||
? IGF.IGM.getGetFunctionMetadataGlobalActorFn()
|
||||
: IGF.IGM.getGetFunctionMetadataGlobalActorBackDeployFn())
|
||||
: type->isDifferentiable()
|
||||
? IGF.IGM.getGetFunctionMetadataDifferentiableFn()
|
||||
: IGF.IGM.getGetFunctionMetadataFn();
|
||||
|
||||
@@ -43,6 +43,8 @@ set(swift_concurrency_install_component back-deployment)
|
||||
set(swift_concurrency_options
|
||||
BACK_DEPLOYMENT_LIBRARY 5.5
|
||||
DARWIN_INSTALL_NAME_DIR "@rpath")
|
||||
set(swift_concurrency_extra_sources "../BackDeployConcurrency/Exclusivity.cpp")
|
||||
set(swift_concurrency_extra_sources
|
||||
"../BackDeployConcurrency/Exclusivity.cpp"
|
||||
"../BackDeployConcurrency/Metadata.cpp")
|
||||
|
||||
add_subdirectory(../Concurrency stdlib/public/BackDeployConcurrency)
|
||||
|
||||
255
stdlib/public/BackDeployConcurrency/Metadata.cpp
Normal file
255
stdlib/public/BackDeployConcurrency/Metadata.cpp
Normal file
@@ -0,0 +1,255 @@
|
||||
//===--- Metadata.cpp - Exclusivity tracking ------------------------------===//
|
||||
//
|
||||
// This source file is part of the Swift.org open source project
|
||||
//
|
||||
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
||||
// Licensed under Apache License v2.0 with Runtime Library Exception
|
||||
//
|
||||
// See https://swift.org/LICENSE.txt for license information
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This implements the runtime support for metadata accessors that aren't
|
||||
// available in Swift runtimes prior to macOS 12/iOS 15 era.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include <cinttypes>
|
||||
|
||||
#include "swift/Runtime/Concurrent.h"
|
||||
#include "swift/Runtime/Metadata.h"
|
||||
|
||||
using namespace swift;
|
||||
|
||||
namespace swift {
|
||||
|
||||
SWIFT_EXPORT_FROM(swift_Concurrency)
|
||||
const FunctionTypeMetadata *
|
||||
swift_getFunctionTypeMetadataGlobalActorStandalone(
|
||||
FunctionTypeFlags flags, FunctionMetadataDifferentiabilityKind diffKind,
|
||||
const Metadata *const *parameters, const uint32_t *parameterFlags,
|
||||
const Metadata *result, const Metadata *globalActor);
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr size_t roundUpToAlignment(size_t offset, size_t alignment) {
|
||||
return ((offset + alignment - 1) & ~(alignment - 1));
|
||||
}
|
||||
|
||||
class MetadataAllocator : public llvm::AllocatorBase<MetadataAllocator> {
|
||||
private:
|
||||
uint16_t Tag;
|
||||
|
||||
public:
|
||||
constexpr MetadataAllocator(uint16_t tag) : Tag(tag) {}
|
||||
MetadataAllocator() = delete;
|
||||
|
||||
void Reset() {}
|
||||
|
||||
LLVM_ATTRIBUTE_RETURNS_NONNULL void *Allocate(size_t size, size_t alignment) {
|
||||
return malloc(size);
|
||||
}
|
||||
using AllocatorBase<MetadataAllocator>::Allocate;
|
||||
|
||||
void Deallocate(const void *Ptr, size_t size, size_t Alignment) {
|
||||
free(const_cast<void *>(Ptr));
|
||||
}
|
||||
using AllocatorBase<MetadataAllocator>::Deallocate;
|
||||
|
||||
void PrintStats() const {}
|
||||
|
||||
MetadataAllocator withTag(uint16_t Tag) {
|
||||
MetadataAllocator Allocator = *this;
|
||||
Allocator.Tag = Tag;
|
||||
return Allocator;
|
||||
}
|
||||
};
|
||||
|
||||
template <uint16_t StaticTag>
|
||||
class TaggedMetadataAllocator : public MetadataAllocator {
|
||||
public:
|
||||
constexpr TaggedMetadataAllocator() : MetadataAllocator(StaticTag) {}
|
||||
};
|
||||
|
||||
template <class EntryTy, uint16_t Tag>
|
||||
using SimpleGlobalCache =
|
||||
StableAddressConcurrentReadableHashMap<EntryTy,
|
||||
TaggedMetadataAllocator<Tag>>;
|
||||
|
||||
class FunctionCacheEntry {
|
||||
public:
|
||||
FullMetadata<FunctionTypeMetadata> Data;
|
||||
|
||||
struct Key {
|
||||
const FunctionTypeFlags Flags;
|
||||
const FunctionMetadataDifferentiabilityKind DifferentiabilityKind;
|
||||
const Metadata *const *Parameters;
|
||||
const uint32_t *ParameterFlags;
|
||||
const Metadata *Result;
|
||||
const Metadata *GlobalActor;
|
||||
|
||||
FunctionTypeFlags getFlags() const { return Flags; }
|
||||
|
||||
FunctionMetadataDifferentiabilityKind getDifferentiabilityKind() const {
|
||||
return DifferentiabilityKind;
|
||||
}
|
||||
|
||||
const Metadata *getParameter(unsigned index) const {
|
||||
assert(index < Flags.getNumParameters());
|
||||
return Parameters[index];
|
||||
}
|
||||
const Metadata *getResult() const { return Result; }
|
||||
|
||||
const uint32_t *getParameterFlags() const {
|
||||
return ParameterFlags;
|
||||
}
|
||||
|
||||
::ParameterFlags getParameterFlags(unsigned index) const {
|
||||
assert(index < Flags.getNumParameters());
|
||||
auto flags = Flags.hasParameterFlags() ? ParameterFlags[index] : 0;
|
||||
return ParameterFlags::fromIntValue(flags);
|
||||
}
|
||||
|
||||
const Metadata *getGlobalActor() const { return GlobalActor; }
|
||||
|
||||
friend llvm::hash_code hash_value(const Key &key) {
|
||||
auto hash = llvm::hash_combine(
|
||||
key.Flags.getIntValue(),
|
||||
key.DifferentiabilityKind.getIntValue(),
|
||||
key.Result, key.GlobalActor);
|
||||
for (unsigned i = 0, e = key.getFlags().getNumParameters(); i != e; ++i) {
|
||||
hash = llvm::hash_combine(hash, key.getParameter(i));
|
||||
hash = llvm::hash_combine(hash, key.getParameterFlags(i).getIntValue());
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
};
|
||||
|
||||
FunctionCacheEntry(const Key &key);
|
||||
|
||||
intptr_t getKeyIntValueForDump() {
|
||||
return 0; // No single meaningful value here.
|
||||
}
|
||||
|
||||
bool matchesKey(const Key &key) const {
|
||||
if (key.getFlags().getIntValue() != Data.Flags.getIntValue())
|
||||
return false;
|
||||
if (key.getDifferentiabilityKind().Value !=
|
||||
Data.getDifferentiabilityKind().Value)
|
||||
return false;
|
||||
if (key.getResult() != Data.ResultType)
|
||||
return false;
|
||||
if (key.getGlobalActor() != Data.getGlobalActor())
|
||||
return false;
|
||||
for (unsigned i = 0, e = key.getFlags().getNumParameters(); i != e; ++i) {
|
||||
if (key.getParameter(i) != Data.getParameter(i))
|
||||
return false;
|
||||
if (key.getParameterFlags(i).getIntValue() !=
|
||||
Data.getParameterFlags(i).getIntValue())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
friend llvm::hash_code hash_value(const FunctionCacheEntry &value) {
|
||||
Key key = {value.Data.Flags, value.Data.getDifferentiabilityKind(),
|
||||
value.Data.getParameters(), value.Data.getParameterFlags(),
|
||||
value.Data.ResultType, value.Data.getGlobalActor()};
|
||||
return hash_value(key);
|
||||
}
|
||||
|
||||
static size_t getExtraAllocationSize(const Key &key) {
|
||||
return getExtraAllocationSize(key.Flags);
|
||||
}
|
||||
|
||||
size_t getExtraAllocationSize() const {
|
||||
return getExtraAllocationSize(Data.Flags);
|
||||
}
|
||||
|
||||
static size_t getExtraAllocationSize(const FunctionTypeFlags &flags) {
|
||||
const auto numParams = flags.getNumParameters();
|
||||
auto size = numParams * sizeof(FunctionTypeMetadata::Parameter);
|
||||
if (flags.hasParameterFlags())
|
||||
size += numParams * sizeof(uint32_t);
|
||||
if (flags.isDifferentiable())
|
||||
size = roundUpToAlignment(size, sizeof(void *)) +
|
||||
sizeof(FunctionMetadataDifferentiabilityKind);
|
||||
if (flags.hasGlobalActor())
|
||||
size = roundUpToAlignment(size, sizeof(void *)) + sizeof(Metadata *);
|
||||
return roundUpToAlignment(size, sizeof(void *));
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
FunctionCacheEntry::FunctionCacheEntry(const Key &key) {
|
||||
auto flags = key.getFlags();
|
||||
|
||||
// Pick a value witness table appropriate to the function convention.
|
||||
// All function types of a given convention have the same value semantics,
|
||||
// so they share a value witness table.
|
||||
switch (flags.getConvention()) {
|
||||
case FunctionMetadataConvention::Swift:
|
||||
if (!flags.isEscaping()) {
|
||||
Data.ValueWitnesses = &VALUE_WITNESS_SYM(NOESCAPE_FUNCTION_MANGLING);
|
||||
} else {
|
||||
Data.ValueWitnesses = &VALUE_WITNESS_SYM(FUNCTION_MANGLING);
|
||||
}
|
||||
break;
|
||||
|
||||
case FunctionMetadataConvention::Thin:
|
||||
case FunctionMetadataConvention::CFunctionPointer:
|
||||
Data.ValueWitnesses = &VALUE_WITNESS_SYM(THIN_FUNCTION_MANGLING);
|
||||
break;
|
||||
|
||||
case FunctionMetadataConvention::Block:
|
||||
#if SWIFT_OBJC_INTEROP
|
||||
// Blocks are ObjC objects, so can share the AnyObject value
|
||||
// witnesses (stored as "BO" rather than "yXl" for ABI compat).
|
||||
Data.ValueWitnesses = &VALUE_WITNESS_SYM(BO);
|
||||
#else
|
||||
assert(false && "objc block without objc interop?");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned numParameters = flags.getNumParameters();
|
||||
|
||||
Data.setKind(MetadataKind::Function);
|
||||
Data.Flags = flags;
|
||||
Data.ResultType = key.getResult();
|
||||
if (flags.hasGlobalActor())
|
||||
*Data.getGlobalActorAddr() = key.getGlobalActor();
|
||||
if (flags.isDifferentiable())
|
||||
*Data.getDifferentiabilityKindAddress() = key.getDifferentiabilityKind();
|
||||
|
||||
for (unsigned i = 0; i < numParameters; ++i) {
|
||||
Data.getParameters()[i] = key.getParameter(i);
|
||||
if (flags.hasParameterFlags())
|
||||
Data.getParameterFlags()[i] = key.getParameterFlags(i).getIntValue();
|
||||
}
|
||||
}
|
||||
|
||||
// Provide a definition and static initializer for the fixed seed. This
|
||||
// initializer should always be zero to ensure its value can never appear to be
|
||||
// non-zero, even during dynamic initialization.
|
||||
uint64_t llvm::hashing::detail::fixed_seed_override = 0;
|
||||
|
||||
/// The uniquing structure for function type metadata with a global actor.
|
||||
static SimpleGlobalCache<FunctionCacheEntry, FunctionTypesTag> FunctionTypes;
|
||||
|
||||
const FunctionTypeMetadata *
|
||||
swift::swift_getFunctionTypeMetadataGlobalActorStandalone(
|
||||
FunctionTypeFlags flags, FunctionMetadataDifferentiabilityKind diffKind,
|
||||
const Metadata *const *parameters, const uint32_t *parameterFlags,
|
||||
const Metadata *result, const Metadata *globalActor) {
|
||||
assert(flags.hasGlobalActor());
|
||||
assert(flags.hasGlobalActor());
|
||||
FunctionCacheEntry::Key key = {
|
||||
flags, diffKind, parameters, parameterFlags, result, globalActor
|
||||
};
|
||||
return &FunctionTypes.getOrInsert(key).first->Data;
|
||||
|
||||
}
|
||||
@@ -9,7 +9,74 @@
|
||||
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "swift/Runtime/Metadata.h"
|
||||
#include <dispatch/dispatch.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
// Allow this library to get force-loaded by autolinking
|
||||
__attribute__((weak, visibility("hidden"))) extern "C" char
|
||||
_swift_FORCE_LOAD_$_swiftCompatibilityConcurrency = 0;
|
||||
using namespace swift;
|
||||
|
||||
namespace swift {
|
||||
|
||||
// Entrypoint provided by the runtime in the OS that first contains support for
|
||||
// concurrency. Explicitly redeclared as "weak" because this code will run on
|
||||
// systems where it is not present.
|
||||
const FunctionTypeMetadata *
|
||||
swift_getFunctionTypeMetadataGlobalActor(
|
||||
FunctionTypeFlags flags, FunctionMetadataDifferentiabilityKind diffKind,
|
||||
const Metadata *const *parameters, const uint32_t *parameterFlags,
|
||||
const Metadata *result, const Metadata *globalActor
|
||||
) SWIFT_RUNTIME_WEAK_IMPORT;
|
||||
|
||||
// Entrypoint provided only in the back-deployed concurrency library, which
|
||||
// has a separate allocation area for global-actor-qualified function types.
|
||||
extern "C"
|
||||
const FunctionTypeMetadata *
|
||||
swift_getFunctionTypeMetadataGlobalActorStandalone(
|
||||
FunctionTypeFlags flags, FunctionMetadataDifferentiabilityKind diffKind,
|
||||
const Metadata *const *parameters, const uint32_t *parameterFlags,
|
||||
const Metadata *result, const Metadata *globalActor
|
||||
) SWIFT_RUNTIME_WEAK_IMPORT;
|
||||
|
||||
// Entrypoint called by the compiler when back-deploying concurrency, which
|
||||
// switches between the real implementation of
|
||||
// swift_getFunctionTypeMetadataGlobalActor and
|
||||
// swift_getFunctionTypeMetadataGlobalActorStandalone depending on what system
|
||||
// it is running on.
|
||||
SWIFT_RUNTIME_STDLIB_INTERNAL
|
||||
const FunctionTypeMetadata *
|
||||
swift_getFunctionTypeMetadataGlobalActorBackDeploy(
|
||||
FunctionTypeFlags flags, FunctionMetadataDifferentiabilityKind diffKind,
|
||||
const Metadata *const *parameters, const uint32_t *parameterFlags,
|
||||
const Metadata *result, const Metadata *globalActor);
|
||||
|
||||
} // end namespace swift
|
||||
|
||||
const FunctionTypeMetadata *
|
||||
swift::swift_getFunctionTypeMetadataGlobalActorBackDeploy(
|
||||
FunctionTypeFlags flags, FunctionMetadataDifferentiabilityKind diffKind,
|
||||
const Metadata *const *parameters, const uint32_t *parameterFlags,
|
||||
const Metadata *result, const Metadata *globalActor) {
|
||||
using BuilderFn = const FunctionTypeMetadata *(*)(
|
||||
FunctionTypeFlags, FunctionMetadataDifferentiabilityKind,
|
||||
const Metadata *const *, const uint32_t *,
|
||||
const Metadata *, const Metadata *);
|
||||
static BuilderFn builderFn;
|
||||
static dispatch_once_t builderToken;
|
||||
dispatch_once(&builderToken, ^{
|
||||
if (swift_getFunctionTypeMetadataGlobalActor) {
|
||||
builderFn = swift_getFunctionTypeMetadataGlobalActor;
|
||||
return;
|
||||
}
|
||||
|
||||
builderFn = reinterpret_cast<BuilderFn>(
|
||||
dlsym(RTLD_DEFAULT,
|
||||
"swift_getFunctionTypeMetadataGlobalActorStandalone"));
|
||||
});
|
||||
|
||||
assert(builderFn && "No way to build global-actor-qualified function type");
|
||||
return builderFn(
|
||||
flags, diffKind, parameters, parameterFlags, result, globalActor);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ func globalActorMetatype<T>(_: T.Type) -> Any.Type {
|
||||
// CHECK-LABEL: define{{( dllexport)?}}{{( protected)?}} swiftcc %swift.type* @"$s4test19globalActorMetatypeyypXpxmlF"
|
||||
// CHECK: [[MAIN_ACTOR_RESPONSE:%[0-9]+]] = call swiftcc %swift.metadata_response @"$sScMMa"(i{{32|64}} 255)
|
||||
// CHECK-NEXT: [[MAIN_ACTOR_METADATA:%[0-9]+]] = extractvalue %swift.metadata_response [[MAIN_ACTOR_RESPONSE]], 0
|
||||
// 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]])
|
||||
// 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]])
|
||||
sil [ossa] @$s4test19globalActorMetatypeyypXpxmlF : $@convention(thin) <T> (@thick T.Type) -> @thick Any.Type {
|
||||
bb0(%0 : $@thick T.Type):
|
||||
%2 = metatype $@thin (@MainActor () -> T).Type
|
||||
|
||||
22
test/IRGen/global_actor_function_types_backdeploy.sil
Normal file
22
test/IRGen/global_actor_function_types_backdeploy.sil
Normal file
@@ -0,0 +1,22 @@
|
||||
// RUN: %target-swift-frontend -target x86_64-apple-macos12 -emit-ir -o - -primary-file %s | %FileCheck %s --check-prefix CHECK-OS
|
||||
// RUN: %target-swift-frontend -target x86_64-apple-macos11 -emit-ir -o - -primary-file %s | %FileCheck %s --check-prefix CHECK-BACKDEPLOY
|
||||
// REQUIRES: concurrency
|
||||
// REQUIRES: OS=macosx
|
||||
|
||||
import Swift
|
||||
import _Concurrency
|
||||
|
||||
func globalActorMetatype<T>(_: T.Type) -> Any.Type {
|
||||
typealias Fn = @MainActor () -> T
|
||||
return Fn.self
|
||||
}
|
||||
|
||||
// CHECK-OS: call %swift.type* @swift_getFunctionTypeMetadataGlobalActor{{.*}}(i{{32|64}} 335544320, i{{32|64}} 0, %swift.type** null, i32* null, %swift.type* %T, %swift.type* {{.*}})
|
||||
// CHECK-BACKDEPLOY: call %swift.type* @swift_getFunctionTypeMetadataGlobalActorBackDeploy{{.*}}(i{{32|64}} 335544320, i{{32|64}} 0, %swift.type** null, i32* null, %swift.type* %T, %swift.type* {{.*}})
|
||||
sil [ossa] @$s4test19globalActorMetatypeyypXpxmlF : $@convention(thin) <T> (@thick T.Type) -> @thick Any.Type {
|
||||
bb0(%0 : $@thick T.Type):
|
||||
%2 = metatype $@thin (@MainActor () -> T).Type
|
||||
%3 = metatype $@thick (@MainActor () -> T).Type
|
||||
%4 = init_existential_metatype %3 : $@thick (@MainActor () -> T).Type, $@thick Any.Type
|
||||
return %4 : $@thick Any.Type
|
||||
}
|
||||
Reference in New Issue
Block a user