Swift进阶-TargetClassMetadata和TargetStructMetadata数据结构源码分析

Swift进阶-类与结构体
Swift-函数派发
Swift进阶-属性
Swift进阶-指针
Swift进阶-内存管理
Swift进阶-TargetClassMetadata和TargetStructMetadata数据结构源码分析
Swift进阶-Mirror解析
Swift进阶-闭包
Swift进阶-协议
Swift进阶-泛型
Swift进阶-String源码解析
Swift进阶-Array源码解析

前言

首先我们从官方上下载Swift源码。然后我们从头开始分析,从哪儿?万物皆初始化函数开始,在类与结构体章节我就分析出:

Swift 对象内存分配: __allocating_init -> swift_allocObject -> _swift_allocObject_ -> swift_slowAlloc -> malloc

从而在源码中找到_swift_allocObject_就是我们对象初始化的入口函数:

_swift_allocObject_

点击进去找到创建HeapObject入口:

创建 HeapObject

HeapMetadata其实是TargetHeapMetadata取的别名:

HeapMetadata

TargetHeapMetadata声明了俩初始化函数,但它本身继承于TargetMetadata
TargetHeapMetadata的源码声明

/// The common structure of all metadata for heap-allocated types.  A
/// pointer to one of these can be retrieved by loading the 'isa'
/// field of any heap object, whether it was managed by Swift or by
/// Objective-C.  However, when loading from an Objective-C object,
/// this metadata may not have the heap-metadata header, and it may
/// not be the Swift type metadata for the object's dynamic type.
template <typename Runtime>
struct TargetHeapMetadata : TargetMetadata<Runtime> {
  using HeaderType = TargetHeapMetadataHeader<Runtime>;

  TargetHeapMetadata() = default;
  constexpr TargetHeapMetadata(MetadataKind kind)
    : TargetMetadata<Runtime>(kind) {}
  constexpr TargetHeapMetadata(TargetAnyClassMetadataObjCInterop<Runtime> *isa)
    : TargetMetadata<Runtime>(isa) {}
};
using HeapMetadata = TargetHeapMetadata<InProcess>;

TargetMetadata的源码声明

/// The common structure of all type metadata.
template <typename Runtime>
struct TargetMetadata {
  using StoredPointer = typename Runtime::StoredPointer;

  /// The basic header type.
  typedef TargetTypeMetadataHeader<Runtime> HeaderType;

  constexpr TargetMetadata()
    : Kind(static_cast<StoredPointer>(MetadataKind::Class)) {}
  constexpr TargetMetadata(MetadataKind Kind)
    : Kind(static_cast<StoredPointer>(Kind)) {}

#if SWIFT_OBJC_INTEROP
protected:
  constexpr TargetMetadata(TargetAnyClassMetadataObjCInterop<Runtime> *isa)
    : Kind(reinterpret_cast<StoredPointer>(isa)) {}
#endif

private:
  /// The kind. Only valid for non-class metadata; getKind() must be used to get
  /// the kind value.
  StoredPointer Kind;
public:
  /// Get the metadata kind.
  MetadataKind getKind() const {
    return getEnumeratedMetadataKind(Kind);
  }
  
  /// Set the metadata kind.
  void setKind(MetadataKind kind) {
    Kind = static_cast<StoredPointer>(kind);
  }

protected:
  const TargetAnyClassMetadata<Runtime> *getClassISA() const {
    return reinterpret_cast<const TargetAnyClassMetadata<Runtime> *>(Kind);
  }
  void setClassISA(const TargetAnyClassMetadata<Runtime> *isa) {
    Kind = reinterpret_cast<StoredPointer>(isa);
  }

public:
  /// Is this a class object--the metadata record for a Swift class (which also
  /// serves as the class object), or the class object for an ObjC class (which
  /// is not metadata)?
  bool isClassObject() const {
    return static_cast<MetadataKind>(getKind()) == MetadataKind::Class;
  }
  
  /// Does the given metadata kind represent metadata for some kind of class?
  static bool isAnyKindOfClass(MetadataKind k) {
    switch (k) {
    case MetadataKind::Class:
    case MetadataKind::ObjCClassWrapper:
    case MetadataKind::ForeignClass:
      return true;

    default:
      return false;
    }
  }
  
  /// Is this metadata for an existential type?
  bool isAnyExistentialType() const {
    switch (getKind()) {
    case MetadataKind::ExistentialMetatype:
    case MetadataKind::Existential:
      return true;

    default:
      return false;
    }
  }
  
  /// Is this either type metadata or a class object for any kind of class?
  bool isAnyClass() const {
    return isAnyKindOfClass(getKind());
  }

  const ValueWitnessTable *getValueWitnesses() const {
    return asFullMetadata(this)->ValueWitnesses;
  }

  const TypeLayout *getTypeLayout() const {
    return getValueWitnesses()->getTypeLayout();
  }

  void setValueWitnesses(const ValueWitnessTable *table) {
    asFullMetadata(this)->ValueWitnesses = table;
  }
  
  // Define forwarders for value witnesses. These invoke this metadata's value
  // witness table with itself as the 'self' parameter.
  #define WANT_ONLY_REQUIRED_VALUE_WITNESSES
  #define FUNCTION_VALUE_WITNESS(WITNESS, UPPER, RET_TYPE, PARAM_TYPES)    \
    template<typename...A>                                                 \
    _ResultOf<ValueWitnessTypes::WITNESS ## Unsigned>::type                            \
    vw_##WITNESS(A &&...args) const {                                      \
      return getValueWitnesses()->WITNESS(std::forward<A>(args)..., this); \
    }
  #define DATA_VALUE_WITNESS(LOWER, UPPER, TYPE)
  #include "swift/ABI/ValueWitness.def"

  unsigned vw_getEnumTag(const OpaqueValue *value) const {
    return getValueWitnesses()->_asEVWT()->getEnumTag(const_cast<OpaqueValue*>(value), this);
  }
  void vw_destructiveProjectEnumData(OpaqueValue *value) const {
    getValueWitnesses()->_asEVWT()->destructiveProjectEnumData(value, this);
  }
  void vw_destructiveInjectEnumTag(OpaqueValue *value, unsigned tag) const {
    getValueWitnesses()->_asEVWT()->destructiveInjectEnumTag(value, tag, this);
  }

  size_t vw_size() const {
    return getValueWitnesses()->getSize();
  }

  size_t vw_alignment() const {
    return getValueWitnesses()->getAlignment();
  }

  size_t vw_stride() const {
    return getValueWitnesses()->getStride();
  }

  unsigned vw_getNumExtraInhabitants() const {
    return getValueWitnesses()->getNumExtraInhabitants();
  }

  /// Allocate an out-of-line buffer if values of this type don't fit in the
  /// ValueBuffer.
  /// NOTE: This is not a box for copy-on-write existentials.
  OpaqueValue *allocateBufferIn(ValueBuffer *buffer) const;

  /// Get the address of the memory previously allocated in the ValueBuffer.
  /// NOTE: This is not a box for copy-on-write existentials.
  OpaqueValue *projectBufferFrom(ValueBuffer *buffer) const;

  /// Deallocate an out-of-line buffer stored in 'buffer' if values of this type
  /// are not stored inline in the ValueBuffer.
  void deallocateBufferIn(ValueBuffer *buffer) const;

  // Allocate an out-of-line buffer box (reference counted) if values of this
  // type don't fit in the ValueBuffer.
  // NOTE: This *is* a box for copy-on-write existentials.
  OpaqueValue *allocateBoxForExistentialIn(ValueBuffer *Buffer) const;

  // Deallocate an out-of-line buffer box if one is present.
  void deallocateBoxForExistentialIn(ValueBuffer *Buffer) const;

  /// Get the nominal type descriptor if this metadata describes a nominal type,
  /// or return null if it does not.
  ConstTargetMetadataPointer<Runtime, TargetTypeContextDescriptor>
  getTypeContextDescriptor() const {
    switch (getKind()) {
    case MetadataKind::Class: {
      if (Runtime::ObjCInterop) {
        const auto cls = static_cast<const TargetClassMetadata<
            Runtime, TargetAnyClassMetadataObjCInterop<Runtime>> *>(this);
        if (!cls->isTypeMetadata())
          return nullptr;
        if (cls->isArtificialSubclass())
          return nullptr;
        return cls->getDescription();
      } else {
        const auto cls = static_cast<const TargetClassMetadata<
            Runtime, TargetAnyClassMetadata<Runtime>> *>(this);
        if (!cls->isTypeMetadata())
          return nullptr;
        if (cls->isArtificialSubclass())
          return nullptr;
        return cls->getDescription();
      }
    }
    case MetadataKind::Struct:
    case MetadataKind::Enum:
    case MetadataKind::Optional:
      return static_cast<const TargetValueMetadata<Runtime> *>(this)
          ->Description;
    case MetadataKind::ForeignClass:
      return static_cast<const TargetForeignClassMetadata<Runtime> *>(this)
          ->Description;
    default:
      return nullptr;
    }
  }

  /// Get the class object for this type if it has one, or return null if the
  /// type is not a class (or not a class with a class object).
  const typename Runtime::template TargetClassMetadata<Runtime> *
  getClassObject() const;

  /// Retrieve the generic arguments of this type, if it has any.
  ConstTargetMetadataPointer<Runtime, swift::TargetMetadata> const *
  getGenericArgs() const {
    auto description = getTypeContextDescriptor();
    if (!description)
      return nullptr;

    auto generics = description->getGenericContext();
    if (!generics)
      return nullptr;

    auto asWords = reinterpret_cast<
      ConstTargetMetadataPointer<Runtime, swift::TargetMetadata> const *>(this);
    return asWords + description->getGenericArgumentOffset();
  }

  bool satisfiesClassConstraint() const;

  const TypeContextDescriptor *getDescription() const;

  bool isStaticallySpecializedGenericMetadata() const;

  bool isCanonicalStaticallySpecializedGenericMetadata() const;

