Mirror
- in
Swift
Found in the source codeMirror
Find 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_getNormalizedType
and_getChildCount
, one is to get the type, one is to get the attribute
_getNormalizedType
The call using the keyword@_silgen_name
, equivalent to callingswift_reflectionMirror_normalizedType
function
@_silgen_name("swift_reflectionMirror_normalizedType")
internal func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
Copy the code
@_silgen_name
@_silgen_name
The function below the keyword is actually called the keyword wrapped function, so let’s create a new onetest.c
File 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 the
main.swift
File to call it
var value = c_add(1, 2)
Copy the code
- use
@_silgen_name
Keyword, also can be called, we directly delete the bridge file andtest.h
All files can be called successfully and used@_silgen_name
After 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 found
swift_reflectionMirror_normalizedType
The 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
call
The implementation of the
unwrapExistential
You can see that the final data will be foundMetadataKind
Inside, so what we’re going to do isMetaData
Data 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
- in
Swift
Source searchTargetStructMetadata
The structure of the
TargetStructMetadata
Inherited 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
TargetValueMetadata
Inherited fromTargetMetadata
Description
- Through the analysis of the structure metaclass above, it has only one
Kind
There’s another oneTargetSignedPointer<Runtime, const TargetValueTypeDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;
The variable, let’s look at its structure TargetValueTypeDescriptor
Is 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
TargetTypeContextDescriptor
The structure of a class that contains a variableName
To inherit fromTargetContextDescriptor
TargetContextDescriptor
The structure of the
Name
Name
isTargetTypeContextDescriptor
Class 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
RelativeDirectPointer
The structure that it is inherited fromRelativeDirectPointerImpl
RelativeDirectPointerImpl
Implementation of, with one variableOffset RelativeOffset;
This class is obtained by address offsetValueTy
andPointerTy
- You can look at it
get()
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 structure
MetaData
To understand the underlying structure of the structure, through the above analysis can be obtained below the structureStructMetaData
Structure, 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
_getChildCount
Is also called using the keyword@_silgen_name
, and the final call isswift_reflectionMirror_count
, you can see that it is also calledcall
function
@_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
- in
call
You see in the function that the processing of the structure is aStructImpl
Format, also fromMetadata
To 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 above
TargetStructDescriptor
In 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
StructImpl
Contains 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