| //===----------------------------------------------------------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2018 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 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "swift/Basic/Lazy.h" |
| #include "swift/Runtime/Reflection.h" |
| #include "swift/Runtime/Casting.h" |
| #include "swift/Runtime/Config.h" |
| #include "swift/Runtime/HeapObject.h" |
| #include "swift/Runtime/Metadata.h" |
| #include "swift/Runtime/Enum.h" |
| #include "swift/Runtime/Unreachable.h" |
| #include "swift/Demangling/Demangle.h" |
| #include "swift/Runtime/Debug.h" |
| #include "swift/Runtime/Portability.h" |
| #include "Private.h" |
| #include "WeakReference.h" |
| #include "llvm/Support/Compiler.h" |
| #include <cassert> |
| #include <cinttypes> |
| #include <cstdio> |
| #include <cstring> |
| #include <new> |
| #include <string> |
| #include <tuple> |
| |
| #if SWIFT_OBJC_INTEROP |
| #include "swift/Runtime/ObjCBridge.h" |
| #include "SwiftObject.h" |
| #include <Foundation/Foundation.h> |
| #include <objc/objc.h> |
| #include <objc/runtime.h> |
| #endif |
| |
| #if defined(_WIN32) |
| #include <stdarg.h> |
| |
| namespace { |
| int asprintf(char **strp, const char *fmt, ...) { |
| va_list argp0, argp1; |
| |
| va_start(argp0, fmt); |
| va_copy(argp1, argp0); |
| |
| int length = _vscprintf(fmt, argp0); |
| |
| *strp = reinterpret_cast<char *>(malloc(length + 1)); |
| if (*strp == nullptr) |
| return -1; |
| |
| length = _vsnprintf(*strp, length, fmt, argp1); |
| |
| va_end(argp0); |
| va_end(argp1); |
| |
| return length; |
| } |
| |
| char *strndup(const char *s, size_t n) { |
| size_t length = std::min(strlen(s), n); |
| |
| char *buffer = reinterpret_cast<char *>(malloc(length + 1)); |
| if (buffer == nullptr) |
| return buffer; |
| |
| strncpy(buffer, s, length); |
| buffer[length] = '\0'; |
| return buffer; |
| } |
| } |
| #endif |
| |
| using namespace swift; |
| |
| #if SWIFT_OBJC_INTEROP |
| // Declare the debugQuickLookObject selector. |
| @interface DeclareSelectors |
| - (id)debugQuickLookObject; |
| @end |
| #endif |
| |
| namespace { |
| |
| /// The layout of Any. |
| using Any = OpaqueExistentialContainer; |
| |
| // Swift assumes Any is returned in memory. |
| // Use AnyReturn to guarantee that even on architectures |
| // where Any would be returned in registers. |
| struct AnyReturn { |
| Any any; |
| AnyReturn(Any a) : any(a) { } |
| operator Any() { return any; } |
| ~AnyReturn() { } |
| }; |
| |
| static std::tuple<const Metadata *, OpaqueValue *> |
| unwrapExistential(const Metadata *T, OpaqueValue *Value) { |
| // If the value is an existential container, look through it to reflect the |
| // contained value. |
| // TODO: Should look through existential metatypes too, but it doesn't |
| // really matter yet since we don't have any special mirror behavior for |
| // concrete metatypes yet. |
| while (T->getKind() == MetadataKind::Existential) { |
| auto *existential |
| = static_cast<const ExistentialTypeMetadata *>(T); |
| |
| // Unwrap the existential container. |
| T = existential->getDynamicType(Value); |
| Value = existential->projectValue(Value); |
| |
| // Existential containers can end up nested in some cases due to generic |
| // abstraction barriers. Repeat in case we have a nested existential. |
| } |
| return std::make_tuple(T, Value); |
| } |
| |
| static bool loadSpecialReferenceStorage(OpaqueValue *fieldData, |
| const FieldType fieldType, |
| Any *outValue) { |
| // isWeak() implies a reference type via Sema. |
| if (!fieldType.isWeak()) |
| return false; |
| |
| auto type = fieldType.getType(); |
| assert(type->getKind() == MetadataKind::Optional); |
| |
| auto *weakField = reinterpret_cast<WeakReference *>(fieldData); |
| auto *strongValue = swift_unknownObjectWeakLoadStrong(weakField); |
| |
| // Now that we have a strong reference, we need to create a temporary buffer |
| // from which to copy the whole value, which might be a native class-bound |
| // existential, which means we also need to copy n witness tables, for |
| // however many protocols are in the protocol composition. For example, if we |
| // are copying a: |
| // weak var myWeakProperty : (Protocol1 & Protocol2)? |
| // then we need to copy three values: |
| // - the instance |
| // - the witness table for Protocol1 |
| // - the witness table for Protocol2 |
| |
| auto *weakContainer = |
| reinterpret_cast<WeakClassExistentialContainer *>(fieldData); |
| |
| // Create a temporary existential where we can put the strong reference. |
| // The allocateBuffer value witness requires a ValueBuffer to own the |
| // allocated storage. |
| ValueBuffer temporaryBuffer; |
| |
| auto *temporaryValue = reinterpret_cast<ClassExistentialContainer *>( |
| type->allocateBufferIn(&temporaryBuffer)); |
| |
| // Now copy the entire value out of the parent, which will include the |
| // witness tables. |
| temporaryValue->Value = strongValue; |
| auto valueWitnessesSize = type->getValueWitnesses()->getSize() - |
| sizeof(WeakClassExistentialContainer); |
| memcpy(temporaryValue->getWitnessTables(), weakContainer->getWitnessTables(), |
| valueWitnessesSize); |
| |
| outValue->Type = type; |
| auto *opaqueValueAddr = type->allocateBoxForExistentialIn(&outValue->Buffer); |
| type->vw_initializeWithCopy(opaqueValueAddr, |
| reinterpret_cast<OpaqueValue *>(temporaryValue)); |
| |
| type->deallocateBufferIn(&temporaryBuffer); |
| |
| return true; |
| } |
| |
| |
| // Abstract base class for reflection implementations. |
| struct ReflectionMirrorImpl { |
| const Metadata *type; |
| OpaqueValue *value; |
| |
| virtual char displayStyle() = 0; |
| virtual intptr_t count() = 0; |
| virtual AnyReturn subscript(intptr_t index, const char **outName, |
| void (**outFreeFunc)(const char *)) = 0; |
| virtual const char *enumCaseName() { return nullptr; } |
| |
| #if SWIFT_OBJC_INTEROP |
| virtual id quickLookObject() { return nil; } |
| #endif |
| |
| virtual ~ReflectionMirrorImpl() {} |
| }; |
| |
| |
| // Implementation for tuples. |
| struct TupleImpl : ReflectionMirrorImpl { |
| char displayStyle() { |
| return 't'; |
| } |
| |
| intptr_t count() { |
| auto *Tuple = static_cast<const TupleTypeMetadata *>(type); |
| return Tuple->NumElements; |
| } |
| |
| AnyReturn subscript(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) { |
| auto *Tuple = static_cast<const TupleTypeMetadata *>(type); |
| |
| if (i < 0 || (size_t)i > Tuple->NumElements) |
| swift::crash("Swift mirror subscript bounds check failure"); |
| |
| // Determine whether there is a label. |
| bool hasLabel = false; |
| if (const char *labels = Tuple->Labels) { |
| const char *space = strchr(labels, ' '); |
| for (intptr_t j = 0; j != i && space; ++j) { |
| labels = space + 1; |
| space = strchr(labels, ' '); |
| } |
| |
| // If we have a label, create it. |
| if (labels && space && labels != space) { |
| *outName = strndup(labels, space - labels); |
| hasLabel = true; |
| } |
| } |
| |
| if (!hasLabel) { |
| // The name is the stringized element number '.0'. |
| char *str; |
| asprintf(&str, ".%" PRIdPTR, i); |
| *outName = str; |
| } |
| |
| *outFreeFunc = [](const char *str) { free(const_cast<char *>(str)); }; |
| |
| // Get the nth element. |
| auto &elt = Tuple->getElement(i); |
| auto *bytes = reinterpret_cast<const char *>(value); |
| auto *eltData = reinterpret_cast<const OpaqueValue *>(bytes + elt.Offset); |
| |
| Any result; |
| |
| result.Type = elt.Type; |
| auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer); |
| result.Type->vw_initializeWithCopy(opaqueValueAddr, |
| const_cast<OpaqueValue *>(eltData)); |
| |
| return AnyReturn(result); |
| } |
| }; |
| |
| struct swift_closure { |
| void *fptr; |
| HeapObject *context; |
| }; |
| SWIFT_RUNTIME_STDLIB_API SWIFT_CC(swift) swift_closure |
| MANGLE_SYM(s20_playgroundPrintHookySScSgvg)(); |
| |
| static bool _shouldReportMissingReflectionMetadataWarnings() { |
| // Missing metadata warnings noise up playground sessions and aren't really |
| // actionable in playground contexts. If we're running in a playground, |
| // suppress warnings. |
| // |
| // Guesstimate whether we're in a playground by looking at the |
| // _playgroundPrintHook variable in the standard library, which is set during |
| // playground execution. |
| auto hook = MANGLE_SYM(s20_playgroundPrintHookySScSgvg)(); |
| if (hook.fptr) { |
| swift_release(hook.context); |
| return false; |
| } else { |
| return true; |
| } |
| } |
| |
| /// Raise a warning about reflection metadata that could not be found |
| /// at runtime. This is usually mostly harmless, but it's good to alert |
| /// users that it happens. |
| static void |
| missing_reflection_metadata_warning(const char *fmt, ...) { |
| bool shouldWarn = |
| SWIFT_LAZY_CONSTANT(_shouldReportMissingReflectionMetadataWarnings()); |
| |
| if (!shouldWarn) |
| return; |
| |
| va_list args; |
| va_start(args, fmt); |
| |
| warningv(0, fmt, args); |
| } |
| |
| static std::pair<StringRef /*name*/, FieldType /*fieldInfo*/> |
| getFieldAt(const Metadata *base, unsigned index) { |
| using namespace reflection; |
| |
| // If we failed to find the field descriptor metadata for the type, fall |
| // back to returning an empty tuple as a standin. |
| auto failedToFindMetadata = [&]() -> std::pair<StringRef, FieldType> { |
| auto typeName = swift_getTypeName(base, /*qualified*/ true); |
| missing_reflection_metadata_warning( |
| "warning: the Swift runtime found no field metadata for " |
| "type '%*s' that claims to be reflectable. Its fields will show up as " |
| "'unknown' in Mirrors\n", |
| (int)typeName.length, typeName.data); |
| return {"unknown", |
| FieldType() |
| .withType(TypeInfo(&METADATA_SYM(EMPTY_TUPLE_MANGLING), {})) |
| .withIndirect(false) |
| .withWeak(false)}; |
| }; |
| |
| auto *baseDesc = base->getTypeContextDescriptor(); |
| if (!baseDesc) |
| return failedToFindMetadata(); |
| |
| auto *fields = baseDesc->Fields.get(); |
| if (!fields) |
| return failedToFindMetadata(); |
| |
| const FieldDescriptor &descriptor = *fields; |
| auto &field = descriptor.getFields()[index]; |
| auto name = field.getFieldName(0); |
| |
| // Enum cases don't always have types. |
| if (!field.hasMangledTypeName()) |
| return {name, FieldType().withIndirect(field.isIndirectCase())}; |
| |
| std::vector<const ContextDescriptor *> descriptorPath; |
| { |
| const auto *parent = reinterpret_cast< |
| const ContextDescriptor *>(baseDesc); |
| while (parent) { |
| if (parent->isGeneric()) |
| descriptorPath.push_back(parent); |
| |
| parent = parent->Parent.get(); |
| } |
| } |
| |
| auto typeName = field.getMangledTypeName(0); |
| |
| auto typeInfo = _getTypeByMangledName( |
| typeName, |
| [&](unsigned depth, unsigned index) -> const Metadata * { |
| if (depth >= descriptorPath.size()) |
| return nullptr; |
| |
| unsigned currentDepth = 0; |
| unsigned flatIndex = index; |
| const ContextDescriptor *currentContext = descriptorPath.back(); |
| |
| for (const auto *context : llvm::reverse(descriptorPath)) { |
| if (currentDepth >= depth) |
| break; |
| |
| flatIndex += context->getNumGenericParams(); |
| currentContext = context; |
| ++currentDepth; |
| } |
| |
| if (index >= currentContext->getNumGenericParams()) |
| return nullptr; |
| |
| return base->getGenericArgs()[flatIndex]; |
| }); |
| |
| // If demangling the type failed, pretend it's an empty type instead with |
| // a log message. |
| if (typeInfo == nullptr) { |
| typeInfo = TypeInfo(&METADATA_SYM(EMPTY_TUPLE_MANGLING), {}); |
| missing_reflection_metadata_warning( |
| "warning: the Swift runtime was unable to demangle the type " |
| "of field '%*s'. the mangled type name is '%*s'. this field will " |
| "show up as an empty tuple in Mirrors\n", |
| (int)name.size(), name.data(), |
| (int)typeName.size(), typeName.data()); |
| } |
| |
| return {name, FieldType() |
| .withType(typeInfo) |
| .withIndirect(field.isIndirectCase()) |
| .withWeak(typeInfo.isWeak())}; |
| } |
| |
| // Implementation for structs. |
| struct StructImpl : ReflectionMirrorImpl { |
| bool isReflectable() { |
| const auto *Struct = static_cast<const StructMetadata *>(type); |
| const auto &Description = Struct->getDescription(); |
| return Description->isReflectable(); |
| } |
| |
| char displayStyle() { |
| return 's'; |
| } |
| |
| intptr_t count() { |
| if (!isReflectable()) { |
| return 0; |
| } |
| |
| auto *Struct = static_cast<const StructMetadata *>(type); |
| return Struct->getDescription()->NumFields; |
| } |
| |
| AnyReturn subscript(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) { |
| auto *Struct = static_cast<const StructMetadata *>(type); |
| |
| if (i < 0 || (size_t)i > Struct->getDescription()->NumFields) |
| swift::crash("Swift mirror subscript bounds check failure"); |
| |
| // Load the offset from its respective vector. |
| auto fieldOffset = Struct->getFieldOffsets()[i]; |
| |
| Any result; |
| StringRef name; |
| FieldType fieldInfo; |
| std::tie(name, fieldInfo) = getFieldAt(type, i); |
| assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented"); |
| |
| *outName = name.data(); |
| *outFreeFunc = nullptr; |
| |
| auto *bytes = reinterpret_cast<char*>(value); |
| auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset); |
| |
| bool didLoad = loadSpecialReferenceStorage(fieldData, fieldInfo, &result); |
| if (!didLoad) { |
| result.Type = fieldInfo.getType(); |
| auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer); |
| result.Type->vw_initializeWithCopy(opaqueValueAddr, |
| const_cast<OpaqueValue *>(fieldData)); |
| } |
| |
| return AnyReturn(result); |
| } |
| }; |
| |
| |
| // Implementation for enums. |
| struct EnumImpl : ReflectionMirrorImpl { |
| bool isReflectable() { |
| const auto *Enum = static_cast<const EnumMetadata *>(type); |
| const auto &Description = Enum->getDescription(); |
| return Description->isReflectable(); |
| } |
| |
| const char *getInfo(unsigned *tagPtr = nullptr, |
| const Metadata **payloadTypePtr = nullptr, |
| bool *indirectPtr = nullptr) { |
| // 'tag' is in the range [0..NumElements-1]. |
| unsigned tag = type->vw_getEnumTag(value); |
| |
| StringRef name; |
| FieldType info; |
| std::tie(name, info) = getFieldAt(type, tag); |
| const Metadata *payloadType = info.getType(); |
| bool indirect = info.isIndirect(); |
| |
| if (tagPtr) |
| *tagPtr = tag; |
| if (payloadTypePtr) |
| *payloadTypePtr = payloadType; |
| if (indirectPtr) |
| *indirectPtr = indirect; |
| |
| return name.data(); |
| } |
| |
| char displayStyle() { |
| return 'e'; |
| } |
| |
| intptr_t count() { |
| if (!isReflectable()) { |
| return 0; |
| } |
| |
| const Metadata *payloadType; |
| getInfo(nullptr, &payloadType, nullptr); |
| return (payloadType != nullptr) ? 1 : 0; |
| } |
| |
| AnyReturn subscript(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) { |
| unsigned tag; |
| const Metadata *payloadType; |
| bool indirect; |
| |
| auto *caseName = getInfo(&tag, &payloadType, &indirect); |
| |
| // Copy the enum payload into a box |
| const Metadata *boxType = (indirect ? &METADATA_SYM(Bo).base : payloadType); |
| BoxPair pair = swift_allocBox(boxType); |
| |
| type->vw_destructiveProjectEnumData(const_cast<OpaqueValue *>(value)); |
| boxType->vw_initializeWithCopy(pair.buffer, const_cast<OpaqueValue *>(value)); |
| type->vw_destructiveInjectEnumTag(const_cast<OpaqueValue *>(value), tag); |
| |
| value = pair.buffer; |
| |
| // If the payload is indirect, we need to jump through the box to get it. |
| if (indirect) { |
| const HeapObject *owner = *reinterpret_cast<HeapObject * const *>(value); |
| value = swift_projectBox(const_cast<HeapObject *>(owner)); |
| } |
| |
| *outName = caseName; |
| *outFreeFunc = nullptr; |
| |
| Any result; |
| |
| result.Type = payloadType; |
| auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer); |
| result.Type->vw_initializeWithCopy(opaqueValueAddr, |
| const_cast<OpaqueValue *>(value)); |
| |
| swift_release(pair.object); |
| return AnyReturn(result); |
| } |
| |
| const char *enumCaseName() { |
| if (!isReflectable()) { |
| return nullptr; |
| } |
| |
| return getInfo(); |
| } |
| }; |
| |
| |
| // Implementation for classes. |
| struct ClassImpl : ReflectionMirrorImpl { |
| bool isReflectable() { |
| const auto *Class = static_cast<const ClassMetadata *>(type); |
| const auto &Description = Class->getDescription(); |
| return Description->isReflectable(); |
| } |
| |
| char displayStyle() { |
| return 'c'; |
| } |
| |
| intptr_t count() { |
| if (!isReflectable()) |
| return 0; |
| |
| auto *Clas = static_cast<const ClassMetadata*>(type); |
| auto count = Clas->getDescription()->NumFields; |
| |
| return count; |
| } |
| |
| AnyReturn subscript(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) { |
| auto *Clas = static_cast<const ClassMetadata*>(type); |
| |
| if (i < 0 || (size_t)i > Clas->getDescription()->NumFields) |
| swift::crash("Swift mirror subscript bounds check failure"); |
| |
| // FIXME: If the class has ObjC heritage, get the field offset using the ObjC |
| // metadata, because we don't update the field offsets in the face of |
| // resilient base classes. |
| uintptr_t fieldOffset; |
| if (usesNativeSwiftReferenceCounting(Clas)) { |
| fieldOffset = Clas->getFieldOffsets()[i]; |
| } else { |
| #if SWIFT_OBJC_INTEROP |
| Ivar *ivars = class_copyIvarList((Class)Clas, nullptr); |
| fieldOffset = ivar_getOffset(ivars[i]); |
| free(ivars); |
| #else |
| swift::crash("Object appears to be Objective-C, but no runtime."); |
| #endif |
| } |
| |
| Any result; |
| StringRef name; |
| FieldType fieldInfo; |
| std::tie(name, fieldInfo) = getFieldAt(type, i); |
| assert(!fieldInfo.isIndirect() && "class indirect properties not implemented"); |
| |
| auto *bytes = *reinterpret_cast<char * const *>(value); |
| auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset); |
| |
| *outName = name.data(); |
| *outFreeFunc = nullptr; |
| |
| bool didLoad = loadSpecialReferenceStorage(fieldData, fieldInfo, &result); |
| if (!didLoad) { |
| result.Type = fieldInfo.getType(); |
| auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer); |
| result.Type->vw_initializeWithCopy(opaqueValueAddr, |
| const_cast<OpaqueValue *>(fieldData)); |
| } |
| |
| return AnyReturn(result); |
| } |
| |
| #if SWIFT_OBJC_INTEROP |
| id quickLookObject() { |
| id object = [*reinterpret_cast<const id *>(value) retain]; |
| if ([object respondsToSelector:@selector(debugQuickLookObject)]) { |
| id quickLookObject = [object debugQuickLookObject]; |
| [quickLookObject retain]; |
| [object release]; |
| return quickLookObject; |
| } |
| |
| return object; |
| } |
| #endif |
| }; |
| |
| |
| #if SWIFT_OBJC_INTEROP |
| // Implementation for ObjC classes. |
| struct ObjCClassImpl : ClassImpl { |
| intptr_t count() { |
| // ObjC makes no guarantees about the state of ivars, so we can't safely |
| // introspect them in the general case. |
| return 0; |
| } |
| |
| AnyReturn subscript(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) { |
| swift::crash("Cannot get children of Objective-C objects."); |
| } |
| }; |
| #endif |
| |
| |
| // Implementation for metatypes. |
| struct MetatypeImpl : ReflectionMirrorImpl { |
| char displayStyle() { |
| return '\0'; |
| } |
| |
| intptr_t count() { |
| return 0; |
| } |
| |
| AnyReturn subscript(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) { |
| swift::crash("Metatypes have no children."); |
| } |
| }; |
| |
| |
| // Implementation for opaque types. |
| struct OpaqueImpl : ReflectionMirrorImpl { |
| char displayStyle() { |
| return '\0'; |
| } |
| |
| intptr_t count() { |
| return 0; |
| } |
| |
| AnyReturn subscript(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) { |
| swift::crash("Opaque types have no children."); |
| } |
| }; |
| |
| |
| template<typename F> |
| auto call(OpaqueValue *passedValue, const Metadata *T, const Metadata *passedType, |
| const F &f) -> decltype(f(nullptr)) |
| { |
| const Metadata *type; |
| OpaqueValue *value; |
| std::tie(type, value) = unwrapExistential(T, passedValue); |
| |
| if (passedType != nullptr) { |
| type = passedType; |
| } |
| |
| auto call = [&](ReflectionMirrorImpl *impl) { |
| impl->type = type; |
| impl->value = value; |
| auto result = f(impl); |
| return result; |
| }; |
| |
| auto callClass = [&] { |
| if (passedType == nullptr) { |
| // Get the runtime type of the object. |
| const void *obj = *reinterpret_cast<const void * const *>(value); |
| auto isa = _swift_getClass(obj); |
| |
| // Look through artificial subclasses. |
| while (isa->isTypeMetadata() && isa->isArtificialSubclass()) { |
| isa = isa->Superclass; |
| } |
| passedType = isa; |
| } |
| |
| #if SWIFT_OBJC_INTEROP |
| // If this is a pure ObjC class, reflect it using ObjC's runtime facilities. |
| // ForeignClass (e.g. CF classes) manifests as a NULL class object. |
| auto *classObject = passedType->getClassObject(); |
| if (classObject == nullptr || !classObject->isTypeMetadata()) { |
| ObjCClassImpl impl; |
| return call(&impl); |
| } |
| #endif |
| |
| // Otherwise, use the native Swift facilities. |
| ClassImpl impl; |
| return call(&impl); |
| }; |
| |
| switch (type->getKind()) { |
| case MetadataKind::Tuple: { |
| TupleImpl impl; |
| return call(&impl); |
| } |
| |
| case MetadataKind::Struct: { |
| StructImpl impl; |
| return call(&impl); |
| } |
| |
| |
| case MetadataKind::Enum: |
| case MetadataKind::Optional: { |
| EnumImpl impl; |
| return call(&impl); |
| } |
| |
| case MetadataKind::ObjCClassWrapper: |
| case MetadataKind::ForeignClass: |
| case MetadataKind::Class: { |
| return callClass(); |
| } |
| |
| case MetadataKind::Metatype: |
| case MetadataKind::ExistentialMetatype: { |
| MetatypeImpl impl; |
| return call(&impl); |
| } |
| |
| case MetadataKind::Opaque: { |
| #if SWIFT_OBJC_INTEROP |
| // If this is the Builtin.UnknownObject type, use the dynamic type of the |
| // object reference. |
| if (type == &METADATA_SYM(BO).base) { |
| return callClass(); |
| } |
| #endif |
| // If this is the Builtin.NativeObject type, and the heap object is a |
| // class instance, use the dynamic type of the object reference. |
| if (type == &METADATA_SYM(Bo).base) { |
| const HeapObject *obj |
| = *reinterpret_cast<const HeapObject * const*>(value); |
| if (obj->metadata->getKind() == MetadataKind::Class) { |
| return callClass(); |
| } |
| } |
| LLVM_FALLTHROUGH; |
| } |
| |
| /// TODO: Implement specialized mirror witnesses for all kinds. |
| default: |
| break; |
| |
| // Types can't have these kinds. |
| case MetadataKind::HeapLocalVariable: |
| case MetadataKind::HeapGenericLocalVariable: |
| case MetadataKind::ErrorObject: |
| swift::crash("Swift mirror lookup failure"); |
| } |
| |
| // If we have an unknown kind of type, or a type without special handling, |
| // treat it as opaque. |
| OpaqueImpl impl; |
| return call(&impl); |
| } |
| |
| } // end anonymous namespace |
| |
| |
| // func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type |
| SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API |
| const Metadata *swift_reflectionMirror_normalizedType(OpaqueValue *value, |
| const Metadata *type, |
| const Metadata *T) { |
| return call(value, T, type, [](ReflectionMirrorImpl *impl) { return impl->type; }); |
| } |
| |
| // func _getChildCount<T>(_: T, type: Any.Type) -> Int |
| SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API |
| intptr_t swift_reflectionMirror_count(OpaqueValue *value, |
| const Metadata *type, |
| const Metadata *T) { |
| return call(value, T, type, [](ReflectionMirrorImpl *impl) { |
| return impl->count(); |
| }); |
| } |
| |
| // We intentionally use a non-POD return type with this entry point to give |
| // it an indirect return ABI for compatibility with Swift. |
| #pragma clang diagnostic push |
| #pragma clang diagnostic ignored "-Wreturn-type-c-linkage" |
| // func _getChild<T>( |
| // of: T, |
| // type: Any.Type, |
| // index: Int, |
| // outName: UnsafeMutablePointer<UnsafePointer<CChar>?>, |
| // outFreeFunc: UnsafeMutablePointer<NameFreeFunc?> |
| // ) -> Any |
| SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API |
| AnyReturn swift_reflectionMirror_subscript(OpaqueValue *value, const Metadata *type, |
| intptr_t index, |
| const char **outName, |
| void (**outFreeFunc)(const char *), |
| const Metadata *T) { |
| return call(value, T, type, [&](ReflectionMirrorImpl *impl) { |
| return impl->subscript(index, outName, outFreeFunc); |
| }); |
| } |
| #pragma clang diagnostic pop |
| |
| // func _getDisplayStyle<T>(_: T) -> CChar |
| SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API |
| char swift_reflectionMirror_displayStyle(OpaqueValue *value, const Metadata *T) { |
| return call(value, T, nullptr, [](ReflectionMirrorImpl *impl) { return impl->displayStyle(); }); |
| } |
| |
| // func _getEnumCaseName<T>(_ value: T) -> UnsafePointer<CChar>? |
| SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API |
| const char *swift_EnumCaseName(OpaqueValue *value, const Metadata *T) { |
| return call(value, T, nullptr, [](ReflectionMirrorImpl *impl) { return impl->enumCaseName(); }); |
| } |
| |
| // func _opaqueSummary(_ metadata: Any.Type) -> UnsafePointer<CChar>? |
| SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API |
| const char *swift_OpaqueSummary(const Metadata *T) { |
| switch (T->getKind()) { |
| case MetadataKind::Class: |
| case MetadataKind::Struct: |
| case MetadataKind::Enum: |
| case MetadataKind::Optional: |
| case MetadataKind::Metatype: |
| return nullptr; |
| case MetadataKind::Opaque: |
| return "(Opaque Value)"; |
| case MetadataKind::Tuple: |
| return "(Tuple)"; |
| case MetadataKind::Function: |
| return "(Function)"; |
| case MetadataKind::Existential: |
| return "(Existential)"; |
| case MetadataKind::ObjCClassWrapper: |
| return "(Objective-C Class Wrapper)"; |
| case MetadataKind::ExistentialMetatype: |
| return "(Existential Metatype)"; |
| case MetadataKind::ForeignClass: |
| return "(Foreign Class)"; |
| case MetadataKind::HeapLocalVariable: |
| return "(Heap Local Variable)"; |
| case MetadataKind::HeapGenericLocalVariable: |
| return "(Heap Generic Local Variable)"; |
| case MetadataKind::ErrorObject: |
| return "(ErrorType Object)"; |
| default: |
| return "(Unknown)"; |
| } |
| } |
| |
| #if SWIFT_OBJC_INTEROP |
| // func _getQuickLookObject<T>(_: T) -> AnyObject? |
| SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API |
| id swift_reflectionMirror_quickLookObject(OpaqueValue *value, const Metadata *T) { |
| return call(value, T, nullptr, [](ReflectionMirrorImpl *impl) { return impl->quickLookObject(); }); |
| } |
| #endif |