//===--- Casting.cpp - Swift Language Dynamic Casting Support -------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // Implementations of the dynamic cast runtime functions. // //===----------------------------------------------------------------------===// #include "swift/Basic/LLVM.h" #include "swift/Basic/Demangle.h" #include "swift/Basic/Fallthrough.h" #include "swift/Basic/Lazy.h" #include "swift/Runtime/Concurrent.h" #include "swift/Runtime/Config.h" #include "swift/Runtime/Enum.h" #include "swift/Runtime/HeapObject.h" #include "swift/Runtime/Metadata.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerIntPair.h" #include "swift/Runtime/Debug.h" #include "ErrorObject.h" #include "ExistentialMetadataImpl.h" #include "Private.h" #include "../SwiftShims/RuntimeShims.h" #include "stddef.h" #if defined(__APPLE__) && defined(__MACH__) #include #include #elif defined(__ELF__) #include #include #endif #include #include #include #include #include // FIXME: Clang defines max_align_t in stddef.h since 3.6. // Remove this hack when we don't care about older Clangs on all platforms. #ifdef __APPLE__ typedef std::max_align_t swift_max_align_t; #else typedef long double swift_max_align_t; #endif using namespace swift; using namespace metadataimpl; #if SWIFT_OBJC_INTEROP //#include #include #include #include #include // Aliases for Objective-C runtime entry points. const char *class_getName(const ClassMetadata* type) { return class_getName( reinterpret_cast(const_cast(type))); } // Aliases for Swift runtime entry points for Objective-C types. extern "C" const void *swift_dynamicCastObjCProtocolConditional( const void *object, size_t numProtocols, const ProtocolDescriptor * const *protocols); #endif namespace { enum class TypeSyntaxLevel { /// Any type syntax is valid. Type, /// Function types must be parenthesized. TypeSimple, }; } static void _buildNameForMetadata(const Metadata *type, TypeSyntaxLevel level, bool qualified, std::string &result); static void _buildNominalTypeName(const NominalTypeDescriptor *ntd, const Metadata *type, bool qualified, std::string &result) { auto options = Demangle::DemangleOptions(); options.DisplayDebuggerGeneratedModule = false; options.QualifyEntities = qualified; // Demangle the basic type name. result += Demangle::demangleTypeAsString(ntd->Name, strlen(ntd->Name), options); // If generic, demangle the type parameters. if (ntd->GenericParams.NumPrimaryParams > 0) { result += "<"; auto typeBytes = reinterpret_cast(type); auto genericParam = reinterpret_cast( typeBytes + sizeof(void*) * ntd->GenericParams.Offset); for (unsigned i = 0, e = ntd->GenericParams.NumPrimaryParams; i < e; ++i, ++genericParam) { if (i > 0) result += ", "; _buildNameForMetadata(*genericParam, TypeSyntaxLevel::Type, qualified, result); } result += ">"; } } static const char *_getProtocolName(const ProtocolDescriptor *protocol) { const char *name = protocol->Name; // An Objective-C protocol's name is unmangled. #if SWIFT_OBJC_INTEROP if (!protocol->Flags.isSwift()) return name; #endif // Protocol names are emitted with the _Tt prefix so that ObjC can // recognize them as mangled Swift names. assert(name[0] == '_' && name[1] == 'T' && name[2] == 't'); return name + 3; } static void _buildExistentialTypeName(const ProtocolDescriptorList *protocols, bool qualified, std::string &result) { auto options = Demangle::DemangleOptions(); options.QualifyEntities = qualified; options.DisplayDebuggerGeneratedModule = false; // If there's only one protocol, the existential type name is the protocol // name. auto descriptors = protocols->getProtocols(); if (protocols->NumProtocols == 1) { auto name = _getProtocolName(descriptors[0]); result += Demangle::demangleTypeAsString(name, strlen(name), options); return; } result += "protocol<"; for (unsigned i = 0, e = protocols->NumProtocols; i < e; ++i) { if (i > 0) result += ", "; auto name = _getProtocolName(descriptors[i]); result += Demangle::demangleTypeAsString(name, strlen(name), options); } result += ">"; } static void _buildFunctionTypeName(const FunctionTypeMetadata *func, bool qualified, std::string &result) { if (func->getNumArguments() == 1) { auto firstArgument = func->getArguments()[0].getPointer(); bool isInout = func->getArguments()[0].getFlag(); // This could be a single input tuple, with one or more arguments inside, // but guaranteed to not have inout types. if (auto tupleMetadata = dyn_cast(firstArgument)) { _buildNameForMetadata(tupleMetadata, TypeSyntaxLevel::TypeSimple, qualified, result); } else { if (isInout) result += "inout "; _buildNameForMetadata(firstArgument, TypeSyntaxLevel::TypeSimple, qualified, result); } } else { result += "("; for (size_t i = 0; i < func->getNumArguments(); ++i) { auto arg = func->getArguments()[i].getPointer(); bool isInout = func->getArguments()[i].getFlag(); if (isInout) result += "inout "; _buildNameForMetadata(arg, TypeSyntaxLevel::TypeSimple, qualified, result); if (i < func->getNumArguments() - 1) { result += ", "; } } result += ")"; } if (func->throws()) { result += " throws"; } result += " -> "; _buildNameForMetadata(func->ResultType, TypeSyntaxLevel::Type, qualified, result); } // Build a user-comprehensible name for a type. static void _buildNameForMetadata(const Metadata *type, TypeSyntaxLevel level, bool qualified, std::string &result) { auto options = Demangle::DemangleOptions(); options.DisplayDebuggerGeneratedModule = false; switch (type->getKind()) { case MetadataKind::Class: { auto classType = static_cast(type); #if SWIFT_OBJC_INTEROP // 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; } #endif return _buildNominalTypeName(classType->getDescription(), classType, qualified, result); } case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Struct: { auto structType = static_cast(type); return _buildNominalTypeName(structType->Description, type, qualified, result); } case MetadataKind::ObjCClassWrapper: { #if SWIFT_OBJC_INTEROP auto objcWrapper = static_cast(type); result += class_getName(objcWrapper->Class); #else assert(false && "no ObjC interop"); #endif return; } case MetadataKind::ForeignClass: { auto foreign = static_cast(type); const char *name = foreign->getName(); size_t len = strlen(name); result += Demangle::demangleTypeAsString(name, len, options); return; } case MetadataKind::Existential: { auto exis = static_cast(type); _buildExistentialTypeName(&exis->Protocols, qualified, result); return; } case MetadataKind::ExistentialMetatype: { auto metatype = static_cast(type); _buildNameForMetadata(metatype->InstanceType, TypeSyntaxLevel::TypeSimple, qualified, result); result += ".Type"; return; } case MetadataKind::Function: { if (level >= TypeSyntaxLevel::TypeSimple) result += "("; auto func = static_cast(type); switch (func->getConvention()) { case FunctionMetadataConvention::Swift: break; case FunctionMetadataConvention::Thin: result += "@convention(thin) "; break; case FunctionMetadataConvention::Block: result += "@convention(block) "; break; case FunctionMetadataConvention::CFunctionPointer: result += "@convention(c) "; break; } _buildFunctionTypeName(func, qualified, result); if (level >= TypeSyntaxLevel::TypeSimple) result += ")"; return; } case MetadataKind::Metatype: { auto metatype = static_cast(type); _buildNameForMetadata(metatype->InstanceType, TypeSyntaxLevel::TypeSimple, qualified, result); if (metatype->InstanceType->isAnyExistentialType()) result += ".Protocol"; else result += ".Type"; return; } case MetadataKind::Tuple: { auto tuple = static_cast(type); result += "("; auto elts = tuple->getElements(); for (unsigned i = 0, e = tuple->NumElements; i < e; ++i) { if (i > 0) result += ", "; _buildNameForMetadata(elts[i].Type, TypeSyntaxLevel::Type, qualified, result); } result += ")"; return; } case MetadataKind::Opaque: { // TODO result += "<<>>"; return; } case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: break; } result += "<<>>"; } /// Return a user-comprehensible name for the given type. std::string swift::nameForMetadata(const Metadata *type, bool qualified) { std::string result; _buildNameForMetadata(type, TypeSyntaxLevel::Type, qualified, result); return result; } extern "C" TwoWordPair::Return swift_getTypeName(const Metadata *type, bool qualified) { using Pair = TwoWordPair; using Key = llvm::PointerIntPair; static pthread_rwlock_t TypeNameCacheLock = PTHREAD_RWLOCK_INITIALIZER; static Lazy>> TypeNameCache; Key key(type, qualified); auto &cache = TypeNameCache.get(); pthread_rwlock_rdlock(&TypeNameCacheLock); auto found = cache.find(key); if (found != cache.end()) { auto result = found->second; pthread_rwlock_unlock(&TypeNameCacheLock); return Pair{result.first, result.second}; } pthread_rwlock_unlock(&TypeNameCacheLock); pthread_rwlock_wrlock(&TypeNameCacheLock); // Someone may have beaten us to the write lock. found = cache.find(key); if (found != cache.end()) { auto result = found->second; pthread_rwlock_unlock(&TypeNameCacheLock); return Pair{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}}); pthread_rwlock_unlock(&TypeNameCacheLock); return Pair{result, size}; } /// Report a dynamic cast failure. // This is noinline with asm("") 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. LLVM_ATTRIBUTE_NORETURN LLVM_ATTRIBUTE_NOINLINE void swift::swift_dynamicCastFailure(const void *sourceType, const char *sourceName, const void *targetType, const char *targetName, const char *message) { asm(""); swift::fatalError("Could not cast value of type '%s' (%p) to '%s' (%p)%s%s\n", sourceName, sourceType, targetName, targetType, message ? ": " : ".", message ? message : ""); } LLVM_ATTRIBUTE_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); } /// Report a corrupted type object. LLVM_ATTRIBUTE_NORETURN LLVM_ATTRIBUTE_ALWAYS_INLINE // Minimize trashed registers static void _failCorruptType(const Metadata *type) { swift::crash("Corrupt Swift type object"); } #if SWIFT_OBJC_INTEROP // Objective-c bridging helpers. namespace { struct _ObjectiveCBridgeableWitnessTable; } static const _ObjectiveCBridgeableWitnessTable * findBridgeWitness(const Metadata *T); static bool _dynamicCastValueToClassViaObjCBridgeable( OpaqueValue *dest, OpaqueValue *src, const Metadata *srcType, const Metadata *targetType, const _ObjectiveCBridgeableWitnessTable *srcBridgeWitness, DynamicCastFlags flags); static bool _dynamicCastValueToClassExistentialViaObjCBridgeable( OpaqueValue *dest, OpaqueValue *src, const Metadata *srcType, const ExistentialTypeMetadata *targetType, const _ObjectiveCBridgeableWitnessTable *srcBridgeWitness, DynamicCastFlags flags); static bool _dynamicCastClassToValueViaObjCBridgeable( OpaqueValue *dest, OpaqueValue *src, const Metadata *srcType, const Metadata *targetType, const _ObjectiveCBridgeableWitnessTable *targetBridgeWitness, DynamicCastFlags flags); #endif /// A convenient method for failing out of a dynamic cast. static bool _fail(OpaqueValue *srcValue, const Metadata *srcType, const Metadata *targetType, DynamicCastFlags flags) { if (flags & DynamicCastFlags::Unconditional) swift_dynamicCastFailure(srcType, targetType); if (flags & DynamicCastFlags::DestroyOnFailure) srcType->vw_destroy(srcValue); return false; } /// A convenient method for succeeding at a dynamic cast. static bool _succeed(OpaqueValue *dest, OpaqueValue *src, const Metadata *srcType, DynamicCastFlags flags) { if (flags & DynamicCastFlags::TakeOnSuccess) { srcType->vw_initializeWithTake(dest, src); } else { srcType->vw_initializeWithCopy(dest, src); } return true; } /// 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 = _swift_getSuperclass(sourceType); } while (sourceType); return nullptr; } /// Dynamically cast a class instance to a Swift class type. const void * swift::swift_dynamicCastClass(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 isa = _swift_getClassOfAllocated(object); if (_dynamicCastClassMetatype(isa, targetType)) return object; return nullptr; } /// Dynamically cast a class object to a Swift class type. const void * swift::swift_dynamicCastClassUnconditional(const void *object, const ClassMetadata *targetType) { 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, const ProtocolDescriptor *protocol) { const void *object = *reinterpret_cast(value); return swift_dynamicCastObjCProtocolConditional(object, 1, &protocol); } #endif /// Check whether a type conforms to a protocol. /// /// \param value - can be null, in which case the question should /// be answered abstractly if possible /// \param conformance - if non-null, and the protocol requires a /// witness table, and the type implements the protocol, the witness /// table will be placed here static bool _conformsToProtocol(const OpaqueValue *value, const Metadata *type, const ProtocolDescriptor *protocol, const WitnessTable **conformance) { // Handle AnyObject directly. if (protocol->Flags.getSpecialProtocol() == SpecialProtocol::AnyObject) { switch (type->getKind()) { case MetadataKind::Class: case MetadataKind::ObjCClassWrapper: case MetadataKind::ForeignClass: // Classes conform to AnyObject. return true; case MetadataKind::Existential: { auto sourceExistential = cast(type); // The existential conforms to AnyObject if it's class-constrained. // FIXME: It also must not carry witness tables. return sourceExistential->isClassBounded(); } case MetadataKind::ExistentialMetatype: case MetadataKind::Metatype: case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Struct: case MetadataKind::Tuple: return false; } _failCorruptType(type); } // Look up the witness table for protocols that need them. if (protocol->Flags.needsWitnessTable()) { auto witness = swift_conformsToProtocol(type, protocol); 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); } else { return classConformsToObjCProtocol(type, protocol); } #endif return false; case MetadataKind::ObjCClassWrapper: { #if SWIFT_OBJC_INTEROP if (value) { return _unknownClassConformsToObjCProtocol(value, protocol); } else { auto wrapper = cast(type); return classConformsToObjCProtocol(wrapper->Class, protocol); } #endif return false; } case MetadataKind::ForeignClass: #if SWIFT_OBJC_INTEROP if (value) return _unknownClassConformsToObjCProtocol(value, protocol); return false; #else _failCorruptType(type); #endif case MetadataKind::Existential: // FIXME case MetadataKind::ExistentialMetatype: // FIXME case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Metatype: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Struct: case MetadataKind::Tuple: 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 ProtocolDescriptorList &protocols, const WitnessTable **conformances) { for (unsigned i = 0, n = protocols.NumProtocols; i != n; ++i) { const ProtocolDescriptor *protocol = protocols[i]; if (!_conformsToProtocol(value, type, protocol, conformances)) return false; if (protocol->Flags.needsWitnessTable()) { assert(*conformances != nullptr); ++conformances; } } return true; } static bool shouldDeallocateSource(bool castSucceeded, DynamicCastFlags flags) { return (castSucceeded && (flags & DynamicCastFlags::TakeOnSuccess)) || (!castSucceeded && (flags & DynamicCastFlags::DestroyOnFailure)); } /// Given that a cast operation is complete, maybe deallocate an /// opaque existential value. static void _maybeDeallocateOpaqueExistential(OpaqueValue *srcExistential, bool castSucceeded, DynamicCastFlags flags) { if (shouldDeallocateSource(castSucceeded, flags)) { auto container = reinterpret_cast(srcExistential); container->Type->vw_deallocateBuffer(&container->Buffer); } } /// 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) { 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(value)); return; } case MetadataKind::Existential: { auto existentialType = cast(type); 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(value); outValue = (OpaqueValue*) &existential->Value; outType = swift_getObjectType((HeapObject*) existential->Value); return; } case ExistentialTypeRepresentation::Opaque: case ExistentialTypeRepresentation::ErrorType: { OpaqueValue *innerValue = existentialType->projectValue(value); const Metadata *innerType = existentialType->getDynamicType(value); inoutCanTake &= existentialType->mayTakeValue(value); return findDynamicValueAndType(innerValue, innerType, outValue, outType, inoutCanTake); } } } case MetadataKind::Metatype: case MetadataKind::ExistentialMetatype: { auto storedType = *(const Metadata **) value; outValue = value; outType = swift_getMetatypeMetadata(storedType); return; } // Non-polymorphic types. case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Struct: case MetadataKind::Tuple: outValue = value; outType = type; return; } _failCorruptType(type); } extern "C" const Metadata * swift::swift_getDynamicType(OpaqueValue *value, const Metadata *self) { OpaqueValue *outValue; const Metadata *outType; bool canTake = false; findDynamicValueAndType(value, self, outValue, outType, canTake); return outType; } /// Given a possibly-existential value, deallocate any buffer in its storage. static void deallocateDynamicValue(OpaqueValue *value, const Metadata *type) { switch (type->getKind()) { case MetadataKind::Existential: { auto existentialType = cast(type); switch (existentialType->getRepresentation()) { case ExistentialTypeRepresentation::Class: // Nothing to clean up. break; case ExistentialTypeRepresentation::ErrorType: // TODO: We could clean up from a reclaimed uniquely-referenced error box. break; case ExistentialTypeRepresentation::Opaque: auto existential = reinterpret_cast(value); // Handle the possibility of nested existentials. OpaqueValue *existentialValue = existential->Type->vw_projectBuffer(&existential->Buffer); deallocateDynamicValue(existentialValue, existential->Type); // Deallocate the buffer. existential->Type->vw_deallocateBuffer(&existential->Buffer); break; } return; } // None of the rest of these require deallocation. case MetadataKind::Class: case MetadataKind::ForeignClass: case MetadataKind::ObjCClassWrapper: case MetadataKind::Metatype: case MetadataKind::ExistentialMetatype: case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Struct: case MetadataKind::Tuple: return; } _failCorruptType(type); } #if SWIFT_OBJC_INTEROP extern "C" id swift_dynamicCastMetatypeToObjectConditional(const Metadata *metatype) { switch (metatype->getKind()) { case MetadataKind::Class: // Swift classes are objects in and of themselves. return (id)metatype; case MetadataKind::ObjCClassWrapper: { // Unwrap ObjC class objects. auto wrapper = static_cast(metatype); return (id)wrapper->getClassObject(); } // Other kinds of metadata don't cast to AnyObject. case MetadataKind::Struct: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Tuple: case MetadataKind::Function: case MetadataKind::Existential: case MetadataKind::Metatype: case MetadataKind::ExistentialMetatype: case MetadataKind::ForeignClass: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: return nullptr; } } extern "C" id swift_dynamicCastMetatypeToObjectUnconditional(const Metadata *metatype) { switch (metatype->getKind()) { case MetadataKind::Class: // Swift classes are objects in and of themselves. return (id)metatype; case MetadataKind::ObjCClassWrapper: { // Unwrap ObjC class objects. auto wrapper = static_cast(metatype); return (id)wrapper->getClassObject(); } // Other kinds of metadata don't cast to AnyObject. case MetadataKind::Struct: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Tuple: case MetadataKind::Function: case MetadataKind::Existential: case MetadataKind::Metatype: case MetadataKind::ExistentialMetatype: case MetadataKind::ForeignClass: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: { std::string sourceName = nameForMetadata(metatype); swift_dynamicCastFailure(metatype, sourceName.c_str(), nullptr, "AnyObject", "only class metatypes can be converted to AnyObject"); } } } #endif /// Perform a dynamic cast to an existential type. static bool _dynamicCastToExistential(OpaqueValue *dest, OpaqueValue *src, const Metadata *srcType, const ExistentialTypeMetadata *targetType, DynamicCastFlags flags) { #if SWIFT_OBJC_INTEROP // This variable's lifetime needs to be for the whole function, but is // only valid with Objective-C interop enabled. id tmp; #endif // Find the actual type of the source. OpaqueValue *srcDynamicValue; const Metadata *srcDynamicType; bool canTake = true; findDynamicValueAndType(src, srcType, srcDynamicValue, srcDynamicType, canTake); auto maybeDeallocateSourceAfterSuccess = [&] { if (shouldDeallocateSource(/*succeeded*/ true, flags)) { // If we're able to take the dynamic value, then clean up any leftover // buffers it may have been contained in. if (canTake && src != srcDynamicValue) deallocateDynamicValue(src, srcType); // Otherwise, deallocate the original value wholesale if we couldn't take // it. else if (!canTake) srcType->vw_destroy(src); } }; // The representation of an existential is different for some protocols. switch (targetType->getRepresentation()) { case ExistentialTypeRepresentation::Class: { auto destExistential = reinterpret_cast(dest); // If the source type is a value type, it cannot possibly conform // to a class-bounded protocol. switch (srcDynamicType->getKind()) { case MetadataKind::ExistentialMetatype: case MetadataKind::Metatype: { #if SWIFT_OBJC_INTEROP // Class metadata can be used as an object when ObjC interop is available. auto metatypePtr = reinterpret_cast(src); auto metatype = *metatypePtr; tmp = swift_dynamicCastMetatypeToObjectConditional(metatype); // If the cast succeeded, use the result value as the class instance // below. if (tmp) { srcDynamicValue = reinterpret_cast(&tmp); srcDynamicType = reinterpret_cast(tmp); break; } #endif // Otherwise, metatypes aren't class objects. return _fail(src, srcType, targetType, flags); } case MetadataKind::Class: case MetadataKind::ObjCClassWrapper: case MetadataKind::ForeignClass: case MetadataKind::Existential: // Handle these cases below. break; case MetadataKind::Struct: case MetadataKind::Enum: case MetadataKind::Optional: #if SWIFT_OBJC_INTEROP // If the source type is bridged to Objective-C, try to bridge. if (auto srcBridgeWitness = findBridgeWitness(srcDynamicType)) { DynamicCastFlags subFlags = flags - (DynamicCastFlags::TakeOnSuccess | DynamicCastFlags::DestroyOnFailure); bool success = _dynamicCastValueToClassExistentialViaObjCBridgeable( dest, srcDynamicValue, srcDynamicType, targetType, srcBridgeWitness, subFlags); // Destroy the source value, since we avoided taking or destroying // it above. if (shouldDeallocateSource(success, flags)) { srcType->vw_destroy(src); } return success; } #endif break; case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Opaque: case MetadataKind::Tuple: // Will never succeed. return _fail(src, srcType, targetType, flags); } // Check for protocol conformances and fill in the witness tables. if (!_conformsToProtocols(srcDynamicValue, srcDynamicType, targetType->Protocols, destExistential->getWitnessTables())) { return _fail(srcDynamicValue, srcDynamicType, targetType, flags); } auto object = *(reinterpret_cast(srcDynamicValue)); destExistential->Value = object; if (!canTake || !(flags & DynamicCastFlags::TakeOnSuccess)) { swift_retain(object); } maybeDeallocateSourceAfterSuccess(); return true; } case ExistentialTypeRepresentation::Opaque: { auto destExistential = reinterpret_cast(dest); // Check for protocol conformances and fill in the witness tables. if (!_conformsToProtocols(srcDynamicValue, srcDynamicType, targetType->Protocols, destExistential->getWitnessTables())) return _fail(srcDynamicValue, srcDynamicType, targetType, flags); // Fill in the type and value. destExistential->Type = srcDynamicType; if (canTake && (flags & DynamicCastFlags::TakeOnSuccess)) { srcDynamicType->vw_initializeBufferWithTake(&destExistential->Buffer, srcDynamicValue); } else { srcDynamicType->vw_initializeBufferWithCopy(&destExistential->Buffer, srcDynamicValue); } maybeDeallocateSourceAfterSuccess(); return true; } case ExistentialTypeRepresentation::ErrorType: { auto destBoxAddr = reinterpret_cast(dest); // Check for the ErrorType protocol conformance, which should be the only // one we need. assert(targetType->Protocols.NumProtocols == 1); const WitnessTable *errorWitness; if (!_conformsToProtocols(srcDynamicValue, srcDynamicType, targetType->Protocols, &errorWitness)) return _fail(srcDynamicValue, srcDynamicType, targetType, flags); BoxPair destBox = swift_allocError(srcDynamicType, errorWitness, srcDynamicValue, /*isTake*/ canTake && (flags & DynamicCastFlags::TakeOnSuccess)); *destBoxAddr = reinterpret_cast(destBox.first); maybeDeallocateSourceAfterSuccess(); return true; } } } static const void * _dynamicCastUnknownClassToExistential(const void *object, const ExistentialTypeMetadata *targetType) { for (unsigned i = 0, e = targetType->Protocols.NumProtocols; i < e; ++i) { const ProtocolDescriptor *protocol = targetType->Protocols[i]; switch (protocol->Flags.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 // All classes conform to AnyObject. if (protocol->Flags.getSpecialProtocol() == SpecialProtocol::AnyObject) break; if (!objectConformsToObjCProtocol(object, protocol)) return nullptr; break; #else assert(false && "ObjC interop disabled?!"); return nullptr; #endif case ProtocolDispatchStrategy::Empty: // The only non-@objc, non-witness-table-requiring protocol should be // AnyObject for now. assert(protocol->Flags.getSpecialProtocol() == SpecialProtocol::AnyObject && "swift protocols besides AnyObject should always require a " "witness table"); break; } } return object; } /// Perform a dynamic class of some sort of class instance to some /// sort of class type. const void * swift::swift_dynamicCastUnknownClass(const void *object, const Metadata *targetType) { switch (targetType->getKind()) { case MetadataKind::Class: { auto targetClassType = static_cast(targetType); return swift_dynamicCastClass(object, targetClassType); } case MetadataKind::ObjCClassWrapper: { #if SWIFT_OBJC_INTEROP auto targetClassType = static_cast(targetType)->Class; return swift_dynamicCastObjCClass(object, targetClassType); #else _failCorruptType(targetType); #endif } case MetadataKind::ForeignClass: { #if SWIFT_OBJC_INTEROP auto targetClassType = static_cast(targetType); return swift_dynamicCastForeignClass(object, targetClassType); #else _failCorruptType(targetType); #endif } case MetadataKind::Existential: { return _dynamicCastUnknownClassToExistential(object, static_cast(targetType)); } case MetadataKind::ExistentialMetatype: case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Metatype: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Struct: case MetadataKind::Tuple: return nullptr; } _failCorruptType(targetType); } /// Perform a dynamic class of some sort of class instance to some /// sort of class type. const void * swift::swift_dynamicCastUnknownClassUnconditional(const void *object, const Metadata *targetType) { switch (targetType->getKind()) { case MetadataKind::Class: { auto targetClassType = static_cast(targetType); return swift_dynamicCastClassUnconditional(object, targetClassType); } case MetadataKind::ObjCClassWrapper: { #if SWIFT_OBJC_INTEROP auto targetClassType = static_cast(targetType)->Class; return swift_dynamicCastObjCClassUnconditional(object, targetClassType); #else _failCorruptType(targetType); #endif } case MetadataKind::ForeignClass: { #if SWIFT_OBJC_INTEROP auto targetClassType = static_cast(targetType); return swift_dynamicCastForeignClassUnconditional(object, targetClassType); #else _failCorruptType(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(targetType))) return result; swift_dynamicCastFailure(_swift_getClass(object), targetType); } case MetadataKind::ExistentialMetatype: case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Metatype: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Struct: case MetadataKind::Tuple: swift_dynamicCastFailure(_swift_getClass(object), targetType); } _failCorruptType(targetType); } const Metadata * swift::swift_dynamicCastMetatype(const Metadata *sourceType, const Metadata *targetType) { auto origSourceType = sourceType; switch (targetType->getKind()) { case MetadataKind::ObjCClassWrapper: // Get the actual class object. targetType = static_cast(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(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; } case MetadataKind::Existential: case MetadataKind::ExistentialMetatype: case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Metatype: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Struct: case MetadataKind::Tuple: return nullptr; } break; case MetadataKind::ForeignClass: switch (sourceType->getKind()) { case MetadataKind::ObjCClassWrapper: // Get the actual class object. sourceType = static_cast(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; case MetadataKind::Existential: case MetadataKind::ExistentialMetatype: case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Metatype: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Struct: case MetadataKind::Tuple: return nullptr; } break; case MetadataKind::Existential: case MetadataKind::ExistentialMetatype: case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Metatype: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Struct: case MetadataKind::Tuple: // The cast succeeds only if the metadata pointers are statically // equivalent. if (sourceType != targetType) return nullptr; return origSourceType; } } const Metadata * swift::swift_dynamicCastMetatypeUnconditional(const Metadata *sourceType, const Metadata *targetType) { auto origSourceType = sourceType; switch (targetType->getKind()) { case MetadataKind::ObjCClassWrapper: // Get the actual class object. targetType = static_cast(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(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); #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); // If we returned, then the cast succeeded. return origSourceType; } case MetadataKind::Existential: case MetadataKind::ExistentialMetatype: case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Metatype: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Struct: case MetadataKind::Tuple: 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(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); // If we returned, then the cast succeeded. return origSourceType; case MetadataKind::Existential: case MetadataKind::ExistentialMetatype: case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Metatype: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Struct: case MetadataKind::Tuple: swift_dynamicCastFailure(sourceType, targetType); } break; case MetadataKind::Existential: case MetadataKind::ExistentialMetatype: case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Metatype: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Struct: case MetadataKind::Tuple: // The cast succeeds only if the metadata pointers are statically // equivalent. if (sourceType != targetType) swift_dynamicCastFailure(sourceType, targetType); return origSourceType; } } #if SWIFT_OBJC_INTEROP /// Do a dynamic cast to the target class. static void *_dynamicCastUnknownClass(void *object, const Metadata *targetType, bool unconditional) { // The unconditional path avoids some failure logic. if (unconditional) { return const_cast( swift_dynamicCastUnknownClassUnconditional(object, targetType)); } return const_cast(swift_dynamicCastUnknownClass(object, targetType)); } #endif static bool _dynamicCastUnknownClassIndirect(OpaqueValue *dest, void *object, const Metadata *targetType, DynamicCastFlags flags) { void **destSlot = reinterpret_cast(dest); // The unconditional path avoids some failure logic. if (flags & DynamicCastFlags::Unconditional) { void *result = const_cast( swift_dynamicCastUnknownClassUnconditional(object, targetType)); *destSlot = result; if (!(flags & DynamicCastFlags::TakeOnSuccess)) { swift_unknownRetain(result); } return true; } // Okay, we're doing a conditional cast. void *result = const_cast(swift_dynamicCastUnknownClass(object, targetType)); assert(result == nullptr || object == result); // If the cast failed, destroy the input and return false. if (!result) { if (flags & DynamicCastFlags::DestroyOnFailure) { swift_unknownRelease(object); } return false; } // Otherwise, store to the destination and return true. *destSlot = result; if (!(flags & DynamicCastFlags::TakeOnSuccess)) { swift_unknownRetain(result); } return true; } #if SWIFT_OBJC_INTEROP extern "C" const ProtocolDescriptor _TMps9ErrorType; static const WitnessTable *findErrorTypeWitness(const Metadata *srcType) { return swift_conformsToProtocol(srcType, &_TMps9ErrorType); } static const Metadata *getNSErrorTypeMetadata() { return SWIFT_LAZY_CONSTANT( swift_getObjCClassMetadata((const ClassMetadata *)getNSErrorClass())); } #endif /// Perform a dynamic cast from an existential type to some kind of /// class type. static bool _dynamicCastToUnknownClassFromExistential(OpaqueValue *dest, OpaqueValue *src, const ExistentialTypeMetadata *srcType, const Metadata *targetType, DynamicCastFlags flags) { switch (srcType->getRepresentation()) { case ExistentialTypeRepresentation::Class: { auto classContainer = reinterpret_cast(src); void *obj = classContainer->Value; #if SWIFT_OBJC_INTEROP // If we're casting to NSError, we may need a representation change, // so fall into the general swift_dynamicCast path. if (targetType == getNSErrorTypeMetadata()) { return swift_dynamicCast(dest, src, swift_getObjectType((HeapObject*)obj), targetType, flags); } #endif return _dynamicCastUnknownClassIndirect(dest, obj, targetType, flags); } case ExistentialTypeRepresentation::Opaque: { auto opaqueContainer = reinterpret_cast(src); auto srcCapturedType = opaqueContainer->Type; OpaqueValue *srcValue = srcCapturedType->vw_projectBuffer(&opaqueContainer->Buffer); bool result = swift_dynamicCast(dest, srcValue, srcCapturedType, targetType, flags); if (src != srcValue) _maybeDeallocateOpaqueExistential(src, result, flags); return result; } case ExistentialTypeRepresentation::ErrorType: { const SwiftError *errorBox = *reinterpret_cast(src); auto srcCapturedType = errorBox->getType(); const OpaqueValue *srcValue; // A bridged NSError is itself the value. if (errorBox->isPureNSError()) srcValue = src; else srcValue = errorBox->getValue(); // We can't take or destroy the value out of the box since it might be // shared. auto subFlags = flags - (DynamicCastFlags::TakeOnSuccess | DynamicCastFlags::DestroyOnFailure); bool result = swift_dynamicCast(dest, const_cast(srcValue), srcCapturedType, targetType, subFlags); if (shouldDeallocateSource(result, flags)) srcType->vw_destroy(src); return result; } } } /// Perform a dynamic cast from an existential type to a /// non-existential type. static bool _dynamicCastFromExistential(OpaqueValue *dest, OpaqueValue *src, const ExistentialTypeMetadata *srcType, const Metadata *targetType, DynamicCastFlags flags) { OpaqueValue *srcValue; const Metadata *srcCapturedType; bool isOutOfLine; bool canTake; switch (srcType->getRepresentation()) { case ExistentialTypeRepresentation::Class: { auto classContainer = reinterpret_cast(src); srcValue = (OpaqueValue*) &classContainer->Value; void *obj = classContainer->Value; srcCapturedType = swift_getObjectType(reinterpret_cast(obj)); isOutOfLine = false; canTake = true; break; } case ExistentialTypeRepresentation::Opaque: { auto opaqueContainer = reinterpret_cast(src); srcCapturedType = opaqueContainer->Type; srcValue = srcCapturedType->vw_projectBuffer(&opaqueContainer->Buffer); isOutOfLine = (src != srcValue); canTake = true; break; } case ExistentialTypeRepresentation::ErrorType: { const SwiftError *errorBox = *reinterpret_cast(src); srcCapturedType = errorBox->getType(); // A bridged NSError is itself the value. if (errorBox->isPureNSError()) srcValue = src; else srcValue = const_cast(errorBox->getValue()); // The value is out-of-line, but we can't take it, since it may be shared. isOutOfLine = true; canTake = false; break; } } auto subFlags = flags; if (!canTake) subFlags = subFlags - (DynamicCastFlags::DestroyOnFailure | DynamicCastFlags::TakeOnSuccess); bool result = swift_dynamicCast(dest, srcValue, srcCapturedType, targetType, subFlags); // Deallocate the existential husk if we took from it. if (canTake && result && isOutOfLine) _maybeDeallocateOpaqueExistential(src, result, flags); // If we couldn't take, we still may need to destroy the whole value. else if (!canTake && shouldDeallocateSource(result, flags)) srcType->vw_destroy(src); return result; } /// Perform a dynamic cast of a metatype to a metatype. /// /// Note that the check is whether 'metatype' is an *instance of* /// 'targetType', not a *subtype of it*. static bool _dynamicCastMetatypeToMetatype(OpaqueValue *dest, const Metadata *metatype, const MetatypeMetadata *targetType, DynamicCastFlags flags) { const Metadata *result; if (flags & DynamicCastFlags::Unconditional) { result = swift_dynamicCastMetatypeUnconditional(metatype, targetType->InstanceType); } else { result = swift_dynamicCastMetatype(metatype, targetType->InstanceType); if (!result) return false; } *((const Metadata **) dest) = result; return true; } /// Check whether an unknown class instance is actually a class object. static const Metadata *_getUnknownClassAsMetatype(void *object) { #if SWIFT_OBJC_INTEROP // Objective-C class metadata are objects, so an AnyObject (or NSObject) // may refer to a class object. // Test whether the object's isa is a metaclass, which indicates that the // object is a class. Class isa = object_getClass((id)object); if (class_isMetaClass(isa)) { return swift_getObjCClassMetadata((const ClassMetadata *)object); } #endif // Class values are currently never metatypes in the native runtime. return nullptr; } /// Perform a dynamic cast of a class value to a metatype type. static bool _dynamicCastUnknownClassToMetatype(OpaqueValue *dest, void *object, const MetatypeMetadata *targetType, DynamicCastFlags flags) { if (auto metatype = _getUnknownClassAsMetatype(object)) return _dynamicCastMetatypeToMetatype(dest, metatype, targetType, flags); if (flags & DynamicCastFlags::Unconditional) swift_dynamicCastFailure(_swift_getClass(object), targetType); if (flags & DynamicCastFlags::DestroyOnFailure) swift_unknownRelease((HeapObject*) object); return false; } /// Perform a dynamic cast to a metatype type. static bool _dynamicCastToMetatype(OpaqueValue *dest, OpaqueValue *src, const Metadata *srcType, const MetatypeMetadata *targetType, DynamicCastFlags flags) { switch (srcType->getKind()) { case MetadataKind::Metatype: { const Metadata *srcMetatype = *(const Metadata * const *) src; return _dynamicCastMetatypeToMetatype(dest, srcMetatype, targetType, flags); } case MetadataKind::ExistentialMetatype: { const Metadata *srcMetatype = *(const Metadata * const *) src; return _dynamicCastMetatypeToMetatype(dest, srcMetatype, targetType, flags); } case MetadataKind::Existential: { auto srcExistentialType = cast(srcType); switch (srcExistentialType->getRepresentation()) { case ExistentialTypeRepresentation::Class: { auto srcExistential = (ClassExistentialContainer*) src; return _dynamicCastUnknownClassToMetatype(dest, srcExistential->Value, targetType, flags); } case ExistentialTypeRepresentation::Opaque: { auto srcExistential = (OpaqueExistentialContainer*) src; auto srcValueType = srcExistential->Type; auto srcValue = srcValueType->vw_projectBuffer(&srcExistential->Buffer); bool result = _dynamicCastToMetatype(dest, srcValue, srcValueType, targetType, flags); if (src != srcValue) _maybeDeallocateOpaqueExistential(src, result, flags); return result; } case ExistentialTypeRepresentation::ErrorType: { const SwiftError *srcBox = *reinterpret_cast(src); auto srcValueType = srcBox->getType(); const OpaqueValue *srcValue; if (srcBox->isPureNSError()) srcValue = src; else srcValue = srcBox->getValue(); // Can't take from a box since the value may be shared. auto subFlags = flags - (DynamicCastFlags::TakeOnSuccess | DynamicCastFlags::DestroyOnFailure); bool result = _dynamicCastToMetatype(dest, const_cast(srcValue), srcValueType, targetType, subFlags); if (shouldDeallocateSource(result, flags)) srcType->vw_destroy(src); return result; } } } case MetadataKind::Class: case MetadataKind::ObjCClassWrapper: case MetadataKind::ForeignClass: { void *object = *reinterpret_cast(src); return _dynamicCastUnknownClassToMetatype(dest, object, targetType, flags); } case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Struct: case MetadataKind::Tuple: return _fail(src, srcType, targetType, flags); } _failCorruptType(srcType); } /// Perform a dynamic cast of a metatype to an existential metatype type. static bool _dynamicCastMetatypeToExistentialMetatype(OpaqueValue *dest, const Metadata *srcMetatype, const ExistentialMetatypeMetadata *targetType, DynamicCastFlags flags, bool writeDestMetatype = true) { // The instance type of an existential metatype must be either an // existential or an existential metatype. auto destMetatype = reinterpret_cast(dest); // If it's an existential, we need to check for conformances. auto targetInstanceType = targetType->InstanceType; if (auto targetInstanceTypeAsExistential = dyn_cast(targetInstanceType)) { // Check for conformance to all the protocols. // TODO: collect the witness tables. auto &protocols = targetInstanceTypeAsExistential->Protocols; const WitnessTable **conformance = writeDestMetatype ? destMetatype->getWitnessTables() : nullptr; for (unsigned i = 0, n = protocols.NumProtocols; i != n; ++i) { const ProtocolDescriptor *protocol = protocols[i]; if (!_conformsToProtocol(nullptr, srcMetatype, protocol, conformance)) { if (flags & DynamicCastFlags::Unconditional) swift_dynamicCastFailure(srcMetatype, targetType); return false; } if (conformance && protocol->Flags.needsWitnessTable()) ++conformance; } if (writeDestMetatype) destMetatype->Value = srcMetatype; return true; } // Otherwise, we're casting to SomeProtocol.Type.Type. auto targetInstanceTypeAsMetatype = cast(targetInstanceType); // If the source type isn't a metatype, the cast fails. auto srcMetatypeMetatype = dyn_cast(srcMetatype); if (!srcMetatypeMetatype) { if (flags & DynamicCastFlags::Unconditional) swift_dynamicCastFailure(srcMetatype, targetType); return false; } // The representation of an existential metatype remains consistent // arbitrarily deep: a metatype, followed by some protocols. The // protocols are the same at every level, so we can just set the // metatype correctly and then recurse, letting the recursive call // fill in the conformance information correctly. // Proactively set the destination metatype so that we can tail-recur, // unless we've already done so. There's no harm in doing this even if // the cast fails. if (writeDestMetatype) *((const Metadata **) dest) = srcMetatype; // Recurse. auto srcInstanceType = srcMetatypeMetatype->InstanceType; return _dynamicCastMetatypeToExistentialMetatype(dest, srcInstanceType, targetInstanceTypeAsMetatype, flags, /*overwrite*/ false); } /// Perform a dynamic cast of a class value to an existential metatype type. static bool _dynamicCastUnknownClassToExistentialMetatype(OpaqueValue *dest, void *object, const ExistentialMetatypeMetadata *targetType, DynamicCastFlags flags) { if (auto metatype = _getUnknownClassAsMetatype(object)) return _dynamicCastMetatypeToExistentialMetatype(dest, metatype, targetType, flags); // Class values are currently never metatypes (?). if (flags & DynamicCastFlags::Unconditional) swift_dynamicCastFailure(_swift_getClass(object), targetType); if (flags & DynamicCastFlags::DestroyOnFailure) swift_unknownRelease((HeapObject*) object); return false; } /// Perform a dynamic cast to an existential metatype type. static bool _dynamicCastToExistentialMetatype(OpaqueValue *dest, OpaqueValue *src, const Metadata *srcType, const ExistentialMetatypeMetadata *targetType, DynamicCastFlags flags) { switch (srcType->getKind()) { case MetadataKind::Metatype: { const Metadata *srcMetatype = *(const Metadata * const *) src; return _dynamicCastMetatypeToExistentialMetatype(dest, srcMetatype, targetType, flags); } // TODO: take advantage of protocol conformances already known. case MetadataKind::ExistentialMetatype: { const Metadata *srcMetatype = *(const Metadata * const *) src; return _dynamicCastMetatypeToExistentialMetatype(dest, srcMetatype, targetType, flags); } case MetadataKind::Existential: { auto srcExistentialType = cast(srcType); switch (srcExistentialType->getRepresentation()) { case ExistentialTypeRepresentation::Class: { auto srcExistential = (ClassExistentialContainer*) src; return _dynamicCastUnknownClassToExistentialMetatype(dest, srcExistential->Value, targetType, flags); } case ExistentialTypeRepresentation::Opaque: { auto srcExistential = (OpaqueExistentialContainer*) src; auto srcValueType = srcExistential->Type; auto srcValue = srcValueType->vw_projectBuffer(&srcExistential->Buffer); bool result = _dynamicCastToExistentialMetatype(dest, srcValue, srcValueType, targetType, flags); if (src != srcValue) _maybeDeallocateOpaqueExistential(src, result, flags); return result; } case ExistentialTypeRepresentation::ErrorType: { const SwiftError *srcBox = *reinterpret_cast(src); auto srcValueType = srcBox->getType(); const OpaqueValue *srcValue; if (srcBox->isPureNSError()) srcValue = src; else srcValue = srcBox->getValue(); // Can't take from a box since the value may be shared. auto subFlags = flags - (DynamicCastFlags::TakeOnSuccess | DynamicCastFlags::DestroyOnFailure); bool result = _dynamicCastToExistentialMetatype(dest, const_cast(srcValue), srcValueType, targetType, subFlags); if (shouldDeallocateSource(result, flags)) srcType->vw_destroy(src); return result; } } } case MetadataKind::Class: case MetadataKind::ObjCClassWrapper: case MetadataKind::ForeignClass: { void *object = *reinterpret_cast(src); return _dynamicCastUnknownClassToExistentialMetatype(dest, object, targetType, flags); } case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Struct: case MetadataKind::Tuple: if (flags & DynamicCastFlags::Unconditional) { swift_dynamicCastFailure(srcType, targetType); } return false; } _failCorruptType(srcType); } static bool _dynamicCastToFunction(OpaqueValue *dest, OpaqueValue *src, const Metadata *srcType, const FunctionTypeMetadata *targetType, DynamicCastFlags flags) { // Function casts succeed on exact matches, or if the target type is // throwier than the source type. // // TODO: We could also allow ABI-compatible variance, such as casting // a dynamic Base -> Derived to Derived -> Base. We wouldn't be able to // perform a dynamic cast that required any ABI adjustment without a JIT // though. // Check for an exact type match first. if (srcType == targetType) { return _succeed(dest, src, srcType, flags); } switch (srcType->getKind()) { case MetadataKind::Function: { auto srcFn = static_cast(srcType); auto targetFn = static_cast(targetType); // Check that argument counts and convention match. "throws" can vary. if (srcFn->Flags.withThrows(false) != targetFn->Flags.withThrows(false)) return _fail(src, srcType, targetType, flags); // If the target type can't throw, neither can the source. if (srcFn->throws() && !targetFn->throws()) return _fail(src, srcType, targetType, flags); // The result and argument types must match. if (srcFn->ResultType != targetFn->ResultType) return _fail(src, srcType, targetType, flags); if (srcFn->getNumArguments() != targetFn->getNumArguments()) return _fail(src, srcType, targetType, flags); for (unsigned i = 0, e = srcFn->getNumArguments(); i < e; ++i) if (srcFn->getArguments()[i] != targetFn->getArguments()[i]) return _fail(src, srcType, targetType, flags); return _succeed(dest, src, srcType, flags); } case MetadataKind::Existential: return _dynamicCastFromExistential(dest, src, static_cast(srcType), targetType, flags); case MetadataKind::Class: case MetadataKind::Struct: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::ObjCClassWrapper: case MetadataKind::ForeignClass: case MetadataKind::ExistentialMetatype: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Metatype: case MetadataKind::Opaque: case MetadataKind::Tuple: return _fail(src, srcType, targetType, flags); } } #if SWIFT_OBJC_INTEROP static id dynamicCastValueToNSError(OpaqueValue *src, const Metadata *srcType, const WitnessTable *srcErrorTypeWitness, DynamicCastFlags flags) { BoxPair errorBox = swift_allocError(srcType, srcErrorTypeWitness, src, /*isTake*/ flags & DynamicCastFlags::TakeOnSuccess); return swift_bridgeErrorTypeToNSError((SwiftError*)errorBox.first); } #endif static bool canCastToExistential(OpaqueValue *dest, OpaqueValue *src, const Metadata *srcType, const Metadata *targetType) { if (targetType->getKind() != MetadataKind::Existential) return false; return _dynamicCastToExistential(dest, src, srcType, cast(targetType), DynamicCastFlags::Default); } /// Perform a dynamic cast to an arbitrary type. bool swift::swift_dynamicCast(OpaqueValue *dest, OpaqueValue *src, const Metadata *srcType, const Metadata *targetType, DynamicCastFlags flags) { // Check if the cast source is Optional and the target is not an existential // that Optional conforms to. Unwrap one level of Optional and continue. if (srcType->getKind() == MetadataKind::Optional && !canCastToExistential(dest, src, srcType, targetType)) { const Metadata *payloadType = cast(srcType)->getGenericArgs()[0]; int enumCase = swift_getEnumCaseSinglePayload(src, payloadType, 1 /*emptyCases=*/); if (enumCase != -1) { // Allow Optional.None -> Optional.None if (targetType->getKind() != MetadataKind::Optional) return _fail(src, srcType, targetType, flags); // Inject the .None tag swift_storeEnumTagSinglePayload(dest, payloadType, enumCase, 1 /*emptyCases=*/); return _succeed(dest, src, srcType, flags); } // .Some // Single payload enums are guaranteed layout compatible with their // payload. Only the source's payload needs to be taken or destroyed. srcType = payloadType; } switch (targetType->getKind()) { // Handle wrapping an Optional target. case MetadataKind::Optional: { // Recursively cast into the layout compatible payload area. const Metadata *payloadType = cast(targetType)->getGenericArgs()[0]; if (swift_dynamicCast(dest, src, srcType, payloadType, flags)) { swift_storeEnumTagSinglePayload(dest, payloadType, -1 /*case*/, 1 /*emptyCases*/); return true; } return false; } // Casts to class type. case MetadataKind::Class: case MetadataKind::ObjCClassWrapper: #if SWIFT_OBJC_INTEROP // If the destination type is an NSError, and the source type is an // ErrorType, then the cast can succeed by NSError bridging. if (targetType == getNSErrorTypeMetadata()) { // Don't rebridge if the source is already some kind of NSError. if (srcType->isAnyClass() && swift_dynamicCastObjCClass(*reinterpret_cast(src), static_cast(targetType)->Class)) return _succeed(dest, src, srcType, flags); if (auto srcErrorTypeWitness = findErrorTypeWitness(srcType)) { auto error = dynamicCastValueToNSError(src, srcType, srcErrorTypeWitness, flags); *reinterpret_cast(dest) = error; return true; } } SWIFT_FALLTHROUGH; #endif case MetadataKind::ForeignClass: switch (srcType->getKind()) { case MetadataKind::Class: case MetadataKind::ObjCClassWrapper: case MetadataKind::ForeignClass: { // Do a dynamic cast on the instance pointer. void *object = *reinterpret_cast(src); return _dynamicCastUnknownClassIndirect(dest, object, targetType, flags); } case MetadataKind::Existential: { auto srcExistentialType = cast(srcType); return _dynamicCastToUnknownClassFromExistential(dest, src, srcExistentialType, targetType, flags); } case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Struct: { #if SWIFT_OBJC_INTEROP // If the source type is bridged to Objective-C, try to bridge. if (auto srcBridgeWitness = findBridgeWitness(srcType)) { return _dynamicCastValueToClassViaObjCBridgeable(dest, src, srcType, targetType, srcBridgeWitness, flags); } #endif return _fail(src, srcType, targetType, flags); } case MetadataKind::ExistentialMetatype: case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Metatype: case MetadataKind::Opaque: case MetadataKind::Tuple: return _fail(src, srcType, targetType, flags); } break; case MetadataKind::Existential: return _dynamicCastToExistential(dest, src, srcType, cast(targetType), flags); case MetadataKind::Metatype: return _dynamicCastToMetatype(dest, src, srcType, cast(targetType), flags); case MetadataKind::ExistentialMetatype: return _dynamicCastToExistentialMetatype(dest, src, srcType, cast(targetType), flags); // Function types. case MetadataKind::Function: { return _dynamicCastToFunction(dest, src, srcType, cast(targetType), flags); } case MetadataKind::Struct: case MetadataKind::Enum: switch (srcType->getKind()) { case MetadataKind::Class: case MetadataKind::ObjCClassWrapper: case MetadataKind::ForeignClass: { #if SWIFT_OBJC_INTEROP // If the target type is bridged to Objective-C, try to bridge. if (auto targetBridgeWitness = findBridgeWitness(targetType)) { return _dynamicCastClassToValueViaObjCBridgeable(dest, src, srcType, targetType, targetBridgeWitness, flags); } // If the source is an NSError, and the target is a bridgeable ErrorType, // try to bridge. if (tryDynamicCastNSErrorToValue(dest, src, srcType, targetType, flags)) { return true; } #endif break; } case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Existential: case MetadataKind::ExistentialMetatype: case MetadataKind::Function: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Metatype: case MetadataKind::Opaque: case MetadataKind::Struct: case MetadataKind::Tuple: break; } SWIFT_FALLTHROUGH; // The non-polymorphic types. case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: case MetadataKind::Opaque: case MetadataKind::Tuple: // If there's an exact type match, we're done. if (srcType == targetType) return _succeed(dest, src, srcType, flags); // If we have an existential, look at its dynamic type. if (auto srcExistentialType = dyn_cast(srcType)) { return _dynamicCastFromExistential(dest, src, srcExistentialType, targetType, flags); } // Otherwise, we have a failure. return _fail(src, srcType, targetType, flags); } _failCorruptType(srcType); } #if defined(NDEBUG) && SWIFT_OBJC_INTEROP void ProtocolConformanceRecord::dump() const { auto symbolName = [&](const void *addr) -> const char * { Dl_info info; int ok = dladdr(addr, &info); if (!ok) return ""; return info.dli_sname; }; switch (auto kind = getTypeKind()) { case ProtocolConformanceTypeKind::Universal: printf("universal"); break; case ProtocolConformanceTypeKind::UniqueDirectType: case ProtocolConformanceTypeKind::NonuniqueDirectType: printf("%s direct type ", kind == ProtocolConformanceTypeKind::UniqueDirectType ? "unique" : "nonunique"); if (auto ntd = getDirectType()->getNominalTypeDescriptor()) { printf("%s", ntd->Name); } else { printf(""); } break; case ProtocolConformanceTypeKind::UniqueDirectClass: printf("unique direct class %s", class_getName(getDirectClass())); break; case ProtocolConformanceTypeKind::UniqueIndirectClass: printf("unique indirect class %s", class_getName(*getIndirectClass())); break; case ProtocolConformanceTypeKind::UniqueGenericPattern: printf("unique generic type %s", symbolName(getGenericPattern())); break; } printf(" => "); switch (getConformanceKind()) { case ProtocolConformanceReferenceKind::WitnessTable: printf("witness table %s\n", symbolName(getStaticWitnessTable())); break; case ProtocolConformanceReferenceKind::WitnessTableAccessor: printf("witness table accessor %s\n", symbolName((const void *)(uintptr_t)getWitnessTableAccessor())); break; } } #endif /// Take the type reference inside a protocol conformance record and fetch the /// canonical metadata pointer for the type it refers to. /// Returns nil for universal or generic type references. const Metadata *ProtocolConformanceRecord::getCanonicalTypeMetadata() const { switch (getTypeKind()) { case ProtocolConformanceTypeKind::UniqueDirectType: // Already unique. return getDirectType(); case ProtocolConformanceTypeKind::NonuniqueDirectType: // Ask the runtime for the unique metadata record we've canonized. return swift_getForeignTypeMetadata((ForeignTypeMetadata*)getDirectType()); case ProtocolConformanceTypeKind::UniqueIndirectClass: // The class may be ObjC, in which case we need to instantiate its Swift // metadata. The class additionally may be weak-linked, so we have to check // for null. if (auto *ClassMetadata = *getIndirectClass()) return swift_getObjCClassMetadata(ClassMetadata); return nullptr; case ProtocolConformanceTypeKind::UniqueDirectClass: // The class may be ObjC, in which case we need to instantiate its Swift // metadata. if (auto *ClassMetadata = getDirectClass()) return swift_getObjCClassMetadata(ClassMetadata); return nullptr; case ProtocolConformanceTypeKind::UniqueGenericPattern: case ProtocolConformanceTypeKind::Universal: // The record does not apply to a single type. return nullptr; } } const WitnessTable *ProtocolConformanceRecord::getWitnessTable(const Metadata *type) const { switch (getConformanceKind()) { case ProtocolConformanceReferenceKind::WitnessTable: return getStaticWitnessTable(); case ProtocolConformanceReferenceKind::WitnessTableAccessor: return getWitnessTableAccessor()(type); } } #if defined(__APPLE__) && defined(__MACH__) #define SWIFT_PROTOCOL_CONFORMANCES_SECTION "__swift2_proto" #elif defined(__ELF__) #define SWIFT_PROTOCOL_CONFORMANCES_SECTION ".swift2_protocol_conformances_start" #endif // std:once_flag token to install the dyld callback to enqueue images for // protocol conformance lookup. static std::once_flag InstallProtocolConformanceAddImageCallbackOnce; namespace { struct ConformanceSection { const ProtocolConformanceRecord *Begin, *End; const ProtocolConformanceRecord *begin() const { return Begin; } const ProtocolConformanceRecord *end() const { return End; } }; struct ConformanceCacheEntry { private: const void *Type; const ProtocolDescriptor *Proto; uintptr_t Data; // All Darwin 64-bit platforms reserve the low 2^32 of address space, which // is more than enough invalid pointer values for any realistic generation // number. It's a little easier to overflow on 32-bit, so we need an extra // bit there. #if !__LP64__ bool Success; #endif ConformanceCacheEntry(const void *type, const ProtocolDescriptor *proto, uintptr_t Data, bool Success) : Type(type), Proto(proto), Data(Data) #if !__LP64__ , Success(Success) #endif { #if __LP64__ # if __APPLE__ assert((!Success && Data <= 0xFFFFFFFFU) || (Success && Data > 0xFFFFFFFFU)); # elif __linux__ || __FreeBSD__ assert((!Success && Data <= 0x0FFFU) || (Success && Data > 0x0FFFU)); # else # error "port me" # endif #endif } public: ConformanceCacheEntry() = default; static ConformanceCacheEntry createSuccess( const void *type, const ProtocolDescriptor *proto, const swift::WitnessTable *witness) { return ConformanceCacheEntry(type, proto, (uintptr_t) witness, true); } static ConformanceCacheEntry createFailure( const void *type, const ProtocolDescriptor *proto, unsigned failureGeneration) { return ConformanceCacheEntry(type, proto, (uintptr_t) failureGeneration, false); } /// \returns true if the entry represents an entry for the pair \p type /// and \p proto. bool matches(const void *type, const ProtocolDescriptor *proto) { return type == Type && Proto == proto; } bool isSuccessful() const { #if __LP64__ # if __APPLE__ return Data > 0xFFFFFFFFU; # elif __linux__ || __FreeBSD__ return Data > 0x0FFFU; # else # error "port me" # endif #else return Success; #endif } /// Get the cached witness table, if successful. const WitnessTable *getWitnessTable() const { assert(isSuccessful()); return (const WitnessTable *)Data; } /// Get the generation number under which this lookup failed. unsigned getFailureGeneration() const { assert(!isSuccessful()); return Data; } }; } // Conformance Cache. struct ConformanceState { ConcurrentMap Cache; std::vector SectionsToScan; pthread_mutex_t SectionsToScanLock; ConformanceState() { SectionsToScan.reserve(16); pthread_mutex_init(&SectionsToScanLock, nullptr); } }; static Lazy Conformances; // This variable is used to signal when a cache was generated and // it is correct to avoid a new scan. static unsigned ConformanceCacheGeneration = 0; void swift::swift_registerProtocolConformances(const ProtocolConformanceRecord *begin, const ProtocolConformanceRecord *end){ auto &C = Conformances.get(); pthread_mutex_lock(&C.SectionsToScanLock); C.SectionsToScan.push_back(ConformanceSection{begin, end}); pthread_mutex_unlock(&C.SectionsToScanLock); } static void _addImageProtocolConformancesBlock(const uint8_t *conformances, size_t conformancesSize) { assert(conformancesSize % sizeof(ProtocolConformanceRecord) == 0 && "weird-sized conformances section?!"); // If we have a section, enqueue the conformances for lookup. auto recordsBegin = reinterpret_cast(conformances); auto recordsEnd = reinterpret_cast (conformances + conformancesSize); swift_registerProtocolConformances(recordsBegin, recordsEnd); } #if defined(__APPLE__) && defined(__MACH__) static void _addImageProtocolConformances(const mach_header *mh, intptr_t vmaddr_slide) { #ifdef __LP64__ using mach_header_platform = mach_header_64; assert(mh->magic == MH_MAGIC_64 && "loaded non-64-bit image?!"); #else using mach_header_platform = mach_header; #endif // Look for a __swift2_proto section. unsigned long conformancesSize; const uint8_t *conformances = getsectiondata(reinterpret_cast(mh), SEG_TEXT, SWIFT_PROTOCOL_CONFORMANCES_SECTION, &conformancesSize); if (!conformances) return; _addImageProtocolConformancesBlock(conformances, conformancesSize); } #elif defined(__ELF__) static int _addImageProtocolConformances(struct dl_phdr_info *info, size_t size, void * /*data*/) { void *handle; if (!info->dlpi_name || info->dlpi_name[0] == '\0') { handle = dlopen(nullptr, RTLD_LAZY); } else handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD); auto conformances = reinterpret_cast( dlsym(handle, SWIFT_PROTOCOL_CONFORMANCES_SECTION)); if (!conformances) { // if there are no conformances, don't hold this handle open. dlclose(handle); return 0; } // Extract the size of the conformances block from the head of the section auto conformancesSize = *reinterpret_cast(conformances); conformances += sizeof(conformancesSize); _addImageProtocolConformancesBlock(conformances, conformancesSize); dlclose(handle); return 0; } #endif static void installCallbacksToInspectDylib() { static OnceToken_t token; auto callback = [](void*) { #if defined(__APPLE__) && defined(__MACH__) // Install our dyld callback if we haven't already. // Dyld will invoke this on our behalf for all images that have already // been loaded. _dyld_register_func_for_add_image(_addImageProtocolConformances); #elif defined(__ELF__) // Search the loaded dls. Unlike the above, this only searches the already // loaded ones. // FIXME: Find a way to have this continue to happen after. // rdar://problem/19045112 dl_iterate_phdr(_addImageProtocolConformances, nullptr); #else # error No known mechanism to inspect dynamic libraries on this platform. #endif }; SWIFT_ONCE_F(token, callback, nullptr); } static size_t hashTypeProtocolPair(const void *type, const ProtocolDescriptor *protocol) { // A simple hash function for the conformance pair. return (size_t)type + ((size_t)protocol >> 2); } /// Search the witness table in the ConformanceCache. \returns a pair of the /// WitnessTable pointer and a boolean value True if a definitive value is /// found. \returns false if the type or its superclasses were not found in /// the cache. static std::pair searchInConformanceCache(const Metadata *type, const ProtocolDescriptor *protocol, ConformanceCacheEntry *&foundEntry) { auto &C = Conformances.get(); auto origType = type; foundEntry = nullptr; recur_inside_cache_lock: // See if we have a cached conformance. Try the specific type first. // Hash and lookup the type-protocol pair in the cache. size_t hash = hashTypeProtocolPair(type, protocol); ConcurrentList &Bucket = C.Cache.findOrAllocateNode(hash); // Check if the type-protocol entry exists in the cache entry that we found. for (auto &Entry : Bucket) { if (!Entry.matches(type, protocol)) continue; if (Entry.isSuccessful()) { return std::make_pair(Entry.getWitnessTable(), true); } if (type == origType) foundEntry = &Entry; // If we got a cached negative response, check the generation number. if (Entry.getFailureGeneration() == C.SectionsToScan.size()) { // We found an entry with a negative value. return std::make_pair(nullptr, true); } } // If the type is generic, see if there's a shared nondependent witness table // for its instances. if (auto generic = type->getGenericPattern()) { // Hash and lookup the type-protocol pair in the cache. size_t hash = hashTypeProtocolPair(generic, protocol); ConcurrentList &Bucket = C.Cache.findOrAllocateNode(hash); for (auto &Entry : Bucket) { if (!Entry.matches(generic, protocol)) continue; if (Entry.isSuccessful()) { return std::make_pair(Entry.getWitnessTable(), true); } // We don't try to cache negative responses for generic // patterns. } } // If the type is a class, try its superclass. if (const ClassMetadata *classType = type->getClassObject()) { if (classHasSuperclass(classType)) { type = swift_getObjCClassMetadata(classType->SuperClass); goto recur_inside_cache_lock; } } // We did not find an entry. return std::make_pair(nullptr, false); } /// Checks if a given candidate is a type itself, one of its /// superclasses or a related generic type. /// This check is supposed to use the same logic that is used /// by searchInConformanceCache. static bool isRelatedType(const Metadata *type, const void *candidate) { while (true) { if (type == candidate) return true; // If the type is generic, see if there's a shared nondependent witness table // for its instances. if (auto generic = type->getGenericPattern()) { if (generic == candidate) return true; } // If the type is a class, try its superclass. if (const ClassMetadata *classType = type->getClassObject()) { if (classHasSuperclass(classType)) { type = swift_getObjCClassMetadata(classType->SuperClass); if (type == candidate) return true; continue; } } break; } return false; } const WitnessTable * swift::swift_conformsToProtocol(const Metadata *type, const ProtocolDescriptor *protocol) { auto &C = Conformances.get(); // Install callbacks for tracking when a new dylib is loaded so we can // scan it. installCallbacksToInspectDylib(); auto origType = type; unsigned numSections = 0; ConformanceCacheEntry *foundEntry; recur: // See if we have a cached conformance. The ConcurrentMap data structure // allows us to insert and search the map concurrently without locking. // We do lock the slow path because the SectionsToScan data structure is not // concurrent. auto FoundConformance = searchInConformanceCache(type, protocol, foundEntry); // The negative answer does not always mean that there is no conformance, // unless it is an exact match on the type. If it is not an exact match, // it may mean that all of the superclasses do not have this conformance, // but the actual type may still have this conformance. if (FoundConformance.second) { if (FoundConformance.first || foundEntry) return FoundConformance.first; } unsigned failedGeneration = ConformanceCacheGeneration; // If we didn't have an up-to-date cache entry, scan the conformance records. pthread_mutex_lock(&C.SectionsToScanLock); // If we have no new information to pull in (and nobody else pulled in // new information while we waited on the lock), we're done. if (C.SectionsToScan.size() == numSections) { if (failedGeneration != ConformanceCacheGeneration) { // Someone else pulled in new conformances while we were waiting. // Start over with our newly-populated cache. pthread_mutex_unlock(&C.SectionsToScanLock); type = origType; goto recur; } // Hash and lookup the type-protocol pair in the cache. size_t hash = hashTypeProtocolPair(type, protocol); ConcurrentList &Bucket = C.Cache.findOrAllocateNode(hash); Bucket.push_front(ConformanceCacheEntry::createFailure( type, protocol, C.SectionsToScan.size())); pthread_mutex_unlock(&C.SectionsToScanLock); return nullptr; } // Update the last known number of sections to scan. numSections = C.SectionsToScan.size(); // Scan only sections that were not scanned yet. unsigned sectionIdx = foundEntry ? foundEntry->getFailureGeneration() : 0; unsigned endSectionIdx = C.SectionsToScan.size(); for (; sectionIdx < endSectionIdx; ++sectionIdx) { auto §ion = C.SectionsToScan[sectionIdx]; // Eagerly pull records for nondependent witnesses into our cache. for (const auto &record : section) { // If the record applies to a specific type, cache it. if (auto metadata = record.getCanonicalTypeMetadata()) { auto P = record.getProtocol(); // Look for an exact match. if (protocol != P) continue; if (!isRelatedType(type, metadata)) continue; // Hash and lookup the type-protocol pair in the cache. size_t hash = hashTypeProtocolPair(metadata, P); ConcurrentList &Bucket = C.Cache.findOrAllocateNode(hash); auto witness = record.getWitnessTable(metadata); if (witness) Bucket.push_front( ConformanceCacheEntry::createSuccess(metadata, P, witness)); else Bucket.push_front(ConformanceCacheEntry::createFailure( metadata, P, C.SectionsToScan.size())); // If the record provides a nondependent witness table for all instances // of a generic type, cache it for the generic pattern. // TODO: "Nondependent witness table" probably deserves its own flag. // An accessor function might still be necessary even if the witness table // can be shared. } else if (record.getTypeKind() == ProtocolConformanceTypeKind::UniqueGenericPattern && record.getConformanceKind() == ProtocolConformanceReferenceKind::WitnessTable) { auto R = record.getGenericPattern(); auto P = record.getProtocol(); // Look for an exact match. if (protocol != P) continue; if (!isRelatedType(type, R)) continue; // Hash and lookup the type-protocol pair in the cache. size_t hash = hashTypeProtocolPair(R, P); ConcurrentList &Bucket = C.Cache.findOrAllocateNode(hash); Bucket.push_front(ConformanceCacheEntry::createSuccess( R, P, record.getStaticWitnessTable())); } } } ++ConformanceCacheGeneration; pthread_mutex_unlock(&C.SectionsToScanLock); // Start over with our newly-populated cache. type = origType; goto recur; } // The return type is incorrect. It is only important that it is // passed using 'sret'. extern "C" OpaqueExistentialContainer _TFs24_injectValueIntoOptionalU__FQ_GSqQ__(OpaqueValue *value, const Metadata *T); // The return type is incorrect. It is only important that it is // passed using 'sret'. extern "C" OpaqueExistentialContainer _TFs26_injectNothingIntoOptionalU__FT_GSqQ__(const Metadata *T); 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(T)->isObjC()) return true; // Blocks are ObjC objects. if (kind == MetadataKind::Function) { auto fT = static_cast(T); return fT->getConvention() == FunctionMetadataConvention::Block; } #endif return false; } #if SWIFT_OBJC_INTEROP //===----------------------------------------------------------------------===// // Bridging to and from Objective-C //===----------------------------------------------------------------------===// namespace { // protocol _ObjectiveCBridgeable { struct _ObjectiveCBridgeableWitnessTable { // typealias _ObjectiveCType : class const Metadata *ObjectiveCType; // class func _isBridgedToObjectiveC() -> bool bool (*isBridgedToObjectiveC)(const Metadata *value, const Metadata *T); // class func _getObjectiveCType() -> Any.Type const Metadata *(*getObjectiveCType)(const Metadata *self, const Metadata *selfType); // func _bridgeToObjectiveC() -> _ObjectiveCType HeapObject *(*bridgeToObjectiveC)(OpaqueValue *self, const Metadata *Self); // class func _forceBridgeFromObjectiveC(x: _ObjectiveCType, // inout result: Self?) void (*forceBridgeFromObjectiveC)(HeapObject *sourceValue, OpaqueValue *result, const Metadata *self, const Metadata *selfType); // class func _conditionallyBridgeFromObjectiveC(x: _ObjectiveCType, // inout result: Self?) -> Bool bool (*conditionallyBridgeFromObjectiveC)(HeapObject *sourceValue, OpaqueValue *result, const Metadata *self, const Metadata *selfType); }; // } } // unnamed namespace extern "C" const ProtocolDescriptor _TMps21_ObjectiveCBridgeable; /// Dynamic cast from a value type that conforms to the _ObjectiveCBridgeable /// protocol to a class type, first by bridging the value to its Objective-C /// object representation and then by dynamic casting that object to the /// resulting target type. static bool _dynamicCastValueToClassViaObjCBridgeable( OpaqueValue *dest, OpaqueValue *src, const Metadata *srcType, const Metadata *targetType, const _ObjectiveCBridgeableWitnessTable *srcBridgeWitness, DynamicCastFlags flags) { // Check whether the source is bridged to Objective-C. if (!srcBridgeWitness->isBridgedToObjectiveC(srcType, srcType)) { return _fail(src, srcType, targetType, flags); } // Bridge the source value to an object. auto srcBridgedObject = srcBridgeWitness->bridgeToObjectiveC(src, srcType); // Dynamic cast the object to the resulting class type. bool success; if (auto cast = _dynamicCastUnknownClass(srcBridgedObject, targetType, flags & DynamicCastFlags::Unconditional)) { *reinterpret_cast(dest) = cast; success = true; } else { success = false; } // Clean up the source if we're supposed to. if (shouldDeallocateSource(success, flags)) { srcType->vw_destroy(src); } // We're done. return success; } /// Dynamic cast from a value type that conforms to the /// _ObjectiveCBridgeable protocol to a class-bounded existential, /// first by bridging the value to its Objective-C object /// representation and then by dynamic-casting that object to the /// resulting target type. static bool _dynamicCastValueToClassExistentialViaObjCBridgeable( OpaqueValue *dest, OpaqueValue *src, const Metadata *srcType, const ExistentialTypeMetadata *targetType, const _ObjectiveCBridgeableWitnessTable *srcBridgeWitness, DynamicCastFlags flags) { // Check whether the source is bridged to Objective-C. if (!srcBridgeWitness->isBridgedToObjectiveC(srcType, srcType)) { return _fail(src, srcType, targetType, flags); } // Bridge the source value to an object. auto srcBridgedObject = srcBridgeWitness->bridgeToObjectiveC(src, srcType); // Try to cast the object to the destination existential. DynamicCastFlags subFlags = DynamicCastFlags::TakeOnSuccess | DynamicCastFlags::DestroyOnFailure; if (flags & DynamicCastFlags::Unconditional) subFlags |= DynamicCastFlags::Unconditional; bool success = _dynamicCastToExistential( dest, (OpaqueValue *)&srcBridgedObject, swift_getObjectType(srcBridgedObject), targetType, subFlags); // Clean up the source if we're supposed to. if (shouldDeallocateSource(success, flags)) { srcType->vw_destroy(src); } // We're done. return success; } /// Dynamic cast from a class type to a value type that conforms to the /// _ObjectiveCBridgeable, first by dynamic casting the object to the /// Objective-C class to which the value type is bridged, and then bridging /// from that object to the value type via the witness table. static bool _dynamicCastClassToValueViaObjCBridgeable( OpaqueValue *dest, OpaqueValue *src, const Metadata *srcType, const Metadata *targetType, const _ObjectiveCBridgeableWitnessTable *targetBridgeWitness, DynamicCastFlags flags) { // Check whether the target is bridged to Objective-C. if (!targetBridgeWitness->isBridgedToObjectiveC(targetType, targetType)) { return _fail(src, srcType, targetType, flags); } // Determine the class type to which the target value type is bridged. auto targetBridgedClass = targetBridgeWitness->getObjectiveCType(targetType, targetType); // Dynamic cast the source object to the class type to which the target value // type is bridged. If we succeed, we can bridge from there; if we fail, // there's nothing more to do. void *srcObject = *reinterpret_cast(src); if (!_dynamicCastUnknownClass(srcObject, targetBridgedClass, flags & DynamicCastFlags::Unconditional)) { return _fail(src, srcType, targetType, flags); } // Unless we're always supposed to consume the input, retain the // object because the witness takes it at +1. bool alwaysConsumeSrc = (flags & DynamicCastFlags::TakeOnSuccess) && (flags & DynamicCastFlags::DestroyOnFailure); if (!alwaysConsumeSrc) { swift_unknownRetain(srcObject); } // Object that frees a buffer when it goes out of scope. struct FreeBuffer { void *Buffer = nullptr; ~FreeBuffer() { free(Buffer); } } freeBuffer; // Allocate a buffer to store the T? returned by bridging. // The extra byte is for the tag. const std::size_t inlineValueSize = 3 * sizeof(void*); alignas(swift_max_align_t) char inlineBuffer[inlineValueSize + 1]; void *optDestBuffer; if (targetType->getValueWitnesses()->getStride() <= inlineValueSize) { // Use the inline buffer. optDestBuffer = inlineBuffer; } else { // Allocate a buffer. optDestBuffer = malloc(targetType->getValueWitnesses()->size); freeBuffer.Buffer = optDestBuffer; } // Initialize the buffer as an empty optional. swift_storeEnumTagSinglePayload((OpaqueValue *)optDestBuffer, targetType, 0, 1); // Perform the bridging operation. bool success; if (flags & DynamicCastFlags::Unconditional) { // For an unconditional dynamic cast, use forceBridgeFromObjectiveC. targetBridgeWitness->forceBridgeFromObjectiveC( (HeapObject *)srcObject, (OpaqueValue *)optDestBuffer, targetType, targetType); success = true; } else { // For a conditional dynamic cast, use conditionallyBridgeFromObjectiveC. success = targetBridgeWitness->conditionallyBridgeFromObjectiveC( (HeapObject *)srcObject, (OpaqueValue *)optDestBuffer, targetType, targetType); } // If we succeeded, take from the optional buffer into the // destination buffer. if (success) { targetType->vw_initializeWithTake(dest, (OpaqueValue *)optDestBuffer); } // Unless we're always supposed to consume the input, release the // input if we need to now. if (!alwaysConsumeSrc && shouldDeallocateSource(success, flags)) { swift_unknownRelease(srcObject); } return success; } //===--- 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. //===----------------------------------------------------------------------===// extern "C" const _ObjectiveCBridgeableWitnessTable _TWPVs19_BridgeableMetatypes21_ObjectiveCBridgeables; static const _ObjectiveCBridgeableWitnessTable * findBridgeWitness(const Metadata *T) { auto w = swift_conformsToProtocol(T, &_TMps21_ObjectiveCBridgeable); if (LLVM_LIKELY(w)) return reinterpret_cast(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: { auto metaTy = static_cast(T); if (metaTy->InstanceType->isAnyClass()) return &_TWPVs19_BridgeableMetatypes21_ObjectiveCBridgeables; break; } case MetadataKind::ExistentialMetatype: { auto existentialMetaTy = static_cast(T); if (existentialMetaTy->isObjC()) return &_TWPVs19_BridgeableMetatypes21_ObjectiveCBridgeables; break; } case MetadataKind::Class: case MetadataKind::Struct: case MetadataKind::Enum: case MetadataKind::Optional: case MetadataKind::Opaque: case MetadataKind::Tuple: case MetadataKind::Function: case MetadataKind::Existential: case MetadataKind::ObjCClassWrapper: case MetadataKind::ForeignClass: case MetadataKind::HeapLocalVariable: case MetadataKind::HeapGenericLocalVariable: case MetadataKind::ErrorObject: break; } return nullptr; } /// \param value passed at +1, consumed. extern "C" HeapObject *swift_bridgeNonVerbatimToObjectiveC( OpaqueValue *value, const Metadata *T ) { assert(!swift_isClassOrObjCExistentialTypeImpl(T)); if (const auto *bridgeWitness = findBridgeWitness(T)) { if (!bridgeWitness->isBridgedToObjectiveC(T, T)) { // Witnesses take 'self' at +0, so we still need to consume the +1 argument. T->vw_destroy(value); return nullptr; } auto result = bridgeWitness->bridgeToObjectiveC(value, T); // Witnesses take 'self' at +0, so we still need to consume the +1 argument. T->vw_destroy(value); return result; } // Consume the +1 argument. T->vw_destroy(value); return nullptr; } extern "C" const Metadata *swift_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 bridgeWitness->getObjectiveCType(T, T); } return nullptr; } // @_silgen_name("swift_bridgeNonVerbatimFromObjectiveC") // func _bridgeNonVerbatimFromObjectiveC( // x: AnyObject, // nativeType: NativeType.Type // inout result: T? // ) extern "C" void swift_bridgeNonVerbatimFromObjectiveC( HeapObject *sourceValue, const Metadata *nativeType, OpaqueValue *destValue, const Metadata *nativeType_ ) { // Check if the type conforms to _BridgedToObjectiveC. if (const auto *bridgeWitness = findBridgeWitness(nativeType)) { // if the type also conforms to _ConditionallyBridgedToObjectiveC, // make sure it bridges at runtime if (bridgeWitness->isBridgedToObjectiveC(nativeType, nativeType)) { // Check if sourceValue has the _ObjectiveCType type required by the // protocol. const Metadata *objectiveCType = bridgeWitness->getObjectiveCType(nativeType, nativeType); auto sourceValueAsObjectiveCType = const_cast(swift_dynamicCastUnknownClass(sourceValue, objectiveCType)); if (sourceValueAsObjectiveCType) { // The type matches. _forceBridgeFromObjectiveC returns `Self`, so // we can just return it directly. bridgeWitness->forceBridgeFromObjectiveC( static_cast(sourceValueAsObjectiveCType), destValue, nativeType, nativeType); return; } } } // Fail. swift::crash("value type is not bridged to Objective-C"); } // @_silgen_name("swift_bridgeNonVerbatimFromObjectiveCConditional") // func _bridgeNonVerbatimFromObjectiveCConditional( // x: AnyObject, // nativeType: T.Type, // inout result: T? // ) -> Bool extern "C" bool swift_bridgeNonVerbatimFromObjectiveCConditional( HeapObject *sourceValue, const Metadata *nativeType, OpaqueValue *destValue, const Metadata *nativeType_ ) { // Local function that releases the source and returns false. auto fail = [&] () -> bool { swift_unknownRelease(sourceValue); 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 = bridgeWitness->getObjectiveCType(nativeType, nativeType); // Check whether we can downcast the source value to the Objective-C // type. auto sourceValueAsObjectiveCType = const_cast(swift_dynamicCastUnknownClass(sourceValue, objectiveCType)); if (!sourceValueAsObjectiveCType) return fail(); // If the type also conforms to _ConditionallyBridgedToObjectiveC, // use conditional bridging. return bridgeWitness->conditionallyBridgeFromObjectiveC( static_cast(sourceValueAsObjectiveCType), destValue, nativeType, nativeType); } // func isBridgedNonVerbatimToObjectiveC(x: T.Type) -> Bool extern "C" bool swift_isBridgedNonVerbatimToObjectiveC( const Metadata *value, const Metadata *T ) { assert(!swift_isClassOrObjCExistentialTypeImpl(T)); auto bridgeWitness = findBridgeWitness(T); return bridgeWitness && bridgeWitness->isBridgedToObjectiveC(value, T); } #endif // func isClassOrObjCExistential(x: T.Type) -> Bool extern "C" bool swift_isClassOrObjCExistentialType(const Metadata *value, const Metadata *T) { return swift_isClassOrObjCExistentialTypeImpl(T); } // func swift_class_getSuperclass(_: AnyClass) -> AnyClass? extern "C" const Metadata *swift_class_getSuperclass( const Metadata *theClass ) { if (const ClassMetadata *classType = theClass->getClassObject()) if (classHasSuperclass(classType)) return swift_getObjCClassMetadata(classType->SuperClass); return nullptr; } extern "C" bool swift_isClassType(const Metadata *type) { return Metadata::isAnyKindOfClass(type->getKind()); } extern "C" bool swift_isOptionalType(const Metadata *type) { return type->getKind() == MetadataKind::Optional; }