mirror of
https://github.com/apple/swift.git
synced 2025-12-25 12:15:36 +01:00
The general rule here is that something needs to be SWIFT_CC(swift) if it's just declared in Swift code using _silgen_name, as opposed to importing something via a header. Of course, SWIFT_CC(swift) expands to nothing by default for now, and I haven't made an effort yet to add the indirect-result / context parameter ABI attributes. This is just a best-effort first pass. I also took the opportunity to shift a few files to just implement their shims header and to demote a few things to be private stdlib interfaces.
1259 lines
42 KiB
Plaintext
1259 lines
42 KiB
Plaintext
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "swift/Basic/Fallthrough.h"
|
|
#include "swift/Runtime/Reflection.h"
|
|
#include "swift/Runtime/HeapObject.h"
|
|
#include "swift/Runtime/Metadata.h"
|
|
#include "swift/Runtime/Enum.h"
|
|
#include "swift/Basic/Demangle.h"
|
|
#include "swift/Runtime/Debug.h"
|
|
#include "swift/Runtime/Portability.h"
|
|
#include "Private.h"
|
|
#include <cassert>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <new>
|
|
#include <string>
|
|
#include <dlfcn.h>
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
#include "swift/Runtime/ObjCBridge.h"
|
|
#include <Foundation/Foundation.h>
|
|
#include <objc/objc.h>
|
|
#include <objc/runtime.h>
|
|
#endif
|
|
|
|
using namespace swift;
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
// Declare the debugQuickLookObject selector.
|
|
@interface DeclareSelectors
|
|
|
|
- (id)debugQuickLookObject;
|
|
@end
|
|
|
|
@class SwiftObject;
|
|
#endif
|
|
|
|
namespace {
|
|
|
|
/// The layout of protocol<>.
|
|
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() { }
|
|
};
|
|
|
|
/// A _Reflectable witness table.
|
|
struct _ReflectableWitnessTable {
|
|
/// func _getMirror() -> Mirror
|
|
Mirror (*getMirror)(OpaqueValue *self, const Metadata *Self);
|
|
};
|
|
|
|
struct MagicMirrorData;
|
|
|
|
struct String;
|
|
|
|
extern "C" void swift_stringFromUTF8InRawMemory(String *out,
|
|
const char *start,
|
|
intptr_t len);
|
|
|
|
struct String {
|
|
// Keep the details of String's implementation opaque to the runtime.
|
|
const void *x, *y, *z;
|
|
|
|
/// Keep String trivial on the C++ side so we can control its instantiation.
|
|
String() = default;
|
|
|
|
/// Wrap a string literal in a swift String.
|
|
template<size_t N>
|
|
explicit String(const char (&s)[N]) {
|
|
swift_stringFromUTF8InRawMemory(this, s, N-1);
|
|
}
|
|
|
|
/// Copy an ASCII string into a swift String on the heap.
|
|
explicit String(const char *ptr, size_t size) {
|
|
swift_stringFromUTF8InRawMemory(this, ptr, size);
|
|
}
|
|
|
|
explicit String(const char *ptr)
|
|
: String(ptr, strlen(ptr))
|
|
{}
|
|
|
|
/// Create a Swift String from two concatenated nul-terminated strings.
|
|
explicit String(const char *ptr1, const char *ptr2) {
|
|
size_t len1 = strlen(ptr1);
|
|
size_t len2 = strlen(ptr2);
|
|
char *concatenated = static_cast<char *>(malloc(len1 + len2));
|
|
memcpy(concatenated, ptr1, len1);
|
|
memcpy(concatenated + len1, ptr2, len2);
|
|
swift_stringFromUTF8InRawMemory(this, concatenated, len1 + len2);
|
|
free(concatenated);
|
|
}
|
|
#if SWIFT_OBJC_INTEROP
|
|
explicit String(NSString *s)
|
|
// FIXME: Use the usual NSString bridging entry point.
|
|
: String([s UTF8String])
|
|
{}
|
|
#endif
|
|
};
|
|
|
|
/// A Mirror witness table for use by MagicMirror.
|
|
struct MirrorWitnessTable;
|
|
|
|
/// The protocol descriptor for _Reflectable from the stdlib.
|
|
extern "C" const ProtocolDescriptor _TMps12_Reflectable;
|
|
|
|
// This structure needs to mirror _MagicMirrorData in the stdlib.
|
|
struct MagicMirrorData {
|
|
/// The owner pointer for the buffer the value lives in. For class values
|
|
/// this is the class instance itself. The mirror owns a strong reference to
|
|
/// this object.
|
|
HeapObject *Owner;
|
|
/// The pointer to the value. The mirror does not own the referenced value.
|
|
const OpaqueValue *Value;
|
|
/// The type metadata for the referenced value. For an ObjC witness, this is
|
|
/// the ObjC class.
|
|
const Metadata *Type;
|
|
};
|
|
static_assert(sizeof(MagicMirrorData) == sizeof(ValueBuffer),
|
|
"MagicMirrorData doesn't exactly fill a ValueBuffer");
|
|
|
|
/// A magic implementation of Mirror that can use runtime metadata to walk an
|
|
/// arbitrary object.
|
|
///
|
|
/// This type is layout-compatible with a Swift existential container for the
|
|
/// _Mirror protocol.
|
|
class MagicMirror {
|
|
public:
|
|
// The data for the mirror.
|
|
MagicMirrorData Data;
|
|
|
|
// The existential header.
|
|
const Metadata *Self;
|
|
const MirrorWitnessTable *MirrorWitness;
|
|
|
|
MagicMirror() = default;
|
|
|
|
/// Build a new MagicMirror for type T by taking ownership of the referenced
|
|
/// value.
|
|
MagicMirror(OpaqueValue *value, const Metadata *T, bool take);
|
|
|
|
/// Build a new MagicMirror for type T, sharing ownership with an existing
|
|
/// heap object, which is retained.
|
|
MagicMirror(HeapObject *owner, const OpaqueValue *value, const Metadata *T);
|
|
};
|
|
|
|
static_assert(alignof(MagicMirror) == alignof(Mirror),
|
|
"MagicMirror layout does not match existential container");
|
|
static_assert(sizeof(MagicMirror) == sizeof(Mirror),
|
|
"MagicMirror layout does not match existential container");
|
|
static_assert(offsetof(MagicMirror, Data) == offsetof(OpaqueExistentialContainer, Buffer),
|
|
"MagicMirror layout does not match existential container");
|
|
static_assert(offsetof(MagicMirror, Self) == offsetof(OpaqueExistentialContainer, Type),
|
|
"MagicMirror layout does not match existential container");
|
|
static_assert(offsetof(MagicMirror, MirrorWitness) ==
|
|
offsetof(Mirror, MirrorWitness),
|
|
"MagicMirror layout does not match existential container");
|
|
|
|
// -- Build an Any from an arbitrary value unowned-referenced by a mirror.
|
|
|
|
// We intentionally use a non-POD return type with these entry points to give
|
|
// them an indirect return ABI for compatibility with Swift.
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
|
|
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
AnyReturn swift_MagicMirrorData_value(HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
Any result;
|
|
|
|
result.Type = type;
|
|
type->vw_initializeBufferWithCopy(&result.Buffer,
|
|
const_cast<OpaqueValue*>(value));
|
|
|
|
return AnyReturn(result);
|
|
}
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
const Metadata *swift_MagicMirrorData_valueType(HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
return swift_getDynamicType(const_cast<OpaqueValue*>(value), type);
|
|
}
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
AnyReturn swift_MagicMirrorData_objcValue(HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
Any result;
|
|
|
|
void *object = *reinterpret_cast<void * const *>(value);
|
|
auto isa = _swift_getClass(object);
|
|
result.Type = swift_getObjCClassMetadata(isa);
|
|
swift_unknownRetain(object);
|
|
*reinterpret_cast<void **>(&result.Buffer) = object;
|
|
return AnyReturn(result);
|
|
}
|
|
#endif
|
|
|
|
#pragma clang diagnostic pop
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
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)";
|
|
}
|
|
}
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
void swift_MagicMirrorData_summary(const Metadata *T, String *result) {
|
|
switch (T->getKind()) {
|
|
case MetadataKind::Class:
|
|
new (result) String("(Class)");
|
|
break;
|
|
case MetadataKind::Struct:
|
|
new (result) String("(Struct)");
|
|
break;
|
|
case MetadataKind::Enum:
|
|
case MetadataKind::Optional:
|
|
new (result) String("(Enum Value)");
|
|
break;
|
|
case MetadataKind::Opaque:
|
|
new (result) String("(Opaque Value)");
|
|
break;
|
|
case MetadataKind::Tuple:
|
|
new (result) String("(Tuple)");
|
|
break;
|
|
case MetadataKind::Function:
|
|
new (result) String("(Function)");
|
|
break;
|
|
case MetadataKind::Existential:
|
|
new (result) String("(Existential)");
|
|
break;
|
|
case MetadataKind::Metatype:
|
|
new (result) String("(Metatype)");
|
|
break;
|
|
case MetadataKind::ObjCClassWrapper:
|
|
new (result) String("(Objective-C Class Wrapper)");
|
|
break;
|
|
case MetadataKind::ExistentialMetatype:
|
|
new (result) String("(ExistentialMetatype)");
|
|
break;
|
|
case MetadataKind::ForeignClass:
|
|
new (result) String("(Foreign Class)");
|
|
break;
|
|
case MetadataKind::HeapLocalVariable:
|
|
new (result) String("(Heap Local Variable)");
|
|
break;
|
|
case MetadataKind::HeapGenericLocalVariable:
|
|
new (result) String("(Heap Generic Local Variable)");
|
|
break;
|
|
case MetadataKind::ErrorObject:
|
|
new (result) String("(ErrorProtocol Object)");
|
|
break;
|
|
}
|
|
}
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
const Metadata *swift_MagicMirrorData_objcValueType(HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
void *object = *reinterpret_cast<void * const *>(value);
|
|
auto isa = _swift_getClass(object);
|
|
return swift_getObjCClassMetadata(isa);
|
|
}
|
|
|
|
static std::tuple<const _ReflectableWitnessTable *, const Metadata *,
|
|
const OpaqueValue *>
|
|
getReflectableConformance(const Metadata *T, const OpaqueValue *Value) {
|
|
recur:
|
|
// If the value is an existential container, look through it to reflect the
|
|
// contained value.
|
|
switch (T->getKind()) {
|
|
case MetadataKind::Tuple:
|
|
case MetadataKind::Struct:
|
|
case MetadataKind::ForeignClass:
|
|
case MetadataKind::ObjCClassWrapper:
|
|
case MetadataKind::Class:
|
|
case MetadataKind::Opaque:
|
|
case MetadataKind::Enum:
|
|
case MetadataKind::Optional:
|
|
case MetadataKind::Function:
|
|
case MetadataKind::Metatype:
|
|
break;
|
|
|
|
case MetadataKind::Existential: {
|
|
auto existential
|
|
= static_cast<const ExistentialTypeMetadata *>(T);
|
|
|
|
// If the existential happens to include the _Reflectable protocol, use
|
|
// the witness table from the container.
|
|
unsigned wtOffset = 0;
|
|
for (unsigned i = 0; i < existential->Protocols.NumProtocols; ++i) {
|
|
if (existential->Protocols[i] == &_TMps12_Reflectable) {
|
|
return std::make_tuple(
|
|
reinterpret_cast<const _ReflectableWitnessTable*>(
|
|
existential->getWitnessTable(Value, wtOffset)),
|
|
existential->getDynamicType(Value),
|
|
existential->projectValue(Value));
|
|
}
|
|
if (existential->Protocols[i]->Flags.needsWitnessTable())
|
|
++wtOffset;
|
|
}
|
|
|
|
// Otherwise, unwrap the existential container and do a runtime lookup on
|
|
// its contained value as usual.
|
|
T = existential->getDynamicType(Value);
|
|
Value = existential->projectValue(Value);
|
|
|
|
// Existential containers can end up nested in some cases due to generic
|
|
// abstraction barriers. Recur in case we have a nested existential.
|
|
goto recur;
|
|
}
|
|
case MetadataKind::ExistentialMetatype:
|
|
// 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.
|
|
break;
|
|
|
|
// Types can't have these kinds.
|
|
case MetadataKind::HeapLocalVariable:
|
|
case MetadataKind::HeapGenericLocalVariable:
|
|
case MetadataKind::ErrorObject:
|
|
swift::crash("Swift mirror lookup failure");
|
|
}
|
|
|
|
return std::make_tuple(
|
|
reinterpret_cast<const _ReflectableWitnessTable*>(
|
|
swift_conformsToProtocol(T, &_TMps12_Reflectable)),
|
|
T,
|
|
Value);
|
|
}
|
|
|
|
/// Produce a mirror for any value, like swift_reflectAny, but do not consume
|
|
/// the value, so we can produce a mirror for a subobject of a value already
|
|
/// owned by a mirror.
|
|
///
|
|
/// \param owner passed at +1, consumed.
|
|
/// \param value passed unowned.
|
|
static Mirror reflect(HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *T) {
|
|
const _ReflectableWitnessTable *witness;
|
|
const Metadata *mirrorType;
|
|
const OpaqueValue *mirrorValue;
|
|
std::tie(witness, mirrorType, mirrorValue)
|
|
= getReflectableConformance(T, value);
|
|
|
|
// Use the _Reflectable conformance if the object has one.
|
|
if (witness) {
|
|
auto result =
|
|
witness->getMirror(const_cast<OpaqueValue*>(mirrorValue), mirrorType);
|
|
swift_release(owner);
|
|
return MirrorReturn(result);
|
|
}
|
|
// Otherwise, fall back to MagicMirror.
|
|
// Consumes 'owner'.
|
|
Mirror result;
|
|
::new (&result) MagicMirror(owner, mirrorValue, mirrorType);
|
|
return result;
|
|
}
|
|
|
|
// -- Tuple destructuring.
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
intptr_t swift_TupleMirror_count(HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
auto Tuple = static_cast<const TupleTypeMetadata *>(type);
|
|
swift_release(owner);
|
|
return Tuple->NumElements;
|
|
}
|
|
|
|
/// \param owner passed at +1, consumed.
|
|
/// \param value passed unowned.
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
void swift_TupleMirror_subscript(String *outString,
|
|
Mirror *outMirror,
|
|
intptr_t i,
|
|
HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
auto Tuple = static_cast<const TupleTypeMetadata *>(type);
|
|
|
|
if (i < 0 || (size_t)i > Tuple->NumElements)
|
|
swift::crash("Swift mirror subscript bounds check failure");
|
|
|
|
// The name is the stringized element number '.0'.
|
|
char buf[32];
|
|
snprintf(buf, 31, ".%zd", i);
|
|
buf[31] = 0;
|
|
new (outString) String(buf, strlen(buf));
|
|
|
|
// Get a Mirror for the nth element.
|
|
auto &elt = Tuple->getElement(i);
|
|
auto bytes = reinterpret_cast<const char*>(value);
|
|
auto eltData = reinterpret_cast<const OpaqueValue *>(bytes + elt.Offset);
|
|
|
|
// 'owner' is consumed by this call.
|
|
new (outMirror) Mirror(reflect(owner, eltData, elt.Type));
|
|
}
|
|
|
|
// Get a field name from a doubly-null-terminated list.
|
|
static const char *getFieldName(const char *fieldNames, size_t i) {
|
|
const char *fieldName = fieldNames;
|
|
for (size_t j = 0; j < i; ++j) {
|
|
size_t len = strlen(fieldName);
|
|
assert(len != 0);
|
|
fieldName += len + 1;
|
|
}
|
|
|
|
return fieldName;
|
|
}
|
|
|
|
// -- Struct destructuring.
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
intptr_t swift_StructMirror_count(HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
auto Struct = static_cast<const StructMetadata *>(type);
|
|
swift_release(owner);
|
|
return Struct->Description->Struct.NumFields;
|
|
}
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
void swift_StructMirror_subscript(String *outString,
|
|
Mirror *outMirror,
|
|
intptr_t i,
|
|
HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
auto Struct = static_cast<const StructMetadata *>(type);
|
|
|
|
if (i < 0 || (size_t)i > Struct->Description->Struct.NumFields)
|
|
swift::crash("Swift mirror subscript bounds check failure");
|
|
|
|
// Load the type and offset from their respective vectors.
|
|
auto fieldType = Struct->getFieldTypes()[i];
|
|
auto fieldOffset = Struct->getFieldOffsets()[i];
|
|
|
|
auto bytes = reinterpret_cast<const char*>(value);
|
|
auto fieldData = reinterpret_cast<const OpaqueValue *>(bytes + fieldOffset);
|
|
|
|
new (outString) String(getFieldName(Struct->Description->Struct.FieldNames, i));
|
|
|
|
// 'owner' is consumed by this call.
|
|
assert(!fieldType.isIndirect() && "indirect struct fields not implemented");
|
|
new (outMirror) Mirror(reflect(owner, fieldData, fieldType.getType()));
|
|
}
|
|
|
|
// -- Enum destructuring.
|
|
|
|
static bool isEnumReflectable(const Metadata *type) {
|
|
const auto Enum = static_cast<const EnumMetadata *>(type);
|
|
const auto &Description = Enum->Description->Enum;
|
|
|
|
// No metadata for C and @objc enums yet
|
|
if (Description.CaseNames == nullptr)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static void getEnumMirrorInfo(const OpaqueValue *value,
|
|
const Metadata *type,
|
|
unsigned *tagPtr,
|
|
const Metadata **payloadTypePtr,
|
|
bool *indirectPtr) {
|
|
const auto Enum = static_cast<const EnumMetadata *>(type);
|
|
const auto &Description = Enum->Description->Enum;
|
|
|
|
unsigned payloadCases = Description.getNumPayloadCases();
|
|
|
|
// 'tag' is in the range [-ElementsWithPayload..ElementsWithNoPayload-1].
|
|
int tag = type->vw_getEnumTag(value);
|
|
|
|
// Convert resilient tag index to fragile tag index.
|
|
tag += payloadCases;
|
|
|
|
const Metadata *payloadType = nullptr;
|
|
bool indirect = false;
|
|
|
|
if (static_cast<unsigned>(tag) < payloadCases) {
|
|
auto payload = Description.GetCaseTypes(type)[tag];
|
|
payloadType = payload.getType();
|
|
indirect = payload.isIndirect();
|
|
}
|
|
|
|
if (tagPtr)
|
|
*tagPtr = tag;
|
|
if (payloadTypePtr)
|
|
*payloadTypePtr = payloadType;
|
|
if (indirectPtr)
|
|
*indirectPtr = indirect;
|
|
}
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
const char *swift_EnumMirror_caseName(HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
if (!isEnumReflectable(type)) {
|
|
swift_release(owner);
|
|
return nullptr;
|
|
}
|
|
|
|
const auto Enum = static_cast<const EnumMetadata *>(type);
|
|
const auto &Description = Enum->Description->Enum;
|
|
|
|
unsigned tag;
|
|
getEnumMirrorInfo(value, type, &tag, nullptr, nullptr);
|
|
|
|
swift_release(owner);
|
|
|
|
return getFieldName(Description.CaseNames, tag);
|
|
}
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
const char *swift_EnumCaseName(OpaqueValue *value, const Metadata *type) {
|
|
// Build a magic mirror. Unconditionally destroy the value at the end.
|
|
const _ReflectableWitnessTable *witness;
|
|
const Metadata *mirrorType;
|
|
const OpaqueValue *cMirrorValue;
|
|
std::tie(witness, mirrorType, cMirrorValue) = getReflectableConformance(type, value);
|
|
|
|
OpaqueValue *mirrorValue = const_cast<OpaqueValue*>(cMirrorValue);
|
|
Mirror mirror;
|
|
|
|
if (witness) {
|
|
mirror = witness->getMirror(mirrorValue, mirrorType);
|
|
} else {
|
|
bool take = mirrorValue == value;
|
|
::new (&mirror) MagicMirror(mirrorValue, mirrorType, take);
|
|
}
|
|
|
|
MagicMirror *theMirror = reinterpret_cast<MagicMirror *>(&mirror);
|
|
MagicMirrorData data = theMirror->Data;
|
|
const char *result = swift_EnumMirror_caseName(data.Owner, data.Value, data.Type);
|
|
return result;
|
|
}
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
intptr_t swift_EnumMirror_count(HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
if (!isEnumReflectable(type)) {
|
|
swift_release(owner);
|
|
return 0;
|
|
}
|
|
|
|
const Metadata *payloadType;
|
|
getEnumMirrorInfo(value, type, nullptr, &payloadType, nullptr);
|
|
swift_release(owner);
|
|
return (payloadType != nullptr) ? 1 : 0;
|
|
}
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
void swift_EnumMirror_subscript(String *outString,
|
|
Mirror *outMirror,
|
|
intptr_t i,
|
|
HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
const auto Enum = static_cast<const EnumMetadata *>(type);
|
|
const auto &Description = Enum->Description->Enum;
|
|
|
|
unsigned tag;
|
|
const Metadata *payloadType;
|
|
bool indirect;
|
|
|
|
getEnumMirrorInfo(value, type, &tag, &payloadType, &indirect);
|
|
|
|
// Copy the enum payload into a box
|
|
const Metadata *boxType = (indirect ? &_TMBo.base : payloadType);
|
|
BoxPair pair = swift_allocBox(boxType);
|
|
|
|
type->vw_destructiveProjectEnumData(const_cast<OpaqueValue *>(value));
|
|
boxType->vw_initializeWithCopy(pair.second, const_cast<OpaqueValue *>(value));
|
|
type->vw_destructiveInjectEnumTag(const_cast<OpaqueValue *>(value),
|
|
(int) (tag - Description.getNumPayloadCases()));
|
|
|
|
swift_release(owner);
|
|
|
|
owner = pair.first;
|
|
value = pair.second;
|
|
|
|
// If the payload is indirect, we need to jump through the box to get it.
|
|
if (indirect) {
|
|
owner = *reinterpret_cast<HeapObject * const *>(value);
|
|
value = swift_projectBox(const_cast<HeapObject *>(owner));
|
|
swift_retain(owner);
|
|
swift_release(pair.first);
|
|
}
|
|
|
|
new (outString) String(getFieldName(Description.CaseNames, tag));
|
|
new (outMirror) Mirror(reflect(owner, value, payloadType));
|
|
}
|
|
|
|
// -- Class destructuring.
|
|
static Mirror getMirrorForSuperclass(const ClassMetadata *sup,
|
|
HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type);
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
intptr_t swift_ClassMirror_count(HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
auto Clas = static_cast<const ClassMetadata*>(type);
|
|
swift_release(owner);
|
|
auto count = Clas->getDescription()->Class.NumFields;
|
|
|
|
// If the class has a superclass, the superclass instance is treated as the
|
|
// first child.
|
|
if (classHasSuperclass(Clas))
|
|
count += 1;
|
|
|
|
return count;
|
|
}
|
|
|
|
/// \param owner passed at +1, consumed.
|
|
/// \param value passed unowned.
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
void swift_ClassMirror_subscript(String *outString,
|
|
Mirror *outMirror,
|
|
intptr_t i,
|
|
HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
auto Clas = static_cast<const ClassMetadata*>(type);
|
|
|
|
if (classHasSuperclass(Clas)) {
|
|
// If the class has a superclass, the superclass instance is treated as the
|
|
// first child.
|
|
if (i == 0) {
|
|
// FIXME: Put superclass name here
|
|
new (outString) String("super");
|
|
new (outMirror) Mirror(
|
|
getMirrorForSuperclass(Clas->SuperClass, owner, value, type));
|
|
return;
|
|
}
|
|
--i;
|
|
}
|
|
|
|
if (i < 0 || (size_t)i > Clas->getDescription()->Class.NumFields)
|
|
swift::crash("Swift mirror subscript bounds check failure");
|
|
|
|
// Load the type and offset from their respective vectors.
|
|
auto fieldType = Clas->getFieldTypes()[i];
|
|
assert(!fieldType.isIndirect()
|
|
&& "class indirect properties not implemented");
|
|
|
|
// 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
|
|
}
|
|
|
|
auto bytes = *reinterpret_cast<const char * const*>(value);
|
|
auto fieldData = reinterpret_cast<const OpaqueValue *>(bytes + fieldOffset);
|
|
|
|
new (outString) String(getFieldName(Clas->getDescription()->Class.FieldNames, i));
|
|
// 'owner' is consumed by this call.
|
|
new (outMirror) Mirror(reflect(owner, fieldData, fieldType.getType()));
|
|
}
|
|
|
|
// -- Mirror witnesses for ObjC classes.
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
|
|
extern "C" const Metadata _TMSb; // Bool
|
|
extern "C" const Metadata _TMSi; // Int
|
|
extern "C" const Metadata _TMSu; // UInt
|
|
extern "C" const Metadata _TMSf; // Float
|
|
extern "C" const Metadata _TMSd; // Double
|
|
extern "C" const Metadata _TMVs4Int8;
|
|
extern "C" const Metadata _TMVs5Int16;
|
|
extern "C" const Metadata _TMVs5Int32;
|
|
extern "C" const Metadata _TMVs5Int64;
|
|
extern "C" const Metadata _TMVs5UInt8;
|
|
extern "C" const Metadata _TMVs6UInt16;
|
|
extern "C" const Metadata _TMVs6UInt32;
|
|
extern "C" const Metadata _TMVs6UInt64;
|
|
|
|
// Set to 1 to enable reflection of objc ivars.
|
|
#define REFLECT_OBJC_IVARS 0
|
|
|
|
/// Map an ObjC type encoding string to a Swift type metadata object.
|
|
///
|
|
#if REFLECT_OBJC_IVARS
|
|
static const Metadata *getMetadataForEncoding(const char *encoding) {
|
|
switch (*encoding) {
|
|
case 'c': // char
|
|
return &_TMVs4Int8;
|
|
case 's': // short
|
|
return &_TMVs5Int16;
|
|
case 'i': // int
|
|
return &_TMVs5Int32;
|
|
case 'l': // long
|
|
return &_TMSi;
|
|
case 'q': // long long
|
|
return &_TMVs5Int64;
|
|
|
|
case 'C': // unsigned char
|
|
return &_TMVs5UInt8;
|
|
case 'S': // unsigned short
|
|
return &_TMVs6UInt16;
|
|
case 'I': // unsigned int
|
|
return &_TMVs6UInt32;
|
|
case 'L': // unsigned long
|
|
return &_TMSu;
|
|
case 'Q': // unsigned long long
|
|
return &_TMVs6UInt64;
|
|
|
|
case 'B': // _Bool
|
|
return &_TMSb;
|
|
|
|
case '@': { // Class
|
|
// TODO: Better metadata?
|
|
const OpaqueMetadata *M = &_TMBO;
|
|
return &M->base;
|
|
}
|
|
|
|
default: // TODO
|
|
// Return 'void' as the type of fields we don't understand.
|
|
return &_TMT_;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/// \param owner passed at +1, consumed.
|
|
/// \param value passed unowned.
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
intptr_t swift_ObjCMirror_count(HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
auto isa = (Class)type;
|
|
|
|
unsigned count = 0;
|
|
#if REFLECT_OBJC_IVARS
|
|
// Don't reflect ivars of classes that lie about their layout.
|
|
if (objcClassLiesAboutLayout(isa)) {
|
|
count = 0;
|
|
} else {
|
|
// Copying the ivar list just to free it is lame, but we have
|
|
// nowhere to save it.
|
|
Ivar *ivars = class_copyIvarList(isa, &count);
|
|
free(ivars);
|
|
}
|
|
#else
|
|
// ObjC makes no guarantees about the state of ivars, so we can't safely
|
|
// introspect them in the general case.
|
|
|
|
// The superobject counts as a child.
|
|
if (_swift_getSuperclass((const ClassMetadata*) isa))
|
|
count += 1;
|
|
|
|
swift_release(owner);
|
|
return count;
|
|
#endif
|
|
}
|
|
|
|
static Mirror ObjC_getMirrorForSuperclass(Class sup,
|
|
HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type);
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C"
|
|
void swift_ObjCMirror_subscript(String *outString,
|
|
Mirror *outMirror,
|
|
intptr_t i,
|
|
HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
#if REFLECT_OBJC_IVARS
|
|
id object = *reinterpret_cast<const id *>(value);
|
|
#endif
|
|
auto isa = (Class)type;
|
|
|
|
// If there's a superclass, it becomes the first child.
|
|
if (auto sup = (Class) _swift_getSuperclass((const ClassMetadata*) isa)) {
|
|
if (i == 0) {
|
|
const char *supName = class_getName(sup);
|
|
new (outString) String(supName, strlen(supName));
|
|
new (outMirror) Mirror(
|
|
ObjC_getMirrorForSuperclass(sup, owner, value, type));
|
|
return;
|
|
}
|
|
--i;
|
|
}
|
|
|
|
#if REFLECT_OBJC_IVARS
|
|
// Copying the ivar list just to free it is lame, but we have
|
|
// no room to save it.
|
|
unsigned count;
|
|
Ivar *ivars;
|
|
// Don't reflect ivars of classes that lie about their layout.
|
|
if (objcClassLiesAboutLayout(isa)) {
|
|
count = 0;
|
|
ivars = nullptr;
|
|
} else {
|
|
// Copying the ivar list just to free it is lame, but we have
|
|
// nowhere to save it.
|
|
ivars = class_copyIvarList(isa, &count);
|
|
}
|
|
|
|
if (i < 0 || (uintptr_t)i >= (uintptr_t)count)
|
|
swift::crash("Swift mirror subscript bounds check failure");
|
|
|
|
const char *name = ivar_getName(ivars[i]);
|
|
ptrdiff_t offset = ivar_getOffset(ivars[i]);
|
|
const char *typeEncoding = ivar_getTypeEncoding(ivars[i]);
|
|
free(ivars);
|
|
|
|
const OpaqueValue *ivar =
|
|
reinterpret_cast<const OpaqueValue *>(
|
|
reinterpret_cast<const char*>(object) + offset);
|
|
|
|
const Metadata *ivarType = getMetadataForEncoding(typeEncoding);
|
|
|
|
new (outString) String(name, strlen(name));
|
|
// 'owner' is consumed by this call.
|
|
new (outMirror) Mirror(reflect(owner, ivar, ivarType));
|
|
#else
|
|
// ObjC makes no guarantees about the state of ivars, so we can't safely
|
|
// introspect them in the general case.
|
|
abort();
|
|
#endif
|
|
}
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C" id
|
|
swift_ClassMirror_quickLookObject(HeapObject *owner, const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
id object = [*reinterpret_cast<const id *>(value) retain];
|
|
swift_release(owner);
|
|
if ([object respondsToSelector:@selector(debugQuickLookObject)]) {
|
|
id quickLookObject = [object debugQuickLookObject];
|
|
[quickLookObject retain];
|
|
[object release];
|
|
return quickLookObject;
|
|
}
|
|
|
|
return object;
|
|
}
|
|
|
|
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
|
|
extern "C" bool swift_isKind(id object, NSString *className) {
|
|
bool result = [object isKindOfClass:NSClassFromString(className)];
|
|
[object release];
|
|
[className release];
|
|
|
|
return result;
|
|
}
|
|
|
|
#endif
|
|
|
|
// -- MagicMirror implementation.
|
|
|
|
#if !defined(__USER_LABEL_PREFIX__)
|
|
#error __USER_LABEL_PREFIX__ is undefined
|
|
#endif
|
|
|
|
// Workaround the bug of clang in Cygwin 64bit
|
|
// https://llvm.org/bugs/show_bug.cgi?id=26744
|
|
#if defined(__CYGWIN__) && defined(__x86_64__)
|
|
#undef __USER_LABEL_PREFIX__
|
|
#define __USER_LABEL_PREFIX__
|
|
#endif
|
|
|
|
#define GLUE_EXPANDED(a, b) a##b
|
|
#define GLUE(a, b) GLUE_EXPANDED(a, b)
|
|
#define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name)
|
|
|
|
#define QUOTE_EXPANDED(literal) #literal
|
|
#define QUOTE(literal) QUOTE_EXPANDED(literal)
|
|
|
|
#define QUOTED_SYMBOL_NAME(name) QUOTE(SYMBOL_NAME(name))
|
|
|
|
// Addresses of the type metadata and Mirror witness tables for the primitive
|
|
// mirrors.
|
|
extern "C" const Metadata OpaqueMirrorMetadata
|
|
__asm__(QUOTED_SYMBOL_NAME(_TMVs13_OpaqueMirror));
|
|
extern "C" const MirrorWitnessTable OpaqueMirrorWitnessTable
|
|
__asm__(QUOTED_SYMBOL_NAME(_TWPVs13_OpaqueMirrors7_Mirrors));
|
|
extern "C" const Metadata TupleMirrorMetadata
|
|
__asm__(QUOTED_SYMBOL_NAME(_TMVs12_TupleMirror));
|
|
extern "C" const MirrorWitnessTable TupleMirrorWitnessTable
|
|
__asm__(QUOTED_SYMBOL_NAME(_TWPVs12_TupleMirrors7_Mirrors));
|
|
|
|
extern "C" const Metadata StructMirrorMetadata
|
|
__asm__(QUOTED_SYMBOL_NAME(_TMVs13_StructMirror));
|
|
extern "C" const MirrorWitnessTable StructMirrorWitnessTable
|
|
__asm__(QUOTED_SYMBOL_NAME(_TWPVs13_StructMirrors7_Mirrors));
|
|
|
|
extern "C" const Metadata EnumMirrorMetadata
|
|
__asm__(QUOTED_SYMBOL_NAME(_TMVs11_EnumMirror));
|
|
extern "C" const MirrorWitnessTable EnumMirrorWitnessTable
|
|
__asm__(QUOTED_SYMBOL_NAME(_TWPVs11_EnumMirrors7_Mirrors));
|
|
|
|
extern "C" const Metadata ClassMirrorMetadata
|
|
__asm__(QUOTED_SYMBOL_NAME(_TMVs12_ClassMirror));
|
|
extern "C" const MirrorWitnessTable ClassMirrorWitnessTable
|
|
__asm__(QUOTED_SYMBOL_NAME(_TWPVs12_ClassMirrors7_Mirrors));
|
|
|
|
extern "C" const Metadata ClassSuperMirrorMetadata
|
|
__asm__(QUOTED_SYMBOL_NAME(_TMVs17_ClassSuperMirror));
|
|
extern "C" const MirrorWitnessTable ClassSuperMirrorWitnessTable
|
|
__asm__(QUOTED_SYMBOL_NAME(_TWPVs17_ClassSuperMirrors7_Mirrors));
|
|
|
|
extern "C" const Metadata MetatypeMirrorMetadata
|
|
__asm__(QUOTED_SYMBOL_NAME(_TMVs15_MetatypeMirror));
|
|
extern "C" const MirrorWitnessTable MetatypeMirrorWitnessTable
|
|
__asm__(QUOTED_SYMBOL_NAME(_TWPVs15_MetatypeMirrors7_Mirrors));
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
extern "C" const Metadata ObjCMirrorMetadata
|
|
__asm__(QUOTED_SYMBOL_NAME(_TMVs11_ObjCMirror));
|
|
extern "C" const MirrorWitnessTable ObjCMirrorWitnessTable
|
|
__asm__(QUOTED_SYMBOL_NAME(_TWPVs11_ObjCMirrors7_Mirrors));
|
|
extern "C" const Metadata ObjCSuperMirrorMetadata
|
|
__asm__(QUOTED_SYMBOL_NAME(_TMVs16_ObjCSuperMirror));
|
|
extern "C" const MirrorWitnessTable ObjCSuperMirrorWitnessTable
|
|
__asm__(QUOTED_SYMBOL_NAME(_TWPVs16_ObjCSuperMirrors7_Mirrors));
|
|
#endif
|
|
|
|
/// \param owner passed at +1, consumed.
|
|
/// \param value passed unowned.
|
|
static Mirror getMirrorForSuperclass(const ClassMetadata *sup,
|
|
HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
#if SWIFT_OBJC_INTEROP
|
|
// If the superclass is natively ObjC, cut over to the ObjC mirror
|
|
// implementation.
|
|
if (!sup->isTypeMetadata())
|
|
return ObjC_getMirrorForSuperclass((Class)sup, owner, value, type);
|
|
#endif
|
|
|
|
Mirror resultBuf;
|
|
MagicMirror *result = ::new (&resultBuf) MagicMirror;
|
|
|
|
result->Self = &ClassSuperMirrorMetadata;
|
|
result->MirrorWitness = &ClassSuperMirrorWitnessTable;
|
|
result->Data.Owner = owner;
|
|
result->Data.Type = sup;
|
|
result->Data.Value = value;
|
|
|
|
return resultBuf;
|
|
}
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
/// \param owner passed at +1, consumed.
|
|
/// \param value passed unowned.
|
|
static Mirror ObjC_getMirrorForSuperclass(Class sup,
|
|
HeapObject *owner,
|
|
const OpaqueValue *value,
|
|
const Metadata *type) {
|
|
Mirror resultBuf;
|
|
MagicMirror *result = ::new (&resultBuf) MagicMirror;
|
|
|
|
result->Self = &ObjCSuperMirrorMetadata;
|
|
result->MirrorWitness = &ObjCSuperMirrorWitnessTable;
|
|
result->Data.Owner = owner;
|
|
result->Data.Type = reinterpret_cast<ClassMetadata*>(sup);
|
|
result->Data.Value = value;
|
|
return resultBuf;
|
|
}
|
|
#endif
|
|
|
|
// (type being mirrored, mirror type, mirror witness)
|
|
using MirrorTriple
|
|
= std::tuple<const Metadata *, const Metadata *, const MirrorWitnessTable *>;
|
|
|
|
static MirrorTriple
|
|
getImplementationForClass(const OpaqueValue *Value) {
|
|
// 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;
|
|
}
|
|
|
|
#if SWIFT_OBJC_INTEROP
|
|
// If this is a pure ObjC class, reflect it using ObjC's runtime facilities.
|
|
if (!isa->isTypeMetadata())
|
|
return {isa, &ObjCMirrorMetadata, &ObjCMirrorWitnessTable};
|
|
#endif
|
|
|
|
// Otherwise, use the native Swift facilities.
|
|
return std::make_tuple(
|
|
isa, &ClassMirrorMetadata, &ClassMirrorWitnessTable);
|
|
}
|
|
|
|
/// Get the magic mirror witnesses appropriate to a particular type.
|
|
static MirrorTriple
|
|
getImplementationForType(const Metadata *T, const OpaqueValue *Value) {
|
|
switch (T->getKind()) {
|
|
case MetadataKind::Tuple:
|
|
return std::make_tuple(
|
|
T, &TupleMirrorMetadata, &TupleMirrorWitnessTable);
|
|
|
|
case MetadataKind::Struct:
|
|
return std::make_tuple(
|
|
T, &StructMirrorMetadata, &StructMirrorWitnessTable);
|
|
|
|
case MetadataKind::Enum:
|
|
case MetadataKind::Optional:
|
|
return std::make_tuple(
|
|
T, &EnumMirrorMetadata, &EnumMirrorWitnessTable);
|
|
|
|
case MetadataKind::ObjCClassWrapper:
|
|
case MetadataKind::ForeignClass:
|
|
case MetadataKind::Class: {
|
|
return getImplementationForClass(Value);
|
|
}
|
|
|
|
case MetadataKind::Metatype:
|
|
case MetadataKind::ExistentialMetatype: {
|
|
return std::make_tuple(T, &MetatypeMirrorMetadata,
|
|
&MetatypeMirrorWitnessTable);
|
|
}
|
|
|
|
case MetadataKind::Opaque: {
|
|
#if SWIFT_OBJC_INTEROP
|
|
// If this is the Builtin.UnknownObject type, use the dynamic type of the
|
|
// object reference.
|
|
if (T == &_TMBO.base) {
|
|
return getImplementationForClass(Value);
|
|
}
|
|
#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 (T == &_TMBo.base) {
|
|
const HeapObject *obj
|
|
= *reinterpret_cast<const HeapObject * const*>(Value);
|
|
if (obj->metadata->getKind() == MetadataKind::Class)
|
|
return getImplementationForClass(Value);
|
|
}
|
|
SWIFT_FALLTHROUGH;
|
|
}
|
|
|
|
/// TODO: Implement specialized mirror witnesses for all kinds.
|
|
case MetadataKind::Function:
|
|
case MetadataKind::Existential:
|
|
return std::make_tuple(
|
|
T, &OpaqueMirrorMetadata, &OpaqueMirrorWitnessTable);
|
|
|
|
// Types can't have these kinds.
|
|
case MetadataKind::HeapLocalVariable:
|
|
case MetadataKind::HeapGenericLocalVariable:
|
|
case MetadataKind::ErrorObject:
|
|
swift::crash("Swift mirror lookup failure");
|
|
}
|
|
}
|
|
|
|
/// MagicMirror ownership-taking whole-value constructor.
|
|
///
|
|
/// \param owner passed at +1, consumed.
|
|
MagicMirror::MagicMirror(OpaqueValue *value, const Metadata *T,
|
|
bool take) {
|
|
// Put value types into a box so we can take stable interior pointers.
|
|
// TODO: Specialize behavior here. If the value is a swift-refcounted class
|
|
// we don't need to put it in a box to point into it.
|
|
BoxPair box = swift_allocBox(T);
|
|
|
|
if (take)
|
|
T->vw_initializeWithTake(box.second, value);
|
|
else
|
|
T->vw_initializeWithCopy(box.second, value);
|
|
std::tie(T, Self, MirrorWitness) = getImplementationForType(T, box.second);
|
|
|
|
Data = {box.first, box.second, T};
|
|
}
|
|
|
|
/// MagicMirror ownership-sharing subvalue constructor.
|
|
///
|
|
/// \param owner passed at +1, consumed.
|
|
MagicMirror::MagicMirror(HeapObject *owner,
|
|
const OpaqueValue *value, const Metadata *T) {
|
|
std::tie(T, Self, MirrorWitness) = getImplementationForType(T, value);
|
|
Data = {owner, value, T};
|
|
}
|
|
|
|
} // end anonymous namespace
|
|
|
|
/// func reflect<T>(x: T) -> Mirror
|
|
///
|
|
/// Produce a mirror for any value. If the value's type conforms to _Reflectable,
|
|
/// invoke its _getMirror() method; otherwise, fall back to an implementation
|
|
/// in the runtime that structurally reflects values of any type.
|
|
///
|
|
/// This function consumes 'value', following Swift's +1 convention for "in"
|
|
/// arguments.
|
|
MirrorReturn swift::swift_reflectAny(OpaqueValue *value, const Metadata *T) {
|
|
const _ReflectableWitnessTable *witness;
|
|
const Metadata *mirrorType;
|
|
const OpaqueValue *cMirrorValue;
|
|
std::tie(witness, mirrorType, cMirrorValue)
|
|
= getReflectableConformance(T, value);
|
|
|
|
OpaqueValue *mirrorValue = const_cast<OpaqueValue*>(cMirrorValue);
|
|
|
|
// Use the _Reflectable conformance if the object has one.
|
|
if (witness) {
|
|
auto result = witness->getMirror(mirrorValue, mirrorType);
|
|
// 'self' of witnesses is passed at +0, so we still need to consume the
|
|
// value.
|
|
T->vw_destroy(value);
|
|
return MirrorReturn(result);
|
|
}
|
|
|
|
// Otherwise, fall back to MagicMirror.
|
|
Mirror result;
|
|
// Take the value, unless we projected a subvalue from it. We don't want to
|
|
// deal with partial value deinitialization.
|
|
bool take = mirrorValue == value;
|
|
::new (&result) MagicMirror(mirrorValue, mirrorType, take);
|
|
// Destroy the whole original value if we couldn't take it.
|
|
if (!take)
|
|
T->vw_destroy(value);
|
|
return MirrorReturn(result);
|
|
}
|
|
|
|
// NB: This function is not used directly in the Swift codebase, but is
|
|
// exported for Xcode support and is used by the sanitizers. Please coordinate
|
|
// before changing.
|
|
//
|
|
/// Demangles a Swift symbol name.
|
|
///
|
|
/// \param mangledName is the symbol name that needs to be demangled.
|
|
/// \param mangledNameLength is the length of the string that should be
|
|
/// demangled.
|
|
/// \param outputBuffer is the user provided buffer where the demangled name
|
|
/// will be placed. If nullptr, a new buffer will be malloced. In that case,
|
|
/// the user of this API is responsible for freeing the returned buffer.
|
|
/// \param outputBufferSize is the size of the output buffer. If the demangled
|
|
/// name does not fit into the outputBuffer, the output will be truncated and
|
|
/// the size will be updated, indicating how large the buffer should be.
|
|
/// \param flags can be used to select the demangling style. TODO: We should
|
|
//// define what these will be.
|
|
/// \returns the demangled name. Returns nullptr if the input String is not a
|
|
/// Swift mangled name.
|
|
SWIFT_RUNTIME_EXPORT
|
|
extern "C" char *swift_demangle(const char *mangledName,
|
|
size_t mangledNameLength,
|
|
char *outputBuffer,
|
|
size_t *outputBufferSize,
|
|
uint32_t flags) {
|
|
if (flags != 0) {
|
|
swift::fatalError(0, "Only 'flags' value of '0' is currently supported.");
|
|
}
|
|
if (outputBuffer != nullptr && outputBufferSize == nullptr) {
|
|
swift::fatalError(0, "'outputBuffer' is passed but the size is 'nullptr'.");
|
|
}
|
|
|
|
// Check if we are dealing with Swift mangled name, otherwise, don't try
|
|
// to demangle and send indication to the user.
|
|
if (mangledName[0] != '_' || mangledName[1] != 'T') {
|
|
return nullptr;
|
|
}
|
|
|
|
// Demangle the name.
|
|
auto options = Demangle::DemangleOptions();
|
|
options.DisplayDebuggerGeneratedModule = false;
|
|
auto result =
|
|
Demangle::demangleSymbolAsString(mangledName,
|
|
mangledNameLength,
|
|
options);
|
|
|
|
// If the output buffer is not provided, malloc memory ourselves.
|
|
if (outputBuffer == nullptr || *outputBufferSize == 0) {
|
|
return strdup(result.c_str());
|
|
}
|
|
|
|
// Indicate a failure if the result does not fit and will be truncated
|
|
// and set the required outputBufferSize.
|
|
if (*outputBufferSize < result.length() + 1) {
|
|
*outputBufferSize = result.length() + 1;
|
|
}
|
|
|
|
// Copy into the provided buffer.
|
|
_swift_strlcpy(outputBuffer, result.c_str(), *outputBufferSize);
|
|
return outputBuffer;
|
|
}
|