mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
These functions don't accept local variable heap memory, although the names make it sound like they work on anything. When you try, they mistakenly identify such things as ObjC objects, call through to the equivalent objc_* function, and crash confusingly. This adds Object to the name of each one to make it more clear what they accept. rdar://problem/37285743
757 lines
22 KiB
Plaintext
757 lines
22 KiB
Plaintext
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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/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);
|
|
}
|
|
};
|
|
|
|
|
|
// Implementation for structs.
|
|
struct StructImpl : ReflectionMirrorImpl {
|
|
bool isReflectable() {
|
|
const auto *Struct = static_cast<const StructMetadata *>(type);
|
|
const auto &Description = Struct->getDescription();
|
|
return Description->getTypeContextDescriptorFlags().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;
|
|
|
|
_swift_getFieldAt(type, i, [&](llvm::StringRef name, FieldType fieldInfo) {
|
|
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->getTypeContextDescriptorFlags().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);
|
|
|
|
const Metadata *payloadType = nullptr;
|
|
bool indirect = false;
|
|
|
|
const char *caseName = nullptr;
|
|
_swift_getFieldAt(type, tag, [&](llvm::StringRef name, FieldType info) {
|
|
caseName = name.data();
|
|
payloadType = info.getType();
|
|
indirect = info.isIndirect();
|
|
});
|
|
|
|
if (tagPtr)
|
|
*tagPtr = tag;
|
|
if (payloadTypePtr)
|
|
*payloadTypePtr = payloadType;
|
|
if (indirectPtr)
|
|
*indirectPtr = indirect;
|
|
|
|
return caseName;
|
|
}
|
|
|
|
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->getTypeContextDescriptorFlags().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;
|
|
|
|
_swift_getFieldAt(type, i, [&](llvm::StringRef name, FieldType fieldInfo) {
|
|
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
|