private: /// The kind. Only valid for non-class metadata; getKind() must be used to get /// the kind value. StoredPointerKind; public: /// Get the metadata kind. MetadataKind getKind() const { return getEnumeratedMetadataKind(Kind); } /// Set the metadata kind. void setKind(MetadataKind kind) { Kind= static_cast<StoredPointer>(kind); }
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) { caseMetadataKind::Class: caseMetadataKind::ObjCClassWrapper: caseMetadataKind::ForeignClass: returntrue;
default: returnfalse; } } /// Is this metadata for an existential type? bool isAnyExistentialType() const { switch (getKind()) { caseMetadataKind::ExistentialMetatype: caseMetadataKind::Existential: returntrue;
default: returnfalse; } } /// Is this either type metadata or a class object for any kind of class? bool isAnyClass() const { return isAnyKindOfClass(getKind()); }
/// 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()) { caseMetadataKind::Class: { const auto cls = static_cast<const TargetClassMetadataType<Runtime> *>(this); if (!cls->isTypeMetadata()) return nullptr; if (cls->isArtificialSubclass()) return nullptr; return cls->getDescription(); } caseMetadataKind::Struct: caseMetadataKind::Enum: caseMetadataKind::Optional: return static_cast<const TargetValueMetadata<Runtime> *>(this) ->Description; caseMetadataKind::ForeignClass: return static_cast<const TargetForeignClassMetadata<Runtime> *>(this) ->Description; default: return nullptr; } }
void addMethod(SILDeclRef fn) { if (!VTable|| methodRequiresReifiedVTableEntry(IGM, VTable, fn)) { VTableEntries.push_back(fn); } else { // Emit a stub method descriptor and lookup function for nonoverridden // methods so that resilient code sequences can still use them. emitNonoverriddenMethod(fn); } }
// Only emit a method lookup function if the class is resilient // and has a non-empty vtable, as well as no elided methods. if (IGM.hasResilientMetadata(getType(), ResilienceExpansion::Minimal) && (HasNonoverriddenMethods||!VTableEntries.empty())) IGM.emitMethodLookupFunction(getType());
if (VTableEntries.empty()) return; auto offset =MetadataLayout->hasResilientSuperclass() ?MetadataLayout->getRelativeVTableOffset() : MetadataLayout->getStaticVTableOffset(); B.addInt32(offset /IGM.getPointerSize()); B.addInt32(VTableEntries.size()); for (auto fn : VTableEntries) emitMethodDescriptor(fn); }
void addVTableTypeMetadata(llvm::GlobalVariable*var) { if (!IGM.getOptions().VirtualFunctionElimination) return; assert(VTable&&"no vtable?!");
IGM.addVTableTypeMetadata(getType(), var, VTableEntriesForVFE); }
void emitNonoverriddenMethod(SILDeclRef fn) { // TODO: Derivative functions do not distinguish themselves in the mangled // names of method descriptor symbols yet, causing symbol name collisions. if (fn.getDerivativeFunctionIdentifier()) return;
HasNonoverriddenMethods=true; // Although this method is non-overridden and therefore left out of the // vtable, we still need to maintain the ABI of a potentially-overridden // method for external clients. // Emit method dispatch thunk. if (hasPublicVisibility(fn.getLinkage(NotForDefinition)) || IGM.getOptions().VirtualFunctionElimination) { IGM.emitDispatchThunk(fn); }
if (IGM.getOptions().VirtualFunctionElimination) { auto offset =B.getNextOffsetFromGlobal() + // 1st field of MethodDescriptorStructTy Size(IGM.DataLayout.getTypeAllocSize(IGM.Int32Ty)); VTableEntriesForVFE.push_back(std::pair<Size, SILDeclRef>(offset, fn)); }
// Emit a freestanding method descriptor structure. This doesn't have to // exist in the table in the class's context descriptor since it isn't // in the vtable, but external clients need to be able to link against the // symbol. IGM.emitNonoverriddenMethodDescriptor(VTable, fn); }
for (auto pair : OverrideTableEntries) emitMethodOverrideDescriptor(pair.first, pair.second); }
void emitMethodOverrideDescriptor(SILDeclRef baseRef, SILDeclRef declRef) { if (IGM.getOptions().VirtualFunctionElimination) { auto offset = B.getNextOffsetFromGlobal() + // 1st field of MethodOverrideDescriptorStructTy Size(IGM.DataLayout.getTypeAllocSize(IGM.RelativeAddressTy)) + // 2nd field of MethodOverrideDescriptorStructTy Size(IGM.DataLayout.getTypeAllocSize(IGM.RelativeAddressTy)); VTableEntriesForVFE.push_back( std::pair<Size, SILDeclRef>(offset, baseRef)); }
auto descriptor =B.beginStruct(IGM.MethodOverrideDescriptorStructTy);
// The class containing the base method. auto *baseClass = cast<ClassDecl>(baseRef.getDecl()->getDeclContext()); IGM.IRGen.noteUseOfTypeContextDescriptor(baseClass, DontRequireMetadata); auto baseClassEntity =LinkEntity::forNominalTypeDescriptor(baseClass); auto baseClassDescriptor = IGM.getAddrOfLLVMVariableOrGOTEquivalent(baseClassEntity); descriptor.addRelativeAddress(baseClassDescriptor);
// The base method. auto baseMethodEntity =LinkEntity::forMethodDescriptor(baseRef); auto baseMethodDescriptor = IGM.getAddrOfLLVMVariableOrGOTEquivalent(baseMethodEntity); descriptor.addRelativeAddress(baseMethodDescriptor);
// The implementation of the override. if (auto entry =VTable->getEntry(IGM.getSILModule(), baseRef)) { assert(entry->getKind() == SILVTable::Entry::Kind::Override);
auto *impl = entry->getImplementation(); if (impl->isAsync()) { llvm::Constant*implFn =IGM.getAddrOfAsyncFunctionPointer(impl); descriptor.addRelativeAddress(implFn); } else { llvm::Function*implFn =IGM.getAddrOfSILFunction(impl, NotForDefinition); descriptor.addCompactFunctionReference(implFn); } } else { // The method is removed by dead method elimination. // It should be never called. We add a pointer to an error function. descriptor.addRelativeAddressOrNull(nullptr); }
descriptor.finishAndAddTo(B); }
void addPlaceholder(MissingMemberDecl*MMD) { llvm_unreachable("cannot generate metadata with placeholders in it"); } void addLayoutInfo() {
structTargetClassDescriptor { var flags: UInt32 var parent: UInt32 var name: Int32 // 类/结构体/枚举 的名称 var accessFunctionPointer: Int32 var fieldDescriptor: FieldDescriptor // 属性的描述,属性信息存在这里 var superClassType: Int32 var metadataNegativeSizeInWords: UInt32 var metadataPositiveSizeInWords: UInt32 var numImmediateMembers: UInt32 var numFields: UInt32 var fieldOffsetVectorOffset: UInt32 var Offset: UInt32 // 偏移量 var size: UInt32 // V-Table的size大小 var vtable: Array // 数组V-Table, 函数表 }