blob: d8dc1e1292166d420772915b42b265ce5def3bf4 [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// 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