Swift-Mirror源码分析

2,257 阅读5分钟

Mirror

  • Swift源码中找到Mirror找到初始化方法
public init(reflecting subject: Any) {
    if case let customized as CustomReflectable = subject {
      self = customized.customMirror
    } else {
      self = Mirror(internalReflecting: subject)
    }
  }
  • Mirror(internalReflecting: subject)的实现,里面有两个关键方法_getNormalizedType_getChildCount,一个是获取类型,一个是获取属性
  • _getNormalizedType的调用使用了关键字@_silgen_name,相当于调用swift_reflectionMirror_normalizedType函数
@_silgen_name("swift_reflectionMirror_normalizedType")
internal func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type

@_silgen_name

  • @_silgen_name的作用就是调用关键字下面的函数时候实际上调用的是关键字包装的函数,我们新建一个test.c文件,实现一个方法并将它声明在.h文件中
int c_add(int a, int b) {
    return a + b;
}
  • 将头文件加入到桥接文件中,在main.swift文件中调用它
var value = c_add(1, 2)
  • 使用@_silgen_name关键字,也是可以调用的,我们直接删掉桥接文件和test.h文件都是可以调用成功的,使用了@_silgen_name修饰之后,调用下面的方法会去全局搜索括号里面的方法,需要注意的是要保证方法的实现,参数对应
@_silgen_name("c_add")
func swift_add(_ a:Int32,_ b:Int32) -> Int32

var value = swift_add(2, 4)
print(value)
  • 接着上文的分析找到swift_reflectionMirror_normalizedType的实现
/ 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; });
}
  • call的实现
  • unwrapExistential的实现,可以看到最终获取数据都会找到MetadataKind里面,所以我们接下来对MetaData数据进行研究,因为类的的结构会比较复杂,我们来研究结构体
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);
}

TargetStructMetadata

  • Swift源码中搜索TargetStructMetadata的结构
  • TargetStructMetadata继承自TargetValueMetadata
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;
  }
};

  • TargetValueMetadata继承自TargetMetadata

Description

  • 通过上面对结构体元类的分析,它除了有Kind之外还有一个 TargetSignedPointer<Runtime, const TargetValueTypeDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;变量,来看下它的结构
  • TargetValueTypeDescriptor是一个模板类,继承自TargetTypeContextDescriptor
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;
  }
};
  • TargetTypeContextDescriptor类的结构,里面有一个变量Name,继承自TargetContextDescriptor
  • TargetContextDescriptor的结构

Name

  • NameTargetTypeContextDescriptor类的变量TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false> Name; TargetRelativeDirectPointer的定义如下
template <typename Runtime, typename Pointee, bool Nullable = true>
using TargetRelativeDirectPointer
  = typename Runtime::template RelativeDirectPointer<Pointee, Nullable>;
  • RelativeDirectPointer的结构,它是继承自RelativeDirectPointerImpl
  • RelativeDirectPointerImpl的实现,有一个变量Offset RelativeOffset;,这个类是通过地址偏移获取ValueTyPointerTy
  • 可以看看它的get()的实现,可以看到它是通过地址偏移获取对应的数据的
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. The offset is applied to the 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;
}
  • 我们可以通过自定义结构体MetaData的方式来理解结构体的底层构成,通过上面的分析可以得到下面的结构体StructMetaData的结构,并可以通过它获取到它的Name
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))

// 打印结果:XQTeacher

_getChildCount

  • _getChildCount的调用也是使用了关键字@_silgen_name,最终调用的是swift_reflectionMirror_count,可以看到它也是调用了call函数
@_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();
  });
}
  • call函数里面看到对结构体的处理是一个StructImpl格式的,也是从Metadata获取数据
// 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);
  }
};
  • 在上文对TargetStructDescriptor类的研究中,还有一些成员属性没有列举出来,我们将它补全如
  /// 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;
......                              
}
  • StructImpl中有一个获取属性名及值的函数subscript,通过函数``
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();
  }
};
  • 最终完善的结构体
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: FieldRecord //连续的存储空间
}

struct FieldRecord {
    var Flags: 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()))