#if SWIFT_OBJC_INTEROP
  /// Get the ObjC class object for this type if it has one, or return null if
  /// the type is not a class (or not a class with a class object).
  /// This is allowed for InProcess values only.
  template <typename R = Runtime>
  typename std::enable_if<std::is_same<R, InProcess>::value, Class>::type
  getObjCClassObject() const {
    return reinterpret_cast<Class>(
        const_cast<TargetClassMetadata<
            InProcess, TargetAnyClassMetadataObjCInterop<InProcess>> *>(
            getClassObject()));
  }
#endif

#ifndef NDEBUG
  LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
                            "Only meant for use in the debugger");
#endif

protected:
  friend struct TargetOpaqueMetadata<Runtime>;
  
  /// Metadata should not be publicly copied or moved.
  constexpr TargetMetadata(const TargetMetadata &) = default;
  TargetMetadata &operator=(const TargetMetadata &) = default;
  constexpr TargetMetadata(TargetMetadata &&) = default;
  TargetMetadata &operator=(TargetMetadata &&) = default;
};

TargetMatedata中只有一个属性Kind

来看一个重点函数getTypeContextDescriptor()

getTypeContextDescriptor()

可以看到这个函数的作用是根据Kind的不同类型,去获取描述器Description。所以可以分析出:
对于class来说它的MetadataTargetClassMetadata
对于struct、enum、optional来说它的MetadataTargetValueMetadata,但是它们都有自己类型的Metadata去继承于TargetValueMetadata

一、TargetClassMetadata

1、TargetClassMetadata源码分析

1.1 从源码分析出TargetClassMetadata的数据结构

ClassMetadata其实是TargetClassMetadata取的别名:

#if SWIFT_OBJC_INTEROP
// 如果是继承自NSObject,TargetClassMetadata的父类是TargetAnyClassMetadataObjCInterop
using ClassMetadata =
    TargetClassMetadata<InProcess,
                        TargetAnyClassMetadataObjCInterop<InProcess>>; TargetAnyClassMetadataObjCInterop
#else
// 如果是纯swift类,TargetClassMetadata的父类是TargetAnyClassMetadata
using ClassMetadata =
    TargetClassMetadata<InProcess, TargetAnyClassMetadata<InProcess>>; 
#endif

TargetClassMetadata的源码声明:

/// The structure of all class metadata.  This structure is embedded
/// directly within the class's heap metadata structure and therefore
/// cannot be extended without an ABI break.
///
/// Note that the layout of this type is compatible with the layout of
/// an Objective-C class.
///
/// If the Runtime supports Objective-C interoperability, this class inherits
/// from TargetAnyClassMetadataObjCInterop, otherwise it inherits from
/// TargetAnyClassMetadata.
template <typename Runtime, typename TargetAnyClassMetadataVariant>
struct TargetClassMetadata : public TargetAnyClassMetadataVariant {
  using StoredPointer = typename Runtime::StoredPointer;
  using StoredSize = typename Runtime::StoredSize;

  TargetClassMetadata() = default;
  constexpr TargetClassMetadata(const TargetAnyClassMetadataVariant &base,
                                ClassFlags flags,
                                ClassIVarDestroyer *ivarDestroyer,
                                StoredPointer size, StoredPointer addressPoint,
                                StoredPointer alignMask,
                                StoredPointer classSize,
                                StoredPointer classAddressPoint)
      : TargetAnyClassMetadataVariant(base), Flags(flags),
        InstanceAddressPoint(addressPoint), InstanceSize(size),
        InstanceAlignMask(alignMask), Reserved(0), ClassSize(classSize),
        ClassAddressPoint(classAddressPoint), Description(nullptr),
        IVarDestroyer(ivarDestroyer) {}

  // The remaining fields are valid only when isTypeMetadata().
  // The Objective-C runtime knows the offsets to some of these fields.
  // Be careful when accessing them.

  /// Swift-specific class flags.
  ClassFlags Flags;

  /// The address point of instances of this type.
  uint32_t InstanceAddressPoint;

  /// The required size of instances of this type.
  /// 'InstanceAddressPoint' bytes go before the address point;
  /// 'InstanceSize - InstanceAddressPoint' bytes go after it.
  uint32_t InstanceSize;

  /// The alignment mask of the address point of instances of this type.
  uint16_t InstanceAlignMask;

  /// Reserved for runtime use.
  uint16_t Reserved;

  /// The total size of the class object, including prefix and suffix
  /// extents.
  uint32_t ClassSize;

  /// The offset of the address point within the class object.
  uint32_t ClassAddressPoint;

  // Description is by far the most likely field for a client to try
  // to access directly, so we force access to go through accessors.
private:
  /// An out-of-line Swift-specific description of the type, or null
  /// if this is an artificial subclass.  We currently provide no
  /// supported mechanism for making a non-artificial subclass
  /// dynamically.
  TargetSignedPointer<Runtime, const TargetClassDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;

public:
  /// A function for destroying instance variables, used to clean up after an
  /// early return from a constructor. If null, no clean up will be performed
  /// and all ivars must be trivial.
  TargetSignedPointer<Runtime, ClassIVarDestroyer * __ptrauth_swift_heap_object_destructor> IVarDestroyer;

  // After this come the class members, laid out as follows:
  //   - class members for the superclass (recursively)
  //   - metadata reference for the parent, if applicable
  //   - generic parameters for this class
  //   - class variables (if we choose to support these)
  //   - "tabulated" virtual methods

  using TargetAnyClassMetadataVariant::isTypeMetadata;

  ConstTargetMetadataPointer<Runtime, TargetClassDescriptor>
  getDescription() const {
    assert(isTypeMetadata());
    return Description;
  }

  typename Runtime::StoredSignedPointer
  getDescriptionAsSignedPointer() const {
    assert(isTypeMetadata());
    return Description;
  }

  void setDescription(const TargetClassDescriptor<Runtime> *description) {
    Description = description;
  }

  // [NOTE: Dynamic-subclass-KVO]
  //
  // Using Objective-C runtime, KVO can modify object behavior without needing
  // to modify the object's code. This is done by dynamically creating an
  // artificial subclass of the the object's type.
  //
  // The isa pointer of the observed object is swapped out to point to
  // the artificial subclass, which has the following properties:
  // - Setters for observed keys are overridden to additionally post
  // notifications.
  // - The `-class` method is overridden to return the original class type
  // instead of the artificial subclass type.
  //
  // For more details, see:
  // https://www.mikeash.com/pyblog/friday-qa-2009-01-23.html

  /// Is this class an artificial subclass, such as one dynamically
  /// created for various dynamic purposes like KVO?
  /// See [NOTE: Dynamic-subclass-KVO]
  bool isArtificialSubclass() const {
    assert(isTypeMetadata());
    return Description == nullptr;
  }
  void setArtificialSubclass() {
    assert(isTypeMetadata());
    Description = nullptr;
  }

  ClassFlags getFlags() const {
    assert(isTypeMetadata());
    return Flags;
  }
  void setFlags(ClassFlags flags) {
    assert(isTypeMetadata());
    Flags = flags;
  }

  StoredSize getInstanceSize() const {
    assert(isTypeMetadata());
    return InstanceSize;
  }
  void setInstanceSize(StoredSize size) {
    assert(isTypeMetadata());
    InstanceSize = size;
  }

  StoredPointer getInstanceAddressPoint() const {
    assert(isTypeMetadata());
    return InstanceAddressPoint;
  }
  void setInstanceAddressPoint(StoredSize size) {
    assert(isTypeMetadata());
    InstanceAddressPoint = size;
  }

  StoredPointer getInstanceAlignMask() const {
    assert(isTypeMetadata());
    return InstanceAlignMask;
  }
  void setInstanceAlignMask(StoredSize mask) {
    assert(isTypeMetadata());
    InstanceAlignMask = mask;
  }

  StoredPointer getClassSize() const {
    assert(isTypeMetadata());
    return ClassSize;
  }
  void setClassSize(StoredSize size) {
    assert(isTypeMetadata());
    ClassSize = size;
  }

  StoredPointer getClassAddressPoint() const {
    assert(isTypeMetadata());
    return ClassAddressPoint;
  }
  void setClassAddressPoint(StoredSize offset) {
    assert(isTypeMetadata());
    ClassAddressPoint = offset;
  }

  uint16_t getRuntimeReservedData() const {
    assert(isTypeMetadata());
    return Reserved;
  }
  void setRuntimeReservedData(uint16_t data) {
    assert(isTypeMetadata());
    Reserved = data;
  }

  /// Get a pointer to the field offset vector, if present, or null.
  const StoredPointer *getFieldOffsets() const {
    assert(isTypeMetadata());
    auto offset = getDescription()->getFieldOffsetVectorOffset();
    if (offset == 0)
      return nullptr;
    auto asWords = reinterpret_cast<const void * const*>(this);
    return reinterpret_cast<const StoredPointer *>(asWords + offset);
  }

