| //===--- MetadataLayout.cpp - Metadata construct layout -------------------===// | |
| // | |
| // This source file is part of the Swift.org open source project | |
| // | |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors | |
| // Licensed under Apache License v2.0 with Runtime Library Exception | |
| // | |
| // See https://swift.org/LICENSE.txt for license information | |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file includes code for laying out type metadata. | |
| // | |
| // It also implements certain low-level access routines for type metadata. | |
| // These routines are generally declared in one of two different places: | |
| // | |
| // - Mid-level routines to extract data from metadata are declared in | |
| // GenMeta.h. This file is a sort of sub-module of GenMeta.cpp. | |
| // | |
| // - Low-level routines to project the addresses of fields in metadata | |
| // are declared in MetadataLayout.h. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "MetadataLayout.h" | |
| #include "GenMeta.h" | |
| #include "ClassMetadataVisitor.h" | |
| #include "EnumMetadataVisitor.h" | |
| #include "IRGenFunction.h" | |
| #include "StructMetadataVisitor.h" | |
| #include "ForeignClassMetadataVisitor.h" | |
| #include "TupleMetadataVisitor.h" | |
| #include "swift/Basic/LLVM.h" | |
| #include "llvm/ADT/Optional.h" | |
| using namespace swift; | |
| using namespace irgen; | |
| namespace { | |
| template <class Impl, template <class> class Base> | |
| class LayoutScanner : public Base<Impl> { | |
| Optional<Size> AddressPoint; | |
| protected: | |
| Optional<Size> DynamicOffsetBase; | |
| template <class... As> | |
| LayoutScanner(As &&... args) : Base<Impl>(std::forward<As>(args)...) {} | |
| public: | |
| using StoredOffset = MetadataLayout::StoredOffset; | |
| void noteAddressPoint() { AddressPoint = this->NextOffset; } | |
| StoredOffset getNextOffset() const { | |
| if (DynamicOffsetBase) { | |
| return StoredOffset(this->NextOffset - *DynamicOffsetBase, | |
| StoredOffset::Dynamic); | |
| } | |
| return StoredOffset(this->NextOffset - *AddressPoint, | |
| StoredOffset::Static); | |
| } | |
| Size getAddressPoint() const { | |
| return *AddressPoint; | |
| } | |
| MetadataSize getMetadataSize() const { | |
| assert(AddressPoint.hasValue() && !AddressPoint->isInvalid() | |
| && "did not find address point?!"); | |
| assert(*AddressPoint < this->NextOffset | |
| && "address point is after end?!"); | |
| return {this->NextOffset, *AddressPoint}; | |
| } | |
| }; | |
| } | |
| ClassMetadataLayout &IRGenModule::getClassMetadataLayout(ClassDecl *decl) { | |
| assert(!decl->isForeign() && "Use getForeignMetadataLayout()"); | |
| return cast<ClassMetadataLayout>( | |
| getMetadataLayout(static_cast<NominalTypeDecl*>(decl))); | |
| } | |
| ForeignClassMetadataLayout &IRGenModule::getForeignMetadataLayout( | |
| ClassDecl *decl) { | |
| assert(decl->isForeign() && "Use getMetadataLayout()"); | |
| return cast<ForeignClassMetadataLayout>( | |
| getMetadataLayout(static_cast<NominalTypeDecl*>(decl))); | |
| } | |
| EnumMetadataLayout &IRGenModule::getMetadataLayout(EnumDecl *decl) { | |
| return cast<EnumMetadataLayout>( | |
| getMetadataLayout(static_cast<NominalTypeDecl*>(decl))); | |
| } | |
| StructMetadataLayout &IRGenModule::getMetadataLayout(StructDecl *decl) { | |
| return cast<StructMetadataLayout>( | |
| getMetadataLayout(static_cast<NominalTypeDecl*>(decl))); | |
| } | |
| NominalMetadataLayout &IRGenModule::getNominalMetadataLayout( | |
| NominalTypeDecl *decl) { | |
| return cast<NominalMetadataLayout>(getMetadataLayout(decl)); | |
| } | |
| MetadataLayout &IRGenModule::getMetadataLayout(NominalTypeDecl *decl) { | |
| auto &entry = MetadataLayouts[decl]; | |
| if (!entry) { | |
| if (auto theClass = dyn_cast<ClassDecl>(decl)) { | |
| if (theClass->getForeignClassKind() == ClassDecl::ForeignKind::CFType) | |
| entry = new ForeignClassMetadataLayout(*this, theClass); | |
| else | |
| entry = new ClassMetadataLayout(*this, theClass); | |
| } else if (auto theEnum = dyn_cast<EnumDecl>(decl)) { | |
| entry = new EnumMetadataLayout(*this, theEnum); | |
| } else if (auto theStruct = dyn_cast<StructDecl>(decl)) { | |
| entry = new StructMetadataLayout(*this, theStruct); | |
| } else { | |
| llvm_unreachable("bad nominal type!"); | |
| } | |
| } | |
| return *cast<MetadataLayout>(entry); | |
| } | |
| void IRGenModule::destroyMetadataLayoutMap() { | |
| for (auto &entry : MetadataLayouts) { | |
| entry.second->destroy(); | |
| } | |
| } | |
| void MetadataLayout::destroy() const { | |
| switch (getKind()) { | |
| case Kind::Class: | |
| delete cast<ClassMetadataLayout>(this); | |
| return; | |
| case Kind::Struct: | |
| delete cast<StructMetadataLayout>(this); | |
| return; | |
| case Kind::Enum: | |
| delete cast<EnumMetadataLayout>(this); | |
| return; | |
| case Kind::ForeignClass: | |
| delete cast<ForeignClassMetadataLayout>(this); | |
| return; | |
| } | |
| llvm_unreachable("bad kind"); | |
| } | |
| /******************************* NOMINAL TYPES ********************************/ | |
| Offset NominalMetadataLayout::emitOffset(IRGenFunction &IGF, | |
| StoredOffset offset) const { | |
| assert(offset.isValid()); | |
| if (offset.isStatic()) | |
| return Offset(offset.getStaticOffset()); | |
| Address layoutAddr( | |
| IGF.IGM.getAddrOfClassMetadataBounds(cast<ClassDecl>(getDecl()), | |
| NotForDefinition), | |
| IGF.IGM.getPointerAlignment()); | |
| auto offsetBaseAddr = IGF.Builder.CreateStructGEP(layoutAddr, 0, Size(0)); | |
| // FIXME: Should this be an invariant load? | |
| llvm::Value *offsetVal = IGF.Builder.CreateLoad(offsetBaseAddr, "base"); | |
| auto relativeOffset = offset.getRelativeOffset().getValue(); | |
| if (relativeOffset != 0) { | |
| offsetVal = IGF.Builder.CreateAdd(offsetVal, | |
| llvm::ConstantInt::get(IGF.IGM.SizeTy, | |
| relativeOffset)); | |
| } | |
| return Offset(offsetVal); | |
| } | |
| Size | |
| NominalMetadataLayout::getStaticGenericRequirementsOffset() const { | |
| return GenericRequirements.getStaticOffset(); | |
| } | |
| Offset | |
| NominalMetadataLayout::getGenericRequirementsOffset(IRGenFunction &IGF) const { | |
| return emitOffset(IGF, GenericRequirements); | |
| } | |
| static llvm::Value *emitLoadOfGenericRequirement(IRGenFunction &IGF, | |
| llvm::Value *metadata, | |
| NominalTypeDecl *decl, | |
| unsigned reqtIndex, | |
| llvm::Type *reqtTy) { | |
| auto offset = | |
| IGF.IGM.getNominalMetadataLayout(decl).getGenericRequirementsOffset(IGF); | |
| offset = offset.offsetBy(IGF, Size(reqtIndex * IGF.IGM.getPointerSize())); | |
| auto slot = IGF.emitAddressAtOffset(metadata, offset, reqtTy, | |
| IGF.IGM.getPointerAlignment()); | |
| auto witness = IGF.emitInvariantLoad(slot); | |
| return witness; | |
| } | |
| /// Given a reference to nominal type metadata of the given type, | |
| /// derive a reference to the nth argument metadata. The type must | |
| /// have generic arguments. | |
| llvm::Value *irgen::emitArgumentMetadataRef(IRGenFunction &IGF, | |
| NominalTypeDecl *decl, | |
| const GenericTypeRequirements &reqts, | |
| unsigned reqtIndex, | |
| llvm::Value *metadata) { | |
| assert(reqts.getRequirements()[reqtIndex].Protocol == nullptr); | |
| return emitLoadOfGenericRequirement(IGF, metadata, decl, reqtIndex, | |
| IGF.IGM.TypeMetadataPtrTy); | |
| } | |
| /// Given a reference to nominal type metadata of the given type, | |
| /// derive a reference to a protocol witness table for the nth | |
| /// argument metadata. The type must have generic arguments. | |
| llvm::Value *irgen::emitArgumentWitnessTableRef(IRGenFunction &IGF, | |
| NominalTypeDecl *decl, | |
| const GenericTypeRequirements &reqts, | |
| unsigned reqtIndex, | |
| llvm::Value *metadata) { | |
| assert(reqts.getRequirements()[reqtIndex].Protocol != nullptr); | |
| return emitLoadOfGenericRequirement(IGF, metadata, decl, reqtIndex, | |
| IGF.IGM.WitnessTablePtrTy); | |
| } | |
| Address irgen::emitAddressOfFieldOffsetVector(IRGenFunction &IGF, | |
| llvm::Value *metadata, | |
| NominalTypeDecl *decl) { | |
| auto &layout = IGF.IGM.getMetadataLayout(decl); | |
| auto offset = [&]() { | |
| if (isa<ClassDecl>(decl)) { | |
| return cast<ClassMetadataLayout>(layout) | |
| .getFieldOffsetVectorOffset(IGF); | |
| } else { | |
| assert(isa<StructDecl>(decl)); | |
| return cast<StructMetadataLayout>(layout) | |
| .getFieldOffsetVectorOffset(); | |
| } | |
| }(); | |
| auto *elementSize = IGF.IGM.SizeTy; | |
| if (isa<StructDecl>(decl)) | |
| elementSize = IGF.IGM.Int32Ty; | |
| return IGF.emitAddressAtOffset(metadata, offset, elementSize, | |
| IGF.IGM.getPointerAlignment()); | |
| } | |
| /********************************** CLASSES ***********************************/ | |
| ClassMetadataLayout::ClassMetadataLayout(IRGenModule &IGM, ClassDecl *decl) | |
| : NominalMetadataLayout(Kind::Class, decl), NumImmediateMembers(0) { | |
| struct Scanner : LayoutScanner<Scanner, ClassMetadataScanner> { | |
| using super = LayoutScanner; | |
| ClassMetadataLayout &Layout; | |
| bool IsInTargetFields = false; | |
| Scanner(IRGenModule &IGM, ClassDecl *decl, ClassMetadataLayout &layout) | |
| : super(IGM, decl), Layout(layout) {} | |
| void noteResilientSuperclass() { | |
| Layout.HasResilientSuperclass = true; | |
| } | |
| void noteStartOfImmediateMembers(ClassDecl *forClass) { | |
| // If our superclass is resilient to us, or the class itself is resilient | |
| // to us, we will access metadata members relative to a base offset. | |
| if (forClass == Target) { | |
| Layout.StartOfImmediateMembers = getNextOffset(); | |
| if (Layout.HasResilientSuperclass || | |
| IGM.hasResilientMetadata(forClass, ResilienceExpansion::Maximal)) { | |
| assert(!DynamicOffsetBase); | |
| DynamicOffsetBase = NextOffset; | |
| } | |
| } | |
| } | |
| void addClassSize() { | |
| Layout.MetadataSize = getNextOffset(); | |
| super::addClassSize(); | |
| } | |
| void addClassAddressPoint() { | |
| Layout.MetadataAddressPoint = getNextOffset(); | |
| super::addClassAddressPoint(); | |
| } | |
| void addInstanceSize() { | |
| Layout.InstanceSize = getNextOffset(); | |
| super::addInstanceSize(); | |
| } | |
| void addInstanceAlignMask() { | |
| Layout.InstanceAlignMask = getNextOffset(); | |
| super::addInstanceAlignMask(); | |
| } | |
| void noteStartOfGenericRequirements(ClassDecl *forClass) { | |
| if (forClass == Target) | |
| Layout.GenericRequirements = getNextOffset(); | |
| super::noteStartOfGenericRequirements(forClass); | |
| } | |
| void addGenericWitnessTable(GenericRequirement requirement, | |
| ClassDecl *forClass) { | |
| if (forClass == Target) { | |
| ++Layout.NumImmediateMembers; | |
| } | |
| super::addGenericWitnessTable(requirement, forClass); | |
| } | |
| void addGenericArgument(GenericRequirement requirement, | |
| ClassDecl *forClass) { | |
| if (forClass == Target) { | |
| ++Layout.NumImmediateMembers; | |
| } | |
| super::addGenericArgument(requirement, forClass); | |
| } | |
| void addReifiedVTableEntry(SILDeclRef fn) { | |
| if (fn.getDecl()->getDeclContext() == Target) { | |
| ++Layout.NumImmediateMembers; | |
| Layout.MethodInfos.try_emplace(fn, getNextOffset()); | |
| } | |
| super::addReifiedVTableEntry(fn); | |
| } | |
| void noteNonoverriddenMethod(SILDeclRef fn) { | |
| if (fn.getDecl()->getDeclContext() == Target) { | |
| auto impl = VTable->getEntry(IGM.getSILModule(), fn); | |
| Layout.MethodInfos.try_emplace(fn, | |
| IGM.getAddrOfSILFunction(impl->getImplementation(), NotForDefinition)); | |
| } | |
| } | |
| void noteStartOfFieldOffsets(ClassDecl *forClass) { | |
| if (forClass == Target) { | |
| assert(!IsInTargetFields); | |
| IsInTargetFields = true; | |
| Layout.FieldOffsetVector = getNextOffset(); | |
| } | |
| super::noteStartOfFieldOffsets(forClass); | |
| } | |
| void noteEndOfFieldOffsets(ClassDecl *forClass) { | |
| assert(IsInTargetFields == (forClass == Target)); | |
| if (IsInTargetFields) | |
| IsInTargetFields = false; | |
| super::noteEndOfFieldOffsets(forClass); | |
| } | |
| void addFieldOffset(VarDecl *field) { | |
| assert(IsInTargetFields == (field->getDeclContext() == Target)); | |
| if (IsInTargetFields) { | |
| ++Layout.NumImmediateMembers; | |
| Layout.FieldOffsets.try_emplace(field, getNextOffset()); | |
| } | |
| super::addFieldOffset(field); | |
| } | |
| void addDefaultActorStorageFieldOffset() { | |
| if (IsInTargetFields) { | |
| ++Layout.NumImmediateMembers; | |
| } | |
| super::addDefaultActorStorageFieldOffset(); | |
| } | |
| void addFieldOffsetPlaceholders(MissingMemberDecl *placeholder) { | |
| if (placeholder->getDeclContext() == Target) { | |
| Layout.NumImmediateMembers += | |
| placeholder->getNumberOfFieldOffsetVectorEntries(); | |
| } | |
| super::addFieldOffsetPlaceholders(placeholder); | |
| } | |
| void addVTableEntries(ClassDecl *forClass) { | |
| if (forClass == Target) | |
| Layout.VTableOffset = getNextOffset(); | |
| super::addVTableEntries(forClass); | |
| } | |
| void layout() { | |
| super::layout(); | |
| Layout.TheSize = getMetadataSize(); | |
| } | |
| }; | |
| Scanner(IGM, decl, *this).layout(); | |
| } | |
| Size ClassMetadataLayout::getMetadataSizeOffset() const { | |
| assert(MetadataSize.isStatic()); | |
| return MetadataSize.getStaticOffset(); | |
| } | |
| Size ClassMetadataLayout::getMetadataAddressPointOffset() const { | |
| assert(MetadataAddressPoint.isStatic()); | |
| return MetadataAddressPoint.getStaticOffset(); | |
| } | |
| Size ClassMetadataLayout::getInstanceSizeOffset() const { | |
| assert(InstanceSize.isStatic()); | |
| return InstanceSize.getStaticOffset(); | |
| } | |
| Size ClassMetadataLayout::getInstanceAlignMaskOffset() const { | |
| assert(InstanceAlignMask.isStatic()); | |
| return InstanceAlignMask.getStaticOffset(); | |
| } | |
| ClassMetadataLayout::MethodInfo | |
| ClassMetadataLayout::getMethodInfo(IRGenFunction &IGF, SILDeclRef method) const{ | |
| auto &stored = getStoredMethodInfo(method); | |
| switch (stored.TheKind) { | |
| case MethodInfo::Kind::Offset: { | |
| auto offset = emitOffset(IGF, stored.TheOffset); | |
| return MethodInfo(offset); | |
| } | |
| case MethodInfo::Kind::DirectImpl: | |
| return MethodInfo(stored.TheImpl); | |
| } | |
| llvm_unreachable("unhandled method info kind!"); | |
| } | |
| Offset ClassMetadataLayout::getFieldOffset(IRGenFunction &IGF, | |
| VarDecl *field) const { | |
| return emitOffset(IGF, getStoredFieldOffset(field)); | |
| } | |
| Size ClassMetadataLayout::getStaticFieldOffset(VarDecl *field) const { | |
| auto &stored = getStoredFieldOffset(field); | |
| assert(stored.isStatic() && "resilient class metadata layout unsupported!"); | |
| return stored.getStaticOffset(); | |
| } | |
| Size | |
| ClassMetadataLayout::getRelativeGenericRequirementsOffset() const { | |
| return GenericRequirements.getRelativeOffset(); | |
| } | |
| Size | |
| ClassMetadataLayout::getStaticFieldOffsetVectorOffset() const { | |
| return FieldOffsetVector.getStaticOffset(); | |
| } | |
| Size | |
| ClassMetadataLayout::getRelativeFieldOffsetVectorOffset() const { | |
| return FieldOffsetVector.getRelativeOffset(); | |
| } | |
| Size | |
| ClassMetadataLayout::getStaticVTableOffset() const { | |
| return VTableOffset.getStaticOffset(); | |
| } | |
| Size | |
| ClassMetadataLayout::getRelativeVTableOffset() const { | |
| return VTableOffset.getRelativeOffset(); | |
| } | |
| Offset | |
| ClassMetadataLayout::getFieldOffsetVectorOffset(IRGenFunction &IGF) const { | |
| return emitOffset(IGF, FieldOffsetVector); | |
| } | |
| Size irgen::getClassFieldOffsetOffset(IRGenModule &IGM, ClassDecl *theClass, | |
| VarDecl *field) { | |
| if (theClass->getForeignClassKind() == ClassDecl::ForeignKind::CFType) | |
| return Size(); | |
| return IGM.getClassMetadataLayout(theClass).getStaticFieldOffset(field); | |
| } | |
| /// Given a reference to class metadata of the given type, | |
| /// compute the field offset for a stored property. | |
| /// The type must have dependent generic layout. | |
| llvm::Value *irgen::emitClassFieldOffset(IRGenFunction &IGF, | |
| ClassDecl *theClass, | |
| VarDecl *field, | |
| llvm::Value *metadata) { | |
| auto slot = emitAddressOfClassFieldOffset(IGF, metadata, theClass, field); | |
| return IGF.emitInvariantLoad(slot); | |
| } | |
| Address irgen::emitAddressOfClassFieldOffset(IRGenFunction &IGF, | |
| llvm::Value *metadata, | |
| ClassDecl *theClass, | |
| VarDecl *field) { | |
| auto offset = | |
| IGF.IGM.getClassMetadataLayout(theClass).getFieldOffset(IGF, field); | |
| auto slot = IGF.emitAddressAtOffset(metadata, offset, IGF.IGM.SizeTy, | |
| IGF.IGM.getPointerAlignment()); | |
| return slot; | |
| } | |
| Address irgen::emitAddressOfSuperclassRefInClassMetadata(IRGenFunction &IGF, | |
| llvm::Value *metadata) { | |
| // The superclass field in a class type is the first field past the isa. | |
| unsigned index = 1; | |
| Address addr(metadata, IGF.IGM.getPointerAlignment()); | |
| addr = IGF.Builder.CreateElementBitCast(addr, IGF.IGM.TypeMetadataPtrTy); | |
| return IGF.Builder.CreateConstArrayGEP(addr, index, IGF.IGM.getPointerSize()); | |
| } | |
| Size irgen::getStaticTupleElementOffset(IRGenModule &IGM, | |
| SILType tupleType, | |
| unsigned eltIdx) { | |
| assert(tupleType.is<TupleType>() && "not a tuple type"); | |
| struct TupleElementOffsetScanner | |
| : LayoutScanner<TupleElementOffsetScanner, TupleMetadataScanner> { | |
| private: | |
| using super = LayoutScanner; | |
| // 8 seems a reasonable potential max number tuple elements to start with | |
| llvm::SmallVector<Size, 8> Offsets; | |
| public: | |
| TupleElementOffsetScanner(IRGenModule &IGM, TupleType *const tupleType) | |
| : super(IGM, tupleType) {} | |
| void addElement(unsigned eltIdx, const TupleTypeElt &elt) { | |
| Offsets.push_back(NextOffset); | |
| super::addElement(eltIdx, elt); | |
| } | |
| Size getElementOffset(unsigned eltIdx) const { | |
| return Offsets[eltIdx]; | |
| } | |
| }; | |
| TupleElementOffsetScanner s(IGM, tupleType.getAs<TupleType>().getPointer()); | |
| s.layout(); | |
| return s.getElementOffset(eltIdx); | |
| } | |
| /*********************************** ENUMS ************************************/ | |
| EnumMetadataLayout::EnumMetadataLayout(IRGenModule &IGM, EnumDecl *decl) | |
| : NominalMetadataLayout(Kind::Enum, decl) { | |
| struct Scanner : LayoutScanner<Scanner, EnumMetadataScanner> { | |
| using super = LayoutScanner; | |
| EnumMetadataLayout &Layout; | |
| Scanner(IRGenModule &IGM, EnumDecl *decl, EnumMetadataLayout &layout) | |
| : super(IGM, decl), Layout(layout) {} | |
| void noteStartOfTypeSpecificMembers() { | |
| assert(getNextOffset().getStaticOffset() == | |
| IGM.getOffsetOfEnumTypeSpecificMetadataMembers()); | |
| } | |
| void addPayloadSize() { | |
| Layout.PayloadSizeOffset = getNextOffset(); | |
| super::addPayloadSize(); | |
| } | |
| void noteStartOfGenericRequirements() { | |
| Layout.GenericRequirements = getNextOffset(); | |
| super::noteStartOfGenericRequirements(); | |
| } | |
| void addTrailingFlags() { | |
| Layout.TrailingFlagsOffset = getNextOffset(); | |
| super::addTrailingFlags(); | |
| } | |
| void layout() { | |
| super::layout(); | |
| Layout.TheSize = getMetadataSize(); | |
| } | |
| }; | |
| Scanner(IGM, decl, *this).layout(); | |
| } | |
| Offset | |
| EnumMetadataLayout::getPayloadSizeOffset() const { | |
| assert(PayloadSizeOffset.isStatic()); | |
| return Offset(PayloadSizeOffset.getStaticOffset()); | |
| } | |
| Offset EnumMetadataLayout::getTrailingFlagsOffset() const { | |
| assert(TrailingFlagsOffset.isStatic()); | |
| return Offset(TrailingFlagsOffset.getStaticOffset()); | |
| } | |
| /********************************** STRUCTS ***********************************/ | |
| StructMetadataLayout::StructMetadataLayout(IRGenModule &IGM, StructDecl *decl) | |
| : NominalMetadataLayout(Kind::Struct, decl) { | |
| struct Scanner : LayoutScanner<Scanner, StructMetadataScanner> { | |
| using super = LayoutScanner; | |
| StructMetadataLayout &Layout; | |
| Scanner(IRGenModule &IGM, StructDecl *decl, StructMetadataLayout &layout) | |
| : super(IGM, decl), Layout(layout) {} | |
| void noteStartOfTypeSpecificMembers() { | |
| assert(getNextOffset().getStaticOffset() == | |
| IGM.getOffsetOfStructTypeSpecificMetadataMembers()); | |
| } | |
| void noteStartOfGenericRequirements() { | |
| Layout.GenericRequirements = getNextOffset(); | |
| super::noteStartOfGenericRequirements(); | |
| } | |
| void noteStartOfFieldOffsets() { | |
| Layout.FieldOffsetVector = getNextOffset(); | |
| super::noteStartOfFieldOffsets(); | |
| } | |
| void addFieldOffset(VarDecl *field) { | |
| Layout.FieldOffsets.try_emplace(field, getNextOffset()); | |
| super::addFieldOffset(field); | |
| } | |
| void noteEndOfFieldOffsets() { | |
| super::noteEndOfFieldOffsets(); | |
| } | |
| void addTrailingFlags() { | |
| Layout.TrailingFlagsOffset = getNextOffset(); | |
| super::addTrailingFlags(); | |
| } | |
| void layout() { | |
| super::layout(); | |
| Layout.TheSize = getMetadataSize(); | |
| } | |
| }; | |
| Scanner(IGM, decl, *this).layout(); | |
| } | |
| Offset StructMetadataLayout::getFieldOffset(IRGenFunction &IGF, | |
| VarDecl *field) const { | |
| // TODO: implement resilient metadata layout | |
| return Offset(getStaticFieldOffset(field)); | |
| } | |
| Size StructMetadataLayout::getStaticFieldOffset(VarDecl *field) const { | |
| auto &stored = getStoredFieldOffset(field); | |
| assert(stored.isStatic() && "resilient struct metadata layout unsupported!"); | |
| return stored.getStaticOffset(); | |
| } | |
| Offset | |
| StructMetadataLayout::getFieldOffsetVectorOffset() const { | |
| assert(FieldOffsetVector.isStatic()); | |
| return Offset(FieldOffsetVector.getStaticOffset()); | |
| } | |
| Offset | |
| StructMetadataLayout::getTrailingFlagsOffset() const { | |
| assert(TrailingFlagsOffset.isStatic()); | |
| return Offset(TrailingFlagsOffset.getStaticOffset()); | |
| } | |
| /****************************** FOREIGN CLASSES *******************************/ | |
| ForeignClassMetadataLayout::ForeignClassMetadataLayout(IRGenModule &IGM, | |
| ClassDecl *theClass) | |
| : MetadataLayout(Kind::ForeignClass), Class(theClass) { | |
| assert(theClass->getForeignClassKind() == ClassDecl::ForeignKind::CFType && | |
| "Not a foreign class"); | |
| struct Scanner : LayoutScanner<Scanner, ForeignClassMetadataScanner> { | |
| using super = LayoutScanner; | |
| ForeignClassMetadataLayout &Layout; | |
| Scanner(IRGenModule &IGM, ClassDecl *decl, | |
| ForeignClassMetadataLayout &layout) | |
| : super(IGM, decl), Layout(layout) {} | |
| void addSuperclass() { | |
| Layout.SuperClassOffset = getNextOffset(); | |
| super::addSuperclass(); | |
| } | |
| void layout() { | |
| super::layout(); | |
| Layout.TheSize = getMetadataSize(); | |
| } | |
| }; | |
| Scanner(IGM, theClass, *this).layout(); | |
| } |