Mirror

  • inSwiftFound in the source codeMirrorFind the initialization method
public init(reflecting subject: Any) {
    if case let customized as CustomReflectable = subject {
      self = customized.customMirror
    } else {
      self = Mirror(internalReflecting: subject)
    }
  }
Copy the code
  • Mirror(internalReflecting: subject)There are two key methods in the implementation of_getNormalizedTypeand_getChildCount, one is to get the type, one is to get the attribute

  • _getNormalizedTypeThe call using the keyword@_silgen_name, equivalent to callingswift_reflectionMirror_normalizedTypefunction
@_silgen_name("swift_reflectionMirror_normalizedType")
internal func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
Copy the code

@_silgen_name

  • @_silgen_nameThe function below the keyword is actually called the keyword wrapped function, so let’s create a new onetest.cFile that implements a method and declares it in a.h file
int c_add(int a, int b) {
    return a + b;
}
Copy the code
  • Adds the header file to the bridge file in themain.swiftFile to call it
var value = c_add(1, 2)
Copy the code
  • use@_silgen_nameKeyword, also can be called, we directly delete the bridge file andtest.hAll files can be called successfully and used@_silgen_nameAfter the modifier, calling the following method will search globally for the methods inside the parentheses, taking care to ensure that the method is implemented with the corresponding arguments
@_silgen_name("c_add")
func swift_add(_ a:Int32,_ b:Int32) -> Int32

var value = swift_add(2, 4)
print(value)
Copy the code
  • Then the above analysis foundswift_reflectionMirror_normalizedTypeThe implementation of the
/ 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; });
}
Copy the code
  • callThe implementation of the

  • unwrapExistentialYou can see that the final data will be foundMetadataKindInside, so what we’re going to do isMetaDataData to study, because the structure of the class will be more complex, let’s study the structure
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); }Copy the code

TargetStructMetadata

  • inSwiftSource searchTargetStructMetadataThe structure of the

  • TargetStructMetadataInherited fromTargetValueMetadata
template <typename Runtime> struct TargetValueMetadata : public TargetMetadata<Runtime> { using StoredPointer = typename Runtime::StoredPointer; TargetValueMetadata(MetadataKind Kind, const TargetTypeContextDescriptor<Runtime> *description) : TargetMetadata<Runtime>(Kind), Description(description) {} /// An out-of-line description of the type. TargetSignedPointer<Runtime, const TargetValueTypeDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description; static bool classof(const TargetMetadata<Runtime> *metadata) { return metadata->getKind() == MetadataKind::Struct || metadata->getKind() == MetadataKind::Enum || metadata->getKind() == MetadataKind::Optional; } ConstTargetMetadataPointer<Runtime, TargetValueTypeDescriptor> getDescription() const { return Description; } typename Runtime::StoredSignedPointer getDescriptionAsSignedPointer() const { return Description; }};Copy the code
  • TargetValueMetadataInherited fromTargetMetadata

Description

  • Through the analysis of the structure metaclass above, it has only oneKindThere’s another one TargetSignedPointer<Runtime, const TargetValueTypeDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;The variable, let’s look at its structure
  • TargetValueTypeDescriptorIs a template class that inherits fromTargetTypeContextDescriptor
template <typename Runtime> class TargetValueTypeDescriptor : public TargetTypeContextDescriptor<Runtime> { public: static bool classof(const TargetContextDescriptor<Runtime> *cd) { return cd->getKind() == ContextDescriptorKind::Struct || cd->getKind() == ContextDescriptorKind::Enum; }};Copy the code
  • TargetTypeContextDescriptorThe structure of a class that contains a variableNameTo inherit fromTargetContextDescriptor

  • TargetContextDescriptorThe structure of the

Name

  • NameisTargetTypeContextDescriptorClass variables ` TargetRelativeDirectPointer < Runtime, const char, /nullable/ false> Name;

, TargetRelativeDirectPointer ` are defined as follows

template <typename Runtime, typename Pointee, bool Nullable = true>
using TargetRelativeDirectPointer
  = typename Runtime::template RelativeDirectPointer<Pointee, Nullable>;
Copy the code
  • RelativeDirectPointerThe structure that it is inherited fromRelativeDirectPointerImpl

  • RelativeDirectPointerImplImplementation of, with one variableOffset RelativeOffset;This class is obtained by address offsetValueTyandPointerTy

  • You can look at itget()It can be seen that it is through address offset to obtain the corresponding data
get() PointerTy get() const & { // Check for null. if (Nullable && RelativeOffset == 0) return nullptr; // The value is addressed relative to `this`. uintptr_t absolute = detail::applyRelativeOffset(this, RelativeOffset); return reinterpret_cast<PointerTy>(absolute); } 👇 namespace detail {/// Apply a relative offset to a base pointer using sign-extended, wrapping arithmetic. template<typename BasePtrTy, typename Offset> static inline uintptr_t applyRelativeOffset(BasePtrTy *basePtr, Offset offset) { static_assert(std::is_integral<Offset>::value && std::is_signed<Offset>::value, "offset type should be signed integer"); auto base = reinterpret_cast<uintptr_t>(basePtr); // We want to do wrapping arithmetic, but with a sign-extended // offset. To do this in C, we need to do signed promotion to get // the sign extension, but we need to perform arithmetic on unsigned values, // since signed overflow is undefined behavior. auto extendOffset = (uintptr_t)(intptr_t)offset; return base + extendOffset; }Copy the code
  • We can do this by customizing the structureMetaDataTo understand the underlying structure of the structure, through the above analysis can be obtained below the structureStructMetaDataStructure, and can be accessed through itName
struct StructMetaData { var Kind : Int var Description : UnsafeMutablePointer<StructDescriptor> } struct StructDescriptor { var Flags : Int32 var Parent : Int32 var name : RelativeDirectPointer<CChar> // var AccessFunctionPtr : UnsafeMutablePointer<Any> // var Fields : UnsafeMutablePointer<Any> } struct RelativeDirectPointer<T> { var Offset : Int32 mutating func get() -> UnsafeMutablePointer<T> { let offset = self.Offset return withUnsafePointer(to: &self, { p in return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: T.self)) }) } } struct XQTeacher { var age = 18 var name = "xq" } var t = XQTeacher() var t1 = XQTeacher.self let ptr = unsafeBitCast(XQTeacher.self as Any.Type, to: UnsafeMutablePointer<StructMetaData>.self) let namePtr = ptr.pointee.Description.pointee.name.get() Print (String(cString: namePtr)) // print result: XQTeacherCopy the code

_getChildCount

  • _getChildCountIs also called using the keyword@_silgen_name, and the final call isswift_reflectionMirror_count, you can see that it is also calledcallfunction
@_silgen_name("swift_reflectionMirror_count")
internal func _getChildCount<T>(_: T, type: Any.Type) -> Int

// 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();
  });
}
Copy the code
  • incallYou see in the function that the processing of the structure is aStructImplFormat, also fromMetadataTo get the data