  uint32_t getSizeInWords() const {
    assert(isTypeMetadata());
    uint32_t size = getClassSize() - getClassAddressPoint();
    assert(size % sizeof(StoredPointer) == 0);
    return size / sizeof(StoredPointer);
  }

  /// Given that this class is serving as the superclass of a Swift class,
  /// return its bounds as metadata.
  ///
  /// Note that the ImmediateMembersOffset member will not be meaningful.
  TargetClassMetadataBounds<Runtime>
  getClassBoundsAsSwiftSuperclass() const {
    using Bounds = TargetClassMetadataBounds<Runtime>;

    auto rootBounds = Bounds::forSwiftRootClass();

    // If the class is not type metadata, just use the root-class bounds.
    if (!isTypeMetadata())
      return rootBounds;

    // Otherwise, pull out the bounds from the metadata.
    auto bounds = Bounds::forAddressPointAndSize(getClassAddressPoint(),
                                                 getClassSize());

    // Round the bounds up to the required dimensions.
    if (bounds.NegativeSizeInWords < rootBounds.NegativeSizeInWords)
      bounds.NegativeSizeInWords = rootBounds.NegativeSizeInWords;
    if (bounds.PositiveSizeInWords < rootBounds.PositiveSizeInWords)
      bounds.PositiveSizeInWords = rootBounds.PositiveSizeInWords;

    return bounds;
  }

#if SWIFT_OBJC_INTEROP
  /// Given a statically-emitted metadata template, this sets the correct
  /// "is Swift" bit for the current runtime. Depending on the deployment
  /// target a binary was compiled for, statically emitted metadata templates
  /// may have a different bit set from the one that this runtime canonically
  /// considers the "is Swift" bit.
  void setAsTypeMetadata() {
    // If the wrong "is Swift" bit is set, set the correct one.
    //
    // Note that the only time we should see the "new" bit set while
    // expecting the "old" one is when running a binary built for a
    // new OS on an old OS, which is not supported, however we do
    // have tests that exercise this scenario.
    auto otherSwiftBit = (3ULL - SWIFT_CLASS_IS_SWIFT_MASK);
    assert(otherSwiftBit == 1ULL || otherSwiftBit == 2ULL);

    if ((this->Data & 3) == otherSwiftBit) {
      this->Data ^= 3;
    }

    // Otherwise there should be nothing to do, since only the old "is
    // Swift" bit is used for backward-deployed runtimes.
    
    assert(isTypeMetadata());
  }
#endif

  bool isStaticallySpecializedGenericMetadata() const {
    auto *description = getDescription();
    if (!description->isGeneric())
      return false;

    return this->Flags & ClassFlags::IsStaticSpecialization;
  }

  bool isCanonicalStaticallySpecializedGenericMetadata() const {
    auto *description = getDescription();
    if (!description->isGeneric())
      return false;

    return this->Flags & ClassFlags::IsCanonicalStaticSpecialization;
  }

  static bool classof(const TargetMetadata<Runtime> *metadata) {
    return metadata->getKind() == MetadataKind::Class;
  }
};

TargetClassMetadata中的属性:
ClassFlags Flags; // swift特有的标志
uint32_t InstanceAddressPoint; // 实例独享内存首地址
uint32_t InstanceSize; // 实例对象内存大小
uint16_t InstanceAlignMask; // 实例对象内存对齐方式
uint16_t Reserved; // 运行时保留字段
uint32_t ClassSize; // 类的内存大小
uint32_t ClassAddressPoint; // 类的内存首地址
TargetClassDescriptor * Description; // 类的描述器
ClassIVarDestroyer * IVarDestroyer // 实例销毁器
其中TargetClassDescriptor记录着类的很多信息,包括类名、属性、函数表等等

来看看官方对于TargetClassMetadata的注释:

所有类元数据的结构。这个结构直接嵌入到类的堆元数据结构中,因此在没有ABI中断的情况下不能扩展。
注意,这种类型的布局与Objective-C类的布局是兼容的。
如果运行时支持Objective-C互操作性,这个类继承自TargetAnyClassMetadataObjCInterop,否则继承自TargetAnyClassMetadata。

而实际上TargetAnyClassMetadataObjCInterop的父类就是TargetAnyClassMetadata了!

TargetAnyClassMetadataObjCInterop

我们先不研究class在运行时支持Objective-C互操作性(即继承自NSObject),所以TargetClassMetadata继承自TargetAnyClassMetadata
TargetAnyClassMetadata的源码声明:

/// The portion of a class metadata object that is compatible with
/// all classes, even non-Swift ones.
template <typename Runtime>
struct TargetAnyClassMetadata : public TargetHeapMetadata<Runtime> {
  using StoredPointer = typename Runtime::StoredPointer;
  using StoredSize = typename Runtime::StoredSize;
  using TargetClassMetadata =
      typename Runtime::template TargetClassMetadata<Runtime>;

protected:
  constexpr TargetAnyClassMetadata(
      TargetAnyClassMetadataObjCInterop<Runtime> *isa,
      TargetClassMetadata *superclass)
      : TargetHeapMetadata<Runtime>(isa), Superclass(superclass) {}
public:
  constexpr TargetAnyClassMetadata(TargetClassMetadata *superclass)
      : TargetHeapMetadata<Runtime>(MetadataKind::Class),
        Superclass(superclass) {}

  // Note that ObjC classes do not have a metadata header.

  /// The metadata for the superclass.  This is null for the root class.
  TargetSignedPointer<Runtime, const TargetClassMetadata *
                                   __ptrauth_swift_objc_superclass>
      Superclass;

  /// Is this object a valid swift type metadata?  That is, can it be
  /// safely downcast to ClassMetadata?
  bool isTypeMetadata() const {
    return true;
  }
  /// A different perspective on the same bit.
  bool isPureObjC() const {
    return !isTypeMetadata();
  }
};

TargetAnyClassClassMetadata有4个属性Kind、Superclass、CacheData、Data

TargetClassMetadata的总结:
a.TargetClassMetadata继承链关系:
TargetClassMetadata --> TargetAnyClassMetadata --> TargetHeapMatadata -->TargetMetadata

b.TargetClassMetadata的数据结构:

// 类 Metadata
struct TargetClassMetadata {
    var kind: Int
    var superClass: Any.Type
    var cacheData: (Int, Int)
    var data: Int
    
    var classFlags: Int32 // swift特有的标志
    var instanceAddressPoint: UInt32 // 实例独享内存首地址
    var instanceSize: UInt32 // 实例对象内存大小
    var instanceAlignmentMask: UInt16 // 实例对象内存对齐方式
    var reserved: UInt16 // 运行时保留字段
    var classSize: UInt32 // 类的内存大小
    var classAddressPoint: UInt32 //类的内存首地址
    var typeDescriptor: UnsafeMutablePointer<TargetClassDescriptor> // 类型描述器
    var iVarDestroyer: UnsafeRawPointer // 实例销毁器
}

一幅图来描述 Person(name: "安老师", age: 18) 的内存结构:

class的实例的内存结构

1.2 分析出完善的TargetClassMetadata数据结构

在1.1章节的内容中就提到TargetClassDescriptor中就记录着类的许多信息,我们就从这里深入了解TargetClassMetadata的数据结构。

TargetClassDescriptor的源码分析:

