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