Files
swift-mirror/stdlib/public/runtime/Casting.cpp
Alastair Houghton f5bdb858e0 [Threading] Create new threading library and use it.
Moved all the threading code to one place.  Added explicit support for
Darwin, Linux, Pthreads, C11 threads and Win32 threads, including new
implementations of Once for Linux, Pthreads, C11 and Win32.

rdar://90776105
2022-06-07 07:39:51 +01:00

1625 lines
56 KiB
C++

//===--- Casting.cpp - Swift Language Dynamic Casting Support -------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// Miscellaneous dynamic cast runtime functions.
// The general-purpose swift_dynamicCast implementation is in DynamicCast.cpp
//
//===----------------------------------------------------------------------===//
#include "swift/Runtime/Casting.h"
#include "../SwiftShims/RuntimeShims.h"
#include "../SwiftShims/GlobalObjects.h"
#include "../CompatibilityOverride/CompatibilityOverride.h"
#include "ErrorObject.h"
#include "ExistentialMetadataImpl.h"
#include "Private.h"
#include "SwiftHashableSupport.h"
#include "swift/Basic/Lazy.h"
#include "swift/Demangling/Demangler.h"
#include "swift/Runtime/Config.h"
#include "swift/Runtime/Debug.h"
#include "swift/Runtime/Enum.h"
#include "swift/Runtime/ExistentialContainer.h"
#include "swift/Runtime/HeapObject.h"
#include "swift/Runtime/Metadata.h"
#include "swift/Threading/Mutex.h"
#include "swift/Basic/Unreachable.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/PointerIntPair.h"
#if SWIFT_OBJC_INTEROP
#include "swift/Runtime/ObjCBridge.h"
#include "SwiftObject.h"
#include "SwiftValue.h"
#endif
#include <cstddef>
#include <cstring>
#include <type_traits>
#if defined(__GLIBCXX__) && __GLIBCXX__ < 20160726
#include <stddef.h>
#endif
using namespace swift;
using namespace swift::hashable_support;
using namespace metadataimpl;
#if SWIFT_OBJC_INTEROP
#include <objc/NSObject.h>
#include <objc/runtime.h>
#include <objc/message.h>
#include <objc/objc.h>
// Aliases for Objective-C runtime entry points.
static const char *class_getName(const ClassMetadata* type) {
return class_getName(
reinterpret_cast<Class>(const_cast<ClassMetadata*>(type)));
}
// Aliases for Swift runtime entry points for Objective-C types.
extern "C" const void *swift_dynamicCastObjCProtocolConditional(
const void *object,
size_t numProtocols,
Protocol * const *protocols);
#endif
#if SWIFT_STDLIB_HAS_TYPE_PRINTING
// Build a user-comprehensible name for a type.
static void _buildNameForMetadata(const Metadata *type,
bool qualified,
std::string &result) {
#if SWIFT_OBJC_INTEROP
if (type->getKind() == MetadataKind::Class) {
auto classType = static_cast<const ClassMetadata *>(type);
// Look through artificial subclasses.
while (classType->isTypeMetadata() && classType->isArtificialSubclass())
classType = classType->Superclass;
// Ask the Objective-C runtime to name ObjC classes.
if (!classType->isTypeMetadata()) {
result += class_getName(classType);
return;
}
} else if (type->getKind() == MetadataKind::ObjCClassWrapper) {
auto objcWrapper = static_cast<const ObjCClassWrapperMetadata *>(type);
const char *className = class_getName(class_const_cast(objcWrapper->Class));
result = className;
return;
}
#endif
// Use the remangler to generate a mangled name from the type metadata.
Demangle::Demangler Dem;
auto demangling = _swift_buildDemanglingForMetadata(type, Dem);
if (demangling == nullptr) {
result = "<<< invalid type >>>";
return;
}
Demangle::DemangleOptions options;
options.QualifyEntities = qualified;
if (!qualified)
options.ShowPrivateDiscriminators = false;
result = Demangle::nodeToString(demangling, options);
}
/// Return a user-comprehensible name for the given type.
std::string swift::nameForMetadata(const Metadata *type,
bool qualified) {
std::string result;
_buildNameForMetadata(type, qualified, result);
return result;
}
#else // SWIFT_STDLIB_HAS_TYPE_PRINTING
std::string swift::nameForMetadata(const Metadata *type, bool qualified) {
return "<<< type printer not available >>>";
}
#endif // SWIFT_STDLIB_HAS_TYPE_PRINTING
/// Used as part of cache key for `TypeNameCache`.
enum class TypeNameKind {
NotQualified,
Qualified,
Mangled,
};
using TypeNameCacheKey = llvm::PointerIntPair<const Metadata *, 2, TypeNameKind>;
static LazyMutex TypeNameCacheLock;
static LazyMutex MangledToPrettyFunctionNameCacheLock;
/// Cache containing rendered names for Metadata.
/// Access MUST be protected using `TypeNameCacheLock`.
static Lazy<llvm::DenseMap<TypeNameCacheKey, std::pair<const char *, size_t>>>
TypeNameCache;
/// Cache containing rendered human-readable names for incoming mangled names.
static Lazy<llvm::DenseMap<llvm::StringRef, std::pair<const char *, size_t>>>
/// Access MUST be protected using `MangledToPrettyFunctionNameCache`.
MangledToPrettyFunctionNameCache;
TypeNamePair
swift::swift_getTypeName(const Metadata *type, bool qualified) {
TypeNameCacheKey key = TypeNameCacheKey(type, qualified ? TypeNameKind::Qualified: TypeNameKind::NotQualified);
auto &cache = TypeNameCache.get();
// Attempt read-only lookup of cache entry.
{
LazyMutex::ScopedLock guard(TypeNameCacheLock);
auto found = cache.find(key);
if (found != cache.end()) {
auto result = found->second;
return TypeNamePair{result.first, result.second};
}
}
// Read-only lookup failed to find item, we may need to create it.
{
LazyMutex::ScopedLock guard(TypeNameCacheLock);
// Do lookup again just to make sure it wasn't created by another
// thread before we acquired the write lock.
auto found = cache.find(key);
if (found != cache.end()) {
auto result = found->second;
return TypeNamePair{result.first, result.second};
}
// Build the metadata name.
auto name = nameForMetadata(type, qualified);
// Copy it to memory we can reference forever.
auto size = name.size();
auto result = (char *)malloc(size + 1);
memcpy(result, name.data(), size);
result[size] = 0;
cache.insert({key, {result, size}});
return TypeNamePair{result, size};
}
}
/// Return mangled name for the given type.
TypeNamePair
swift::swift_getMangledTypeName(const Metadata *type) {
TypeNameCacheKey key(type, TypeNameKind::Mangled);
auto &cache = TypeNameCache.get();
// Attempt read-only lookup of cache entry.
{
LazyMutex::ScopedLock guard(TypeNameCacheLock);
auto found = cache.find(key);
if (found != cache.end()) {
auto result = found->second;
return TypeNamePair{result.first, result.second};
}
}
// Read-only cache lookup failed, we may need to create it.
{
LazyMutex::ScopedLock guard(TypeNameCacheLock);
// Do lookup again just to make sure it wasn't created by another
// thread before we acquired the write lock.
auto found = cache.find(key);
if (found != cache.end()) {
auto result = found->second;
return TypeNamePair{result.first, result.second};
}
// Build the mangled name.
Demangle::Demangler Dem;
auto demangling = _swift_buildDemanglingForMetadata(type, Dem);
if (demangling == nullptr) {
return TypeNamePair{NULL, 0};
}
auto mangling = Demangle::mangleNode(demangling);
if (!mangling.isSuccess())
return TypeNamePair{NULL, 0};
std::string name = mangling.result();
// Copy it to memory we can reference forever.
auto size = name.size();
auto result = (char *)malloc(size + 1);
memcpy(result, name.data(), size);
result[size] = 0;
cache.insert({key, {result, size}});
return TypeNamePair{result, size};
}
}
TypeNamePair
swift::swift_getFunctionFullNameFromMangledName(
const char *mangledNameStart, uintptr_t mangledNameLength) {
llvm::StringRef mangledName(mangledNameStart, mangledNameLength);
auto &cache = MangledToPrettyFunctionNameCache.get();
// Attempt read-only lookup of cache entry.
{
LazyMutex::ScopedLock guard(MangledToPrettyFunctionNameCacheLock);
auto found = cache.find(mangledName);
if (found != cache.end()) {
auto result = found->second;
return TypeNamePair{result.first, result.second};
}
}
for (char c : mangledName) {
if (c >= '\x01' && c <= '\x1F')
return TypeNamePair{nullptr, 0};
}
// Read-only lookup failed, we may need to demangle and cache the entry.
// We have to copy the string to be able to refer to it "forever":
auto copy = (char *)malloc(mangledNameLength);
memcpy(copy, mangledNameStart, mangledNameLength);
mangledName = StringRef(copy, mangledNameLength);
std::string demangled;
StackAllocatedDemangler<1024> Dem;
NodePointer node = Dem.demangleSymbol(mangledName);
if (!node) {
return TypeNamePair{nullptr, 0};
}
// Form the demangled string from the node tree.
node = node->findByKind(Demangle::Node::Kind::Function, /*maxDepth=*/3);
if (!node || node->getNumChildren() < 3) {
// we normally expect Class/Identifier/Type, but don't need `Type`
return TypeNamePair{nullptr, 0};
}
// Class identifier:
auto clazz = node->findByKind(Demangle::Node::Kind::Class, 1);
if (clazz) {
if (auto module = clazz->findByKind(Demangle::Node::Kind::Module, 1)) {
demangled += module->getText();
demangled += ".";
}
if (auto clazzIdent = clazz->findByKind(Demangle::Node::Kind::Identifier, 1)) {
demangled += clazzIdent->getText();
demangled += ".";
}
}
// Function identifier:
NodePointer funcIdent = nullptr; // node == Function
for (size_t i = 0; i < node->getNumChildren(); ++i) {
if (node->getChild(i)->getKind() == Demangle::Node::Kind::Identifier) {
funcIdent = node->getChild(i);
}
}
// We always expect to work with functions here and they must have idents
if (!funcIdent) {
return TypeNamePair{nullptr, 0};
}
assert(funcIdent->getKind() == Demangle::Node::Kind::Identifier);
demangled += funcIdent->getText();
demangled += "(";
if (auto labelList = node->findByKind(Demangle::Node::Kind::LabelList, /*maxDepth=*/1)) {
if (labelList->getNumChildren()) {
size_t paramIdx = 0;
while (paramIdx < labelList->getNumChildren()) {
auto labelIdentifier = labelList->getChild(paramIdx++);
if (labelIdentifier) {
if (labelIdentifier->getKind() == Demangle::Node::Kind::Identifier) {
demangled += labelIdentifier->getText();
demangled += ":";
} else if (labelIdentifier->getKind() ==
Demangle::Node::Kind::FirstElementMarker) {
demangled += "_:";
}
}
}
} else if (auto argumentTuple = node->findByKind(
Demangle::Node::Kind::ArgumentTuple, /*maxDepth=*/5)) {
// LabelList was empty.
//
// The function has no labels at all, but could have some parameters...
// we need to check for their count, and render it as e.g. (::) for two
// anonymous parameters.
auto params = argumentTuple->getFirstChild();
if (auto paramsType = params->getFirstChild()) {
if (paramsType->getKind() != Demangle::Node::Kind::Tuple) {
// was a single, unnamed, parameter
demangled += "_:";
} else {
// there are a few parameters; find out how many
while (params && params->getFirstChild() &&
params->getFirstChild()->getKind() !=
Demangle::Node::Kind::TupleElement) {
params = params->getFirstChild();
}
if (params) {
for (size_t i = 0; i < params->getNumChildren(); ++i) {
demangled += "_:";
}
}
}
}
}
}
demangled += ")";
// We have to copy the string to be able to refer to it;
auto size = demangled.size();
auto result = (char *)malloc(size + 1);
memcpy(result, demangled.data(), size);
result[size] = 0; // 0-terminated string
{
LazyMutex::ScopedLock guard(MangledToPrettyFunctionNameCacheLock);
cache.insert({mangledName, {result, size}});
return TypeNamePair{result, size};
}
}
/// Report a dynamic cast failure.
// This is noinline to preserve this frame in stack traces.
// We want "dynamicCastFailure" to appear in crash logs even we crash
// during the diagnostic because some Metadata is invalid.
SWIFT_NORETURN SWIFT_NOINLINE void
swift::swift_dynamicCastFailure(const void *sourceType, const char *sourceName,
const void *targetType, const char *targetName,
const char *message) {
swift::fatalError(/* flags = */ 0,
"Could not cast value of type '%s' (%p) to '%s' (%p)%s%s\n",
sourceName, sourceType,
targetName, targetType,
message ? ": " : ".",
message ? message : "");
}
SWIFT_NORETURN void swift::swift_dynamicCastFailure(const Metadata *sourceType,
const Metadata *targetType,
const char *message) {
std::string sourceName = nameForMetadata(sourceType);
std::string targetName = nameForMetadata(targetType);
swift_dynamicCastFailure(sourceType, sourceName.c_str(),
targetType, targetName.c_str(), message);
}
// Objective-C bridging helpers.
namespace {
struct _ObjectiveCBridgeableWitnessTable;
}
static const _ObjectiveCBridgeableWitnessTable *
findBridgeWitness(const Metadata *T);
/// Dynamically cast a class metatype to a Swift class metatype.
static const ClassMetadata *
_dynamicCastClassMetatype(const ClassMetadata *sourceType,
const ClassMetadata *targetType) {
do {
if (sourceType == targetType) {
return sourceType;
}
sourceType = sourceType->Superclass;
} while (sourceType);
return nullptr;
}
#if !SWIFT_OBJC_INTEROP // __SwiftValue is a native class
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL
bool swift_unboxFromSwiftValueWithType(OpaqueValue *source,
OpaqueValue *result,
const Metadata *destinationType);
/// Nominal type descriptor for Swift.__SwiftValue
extern "C" const ClassDescriptor NOMINAL_TYPE_DESCR_SYM(s12__SwiftValueC);
#endif
/// Dynamically cast a class instance to a Swift class type.
static const void *swift_dynamicCastClassImpl(const void *object,
const ClassMetadata *targetType) {
#if SWIFT_OBJC_INTEROP
assert(!targetType->isPureObjC());
// Swift native classes never have a tagged-pointer representation.
if (isObjCTaggedPointerOrNull(object)) {
return nullptr;
}
#endif
auto srcType = _swift_getClassOfAllocated(object);
if (_dynamicCastClassMetatype(srcType, targetType))
return object;
#if !SWIFT_OBJC_INTEROP // __SwiftValue is a native class on Linux
if (srcType->getKind() == MetadataKind::Class
&& targetType->getKind() == MetadataKind::Class) {
auto srcClassType = cast<ClassMetadata>(srcType);
auto srcDescr = srcClassType->getDescription();
if (srcDescr == &NOMINAL_TYPE_DESCR_SYM(s12__SwiftValueC)) {
auto srcValue = reinterpret_cast<OpaqueValue *>(&object);
void *result;
auto destLocation = reinterpret_cast<OpaqueValue *>(&result);
if (swift_unboxFromSwiftValueWithType(srcValue, destLocation, targetType)) {
swift_unknownObjectRelease(const_cast<void *>(object));
return result;
}
}
}
#endif
return nullptr;
}
/// Dynamically cast a class object to a Swift class type.
static const void *
swift_dynamicCastClassUnconditionalImpl(const void *object,
const ClassMetadata *targetType,
const char *file, unsigned line, unsigned column) {
auto value = swift_dynamicCastClass(object, targetType);
if (value) return value;
swift_dynamicCastFailure(_swift_getClass(object), targetType);
}
#if SWIFT_OBJC_INTEROP
static bool _unknownClassConformsToObjCProtocol(const OpaqueValue *value,
Protocol *protocol) {
const void *object
= *reinterpret_cast<const void * const *>(value);
return swift_dynamicCastObjCProtocolConditional(object, 1, &protocol);
}
#endif
bool swift::_conformsToProtocol(const OpaqueValue *value,
const Metadata *type,
ProtocolDescriptorRef protocol,
const WitnessTable **conformance) {
// Look up the witness table for protocols that need them.
if (protocol.needsWitnessTable()) {
auto witness = swift_conformsToProtocol(type, protocol.getSwiftProtocol());
if (!witness)
return false;
if (conformance)
*conformance = witness;
return true;
}
// For Objective-C protocols, check whether we have a class that
// conforms to the given protocol.
switch (type->getKind()) {
case MetadataKind::Class:
#if SWIFT_OBJC_INTEROP
if (value) {
return _unknownClassConformsToObjCProtocol(value,
protocol.getObjCProtocol());
} else {
return classConformsToObjCProtocol(type, protocol);
}
#endif
return false;
case MetadataKind::ObjCClassWrapper: {
#if SWIFT_OBJC_INTEROP
if (value) {
return _unknownClassConformsToObjCProtocol(value,
protocol.getObjCProtocol());
} else {
auto wrapper = cast<ObjCClassWrapperMetadata>(type);
return classConformsToObjCProtocol(wrapper->Class, protocol);
}
#endif
return false;
}
case MetadataKind::ForeignClass:
#if SWIFT_OBJC_INTEROP
if (value)
return _unknownClassConformsToObjCProtocol(value,
protocol.getObjCProtocol());
return false;
#else
return false;
#endif
case MetadataKind::Existential: {
#if SWIFT_OBJC_INTEROP
// If all protocols are @objc and at least one of them conforms to the
// protocol, succeed.
auto existential = cast<ExistentialTypeMetadata>(type);
if (!existential->isObjC())
return false;
for (auto existentialProto : existential->getProtocols()) {
if (protocol_conformsToProtocol(existentialProto.getObjCProtocol(),
protocol.getObjCProtocol()))
return true;
}
#endif
return false;
}
case MetadataKind::ExistentialMetatype:
default:
return false;
}
return false;
}
/// Check whether a type conforms to the given protocols, filling in a
/// list of conformances.
static bool _conformsToProtocols(const OpaqueValue *value,
const Metadata *type,
const ExistentialTypeMetadata *existentialType,
const WitnessTable **conformances) {
if (auto *superclass = existentialType->getSuperclassConstraint()) {
if (!swift_dynamicCastMetatype(type, superclass))
return false;
}
if (existentialType->isClassBounded()) {
if (!Metadata::isAnyKindOfClass(type->getKind()))
return false;
}
for (auto protocol : existentialType->getProtocols()) {
if (!_conformsToProtocol(value, type, protocol, conformances))
return false;
if (conformances != nullptr && protocol.needsWitnessTable()) {
assert(*conformances != nullptr);
++conformances;
}
}
return true;
}
/// Given a possibly-existential value, find its dynamic type and the
/// address of its storage.
static void
findDynamicValueAndType(OpaqueValue *value, const Metadata *type,
OpaqueValue *&outValue, const Metadata *&outType,
bool &inoutCanTake,
bool isTargetTypeAnyObject,
bool isTargetExistentialMetatype) {
switch (type->getKind()) {
case MetadataKind::Class:
case MetadataKind::ObjCClassWrapper:
case MetadataKind::ForeignClass: {
// TODO: avoid unnecessary repeat lookup of
// ObjCClassWrapper/ForeignClass when the type matches.
outValue = value;
outType = swift_getObjectType(*reinterpret_cast<HeapObject**>(value));
return;
}
case MetadataKind::Existential: {
auto existentialType = cast<ExistentialTypeMetadata>(type);
inoutCanTake &= existentialType->mayTakeValue(value);
// We can't drill through existential containers unless the result is an
// existential metatype.
if (!isTargetExistentialMetatype) {
outValue = value;
outType = type;
return;
}
switch (existentialType->getRepresentation()) {
case ExistentialTypeRepresentation::Class: {
// Class existentials can't recursively contain existential containers,
// so we can fast-path by not bothering to recur.
auto existential =
reinterpret_cast<ClassExistentialContainer*>(value);
outValue = (OpaqueValue*) &existential->Value;
outType = swift_getObjectType((HeapObject*) existential->Value);
return;
}
case ExistentialTypeRepresentation::Opaque:
case ExistentialTypeRepresentation::Error: {
const Metadata *innerType = existentialType->getDynamicType(value);
// Short cut class in existential as AnyObject casts.
if (isTargetTypeAnyObject &&
innerType->getKind() == MetadataKind::Class) {
// inline value buffer storage.
outValue = value;
outType = 0;
inoutCanTake = true;
return;
}
OpaqueValue *innerValue
= existentialType->projectValue(value);
return findDynamicValueAndType(innerValue, innerType,
outValue, outType, inoutCanTake, false,
isTargetExistentialMetatype);
}
}
}
case MetadataKind::Metatype:
case MetadataKind::ExistentialMetatype: {
auto storedType = *(const Metadata **) value;
outValue = value;
outType = swift_getMetatypeMetadata(storedType);
return;
}
// Non-polymorphic types.
default:
outValue = value;
outType = type;
return;
}
}
extern "C" const Metadata *
swift::swift_getDynamicType(OpaqueValue *value, const Metadata *self,
bool existentialMetatype) {
OpaqueValue *outValue;
const Metadata *outType;
bool canTake = false;
findDynamicValueAndType(value, self, outValue, outType, canTake,
/*isAnyObject*/ false,
existentialMetatype);
return outType;
}
#if SWIFT_OBJC_INTEROP
SWIFT_RUNTIME_EXPORT
id
swift_dynamicCastMetatypeToObjectConditional(const Metadata *metatype) {
switch (metatype->getKind()) {
case MetadataKind::Class:
case MetadataKind::ObjCClassWrapper:
// Swift classes are objects in and of themselves.
// ObjC class wrappers get unwrapped.
return (id)metatype->getObjCClassObject();
// Other kinds of metadata don't cast to AnyObject.
default:
return nullptr;
}
}
SWIFT_RUNTIME_EXPORT
id
swift_dynamicCastMetatypeToObjectUnconditional(const Metadata *metatype,
const char *file, unsigned line, unsigned column) {
switch (metatype->getKind()) {
case MetadataKind::Class:
case MetadataKind::ObjCClassWrapper:
// Swift classes are objects in and of themselves.
// ObjC class wrappers get unwrapped.
return (id)metatype->getObjCClassObject();
// Other kinds of metadata don't cast to AnyObject.
default: {
std::string sourceName = nameForMetadata(metatype);
swift_dynamicCastFailure(metatype, sourceName.c_str(),
nullptr, "AnyObject",
"only class metatypes can be converted to AnyObject");
}
}
}
#endif
/******************************************************************************/
/********************************** Classes ***********************************/
/******************************************************************************/
static const void *
_dynamicCastUnknownClassToExistential(const void *object,
const ExistentialTypeMetadata *targetType) {
// FIXME: check superclass constraint here.
for (auto protocol : targetType->getProtocols()) {
switch (protocol.getDispatchStrategy()) {
case ProtocolDispatchStrategy::Swift:
// If the target existential requires witness tables, we can't do this cast.
// The result type would not have a single-refcounted-pointer rep.
return nullptr;
case ProtocolDispatchStrategy::ObjC:
#if SWIFT_OBJC_INTEROP
if (!objectConformsToObjCProtocol(object, protocol))
return nullptr;
break;
#else
assert(false && "ObjC interop disabled?!");
return nullptr;
#endif
}
}
return object;
}
/// Perform a dynamic class of some sort of class instance to some
/// sort of class type.
static const void *
swift_dynamicCastUnknownClassImpl(const void *object,
const Metadata *targetType) {
switch (targetType->getKind()) {
case MetadataKind::Class: {
auto targetClassType = static_cast<const ClassMetadata *>(targetType);
return swift_dynamicCastClass(object, targetClassType);
}
case MetadataKind::ObjCClassWrapper: {
#if SWIFT_OBJC_INTEROP
auto targetClassType
= static_cast<const ObjCClassWrapperMetadata *>(targetType)->Class;
return swift_dynamicCastObjCClass(object, targetClassType);
#else
return nullptr;
#endif
}
case MetadataKind::ForeignClass: {
#if SWIFT_OBJC_INTEROP
auto targetClassType = static_cast<const ForeignClassMetadata*>(targetType);
return swift_dynamicCastForeignClass(object, targetClassType);
#else
return nullptr;
#endif
}
case MetadataKind::Existential: {
return _dynamicCastUnknownClassToExistential(object,
static_cast<const ExistentialTypeMetadata *>(targetType));
}
default:
return nullptr;
}
}
/// Perform a dynamic class of some sort of class instance to some
/// sort of class type.
static const void *
swift_dynamicCastUnknownClassUnconditionalImpl(const void *object,
const Metadata *targetType,
const char *file, unsigned line, unsigned column) {
switch (targetType->getKind()) {
case MetadataKind::Class: {
auto targetClassType = static_cast<const ClassMetadata *>(targetType);
return swift_dynamicCastClassUnconditional(object, targetClassType, file, line, column);
}
case MetadataKind::ObjCClassWrapper: {
#if SWIFT_OBJC_INTEROP
auto targetClassType
= static_cast<const ObjCClassWrapperMetadata *>(targetType)->Class;
return swift_dynamicCastObjCClassUnconditional(object, targetClassType, file, line, column);
#else
swift_dynamicCastFailure(_swift_getClass(object), targetType);
#endif
}
case MetadataKind::ForeignClass: {
#if SWIFT_OBJC_INTEROP
auto targetClassType = static_cast<const ForeignClassMetadata*>(targetType);
return swift_dynamicCastForeignClassUnconditional(object, targetClassType, file, line, column);
#else
swift_dynamicCastFailure(_swift_getClass(object), targetType);
#endif
}
case MetadataKind::Existential: {
// We can cast to ObjC existentials. Non-ObjC existentials don't have
// a single-refcounted-pointer representation.
if (auto result = _dynamicCastUnknownClassToExistential(object,
static_cast<const ExistentialTypeMetadata *>(targetType)))
return result;
swift_dynamicCastFailure(_swift_getClass(object), targetType);
}
default:
swift_dynamicCastFailure(_swift_getClass(object), targetType);
}
}
/******************************************************************************/
/********************************* Metatypes **********************************/
/******************************************************************************/
static const Metadata *
swift_dynamicCastMetatypeImpl(const Metadata *sourceType,
const Metadata *targetType) {
auto origSourceType = sourceType;
// Identical types always succeed
if (sourceType == targetType)
return origSourceType;
switch (targetType->getKind()) {
case MetadataKind::ObjCClassWrapper:
// Get the actual class object.
targetType = static_cast<const ObjCClassWrapperMetadata*>(targetType)
->Class;
SWIFT_FALLTHROUGH;
case MetadataKind::Class:
// The source value must also be a class; otherwise the cast fails.
switch (sourceType->getKind()) {
case MetadataKind::ObjCClassWrapper:
// Get the actual class object.
sourceType = static_cast<const ObjCClassWrapperMetadata*>(sourceType)
->Class;
SWIFT_FALLTHROUGH;
case MetadataKind::Class: {
// Check if the source is a subclass of the target.
#if SWIFT_OBJC_INTEROP
// We go through ObjC lookup to deal with potential runtime magic in ObjC
// land.
if (swift_dynamicCastObjCClassMetatype((const ClassMetadata*)sourceType,
(const ClassMetadata*)targetType))
return origSourceType;
#else
if (_dynamicCastClassMetatype((const ClassMetadata*)sourceType,
(const ClassMetadata*)targetType))
return origSourceType;
#endif
return nullptr;
}
case MetadataKind::ForeignClass: {
// Check if the source is a subclass of the target.
if (swift_dynamicCastForeignClassMetatype(
(const ClassMetadata*)sourceType,
(const ClassMetadata*)targetType))
return origSourceType;
return nullptr;
}
default:
return nullptr;
}
break;
case MetadataKind::ForeignClass:
switch (sourceType->getKind()) {
case MetadataKind::ObjCClassWrapper:
// Get the actual class object.
sourceType = static_cast<const ObjCClassWrapperMetadata*>(sourceType)
->Class;
SWIFT_FALLTHROUGH;
case MetadataKind::Class:
case MetadataKind::ForeignClass:
// Check if the source is a subclass of the target.
if (swift_dynamicCastForeignClassMetatype(
(const ClassMetadata*)sourceType,
(const ClassMetadata*)targetType))
return origSourceType;
return nullptr;
default:
return nullptr;
}
break;
default:
return nullptr;
}
swift_unreachable("Unhandled MetadataKind in switch.");
}
static const Metadata *
swift_dynamicCastMetatypeUnconditionalImpl(const Metadata *sourceType,
const Metadata *targetType,
const char *file, unsigned line, unsigned column) {
auto origSourceType = sourceType;
// Identical types always succeed
if (sourceType == targetType)
return origSourceType;
switch (targetType->getKind()) {
case MetadataKind::ObjCClassWrapper:
// Get the actual class object.
targetType = static_cast<const ObjCClassWrapperMetadata*>(targetType)
->Class;
SWIFT_FALLTHROUGH;
case MetadataKind::Class:
// The source value must also be a class; otherwise the cast fails.
switch (sourceType->getKind()) {
case MetadataKind::ObjCClassWrapper:
// Get the actual class object.
sourceType = static_cast<const ObjCClassWrapperMetadata*>(sourceType)
->Class;
SWIFT_FALLTHROUGH;
case MetadataKind::Class: {
// Check if the source is a subclass of the target.
#if SWIFT_OBJC_INTEROP
// We go through ObjC lookup to deal with potential runtime magic in ObjC
// land.
swift_dynamicCastObjCClassMetatypeUnconditional(
(const ClassMetadata*)sourceType,
(const ClassMetadata*)targetType,
file, line, column);
#else
if (!_dynamicCastClassMetatype((const ClassMetadata*)sourceType,
(const ClassMetadata*)targetType))
swift_dynamicCastFailure(sourceType, targetType);
#endif
// If we returned, then the cast succeeded.
return origSourceType;
}
case MetadataKind::ForeignClass: {
// Check if the source is a subclass of the target.
swift_dynamicCastForeignClassMetatypeUnconditional(
(const ClassMetadata*)sourceType,
(const ClassMetadata*)targetType,
file, line, column);
// If we returned, then the cast succeeded.
return origSourceType;
}
default:
swift_dynamicCastFailure(sourceType, targetType);
}
break;
case MetadataKind::ForeignClass:
// The source value must also be a class; otherwise the cast fails.
switch (sourceType->getKind()) {
case MetadataKind::ObjCClassWrapper:
// Get the actual class object.
sourceType = static_cast<const ObjCClassWrapperMetadata*>(sourceType)
->Class;
SWIFT_FALLTHROUGH;
case MetadataKind::Class:
case MetadataKind::ForeignClass:
// Check if the source is a subclass of the target.
swift_dynamicCastForeignClassMetatypeUnconditional(
(const ClassMetadata*)sourceType,
(const ClassMetadata*)targetType,
file, line, column);
// If we returned, then the cast succeeded.
return origSourceType;
default:
swift_dynamicCastFailure(sourceType, targetType);
}
break;
case MetadataKind::Existential: {
auto targetTypeAsExistential = static_cast<const ExistentialTypeMetadata *>(targetType);
if (_conformsToProtocols(nullptr, sourceType, targetTypeAsExistential, nullptr))
return origSourceType;
swift_dynamicCastFailure(sourceType, targetType);
}
default:
swift_dynamicCastFailure(sourceType, targetType);
}
}
/******************************************************************************/
/******************************** Existentials ********************************/
/******************************************************************************/
#if SWIFT_OBJC_INTEROP
static void unwrapExistential(OpaqueValue *src,
const ExistentialTypeMetadata *srcType,
OpaqueValue *&srcValue,
const Metadata *&srcCapturedType,
bool &isOutOfLine,
bool &canTake) {
switch (srcType->getRepresentation()) {
case ExistentialTypeRepresentation::Class: {
auto classContainer =
reinterpret_cast<ClassExistentialContainer*>(src);
srcValue = (OpaqueValue*) &classContainer->Value;
void *obj = classContainer->Value;
srcCapturedType = swift_getObjectType(reinterpret_cast<HeapObject*>(obj));
isOutOfLine = false;
canTake = true;
break;
}
case ExistentialTypeRepresentation::Opaque: {
auto opaqueContainer = reinterpret_cast<OpaqueExistentialContainer*>(src);
srcCapturedType = opaqueContainer->Type;
srcValue = srcType->projectValue(src);
// Can't take out of possibly shared existential boxes.
canTake = (src == srcValue);
assert(canTake == srcCapturedType->getValueWitnesses()->isValueInline() &&
"Only inline storage is take-able");
isOutOfLine = (src != srcValue);
break;
}
case ExistentialTypeRepresentation::Error: {
const SwiftError *errorBox
= *reinterpret_cast<const SwiftError * const *>(src);
srcCapturedType = errorBox->getType();
// A bridged NSError is itself the value.
if (errorBox->isPureNSError())
srcValue = src;
else
srcValue = const_cast<OpaqueValue*>(errorBox->getValue());
// The value is out-of-line, but we can't take it, since it may be shared.
isOutOfLine = true;
canTake = false;
break;
}
}
}
#endif
/******************************************************************************/
/****************************** Main Entrypoint *******************************/
/******************************************************************************/
static inline bool swift_isClassOrObjCExistentialTypeImpl(const Metadata *T) {
auto kind = T->getKind();
// Classes.
if (Metadata::isAnyKindOfClass(kind))
return true;
#if SWIFT_OBJC_INTEROP
// ObjC existentials.
if (kind == MetadataKind::Existential &&
static_cast<const ExistentialTypeMetadata *>(T)->isObjC())
return true;
// Blocks are ObjC objects.
if (kind == MetadataKind::Function) {
auto fT = static_cast<const FunctionTypeMetadata *>(T);
return fT->getConvention() == FunctionMetadataConvention::Block;
}
#endif
return false;
}
/******************************************************************************/
/********************************** Bridging **********************************/
/******************************************************************************/
//===----------------------------------------------------------------------===//
// Bridging to and from Objective-C
//===----------------------------------------------------------------------===//
namespace {
// protocol _ObjectiveCBridgeable {
struct _ObjectiveCBridgeableWitnessTable : WitnessTable {
#define _protocolWitnessSignedPointer(n) \
__ptrauth_swift_protocol_witness_function_pointer(SpecialPointerAuthDiscriminators::n##Discriminator) n
static_assert(WitnessTableFirstRequirementOffset == 1,
"Witness table layout changed");
void *_ObjectiveCType;
// func _bridgeToObjectiveC() -> _ObjectiveCType
SWIFT_CC(swift)
HeapObject *(*_protocolWitnessSignedPointer(bridgeToObjectiveC))(
SWIFT_CONTEXT OpaqueValue *self, const Metadata *Self,
const _ObjectiveCBridgeableWitnessTable *witnessTable);
// class func _forceBridgeFromObjectiveC(x: _ObjectiveCType,
// inout result: Self?)
SWIFT_CC(swift)
void (*_protocolWitnessSignedPointer(forceBridgeFromObjectiveC))(
HeapObject *sourceValue,
OpaqueValue *result,
SWIFT_CONTEXT const Metadata *self,
const Metadata *selfType,
const _ObjectiveCBridgeableWitnessTable *witnessTable);
// class func _conditionallyBridgeFromObjectiveC(x: _ObjectiveCType,
// inout result: Self?) -> Bool
SWIFT_CC(swift)
bool (*_protocolWitnessSignedPointer(conditionallyBridgeFromObjectiveC))(
HeapObject *sourceValue,
OpaqueValue *result,
SWIFT_CONTEXT const Metadata *self,
const Metadata *selfType,
const _ObjectiveCBridgeableWitnessTable *witnessTable);
};
// }
/// Retrieve the bridged Objective-C type for the given type that
/// conforms to \c _ObjectiveCBridgeable.
MetadataResponse _getBridgedObjectiveCType(
MetadataRequest request,
const Metadata *conformingType,
const _ObjectiveCBridgeableWitnessTable *wtable) {
// FIXME: Can we directly reference the descriptor somehow?
const ProtocolConformanceDescriptor *conformance = wtable->getDescription();
const ProtocolDescriptor *protocol = conformance->getProtocol();
auto assocTypeRequirement = protocol->getRequirements().begin();
assert(assocTypeRequirement->Flags.getKind() ==
ProtocolRequirementFlags::Kind::AssociatedTypeAccessFunction);
auto mutableWTable = (WitnessTable *)wtable;
return swift_getAssociatedTypeWitness(
request, mutableWTable, conformingType,
protocol->getRequirementBaseDescriptor(),
assocTypeRequirement);
}
} // unnamed namespace
extern "C" const ProtocolDescriptor PROTOCOL_DESCR_SYM(s21_ObjectiveCBridgeable);
#if SWIFT_OBJC_INTEROP
static id bridgeAnythingNonVerbatimToObjectiveC(OpaqueValue *src,
const Metadata *srcType,
bool consume) {
// We can always bridge objects verbatim.
if (srcType->isAnyClass()) {
id result;
memcpy(&result, src, sizeof(id));
if (!consume)
swift_unknownObjectRetain(result);
return result;
}
// Dig through existential types.
if (auto srcExistentialTy = dyn_cast<ExistentialTypeMetadata>(srcType)) {
OpaqueValue *srcInnerValue;
const Metadata *srcInnerType;
bool isOutOfLine;
bool canTake;
unwrapExistential(src, srcExistentialTy,
srcInnerValue, srcInnerType, isOutOfLine, canTake);
auto result = bridgeAnythingNonVerbatimToObjectiveC(srcInnerValue,
srcInnerType,
consume && canTake);
// Clean up the existential, or its remains after taking the value from
// it.
if (consume) {
if (canTake) {
if (isOutOfLine) {
// Copy-on-write existentials share boxed and can't be 'take'n out of
// without a uniqueness check (which we currently don't do).
swift::fatalError(
0 /* flags */,
"Attempting to move out of a copy-on-write existential");
}
} else {
// We didn't take the value, so clean up the existential value.
srcType->vw_destroy(src);
}
}
return result;
}
// Handle metatypes.
if (isa<ExistentialMetatypeMetadata>(srcType)
|| isa<MetatypeMetadata>(srcType)) {
const Metadata *srcMetatypeValue;
memcpy(&srcMetatypeValue, src, sizeof(srcMetatypeValue));
// Class metatypes bridge to their class object.
if (isa<ClassMetadata>(srcMetatypeValue)
|| isa<ObjCClassWrapperMetadata>(srcMetatypeValue)) {
return (id)srcMetatypeValue->getObjCClassObject();
// ObjC protocols bridge to their Protocol object.
} else if (auto existential
= dyn_cast<ExistentialTypeMetadata>(srcMetatypeValue)) {
if (existential->isObjC() && existential->NumProtocols == 1) {
// Though they're statically-allocated globals, Protocol inherits
// NSObject's default refcounting behavior so must be retained.
auto protocolObj = existential->getProtocols()[0].getObjCProtocol();
return objc_retain(protocolObj);
}
}
// Handle bridgeable types.
} else if (auto srcBridgeWitness = findBridgeWitness(srcType)) {
// Bridge the source value to an object.
auto srcBridgedObject =
srcBridgeWitness->bridgeToObjectiveC(src, srcType, srcBridgeWitness);
// Consume if the source object was passed in +1.
if (consume)
srcType->vw_destroy(src);
return (id)srcBridgedObject;
// Handle Errors.
} else if (auto srcErrorWitness = findErrorWitness(srcType)) {
// Bridge the source value to an NSError.
auto flags = consume ? DynamicCastFlags::TakeOnSuccess
: DynamicCastFlags::Default;
return dynamicCastValueToNSError(src, srcType, srcErrorWitness, flags);
}
// Fall back to boxing.
return (id)bridgeAnythingToSwiftValueObject(src, srcType, consume);
}
/// public
/// func _bridgeAnythingNonVerbatimToObjectiveC<T>(_ x: __owned T) -> AnyObject
///
/// Called by inlined stdlib code.
#define _bridgeAnythingNonVerbatimToObjectiveC \
MANGLE_SYM(s38_bridgeAnythingNonVerbatimToObjectiveCyyXlxnlF)
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
id _bridgeAnythingNonVerbatimToObjectiveC(OpaqueValue *src,
const Metadata *srcType) {
bool shouldConsume = true;
return bridgeAnythingNonVerbatimToObjectiveC(src, srcType,
/*consume*/shouldConsume);
}
#endif
//===--- Bridging helpers for the Swift stdlib ----------------------------===//
// Functions that must discover and possibly use an arbitrary type's
// conformance to a given protocol. See ../core/BridgeObjectiveC.swift for
// documentation.
//===----------------------------------------------------------------------===//
#if SWIFT_OBJC_INTEROP
#define BRIDGING_CONFORMANCE_SYM \
MANGLE_SYM(s19_BridgeableMetatypeVs21_ObjectiveCBridgeablesWP)
extern "C" const _ObjectiveCBridgeableWitnessTable BRIDGING_CONFORMANCE_SYM;
#endif
/// Nominal type descriptor for Swift.String.
extern "C" const StructDescriptor NOMINAL_TYPE_DESCR_SYM(SS);
static const _ObjectiveCBridgeableWitnessTable *
swift_conformsToObjectiveCBridgeable(const Metadata *T) {
return reinterpret_cast<const _ObjectiveCBridgeableWitnessTable *>
(swift_conformsToProtocol(T, &PROTOCOL_DESCR_SYM(s21_ObjectiveCBridgeable)));
}
static const _ObjectiveCBridgeableWitnessTable *
findBridgeWitness(const Metadata *T) {
// Special case: Memoize the bridge witness for Swift.String.
// Swift.String is the most heavily used bridge because of the prevalence of
// string-keyed dictionaries in Obj-C. It's worth burning a few words of static
// storage to avoid repeatedly looking up this conformance.
if (T->getKind() == MetadataKind::Struct) {
auto structDescription = cast<StructMetadata>(T)->Description;
if (structDescription == &NOMINAL_TYPE_DESCR_SYM(SS)) {
static auto *Swift_String_ObjectiveCBridgeable = swift_conformsToObjectiveCBridgeable(T);
return Swift_String_ObjectiveCBridgeable;
}
}
auto w = swift_conformsToObjectiveCBridgeable(T);
if (SWIFT_LIKELY(w))
return reinterpret_cast<const _ObjectiveCBridgeableWitnessTable *>(w);
// Class and ObjC existential metatypes can be bridged, but metatypes can't
// directly conform to protocols yet. Use a stand-in conformance for a type
// that looks like a metatype value if the metatype can be bridged.
switch (T->getKind()) {
case MetadataKind::Metatype: {
#if SWIFT_OBJC_INTEROP
auto metaTy = static_cast<const MetatypeMetadata *>(T);
if (metaTy->InstanceType->isAnyClass())
return &BRIDGING_CONFORMANCE_SYM;
#endif
break;
}
case MetadataKind::ExistentialMetatype: {
#if SWIFT_OBJC_INTEROP
auto existentialMetaTy =
static_cast<const ExistentialMetatypeMetadata *>(T);
if (existentialMetaTy->isObjC())
return &BRIDGING_CONFORMANCE_SYM;
#endif
break;
}
default:
break;
}
return nullptr;
}
// public func _getBridgedNonVerbatimObjectiveCType<T>(_: T.Type) -> Any.Type?
// Called by inlined stdlib code.
#define _getBridgedNonVerbatimObjectiveCType \
MANGLE_SYM(s36_getBridgedNonVerbatimObjectiveCTypeyypXpSgxmlF)
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
const Metadata *_getBridgedNonVerbatimObjectiveCType(
const Metadata *value, const Metadata *T
) {
// Classes and Objective-C existentials bridge verbatim.
assert(!swift_isClassOrObjCExistentialTypeImpl(T));
// Check if the type conforms to _BridgedToObjectiveC, in which case
// we'll extract its associated type.
if (const auto *bridgeWitness = findBridgeWitness(T)) {
return _getBridgedObjectiveCType(MetadataState::Complete, T,
bridgeWitness).Value;
}
return nullptr;
}
#if SWIFT_OBJC_INTEROP
// @_silgen_name("_bridgeNonVerbatimFromObjectiveCToAny")
// func _bridgeNonVerbatimFromObjectiveCToAny(
// x: AnyObject,
// inout result: Any?
// )
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL
void
_bridgeNonVerbatimFromObjectiveCToAny(HeapObject *sourceValue,
OpaqueValue *destValue);
// @_silgen_name("_bridgeNonVerbatimBoxedValue")
// func _bridgeNonVerbatimBoxedValue<NativeType>(
// x: UnsafePointer<NativeType>,
// inout result: NativeType?
// )
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL
void
_bridgeNonVerbatimBoxedValue(const OpaqueValue *sourceValue,
OpaqueValue *destValue,
const Metadata *nativeType);
// Try bridging by conversion to Any or boxing if applicable.
static bool tryBridgeNonVerbatimFromObjectiveCUniversal(
HeapObject *sourceValue,
const Metadata *nativeType,
OpaqueValue *destValue
) {
// If the type is the Any type, we can bridge by "upcasting" the object
// to Any.
if (auto nativeExistential = dyn_cast<ExistentialTypeMetadata>(nativeType)) {
if (nativeExistential->NumProtocols == 0 &&
!nativeExistential->isClassBounded()) {
_bridgeNonVerbatimFromObjectiveCToAny(sourceValue, destValue);
return true;
}
}
// Check if the value is a box containing a value of the desired type.
if (auto srcBox = getAsSwiftValue((id)sourceValue)) {
const Metadata *sourceType;
const OpaqueValue *sourceBoxedValue;
std::tie(sourceType, sourceBoxedValue) = getValueFromSwiftValue(srcBox);
if (sourceType == nativeType) {
_bridgeNonVerbatimBoxedValue(sourceBoxedValue, destValue, nativeType);
return true;
}
}
// Try to bridge NSError to Error.
if (tryDynamicCastNSErrorObjectToValue(sourceValue, destValue, nativeType,
DynamicCastFlags::Default)) {
return true;
}
return false;
}
// func _bridgeNonVerbatimFromObjectiveC<T>(
// _ x: AnyObject,
// _ nativeType: T.Type
// _ inout result: T?
// )
// Called by inlined stdlib code.
#define _bridgeNonVerbatimFromObjectiveC \
MANGLE_SYM(s32_bridgeNonVerbatimFromObjectiveCyyyXl_xmxSgztlF)
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
void
_bridgeNonVerbatimFromObjectiveC(
HeapObject *sourceValue,
const Metadata *nativeType,
OpaqueValue *destValue,
const Metadata *nativeType_
) {
if (tryBridgeNonVerbatimFromObjectiveCUniversal(sourceValue, nativeType,
destValue))
return;
// Check if the type conforms to _BridgedToObjectiveC.
if (const auto *bridgeWitness = findBridgeWitness(nativeType)) {
// Check if sourceValue has the _ObjectiveCType type required by the
// protocol.
const Metadata *objectiveCType =
_getBridgedObjectiveCType(MetadataState::Complete, nativeType,
bridgeWitness).Value;
auto sourceValueAsObjectiveCType =
const_cast<void*>(swift_dynamicCastUnknownClass(sourceValue,
objectiveCType));
if (!sourceValueAsObjectiveCType) {
swift::swift_dynamicCastFailure(_swift_getClass(sourceValue),
objectiveCType);
}
// The type matches. _forceBridgeFromObjectiveC returns `Self`, so
// we can just return it directly.
bridgeWitness->forceBridgeFromObjectiveC(
static_cast<HeapObject*>(sourceValueAsObjectiveCType),
destValue, nativeType, nativeType, bridgeWitness);
return;
}
// Fail.
swift::crash("value type is not bridged to Objective-C");
}
/// func _bridgeNonVerbatimFromObjectiveCConditional<T>(
/// _ x: AnyObject, _ nativeType: T.Type, _ result: inout T?) -> Bool
/// Called by inlined stdlib code.
#define _bridgeNonVerbatimFromObjectiveCConditional \
MANGLE_SYM(s43_bridgeNonVerbatimFromObjectiveCConditionalySbyXl_xmxSgztlF)
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
bool
_bridgeNonVerbatimFromObjectiveCConditional(
HeapObject *sourceValue,
const Metadata *nativeType,
OpaqueValue *destValue,
const Metadata *nativeType_
) {
if (tryBridgeNonVerbatimFromObjectiveCUniversal(sourceValue, nativeType,
destValue))
return true;
// Local function that releases the source and returns false.
auto fail = [&] () -> bool {
return false;
};
// Check if the type conforms to _BridgedToObjectiveC.
const auto *bridgeWitness = findBridgeWitness(nativeType);
if (!bridgeWitness)
return fail();
// Dig out the Objective-C class type through which the native type
// is bridged.
const Metadata *objectiveCType =
_getBridgedObjectiveCType(MetadataState::Complete, nativeType,
bridgeWitness).Value;
// Check whether we can downcast the source value to the Objective-C
// type.
auto sourceValueAsObjectiveCType =
const_cast<void*>(swift_dynamicCastUnknownClass(sourceValue,
objectiveCType));
if (!sourceValueAsObjectiveCType)
return fail();
// If the type also conforms to _ConditionallyBridgedToObjectiveC,
// use conditional bridging.
return bridgeWitness->conditionallyBridgeFromObjectiveC(
static_cast<HeapObject*>(sourceValueAsObjectiveCType),
destValue, nativeType, nativeType, bridgeWitness);
}
#endif // SWIFT_OBJC_INTEROP
// func _isBridgedNonVerbatimToObjectiveC<T>(_: T.Type) -> Bool
// Called by inlined stdlib code.
#define _isBridgedNonVerbatimToObjectiveC \
MANGLE_SYM(s33_isBridgedNonVerbatimToObjectiveCySbxmlF)
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
bool _isBridgedNonVerbatimToObjectiveC(const Metadata *value,
const Metadata *T) {
assert(!swift_isClassOrObjCExistentialTypeImpl(T));
auto bridgeWitness = findBridgeWitness(T);
return (bool)bridgeWitness;
}
// func _isClassOrObjCExistential<T>(x: T.Type) -> Bool
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
bool _swift_isClassOrObjCExistentialType(const Metadata *value,
const Metadata *T) {
return swift_isClassOrObjCExistentialTypeImpl(T);
}
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
void _swift_setClassMetadata(const HeapMetadata *newClassMetadata,
HeapObject* onObject,
const Metadata *T) {
assert(T == newClassMetadata);
onObject->metadata = newClassMetadata;
}
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL
const Metadata *swift::_swift_class_getSuperclass(const Metadata *theClass) {
if (const ClassMetadata *classType = theClass->getClassObject()) {
if (classHasSuperclass(classType))
return getMetadataForClass(classType->Superclass);
}
if (const ForeignClassMetadata *foreignClassType
= dyn_cast<ForeignClassMetadata>(theClass)) {
if (const Metadata *superclass = foreignClassType->Superclass)
return superclass;
}
return nullptr;
}
// Called by compiler-generated cast code.
SWIFT_RUNTIME_STDLIB_API
bool swift_isClassType(const Metadata *type) {
return Metadata::isAnyKindOfClass(type->getKind());
}
// Called by compiler-generated code.
SWIFT_RUNTIME_STDLIB_API
bool swift_isOptionalType(const Metadata *type) {
return type->getKind() == MetadataKind::Optional;
}
#if !SWIFT_OBJC_INTEROP
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL
bool _swift_isOptional(OpaqueValue *src, const Metadata *type) {
return swift_isOptionalType(type);
}
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_SPI
HeapObject *_swift_extractDynamicValue(OpaqueValue *value, const Metadata *self) {
OpaqueValue *outValue;
const Metadata *outType;
bool canTake = false;
findDynamicValueAndType(value, self, outValue, outType, canTake,
/*isAnyObject*/ true,
/*isExistentialMetatype*/ true);
if (!outType || (outType != self && outType->isAnyClass())) {
HeapObject *object = *(reinterpret_cast<HeapObject**>(outValue));
swift_retain(object);
return object;
}
return nullptr;
}
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERNAL
HeapObject *_swift_bridgeToObjectiveCUsingProtocolIfPossible(
OpaqueValue *src, const Metadata *srcType) {
assert(!swift_isClassOrObjCExistentialTypeImpl(srcType));
OpaqueValue *outValue;
const Metadata *outType;
bool canTake = false;
findDynamicValueAndType(src, srcType, outValue, outType, canTake,
/*isAnyObject*/ false,
/*isExistentialMetatype*/ true);
auto bridgeWitness = findBridgeWitness(outType);
if (bridgeWitness) {
auto bridgedObject =
bridgeWitness->bridgeToObjectiveC(outValue, outType, bridgeWitness);
return bridgedObject;
} else {
return nullptr;
}
}
#endif
#define OVERRIDE_CASTING COMPATIBILITY_OVERRIDE
#include COMPATIBILITY_OVERRIDE_INCLUDE_PATH