template <typename Runtime>
class TargetClassDescriptor final
    : public TargetTypeContextDescriptor<Runtime>,
      public TrailingGenericContextObjects<TargetClassDescriptor<Runtime>,
                              TargetTypeGenericContextDescriptorHeader,
                              /*additional trailing objects:*/
                              TargetResilientSuperclass<Runtime>,
                              TargetForeignMetadataInitialization<Runtime>,
                              TargetSingletonMetadataInitialization<Runtime>,
                              TargetVTableDescriptorHeader<Runtime>,
                              TargetMethodDescriptor<Runtime>,
                              TargetOverrideTableHeader<Runtime>,
                              TargetMethodOverrideDescriptor<Runtime>,
                              TargetObjCResilientClassStubInfo<Runtime>,
                              TargetCanonicalSpecializedMetadatasListCount<Runtime>,
                              TargetCanonicalSpecializedMetadatasListEntry<Runtime>,
                              TargetCanonicalSpecializedMetadataAccessorsListEntry<Runtime>,
                              TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>> {
private:
  using TrailingGenericContextObjects =
    swift::TrailingGenericContextObjects<TargetClassDescriptor<Runtime>,
                                         TargetTypeGenericContextDescriptorHeader,
                                         TargetResilientSuperclass<Runtime>,
                                         TargetForeignMetadataInitialization<Runtime>,
                                         TargetSingletonMetadataInitialization<Runtime>,
                                         TargetVTableDescriptorHeader<Runtime>,
                                         TargetMethodDescriptor<Runtime>,
                                         TargetOverrideTableHeader<Runtime>,
                                         TargetMethodOverrideDescriptor<Runtime>,
                                         TargetObjCResilientClassStubInfo<Runtime>,
                                         TargetCanonicalSpecializedMetadatasListCount<Runtime>,
                                         TargetCanonicalSpecializedMetadatasListEntry<Runtime>,
                                         TargetCanonicalSpecializedMetadataAccessorsListEntry<Runtime>,
                                         TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>>;

  using TrailingObjects =
    typename TrailingGenericContextObjects::TrailingObjects;
  friend TrailingObjects;

public:
  using MethodDescriptor = TargetMethodDescriptor<Runtime>;
  using VTableDescriptorHeader = TargetVTableDescriptorHeader<Runtime>;
  using OverrideTableHeader = TargetOverrideTableHeader<Runtime>;
  using MethodOverrideDescriptor = TargetMethodOverrideDescriptor<Runtime>;
  using ResilientSuperclass = TargetResilientSuperclass<Runtime>;
  using ForeignMetadataInitialization =
    TargetForeignMetadataInitialization<Runtime>;
  using SingletonMetadataInitialization =
    TargetSingletonMetadataInitialization<Runtime>;
  using ObjCResilientClassStubInfo =
    TargetObjCResilientClassStubInfo<Runtime>;
  using Metadata =
    TargetRelativeDirectPointer<Runtime, TargetMetadata<Runtime>, /*Nullable*/ false>;
  using MetadataListCount =
    TargetCanonicalSpecializedMetadatasListCount<Runtime>;
  using MetadataListEntry = 
    TargetCanonicalSpecializedMetadatasListEntry<Runtime>;
  using MetadataAccessor = 
    TargetRelativeDirectPointer<Runtime, MetadataResponse(MetadataRequest), /*Nullable*/ false>;
  using MetadataAccessorListEntry =
      TargetCanonicalSpecializedMetadataAccessorsListEntry<Runtime>;
  using MetadataCachingOnceToken =
      TargetCanonicalSpecializedMetadatasCachingOnceToken<Runtime>;

  using StoredPointer = typename Runtime::StoredPointer;
  using StoredPointerDifference = typename Runtime::StoredPointerDifference;
  using StoredSize = typename Runtime::StoredSize;

  using TrailingGenericContextObjects::getGenericContext;
  using TrailingGenericContextObjects::getGenericContextHeader;
  using TrailingGenericContextObjects::getFullGenericContextHeader;
  using TrailingGenericContextObjects::getGenericParams;
  using TargetTypeContextDescriptor<Runtime>::getTypeContextDescriptorFlags;

  TypeReferenceKind getResilientSuperclassReferenceKind() const {
    return getTypeContextDescriptorFlags()
      .class_getResilientSuperclassReferenceKind();
  }

  /// The type of the superclass, expressed as a mangled type name that can
  /// refer to the generic arguments of the subclass type.
  TargetRelativeDirectPointer<Runtime, const char> SuperclassType;

  union {
    /// If this descriptor does not have a resilient superclass, this is the
    /// negative size of metadata objects of this class (in words).
    uint32_t MetadataNegativeSizeInWords;

    /// If this descriptor has a resilient superclass, this is a reference
    /// to a cache holding the metadata's extents.
    TargetRelativeDirectPointer<Runtime,
                                TargetStoredClassMetadataBounds<Runtime>>
      ResilientMetadataBounds;
  };

  union {
    /// If this descriptor does not have a resilient superclass, this is the
    /// positive size of metadata objects of this class (in words).
    uint32_t MetadataPositiveSizeInWords;

    /// Otherwise, these flags are used to do things like indicating
    /// the presence of an Objective-C resilient class stub.
    ExtraClassDescriptorFlags ExtraClassFlags;
  };

  /// The number of additional members added by this class to the class
  /// metadata.  This data is opaque by default to the runtime, other than
  /// as exposed in other members; it's really just
  /// NumImmediateMembers * sizeof(void*) bytes of data.
  ///
  /// Whether those bytes are added before or after the address point
  /// depends on areImmediateMembersNegative().
  uint32_t NumImmediateMembers; // ABI: could be uint16_t?

  StoredSize getImmediateMembersSize() const {
    return StoredSize(NumImmediateMembers) * sizeof(StoredPointer);
  }

  /// Are the immediate members of the class metadata allocated at negative
  /// offsets instead of positive?
  bool areImmediateMembersNegative() const {
    return getTypeContextDescriptorFlags().class_areImmediateMembersNegative();
  }

  /// The number of stored properties in the class, not including its
  /// superclasses. If there is a field offset vector, this is its length.
  uint32_t NumFields;

private:
  /// The offset of the field offset vector for this class's stored
  /// properties in its metadata, in words. 0 means there is no field offset
  /// vector.
  ///
  /// If this class has a resilient superclass, this offset is relative to
  /// the size of the resilient superclass metadata. Otherwise, it is
  /// absolute.
  uint32_t FieldOffsetVectorOffset;

  template<typename T>
  using OverloadToken =
    typename TrailingGenericContextObjects::template OverloadToken<T>;
  
  using TrailingGenericContextObjects::numTrailingObjects;

  size_t numTrailingObjects(OverloadToken<ResilientSuperclass>) const {
    return this->hasResilientSuperclass() ? 1 : 0;
  }

  size_t numTrailingObjects(OverloadToken<ForeignMetadataInitialization>) const{
    return this->hasForeignMetadataInitialization() ? 1 : 0;
  }

  size_t numTrailingObjects(OverloadToken<SingletonMetadataInitialization>) const{
    return this->hasSingletonMetadataInitialization() ? 1 : 0;
  }

  size_t numTrailingObjects(OverloadToken<VTableDescriptorHeader>) const {
    return hasVTable() ? 1 : 0;
  }

  size_t numTrailingObjects(OverloadToken<MethodDescriptor>) const {
    if (!hasVTable())
      return 0;

    return getVTableDescriptor()->VTableSize;
  }

  size_t numTrailingObjects(OverloadToken<OverrideTableHeader>) const {
    return hasOverrideTable() ? 1 : 0;
  }

  size_t numTrailingObjects(OverloadToken<MethodOverrideDescriptor>) const {
    if (!hasOverrideTable())
      return 0;

    return getOverrideTable()->NumEntries;
  }

  size_t numTrailingObjects(OverloadToken<ObjCResilientClassStubInfo>) const {
    return hasObjCResilientClassStub() ? 1 : 0;
  }

  size_t numTrailingObjects(OverloadToken<MetadataListCount>) const {
    return this->hasCanonicicalMetadataPrespecializations() ?
      1
      : 0;
  }

  size_t numTrailingObjects(OverloadToken<MetadataListEntry>) const {
    return this->hasCanonicicalMetadataPrespecializations() ?
      this->template getTrailingObjects<MetadataListCount>()->count
      : 0;
  }

  size_t numTrailingObjects(OverloadToken<MetadataAccessorListEntry>) const {
    return this->hasCanonicicalMetadataPrespecializations() ?
      this->template getTrailingObjects<MetadataListCount>()->count
      : 0;
  }

  size_t numTrailingObjects(OverloadToken<MetadataCachingOnceToken>) const {
    return this->hasCanonicicalMetadataPrespecializations() ? 1 : 0;
  }

public:
  const TargetRelativeDirectPointer<Runtime, const void, /*nullable*/true> &
  getResilientSuperclass() const {
    assert(this->hasResilientSuperclass());
    return this->template getTrailingObjects<ResilientSuperclass>()->Superclass;
  }

  const ForeignMetadataInitialization &getForeignMetadataInitialization() const{
    assert(this->hasForeignMetadataInitialization());
    return *this->template getTrailingObjects<ForeignMetadataInitialization>();
  }

  const SingletonMetadataInitialization &getSingletonMetadataInitialization() const{
    assert(this->hasSingletonMetadataInitialization());
    return *this->template getTrailingObjects<SingletonMetadataInitialization>();
  }

  /// True if metadata records for this type have a field offset vector for
  /// its stored properties.
  bool hasFieldOffsetVector() const { return FieldOffsetVectorOffset != 0; }

  unsigned getFieldOffsetVectorOffset() const {
    if (hasResilientSuperclass()) {
      auto bounds = getMetadataBounds();
      return (bounds.ImmediateMembersOffset / sizeof(StoredPointer)
              + FieldOffsetVectorOffset);
    }

    return FieldOffsetVectorOffset;
  }

  bool isActor() const {
    return this->getTypeContextDescriptorFlags().class_isActor();
  }

  bool isDefaultActor() const {
    return this->getTypeContextDescriptorFlags().class_isDefaultActor();
  }

  bool hasVTable() const {
    return this->getTypeContextDescriptorFlags().class_hasVTable();
  }

  bool hasOverrideTable() const {
    return this->getTypeContextDescriptorFlags().class_hasOverrideTable();
  }

  bool hasResilientSuperclass() const {
    return this->getTypeContextDescriptorFlags().class_hasResilientSuperclass();
  }
  
  const VTableDescriptorHeader *getVTableDescriptor() const {
    if (!hasVTable())
      return nullptr;
    return this->template getTrailingObjects<VTableDescriptorHeader>();
  }

  llvm::ArrayRef<MethodDescriptor> getMethodDescriptors() const {
    if (!hasVTable())
      return {};
    return {this->template getTrailingObjects<MethodDescriptor>(),
            numTrailingObjects(OverloadToken<MethodDescriptor>{})};
  }

  const OverrideTableHeader *getOverrideTable() const {
    if (!hasOverrideTable())
      return nullptr;
    return this->template getTrailingObjects<OverrideTableHeader>();
  }

  llvm::ArrayRef<MethodOverrideDescriptor> getMethodOverrideDescriptors() const {
    if (!hasOverrideTable())
      return {};
    return {this->template getTrailingObjects<MethodOverrideDescriptor>(),
            numTrailingObjects(OverloadToken<MethodOverrideDescriptor>{})};
  }

  /// Return the bounds of this class's metadata.
  TargetClassMetadataBounds<Runtime> getMetadataBounds() const {
    if (!hasResilientSuperclass())
      return getNonResilientMetadataBounds();

    // This lookup works by ADL and will intentionally fail for
    // non-InProcess instantiations.
    return getResilientMetadataBounds(this);
  }

  /// Given that this class is known to not have a resilient superclass
  /// return its metadata bounds.
  TargetClassMetadataBounds<Runtime> getNonResilientMetadataBounds() const {
    return { getNonResilientImmediateMembersOffset()
               * StoredPointerDifference(sizeof(void*)),
             MetadataNegativeSizeInWords,
             MetadataPositiveSizeInWords };
  }

  /// Return the offset of the start of generic arguments in the nominal
  /// type's metadata. The returned value is measured in words.
  int32_t getGenericArgumentOffset() const {
    if (!hasResilientSuperclass())
      return getNonResilientGenericArgumentOffset();

    // This lookup works by ADL and will intentionally fail for
    // non-InProcess instantiations.
    return getResilientImmediateMembersOffset(this);
  }

  /// Given that this class is known to not have a resilient superclass,
  /// return the offset of its generic arguments in words.
  int32_t getNonResilientGenericArgumentOffset() const {
    return getNonResilientImmediateMembersOffset();
  }

  /// Given that this class is known to not have a resilient superclass,
  /// return the offset of its immediate members in words.
  int32_t getNonResilientImmediateMembersOffset() const {
    assert(!hasResilientSuperclass());
    return areImmediateMembersNegative()
             ? -int32_t(MetadataNegativeSizeInWords)
             : int32_t(MetadataPositiveSizeInWords - NumImmediateMembers);
  }

  void *getMethod(unsigned i) const {
    assert(hasVTable()
           && i < numTrailingObjects(OverloadToken<MethodDescriptor>{}));
    return getMethodDescriptors()[i].Impl.get();
  }

  /// Whether this context descriptor references an Objective-C resilient
  /// class stub. See the above description of TargetObjCResilientClassStubInfo
  /// for details.
  bool hasObjCResilientClassStub() const {
    if (!hasResilientSuperclass())
      return false;
    return ExtraClassFlags.hasObjCResilientClassStub();
  }

  const void *getObjCResilientClassStub() const {
    if (!hasObjCResilientClassStub())
      return nullptr;

    return this->template getTrailingObjects<ObjCResilientClassStubInfo>()
      ->Stub.get();
  }

  llvm::ArrayRef<Metadata> getCanonicicalMetadataPrespecializations() const {
    if (!this->hasCanonicicalMetadataPrespecializations()) {
      return {};
    }

    auto *listCount = this->template getTrailingObjects<MetadataListCount>();
    auto *list = this->template getTrailingObjects<MetadataListEntry>();
    return llvm::ArrayRef<Metadata>(
        reinterpret_cast<const Metadata *>(list),
        listCount->count
        );
  }

  llvm::ArrayRef<MetadataAccessor> getCanonicalMetadataPrespecializationAccessors() const {
    if (!this->hasCanonicicalMetadataPrespecializations()) {
      return {};
    }

    auto *listCount = this->template getTrailingObjects<MetadataListCount>();
    auto *list = this->template getTrailingObjects<MetadataAccessorListEntry>();
    return llvm::ArrayRef<MetadataAccessor>(
        reinterpret_cast<const MetadataAccessor *>(list),
        listCount->count
        );
  }

  swift_once_t *getCanonicalMetadataPrespecializationCachingOnceToken() const {
    if (!this->hasCanonicicalMetadataPrespecializations()) {
      return nullptr;
    }
    auto box = this->template getTrailingObjects<MetadataCachingOnceToken>();
    return box->token.get();
  }

  static bool classof(const TargetContextDescriptor<Runtime> *cd) {
    return cd->getKind() == ContextDescriptorKind::Class;
  }
};

