//===--- ErrorObject.h - Cocoa-interoperable recoverable error object -----===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 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 // //===----------------------------------------------------------------------===// // // This implements the object representation of the standard ErrorType protocol // type, which represents recoverable errors in the language. This // implementation is designed to interoperate efficiently with Cocoa libraries // by: // - allowing for NSError and CFError objects to "toll-free bridge" to // ErrorType existentials, which allows for cheap Cocoa to Swift interop // - allowing a native Swift error to lazily "become" an NSError when // passed into Cocoa, allowing for cheap Swift to Cocoa interop // //===----------------------------------------------------------------------===// #ifndef __SWIFT_RUNTIME_ERROROBJECT_H__ #define __SWIFT_RUNTIME_ERROROBJECT_H__ #include "swift/Runtime/Metadata.h" #include "swift/Runtime/HeapObject.h" #include #include #include #include namespace swift { /// A mockery of the physical layout of NSError and CFError. struct NSErrorLayout { // CFError has a CF refcounting header. NSError reserves a word after the // 'isa' in order to be layout-compatible. CFRuntimeBase base; // The NSError part of the object is lazily initialized, so we need atomic // semantics. std::atomic code; std::atomic domain; std::atomic userInfo; }; static_assert(sizeof(CFRuntimeBase) == sizeof(void*) * 2, "size of CFRuntimeBase changed"); /// The layout of the Swift ErrorType box. struct SwiftError : NSErrorLayout { // By inheriting OpaqueNSError, the SwiftError structure reserves enough // space within itself to lazily emplace an NSError instance, and gets // Core Foundation's refcounting scheme. /// The type of Swift error value contained in the box. /// This is only available for native Swift errors. const Metadata *type; /// The ErrorType witness table. /// This is only available for native Swift errors. const WitnessTable *errorConformance; /// Get a pointer to the value contained inside the indirectly-referenced /// box reference. static const OpaqueValue *getIndirectValue(const SwiftError * const *ptr) { // If the box is a bridged NSError, then the box's address is itself the // value. if ((*ptr)->isPureNSError()) return reinterpret_cast(ptr); return (*ptr)->getValue(); } static OpaqueValue *getIndirectValue(SwiftError * const *ptr) { return const_cast(getIndirectValue( const_cast(ptr))); } /// Get a pointer to the value, which is tail-allocated after /// the fixed header. const OpaqueValue *getValue() const { // If the box is a bridged NSError, then the box's address is itself the // value. We can't provide an address for that; getIndirectValue must be // used if we haven't established this as an NSError yet.. assert(!isPureNSError()); auto baseAddr = reinterpret_cast(this + 1); // Round up to the value's alignment. unsigned alignMask = type->getValueWitnesses()->getAlignmentMask(); baseAddr = (baseAddr + alignMask) & ~(uintptr_t)alignMask; return reinterpret_cast(baseAddr); } OpaqueValue *getValue() { return const_cast( const_cast(this)->getValue()); } // True if the object is really an NSError or CFError instance. // The type and errorConformance fields don't exist in an NSError. bool isPureNSError() const; /// Get the type of the contained value. const Metadata *getType() const; /// Get the ErrorType protocol witness table for the contained type. const WitnessTable *getErrorConformance() const; // Don't copy or move, please. SwiftError(const SwiftError &) = delete; SwiftError(SwiftError &&) = delete; SwiftError &operator=(const SwiftError &) = delete; SwiftError &operator=(SwiftError &&) = delete; }; /// Allocate a catchable error object. extern "C" BoxPair::Return swift_allocError(const Metadata *type, const WitnessTable *errorConformance); /// Deallocate an error object whose contained object has already been /// destroyed. extern "C" void swift_deallocError(SwiftError *error, const Metadata *type); struct ErrorValueResult { const OpaqueValue *value; const Metadata *type; const WitnessTable *errorConformance; }; /// Extract a pointer to the value, the type metadata, and the ErrorType /// protocol witness from an error object. /// /// The "scratch" pointer should point to an uninitialized word-sized /// temporary buffer. The implementation may write a reference to itself to /// that buffer if the error object is a toll-free-bridged NSError instead of /// a native Swift error, in which case the object itself is the "boxed" value. extern "C" void swift_getErrorValue(const SwiftError *errorObject, void **scratch, ErrorValueResult *out); /// Initialize an ErrorType box to make it usable as an NSError instance. extern "C" id swift_becomeNSError(SwiftError *errorObject); #if SWIFT_OBJC_INTEROP /// Attempt to dynamically cast an NSError instance to a Swift ErrorType /// implementation using the _ObjectiveCBridgeableErrorType protocol. /// /// srcType must be some kind of class metadata. bool tryDynamicCastNSErrorToValue(OpaqueValue *dest, OpaqueValue *src, const Metadata *srcType, const Metadata *destType, DynamicCastFlags flags); #endif } // namespace swift #endif