| //===----------------------------------------------------------------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2020 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/Basic/Unreachable.h" |
| #include "swift/Demangling/Demangle.h" |
| #include "swift/Runtime/Debug.h" |
| #include "swift/Runtime/Portability.h" |
| #include "Private.h" |
| #include "WeakReference.h" |
| #include "../SwiftShims/Reflection.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" |
| #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); |
| (*strp)[length] = '\0'; |
| |
| 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; |
| |
| namespace { |
| |
| class FieldType { |
| const Metadata *type; |
| bool indirect; |
| bool var = false; |
| TypeReferenceOwnership referenceOwnership; |
| public: |
| |
| constexpr FieldType() : type(nullptr), indirect(false), referenceOwnership() { } |
| constexpr FieldType(const Metadata *T) : type(T), indirect(false), referenceOwnership() { } |
| |
| static constexpr FieldType untypedEnumCase(bool indirect) { |
| FieldType type{}; |
| type.indirect = indirect; |
| return type; |
| } |
| const Metadata *getType() const { return type; } |
| const TypeReferenceOwnership getReferenceOwnership() const { return referenceOwnership; } |
| bool isIndirect() const { return indirect; } |
| void setIndirect(bool value) { indirect = value; } |
| bool isVar() const { return var; } |
| void setIsVar(bool value) { var = value; } |
| void setReferenceOwnership(TypeReferenceOwnership newOwnership) { |
| referenceOwnership = newOwnership; |
| } |
| }; |
| |
| /// 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 void copyWeakFieldContents(OpaqueValue *destContainer, const Metadata *type, OpaqueValue *fieldData) { |
| assert(type->getKind() == MetadataKind::Optional); |
| auto *srcContainer = reinterpret_cast<WeakClassExistentialContainer*>(fieldData); |
| auto *destClassContainer = reinterpret_cast<ClassExistentialContainer*>(destContainer); |
| destClassContainer->Value = swift_unknownObjectWeakLoadStrong(&srcContainer->Value); |
| auto witnessTablesSize = type->vw_size() - sizeof(WeakClassExistentialContainer); |
| memcpy(destClassContainer->getWitnessTables(), srcContainer->getWitnessTables(), witnessTablesSize); |
| } |
| |
| static void copyUnownedFieldContents(OpaqueValue *destContainer, const Metadata *type, OpaqueValue *fieldData) { |
| auto *srcContainer = reinterpret_cast<UnownedClassExistentialContainer*>(fieldData); |
| auto *destClassContainer = reinterpret_cast<ClassExistentialContainer*>(destContainer); |
| destClassContainer->Value = swift_unknownObjectUnownedLoadStrong(&srcContainer->Value); |
| auto witnessTablesSize = type->vw_size() - sizeof(UnownedClassExistentialContainer); |
| memcpy(destClassContainer->getWitnessTables(), srcContainer->getWitnessTables(), witnessTablesSize); |
| } |
| |
| static void copyUnmanagedFieldContents(OpaqueValue *destContainer, const Metadata *type, OpaqueValue *fieldData) { |
| // Also known as "unowned(unsafe)". |
| // This is simpler than the unowned/weak cases because unmanaged |
| // references are fundamentally the same as strong ones, so we |
| // can use the regular strong reference support that already |
| // knows how to handle existentials and Obj-C references. |
| type->vw_initializeWithCopy(destContainer, fieldData); |
| } |
| |
| static AnyReturn copyFieldContents(OpaqueValue *fieldData, |
| const FieldType fieldType) { |
| Any outValue; |
| auto *type = fieldType.getType(); |
| outValue.Type = type; |
| auto ownership = fieldType.getReferenceOwnership(); |
| auto *destContainer = type->allocateBoxForExistentialIn(&outValue.Buffer); |
| |
| if (ownership.isStrong()) { |
| type->vw_initializeWithCopy(destContainer, fieldData); |
| } |
| |
| // Generate a conditional clause for every known ownership type. |
| // If this causes errors, it's because someone added a new ownership type |
| // to ReferenceStorage.def and missed some related updates. |
| #define REF_STORAGE(Name, ...) \ |
| else if (ownership.is##Name()) { \ |
| copy##Name##FieldContents(destContainer, type, fieldData); \ |
| } |
| #include "swift/AST/ReferenceStorage.def" |
| |
| else { |
| // The field was declared with a reference type we don't understand. |
| warning(0, "Value with unrecognized reference type is reflected as ()"); |
| // Clean up the buffer allocated above |
| type->deallocateBoxForExistentialIn(&outValue.Buffer); |
| // Return an existential containing Void |
| outValue.Type = &METADATA_SYM(EMPTY_TUPLE_MANGLING); |
| } |
| |
| return AnyReturn(outValue); |
| } |
| |
| |
| // Abstract base class for reflection implementations. |
| struct ReflectionMirrorImpl { |
| const Metadata *type; |
| OpaqueValue *value; |
| |
| virtual char displayStyle() = 0; |
| virtual intptr_t count() = 0; |
| virtual intptr_t childOffset(intptr_t index) = 0; |
| virtual const FieldType childMetadata(intptr_t index, |
| const char **outName, |
| void (**outFreeFunc)(const char *)) = 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 |
| |
| // For class types, traverse through superclasses when providing field |
| // information. The base implementations call through to their local-only |
| // counterparts. |
| virtual intptr_t recursiveCount() { |
| return count(); |
| } |
| virtual intptr_t recursiveChildOffset(intptr_t index) { |
| return childOffset(index); |
| } |
| virtual const FieldType recursiveChildMetadata(intptr_t index, |
| const char **outName, |
| void (**outFreeFunc)(const char *)) |
| { |
| return childMetadata(index, outName, outFreeFunc); |
| } |
| |
| virtual ~ReflectionMirrorImpl() {} |
| }; |
| |
| |
| // Implementation for tuples. |
| struct TupleImpl : ReflectionMirrorImpl { |
| char displayStyle() override { |
| return 't'; |
| } |
| |
| intptr_t count() override { |
| auto *Tuple = static_cast<const TupleTypeMetadata *>(type); |
| return Tuple->NumElements; |
| } |
| |
| intptr_t childOffset(intptr_t i) override { |
| auto *Tuple = static_cast<const TupleTypeMetadata *>(type); |
| |
| if (i < 0 || (size_t)i > Tuple->NumElements) |
| swift::crash("Swift mirror subscript bounds check failure"); |
| |
| // Get the nth element. |
| auto &elt = Tuple->getElement(i); |
| return elt.Offset; |
| } |
| |
| const FieldType childMetadata(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) override { |
| 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); |
| |
| FieldType result(elt.Type); |
| // All tuples are mutable. |
| result.setIsVar(true); |
| return result; |
| } |
| |
| AnyReturn subscript(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) override { |
| auto eltOffset = childOffset(i); |
| auto fieldType = childMetadata(i, outName, outFreeFunc); |
| |
| auto *bytes = reinterpret_cast<const char *>(value); |
| auto *eltData = reinterpret_cast<const OpaqueValue *>(bytes + eltOffset); |
| |
| Any result; |
| |
| result.Type = fieldType.getType(); |
| 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; |
| }; |
| #if SWIFT_LIBRARY_EVOLUTION |
| SWIFT_RUNTIME_STDLIB_API SWIFT_CC(swift) swift_closure |
| MANGLE_SYM(s20_playgroundPrintHookySScSgvg)(); |
| #else |
| SWIFT_RUNTIME_STDLIB_API swift_closure |
| MANGLE_SYM(s20_playgroundPrintHookySScSgvp); |
| #endif |
| |
| 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. |
| #if SWIFT_LIBRARY_EVOLUTION |
| auto hook = MANGLE_SYM(s20_playgroundPrintHookySScSgvg)(); |
| #else |
| auto hook = MANGLE_SYM(s20_playgroundPrintHookySScSgvp); |
| #endif |
| 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(&METADATA_SYM(EMPTY_TUPLE_MANGLING))}; |
| }; |
| |
| auto *baseDesc = base->getTypeContextDescriptor(); |
| if (!baseDesc) |
| return failedToFindMetadata(); |
| |
| auto *fields = baseDesc->Fields.get(); |
| if (!fields) |
| return failedToFindMetadata(); |
| |
| auto &field = fields->getFields()[index]; |
| // Bounds are always valid as the offset is constant. |
| auto name = field.getFieldName(); |
| |
| // Enum cases don't always have types. |
| if (!field.hasMangledTypeName()) |
| return {name, FieldType::untypedEnumCase(field.isIndirectCase())}; |
| |
| auto typeName = field.getMangledTypeName(); |
| |
| SubstGenericParametersFromMetadata substitutions(base); |
| auto result = swift_getTypeByMangledName( |
| MetadataState::Complete, typeName, substitutions.getGenericArgs(), |
| [&substitutions](unsigned depth, unsigned index) { |
| return substitutions.getMetadata(depth, index); |
| }, |
| [&substitutions](const Metadata *type, unsigned index) { |
| return substitutions.getWitnessTable(type, index); |
| }); |
| |
| // If demangling the type failed, pretend it's an empty type instead with |
| // a log message. |
| TypeInfo typeInfo; |
| if (result.isError()) { |
| typeInfo = TypeInfo({&METADATA_SYM(EMPTY_TUPLE_MANGLING), |
| MetadataState::Complete}, {}); |
| |
| auto *error = result.getError(); |
| char *str = error->copyErrorString(); |
| missing_reflection_metadata_warning( |
| "warning: the Swift runtime was unable to demangle the type " |
| "of field '%*s'. the mangled type name is '%*s': %s. this field will " |
| "show up as an empty tuple in Mirrors\n", |
| (int)name.size(), name.data(), (int)typeName.size(), typeName.data(), |
| str); |
| error->freeErrorString(str); |
| } else { |
| typeInfo = result.getType(); |
| } |
| |
| auto fieldType = FieldType(typeInfo.getMetadata()); |
| fieldType.setIndirect(field.isIndirectCase()); |
| fieldType.setReferenceOwnership(typeInfo.getReferenceOwnership()); |
| fieldType.setIsVar(field.isVar()); |
| return {name, fieldType}; |
| } |
| |
| // 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() override { |
| return 's'; |
| } |
| |
| intptr_t count() override { |
| if (!isReflectable()) { |
| return 0; |
| } |
| |
| auto *Struct = static_cast<const StructMetadata *>(type); |
| return Struct->getDescription()->NumFields; |
| } |
| |
| intptr_t childOffset(intptr_t i) override { |
| 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. |
| return Struct->getFieldOffsets()[i]; |
| } |
| |
| const FieldType childMetadata(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) override { |
| StringRef name; |
| FieldType fieldInfo; |
| std::tie(name, fieldInfo) = getFieldAt(type, i); |
| assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented"); |
| |
| *outName = name.data(); |
| *outFreeFunc = nullptr; |
| |
| return fieldInfo; |
| } |
| |
| AnyReturn subscript(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) override { |
| auto fieldInfo = childMetadata(i, outName, outFreeFunc); |
| |
| auto *bytes = reinterpret_cast<char*>(value); |
| auto fieldOffset = childOffset(i); |
| auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset); |
| |
| return copyFieldContents(fieldData, fieldInfo); |
| } |
| }; |
| |
| |
| // 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() override { |
| return 'e'; |
| } |
| |
| intptr_t count() override { |
| if (!isReflectable()) { |
| return 0; |
| } |
| |
| // No fields if reflecting the enumeration type instead of a case |
| if (!value) { |
| return 0; |
| } |
| |
| const Metadata *payloadType; |
| getInfo(nullptr, &payloadType, nullptr); |
| return (payloadType != nullptr) ? 1 : 0; |
| } |
| |
| intptr_t childOffset(intptr_t i) override { |
| return 0; |
| } |
| |
| const FieldType childMetadata(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) override { |
| return FieldType(); |
| } |
| |
| AnyReturn subscript(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) override { |
| unsigned tag; |
| const Metadata *payloadType; |
| bool indirect; |
| |
| auto *caseName = getInfo(&tag, &payloadType, &indirect); |
| |
| // Copy the enum itself so that we can project the data without destroying |
| // the original. |
| Any enumCopy; |
| auto *enumCopyContainer |
| = type->allocateBoxForExistentialIn(&enumCopy.Buffer); |
| type->vw_initializeWithCopy(enumCopyContainer, |
| const_cast<OpaqueValue *>(value)); |
| |
| // Copy the enum payload into a box |
| const Metadata *boxType = (indirect ? &METADATA_SYM(Bo).base : payloadType); |
| BoxPair pair = swift_allocBox(boxType); |
| type->vw_destructiveProjectEnumData(enumCopyContainer); |
| boxType->vw_initializeWithTake(pair.buffer, enumCopyContainer); |
| type->deallocateBoxForExistentialIn(&enumCopy.Buffer); |
| |
| 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() override { |
| 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() override { |
| return 'c'; |
| } |
| |
| bool hasSuperclassMirror() { |
| auto *Clas = static_cast<const ClassMetadata*>(type); |
| auto description = Clas->getDescription(); |
| |
| return ((description->SuperclassType) |
| && (Clas->Superclass) |
| && (Clas->Superclass->isTypeMetadata())); |
| } |
| |
| ClassImpl superclassMirror() { |
| auto *Clas = static_cast<const ClassMetadata*>(type); |
| auto description = Clas->getDescription(); |
| |
| if (description->SuperclassType) { |
| if (auto theSuperclass = Clas->Superclass) { |
| auto impl = ClassImpl(); |
| impl.type = (Metadata *)theSuperclass; |
| impl.value = nullptr; |
| return impl; |
| } |
| } |
| swift::crash("No superclass mirror found"); |
| } |
| |
| intptr_t count() override { |
| if (!isReflectable()) |
| return 0; |
| |
| auto *Clas = static_cast<const ClassMetadata*>(type); |
| auto description = Clas->getDescription(); |
| auto count = description->NumFields; |
| |
| return count; |
| } |
| |
| intptr_t recursiveCount() override { |
| if (hasSuperclassMirror()) { |
| return superclassMirror().recursiveCount() + count(); |
| } |
| |
| return count(); |
| } |
| |
| intptr_t childOffset(intptr_t i) override { |
| auto *Clas = static_cast<const ClassMetadata*>(type); |
| auto description = Clas->getDescription(); |
| |
| if (i < 0 || (size_t)i > description->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( |
| reinterpret_cast<Class>(const_cast<ClassMetadata *>(Clas)), nullptr); |
| fieldOffset = ivar_getOffset(ivars[i]); |
| free(ivars); |
| #else |
| swift::crash("Object appears to be Objective-C, but no runtime."); |
| #endif |
| } |
| return (intptr_t)fieldOffset; |
| } |
| |
| intptr_t recursiveChildOffset(intptr_t i) override { |
| if (hasSuperclassMirror()) { |
| auto superMirror = superclassMirror(); |
| auto superclassFieldCount = superMirror.recursiveCount(); |
| |
| if (i < superclassFieldCount) { |
| return superMirror.recursiveChildOffset(i); |
| } else { |
| i -= superclassFieldCount; |
| } |
| } |
| |
| return childOffset(i); |
| } |
| |
| const FieldType childMetadata(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) override { |
| StringRef name; |
| FieldType fieldInfo; |
| std::tie(name, fieldInfo) = getFieldAt(type, i); |
| assert(!fieldInfo.isIndirect() && "class indirect properties not implemented"); |
| |
| *outName = name.data(); |
| *outFreeFunc = nullptr; |
| |
| return fieldInfo; |
| } |
| |
| const FieldType recursiveChildMetadata(intptr_t i, |
| const char **outName, |
| void (**outFreeFunc)(const char *)) override { |
| if (hasSuperclassMirror()) { |
| auto superMirror = superclassMirror(); |
| auto superclassFieldCount = superMirror.recursiveCount(); |
| |
| if (i < superclassFieldCount) { |
| return superMirror.recursiveChildMetadata(i, outName, outFreeFunc); |
| } else { |
| i -= superclassFieldCount; |
| } |
| } |
| |
| return childMetadata(i, outName, outFreeFunc); |
| } |
| |
| AnyReturn subscript(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) override { |
| auto fieldInfo = childMetadata(i, outName, outFreeFunc); |
| |
| auto *bytes = *reinterpret_cast<char * const *>(value); |
| auto fieldOffset = childOffset(i); |
| auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset); |
| |
| return copyFieldContents(fieldData, fieldInfo); |
| } |
| |
| #if SWIFT_OBJC_INTEROP |
| id quickLookObject() override { |
| return _quickLookObjectForPointer(value); |
| } |
| #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; |
| } |
| |
| intptr_t childOffset(intptr_t i) { |
| swift::crash("Cannot get children of Objective-C objects."); |
| } |
| |
| const FieldType childMetadata(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) { |
| swift::crash("Cannot get children of Objective-C objects."); |
| } |
| |
| AnyReturn subscript(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) { |
| swift::crash("Cannot get children of Objective-C objects."); |
| } |
| |
| virtual intptr_t recursiveCount() { |
| return 0; |
| } |
| |
| virtual intptr_t recursiveChildOffset(intptr_t index) { |
| swift::crash("Cannot get children of Objective-C objects."); |
| } |
| virtual const FieldType recursiveChildMetadata(intptr_t index, |
| 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() override { |
| return '\0'; |
| } |
| |
| intptr_t count() override { |
| return 0; |
| } |
| |
| intptr_t childOffset(intptr_t i) override { |
| swift::crash("Metatypes have no children."); |
| } |
| |
| const FieldType childMetadata(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) override { |
| swift::crash("Metatypes have no children."); |
| } |
| |
| AnyReturn subscript(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) override { |
| swift::crash("Metatypes have no children."); |
| } |
| }; |
| |
| |
| // Implementation for opaque types. |
| struct OpaqueImpl : ReflectionMirrorImpl { |
| char displayStyle() override { |
| return '\0'; |
| } |
| |
| intptr_t count() override { |
| return 0; |
| } |
| |
| intptr_t childOffset(intptr_t i) override { |
| swift::crash("Opaque types have no children."); |
| } |
| |
| const FieldType childMetadata(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) override { |
| swift::crash("Opaque types have no children."); |
| } |
| |
| AnyReturn subscript(intptr_t i, const char **outName, |
| void (**outFreeFunc)(const char *)) override { |
| 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 AnyObject 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(); |
| } |
| } |
| SWIFT_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 _getMetadataKind(_ type: Any.Type) -> UInt |
| SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API |
| uintptr_t swift_getMetadataKind(const Metadata *type) { |
| return static_cast<uintptr_t>(type->getKind()); |
| } |
| |
| // 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(); |
| }); |
| } |
| |
| // func _getChildCount(_ type: Any.Type) -> Int |
| SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API |
| intptr_t swift_reflectionMirror_recursiveCount(const Metadata *type) { |
| return call(nullptr, type, type, [](ReflectionMirrorImpl *impl) { |
| return impl->recursiveCount(); |
| }); |
| } |
| |
| // func _getChildMetadata( |
| // type: Any.Type, |
| // index: Int, |
| // fieldMetadata: UnsafeMutablePointer<_FieldReflectionMetadata> |
| // ) -> Any.Type |
| SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API |
| const Metadata *swift_reflectionMirror_recursiveChildMetadata( |
| const Metadata *type, |
| intptr_t index, |
| _FieldReflectionMetadata* field) { |
| return call(nullptr, type, type, [&](ReflectionMirrorImpl *impl) { |
| FieldType fieldInfo = impl->recursiveChildMetadata(index, &field->name, |
| &field->freeFunc); |
| |
| field->isStrong = fieldInfo.getReferenceOwnership().isStrong(); |
| field->isVar = fieldInfo.isVar(); |
| return fieldInfo.getType(); |
| }); |
| } |
| |
| // internal func _getChildOffset( |
| // type: Any.Type, |
| // index: Int |
| // ) -> Int |
| SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API |
| intptr_t swift_reflectionMirror_recursiveChildOffset( |
| const Metadata *type, |
| intptr_t index) { |
| return call(nullptr, type, type, [&](ReflectionMirrorImpl *impl) { |
| return impl->recursiveChildOffset(index); |
| }); |
| } |
| |
| // 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 |