using ClassDescriptor = TargetClassDescriptor<InProcess>;

TargetClassDescriptor中的属性:
var superClassType: TargetRelativeDirectPointer<Runtime, const char>; // 父类类型
var metadataNegativeSizeInWords: UInt32;
var metadataPositiveSizeInWords: UInt32;
var numImmediateMembers: UInt32;
var numFields: UInt32;
var fieldOffsetVectorOffset: UInt32; // 每一个属性值距离当前实例对象地址的偏移量

注意:TargetRelativeDirectPointer<Runtime, const char>到底是什么?
它是一个相对地址信息,并且存储的是偏移量。(ps: swift中在数据结构存储数据都是通过偏移量去访问内存地址)

TargetRelativeDirectPointer的源码声明:

// TargetRelativeDirectPointer其实是RelativeDirectPointer的别名
template <typename Runtime, typename Pointee, bool Nullable = true>
using TargetRelativeDirectPointer
  = typename Runtime::template RelativeDirectPointer<Pointee, Nullable>;
/// A direct relative reference to an object that is not a function pointer.
template <typename T, bool Nullable, typename Offset>
class RelativeDirectPointer<T, Nullable, Offset,
    typename std::enable_if<!std::is_function<T>::value>::type>
    : private RelativeDirectPointerImpl<T, Nullable, Offset>
{
  using super = RelativeDirectPointerImpl<T, Nullable, Offset>;
public:
  using super::get;
  using super::super;
  
  RelativeDirectPointer &operator=(T *absolute) & {
    super::operator=(absolute);
    return *this;
  }

  operator typename super::PointerTy() const & {
    return this->get();
  }

  const typename super::ValueTy *operator->() const & {
    return this->get();
  }

  const typename super::ValueTy* getRelative(void *base) const & {
    return this->super::getRelative(base);
  }

  using super::isNull;
};

这个类的定义还是⽐较简洁的,其中 T 就是我们进来的类型, Offset 就是 int32_t 的类型,这⾥的源码我就不带着⼤家⼀点点分析了,在 Swift 中引⽤⼀个 Object 有两种情况

a.当前 Object 的引⽤是⼀个 absolute 指针,就像我们的对象⼀样:

object引用绝对指针

b.当前指针存储的是相对引⽤,相对引⽤指的是当前引⽤的内存地址到当前对象的内存地址的距离:

Object引用的指针存储的是相对引用

以上,我仿照这个思路把当前TargetRelativeDirectPointer数据结构还原出来:

// 相对地址信息 - 存储的是偏移量
struct TargetRelativeDirectPointer<Pointee> {
    var offset: Int32
    
    mutating func getmeasureRelativeOffset() -> UnsafeMutablePointer<Pointee>{
        let offset = self.offset
        
        return withUnsafePointer(to: &self) { p in
            /*
             获得self,变为raw,然后+offset
             - UnsafeRawPointer(p) 表示this
             - advanced(by: numericCast(offset) 表示移动的步长,即offset
             - assumingMemoryBound(to: T.self) 表示假定类型是T,即自己指定的类型
             - UnsafeMutablePointer(mutating:) 表示返回的指针类型
            */
           return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self))
        }
    }
}

再回头看TargetClassDescriptor是继承自TargetTypeContextDescriptor的。
TargetTypeContextDescriptor的源码声明:

template <typename Runtime>
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;
      
  bool isReflectable() const { return (bool)Fields; }

  MetadataAccessFunction getAccessFunction() const {
    return MetadataAccessFunction(AccessFunctionPtr.get());
  }

  TypeContextDescriptorFlags getTypeContextDescriptorFlags() const {
    return TypeContextDescriptorFlags(this->Flags.getKindSpecificFlags());
  }

  /// Return the kind of metadata initialization required by this type.
  /// Note that this is only meaningful for non-generic types.
  TypeContextDescriptorFlags::MetadataInitializationKind
  getMetadataInitialization() const {
    return getTypeContextDescriptorFlags().getMetadataInitialization();
  }

  /// Does this type have non-trivial "singleton" metadata initialization?
  ///
  /// The type of the initialization-control structure differs by subclass,
  /// so it doesn't appear here.
  bool hasSingletonMetadataInitialization() const {
    return getTypeContextDescriptorFlags().hasSingletonMetadataInitialization();
  }

  /// Does this type have "foreign" metadata initialiation?
  bool hasForeignMetadataInitialization() const {
    return getTypeContextDescriptorFlags().hasForeignMetadataInitialization();
  }

  bool hasCanonicicalMetadataPrespecializations() const {
    return getTypeContextDescriptorFlags().hasCanonicalMetadataPrespecializations();
  }

  /// Given that this type has foreign metadata initialization, return the
  /// control structure for it.
  const TargetForeignMetadataInitialization<Runtime> &
  getForeignMetadataInitialization() const;

  const TargetSingletonMetadataInitialization<Runtime> &
  getSingletonMetadataInitialization() const;

  const TargetTypeGenericContextDescriptorHeader<Runtime> &
  getFullGenericContextHeader() const;

  const TargetGenericContextDescriptorHeader<Runtime> &
  getGenericContextHeader() const {
    return getFullGenericContextHeader();
  }

  llvm::ArrayRef<GenericParamDescriptor> getGenericParams() const;

  /// Return the offset of the start of generic arguments in the nominal
  /// type's metadata. The returned value is measured in sizeof(StoredPointer).
  int32_t getGenericArgumentOffset() const;

  constexpr inline auto
  getNameOffset() const -> typename Runtime::StoredSize {
    return offsetof(typename std::remove_reference<decltype(*this)>::type, Name);
  }

  /// Return the start of the generic arguments array in the nominal
  /// type's metadata. The returned value is measured in sizeof(StoredPointer).
  const TargetMetadata<Runtime> * const *getGenericArguments(
                               const TargetMetadata<Runtime> *metadata) const {
    auto offset = getGenericArgumentOffset();
    auto words =
      reinterpret_cast<const TargetMetadata<Runtime> * const *>(metadata);
    return words + offset;
  }

  const llvm::ArrayRef<TargetRelativeDirectPointer<Runtime, TargetMetadata<Runtime>, /*Nullable*/ false>>
  getCanonicicalMetadataPrespecializations() const;

  swift_once_t *getCanonicalMetadataPrespecializationCachingOnceToken() const;

  static bool classof(const TargetContextDescriptor<Runtime> *cd) {
    return cd->getKind() >= ContextDescriptorKind::Type_First
        && cd->getKind() <= ContextDescriptorKind::Type_Last;
  }
};