// Implementation for structs. struct StructImpl : ReflectionMirrorImpl { bool isReflectable() { const auto *Struct = static_cast<const StructMetadata *>(type); const auto &Description = Struct->getDescription(); return Description->isReflectable(); } char displayStyle() { return 's'; } intptr_t count() { if (! isReflectable()) { return 0; } auto *Struct = static_cast<const StructMetadata *>(type); return Struct->getDescription()->NumFields; } intptr_t childOffset(intptr_t i) { 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 *)) { 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 *)) { 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); }};Copy the code
  • In the aboveTargetStructDescriptorIn the study of class, there are still some member attributes that are not listed, so we complete them as
/// The number of stored properties in the struct. /// If there is a field offset vector, this is its length. uint32_t NumFields; /// The offset of the field offset vector for this struct's stored /// properties in its metadata, if any. 0 means there is no field offset /// vector. uint32_t FieldOffsetVectorOffset; ----------------------------- class TargetTypeContextDescriptor : public TargetContextDescriptor<Runtime> { public: /// The name of the type. TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false> Name; /// A pointer to the metadata access function for this type. /// /// The function type here is a stand-in. You should use getAccessFunction() /// to wrap the function pointer in an accessor that uses the proper calling /// convention for a given number of arguments. TargetRelativeDirectPointer<Runtime, MetadataResponse(...) , /*Nullable*/ true> AccessFunctionPtr; /// A pointer to the field descriptor for the type, if any. TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor, /*nullable*/ true> Fields; . }Copy the code
  • StructImplContains a function that gets the name and value of an attributesubscript, via the function ‘ ‘

class FieldRecord { const FieldRecordFlags Flags; public: const RelativeDirectPointer<const char> MangledTypeName; const RelativeDirectPointer<const char> FieldName; FieldRecord() = delete; bool hasMangledTypeName() const { return MangledTypeName; } StringRef getMangledTypeName() const { return Demangle::makeSymbolicMangledNameStringRef(MangledTypeName.get()); } StringRef getFieldName() const { return FieldName.get(); } bool isIndirectCase() const { return Flags.isIndirectCase(); }};Copy the code
  • The final complete structure
struct StructMetaData { var Kind : Int var Description : UnsafeMutablePointer<StructDescriptor> } struct StructDescriptor { var Flags : Int32 var Parent : Int32 var name : RelativeDirectPointer<CChar> var AccessFunctionPtr : RelativeDirectPointer<UnsafeRawPointer> var Fields : RelativeDirectPointer<FieldDescriptor> var NumFields : Int32 var FieldOffsetVectorOffset : Int32 } struct FieldDescriptor { var MangledTypeName : RelativeDirectPointer<CChar> var Superclass : RelativeDirectPointer<CChar> var Kind : Int16 var FieldRecordSize : Int16 var NumFields : Int32 var fields: Struct FieldRecord {var Flags: Int32 var MangledTypeName: Int32 var MangledTypeName: RelativeDirectPointer<CChar> var FieldName: RelativeDirectPointer<CChar> } struct RelativeDirectPointer<T> { var Offset : Int32 mutating func get() -> UnsafeMutablePointer<T> { let offset = self.Offset return withUnsafePointer(to: &self, { p in return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: T.self)) }) } } struct XQTeacher { var age = 18 var name = "xq" } var t = XQTeacher() var t1 = XQTeacher.self let ptr = unsafeBitCast(XQTeacher.self as Any.Type, to: UnsafeMutablePointer<StructMetaData>.self) let namePtr = ptr.pointee.Description.pointee.name.get() print(String(cString: namePtr)) let fieldDescriptorPtr = ptr.pointee.Description.pointee.Fields.get() let recordPtr = withUnsafePointer(to: &fieldDescriptorPtr.pointee.fields, { return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to:FieldRecord.self).advanced(by: 0)) }) print(String(cString:recordPtr.pointee.FieldName.get()))Copy the code