diff --git a/include/swift/Basic/RelativePointer.h b/include/swift/Basic/RelativePointer.h index 8570d87a691..33681f587d9 100644 --- a/include/swift/Basic/RelativePointer.h +++ b/include/swift/Basic/RelativePointer.h @@ -17,6 +17,114 @@ // unnecessary relocation at dynamic linking time. This header contains types // to help dereference these relative addresses. // +// Theory of references to objects +// ------------------------------- +// +// A reference can be absolute or relative: +// +// - An absolute reference is a pointer to the object. +// +// - A relative reference is a (signed) offset from the address of the +// reference to the address of its direct referent. +// +// A relative reference can be direct, indirect, or symbolic. +// +// In a direct reference, the direct referent is simply the target object. +// Generally, a statically-emitted relative reference can only be direct +// if it can be resolved to a constant offset by the linker, because loaders +// do not support forming relative references. This means that either the +// reference and object must lie within the same linkage unit or the +// difference must be computed at runtime by code. +// +// In a symbolic reference, the direct referent is a string holding the symbol +// name of the object. A relative reference can only be symbolic if the +// object actually has a symbol at runtime, which may require exporting +// many internal symbols that would otherwise be strippable. +// +// In an indirect reference, the direct referent is a variable holding an +// absolute reference to the object. An indirect relative reference may +// refer to an arbitrary symbol, be it anonymous within the linkage unit +// or completely external to it, but it requires the introduction of an +// intermediate absolute reference that requires load-time initialization. +// However, this initialization can be shared among all indirect references +// within the linkage unit, and the linker will generally place all such +// references adjacent to one another to improve load-time locality. +// +// A reference can be made a dynamic union of more than one of these options. +// This allows the compiler/linker to use a direct reference when possible +// and a less-efficient option where required. However, it also requires +// the cases to be dynamically distinguished. This can be done by setting +// a low bit of the offset, as long as the difference between the direct +// referent's address and the reference is a multiple of 2. This works well +// for "indirectable" references because most objects are known to be +// well-aligned, and the cases that aren't (chiefly functions and strings) +// rarely need the flexibility of this kind of reference. It does not +// work quite as well for "possibly symbolic" references because C strings +// are not naturally aligned, and making them aligned generally requires +// moving them out of the linker's ordinary string section; however, it's +// still workable. +// +// Finally, a relative reference can be near or far. A near reference +// is potentially smaller, but it requires the direct referent to lie +// within a certain distance of the reference, even if dynamically +// initialized. +// +// In Swift, we always prefer to use a near direct relative reference +// when it is possible to do so: that is, when the relationship is always +// between two global objects emitted in the same linkage unit, and there +// is no compatibility constraint requiring the use of an absolute reference. +// +// When more flexibility is required, there are several options: +// +// 1. Use an absolute reference. Size penalty on 64-bit. Requires +// load-time work. +// +// 2. Use a far direct relative reference. Size penalty on 64-bit. +// Requires load-time work when object is outside linkage unit. +// Generally not directly supported by loaders. +// +// 3. Use an always-indirect relative reference. Size penalty of one +// pointer (shared). Requires load-time work even when object is +// within linkage unit. +// +// 4. Use a near indirectable relative reference. Size penalty of one +// pointer (shared) when reference exceeds range. Runtime / code-size +// penalty on access. Requires load-time work (shared) only when +// object is outside linkage unit. +// +// 5. Use a far indirectable relative reference. Size penalty on 64-bit. +// Size penalty of one pointer (shared) when reference exceeds range +// and is initialized statically. Runtime / code-size penalty on access. +// Requires load-time work (shared) only when object is outside linkage +// unit. +// +// 6. Use a near or far symbolic relative reference. No load-time work. +// Severe runtime penalty on access. Requires custom logic to statically +// optimize. Requires emission of symbol for target even if private +// to linkage unit. +// +// 7. Use a near or far direct-or-symbolic relative reference. No +// load-time work. Severe runtime penalty on access if object is +// outside of linkage unit. Requires custom logic to statically optimize. +// +// In general, it's our preference in Swift to use option #4 when there +// is no possibility of initializing the reference dynamically and option #5 +// when there is. This is because it is infeasible to actually share the +// memory for the intermediate absolute reference when it must be allocated +// dynamically. +// +// Symbolic references are an interesting idea that we have not yet made +// use of. They may be acceptable in reflective metadata cases where it +// is desireable to heavily bias towards never using the metadata. However, +// they're only profitable if there wasn't any other indirect reference +// to the target, and it is likely that their optimal use requires a more +// intelligent toolchain from top to bottom. +// +// Note that the cost of load-time work also includes a binary-size penalty +// to store the loader metadata necessary to perform that work. Therefore +// it is better to avoid it even when there are dynamic optimizations in +// place to skip the work itself. +// //===----------------------------------------------------------------------===// #ifndef SWIFT_BASIC_RELATIVEPOINTER_H @@ -279,7 +387,8 @@ public: /// A direct relative reference to an aligned object, with an additional /// tiny integer value crammed into its low bits. -template +template class RelativeDirectPointerIntPair { Offset RelativeOffsetPlusInt; @@ -305,9 +414,14 @@ public: using PointerTy = PointeeTy*; PointerTy getPointer() const & { + Offset offset = (RelativeOffsetPlusInt & ~getMask()); + + // Check for null. + if (Nullable && offset == 0) + return nullptr; + // The value is addressed relative to `this`. - uintptr_t absolute = detail::applyRelativeOffset(this, - RelativeOffsetPlusInt & ~getMask()); + uintptr_t absolute = detail::applyRelativeOffset(this, offset); return reinterpret_cast(absolute); } diff --git a/include/swift/Runtime/Metadata.h b/include/swift/Runtime/Metadata.h index 09713ac3f56..c4b5cb2cf68 100644 --- a/include/swift/Runtime/Metadata.h +++ b/include/swift/Runtime/Metadata.h @@ -34,31 +34,6 @@ namespace swift { -/// A bump pointer for metadata allocations. Since metadata is (currently) -/// never released, it does not support deallocation. This allocator by itself -/// is not thread-safe; in concurrent uses, allocations must be guarded by -/// a lock, such as the per-metadata-cache lock used to guard metadata -/// instantiations. All allocations are pointer-aligned. -class MetadataAllocator { - /// Address of the next available space. The allocator grabs a page at a time, - /// so the need for a new page can be determined by page alignment. - /// - /// Initializing to -1 instead of nullptr ensures that the first allocation - /// triggers a page allocation since it will always span a "page" boundary. - char *next = (char*)(~(uintptr_t)0U); - -public: - MetadataAllocator() = default; - - // Don't copy or move, please. - MetadataAllocator(const MetadataAllocator &) = delete; - MetadataAllocator(MetadataAllocator &&) = delete; - MetadataAllocator &operator=(const MetadataAllocator &) = delete; - MetadataAllocator &operator=(MetadataAllocator &&) = delete; - - void *alloc(size_t size); -}; - template struct RuntimeTarget; @@ -90,6 +65,10 @@ struct InProcess { template using FarRelativeDirectPointer = FarRelativeDirectPointer; + + template + using FarRelativeIndirectablePointer = + FarRelativeIndirectablePointer; template using RelativeDirectPointer = RelativeDirectPointer; @@ -118,6 +97,9 @@ struct External { template using FarRelativeDirectPointer = StoredPointer; + + template + using FarRelativeIndirectablePointer = StoredSize; template using RelativeDirectPointer = int32_t; @@ -145,6 +127,10 @@ template using TargetRelativeDirectPointer = typename Runtime::template RelativeDirectPointer; +template +using TargetFarRelativeIndirectablePointer + = typename Runtime::template FarRelativeIndirectablePointer; + struct HeapObject; template struct TargetMetadata; @@ -1480,9 +1466,22 @@ struct TargetNominalTypeDescriptor { }; RelativeDirectPointerIntPair, - NominalTypeKind> + NominalTypeKind, /*Nullable*/ true> GenericMetadataPatternAndKind; + using NonGenericMetadataAccessFunction = const Metadata *(); + + /// A pointer to the metadata access function for this type. + /// + /// The type of the returned function is speculative; in reality, it + /// takes one argument for each of the generic requirements, in the order + /// they are listed. Therefore, the function type is correct only if + /// this type is non-generic. + /// + /// Not all type metadata have access functions. + TargetRelativeDirectPointer AccessFunction; + /// A pointer to the generic metadata pattern that is used to instantiate /// instances of this type. Zero if the type is not generic. TargetGenericMetadata *getGenericMetadataPattern() const { @@ -1490,6 +1489,10 @@ struct TargetNominalTypeDescriptor { GenericMetadataPatternAndKind.getPointer()); } + NonGenericMetadataAccessFunction *getAccessFunction() const { + return AccessFunction.get(); + } + NominalTypeKind getKind() const { return GenericMetadataPatternAndKind.getInt(); } @@ -1928,9 +1931,9 @@ struct TargetValueMetadata : public TargetMetadata { Description; /// The parent type of this member type, or null if this is not a - /// member type. - FarRelativeIndirectablePointer, - /*nullable*/ true> Parent; + /// member type. It's acceptable to make this a direct pointer because + /// parent types are relatively uncommon. + TargetPointer> Parent; static bool classof(const TargetMetadata *metadata) { return metadata->getKind() == MetadataKind::Struct @@ -2778,12 +2781,6 @@ public: using ProtocolConformanceRecord = TargetProtocolConformanceRecord; -/// \brief Fetch a uniqued metadata object for a nominal type with -/// resilient layout. -SWIFT_RUNTIME_EXPORT -extern "C" const Metadata * -swift_getResilientMetadata(GenericMetadata *pattern); - /// \brief Fetch a uniqued metadata object for a generic nominal type. /// /// The basic algorithm for fetching a metadata object is: @@ -3028,11 +3025,16 @@ struct ClassFieldLayout { /// Initialize the field offset vector for a dependent-layout class, using the /// "Universal" layout strategy. +/// +/// This will relocate the metadata if it doesn't have enough space +/// for its superclass. Note that swift_allocateGenericClassMetadata will +/// never produce a metadata that requires relocation. SWIFT_RUNTIME_EXPORT -extern "C" void swift_initClassMetadata_UniversalStrategy(ClassMetadata *self, - size_t numFields, - const ClassFieldLayout *fieldLayouts, - size_t *fieldOffsets); +extern "C" ClassMetadata * +swift_initClassMetadata_UniversalStrategy(ClassMetadata *self, + size_t numFields, + const ClassFieldLayout *fieldLayouts, + size_t *fieldOffsets); /// \brief Fetch a uniqued metadata for a metatype type. SWIFT_RUNTIME_EXPORT diff --git a/include/swift/Runtime/RuntimeFunctions.def b/include/swift/Runtime/RuntimeFunctions.def index afb10f1e65e..a1bce1e027e 100644 --- a/include/swift/Runtime/RuntimeFunctions.def +++ b/include/swift/Runtime/RuntimeFunctions.def @@ -568,12 +568,6 @@ FUNCTION(GetForeignTypeMetadata, swift_getForeignTypeMetadata, DefaultCC, ARGS(TypeMetadataPtrTy), ATTRS(NoUnwind, ReadNone)) // only writes to runtime-private fields -// Metadata *swift_getResilientMetadata(GenericMetadata *pattern); -FUNCTION(GetResilientMetadata, swift_getResilientMetadata, DefaultCC, - RETURNS(TypeMetadataPtrTy), - ARGS(TypeMetadataPatternPtrTy), - ATTRS(NoUnwind, ReadOnly)) - // Metadata *swift_getGenericMetadata(GenericMetadata *pattern, // const void *arguments); FUNCTION(GetGenericMetadata, swift_getGenericMetadata, RegisterPreservingCC, @@ -664,13 +658,13 @@ FUNCTION(GetExistentialMetadata, ATTRS(NoUnwind, ReadOnly)) // struct FieldInfo { size_t Size; size_t AlignMask; }; -// void swift_initClassMetadata_UniversalStrategy(Metadata *self, -// size_t numFields, -// const FieldInfo *fields, -// size_t *fieldOffsets); +// Metadata *swift_initClassMetadata_UniversalStrategy(Metadata *self, +// size_t numFields, +// const FieldInfo *fields, +// size_t *fieldOffsets); FUNCTION(InitClassMetadataUniversal, swift_initClassMetadata_UniversalStrategy, DefaultCC, - RETURNS(VoidTy), + RETURNS(TypeMetadataPtrTy), ARGS(TypeMetadataPtrTy, SizeTy, SizeTy->getPointerTo(), SizeTy->getPointerTo()), @@ -934,10 +928,6 @@ FUNCTION(RegisterTypeMetadataRecords, ARGS(TypeMetadataRecordPtrTy, TypeMetadataRecordPtrTy), ATTRS(NoUnwind)) -FUNCTION(InitializeSuperclass, swift_initializeSuperclass, DefaultCC, - RETURNS(VoidTy), - ARGS(TypeMetadataPtrTy, Int1Ty), - ATTRS(NoUnwind)) FUNCTION(InstantiateObjCClass, swift_instantiateObjCClass, DefaultCC, RETURNS(VoidTy), ARGS(TypeMetadataPtrTy), diff --git a/lib/IRGen/ClassMetadataLayout.h b/lib/IRGen/ClassMetadataLayout.h index 39a3347459a..f87f5d8b784 100644 --- a/lib/IRGen/ClassMetadataLayout.h +++ b/lib/IRGen/ClassMetadataLayout.h @@ -95,7 +95,7 @@ private: // Add a reference to the parent class, if applicable. if (theClass->getDeclContext()->isTypeContext()) { - asImpl().addParentMetadataRef(theClass); + asImpl().addParentMetadataRef(theClass, type); } // Add space for the generic parameters, if applicable. @@ -232,7 +232,7 @@ public: void addIVarDestroyer() { addPointer(); } void addValueWitnessTable() { addPointer(); } void addDestructorFunction() { addPointer(); } - void addParentMetadataRef(ClassDecl *forClass) { addPointer(); } + void addParentMetadataRef(ClassDecl *forClass, Type classType) {addPointer();} void addSuperClass() { addPointer(); } void addClassFlags() { addInt32(); } void addInstanceAddressPoint() { addInt32(); } diff --git a/lib/IRGen/ConstantBuilder.h b/lib/IRGen/ConstantBuilder.h index c6ee1c29c14..2fbdb1bc2ce 100644 --- a/lib/IRGen/ConstantBuilder.h +++ b/lib/IRGen/ConstantBuilder.h @@ -72,37 +72,48 @@ protected: relativeAddressBase = base; } - llvm::Constant *getRelativeAddressFromNextField(llvm::Constant *referent, - llvm::IntegerType *addressTy = nullptr) { + llvm::Constant *getRelativeAddressFromNextField(ConstantReference referent, + llvm::IntegerType *addressTy) { assert(relativeAddressBase && "no relative address base set"); - if (!addressTy) - addressTy = IGM.RelativeAddressTy; // Determine the address of the next field in the initializer. llvm::Constant *fieldAddr = - llvm::ConstantExpr::getPtrToInt(relativeAddressBase, IGM.SizeTy); + llvm::ConstantExpr::getPtrToInt(relativeAddressBase, IGM.IntPtrTy); fieldAddr = llvm::ConstantExpr::getAdd(fieldAddr, llvm::ConstantInt::get(IGM.SizeTy, getNextOffset().getValue())); - referent = llvm::ConstantExpr::getPtrToInt(referent, IGM.SizeTy); + llvm::Constant *referentValue = + llvm::ConstantExpr::getPtrToInt(referent.getValue(), IGM.IntPtrTy); llvm::Constant *relative - = llvm::ConstantExpr::getSub(referent, fieldAddr); - + = llvm::ConstantExpr::getSub(referentValue, fieldAddr); + if (relative->getType() != addressTy) relative = llvm::ConstantExpr::getTrunc(relative, addressTy); + + if (referent.isIndirect()) { + relative = llvm::ConstantExpr::getAdd(relative, + llvm::ConstantInt::get(addressTy, 1)); + } + return relative; } /// Add a 32-bit relative address from the current location in the local /// being built to another global variable. void addRelativeAddress(llvm::Constant *referent) { - addInt32(getRelativeAddressFromNextField(referent)); + addRelativeAddress({referent, ConstantReference::Direct}); + } + void addRelativeAddress(ConstantReference referent) { + addInt32(getRelativeAddressFromNextField(referent, IGM.RelativeAddressTy)); } /// Add a pointer-sized relative address from the current location in the /// local being built to another global variable. void addFarRelativeAddress(llvm::Constant *referent) { + addFarRelativeAddress({referent, ConstantReference::Direct}); + } + void addFarRelativeAddress(ConstantReference referent) { addWord(getRelativeAddressFromNextField(referent, IGM.FarRelativeAddressTy)); } @@ -111,6 +122,9 @@ protected: /// being built to another global variable, or null if a null referent /// is passed. void addRelativeAddressOrNull(llvm::Constant *referent) { + addRelativeAddressOrNull({referent, ConstantReference::Direct}); + } + void addRelativeAddressOrNull(ConstantReference referent) { if (referent) addRelativeAddress(referent); else @@ -121,6 +135,9 @@ protected: /// local being built to another global variable, or null if a null referent /// is passed. void addFarRelativeAddressOrNull(llvm::Constant *referent) { + addFarRelativeAddressOrNull({referent, ConstantReference::Direct}); + } + void addFarRelativeAddressOrNull(ConstantReference referent) { if (referent) addFarRelativeAddress(referent); else @@ -133,7 +150,9 @@ protected: void addRelativeAddressWithTag(llvm::Constant *referent, unsigned tag) { assert(tag < 4 && "tag too big to pack in relative address"); - llvm::Constant *relativeAddr = getRelativeAddressFromNextField(referent); + llvm::Constant *relativeAddr = + getRelativeAddressFromNextField({referent, ConstantReference::Direct}, + IGM.RelativeAddressTy); relativeAddr = llvm::ConstantExpr::getAdd(relativeAddr, llvm::ConstantInt::get(IGM.RelativeAddressTy, tag)); addInt32(relativeAddr); diff --git a/lib/IRGen/GenCast.cpp b/lib/IRGen/GenCast.cpp index a9b5e1fa842..508e8deb300 100644 --- a/lib/IRGen/GenCast.cpp +++ b/lib/IRGen/GenCast.cpp @@ -104,8 +104,9 @@ FailableCastResult irgen::emitClassIdenticalCast(IRGenFunction &IGF, // TODO: use ObjC class references llvm::Value *targetMetadata; if (allowConservative && - (targetMetadata = tryEmitConstantTypeMetadataRef(IGF.IGM, - toType.getSwiftRValueType()))) { + (targetMetadata = + tryEmitConstantHeapMetadataRef(IGF.IGM, toType.getSwiftRValueType(), + /*allowUninitialized*/ true))) { // ok } else { targetMetadata diff --git a/lib/IRGen/GenClass.cpp b/lib/IRGen/GenClass.cpp index f147d36e7e0..3fcc480230a 100644 --- a/lib/IRGen/GenClass.cpp +++ b/lib/IRGen/GenClass.cpp @@ -168,10 +168,15 @@ namespace { unsigned NumInherited = 0; - // Does the class require a metadata template? This will be true if - // the class or any of its ancestors have generic parameters, or if - // any of the below conditions are false. - bool ClassHasMetadataPattern = false; + // Does the class metadata require dynamic initialization above and + // beond what the runtime can automatically achieve? + // + // This is true if the class or any of its ancestors: + // - is generic, + // - is resilient, + // - has a parent type which isn't emittable as a constant, + // - or has a field with resilient layout. + bool ClassMetadataRequiresDynamicInitialization = false; // Does the superclass have a fixed number of stored properties? // If not, and the class has generally-dependent layout, we have to @@ -217,7 +222,8 @@ namespace { fieldLayout.InheritedStoredProperties = inheritedStoredProps; fieldLayout.AllFieldAccesses = IGM.Context.AllocateCopy(AllFieldAccesses); fieldLayout.MetadataAccess = MetadataAccess; - fieldLayout.HasMetadataPattern = ClassHasMetadataPattern; + fieldLayout.MetadataRequiresDynamicInitialization = + ClassMetadataRequiresDynamicInitialization; return fieldLayout; } @@ -225,7 +231,17 @@ namespace { void addFieldsForClass(ClassDecl *theClass, SILType classType) { if (theClass->isGenericContext()) - ClassHasMetadataPattern = true; + ClassMetadataRequiresDynamicInitialization = true; + + if (!ClassMetadataRequiresDynamicInitialization) { + if (auto parentType = + theClass->getDeclContext()->getDeclaredTypeInContext()) { + if (!tryEmitConstantTypeMetadataRef(IGM, + parentType->getCanonicalType(), + SymbolReferenceKind::Absolute)) + ClassMetadataRequiresDynamicInitialization = true; + } + } if (theClass->hasSuperclass()) { // TODO: apply substitutions when computing base-class layouts! @@ -247,7 +263,7 @@ namespace { } else if (IGM.isResilient(superclass, ResilienceExpansion::Maximal)) { // If the superclass is resilient, the number of stored properties // is not known at compile time. - ClassHasMetadataPattern = true; + ClassMetadataRequiresDynamicInitialization = true; ClassHasFixedFieldCount = false; ClassHasFixedSize = false; @@ -281,7 +297,7 @@ namespace { auto &eltType = IGM.getTypeInfo(type); if (!eltType.isFixedSize()) { - ClassHasMetadataPattern = true; + ClassMetadataRequiresDynamicInitialization = true; ClassHasFixedSize = false; if (type.hasArchetype()) @@ -839,11 +855,19 @@ namespace { } } + llvm::Constant *getMetaclassRefOrNull(ClassDecl *theClass) { + if (theClass->isGenericContext()) { + return llvm::ConstantPointerNull::get(IGM.ObjCClassPtrTy); + } else { + return IGM.getAddrOfMetaclassObject(theClass, NotForDefinition); + } + } + void buildMetaclassStub() { assert(Layout && "can't build a metaclass from a category"); // The isa is the metaclass pointer for the root class. auto rootClass = getRootClassForMetaclass(IGM, TheEntity.get()); - auto rootPtr = IGM.getAddrOfMetaclassObject(rootClass, NotForDefinition); + auto rootPtr = getMetaclassRefOrNull(rootClass); // The superclass of the metaclass is the metaclass of the // superclass. Note that for metaclass stubs, we can always @@ -854,11 +878,10 @@ namespace { llvm::Constant *superPtr; if (getClass()->hasSuperclass()) { auto base = getClass()->getSuperclass()->getClassOrBoundGenericClass(); - superPtr = IGM.getAddrOfMetaclassObject(base, NotForDefinition); + superPtr = getMetaclassRefOrNull(base); } else { - superPtr = IGM.getAddrOfMetaclassObject( - IGM.getObjCRuntimeBaseForSwiftRootClass(getClass()), - NotForDefinition); + superPtr = getMetaclassRefOrNull( + IGM.getObjCRuntimeBaseForSwiftRootClass(getClass())); } auto dataPtr = emitROData(ForMetaClass); @@ -904,7 +927,8 @@ namespace { fields.push_back(IGM.getAddrOfObjCClass(getClass(), NotForDefinition)); else { auto type = getSelfType(getClass()).getSwiftRValueType(); - llvm::Constant *metadata = tryEmitConstantTypeMetadataRef(IGM, type); + llvm::Constant *metadata = + tryEmitConstantHeapMetadataRef(IGM, type, /*allowUninit*/ true); assert(metadata && "extended objc class doesn't have constant metadata?"); fields.push_back(metadata); @@ -1823,10 +1847,12 @@ ClassDecl *irgen::getRootClassForMetaclass(IRGenModule &IGM, ClassDecl *C) { IGM.Context.Id_SwiftObject); } -bool irgen::getClassHasMetadataPattern(IRGenModule &IGM, ClassDecl *theClass) { - // Classes imported from Objective-C never have a metadata pattern. +bool irgen::doesClassMetadataRequireDynamicInitialization(IRGenModule &IGM, + ClassDecl *theClass) { + // Classes imported from Objective-C never requires dynamic initialization. if (theClass->hasClangNode()) return false; - return getSelfTypeInfo(IGM, theClass).getClassLayout(IGM).HasMetadataPattern; + auto &layout = getSelfTypeInfo(IGM, theClass).getClassLayout(IGM); + return layout.MetadataRequiresDynamicInitialization; } diff --git a/lib/IRGen/GenClass.h b/lib/IRGen/GenClass.h index 83645ee5761..41b1870411e 100644 --- a/lib/IRGen/GenClass.h +++ b/lib/IRGen/GenClass.h @@ -112,7 +112,11 @@ namespace irgen { ClassDecl *getRootClassForMetaclass(IRGenModule &IGM, ClassDecl *theClass); - bool getClassHasMetadataPattern(IRGenModule &IGM, ClassDecl *theClass); + /// Does the class metadata for the given class require dynamic + /// initialization beyond what can be achieved automatically by + /// the runtime? + bool doesClassMetadataRequireDynamicInitialization(IRGenModule &IGM, + ClassDecl *theClass); } // end namespace irgen } // end namespace swift diff --git a/lib/IRGen/GenDecl.cpp b/lib/IRGen/GenDecl.cpp index e88ba83180b..15c06b63ffd 100644 --- a/lib/IRGen/GenDecl.cpp +++ b/lib/IRGen/GenDecl.cpp @@ -105,7 +105,8 @@ public: class_addProtocol = IGM.getClassAddProtocolFn(); CanType origTy = ext->getDeclaredTypeOfContext()->getCanonicalType(); - classMetadata = tryEmitConstantTypeMetadataRef(IGM, origTy); + classMetadata = + tryEmitConstantHeapMetadataRef(IGM, origTy, /*allowUninit*/ true); assert(classMetadata && "extended objc class doesn't have constant metadata?!"); classMetadata = llvm::ConstantExpr::getBitCast(classMetadata, @@ -1698,6 +1699,42 @@ static llvm::Constant *getElementBitCast(llvm::Constant *ptr, } } +/// Return a reference to an object that's suitable for being used for +/// the given kind of reference. +/// +/// Note that, if the requested reference kind is a relative reference. +/// the returned constant will not actually be a relative reference. +/// To form the actual relative reference, you must pass the returned +/// result to emitRelativeReference, passing the correct base-address +/// information. +ConstantReference +IRGenModule::getAddrOfLLVMVariable(LinkEntity entity, Alignment alignment, + llvm::Type *definitionType, + llvm::Type *defaultType, + DebugTypeInfo debugType, + SymbolReferenceKind refKind) { + switch (refKind) { + case SymbolReferenceKind::Relative_Direct: + case SymbolReferenceKind::Far_Relative_Direct: + assert(definitionType == nullptr); + // FIXME: don't just fall through; force the creation of a weak + // definition so that we can emit a relative reference. + SWIFT_FALLTHROUGH; + + case SymbolReferenceKind::Absolute: + return { getAddrOfLLVMVariable(entity, alignment, definitionType, + defaultType, debugType), + ConstantReference::Direct }; + + + case SymbolReferenceKind::Relative_Indirectable: + case SymbolReferenceKind::Far_Relative_Indirectable: + assert(definitionType == nullptr); + return getAddrOfLLVMVariableOrGOTEquivalent(entity, alignment, defaultType); + } + llvm_unreachable("bad reference kind"); +} + /// A convenient wrapper around getAddrOfLLVMVariable which uses the /// default type as the definition type. llvm::Constant * @@ -1799,7 +1836,7 @@ IRGenModule::getAddrOfLLVMVariable(LinkEntity entity, Alignment alignment, /// Creates a private, unnamed constant containing the address of another /// global variable. LLVM can replace relative references to this variable with /// relative references to the GOT entry for the variable in the object file. -std::pair +ConstantReference IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity, Alignment alignment, llvm::Type *defaultType) { @@ -1843,12 +1880,12 @@ IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity, // aliasee to work around that. if (auto alias = dyn_cast(entry)) entry = alias->getAliasee(); - return {entry, DirectOrGOT::Direct}; + return {entry, ConstantReference::Direct}; } auto &gotEntry = GlobalGOTEquivalents[entity]; if (gotEntry) { - return {gotEntry, DirectOrGOT::GOT}; + return {gotEntry, ConstantReference::Indirect}; } // Look up the global variable. @@ -1859,35 +1896,7 @@ IRGenModule::getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity, entity.mangle(name); auto gotEquivalent = createGOTEquivalent(*this, global, name); gotEntry = gotEquivalent; - return {gotEquivalent, DirectOrGOT::GOT}; -} - -/// If true, we lazily initialize metadata at runtime because the layout -/// is only partially known. Otherwise, we can emit a direct reference a -/// constant metadata symbol. -bool -IRGenModule::hasMetadataPattern(NominalTypeDecl *theDecl) { - assert(theDecl != nullptr); - // Protocols must be special-cased in a few places. - assert(!isa(theDecl)); - - // For classes, we already computed this when we did the layout. - // FIXME: Try not to call this for classes of other modules, by referencing - // the metadata accessor instead. - if (auto *theClass = dyn_cast(theDecl)) - return irgen::getClassHasMetadataPattern(*this, theClass); - - // Ok, we have a value type. If it is generic, it is always initialized - // at runtime. - if (theDecl->isGenericContext()) - return true; - - // If the type is not fixed-size, its size depends on resilient types, - // and the metadata is initialized at runtime. - if (!getTypeInfoForUnlowered(theDecl->getDeclaredType()).isFixedSize()) - return true; - - return false; + return {gotEquivalent, ConstantReference::Indirect}; } namespace { @@ -1905,16 +1914,16 @@ getTypeEntityInfo(IRGenModule &IGM, CanType conformingType) { llvm::Type *defaultTy, *defaultPtrTy; auto nom = conformingType->getAnyNominal(); - if (IGM.hasMetadataPattern(nom)) { - // Conformances for generics, concrete subclasses of generics, and - // resiliently-sized types are represented by referencing the - // nominal type descriptor. + auto clas = dyn_cast(nom); + if (nom->isGenericContext() || + (clas && doesClassMetadataRequireDynamicInitialization(IGM, clas))) { + // Conformances for generics and concrete subclasses of generics + // are represented by referencing the nominal type descriptor. typeKind = TypeMetadataRecordKind::UniqueNominalTypeDescriptor; entity = LinkEntity::forNominalTypeDescriptor(nom); defaultTy = IGM.NominalTypeDescriptorTy; defaultPtrTy = IGM.NominalTypeDescriptorPtrTy; - } else if (auto ct = dyn_cast(conformingType)) { - auto clas = ct->getDecl(); + } else if (clas) { if (clas->isForeign()) { typeKind = TypeMetadataRecordKind::NonuniqueDirectType; entity = LinkEntity::forForeignTypeMetadataCandidate(conformingType); @@ -1963,17 +1972,16 @@ getTypeEntityInfo(IRGenModule &IGM, CanType conformingType) { /// Form an LLVM constant for the relative distance between a reference /// (appearing at gep (0, indices) of `base`) and `target`. llvm::Constant * -IRGenModule::emitRelativeReference(std::pair target, +IRGenModule::emitRelativeReference(ConstantReference target, llvm::Constant *base, ArrayRef baseIndices) { llvm::Constant *relativeAddr = - emitDirectRelativeReference(target.first, base, baseIndices); + emitDirectRelativeReference(target.getValue(), base, baseIndices); - // If the reference is to a GOT entry, flag it by setting the low bit. + // If the reference is indirect, flag it by setting the low bit. // (All of the base, direct target, and GOT entry need to be pointer-aligned // for this to be OK.) - if (target.second == IRGenModule::DirectOrGOT::GOT) { + if (target.isIndirect()) { relativeAddr = llvm::ConstantExpr::getAdd(relativeAddr, llvm::ConstantInt::get(RelativeAddressTy, 1)); } @@ -2068,10 +2076,9 @@ llvm::Constant *IRGenModule::emitProtocolConformances() { // TODO: Produce a relative reference to a private generator function // if the witness table requires lazy initialization, instantiation, or // conditional conformance checking. - std::pair witnessTableRef; auto witnessTableVar = getAddrOfWitnessTable(conformance); - witnessTableRef = std::make_pair(witnessTableVar, - DirectOrGOT::Direct); + auto witnessTableRef = + ConstantReference(witnessTableVar, ConstantReference::Direct); auto typeRef = getAddrOfLLVMVariableOrGOTEquivalent( typeEntity.entity, getPointerAlignment(), typeEntity.defaultTy); @@ -2414,6 +2421,13 @@ llvm::GlobalValue *IRGenModule::defineTypeMetadata(CanType concreteType, /// for a type metadata and it will have type TypeMetadataPtrTy. llvm::Constant *IRGenModule::getAddrOfTypeMetadata(CanType concreteType, bool isPattern) { + return getAddrOfTypeMetadata(concreteType, isPattern, + SymbolReferenceKind::Absolute).getDirectValue(); +} + +ConstantReference IRGenModule::getAddrOfTypeMetadata(CanType concreteType, + bool isPattern, + SymbolReferenceKind refKind) { assert(isPattern || !isa(concreteType)); llvm::Type *defaultVarTy; @@ -2481,13 +2495,13 @@ llvm::Constant *IRGenModule::getAddrOfTypeMetadata(CanType concreteType, 0, 1, nullptr); auto addr = getAddrOfLLVMVariable(entity, alignment, - nullptr, defaultVarTy, DbgTy); + nullptr, defaultVarTy, DbgTy, refKind); // FIXME: MC breaks when emitting alias references on some platforms // (rdar://problem/22450593 ). Work around this by referring to the aliasee // instead. - if (auto alias = dyn_cast(addr)) - addr = alias->getAliasee(); + if (auto alias = dyn_cast(addr.getValue())) + addr = ConstantReference(alias->getAliasee(), addr.isIndirect()); // Adjust if necessary. if (adjustmentIndex) { @@ -2495,8 +2509,10 @@ llvm::Constant *IRGenModule::getAddrOfTypeMetadata(CanType concreteType, llvm::ConstantInt::get(Int32Ty, 0), llvm::ConstantInt::get(Int32Ty, adjustmentIndex) }; - addr = llvm::ConstantExpr::getInBoundsGetElementPtr( - /*Ty=*/nullptr, addr, indices); + addr = ConstantReference( + llvm::ConstantExpr::getInBoundsGetElementPtr( + /*Ty=*/nullptr, addr.getValue(), indices), + addr.isIndirect()); } return addr; diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 1921b023162..1fdc0a0dfff 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -61,12 +61,47 @@ using namespace irgen; static llvm::Value *emitLoadOfObjCHeapMetadataRef(IRGenFunction &IGF, llvm::Value *object); -static llvm::LoadInst * -emitLoadFromMetadataAtIndex(IRGenFunction &IGF, - llvm::Value *metadata, - int index, - llvm::Type *objectTy, - const llvm::Twine &suffix = ""); +static Address emitAddressOfMetadataSlotAtIndex(IRGenFunction &IGF, + llvm::Value *metadata, + int index, + llvm::Type *objectTy) { + // Require the metadata to be some type that we recognize as a + // metadata pointer. + assert(metadata->getType() == IGF.IGM.TypeMetadataPtrTy); + + // We require objectType to be a pointer type so that the GEP will + // scale by the right amount. We could load an arbitrary type using + // some extra bitcasting. + assert(IGF.IGM.DataLayout.getTypeStoreSize(objectTy) == + IGF.IGM.DataLayout.getTypeStoreSize(IGF.IGM.SizeTy)); + + // Cast to T*. + auto objectPtrTy = objectTy->getPointerTo(); + auto metadataWords = IGF.Builder.CreateBitCast(metadata, objectPtrTy); + + auto indexV = llvm::ConstantInt::getSigned(IGF.IGM.SizeTy, index); + + // GEP to the slot. + Address slot(IGF.Builder.CreateInBoundsGEP(metadataWords, indexV), + IGF.IGM.getPointerAlignment()); + + return slot; +} + +/// Emit a load from the given metadata at a constant index. +static llvm::LoadInst *emitLoadFromMetadataAtIndex(IRGenFunction &IGF, + llvm::Value *metadata, + int index, + llvm::Type *objectTy, + const llvm::Twine &suffix = "") { + Address slot = + emitAddressOfMetadataSlotAtIndex(IGF, metadata, index, objectTy); + + // Load. + return IGF.Builder.CreateLoad(slot, metadata->getName() + suffix); +} + +static int getClassParentIndex(IRGenModule &IGM, ClassDecl *classDecl); /// Produce a constant to place in a metatype's isa field /// corresponding to the given metadata kind. @@ -207,22 +242,45 @@ static void emitPolymorphicParametersFromArray(IRGenFunction &IGF, } /// Attempts to return a constant heap metadata reference for a -/// nominal type. -llvm::Constant *irgen::tryEmitConstantTypeMetadataRef(IRGenModule &IGM, - CanType type) { - auto theDecl = type->getAnyNominal(); - assert(theDecl && "emitting constant metadata ref for non-nominal type?"); +/// class type. This is generally only valid for specific kinds of +/// ObjC reference, like superclasses or category references. +llvm::Constant *irgen::tryEmitConstantHeapMetadataRef(IRGenModule &IGM, + CanType type, + bool allowDynamicUninitialized) { + auto theDecl = type->getClassOrBoundGenericClass(); + assert(theDecl && "emitting constant heap metadata ref for non-class type?"); - if (IGM.hasMetadataPattern(theDecl)) + // If the class must not require dynamic initialization --- e.g. if it + // is a super reference --- then respect everything that might impose that. + if (!allowDynamicUninitialized) { + if (doesClassMetadataRequireDynamicInitialization(IGM, theDecl)) + return nullptr; + + // Otherwise, just respect genericity. + } else if (theDecl->isGenericContext()) { return nullptr; + } - if (auto theClass = type->getClassOrBoundGenericClass()) - if (!hasKnownSwiftMetadata(IGM, theClass)) - return IGM.getAddrOfObjCClass(theClass, NotForDefinition); + // For imported classes, use the ObjC class symbol. + // This incidentally cannot coincide with most of the awkward cases, like + // having parent metadata. + if (!hasKnownSwiftMetadata(IGM, theDecl)) + return IGM.getAddrOfObjCClass(theDecl, NotForDefinition); return IGM.getAddrOfTypeMetadata(type, false); } +/// Attempts to return a constant type metadata reference for a +/// nominal type. +ConstantReference +irgen::tryEmitConstantTypeMetadataRef(IRGenModule &IGM, CanType type, + SymbolReferenceKind refKind) { + if (!isTypeMetadataAccessTrivial(IGM, type)) + return ConstantReference(); + + return IGM.getAddrOfTypeMetadata(type, false, refKind); +} + /// Emit a reference to an ObjC class. In general, the only things /// you're allowed to do with the address of an ObjC class symbol are /// (1) send ObjC messages to it (in which case the message will be @@ -357,13 +415,19 @@ bool irgen::isTypeMetadataAccessTrivial(IRGenModule &IGM, CanType type) { // Value type metadata only requires dynamic initialization on first // access if it contains a resilient type. if (isa(type) || isa(type)) { - assert(!type->getAnyNominal()->isGenericContext() && + auto nominalType = cast(type); + assert(!nominalType->getDecl()->isGenericContext() && "shouldn't be called for a generic type"); // Imported type metadata always requires an accessor. - if (type->getAnyNominal()->hasClangNode()) + if (nominalType->getDecl()->hasClangNode()) return false; + // Metadata with a non-trivial parent node always requires an accessor. + if (auto parent = nominalType.getParent()) + if (!isTypeMetadataAccessTrivial(IGM, parent)) + return false; + // Resiliently-sized metadata access always requires an accessor. return (IGM.getTypeInfoForLowered(type).isFixedSize()); } @@ -389,6 +453,27 @@ bool irgen::isTypeMetadataAccessTrivial(IRGenModule &IGM, CanType type) { return false; } +static bool hasRequiredTypeMetadataAccessFunction(IRGenModule &IGM, + NominalTypeDecl *typeDecl) { + // This needs to be kept in sync with getTypeMetadataStrategy. + + if (isa(typeDecl)) + return false; + + switch (getDeclLinkage(typeDecl)) { + case FormalLinkage::PublicUnique: + case FormalLinkage::HiddenUnique: + case FormalLinkage::Private: + return true; + + case FormalLinkage::PublicNonUnique: + case FormalLinkage::HiddenNonUnique: + return false; + } + llvm_unreachable("bad formal linkage"); + +} + /// Return the standard access strategy for getting a non-dependent /// type metadata object. MetadataAccessStrategy @@ -402,6 +487,8 @@ irgen::getTypeMetadataAccessStrategy(IRGenModule &IGM, CanType type) { // Note that while protocol types don't have a metadata pattern, // we still require an accessor since we actually want to get // the metadata for the existential type. + // + // This needs to kept in sync with hasRequiredTypeMetadataAccessPattern. auto nominal = type->getAnyNominal(); if (nominal && !isa(nominal)) { // Metadata accessors for fully-substituted generic types are @@ -926,6 +1013,13 @@ static Address emitAddressOfSuperclassRefInClassMetadata(IRGenFunction &IGF, return IGF.Builder.CreateConstArrayGEP(addr, index, IGF.IGM.getPointerSize()); } +static bool isLoadFrom(llvm::Value *value, Address address) { + if (auto load = dyn_cast(value)) { + return load->getOperand(0) == address.getAddress(); + } + return false; +} + /// Emit the body of a lazy cache accessor. /// /// If cacheVariable is null, we perform the direct access every time. @@ -994,10 +1088,19 @@ void irgen::emitLazyCacheAccessFunction(IRGenModule &IGM, IGF.Builder.emitBlock(isNullBB); llvm::Value *directResult = getValue(IGF); - // Store it back to the cache variable. The direct metadata lookup is - // required to have already dependency-ordered any initialization - // it triggered before loads from the pointer it returned. - IGF.Builder.CreateStore(directResult, cache); + // Store it back to the cache variable. This needs to be a store-release + // because it needs to propagate memory visibility to the other threads + // that can access the cache: the initializing stores might be visible + // to this thread, but they aren't transitively guaranteed to be visible + // to other threads unless this is a store-release. + // + // However, we can skip this if the value was actually loaded from the + // cache. This is a simple, if hacky, peephole that's useful for the + // code in emitInPlaceTypeMetadataAccessFunctionBody. + if (!isLoadFrom(directResult, cache)) { + IGF.Builder.CreateStore(directResult, cache) + ->setAtomic(llvm::Release); + } IGF.Builder.CreateBr(contBB); auto storeBB = IGF.Builder.GetInsertBlock(); @@ -1056,79 +1159,165 @@ static llvm::Value *emitGenericMetadataAccessFunction(IRGenFunction &IGF, } +using InPlaceMetadataInitializer = + llvm::function_ref; + +/// Emit a helper function for swift_once that performs in-place +/// initialization of the given nominal type. +static llvm::Constant * +createInPlaceMetadataInitializationFunction(IRGenModule &IGM, + CanNominalType type, + llvm::Constant *metadata, + llvm::Constant *cacheVariable, + InPlaceMetadataInitializer &&initialize) { + // There's an ignored i8* parameter. + auto fnTy = llvm::FunctionType::get(IGM.VoidTy, {IGM.Int8PtrTy}, + /*variadic*/ false); + llvm::Function *fn = llvm::Function::Create(fnTy, + llvm::GlobalValue::PrivateLinkage, + Twine("initialize_metadata_") + + type->getDecl()->getName().str(), + &IGM.Module); + fn->setAttributes(IGM.constructInitialAttributes()); + + // Set up the function. + IRGenFunction IGF(IGM, fn); + if (IGM.DebugInfo) + IGM.DebugInfo->emitArtificialFunction(IGF, fn); + + // Emit the initialization. + llvm::Value *relocatedMetadata = initialize(IGF, metadata); + + // Store back to the cache variable. + IGF.Builder.CreateStore(relocatedMetadata, + Address(cacheVariable, IGM.getPointerAlignment())) + ->setAtomic(llvm::Release); + + IGF.Builder.CreateRetVoid(); + return fn; +} + +/// Emit the function body for the type metadata accessor of a nominal type +/// that might require in-place initialization. +static llvm::Value * +emitInPlaceTypeMetadataAccessFunctionBody(IRGenFunction &IGF, + CanNominalType type, + llvm::Constant *cacheVariable, + InPlaceMetadataInitializer &&initializer) { + llvm::Constant *metadata = IGF.IGM.getAddrOfTypeMetadata(type, false); + + // We might not have interesting initialization to do. + assert((cacheVariable == nullptr) == + isTypeMetadataAccessTrivial(IGF.IGM, type)); + if (!cacheVariable) + return metadata; + + // Okay, we have non-trivial initialization to do. + // Ensure that we don't have multiple threads racing to do this. + llvm::GlobalVariable *onceGuard = + new llvm::GlobalVariable(IGF.IGM.Module, IGF.IGM.OnceTy, /*constant*/ false, + llvm::GlobalValue::PrivateLinkage, + llvm::Constant::getNullValue(IGF.IGM.OnceTy), + Twine(IGF.CurFn->getName()) + ".once_token"); + + // There's no point in performing the fast-path token check here + // because we've already checked the cache variable. We're just using + // swift_once to guarantee thread safety. + assert(cacheVariable && "lazy initialization but no cache variable"); + + // Create the protected function. swift_once wants this as an i8*. + llvm::Value *onceFn = + createInPlaceMetadataInitializationFunction(IGF.IGM, type, metadata, + cacheVariable, + std::move(initializer)); + onceFn = IGF.Builder.CreateBitCast(onceFn, IGF.IGM.Int8PtrTy); + + auto onceCall = IGF.Builder.CreateCall(IGF.IGM.getOnceFn(), + {onceGuard, onceFn}); + onceCall->setCallingConv(IGF.IGM.DefaultCC); + + // We can just load the cache now. + // TODO: this should be consume-ordered when LLVM supports it. + Address cacheAddr = Address(cacheVariable, IGF.IGM.getPointerAlignment()); + llvm::Value *relocatedMetadata = IGF.Builder.CreateLoad(cacheAddr); + + // emitLazyCacheAccessFunction will see that the value was loaded from + // the guard variable and skip the redundant store back. + return relocatedMetadata; +} + /// Emit the body of a metadata accessor function for the given type. -static llvm::Value *emitMetadataAccessFunction(IRGenFunction &IGF, - CanType type) { - if (auto nominal = type->getAnyNominal()) { - if (nominal->isGenericContext()) { - // This is a metadata accessor for a fully substituted generic type. - assert(!type->hasArchetype() && - "partially substituted types do not have accessors"); - return emitDirectTypeMetadataRef(IGF, type); - } +/// +/// This function is appropriate for ordinary situations where the +/// construction of the metadata value just involves calling idempotent +/// metadata-construction functions. It is not used for the in-place +/// initialization of non-generic nominal type metadata. +static llvm::Value *emitTypeMetadataAccessFunctionBody(IRGenFunction &IGF, + CanType type) { + assert(!type->hasArchetype() && + "cannot emit metadata accessor for context-dependent type"); - // We should not be emitting metadata accessors for types unless - // we have full knowledge of their layout. - assert(!IGF.IGM.isResilient(nominal, ResilienceExpansion::Maximal)); + // We only take this path for That means + // everything except non-generic nominal types. + auto nominalType = dyn_cast(type); + if (!nominalType) + return emitDirectTypeMetadataRef(IGF, type); - // We will still have a metadata pattern if the type is not generic, - // but contains resiliently-sized fields. - bool isPattern = IGF.IGM.hasMetadataPattern(nominal); + auto typeDecl = nominalType->getDecl(); + if (typeDecl->isGenericContext()) { + // This is a metadata accessor for a fully substituted generic type. + return emitDirectTypeMetadataRef(IGF, type); + } - // Non-native Swift classes need to be handled differently. - if (auto classDecl = dyn_cast(nominal)) { - // We emit a completely different pattern for foreign classes. - if (classDecl->isForeign()) { - return emitForeignTypeMetadataRef(IGF, type); - } + // We should never be emitting a metadata accessor for resilient nominal + // types outside of their defining module. We'd only do that anyway for + // types that don't guarantee the existence of a non-unique access + // function, and that should never be true of a resilient type with + // external availability. + // + // (The type might still not have a statically-known layout. It just + // can't be resilient at the top level: we have to know its immediate + // members, or we can't even begin to approach the problem of emitting + // metadata for it.) + assert(!IGF.IGM.isResilient(typeDecl, ResilienceExpansion::Maximal)); - // Classes that might not have Swift metadata use a different - // symbol name. - if (!hasKnownSwiftMetadata(IGF.IGM, classDecl)) { - assert(!classDecl->isGenericContext() && - "ObjC class cannot be generic"); - return emitObjCMetadataRef(IGF, classDecl); - } - - // If this is a class with constant metadata, we still need to - // force ObjC initialization if we're doing Objective-C interop. - if (IGF.IGM.ObjCInterop && !isPattern) { - llvm::Value *metadata = IGF.IGM.getAddrOfTypeMetadata(type, false); - metadata = IGF.Builder.CreateBitCast(metadata, IGF.IGM.ObjCClassPtrTy); - metadata = IGF.Builder.CreateCall(IGF.IGM.getGetInitializedObjCClassFn(), - metadata); - return IGF.Builder.CreateBitCast(metadata, IGF.IGM.TypeMetadataPtrTy); - } - - // Imported value types require foreign metadata uniquing too. - } else if (nominal->hasClangNode()) { + // Non-native types are just wrapped in various ways. + if (auto classDecl = dyn_cast(typeDecl)) { + // We emit a completely different pattern for foreign classes. + if (classDecl->isForeign()) { return emitForeignTypeMetadataRef(IGF, type); } - // If we have a pattern but no generic substitutions, we're just - // doing resilient type layout. - if (isPattern) { - llvm::Constant *getter = IGF.IGM.getGetResilientMetadataFn(); - - llvm::Value *metadata = IGF.IGM.getAddrOfTypeMetadata(type, true); - auto result = IGF.Builder.CreateCall(getter, {metadata}); - result->setDoesNotThrow(); - result->addAttribute(llvm::AttributeSet::FunctionIndex, - llvm::Attribute::ReadNone); - return result; + // Classes that might not have Swift metadata use a different + // symbol name. + if (!hasKnownSwiftMetadata(IGF.IGM, classDecl)) { + assert(!classDecl->isGenericContext() && + "ObjC class cannot be generic"); + return emitObjCMetadataRef(IGF, classDecl); } - // Accessor is trivial, just return pointer to constant metadata. - return IGF.IGM.getAddrOfTypeMetadata(type, false); + // Imported value types require foreign metadata uniquing. + } else if (typeDecl->hasClangNode()) { + return emitForeignTypeMetadataRef(IGF, type); } - return emitDirectTypeMetadataRef(IGF, type); + // Okay, everything else is built from a Swift metadata object. + llvm::Constant *metadata = IGF.IGM.getAddrOfTypeMetadata(type, false); + + // We should not be doing more serious work along this path. + assert(isTypeMetadataAccessTrivial(IGF.IGM, type)); + + return metadata; } +using MetadataAccessGenerator = + llvm::function_ref; + /// Get or create an accessor function to the given non-dependent type. static llvm::Function *getTypeMetadataAccessFunction(IRGenModule &IGM, - CanType type, - ForDefinition_t shouldDefine) { + CanType type, + ForDefinition_t shouldDefine, + MetadataAccessGenerator &&generator) { assert(!type->hasArchetype()); assert(!isa(type)); @@ -1152,12 +1341,25 @@ static llvm::Function *getTypeMetadataAccessFunction(IRGenModule &IGM, emitLazyCacheAccessFunction(IGM, accessor, cacheVariable, [&](IRGenFunction &IGF) -> llvm::Value* { - return emitMetadataAccessFunction(IGF, type); + return generator(IGF, cacheVariable); }); return accessor; } +/// Get or create an accessor function to the given non-dependent type. +static llvm::Function *getTypeMetadataAccessFunction(IRGenModule &IGM, + CanType type, + ForDefinition_t shouldDefine) { + return getTypeMetadataAccessFunction(IGM, type, shouldDefine, + [&](IRGenFunction &IGF, + llvm::Constant *cacheVariable) { + // We should not be called with ForDefinition for nominal types + // that require in-place initialization. + return emitTypeMetadataAccessFunctionBody(IGF, type); + }); +} + /// Get or create an accessor function to the given generic type. static llvm::Function *getGenericTypeMetadataAccessFunction(IRGenModule &IGM, NominalTypeDecl *nominal, @@ -1184,17 +1386,33 @@ static llvm::Function *getGenericTypeMetadataAccessFunction(IRGenModule &IGM, return accessor; } -/// Force a public metadata access function into existence if necessary -/// for the given type. -static void maybeEmitTypeMetadataAccessFunction(IRGenModule &IGM, - NominalTypeDecl *theDecl) { +/// Return the type metadata access function for the given type, if it +/// is guaranteed to exist. +static llvm::Constant * +getRequiredTypeMetadataAccessFunction(IRGenModule &IGM, + NominalTypeDecl *theDecl, + ForDefinition_t shouldDefine) { + if (!hasRequiredTypeMetadataAccessFunction(IGM, theDecl)) + return nullptr; + if (theDecl->isGenericContext()) { - (void) getGenericTypeMetadataAccessFunction(IGM, theDecl, ForDefinition); - return; + return getGenericTypeMetadataAccessFunction(IGM, theDecl, shouldDefine); } CanType declaredType = theDecl->getDeclaredType()->getCanonicalType(); - (void) getTypeMetadataAccessFunction(IGM, declaredType, ForDefinition); + return getTypeMetadataAccessFunction(IGM, declaredType, shouldDefine); +} + +/// Force a public metadata access function into existence if necessary +/// for the given type. +template +static void maybeEmitNominalTypeMetadataAccessFunction(IRGenModule &IGM, + NominalTypeDecl *theDecl, + BuilderTy &builder) { + if (!hasRequiredTypeMetadataAccessFunction(IGM, theDecl)) + return; + + builder.createMetadataAccessFunction(); } /// Emit a call to the type metadata accessor for the given function. @@ -1822,30 +2040,39 @@ namespace { asImpl().addName(); asImpl().addKindDependentFields(); asImpl().addGenericMetadataPatternAndKind(); + asImpl().addAccessFunction(); asImpl().addGenericParams(); } + CanType getAbstractType() { + return asImpl().getTarget()->getDeclaredType()->getCanonicalType(); + } + void addName() { - NominalTypeDecl *ntd = asImpl().getTarget(); - addRelativeAddress(getMangledTypeName(IGM, - ntd->getDeclaredType()->getCanonicalType(), + addRelativeAddress(getMangledTypeName(IGM, getAbstractType(), /*willBeRelativelyAddressed*/ true)); } void addGenericMetadataPatternAndKind() { NominalTypeDecl *ntd = asImpl().getTarget(); auto kind = asImpl().getKind(); - if (!IGM.hasMetadataPattern(ntd)) { + if (!ntd->isGenericContext()) { // There's no pattern to link. addConstantInt32(kind); return; } addRelativeAddressWithTag( - IGM.getAddrOfTypeMetadata(ntd->getDeclaredType()->getCanonicalType(), - /*pattern*/ true), + IGM.getAddrOfTypeMetadata(getAbstractType(), /*pattern*/ true), kind); } + + void addAccessFunction() { + NominalTypeDecl *typeDecl = asImpl().getTarget(); + llvm::Constant *accessFn = + getRequiredTypeMetadataAccessFunction(IGM, typeDecl, NotForDefinition); + addRelativeAddressOrNull(accessFn); + } void addGenericParams() { NominalTypeDecl *ntd = asImpl().getTarget(); @@ -2430,7 +2657,7 @@ irgen::emitFieldTypeAccessor(IRGenModule &IGM, // If the type is not generic, we can use a global variable to cache the // address of the field type vector for the single instance. - if (!type->getGenericParamsOfContext()) { + if (!type->isGenericContext()) { vectorPtr = new llvm::GlobalVariable(*IGM.getModule(), metadataArrayPtrTy, /*constant*/ false, @@ -2519,6 +2746,10 @@ irgen::emitFieldTypeAccessor(IRGenModule &IGM, zero, builtVectorInt, llvm::AtomicOrdering::SequentiallyConsistent, llvm::AtomicOrdering::SequentiallyConsistent); + + // We might have added internal control flow above. + buildBB = IGF.Builder.GetInsertBlock(); + // The pointer in the slot should still have been null. auto didStore = IGF.Builder.CreateExtractValue(raceVectorInt, 1); raceVectorInt = IGF.Builder.CreateExtractValue(raceVectorInt, 0); @@ -2561,6 +2792,7 @@ namespace { CanType Type; Optional Conformance; Size ToOffset; + bool IsRelative; }; SmallVector FillOps; @@ -2575,6 +2807,7 @@ namespace { IRGenModule &IGM = super::IGM; using super::asImpl; + using super::Target; /// Set to true if the metadata record for the generic type has fields /// outside of the generic parameter vector. @@ -2602,7 +2835,7 @@ namespace { llvm::Function *f = llvm::Function::Create(ty, llvm::GlobalValue::PrivateLinkage, llvm::Twine("create_generic_metadata_") - + super::Target->getName().str(), + + Target->getName().str(), &IGM.Module); f->setAttributes(IGM.constructInitialAttributes()); @@ -2615,9 +2848,9 @@ namespace { llvm::Value *args = params.claimNext(); // Bind the generic arguments. - if (super::Target->isGenericContext()) { + if (Target->isGenericContext()) { Address argsArray(args, IGM.getPointerAlignment()); - emitPolymorphicParametersFromArray(IGF, super::Target, argsArray); + emitPolymorphicParametersFromArray(IGF, Target, argsArray); } // Allocate the metadata. @@ -2636,10 +2869,22 @@ namespace { } else { value = IGF.emitTypeMetadataRef(fillOp.Type); } - value = IGF.Builder.CreateBitCast(value, IGM.Int8PtrTy); + auto dest = createPointerSizedGEP(IGF, metadataWords, fillOp.ToOffset - AddressPoint); - IGF.Builder.CreateStore(value, dest); + + // A far relative indirectable pointer. + if (fillOp.IsRelative) { + dest = IGF.Builder.CreateElementBitCast(dest, + IGM.FarRelativeAddressTy); + IGF.emitStoreOfRelativeIndirectablePointer(value, dest, + /*isFar*/ true); + + // A direct pointer. + } else { + value = IGF.Builder.CreateBitCast(value, IGM.Int8PtrTy); + IGF.Builder.CreateStore(value, dest); + } } // Initialize the instantiated dependent value witness table, if we have @@ -2673,8 +2918,17 @@ namespace { return f; } + + void addFillOp(CanType type, Optional conf, + bool isRelative) { + FillOps.push_back({type, conf, getNextOffset(), isRelative }); + } public: + void createMetadataAccessFunction() { + (void) getGenericTypeMetadataAccessFunction(IGM, Target, ForDefinition); + } + void layout() { TemplateHeaderSize = ((NumPrivateDataWords + 1) * IGM.getPointerSize()) + Size(8); @@ -2717,7 +2971,7 @@ namespace { // TODO: ultimately, this should be the number of actual template // arguments, not the number of witness tables required. unsigned numGenericArguments = - GenericArguments::getNumGenericArguments(IGM, super::Target); + GenericArguments::getNumGenericArguments(IGM, Target); headerFields[Field++] = llvm::ConstantInt::get(IGM.Int16Ty, numGenericArguments); @@ -2747,7 +3001,7 @@ namespace { template void addGenericArgument(CanType type, T &&...args) { NumGenericWitnesses++; - FillOps.push_back({ type, None, getNextOffset() }); + addFillOp(type, None, /*relative*/ false); super::addGenericArgument(type, std::forward(args)...); } @@ -2755,7 +3009,7 @@ namespace { void addGenericWitnessTable(CanType type, ProtocolConformanceRef conf, T &&...args) { NumGenericWitnesses++; - FillOps.push_back({ type, conf, getNextOffset() }); + addFillOp(type, conf, /*relative*/ false); super::addGenericWitnessTable(type, conf, std::forward(args)...); } @@ -2791,6 +3045,87 @@ namespace { // Classes +static Address +emitAddressOfFieldOffsetVectorInClassMetadata(IRGenFunction &IGF, + ClassDecl *theClass, + llvm::Value *metadata) { + BEGIN_METADATA_SEARCHER_0(GetOffsetToFieldOffsetVector, Class) + void noteStartOfFieldOffsets(ClassDecl *whichClass) { + if (whichClass == Target) + setTargetOffset(); + } + END_METADATA_SEARCHER() + + auto offset = + GetOffsetToFieldOffsetVector(IGF.IGM, theClass).getTargetOffset(); + + Address addr(metadata, IGF.IGM.getPointerAlignment()); + addr = IGF.Builder.CreateBitCast(addr, + IGF.IGM.SizeTy->getPointerTo()); + return createPointerSizedGEP(IGF, addr, offset); +} + +static llvm::Value *emitInitializeFieldOffsetVector(IRGenFunction &IGF, + ClassDecl *target, + llvm::Value *metadata) { + llvm::Value *fieldVector + = emitAddressOfFieldOffsetVectorInClassMetadata(IGF, target, metadata) + .getAddress(); + + // Collect the stored properties of the type. + llvm::SmallVector storedProperties; + for (auto prop : target->getStoredProperties()) { + storedProperties.push_back(prop); + } + + // Fill out an array with the field type metadata records. + Address fields = IGF.createAlloca( + llvm::ArrayType::get(IGF.IGM.SizeTy, + storedProperties.size() * 2), + IGF.IGM.getPointerAlignment(), "classFields"); + IGF.Builder.CreateLifetimeStart(fields, + IGF.IGM.getPointerSize() * storedProperties.size() * 2); + + Address firstField; + unsigned index = 0; + for (auto prop : storedProperties) { + auto propFormalTy = prop->getType()->getCanonicalType(); + SILType propLoweredTy = IGF.IGM.SILMod->Types.getLoweredType(propFormalTy); + auto &propTI = IGF.getTypeInfo(propLoweredTy); + auto sizeAndAlignMask + = propTI.getSizeAndAlignmentMask(IGF, propLoweredTy); + + llvm::Value *size = sizeAndAlignMask.first; + Address sizeAddr = + IGF.Builder.CreateStructGEP(fields, index, IGF.IGM.getPointerSize()); + IGF.Builder.CreateStore(size, sizeAddr); + if (index == 0) firstField = sizeAddr; + + llvm::Value *alignMask = sizeAndAlignMask.second; + Address alignMaskAddr = + IGF.Builder.CreateStructGEP(fields, index + 1, + IGF.IGM.getPointerSize()); + IGF.Builder.CreateStore(alignMask, alignMaskAddr); + + index += 2; + } + + if (storedProperties.empty()) { + firstField = IGF.Builder.CreateStructGEP(fields, 0, Size(0)); + } + + // Ask the runtime to lay out the class. This can relocate it if it + // wasn't allocated with swift_allocateGenericClassMetadata. + auto numFields = IGF.IGM.getSize(Size(storedProperties.size())); + metadata = IGF.Builder.CreateCall(IGF.IGM.getInitClassMetadataUniversalFn(), + {metadata, numFields, + firstField.getAddress(), fieldVector}); + IGF.Builder.CreateLifetimeEnd(fields, + IGF.IGM.getPointerSize() * storedProperties.size() * 2); + + return metadata; +} + namespace { /// An adapter for laying out class metadata. template @@ -2801,8 +3136,8 @@ namespace { Optional ClassObjectExtents; protected: - IRGenModule &IGM = super::IGM; - ClassDecl * const& Target = super::Target; + using super::IGM; + using super::Target; using super::setRelativeAddressBase; using super::addWord; using super::addConstantWord; @@ -2832,8 +3167,6 @@ namespace { ClassObjectExtents = getSizeOfMetadata(IGM, Target); } - bool HasRuntimeParent = false; - public: /// The 'metadata flags' field in a class is actually a pointer to /// the metaclass object for the class. @@ -2904,18 +3237,9 @@ namespace { } } - void addParentMetadataRef(ClassDecl *forClass) { - // FIXME: this is wrong for multiple levels of generics; we need - // to apply substitutions through. - Type parentType = - forClass->getDeclContext()->getDeclaredTypeInContext(); - if (!addReferenceToType(parentType->getCanonicalType())) - HasRuntimeParent = true; - } - - bool addReferenceToType(CanType type) { + bool addReferenceToHeapMetadata(CanType type, bool allowUninitialized) { if (llvm::Constant *metadata - = tryEmitConstantTypeMetadataRef(IGM, type)) { + = tryEmitConstantHeapMetadataRef(IGM, type, allowUninitialized)) { addWord(metadata); return true; } else { @@ -3104,10 +3428,104 @@ namespace { ClassDecl *forClass) { addWord(llvm::Constant::getNullValue(IGM.WitnessTablePtrTy)); } + + protected: + bool isFinishInitializationIdempotent() { + if (!Layout.isFixedLayout()) + return false; + + if (doesClassMetadataRequireDynamicInitialization(IGM, Target)) + return false; + + return true; + } + + llvm::Value *emitFinishIdempotentInitialization(IRGenFunction &IGF, + llvm::Value *metadata) { + if (IGF.IGM.ObjCInterop) { + metadata = + IGF.Builder.CreateBitCast(metadata, IGF.IGM.ObjCClassPtrTy); + metadata = + IGF.Builder.CreateCall(IGF.IGM.getGetInitializedObjCClassFn(), + metadata); + metadata = + IGF.Builder.CreateBitCast(metadata, IGF.IGM.TypeMetadataPtrTy); + } + return metadata; + } + + llvm::Value *emitFinishInitializationOfClassMetadata(IRGenFunction &IGF, + llvm::Value *metadata) { + // We assume that we've already filled in the class's generic arguments. + // We need to: + // - relocate the metadata to accomodate the superclass, + // if something in our hierarchy is resilient to us; + // - fill out the subclass's field offset vector, if its layout + // wasn't fixed; + // - copy field offsets and generic arguments from higher in the + // class hierarchy, if + // - copy the superclass data, if there are generic arguments + // or field offset vectors there that weren't filled in; + // - populate the field offset vector, if layout isn't fixed, and + // - register the class with the ObjC runtime, if ObjC interop is + // enabled. + // + // emitInitializeFieldOffsetVector will do everything in the full case. + if (doesClassMetadataRequireDynamicInitialization(IGF.IGM, Target)) { + metadata = emitInitializeFieldOffsetVector(IGF, Target, metadata); + + // TODO: do something intermediate when e.g. all we needed to do was + // set parent metadata pointers. + + // Otherwise, all we need to do is register with the ObjC runtime. + } else { + metadata = emitFinishIdempotentInitialization(IGF, metadata); + } + + // Realizing the class with the ObjC runtime will copy back to the + // field offset globals for us; but if ObjC interop is disabled, we + // have to do that ourselves, assuming we didn't just emit them all + // correctly in the first place. + if (!Layout.isFixedLayout() && !IGF.IGM.ObjCInterop) + emitInitializeFieldOffsets(IGF, metadata); + + return metadata; + } + + // The Objective-C runtime will copy field offsets from the field offset + // vector into field offset globals for us, if present. If there's no + // Objective-C runtime, we have to do this ourselves. + void emitInitializeFieldOffsets(IRGenFunction &IGF, + llvm::Value *metadata) { + unsigned index = FieldLayout.InheritedStoredProperties.size(); + + for (auto prop : Target->getStoredProperties()) { + auto access = FieldLayout.AllFieldAccesses[index]; + if (access == FieldAccess::NonConstantDirect) { + Address offsetA = IGF.IGM.getAddrOfFieldOffset(prop, + /*indirect*/ false, + ForDefinition); + + // We can't use emitClassFieldOffset() here because that creates + // an invariant load, which could be hoisted above the point + // where the metadata becomes fully initialized + Size offset = getClassFieldOffset(IGF.IGM, Target, prop); + int index = IGF.IGM.getOffsetInWords(offset); + auto offsetVal = emitLoadFromMetadataAtIndex(IGF, metadata, index, + IGF.IGM.SizeTy); + IGF.Builder.CreateStore(offsetVal, offsetA); + } + + index++; + } + } }; class ClassMetadataBuilder : public ClassMetadataBuilderBase { + + bool HasUnfilledSuperclass = false; + bool HasUnfilledParent = false; public: ClassMetadataBuilder(IRGenModule &IGM, ClassDecl *theClass, const StructLayout &layout, @@ -3115,13 +3533,6 @@ namespace { llvm::GlobalVariable *relativeAddressBase) : ClassMetadataBuilderBase(IGM, theClass, layout, fieldLayout, relativeAddressBase) { - - assert(layout.isFixedLayout() && - "non-fixed layout classes require a template"); - // FIXME: Distinguish Objective-C sliding from resilient layout - assert((fieldLayout.MetadataAccess == FieldAccess::ConstantDirect || - fieldLayout.MetadataAccess == FieldAccess::NonConstantDirect) && - "resilient superclasses require a template"); } llvm::Constant *getInit() { @@ -3151,32 +3562,101 @@ namespace { = ArchetypeBuilder::mapTypeIntoContext(Target, Target->getSuperclass()); - bool constantSuperclass = - addReferenceToType(superclassTy->getCanonicalType()); - assert(constantSuperclass && "need template if superclass is dependent"); - (void) constantSuperclass; + if (!addReferenceToHeapMetadata(superclassTy->getCanonicalType(), + /*allowUninit*/ false)) { + HasUnfilledSuperclass = true; + } + } + + void addParentMetadataRef(ClassDecl *forClass, Type classType) { + CanType parentType = classType->getCanonicalType().getNominalParent(); + + if (auto metadata = + tryEmitConstantTypeMetadataRef(IGM, parentType, + SymbolReferenceKind::Absolute)) { + addWord(metadata.getValue()); + } else { + // Leave a null pointer placeholder to be filled by in-place + // initialization. + addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy)); + if (forClass == Target) + HasUnfilledParent = true; + } + } + + bool canBeConstant() { + // TODO: the metadata global can actually be constant in a very + // special case: it's not a pattern, ObjC interoperation isn't + // required, there are no class fields, and there is nothing that + // needs to be runtime-adjusted. + return false; + } + + void createMetadataAccessFunction() { + assert(!Target->isGenericContext()); + auto type =cast(Target->getDeclaredType()->getCanonicalType()); + + (void) getTypeMetadataAccessFunction(IGM, type, ForDefinition, + [&](IRGenFunction &IGF, llvm::Constant *cacheVar) -> llvm::Value* { + // There's an interesting special case where we can do the + // initialization idempotently and thus avoid the need for a lock. + if (!HasUnfilledSuperclass && !HasUnfilledParent && + isFinishInitializationIdempotent()) { + auto type = Target->getDeclaredType()->getCanonicalType(); + auto metadata = + IGF.IGM.getAddrOfTypeMetadata(type, /*pattern*/ false); + return emitFinishIdempotentInitialization(IGF, metadata); + } + + // Otherwise, use the generic path. + return emitInPlaceTypeMetadataAccessFunctionBody(IGF, type, cacheVar, + [&](IRGenFunction &IGF, llvm::Value *metadata) { + return emitInPlaceMetadataInitialization(IGF, type, metadata); + }); + }); + } + + private: + llvm::Value *emitInPlaceMetadataInitialization(IRGenFunction &IGF, + CanClassType type, + llvm::Value *metadata) { + // Many of the things done by generic instantiation are unnecessary here: + // initializing the metaclass pointer + // initializing the ro-data pointer + + // Initialize the superclass if we didn't do so as a constant. + if (HasUnfilledSuperclass) { + auto superclass = type->getSuperclass(nullptr)->getCanonicalType(); + llvm::Value *superclassMetadata = + emitClassHeapMetadataRef(IGF, superclass, + MetadataValueType::TypeMetadata, + /*allowUninit*/ false); + Address superField = + emitAddressOfSuperclassRefInClassMetadata(IGF, metadata); + superField = IGF.Builder.CreateElementBitCast(superField, + IGF.IGM.TypeMetadataPtrTy); + IGF.Builder.CreateStore(superclassMetadata, superField); + } + + // Initialize the class's own parent pointer if it has one and it + // wasn't emitted as a constant. + if (HasUnfilledParent) { + auto parentType = type.getParent(); + assert(parentType); + llvm::Value *parentMetadata = IGF.emitTypeMetadataRef(parentType); + + int index = getClassParentIndex(IGF.IGM, Target); + Address slot = emitAddressOfMetadataSlotAtIndex(IGF, metadata, index, + IGF.IGM.TypeMetadataPtrTy); + IGF.Builder.CreateStore(parentMetadata, slot); + } + + metadata = emitFinishInitializationOfClassMetadata(IGF, metadata); + + return metadata; } }; - Address emitAddressOfFieldOffsetVectorInClassMetadata(IRGenFunction &IGF, - ClassDecl *theClass, - llvm::Value *metadata) { - BEGIN_METADATA_SEARCHER_0(GetOffsetToFieldOffsetVector, Class) - void noteStartOfFieldOffsets(ClassDecl *whichClass) { - if (whichClass == Target) - setTargetOffset(); - } - END_METADATA_SEARCHER() - - auto offset = - GetOffsetToFieldOffsetVector(IGF.IGM, theClass).getTargetOffset(); - - Address addr(metadata, IGF.IGM.getPointerAlignment()); - addr = IGF.Builder.CreateBitCast(addr, - IGF.IGM.SizeTy->getPointerTo()); - return createPointerSizedGEP(IGF, addr, offset); - } - /// A builder for metadata templates. class GenericClassMetadataBuilder : public GenericMetadataBuilderBasegetCanonicalType().getNominalParent(); + this->addFillOp(parentType, None, /*relative*/ false); + addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy)); + } + void addSuperClass() { // Filled in by the runtime. addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy)); @@ -3316,34 +3802,6 @@ namespace { } } - // The Objective-C runtime will copy field offsets from the field offset - // vector into field offset globals for us, if present. If there's no - // Objective-C runtime, we have to do this ourselves. - void emitInitializeFieldOffsets(IRGenFunction &IGF, - llvm::Value *metadata) { - unsigned index = FieldLayout.InheritedStoredProperties.size(); - - for (auto prop : Target->getStoredProperties()) { - auto access = FieldLayout.AllFieldAccesses[index]; - if (access == FieldAccess::NonConstantDirect) { - Address offsetA = IGF.IGM.getAddrOfFieldOffset(prop, - /*indirect*/ false, - ForDefinition); - - // We can't use emitClassFieldOffset() here because that creates - // an invariant load, which could be hoisted above the point - // where the metadata becomes fully initialized - Size offset = getClassFieldOffset(IGF.IGM, Target, prop); - int index = IGF.IGM.getOffsetInWords(offset); - auto offsetVal = emitLoadFromMetadataAtIndex(IGF, metadata, index, - IGF.IGM.SizeTy); - IGF.Builder.CreateStore(offsetVal, offsetA); - } - - index++; - } - } - void emitInitializeMetadata(IRGenFunction &IGF, llvm::Value *metadata, llvm::Value *vwtable) { @@ -3430,86 +3888,10 @@ namespace { metaclassRODataPtr.getAddress(), IGF.IGM.IntPtrTy); IGF.Builder.CreateStore(rodata, rodataPtrSlot); } - - // If we have fields that are not fixed-size, ask the runtime to - // populate the offset vector. - // - // FIXME: if only the superclass is resilient, we can get away - // with sliding field offsets instead of doing the entire layout all - // over again. - if (!Layout.isFixedLayout() || Target->isGenericContext()) { - llvm::Value *fieldVector - = emitAddressOfFieldOffsetVectorInClassMetadata(IGF, - Target, metadata) - .getAddress(); - - // Collect the stored properties of the type. - llvm::SmallVector storedProperties; - for (auto prop : Target->getStoredProperties()) { - storedProperties.push_back(prop); - } - // Fill out an array with the field type metadata records. - Address fields = IGF.createAlloca( - llvm::ArrayType::get(IGF.IGM.SizeTy, - storedProperties.size() * 2), - IGF.IGM.getPointerAlignment(), "classFields"); - IGF.Builder.CreateLifetimeStart(fields, - IGF.IGM.getPointerSize() * storedProperties.size() * 2); - - Address firstField; - unsigned index = 0; - for (auto prop : storedProperties) { - auto propFormalTy = prop->getType()->getCanonicalType(); - SILType propLoweredTy = IGM.SILMod->Types.getLoweredType(propFormalTy); - auto &propTI = IGF.getTypeInfo(propLoweredTy); - auto sizeAndAlignMask - = propTI.getSizeAndAlignmentMask(IGF, propLoweredTy); - - llvm::Value *size = sizeAndAlignMask.first; - Address sizeAddr = - IGF.Builder.CreateStructGEP(fields, index, IGF.IGM.getPointerSize()); - IGF.Builder.CreateStore(size, sizeAddr); - if (index == 0) firstField = sizeAddr; - - llvm::Value *alignMask = sizeAndAlignMask.second; - Address alignMaskAddr = - IGF.Builder.CreateStructGEP(fields, index + 1, - IGF.IGM.getPointerSize()); - IGF.Builder.CreateStore(alignMask, alignMaskAddr); - - index += 2; - } - - if (storedProperties.empty()) { - firstField = IGF.Builder.CreateStructGEP(fields, 0, Size(0)); - } - - // Ask the runtime to lay out the class. - auto numFields = IGF.IGM.getSize(Size(storedProperties.size())); - IGF.Builder.CreateCall(IGF.IGM.getInitClassMetadataUniversalFn(), - {metadata, numFields, - firstField.getAddress(), fieldVector}); - IGF.Builder.CreateLifetimeEnd(fields, - IGF.IGM.getPointerSize() * storedProperties.size() * 2); - - } else { - // If we have any ancestor generic parameters or field offset vectors, - // copy them from the superclass metadata. - auto initFn = IGF.IGM.getInitializeSuperclassFn(); - - bool copyFieldOffsetVectors = false; - if (FieldLayout.MetadataAccess != FieldAccess::ConstantDirect) - copyFieldOffsetVectors = true; - - IGF.Builder.CreateCall(initFn, - {metadata, - llvm::ConstantInt::get(IGF.IGM.Int1Ty, - copyFieldOffsetVectors)}); - } - - if (!IGF.IGM.ObjCInterop) - emitInitializeFieldOffsets(IGF, metadata); + // We can assume that this never relocates the metadata because + // it should have been allocated properly for the class. + (void) emitFinishInitializationOfClassMetadata(IGF, metadata); } }; } @@ -3546,21 +3928,26 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl, // TODO: classes nested within generic types llvm::Constant *init; bool isPattern; - if (IGM.hasMetadataPattern(classDecl)) { + bool canBeConstant; + if (classDecl->isGenericContext()) { GenericClassMetadataBuilder builder(IGM, classDecl, layout, fieldLayout, tempBase.get()); builder.layout(); init = builder.getInit(); isPattern = true; + canBeConstant = false; + + maybeEmitNominalTypeMetadataAccessFunction(IGM, classDecl, builder); } else { ClassMetadataBuilder builder(IGM, classDecl, layout, fieldLayout, tempBase.get()); builder.layout(); init = builder.getInit(); isPattern = false; - } + canBeConstant = builder.canBeConstant(); - maybeEmitTypeMetadataAccessFunction(IGM, classDecl); + maybeEmitNominalTypeMetadataAccessFunction(IGM, classDecl, builder); + } CanType declaredType = classDecl->getDeclaredType()->getCanonicalType(); @@ -3572,14 +3959,12 @@ void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl, section = "__DATA,__objc_data, regular"; auto var = IGM.defineTypeMetadata(declaredType, isIndirect, isPattern, - // TODO: the metadata global can actually be constant in a very - // special case: it's not a pattern, ObjC interoperation isn't - // required, there are no class fields, and there is nothing that - // needs to be runtime-adjusted. - /*isConstant*/ false, init, std::move(tempBase), section); + canBeConstant, init, std::move(tempBase), section); - // Add non-generic classes to the ObjC class list. - if (IGM.ObjCInterop && !isPattern && !isIndirect) { + // Add classes that don't require dynamic initialization to the + // ObjC class list. + if (IGM.ObjCInterop && !isPattern && !isIndirect && + !doesClassMetadataRequireDynamicInitialization(IGM, classDecl)) { // Emit the ObjC class symbol to make the class visible to ObjC. if (classDecl->isObjC()) { emitObjCClassSymbol(IGM, classDecl, var); @@ -3602,36 +3987,6 @@ void IRGenFunction::setDereferenceableLoad(llvm::LoadInst *load, load->setMetadata(IGM.DereferenceableID, sizeNode); } -/// Emit a load from the given metadata at a constant index. -static llvm::LoadInst *emitLoadFromMetadataAtIndex(IRGenFunction &IGF, - llvm::Value *metadata, - int index, - llvm::Type *objectTy, - const llvm::Twine &suffix) { - // Require the metadata to be some type that we recognize as a - // metadata pointer. - assert(metadata->getType() == IGF.IGM.TypeMetadataPtrTy); - - // We require objectType to be a pointer type so that the GEP will - // scale by the right amount. We could load an arbitrary type using - // some extra bitcasting. - assert(IGF.IGM.DataLayout.getTypeStoreSize(objectTy) == - IGF.IGM.DataLayout.getTypeStoreSize(IGF.IGM.SizeTy)); - - // Cast to T*. - auto objectPtrTy = objectTy->getPointerTo(); - auto metadataWords = IGF.Builder.CreateBitCast(metadata, objectPtrTy); - - auto indexV = llvm::ConstantInt::getSigned(IGF.IGM.SizeTy, index); - - // GEP to the slot. - Address slot(IGF.Builder.CreateInBoundsGEP(metadataWords, indexV), - IGF.IGM.getPointerAlignment()); - - // Load. - return IGF.Builder.CreateLoad(slot, metadata->getName() + suffix); -} - /// Emit a load from the given metadata at a constant index. /// /// The load is marked invariant. This function should not be called @@ -3719,13 +4074,22 @@ static llvm::Value *emitLoadOfWitnessTableRefAtIndex(IRGenFunction &IGF, namespace { /// A class for finding the 'parent' index in a class metadata object. BEGIN_METADATA_SEARCHER_0(FindClassParentIndex, Class) - void addParentMetadataRef(ClassDecl *forClass) { + void addParentMetadataRef(ClassDecl *forClass, Type classType) { if (forClass == Target) setTargetOffset(); - super::addParentMetadataRef(forClass); + super::addParentMetadataRef(forClass, classType); } END_METADATA_SEARCHER() } +/// Return the index of the parent metadata pointer for the given class. +static int getClassParentIndex(IRGenModule &IGM, ClassDecl *classDecl) { + assert(classDecl->getDeclContext()->isTypeContext()); + return FindClassParentIndex(IGM, classDecl).getTargetIndex(); +} + +/// In both enums and structs, the parent index is at index 2. +static constexpr int ValueTypeParentIndex = 2; + /// Given a reference to some metadata, derive a reference to the /// type's parent type. llvm::Value *irgen::emitParentMetadataRef(IRGenFunction &IGF, @@ -3744,15 +4108,13 @@ llvm::Value *irgen::emitParentMetadataRef(IRGenFunction &IGF, llvm_unreachable("protocols never have parent types!"); case DeclKind::Class: { - int index = - FindClassParentIndex(IGF.IGM, cast(decl)).getTargetIndex(); + int index = getClassParentIndex(IGF.IGM, cast(decl)); return emitLoadOfMetadataRefAtIndex(IGF, metadata, index); } case DeclKind::Enum: case DeclKind::Struct: - // In both of these cases, 'Parent' is always the third field. - return emitLoadOfMetadataRefAtIndex(IGF, metadata, 2); + return emitLoadOfMetadataRefAtIndex(IGF, metadata, ValueTypeParentIndex); } llvm_unreachable("bad decl kind!"); } @@ -4214,6 +4576,108 @@ llvm::Value *irgen::emitVirtualMethodValue(IRGenFunction &IGF, return emitInvariantLoadFromMetadataAtIndex(IGF, metadata, index, fnTy); } +//===----------------------------------------------------------------------===// +// Value types (structs and enums) +//===----------------------------------------------------------------------===// + +namespace { + template + class ValueTypeMetadataBuilderBase : public ConstantBuilder { + using super = ConstantBuilder; + + protected: + using super::asImpl; + using super::IGM; + using super::Target; + using super::addWord; + + template + ValueTypeMetadataBuilderBase(IRGenModule &IGM, DeclTy *theDecl) + : super(IGM, theDecl) {} + + CanType getParentType() const { + Type parentType = + Target->getDeclContext()->getDeclaredTypeInContext(); + return (parentType ? parentType->getCanonicalType() : CanType()); + } + + public: + void addParentMetadataRef() { + llvm::Constant *parentMetadata = nullptr; + if (auto parentType = getParentType()) { + parentMetadata = + tryEmitConstantTypeMetadataRef(IGM, parentType, + SymbolReferenceKind::Absolute) + .getDirectValue(); + if (!parentMetadata) { + asImpl().flagUnfilledParent(); + } + } + + if (!parentMetadata) + parentMetadata = llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy); + addWord(parentMetadata); + } + }; +} + +static llvm::Value * +emitInPlaceValueTypeMetadataInitialization(IRGenFunction &IGF, + CanNominalType type, + llvm::Value *metadata, + bool hasUnfilledParent) { + // All the value types are basically similar. + assert(isa(type) || isa(type)); + + // Initialize the parent-metadata field if it wasn't done statically. + if (hasUnfilledParent) { + CanType parentType = type.getParent(); + assert(parentType); + + // Value types hold the parent metadata as a far relative + // indirectable pointer. + llvm::Value *parentMetadata = IGF.emitTypeMetadataRef(parentType); + Address addr = + emitAddressOfMetadataSlotAtIndex(IGF, metadata, ValueTypeParentIndex, + IGF.IGM.TypeMetadataPtrTy); + IGF.Builder.CreateStore(parentMetadata, addr); + } + + // Set up the value witness table if it's dependent. + SILType loweredType = IGF.IGM.getLoweredType(AbstractionPattern(type), type); + auto &ti = IGF.IGM.getTypeInfo(loweredType); + if (!ti.isFixedSize()) { + // We assume that that value witness table will already have been written + // into the metadata; just load it. + llvm::Value *vwtable = IGF.emitValueWitnessTableRefForMetadata(metadata); + + // Initialize the metadata. + ti.initializeMetadata(IGF, metadata, vwtable, loweredType.getAddressType()); + } + + return metadata; +} + +/// Create an access function for the type metadata of the given +/// non-generic nominal type. +static void createInPlaceValueTypeMetadataAccessFunction(IRGenModule &IGM, + NominalTypeDecl *typeDecl, + bool hasUnfilledParent) { + assert(!typeDecl->isGenericContext()); + auto type = + cast(typeDecl->getDeclaredType()->getCanonicalType()); + + (void) getTypeMetadataAccessFunction(IGM, type, ForDefinition, + [&](IRGenFunction &IGF, + llvm::Constant *cacheVariable) { + return emitInPlaceTypeMetadataAccessFunctionBody(IGF, type, cacheVariable, + [&](IRGenFunction &IGF, llvm::Value *metadata) { + return emitInPlaceValueTypeMetadataInitialization(IGF, type, metadata, + hasUnfilledParent); + }); + }); +} + //===----------------------------------------------------------------------===// // Structs //===----------------------------------------------------------------------===// @@ -4222,8 +4686,8 @@ namespace { /// An adapter for laying out struct metadata. template class StructMetadataBuilderBase - : public ConstantBuilder> { - using super = ConstantBuilder>; + : public ValueTypeMetadataBuilderBase>{ + using super = ValueTypeMetadataBuilderBase>; protected: using super::IGM; @@ -4251,11 +4715,6 @@ namespace { addFarRelativeAddress(descriptor); } - void addParentMetadataRef() { - // FIXME: populate - addFarRelativeAddressOrNull(nullptr); - } - void addFieldOffset(VarDecl *var) { assert(var->hasStorage() && "storing field offset for computed property?!"); @@ -4289,15 +4748,30 @@ namespace { class StructMetadataBuilder : public StructMetadataBuilderBase { + + bool HasUnfilledParent = false; public: StructMetadataBuilder(IRGenModule &IGM, StructDecl *theStruct, llvm::GlobalVariable *relativeAddressBase) : StructMetadataBuilderBase(IGM, theStruct, relativeAddressBase) {} + void flagUnfilledParent() { + HasUnfilledParent = true; + } + + bool canBeConstant() { + return !HasUnfilledParent; + } + void addValueWitnessTable() { auto type = this->Target->getDeclaredType()->getCanonicalType(); addWord(emitValueWitnessTable(IGM, type)); } + + void createMetadataAccessFunction() { + createInPlaceValueTypeMetadataAccessFunction(IGM, Target, + HasUnfilledParent); + } }; /// Emit a value witness table for a fixed-layout generic type, or a null @@ -4336,6 +4810,15 @@ namespace { {metadataPattern, arguments}); } + void addParentMetadataRef() { + // Override to always use a fill op instead of a relocation. + if (CanType parentType = getParentType()) { + addFillOp(parentType, None, /*relative*/ false); + } + + addConstantWord(0); + } + void addValueWitnessTable() { addWord(getValueWitnessTableForGenericValueType(IGM, Target, HasDependentVWT)); @@ -4371,19 +4854,24 @@ void irgen::emitStructMetadata(IRGenModule &IGM, StructDecl *structDecl) { // TODO: structs nested within generic types llvm::Constant *init; bool isPattern; - if (IGM.hasMetadataPattern(structDecl)) { + bool canBeConstant; + if (structDecl->isGenericContext()) { GenericStructMetadataBuilder builder(IGM, structDecl, tempBase.get()); builder.layout(); init = builder.getInit(); isPattern = true; + canBeConstant = false; + + maybeEmitNominalTypeMetadataAccessFunction(IGM, structDecl, builder); } else { StructMetadataBuilder builder(IGM, structDecl, tempBase.get()); builder.layout(); init = builder.getInit(); isPattern = false; - } + canBeConstant = builder.canBeConstant(); - maybeEmitTypeMetadataAccessFunction(IGM, structDecl); + maybeEmitNominalTypeMetadataAccessFunction(IGM, structDecl, builder); + } CanType declaredType = structDecl->getDeclaredType()->getCanonicalType(); @@ -4391,7 +4879,7 @@ void irgen::emitStructMetadata(IRGenModule &IGM, StructDecl *structDecl) { bool isIndirect = false; IGM.defineTypeMetadata(declaredType, isIndirect, isPattern, - /*isConstant*/!isPattern, init, + canBeConstant, init, std::move(tempBase)); } @@ -4401,9 +4889,8 @@ namespace { template class EnumMetadataBuilderBase - : public ConstantBuilder> -{ - using super = ConstantBuilder>; + : public ValueTypeMetadataBuilderBase> { + using super = ValueTypeMetadataBuilderBase>; protected: using super::IGM; @@ -4431,12 +4918,7 @@ public: addFarRelativeAddress(descriptor); } - - void addParentMetadataRef() { - // FIXME: populate - addFarRelativeAddressOrNull(nullptr); - } - + void addGenericArgument(CanType type) { addWord(llvm::Constant::getNullValue(IGM.TypeMetadataPtrTy)); } @@ -4447,8 +4929,9 @@ public: }; class EnumMetadataBuilder - : public EnumMetadataBuilderBase -{ + : public EnumMetadataBuilderBase { + bool HasUnfilledParent = false; + public: EnumMetadataBuilder(IRGenModule &IGM, EnumDecl *theEnum, llvm::GlobalVariable *relativeAddressBase) @@ -4462,15 +4945,29 @@ public: void addPayloadSize() { auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType(); auto &enumTI = IGM.getTypeInfoForLowered(enumTy); - (void) enumTI; - assert(enumTI.isFixedSize(ResilienceExpansion::Maximal) && - "emitting constant enum metadata for resilient-sized type?"); + if (!enumTI.isFixedSize(ResilienceExpansion::Maximal)) { + addConstantWord(0); + return; + } + assert(!enumTI.isFixedSize(ResilienceExpansion::Minimal) && "non-generic, non-resilient enums don't need payload size in metadata"); - auto &strategy = getEnumImplStrategy(IGM, enumTy); addConstantWord(strategy.getPayloadSizeForMetadata()); } + + void flagUnfilledParent() { + HasUnfilledParent = true; + } + + bool canBeConstant() { + return !HasUnfilledParent; + } + + void createMetadataAccessFunction() { + createInPlaceValueTypeMetadataAccessFunction(IGM, Target, + HasUnfilledParent); + } }; class GenericEnumMetadataBuilder @@ -4488,6 +4985,15 @@ public: return IGF.Builder.CreateCall(IGM.getAllocateGenericValueMetadataFn(), {metadataPattern, arguments}); } + + void addParentMetadataRef() { + // Override to always use a fill op instead of a relocation. + if (CanType parentType = getParentType()) { + addFillOp(parentType, None, /*relative*/ false); + } + + addConstantWord(0); + } void addValueWitnessTable() { addWord(getValueWitnessTableForGenericValueType(IGM, Target, @@ -4536,19 +5042,24 @@ void irgen::emitEnumMetadata(IRGenModule &IGM, EnumDecl *theEnum) { llvm::Constant *init; bool isPattern; - if (IGM.hasMetadataPattern(theEnum)) { + bool canBeConstant; + if (theEnum->isGenericContext()) { GenericEnumMetadataBuilder builder(IGM, theEnum, tempBase.get()); builder.layout(); init = builder.getInit(); isPattern = true; + canBeConstant = false; + + maybeEmitNominalTypeMetadataAccessFunction(IGM, theEnum, builder); } else { EnumMetadataBuilder builder(IGM, theEnum, tempBase.get()); builder.layout(); init = builder.getInit(); isPattern = false; - } + canBeConstant = builder.canBeConstant(); - maybeEmitTypeMetadataAccessFunction(IGM, theEnum); + maybeEmitNominalTypeMetadataAccessFunction(IGM, theEnum, builder); + } CanType declaredType = theEnum->getDeclaredType()->getCanonicalType(); @@ -4718,6 +5229,10 @@ namespace { auto type = this->Target->getDeclaredType()->getCanonicalType(); addWord(emitValueWitnessTable(IGM, type)); } + + void flagUnfilledParent() { + llvm_unreachable("foreign type with parent type metadata?"); + } }; /// A builder for ForeignEnumMetadata. @@ -4745,6 +5260,10 @@ namespace { void addPayloadSize() const { llvm_unreachable("nongeneric enums shouldn't need payload size in metadata"); } + + void flagUnfilledParent() { + llvm_unreachable("foreign type with parent type metadata?"); + } }; } diff --git a/lib/IRGen/GenMeta.h b/lib/IRGen/GenMeta.h index 8a2b6639484..7f61d894103 100644 --- a/lib/IRGen/GenMeta.h +++ b/lib/IRGen/GenMeta.h @@ -39,6 +39,7 @@ namespace swift { namespace irgen { class Callee; + class ConstantReference; class Explosion; class FieldTypeInfo; class GenericTypeRequirements; @@ -46,6 +47,7 @@ namespace irgen { class IRGenModule; class Size; class StructLayout; + enum class SymbolReferenceKind : unsigned char; struct ClassLayout; /// Is the given class known to have Swift-compatible metadata? @@ -79,8 +81,16 @@ namespace irgen { /// Emit a reference to a compile-time constant piece of type metadata, or /// return a null pointer if the type's metadata cannot be represented by a /// constant. - llvm::Constant *tryEmitConstantTypeMetadataRef(IRGenModule &IGM, - CanType type); + ConstantReference tryEmitConstantTypeMetadataRef(IRGenModule &IGM, + CanType type, + SymbolReferenceKind refKind); + + /// Emit a reference to a compile-time constant piece of heap metadata, or + /// return a null pointer if the type's heap metadata cannot be represented + /// by a constant. + llvm::Constant *tryEmitConstantHeapMetadataRef(IRGenModule &IGM, + CanType type, + bool allowUninitialized); enum class MetadataValueType { ObjCClass, TypeMetadata }; diff --git a/lib/IRGen/GenValueWitness.cpp b/lib/IRGen/GenValueWitness.cpp index 747e15e7dbd..8d3b8a31b75 100644 --- a/lib/IRGen/GenValueWitness.cpp +++ b/lib/IRGen/GenValueWitness.cpp @@ -1361,10 +1361,6 @@ llvm::Constant *irgen::emitValueWitnessTable(IRGenModule &IGM, assert(!isa(abstractType) && "emitting VWT for generic instance"); - // We shouldn't emit global value witness tables for non-fixed-layout types. - assert(!hasDependentValueWitnessTable(IGM, abstractType) && - "emitting global VWT for dynamic-layout type"); - SmallVector witnesses; addValueWitnessesForAbstractType(IGM, abstractType, witnesses); diff --git a/lib/IRGen/IRGen.h b/lib/IRGen/IRGen.h index 46b23173c6a..e9ff125414d 100644 --- a/lib/IRGen/IRGen.h +++ b/lib/IRGen/IRGen.h @@ -143,6 +143,55 @@ enum IsExact_t : bool { IsExact = true }; +/// Ways in which an object can be referenced. +/// +/// See the comment in RelativePointer.h. + +enum class SymbolReferenceKind : unsigned char { + /// An absolute reference to the object, i.e. an ordinary pointer. + /// + /// Generally well-suited for when C compatibility is a must, dynamic + /// initialization is the dominant case, or the runtime performance + /// of accesses is an overriding concern. + Absolute, + + /// A direct relative reference to the object, i.e. the offset of the + /// object from the address at which the relative reference is stored. + /// + /// Generally well-suited for when the reference is always statically + /// initialized and will always refer to another object within the + /// same linkage unit. + Relative_Direct, + + /// A direct relative reference that is guaranteed to be as wide as a + /// pointer. + /// + /// Generally well-suited for when the reference may be dynamically + /// initialized, but will only refer to objects within the linkage unit + /// when statically initialized. + Far_Relative_Direct, + + /// A relative reference that may be indirect: the direct reference is + /// either directly to the object or to a variable holding an absolute + /// reference to the object. + /// + /// The low bit of the target offset is used to mark an indirect reference, + /// and so the low bit of the target address must be zero. This means that, + /// in general, it is not possible to form this kind of reference to a + /// function (due to the THUMB bit) or unaligned data (such as a C string). + /// + /// Generally well-suited for when the reference is always statically + /// initialized but may refer to soemthing outside of the linkage unit. + Relative_Indirectable, + + /// An indirectable reference to the object; guaranteed to be as wide + /// as a pointer. + /// + /// Generally well-suited for when the reference may be dynamically + /// initialized but may also statically refer outside of the linkage unit. + Far_Relative_Indirectable, +}; + /// Destructor variants. enum class DestructorKind : uint8_t { /// A deallocating destructor destroys the object and deallocates diff --git a/lib/IRGen/IRGenFunction.cpp b/lib/IRGen/IRGenFunction.cpp index 17a2243e02b..e4d112e8d9f 100644 --- a/lib/IRGen/IRGenFunction.cpp +++ b/lib/IRGen/IRGenFunction.cpp @@ -204,6 +204,73 @@ void IRGenFunction::emitDeallocRawCall(llvm::Value *pointer, {pointer, size, alignMask}); } +/// Initialize a relative indirectable pointer to the given value. +/// This always leaves the value in the direct state; if it's not a +/// far reference, it's the caller's responsibility to ensure that the +/// pointer ranges are sufficient. +void IRGenFunction::emitStoreOfRelativeIndirectablePointer(llvm::Value *value, + Address addr, + bool isFar) { + value = Builder.CreatePtrToInt(value, IGM.IntPtrTy); + auto addrAsInt = + Builder.CreatePtrToInt(addr.getAddress(), IGM.IntPtrTy); + + auto difference = Builder.CreateSub(value, addrAsInt); + if (!isFar) { + difference = Builder.CreateTrunc(difference, IGM.RelativeAddressTy); + } + + Builder.CreateStore(difference, addr); +} + +llvm::Value * +IRGenFunction::emitLoadOfRelativeIndirectablePointer(Address addr, + bool isFar, + llvm::PointerType *expectedType, + const llvm::Twine &name) { + // Load the pointer and turn it back into a pointer. + llvm::Value *value = Builder.CreateLoad(addr); + assert(value->getType() == (isFar ? IGM.FarRelativeAddressTy + : IGM.RelativeAddressTy)); + if (!isFar) { + value = Builder.CreateSExt(value, IGM.IntPtrTy); + } + assert(value->getType() == IGM.IntPtrTy); + + llvm::BasicBlock *origBB = Builder.GetInsertBlock(); + llvm::Value *directResult = Builder.CreateIntToPtr(value, expectedType); + + // Check whether the low bit is set. + llvm::Constant *one = llvm::ConstantInt::get(IGM.IntPtrTy, 1); + llvm::BasicBlock *indirectBB = createBasicBlock("relptr.indirect"); + llvm::BasicBlock *contBB = createBasicBlock("relptr.cont"); + llvm::Value *isIndirect = Builder.CreateAnd(value, one); + isIndirect = Builder.CreateIsNotNull(isIndirect); + Builder.CreateCondBr(isIndirect, indirectBB, contBB); + + // In the indirect block, clear the low bit and perform an additional load. + llvm::Value *indirectResult; { + Builder.emitBlock(indirectBB); + + // Clear the low bit. + llvm::Value *ptr = Builder.CreateSub(value, one); + ptr = Builder.CreateIntToPtr(ptr, expectedType->getPointerTo()); + + // Load. + Address indirectAddr(ptr, IGM.getPointerAlignment()); + indirectResult = Builder.CreateLoad(indirectAddr); + + Builder.CreateBr(contBB); + } + + Builder.emitBlock(contBB); + auto phi = Builder.CreatePHI(expectedType, 2, name); + phi->addIncoming(directResult, origBB); + phi->addIncoming(indirectResult, indirectBB); + + return phi; +} + void IRGenFunction::emitFakeExplosion(const TypeInfo &type, Explosion &explosion) { if (!isa(type)) { diff --git a/lib/IRGen/IRGenFunction.h b/lib/IRGen/IRGenFunction.h index 06f5ebb25e3..cb3e0a3552e 100644 --- a/lib/IRGen/IRGenFunction.h +++ b/lib/IRGen/IRGenFunction.h @@ -140,6 +140,16 @@ public: const TypeInfo &type, const llvm::Twine &name = ""); + void emitStoreOfRelativeIndirectablePointer(llvm::Value *value, + Address addr, + bool isFar); + + llvm::Value * + emitLoadOfRelativeIndirectablePointer(Address addr, bool isFar, + llvm::PointerType *expectedType, + const llvm::Twine &name = ""); + + llvm::Value *emitAllocObjectCall(llvm::Value *metadata, llvm::Value *size, llvm::Value *alignMask, const llvm::Twine &name = ""); diff --git a/lib/IRGen/IRGenModule.h b/lib/IRGen/IRGenModule.h index 98a5debcd86..a5749b0a9eb 100644 --- a/lib/IRGen/IRGenModule.h +++ b/lib/IRGen/IRGenModule.h @@ -31,6 +31,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/IR/CallingConv.h" +#include "llvm/IR/Constant.h" #include "llvm/IR/ValueHandle.h" #include "llvm/IR/Attributes.h" #include "llvm/Target/TargetMachine.h" @@ -305,6 +306,29 @@ private: friend class CurrentIGMPtr; }; +class ConstantReference { +public: + enum Directness : bool { Direct, Indirect }; +private: + llvm::PointerIntPair ValueAndIsIndirect; +public: + ConstantReference() {} + ConstantReference(llvm::Constant *value, Directness isIndirect) + : ValueAndIsIndirect(value, isIndirect) {} + + Directness isIndirect() const { return ValueAndIsIndirect.getInt(); } + llvm::Constant *getValue() const { return ValueAndIsIndirect.getPointer(); } + + llvm::Constant *getDirectValue() const { + assert(!isIndirect()); + return getValue(); + } + + explicit operator bool() const { + return ValueAndIsIndirect.getPointer() != nullptr; + } +}; + /// IRGenModule - Primary class for emitting IR for global declarations. /// class IRGenModule { @@ -797,6 +821,8 @@ public: llvm::StringRef section = {}); llvm::Constant *getAddrOfTypeMetadata(CanType concreteType, bool isPattern); + ConstantReference getAddrOfTypeMetadata(CanType concreteType, bool isPattern, + SymbolReferenceKind kind); llvm::Function *getAddrOfTypeMetadataAccessFunction(CanType type, ForDefinition_t forDefinition); llvm::Function *getAddrOfGenericTypeMetadataAccessFunction( @@ -855,22 +881,16 @@ public: StringRef mangleType(CanType type, SmallVectorImpl &buffer); - bool hasMetadataPattern(NominalTypeDecl *theDecl); - // Get the ArchetypeBuilder for the currently active generic context. Crashes // if there is no generic context. ArchetypeBuilder &getContextArchetypes(); - enum class DirectOrGOT { - Direct, GOT, - }; - - std::pair + ConstantReference getAddrOfLLVMVariableOrGOTEquivalent(LinkEntity entity, Alignment alignment, llvm::Type *defaultType); llvm::Constant * - emitRelativeReference(std::pair target, + emitRelativeReference(ConstantReference target, llvm::Constant *base, ArrayRef baseIndices); @@ -894,6 +914,12 @@ private: ForDefinition_t forDefinition, llvm::Type *defaultType, DebugTypeInfo debugType); + ConstantReference getAddrOfLLVMVariable(LinkEntity entity, + Alignment alignment, + llvm::Type *definitionType, + llvm::Type *defaultType, + DebugTypeInfo debugType, + SymbolReferenceKind refKind); void emitLazyPrivateDefinitions(); void addRuntimeResolvableType(CanType type); diff --git a/lib/IRGen/StructLayout.h b/lib/IRGen/StructLayout.h index 12335a0254a..c8454e5ea6b 100644 --- a/lib/IRGen/StructLayout.h +++ b/lib/IRGen/StructLayout.h @@ -416,8 +416,8 @@ struct ClassLayout { /// Lazily-initialized metadata access method. See the comment in /// ClassLayoutBuilder. FieldAccess MetadataAccess; - /// Does the class require a metadata pattern. - bool HasMetadataPattern; + /// Does the class metadata require dynamic initialization. + bool MetadataRequiresDynamicInitialization; unsigned getFieldIndex(VarDecl *field) const { // FIXME: This is algorithmically terrible. diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index 2f1f0bea4aa..8d95af3490a 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -243,28 +243,11 @@ swift::swift_allocateGenericValueMetadata(GenericMetadata *pattern, pattern->AddressPoint; auto patternMetadata = reinterpret_cast(patternBytes); metadata->Description = patternMetadata->Description.get(); - metadata->Parent = patternMetadata->Parent.get(); + metadata->Parent = patternMetadata->Parent; return metadata; } -/// Entrypoint for non-generic types with resilient layout. -const Metadata * -swift::swift_getResilientMetadata(GenericMetadata *pattern) { - assert(pattern->NumKeyArguments == 0); - - auto entry = getCache(pattern).findOrAdd(nullptr, 0, - [&]() -> GenericCacheEntry* { - // Create new metadata to cache. - auto metadata = pattern->CreateFunction(pattern, nullptr); - auto entry = GenericCacheEntry::getFromMetadata(pattern, metadata); - entry->Value = metadata; - return entry; - }); - - return entry->Value; -} - /// The primary entrypoint. SWIFT_RT_ENTRY_VISIBILITY const Metadata * @@ -1473,8 +1456,13 @@ static void _swift_initGenericClassObjCName(ClassMetadata *theClass) { } #endif -static void _swift_initializeSuperclass(ClassMetadata *theClass, - bool copyFieldOffsetVectors) { +/// Initialize the invariant superclass components of a class metadata, +/// such as the generic type arguments, field offsets, and so on. +/// +/// This may also relocate the metadata object if it wasn't allocated +/// with enough space. +static ClassMetadata *_swift_initializeSuperclass(ClassMetadata *theClass, + bool copyFieldOffsetVectors) { #if SWIFT_OBJC_INTEROP // If the class is generic, we need to give it a name for Objective-C. if (theClass->getDescription()->GenericParams.isGeneric()) @@ -1483,7 +1471,43 @@ static void _swift_initializeSuperclass(ClassMetadata *theClass, const ClassMetadata *theSuperclass = theClass->SuperClass; if (theSuperclass == nullptr) - return; + return theClass; + + // Relocate the metadata if necessary. + // + // For now, we assume that relocation is only required when the parent + // class has prefix matter we didn't know about. This isn't consistent + // with general class resilience, however. + if (theSuperclass->isTypeMetadata()) { + auto superAP = theSuperclass->getClassAddressPoint(); + auto oldClassAP = theClass->getClassAddressPoint(); + if (superAP > oldClassAP) { + size_t extraPrefixSize = superAP - oldClassAP; + size_t oldClassSize = theClass->getClassSize(); + + // Allocate a new metadata object. + auto rawNewClass = (char*) malloc(extraPrefixSize + oldClassSize); + auto rawOldClass = (const char*) theClass; + auto rawSuperclass = (const char*) theSuperclass; + + // Copy the extra prefix from the superclass. + memcpy((void**) (rawNewClass), + (void* const *) (rawSuperclass - superAP), + extraPrefixSize); + // Copy the rest of the data from the derived class. + memcpy((void**) (rawNewClass + extraPrefixSize), + (void* const *) (rawOldClass - oldClassAP), + oldClassSize); + + // Update the class extents on the new metadata object. + theClass = reinterpret_cast(rawNewClass + oldClassAP); + theClass->setClassAddressPoint(superAP); + theClass->setClassSize(extraPrefixSize + oldClassSize); + + // The previous metadata should be global data, so we have no real + // choice but to drop it on the floor. + } + } // If any ancestor classes have generic parameters or field offset // vectors, inherit them. @@ -1528,15 +1552,24 @@ static void _swift_initializeSuperclass(ClassMetadata *theClass, = (const ClassMetadata *)object_getClass((id)theSuperclass); theMetaclass->SuperClass = theSuperMetaclass; #endif + + return theClass; +} + +static MetadataAllocator &getResilientMetadataAllocator() { + // This should be constant-initialized, but this is safe. + static MetadataAllocator allocator; + return allocator; } /// Initialize the field offset vector for a dependent-layout class, using the /// "Universal" layout strategy. -void swift::swift_initClassMetadata_UniversalStrategy(ClassMetadata *self, - size_t numFields, - const ClassFieldLayout *fieldLayouts, - size_t *fieldOffsets) { - _swift_initializeSuperclass(self, /*copyFieldOffsetVectors=*/true); +ClassMetadata * +swift::swift_initClassMetadata_UniversalStrategy(ClassMetadata *self, + size_t numFields, + const ClassFieldLayout *fieldLayouts, + size_t *fieldOffsets) { + self = _swift_initializeSuperclass(self, /*copyFieldOffsetVectors=*/true); // Start layout by appending to a standard heap object header. size_t size, alignMask; @@ -1625,9 +1658,10 @@ void swift::swift_initClassMetadata_UniversalStrategy(ClassMetadata *self, // even if Swift doesn't, because of SwiftObject.) rodata->InstanceStart = size; - auto &allocator = unsafeGetInitializedCache( - self->getDescription()->getGenericMetadataPattern()) - .getAllocator(); + auto genericPattern = self->getDescription()->getGenericMetadataPattern(); + auto &allocator = + genericPattern ? unsafeGetInitializedCache(genericPattern).getAllocator() + : getResilientMetadataAllocator(); // Always clone the ivar descriptors. if (numFields) { @@ -1703,6 +1737,8 @@ void swift::swift_initClassMetadata_UniversalStrategy(ClassMetadata *self, } } #endif + + return self; } /// \brief Fetch the type metadata associated with the formal dynamic @@ -2460,19 +2496,6 @@ void _swift_debug_verifyTypeLayoutAttribute(Metadata *type, } #endif -SWIFT_RUNTIME_EXPORT -extern "C" -void swift_initializeSuperclass(ClassMetadata *theClass, - bool copyFieldOffsetVectors) { - // Copy generic parameters and field offset vectors from the superclass. - _swift_initializeSuperclass(theClass, copyFieldOffsetVectors); - -#if SWIFT_OBJC_INTEROP - // Register the class pair with the ObjC runtime. - swift_instantiateObjCClass(theClass); -#endif -} - /*** Protocol witness tables *************************************************/ namespace { diff --git a/stdlib/public/runtime/MetadataCache.h b/stdlib/public/runtime/MetadataCache.h index a2a2344583e..03240372450 100644 --- a/stdlib/public/runtime/MetadataCache.h +++ b/stdlib/public/runtime/MetadataCache.h @@ -26,6 +26,31 @@ namespace swift { +/// A bump pointer for metadata allocations. Since metadata is (currently) +/// never released, it does not support deallocation. This allocator by itself +/// is not thread-safe; in concurrent uses, allocations must be guarded by +/// a lock, such as the per-metadata-cache lock used to guard metadata +/// instantiations. All allocations are pointer-aligned. +class MetadataAllocator { + /// Address of the next available space. The allocator grabs a page at a time, + /// so the need for a new page can be determined by page alignment. + /// + /// Initializing to -1 instead of nullptr ensures that the first allocation + /// triggers a page allocation since it will always span a "page" boundary. + char *next = (char*)(~(uintptr_t)0U); + +public: + constexpr MetadataAllocator() = default; + + // Don't copy or move, please. + MetadataAllocator(const MetadataAllocator &) = delete; + MetadataAllocator(MetadataAllocator &&) = delete; + MetadataAllocator &operator=(const MetadataAllocator &) = delete; + MetadataAllocator &operator=(MetadataAllocator &&) = delete; + + void *alloc(size_t size); +}; + // A wrapper around a pointer to a metadata cache entry that provides // DenseMap semantics that compare values in the key vector for the metadata // instance. diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index c3425eedb68..632f4e83d05 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -220,11 +220,10 @@ swift::_matchMetadataByMangledTypeName(const llvm::StringRef typeName, if (ntd == nullptr || ntd->Name.get() != typeName) return nullptr; - // Instantiate resilient types. - if (metadata == nullptr && - ntd->getGenericMetadataPattern() && - !ntd->GenericParams.isGeneric()) { - return swift_getResilientMetadata(ntd->getGenericMetadataPattern()); + // Call the accessor if there is one. + if (metadata == nullptr && !ntd->GenericParams.isGeneric()) { + if (auto accessFn = ntd->getAccessFunction()) + accessFn(); } return metadata; diff --git a/test/IRGen/class_resilience.swift b/test/IRGen/class_resilience.swift index 0173cbe026a..c7514e2eb7a 100644 --- a/test/IRGen/class_resilience.swift +++ b/test/IRGen/class_resilience.swift @@ -119,15 +119,14 @@ public class MyResilientChild : MyResilientParent { // CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont // CHECK: cacheIsNull: -// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_getResilientMetadata( -// CHECK-NEXT: store %swift.type* [[METADATA]], %swift.type** @_TMLC16class_resilience26ClassWithResilientProperty +// CHECK-NEXT: call void @swift_once(i64* @_TMaC16class_resilience26ClassWithResilientProperty.once_token, i8* bitcast (void (i8*)* @initialize_metadata_ClassWithResilientProperty to i8*)) +// CHECK-NEXT: [[METADATA:%.*]] = load %swift.type*, %swift.type** @_TMLC16class_resilience26ClassWithResilientProperty // CHECK-NEXT: br label %cont // CHECK: cont: // CHECK-NEXT: [[RESULT:%.*]] = phi %swift.type* [ [[CACHE]], %entry ], [ [[METADATA]], %cacheIsNull ] // CHECK-NEXT: ret %swift.type* [[RESULT]] - // ClassWithResilientProperty.color getter // CHECK-LABEL: define{{( protected)?}} i32 @_TFC16class_resilience26ClassWithResilientPropertyg5colorVs5Int32(%C16class_resilience26ClassWithResilientProperty*) @@ -148,8 +147,8 @@ public class MyResilientChild : MyResilientParent { // CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont // CHECK: cacheIsNull: -// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_getResilientMetadata( -// CHECK-NEXT: store %swift.type* [[METADATA]], %swift.type** @_TMLC16class_resilience33ClassWithResilientlySizedProperty +// CHECK-NEXT: call void @swift_once(i64* @_TMaC16class_resilience33ClassWithResilientlySizedProperty.once_token, i8* bitcast (void (i8*)* @initialize_metadata_ClassWithResilientlySizedProperty to i8*)) +// CHECK-NEXT: [[METADATA:%.*]] = load %swift.type*, %swift.type** @_TMLC16class_resilience33ClassWithResilientlySizedProperty // CHECK-NEXT: br label %cont // CHECK: cont: @@ -224,13 +223,12 @@ public class MyResilientChild : MyResilientParent { // CHECK-NEXT: ret i32 [[RESULT]] -// ClassWithResilientProperty metadata instantiation function +// ClassWithResilientProperty metadata initialization function -// CHECK-LABEL: define{{( protected)?}} private %swift.type* @create_generic_metadata_ClassWithResilientProperty(%swift.type_pattern*, i8**) -// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata( +// CHECK-LABEL: define{{( protected)?}} private void @initialize_metadata_ClassWithResilientProperty // CHECK: [[SIZE_METADATA:%.*]] = call %swift.type* @_TMaV16resilient_struct4Size() -// CHECK: call void @swift_initClassMetadata_UniversalStrategy( +// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_initClassMetadata_UniversalStrategy( // CHECK-native: [[METADATA_PTR:%.*]] = bitcast %swift.type* [[METADATA]] to [[INT]]* // CHECK-native-NEXT: [[FIELD_OFFSET_PTR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_PTR]], [[INT]] {{12|15}} // CHECK-native-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_PTR]] @@ -239,15 +237,15 @@ public class MyResilientChild : MyResilientParent { // CHECK-native-NEXT: [[FIELD_OFFSET_PTR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_PTR]], [[INT]] {{13|16}} // CHECK-native-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_PTR]] // CHECK-native-NEXT: store [[INT]] [[FIELD_OFFSET]], [[INT]]* @_TWvdvC16class_resilience26ClassWithResilientProperty5colorVs5Int32 -// CHECK: ret %swift.type* [[METADATA]] +// CHECK: store atomic %swift.type* [[METADATA]], %swift.type** @_TMLC16class_resilience26ClassWithResilientProperty release, +// CHECK: ret void -// ClassWithResilientlySizedProperty metadata instantiation function +// ClassWithResilientlySizedProperty metadata initialization function -// CHECK-LABEL: define{{( protected)?}} private %swift.type* @create_generic_metadata_ClassWithResilientlySizedProperty(%swift.type_pattern*, i8**) -// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata( +// CHECK-LABEL: define{{( protected)?}} private void @initialize_metadata_ClassWithResilientlySizedProperty // CHECK: [[RECTANGLE_METADATA:%.*]] = call %swift.type* @_TMaV16resilient_struct9Rectangle() -// CHECK: call void @swift_initClassMetadata_UniversalStrategy( +// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_initClassMetadata_UniversalStrategy( // CHECK-native: [[METADATA_PTR:%.*]] = bitcast %swift.type* [[METADATA]] to [[INT]]* // CHECK-native-NEXT: [[FIELD_OFFSET_PTR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_PTR]], [[INT]] {{11|14}} // CHECK-native-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_PTR]] @@ -256,4 +254,6 @@ public class MyResilientChild : MyResilientParent { // CHECK-native-NEXT: [[FIELD_OFFSET_PTR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[METADATA_PTR]], [[INT]] {{12|15}} // CHECK-native-NEXT: [[FIELD_OFFSET:%.*]] = load [[INT]], [[INT]]* [[FIELD_OFFSET_PTR]] // CHECK-native-NEXT: store [[INT]] [[FIELD_OFFSET]], [[INT]]* @_TWvdvC16class_resilience33ClassWithResilientlySizedProperty5colorVs5Int32 -// CHECK: ret %swift.type* [[METADATA]] +// CHECK: store atomic %swift.type* [[METADATA]], %swift.type** @_TMLC16class_resilience33ClassWithResilientlySizedProperty release, +// CHECK: ret void + diff --git a/test/IRGen/concrete_inherits_generic_base.swift b/test/IRGen/concrete_inherits_generic_base.swift index 3f9faa5feca..6d5846cdf6f 100644 --- a/test/IRGen/concrete_inherits_generic_base.swift +++ b/test/IRGen/concrete_inherits_generic_base.swift @@ -23,8 +23,8 @@ class Base { // CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont // CHECK: cacheIsNull: -// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_getResilientMetadata( -// CHECK-NEXT: store %swift.type* [[METADATA]], %swift.type** @_TMLC3foo12SuperDerived +// CHECK-NEXT: call void @swift_once(i64* @_TMaC3foo12SuperDerived.once_token, i8* bitcast (void (i8*)* @initialize_metadata_SuperDerived to i8*)) +// CHECK-NEXT: [[METADATA:%.*]] = load %swift.type*, %swift.type** @_TMLC3foo12SuperDerived // CHECK-NEXT: br label %cont // CHECK: cont: // CHECK-NEXT: [[RESULT:%.*]] = phi %swift.type* [ [[CACHE]], %entry ], [ [[METADATA]], %cacheIsNull ] @@ -39,8 +39,8 @@ class SuperDerived: Derived { // CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont // CHECK: cacheIsNull: -// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_getResilientMetadata( -// CHECK-NEXT: store %swift.type* [[METADATA]], %swift.type** @_TMLC3foo7Derived +// CHECK-NEXT: call void @swift_once(i64* @_TMaC3foo7Derived.once_token, i8* bitcast (void (i8*)* @initialize_metadata_Derived to i8*)) +// CHECK-NEXT: [[METADATA:%.*]] = load %swift.type*, %swift.type** @_TMLC3foo7Derived // CHECK-NEXT: br label %cont // CHECK: cont: // CHECK-NEXT: [[RESULT:%.*]] = phi %swift.type* [ [[CACHE]], %entry ], [ [[METADATA]], %cacheIsNull ] @@ -69,9 +69,9 @@ presentBase(Derived(x: "two")) presentBase(Base(x: "two")) presentBase(Base(x: 2)) -// CHECK-LABEL: define{{( protected)?}} private %swift.type* @create_generic_metadata_SuperDerived(%swift.type_pattern*, i8**) +// CHECK-LABEL: define{{( protected)?}} private void @initialize_metadata_SuperDerived(i8*) // CHECK: [[TMP:%.*]] = call %swift.type* @_TMaC3foo7Derived() -// CHECK-NEXT: [[SUPER:%.*]] = bitcast %swift.type* [[TMP:%.*]] to %objc_class* -// CHECK-NEXT: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_pattern* %0, i8** %1, %objc_class* [[SUPER]]) -// CHECK: call void @swift_initializeSuperclass(%swift.type* [[METADATA]], i1 false) -// CHECK-NEXT: ret %swift.type* [[METADATA]] +// CHECK-NEXT: store %swift.type* [[TMP]], %swift.type** getelementptr inbounds ({{.*}} @_TMfC3foo12SuperDerived{{.*}}, i32 1), align +// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_initClassMetadata_UniversalStrategy( +// CHECK: store atomic %swift.type* [[METADATA]], %swift.type** @_TMLC3foo12SuperDerived release, +// CHECK: ret void diff --git a/test/IRGen/enum.sil b/test/IRGen/enum.sil index dc52fb6dc52..d4081a6d7e4 100644 --- a/test/IRGen/enum.sil +++ b/test/IRGen/enum.sil @@ -2570,8 +2570,8 @@ bb4: // CHECK: [[T:%T]] = load %swift.type*, %swift.type** [[T0]], // CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_pattern* %0, i8** %1) // CHECK: [[METADATA_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8** -// CHECK: [[T0:%.*]] = bitcast %swift.type* [[T]] to i8* // CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 3 +// CHECK: [[T0:%.*]] = bitcast %swift.type* [[T]] to i8* // CHECK: store i8* [[T0]], i8** [[T1]] // CHECK: [[VWT:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY]], i32 5 // CHECK: [[T0:%.*]] = bitcast i8** [[VWT]] to i8* @@ -2613,7 +2613,7 @@ bb4: // -- Fill function for dynamic single-payload. Call into the runtime to // calculate the size. -// CHECK: define{{( protected)?}} private %swift.type* @create_generic_metadata_DynamicSinglePayload(%swift.type_pattern*, i8**) {{.*}} { +// CHECK-LABEL: define{{( protected)?}} private %swift.type* @create_generic_metadata_DynamicSinglePayload(%swift.type_pattern*, i8**) {{.*}} { // CHECK: call void @swift_initEnumValueWitnessTableSinglePayload // CHECK-64-LABEL: define linkonce_odr hidden void @_TwxsV4enum17StructWithWeakVar(%swift.opaque* %dest, i32 %index, %swift.type* %StructWithWeakVar) diff --git a/test/IRGen/enum_resilience.swift b/test/IRGen/enum_resilience.swift index 37c9e514e5b..596add6c5d2 100644 --- a/test/IRGen/enum_resilience.swift +++ b/test/IRGen/enum_resilience.swift @@ -229,15 +229,12 @@ public func getResilientEnumType() -> Any.Type { // CHECK-NEXT: br i1 [[COND]], label %cacheIsNull, label %cont // CHECK: cacheIsNull: -// CHECK-NEXT: [[METADATA2:%.*]] = call %swift.type* @swift_getResilientMetadata -// CHECK-NEXT: store %swift.type* [[METADATA2]], %swift.type** @_TMLO15enum_resilience24EnumWithResilientPayload +// CHECK-NEXT: call void @swift_once(i64* @_TMaO15enum_resilience24EnumWithResilientPayload.once_token, i8* bitcast (void (i8*)* @initialize_metadata_EnumWithResilientPayload to i8*)) +// CHECK-NEXT: [[METADATA2:%.*]] = load %swift.type*, %swift.type** @_TMLO15enum_resilience24EnumWithResilientPayload // CHECK-NEXT: br label %cont // CHECK: cont: // CHECK-NEXT: [[RESULT:%.*]] = phi %swift.type* [ [[METADATA]], %entry ], [ [[METADATA2]], %cacheIsNull ] // CHECK-NEXT: ret %swift.type* [[RESULT]] - -// FIXME: this is bogus - -// CHECK-LABEL: define{{( protected)?}} private %swift.type* @create_generic_metadata_EnumWithResilientPayload(%swift.type_pattern*, i8**) +// CHECK-LABEL: define{{( protected)?}} private void @initialize_metadata_EnumWithResilientPayload(i8*) diff --git a/test/IRGen/enum_value_semantics.sil b/test/IRGen/enum_value_semantics.sil index f70c36161f7..ab4eabcfa9a 100644 --- a/test/IRGen/enum_value_semantics.sil +++ b/test/IRGen/enum_value_semantics.sil @@ -122,12 +122,13 @@ enum GenericFixedLayout { // CHECK: ] -// CHECK-LABEL: @_TMfO20enum_value_semantics20SinglePayloadTrivial = internal constant <{ {{.*i(32|64)}} }> <{ -// CHECK: i8** getelementptr inbounds ([26 x i8*], [26 x i8*]* @_TWVO20enum_value_semantics20SinglePayloadTrivial, i32 0, i32 0), -// CHECK: i64 2, -// CHECK: {{.*}}* @_TMnO20enum_value_semantics20SinglePayloadTrivial -// CHECK: i64 0 -// CHECK: }> +// CHECK-LABEL: @_TMfO20enum_value_semantics20SinglePayloadTrivial = +// CHECK-SAME: internal constant {{.*}} <{ +// CHECK-SAME: i8** getelementptr inbounds ([26 x i8*], [26 x i8*]* @_TWVO20enum_value_semantics20SinglePayloadTrivial, i32 0, i32 0), +// CHECK-SAME: i64 2, +// CHECK-SAME: {{.*}}* @_TMnO20enum_value_semantics20SinglePayloadTrivial +// CHECK-SAME: %swift.type* null +// CHECK-SAME: }> // CHECK-LABEL: @_TWVO20enum_value_semantics23SinglePayloadNontrivial = {{(protected )?}}constant [26 x i8*] [ @@ -163,12 +164,13 @@ enum GenericFixedLayout { // CHECK: ] -// CHECK-LABEL: @_TMfO20enum_value_semantics23SinglePayloadNontrivial = internal constant <{ {{.*i(32|64)}} }> <{ -// CHECK: i8** getelementptr inbounds ([26 x i8*], [26 x i8*]* @_TWVO20enum_value_semantics23SinglePayloadNontrivial, i32 0, i32 0), -// CHECK: i64 2, -// CHECK: {{.*}}* @_TMnO20enum_value_semantics23SinglePayloadNontrivial -// CHECK: i64 0 -// CHECK: }> +// CHECK-LABEL: @_TMfO20enum_value_semantics23SinglePayloadNontrivial = +// CHECK-SAME: internal constant {{.*}} <{ +// CHECK-SAME: i8** getelementptr inbounds ([26 x i8*], [26 x i8*]* @_TWVO20enum_value_semantics23SinglePayloadNontrivial, i32 0, i32 0), +// CHECK-SAME: i64 2, +// CHECK-SAME: {{.*}}* @_TMnO20enum_value_semantics23SinglePayloadNontrivial +// CHECK-SAME: %swift.type* null +// CHECK-SAME: }> // CHECK-LABEL: @_TMPO20enum_value_semantics18GenericFixedLayout = {{(protected )?}}global <{{[{].*\* [}]}}> <{ diff --git a/test/IRGen/generic_classes.sil b/test/IRGen/generic_classes.sil index 0ea9d90c4e0..ed615cde5b4 100644 --- a/test/IRGen/generic_classes.sil +++ b/test/IRGen/generic_classes.sil @@ -308,11 +308,11 @@ entry(%c : $RootGeneric): // CHECK: define{{( protected)?}} private %swift.type* @create_generic_metadata_RootGeneric(%swift.type_pattern*, i8**) {{.*}} { // -- initialize the dependent field offsets -// CHECK: call void @swift_initClassMetadata_UniversalStrategy(%swift.type* {{%.*}}, i64 3, i64* {{%.*}}, i64* {{%.*}}) +// CHECK: call %swift.type* @swift_initClassMetadata_UniversalStrategy(%swift.type* {{%.*}}, i64 3, i64* {{%.*}}, i64* {{%.*}}) // CHECK: } // CHECK: define{{( protected)?}} private %swift.type* @create_generic_metadata_RootGenericFixedLayout(%swift.type_pattern*, i8**) {{.*}} { -// CHECK: call void @swift_initClassMetadata_UniversalStrategy(%swift.type* {{%.*}}, i64 3, i64* {{%.*}}, i64* {{%.*}}) +// CHECK: call %swift.type* @swift_initClassMetadata_UniversalStrategy(%swift.type* {{%.*}}, i64 3, i64* {{%.*}}, i64* {{%.*}}) // CHECK: } // CHECK: define{{( protected)?}} private %swift.type* @create_generic_metadata_GenericInheritsGeneric(%swift.type_pattern*, i8**) {{.*}} { @@ -327,11 +327,11 @@ entry(%c : $RootGeneric): // CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_pattern* %0, i8** %1, %objc_class* [[T0]]) // CHECK: [[METADATA_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8** // Put the generic arguments in their correct positions. -// CHECK: [[T0:%.*]] = bitcast %swift.type* %A to i8* // CHECK: [[A_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY:%.*]], i32 18 +// CHECK: [[T0:%.*]] = bitcast %swift.type* %A to i8* // CHECK: store i8* [[T0]], i8** [[A_ADDR]], align 8 -// CHECK: [[T0:%.*]] = bitcast %swift.type* %B to i8* // CHECK: [[B_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[METADATA_ARRAY:%.*]], i32 19 +// CHECK: [[T0:%.*]] = bitcast %swift.type* %B to i8* // CHECK: store i8* [[T0]], i8** [[B_ADDR]], align 8 // Set up the isa. // CHECK-objc: [[METADATA_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8** @@ -370,6 +370,6 @@ entry(%c : $RootGeneric): // CHECK: store i64 [[SIZE]], i64* [[SIZE_ADDR]], align 8 // CHECK: [[ALIGN_ADDR:%.*]] = getelementptr inbounds [2 x i64], [2 x i64]* [[TYPES]], i32 0, i32 1 // CHECK: store i64 [[ALIGN]], i64* [[ALIGN_ADDR]], align 8 -// CHECK: call void @swift_initClassMetadata_UniversalStrategy(%swift.type* [[METADATA]], i64 1, i64* [[SIZE_ADDR]], i64* [[OFFSETS]]) +// CHECK: call %swift.type* @swift_initClassMetadata_UniversalStrategy(%swift.type* [[METADATA]], i64 1, i64* [[SIZE_ADDR]], i64* [[OFFSETS]]) // CHECK: ret %swift.type* [[METADATA]] // CHECK: } diff --git a/test/IRGen/generic_structs.sil b/test/IRGen/generic_structs.sil index 117ff8f4aca..1f068b98fe0 100644 --- a/test/IRGen/generic_structs.sil +++ b/test/IRGen/generic_structs.sil @@ -284,8 +284,8 @@ entry(%0 : $*ComplexDynamic, %1 : $*Byteful, %2 : $*A, %3 : $*B, %4 : $*Ch // CHECK: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_pattern* %0, i8** %1) // CHECK: [[SELF_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8** // Fill type argument. -// CHECK: [[T0:%.*]] = bitcast %swift.type* %T to i8* // CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 4 +// CHECK: [[T0:%.*]] = bitcast %swift.type* %T to i8* // CHECK: store i8* [[T0]], i8** [[T1]], align 8 // Fill vwtable reference. // CHECK: [[VWTABLE_ADDR:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 6 diff --git a/test/IRGen/generic_types.swift b/test/IRGen/generic_types.swift index 5d277bf87b1..44b57f3de21 100644 --- a/test/IRGen/generic_types.swift +++ b/test/IRGen/generic_types.swift @@ -90,8 +90,8 @@ import Swift // CHECK-objc: [[SUPER:%.*]] = call %objc_class* @rt_swift_getInitializedObjCClass(%objc_class* @"OBJC_CLASS_$_SwiftObject") // CHECK-objc: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_pattern* %0, i8** %1, %objc_class* [[SUPER]]) // CHECK: [[SELF_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8** -// CHECK: [[T0:%.*]] = bitcast %swift.type* %T to i8* // CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 10 +// CHECK: [[T0:%.*]] = bitcast %swift.type* %T to i8* // CHECK: store i8* [[T0]], i8** [[T1]], align 8 // CHECK: ret %swift.type* [[METADATA]] // CHECK: } @@ -103,8 +103,8 @@ import Swift // CHECK-objc: [[SUPER:%.*]] = call %objc_class* @rt_swift_getInitializedObjCClass(%objc_class* @"OBJC_CLASS_$_SwiftObject") // CHECK-objc: [[METADATA:%.*]] = call %swift.type* @swift_allocateGenericClassMetadata(%swift.type_pattern* %0, i8** %1, %objc_class* [[SUPER]]) // CHECK: [[SELF_ARRAY:%.*]] = bitcast %swift.type* [[METADATA]] to i8** -// CHECK: [[T0:%.*]] = bitcast %swift.type* %T to i8* // CHECK: [[T1:%.*]] = getelementptr inbounds i8*, i8** [[SELF_ARRAY]], i32 10 +// CHECK: [[T0:%.*]] = bitcast %swift.type* %T to i8* // CHECK: store i8* [[T0]], i8** [[T1]], align 8 // CHECK: ret %swift.type* [[METADATA]] // CHECK: } diff --git a/test/IRGen/nested_types.sil b/test/IRGen/nested_types.sil new file mode 100644 index 00000000000..cfd8ab566e9 --- /dev/null +++ b/test/IRGen/nested_types.sil @@ -0,0 +1,38 @@ +// RUN: %target-swift-frontend -emit-ir %s | FileCheck %s + +sil_stage canonical + +import Builtin + +class Outer { + struct Inner { + } +} + +sil_vtable Outer {} + +sil @test0 : $@convention(thin) (@thick Outer.Inner.Type) -> (@thick Outer.Type) { +bb0(%0 : $@thick Outer.Inner.Type): + %1 = metatype $@thick Outer.Type + return %1 : $@thick Outer.Type +} +// CHECK-LABEL: define %swift.type* @test0(%swift.type*) +// TODO: it would be more efficient to get this type from the parent metadata field +// CHECK: [[T0:%.*]] = call %swift.type* @_TMaC12nested_types5Outer() +// CHECK-NEXT: ret %swift.type* [[T0]] + +// CHECK-LABEL: define %swift.type* @_TMaVC12nested_types5Outer5Inner() +// CHECK: [[T0:%.*]] = load %swift.type*, %swift.type** @_TMLVC12nested_types5Outer5Inner +// CHECK-NEXT: [[T1:%.*]] = icmp eq %swift.type* [[T0]], null +// CHECK-NEXT: br i1 [[T1]] +// CHECK: call void @swift_once({{.*}}* @_TMaVC12nested_types5Outer5Inner.once_token, i8* bitcast (void (i8*)* @initialize_metadata_Inner to i8*)) +// CHECK-NEXT: [[T2:%.*]] = load %swift.type*, %swift.type** @_TMLVC12nested_types5Outer5Inner +// CHECK-NEXT: br label +// CHECK: [[T4:%.*]] = phi %swift.type* [ [[T0]], {{.*}} ], [ [[T2]], {{.*}} ] +// CHECK-NEXT: ret %swift.type* [[T4]] + +// CHECK-LABEL: define private void @initialize_metadata_Inner +// CHECK: [[T0:%.*]] = call %swift.type* @_TMaC12nested_types5Outer() +// CHECK-NEXT: store %swift.type* [[T0]], %swift.type** getelementptr inbounds (%swift.type*, %swift.type** bitcast ({{.*}} @_TMfVC12nested_types5Outer5Inner{{.*}}, i64 2), align +// CHECK-NEXT: store atomic %swift.type* bitcast ({{.*}} @_TMfVC12nested_types5Outer5Inner{{.*}} to %swift.type*), %swift.type** @_TMLVC12nested_types5Outer5Inner release, align +// CHECK-NEXT: ret void diff --git a/test/IRGen/protocol_conformance_records.swift b/test/IRGen/protocol_conformance_records.swift index eac99aeb404..43e14bce462 100644 --- a/test/IRGen/protocol_conformance_records.swift +++ b/test/IRGen/protocol_conformance_records.swift @@ -72,11 +72,11 @@ extension Int: Runcible { // -- protocol descriptor // CHECK: [[RUNCIBLE]] // -- nominal type descriptor -// CHECK: @got._TMnV16resilient_struct4Size +// CHECK: @got._TMV16resilient_struct4Size // -- witness table // CHECK: @_TWPurGV28protocol_conformance_records17NativeGenericTypex_S_8RuncibleS_ -// -- flags 0x04: unique nominal type descriptor -// CHECK: i32 4 +// -- flags 0x04: unique direct metadata +// CHECK: i32 1 // CHECK: } // CHECK: ] diff --git a/test/IRGen/protocol_resilience.sil b/test/IRGen/protocol_resilience.sil index 342639da3f5..9ae9f4e52c5 100644 --- a/test/IRGen/protocol_resilience.sil +++ b/test/IRGen/protocol_resilience.sil @@ -276,7 +276,7 @@ bb0(%0 : $*ResilientConformingType): // CHECK: cacheIsNull: // CHECK: [[WTABLE:%.*]] = call i8** @_TWaV19protocol_resilience23ResilientConformingType18resilient_protocol22OtherResilientProtocolS_() -// CHECK-NEXT: store i8** [[WTABLE]], i8*** @_TWLV19protocol_resilience23ResilientConformingTypeS0_18resilient_protocol22OtherResilientProtocolS_ +// CHECK-NEXT: store atomic i8** [[WTABLE]], i8*** @_TWLV19protocol_resilience23ResilientConformingTypeS0_18resilient_protocol22OtherResilientProtocolS_ release // CHECK-NEXT: br label %cont // CHECK: cont: diff --git a/test/IRGen/struct_resilience.swift b/test/IRGen/struct_resilience.swift index b0f96fa8ce6..d4c3e898a83 100644 --- a/test/IRGen/struct_resilience.swift +++ b/test/IRGen/struct_resilience.swift @@ -6,7 +6,7 @@ import resilient_enum // CHECK: %Si = type <{ [[INT:i32|i64]] }> -// CHECK-LABEL: @_TMPV17struct_resilience26StructWithResilientStorage = {{(protected )?}}global +// CHECK-LABEL: @_TMfV17struct_resilience26StructWithResilientStorage = internal constant // Resilient structs from outside our resilience domain are manipulated via // value witnesses @@ -146,17 +146,10 @@ public struct StructWithIndirectResilientEnum { // CHECK: ret %swift.type* bitcast ([[INT]]* getelementptr inbounds {{.*}} @_TMfV17struct_resilience6MySize, i32 0, i32 1) to %swift.type*) -// FIXME: this should modify the template in-place instead of copying it - -// CHECK-LABEL: define{{( protected)?}} private %swift.type* @create_generic_metadata_StructWithResilientStorage(%swift.type_pattern*, i8**) +// CHECK-LABEL: define{{( protected)?}} private void @initialize_metadata_StructWithResilientStorage(i8*) // CHECK: [[FIELDS:%.*]] = alloca [4 x i8**] -// CHECK: [[RESULT:%.*]] = call %swift.type* @swift_allocateGenericValueMetadata(%swift.type_pattern* %0, i8** %1) -// CHECK: [[RESULT_ADDR:%.*]] = bitcast %swift.type* [[RESULT]] to i8** -// CHECK: [[VWT:%.*]] = getelementptr inbounds i8*, i8** [[RESULT_ADDR]], i32 8 -// CHECK: [[VWT_ADDR:%.*]] = bitcast i8** [[VWT]] to i8* +// CHECK: [[VWT:%.*]] = load i8**, i8*** getelementptr inbounds ({{.*}} @_TMfV17struct_resilience26StructWithResilientStorage{{.*}}, i64 -1) -// CHECK: [[RESULT_ADDR2:%.*]] = bitcast %swift.type* %2 to [[INT]]* -// CHECK: [[FIELD_OFFSETS_ADDR:%.*]] = getelementptr inbounds [[INT]], [[INT]]* [[RESULT_ADDR:%.*]], i32 3 // CHECK: [[FIELDS_ADDR:%.*]] = getelementptr inbounds [4 x i8**], [4 x i8**]* [[FIELDS]], i32 0, i32 0 // public let s: Size @@ -180,5 +173,6 @@ public struct StructWithIndirectResilientEnum { // CHECK: [[FIELD_4:%.*]] = getelementptr inbounds i8**, i8*** [[FIELDS_ADDR]], i32 3 // CHECK: store i8** [[SIZE_AND_ALIGNMENT:%.*]], i8*** [[FIELD_4]] -// CHECK: call void @swift_initStructMetadata_UniversalStrategy([[INT]] 4, i8*** [[FIELDS_ADDR]], [[INT]]* [[FIELD_OFFSETS_ADDR]], i8** [[VWT]]) -// CHECK: ret %swift.type* [[RESULT]] +// CHECK: call void @swift_initStructMetadata_UniversalStrategy([[INT]] 4, i8*** [[FIELDS_ADDR]], [[INT]]* {{.*}}, i8** [[VWT]]) +// CHECK: store atomic %swift.type* {{.*}} @_TMfV17struct_resilience26StructWithResilientStorage{{.*}}, %swift.type** @_TMLV17struct_resilience26StructWithResilientStorage release, +// CHECK: ret void diff --git a/test/IRGen/typemetadata.sil b/test/IRGen/typemetadata.sil index a9f785f9339..477d5e5fb62 100644 --- a/test/IRGen/typemetadata.sil +++ b/test/IRGen/typemetadata.sil @@ -31,7 +31,7 @@ bb0: // CHECK-NEXT: br i1 [[T1]] // CHECK: [[T0:%.*]] = call %objc_class* @rt_swift_getInitializedObjCClass({{.*}} @_TMfC12typemetadata1C, {{.*}}) // CHECK-NEXT: [[T1:%.*]] = bitcast %objc_class* [[T0]] to %swift.type* -// CHECK: store %swift.type* [[T1]], %swift.type** @_TMLC12typemetadata1C, align 8 +// CHECK: store atomic %swift.type* [[T1]], %swift.type** @_TMLC12typemetadata1C release, align 8 // CHECK-NEXT: br label // CHECK: [[RES:%.*]] = phi // CHECK-NEXT: ret %swift.type* [[RES]] @@ -42,7 +42,7 @@ bb0: // CHECK-NEXT: br i1 [[T1]] // CHECK: [[T0:%.*]] = call %swift.type* @_TMaC12typemetadata1C() // CHECK-NEXT: [[T1:%.*]] = call %swift.type* @swift_getTupleTypeMetadata2(%swift.type* {{.*}} @_TMfV12typemetadata1S, {{.*}} %swift.type* [[T0]], i8* null, i8** null) -// CHECK-NEXT: store %swift.type* [[T1]], %swift.type** @_TMLTV12typemetadata1SCS_1C_, align 8 +// CHECK-NEXT: store atomic %swift.type* [[T1]], %swift.type** @_TMLTV12typemetadata1SCS_1C_ release, align 8 // CHECK-NEXT: br label // CHECK: [[RES:%.*]] = phi // CHECK-NEXT: ret %swift.type* [[RES]] diff --git a/unittests/runtime/Metadata.cpp b/unittests/runtime/Metadata.cpp index 6481f3d31f4..f5581ad5d0c 100644 --- a/unittests/runtime/Metadata.cpp +++ b/unittests/runtime/Metadata.cpp @@ -249,23 +249,6 @@ TEST(Concurrent, ConcurrentMap) { } -TEST(MetadataAllocator, alloc_firstAllocationMoreThanPageSized) { - using swift::MetadataAllocator; - MetadataAllocator allocator; - - // rdar://problem/21659505 -- if the first allocation from a metadata - // allocator was greater than page sized, a typo caused us to incorrectly - // flag an error. - uintptr_t pagesize = sysconf(_SC_PAGESIZE); - void *page = allocator.alloc(pagesize); - EXPECT_NE(page, nullptr); - EXPECT_NE(page, MAP_FAILED); - EXPECT_EQ(uintptr_t(page) & uintptr_t(pagesize-1), uintptr_t(0)); - - // Don't leak the page the allocator allocates. - munmap(page, pagesize); -} - TEST(MetadataTest, getGenericMetadata) { auto metadataTemplate = (GenericMetadata*) &MetadataTest1;