TargetTypeContextDescriptor中的属性:
var name: TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false>; // class/struct/enum 的名称
var accessFunctionPointer: TargetRelativeDirectPointer<Runtime, MetadataResponse(...), /*Nullable*/ true>;
var fieldDescriptor: TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor, /*nullable*/ true>; // 属性描述器
这三个属性都是TargetRelativeDirectPointer类型的

TargetTypeContextDescriptor是继承自TargetContextDescriptor
TargetContextDescriptor的源码声明:

// Base class for all context descriptors.
template<typename Runtime>
struct TargetContextDescriptor {
  /// Flags describing the context, including its kind and format version.
  ContextDescriptorFlags Flags;
  
  /// The parent context, or null if this is a top-level context.
  TargetRelativeContextPointer<Runtime> Parent;

  bool isGeneric() const { return Flags.isGeneric(); }
  bool isUnique() const { return Flags.isUnique(); }
  ContextDescriptorKind getKind() const { return Flags.getKind(); }

  /// Get the generic context information for this context, or null if the
  /// context is not generic.
  const TargetGenericContext<Runtime> *getGenericContext() const;

  /// Get the module context for this context.
  const TargetModuleContextDescriptor<Runtime> *getModuleContext() const;

  /// Is this context part of a C-imported module?
  bool isCImportedContext() const;

  unsigned getNumGenericParams() const {
    auto *genericContext = getGenericContext();
    return genericContext
              ? genericContext->getGenericContextHeader().NumParams
              : 0;
  }

  constexpr inline auto
  getParentOffset() const -> typename Runtime::StoredSize {
    return offsetof(typename std::remove_reference<decltype(*this)>::type, Parent);
  }

#ifndef NDEBUG
  LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
                            "only for use in the debugger");
#endif

private:
  TargetContextDescriptor(const TargetContextDescriptor &) = delete;
  TargetContextDescriptor(TargetContextDescriptor &&) = delete;
  TargetContextDescriptor &operator=(const TargetContextDescriptor &) = delete;
  TargetContextDescriptor &operator=(TargetContextDescriptor &&) = delete;
};

TargetContextDescriptor中的属性:
var flags: UInt32
var parent: TargetRelativeContextPointer<Runtime>

TargetClassDescriptor的总结:
a.TargetClassDescriptor继承链关系:
TargetClassDescriptor -->TargetTypeContextDescriptor --> TargetContextDescriptor

b.TargetClassDescriptor的数据结构:

// 类描述器
struct TargetClassDescriptor{
    var flags: UInt32
    var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
    
    var name: TargetRelativeDirectPointer<CChar>   // class/struct/enum 的名称
    var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
    var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor> // 属性描述器
    
    var superClassType: TargetRelativeDirectPointer<CChar> // 父类类型
    var metadataNegativeSizeInWords: UInt32
    var metadataPositiveSizeInWords: UInt32
    var numImmediateMembers: UInt32
    var numFields: UInt32
    var fieldOffsetVectorOffset: UInt32 // 每一个属性值距离当前实例对象地址的偏移量
    //var Offset: UInt32
    // var size: UInt32
    // V-Table  (methods)
}
1.3 FieldDescriptor属性描述器(包含了属性信息)

FieldDescriptor的源码声明:

// Field descriptors contain a collection of field records for a single
// class, struct or enum declaration.
class FieldDescriptor {
  const FieldRecord *getFieldRecordBuffer() const {
    return reinterpret_cast<const FieldRecord *>(this + 1);
  }

public:
  const RelativeDirectPointer<const char> MangledTypeName;
  const RelativeDirectPointer<const char> Superclass;

  FieldDescriptor() = delete;

  const FieldDescriptorKind Kind;
  const uint16_t FieldRecordSize;
  const uint32_t NumFields;

  using const_iterator = FieldRecordIterator;

  bool isEnum() const {
    return (Kind == FieldDescriptorKind::Enum ||
            Kind == FieldDescriptorKind::MultiPayloadEnum);
  }

  bool isClass() const {
    return (Kind == FieldDescriptorKind::Class ||
            Kind == FieldDescriptorKind::ObjCClass);
  }

  bool isProtocol() const {
    return (Kind == FieldDescriptorKind::Protocol ||
            Kind == FieldDescriptorKind::ClassProtocol ||
            Kind == FieldDescriptorKind::ObjCProtocol);
  }

  bool isStruct() const {
    return Kind == FieldDescriptorKind::Struct;
  }

  const_iterator begin() const {
    auto Begin = getFieldRecordBuffer();
    auto End = Begin + NumFields;
    return const_iterator { Begin, End };
  }

  const_iterator end() const {
    auto Begin = getFieldRecordBuffer();
    auto End = Begin + NumFields;
    return const_iterator { End, End };
  }

  llvm::ArrayRef<FieldRecord> getFields() const {
    return {getFieldRecordBuffer(), NumFields};
  }

  bool hasMangledTypeName() const {
    return MangledTypeName;
  }

  StringRef getMangledTypeName() const {
    return Demangle::makeSymbolicMangledNameStringRef(MangledTypeName.get());
  }

  bool hasSuperclass() const {
    return Superclass;
  }

  StringRef getSuperclass() const {
    return Demangle::makeSymbolicMangledNameStringRef(Superclass.get());
  }
};

FieldDescriptor包含的属性:
var mangledTypeName: TargetRelativeDirectPointer<CChar>; // 混写类型名称
var superclass: TargetRelativeDirectPointer<CChar>;
var kind: UInt16;
var fieldRecordSize: UInt16; // 属性的size
var numFields: UInt32; // 属性个数

但其实FieldDescriptor的属性是包含了一个属性列表的,因为源码声明里面可以看出:

getFields
getFieldRecordBuffer

FieldDescriptor数据结构可以还原成下面这样:

// 属性描述器
struct FieldDescriptor {
    var mangledTypeName: TargetRelativeDirectPointer<CChar>
    var superclass: TargetRelativeDirectPointer<CChar>
    var kind: UInt16
    var fieldRecordSize: UInt16
    var numFields: UInt32 // 属性个数
    var fields: FiledRecordBuffer<FieldRecord> // 属性列表
}

struct FiledRecordBuffer<Element>{
    var element: Element
    
    mutating func buffer(n: Int) -> UnsafeBufferPointer<Element> {
        return withUnsafePointer(to: &self) {
            let ptr = $0.withMemoryRebound(to: Element.self, capacity: 1) { start in
                return start
            }
            return UnsafeBufferPointer(start: ptr, count: n)
        }
    }
    
    mutating func index(of i: Int) -> UnsafeMutablePointer<Element> {
        return withUnsafePointer(to: &self) {
            return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self).advanced(by: i))
        }
    }
}

接下来还需要还原FieldRecord的数据结构,先来看看
FieldRecord的源码声明:

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();
  }

  bool isVar() const {
    return Flags.isVar();
  }
};

很简单地就能还原出,FieldRecord的数据结构:

// 属性
struct FieldRecord {
    var flags: Int32
    var mangledTypeName: TargetRelativeDirectPointer<CChar> // 属性的类型
    var fieldName: TargetRelativeDirectPointer<UInt8> // 属性的名称
}

2、列出TargetClassMetadata的完整数据结构

2.1 类 Metadata
// 类 Metadata
struct TargetClassMetadata {
    var kind: Int
    var superClass: Any.Type
    var cacheData: (Int, Int)
    var data: Int
    
    var classFlags: Int32 // swift特有的标志
    var instanceAddressPoint: UInt32 // 实例独享内存首地址
    var instanceSize: UInt32 // 实例对象内存大小
    var instanceAlignmentMask: UInt16 // 实例对象内存对齐方式
    var reserved: UInt16 // 运行时保留字段
    var classSize: UInt32 // 类的内存大小
    var classAddressPoint: UInt32 //类的内存首地址
    var typeDescriptor: UnsafeMutablePointer<TargetClassDescriptor> // 类型描述器
    var iVarDestroyer: UnsafeRawPointer // 实例销毁器
}

// 类描述器
struct TargetClassDescriptor{
    var flags: UInt32
    var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
    
    var name: TargetRelativeDirectPointer<CChar>   // class/struct/enum 的名称
    var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
    var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor> // 属性描述器
    
    var superClassType: TargetRelativeDirectPointer<CChar> // 父类类型
    var metadataNegativeSizeInWords: UInt32
    var metadataPositiveSizeInWords: UInt32
    var numImmediateMembers: UInt32
    var numFields: UInt32
    var fieldOffsetVectorOffset: UInt32 // 每一个属性值距离当前实例对象地址的偏移量
    //var Offset: UInt32
    // var size: UInt32
    // V-Table  (methods)
    
    func getFieldOffsets(_ metadata: UnsafeRawPointer) -> UnsafePointer<Int> {
        return metadata.assumingMemoryBound(to: Int.self).advanced(by: numericCast(self.fieldOffsetVectorOffset))
    }
    
    // 泛型参数的偏移量 - 源码里是经过一系列计算 而HandyJSON直接给2
    var genericArgumentOffset: Int { return 2 }
}
2.2 通用class/struct/enum类-相对地址信息
// 相对地址信息 - 存储的是偏移量
struct TargetRelativeDirectPointer<Pointee> {
    var offset: Int32
    
    mutating func getmeasureRelativeOffset() -> UnsafeMutablePointer<Pointee>{
        let offset = self.offset
        
        return withUnsafePointer(to: &self) { p in
            /*
             获得self,变为raw,然后+offset
             
             - UnsafeRawPointer(p) 表示this
             - advanced(by: numericCast(offset) 表示移动的步长,即offset
             - assumingMemoryBound(to: T.self) 表示假定类型是T,即自己指定的类型
             - UnsafeMutablePointer(mutating:) 表示返回的指针类型
            */
           return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self))
        }
    }
}
2.3 通用class/struct/enum类 - 属性信息
// 属性描述器
struct FieldDescriptor {
    var mangledTypeName: TargetRelativeDirectPointer<CChar>
    var superclass: TargetRelativeDirectPointer<CChar>
    var kind: UInt16
    var fieldRecordSize: UInt16
    var numFields: UInt32 // 属性个数
    var fields: FiledRecordBuffer<FieldRecord> // 属性列表
}

// 属性
struct FieldRecord {
    var flags: Int32
    var mangledTypeName: TargetRelativeDirectPointer<CChar> // 属性的类型
    var fieldName: TargetRelativeDirectPointer<UInt8> // 属性的名称
}

struct FiledRecordBuffer<Element>{
    var element: Element
    
    mutating func buffer(n: Int) -> UnsafeBufferPointer<Element> {
        return withUnsafePointer(to: &self) {
            let ptr = $0.withMemoryRebound(to: Element.self, capacity: 1) { start in
                return start
            }
            return UnsafeBufferPointer(start: ptr, count: n)
        }
    }
    
    mutating func index(of i: Int) -> UnsafeMutablePointer<Element> {
        return withUnsafePointer(to: &self) {
            return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self).advanced(by: i))
        }
    }
}

3、验证TargetClassMetadata数据结构

class Person {
    var name = "安老师"
    var age = 18
}

let person = Person() // 创建一个Person实例
var pClazz = Person.self // 拿到类对象
// 拿到ClassMetadata指针
let classMetadata_ptr = unsafeBitCast(pClazz as Any.Type, to: UnsafeMutablePointer<TargetClassMetadata>.self)

unsafeBitCast的作用:按位转换成指针 UnsafeMutablePointer<TargetClassMetadata>,就可以对指针进行操作。

// 取出类描述器里的name的相对偏移量
let name_ptr = classMetadata_ptr.pointee.typeDescriptor.pointee.name.getmeasureRelativeOffset()
print(String(cString: name_ptr)) // Person

ps:classMetadata_ptr.pointee.typeDescriptor.pointee.name的类型是这个相对地址信息,上面说过它存储的是偏移量。

// 属性个数
let numFileds = classMetadata_ptr.pointee.typeDescriptor.pointee.numFields
print(numFileds)  // 2

下面我要输出person实例里的所有属性值:

// 拿到首个属性偏移地址信息
let offsets = classMetadata_ptr.pointee.typeDescriptor.pointee.getFieldOffsets(UnsafeRawPointer(classMetadata_ptr).assumingMemoryBound(to: Int.self))

ps: 在TargetClassDescriptor里有一个属性叫fieldOffsetVectorOffset,它存储的是每一个属性值距离当前实例对象地址的偏移量;从classMetadata_ptr指针偏移fieldOffsetVectorOffset

for i in 0..<numFileds {
    // 获取属性名
    let fieldName = classMetadata_ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getmeasureRelativeOffset().pointee.fields.index(of: Int(i)).pointee.fieldName.getmeasureRelativeOffset()
    print("fieldName:\(String(cString: fieldName))")
    
    // 混写过的类型名称
    let mangledTypeName = classMetadata_ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getmeasureRelativeOffset().pointee.fields.index(of: Int(i)).pointee.mangledTypeName.getmeasureRelativeOffset()
    print("mangledTypeName:\(String(cString: mangledTypeName))")
    
    // 泛型向量
    let genericVector = UnsafeRawPointer(classMetadata_ptr).advanced(by: classMetadata_ptr.pointee.typeDescriptor.pointee.genericArgumentOffset * MemoryLayout<UnsafeRawPointer>.size).assumingMemoryBound(to: Any.Type.self)
    
    // 获取属性类型:
    // 新建C文件,声明这个函数 (CAPI.h)
    let fieldType = swift_getTypeByMangledNameInContext(mangledTypeName,
                                                        256,
                                                        UnsafeRawPointer(classMetadata_ptr.pointee.typeDescriptor),
                                                        UnsafeRawPointer(genericVector)?.assumingMemoryBound(to: Optional<UnsafeRawPointer>.self))
    let realType = unsafeBitCast(fieldType, to: Any.Type.self)
    print("fieldType: \(realType)")
    
    // 狡猾地把真实类型信息,保存到protocol的metadata,再通过Self.self获取真实类型
    let protocolType = getBitCast(type: realType)

    // 对象的起始地址
    let instanceAddress = Unmanaged.passUnretained(person).toOpaque() // Teacher()的起始地址
    // 每个属性的偏移量
    let fieldOffset = offsets[Int(i)]
    
    // 获取属性的值
    let value = protocolType.get(from: instanceAddress.advanced(by: fieldOffset))
    print("fieldValue: \(value)")

    
    /*
    // HandyJSON 的方式 通过函数映射 (CApi.swift)
    let fieldType = _getTypeByMangledNameInContext(mangledTypeName,
                                                   256,
                                                   genericContext: UnsafeRawPointer(classMetadata_ptr.pointee.typeDescriptor),
                                                   genericArguments: UnsafeRawPointer(genericVector)?.assumingMemoryBound(to: Optional<UnsafeRawPointer>.self))
    
    print(fieldType as Any)
    */
   
    print("==================")
}

for...in打印结果:

for...in打印结果

上面还有一部分代码没粘贴上来,后面会粘出来的,先一步步分析。

分析一:获取属性名

// 获取属性名
let fieldName = classMetadata_ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getmeasureRelativeOffset().pointee.fields.index(of: Int(i)).pointee.fieldName.getmeasureRelativeOffset()

1.classMetadata_ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getmeasureRelativeOffset().pointee
在TargetClassDescriptor中的fieldDescriptor是相对地址信息类型,通过调用getmeasureRelativeOffset()来做地址偏移,才能获取到真正的fieldDescriptor对象

2.classMetadata_ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getmeasureRelativeOffset().pointee.fields.index(of: Int(i)).pointee
拿到真正的fieldDescriptor对象后,可以找到fields属性列表,可以发现它是一个FiledRecordBuffer<FieldRecord>类型,通过源码可知属性列表是一片连续的内存空间,需要逐个拿出对应地址的field指针;再.pointee得到FieldRecord实例对象,才能继续对FieldRecord实例的属性进行访问。

分析二:获取属性类型

  1. swift_getTypeByMangledNameInContext_getTypeByMangledNameInContext 的作用是讲混写后的属性类型名还原,调用的是同一个C标准库里的函数,只是可以通过两种方式去调用:
// 新建C文件,声明这个函数 (CAPI.h)
let fieldType = swift_getTypeByMangledNameInContext(mangledTypeName,
                                                    256,
                                                    UnsafeRawPointer(classMetadata_ptr.pointee.typeDescriptor),
                                                    UnsafeRawPointer(genericVector)?.assumingMemoryBound(to: Optional<UnsafeRawPointer>.self))
/*
// HandyJSON 的方式 通过函数映射 (CApi.swift)
let fieldType = _getTypeByMangledNameInContext(mangledTypeName,
                                               256,
                                               genericContext: UnsafeRawPointer(classMetadata_ptr.pointee.typeDescriptor),
                                               genericArguments: UnsafeRawPointer(genericVector)?.assumingMemoryBound(to: Optional<UnsafeRawPointer>.self))
    
print(fieldType as Any)
*/

let realType = unsafeBitCast(fieldType, to: Any.Type.self)
print("fieldType: \(realType)")

方式一:创建C文件,在.h文件下声明这个函数即可:

image.png

方式二:通过swift函数映射的方式@_silgen_name

swift声明

2.注意fieldType的类型依然是不确定类型UnsafeRawPointer,但我们程序依旧不知道它是什么类型,所以只能转换成 Any.Type 类型

let realType = unsafeBitCast(fieldType, to: Any.Type.self)

3.getBitCast其实是上面代码缺失部分之一

// 狡猾地把真实类型信息,保存到protocol的metadata,再通过Self.self获取真实类型
let protocolType = getBitCast(type: realType)

getBitCast函数的实现:(狡猾地把真实类型信息,保存到protocol的metadata,再通过Self.self获取真实类型)

// 将一个Any.Type转换成BrigeProtocol
func getBitCast(type: Any.Type) -> BrigeProtocol.Type {
    let container = ProtocolMetadata(type: type, witness: 0)
    let bitCast = unsafeBitCast(container, to: BrigeProtocol.Type.self) // 将struct保存到Protocol的Metadata
    return bitCast
}

BrigeProtocol的声明:

protocol BrigeProtocol {}
extension BrigeProtocol {
    // 获取真实类型信息的值
    static func get(from pointer: UnsafeRawPointer) -> Any {
        return pointer.assumingMemoryBound(to: Self.self).pointee
    }
}

// 协议的Metadata
// 协议见证表
struct ProtocolMetadata { // TargetWitnessTable
    let type: Any.Type // 真实类型
    let witness: Int
}

关于协议相关的在往后的章节会讲到,不在本章节过多细说了。

分析三:获取属性的值

    // 对象的起始地址
    let instanceAddress = Unmanaged.passUnretained(person).toOpaque() // Teacher()的起始地址
    // 每个属性的偏移量
    let fieldOffset = offsets[Int(i)]
    
    // 获取属性的值
    let value = protocolType.get(from: instanceAddress.advanced(by: fieldOffset))
    print("fieldValue: \(value)")

为什么protocolType.get(from: instanceAddress.advanced(by: fieldOffset))能获取到属性的值呢?
首先获取某个对象的属性值,需要拿到对象的首地址和属性对应的偏移量,然后在首地址的基础上偏移,再对其真实类型的绑定。
其中Self.self就是通过获取真实类型的过程。

以上就是TargetClassMetadata数据结构的全部内容。

二、TargetStructMetadata

1、TargetStructMetadata源码分析

1.1 从源码分析出TargetStructMetadata的数据结构

TargetStructMetadata的源码声明:

/// The structure of type metadata for structs.
template <typename Runtime>
struct TargetStructMetadata : public TargetValueMetadata<Runtime> {
  using StoredPointer = typename Runtime::StoredPointer;
  using TargetValueMetadata<Runtime>::TargetValueMetadata;

  const TargetStructDescriptor<Runtime> *getDescription() const {
    return llvm::cast<TargetStructDescriptor<Runtime>>(this->Description);
  }

  // The first trailing field of struct metadata is always the generic
  // argument array.

  /// Get a pointer to the field offset vector, if present, or null.
  const uint32_t *getFieldOffsets() const {
    auto offset = getDescription()->FieldOffsetVectorOffset;
    if (offset == 0)
      return nullptr;
    auto asWords = reinterpret_cast<const void * const*>(this);
    return reinterpret_cast<const uint32_t *>(asWords + offset);
  }

  bool isStaticallySpecializedGenericMetadata() const {
    auto *description = getDescription();
    if (!description->isGeneric())
      return false;

    auto *trailingFlags = getTrailingFlags();
    if (trailingFlags == nullptr)
      return false;

    return trailingFlags->isStaticSpecialization();
  }

  bool isCanonicalStaticallySpecializedGenericMetadata() const {
    auto *description = getDescription();
    if (!description->isGeneric())
      return false;

    auto *trailingFlags = getTrailingFlags();
    if (trailingFlags == nullptr)
      return false;

    return trailingFlags->isCanonicalStaticSpecialization();
  }

  const MetadataTrailingFlags *getTrailingFlags() const {
    auto description = getDescription();
    auto flags = description->getFullGenericContextHeader()
                     .DefaultInstantiationPattern->PatternFlags;
    if (!flags.hasTrailingFlags())
      return nullptr;
    auto fieldOffset = description->FieldOffsetVectorOffset;
    auto offset =
        fieldOffset +
        // Pad to the nearest pointer.
        ((description->NumFields * sizeof(uint32_t) + sizeof(void *) - 1) /
         sizeof(void *));
    auto asWords = reinterpret_cast<const void *const *>(this);
    return reinterpret_cast<const MetadataTrailingFlags *>(asWords + offset);
  }

  static constexpr int32_t getGenericArgumentOffset() {
    return sizeof(TargetStructMetadata<Runtime>) / sizeof(StoredPointer);
  }

  static bool classof(const TargetMetadata<Runtime> *metadata) {
    return metadata->getKind() == MetadataKind::Struct;
  }
};
using StructMetadata = TargetStructMetadata<InProcess>;

TargetStructMetadata没有啥的属性,看看它父类TargetValueMetadata
TargetValueMetadata的源码声明:

/// The common structure of metadata for structs and enums.
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;
  }
};
using ValueMetadata = TargetValueMetadata<InProcess>;

TargetValueMetadata有一个Description的属性;

/// An out-of-line description of the type.
TargetSignedPointer<Runtime, const TargetValueTypeDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;

TargetValueMetadata继承自TargetMetadata,上面我已经粘贴过了它的源码,它只有一个 Kind属性。

TargetStructMetadata的数据结构:

struct TargetStructMetadata {
    var Kind: Int
     // 结构体描述器 (TargetStructDescriptor是解析后的自定义的,它可以替代TargetValueTypeDescriptor)
    var typeDescriptor: UnsafeMutablePointer<TargetStructDescriptor>
}

接下来看看结构体描述器TargetValueTypeDescriptor到底是什么

1.2 从源码分析出TargetStructDescriptor(自定义)的数据结构

TargetValueTypeDescriptor的源码分析:

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;
  }
};
using ValueTypeDescriptor = TargetValueTypeDescriptor<InProcess>;

TargetValueTypeDescriptor继承自TargetTypeContextDescriptor; TargetTypeContextDescriptor和FieldDescriptor的源码在第一部分就有自行看看。

TargetStructMetadata继承关系图

得出TargetStructDescriptor的数据结构:

struct TargetStructDescriptor {
    var flags: UInt32
    var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
    var name: TargetRelativeDirectPointer<CChar> // 类名
    var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
    var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor> // 属性描述器
    var numFields: UInt32 
    var fieldOffsetVectorOffset: UInt32 // 每一个属性值距离当前实例对象地址的偏移量
    
    // 泛型参数的偏移量 - 源码里是经过一系列计算 而HandyJSON直接给2
    var genericArgumentOffset: Int { return 2 }
}

2、验证TargetStructMetadata数据结构

struct Person {
    var age:Int = 18
    let name:String = "安安"
    let sex = false
    var address = "ZH-1201"
    var birthday = ("1995", "12", "26")
}

var person = Person()
/**
 var personType = Person.self
 let person_ptr = withUnsafePointer(to: &personType) { ptr in
     UnsafeRawPointer(ptr).bindMemory(to: UnsafeMutablePointer<TargetStructMetadata>.self, capacity: 1)
 }.pointee
 print(person_ptr.pointee.typeDescriptor.pointee.numFields)
 */

let pointer = unsafeBitCast(Person.self as Any.Type, to: UnsafeMutablePointer<TargetStructMetadata>.self)

let numFileds = pointer.pointee.typeDescriptor.pointee.numFields
print("numFileds: \(numFileds)")

var bufferPtr = UnsafeBufferPointer(start: UnsafeRawPointer(UnsafeRawPointer(pointer).assumingMemoryBound(to: Int.self).advanced(by: numericCast(pointer.pointee.typeDescriptor.pointee.fieldOffsetVectorOffset))).assumingMemoryBound(to: Int32.self), count: Int(pointer.pointee.typeDescriptor.pointee.numFields))
for i in 0..<numFileds {
    let filedName = pointer.pointee.typeDescriptor.pointee.fieldDescriptor.getmeasureRelativeOffset().pointee.fields.index(of: Int(i)).pointee.fieldName.getmeasureRelativeOffset()
    print("filedName: \(String(cString: filedName))")
    
    // 混写过的mangleTypeName
    let mangledTypeName = pointer.pointee.typeDescriptor.pointee.fieldDescriptor.getmeasureRelativeOffset().pointee.fields.index(of: Int(i)).pointee.mangledTypeName.getmeasureRelativeOffset()
    
    // 泛型向量
    let genericVector = UnsafeRawPointer(pointer).advanced(by: pointer.pointee.typeDescriptor.pointee.genericArgumentOffset * MemoryLayout<UnsafeRawPointer>.size).assumingMemoryBound(to: Any.Type.self)
    
    
    // 获取属性类型:
    // 新建C文件,声明这个函数 (CAPI.h)
    let fieldType = swift_getTypeByMangledNameInContext(mangledTypeName, 256, UnsafeRawPointer(pointer.pointee.typeDescriptor), UnsafeRawPointer(genericVector)?.assumingMemoryBound(to: Optional<UnsafeRawPointer>.self))
    // 属性类型 (Any包裹了真实类型)
    let type = unsafeBitCast(fieldType, to: Any.Type.self)
    print("filedType: \(type)")
    
    // 对象的起始地址
    let instanceAddress = withUnsafeMutablePointer(to: &person){$0} // Person()的起始地址
    // 每个属性的偏移量
    let fieldOffset = bufferPtr[Int(i)]
    // 真实属性类型
    let realType = getBitCast(type: type) // 狡猾地把真实类型信息,保存到protocol的metadata,再通过Self.self获取真实类型
    let value = realType.get(from: UnsafeRawPointer(UnsafeRawPointer(instanceAddress).advanced(by: numericCast(fieldOffset))))
    print("filedValue: \(value)")
    
    print("========================================")
}

来看看打印结果:

打印结果

上面在分析类的时候就分析过了,就不分析了。

在文章的最后给出TargetEnumMetadata的数据结构:

// 枚举Metadata
struct TargetEnumMetadata {
    var kind: Int
    var typeDescriptor: UnsafeMutablePointer<TargetEnumDescriptor>
}

// 枚举描述器
struct TargetEnumDescriptor {
    var flags: UInt32
    var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
    var name: TargetRelativeDirectPointer<CChar>
    var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
    var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>
    var NumPayloadCasesAndPayloadSizeOffset: UInt32
    var NumEmptyCases: UInt32
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容