//===--- GenMeta.cpp - IR generation for metadata constructs --------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file implements IR generation for metadata constructs like // metatypes and modules. These is presently always trivial, but in // the future we will likely have some sort of physical // representation for at least some metatypes. // //===----------------------------------------------------------------------===// #include "swift/AST/ArchetypeBuilder.h" #include "swift/AST/ASTContext.h" #include "swift/AST/CanTypeVisitor.h" #include "swift/AST/Decl.h" #include "swift/AST/IRGenOptions.h" #include "swift/AST/Substitution.h" #include "swift/AST/Types.h" #include "swift/SIL/FormalLinkage.h" #include "swift/SIL/SILModule.h" #include "swift/SIL/TypeLowering.h" #include "swift/ABI/MetadataValues.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Module.h" #include "llvm/ADT/SmallString.h" #include "Address.h" #include "Callee.h" #include "ClassMetadataLayout.h" #include "FixedTypeInfo.h" #include "GenClass.h" #include "GenPoly.h" #include "GenProto.h" #include "GenStruct.h" #include "HeapTypeInfo.h" #include "IRGenModule.h" #include "IRGenDebugInfo.h" #include "Linking.h" #include "ScalarTypeInfo.h" #include "StructMetadataLayout.h" #include "StructLayout.h" #include "EnumMetadataLayout.h" #include "GenMeta.h" using namespace swift; using namespace irgen; static llvm::Value *emitLoadOfObjCHeapMetadataRef(IRGenFunction &IGF, llvm::Value *object); /// Produce a constant to place in a metatype's isa field /// corresponding to the given metadata kind. static llvm::ConstantInt *getMetadataKind(IRGenModule &IGM, MetadataKind kind) { return llvm::ConstantInt::get(IGM.MetadataKindTy, uint8_t(kind)); } static Size::int_type getOffsetInWords(IRGenModule &IGM, Size offset) { assert(offset.isMultipleOf(IGM.getPointerSize())); return offset / IGM.getPointerSize(); } static Address createPointerSizedGEP(IRGenFunction &IGF, Address base, Size offset) { return IGF.Builder.CreateConstArrayGEP(base, getOffsetInWords(IGF.IGM, offset), offset); } static llvm::Constant *getMangledTypeName(IRGenModule &IGM, CanType type) { auto name = LinkEntity::forTypeMangling(type); llvm::SmallString<32> mangling; name.mangle(mangling); return IGM.getAddrOfGlobalString(mangling); } llvm::Value *irgen::emitObjCMetadataRefForMetadata(IRGenFunction &IGF, llvm::Value *classPtr) { classPtr = IGF.Builder.CreateBitCast(classPtr, IGF.IGM.ObjCClassPtrTy); // Fetch the metadata for that class. auto call = IGF.Builder.CreateCall(IGF.IGM.getGetObjCClassMetadataFn(), classPtr); call->setDoesNotThrow(); call->setDoesNotAccessMemory(); call->setCallingConv(IGF.IGM.RuntimeCC); return call; } /// Emit a reference to the Swift metadata for an Objective-C class. static llvm::Value *emitObjCMetadataRef(IRGenFunction &IGF, ClassDecl *theClass) { // Derive a pointer to the Objective-C class. auto classPtr = emitObjCHeapMetadataRef(IGF, theClass); return emitObjCMetadataRefForMetadata(IGF, classPtr); } namespace { /// A structure for collecting generic arguments for emitting a /// nominal metadata reference. The structure produced here is /// consumed by swift_getGenericMetadata() and must correspond to /// the fill operations that the compiler emits for the bound decl. struct GenericArguments { /// The values to use to initialize the arguments structure. SmallVector Values; SmallVector Types; void collect(IRGenFunction &IGF, BoundGenericType *type) { // Add all the argument archetypes. // TODO: only the *primary* archetypes // TODO: not archetypes from outer contexts // TODO: but we are partially determined by the outer context! for (auto &sub : type->getSubstitutions(/*FIXME:*/nullptr, nullptr)) { CanType subbed = sub.getReplacement()->getCanonicalType(); Values.push_back(IGF.emitTypeMetadataRef(subbed)); } // All of those values are metadata pointers. Types.append(Values.size(), IGF.IGM.TypeMetadataPtrTy); // Add protocol witness tables for all those archetypes. for (auto &sub : type->getSubstitutions(/*FIXME:*/nullptr, nullptr)) emitWitnessTableRefs(IGF, sub, Values); // All of those values are witness table pointers. Types.append(Values.size() - Types.size(), IGF.IGM.WitnessTablePtrTy); } }; } /// Given an array of polymorphic arguments as might be set up by /// GenericArguments, bind the polymorphic parameters. static void emitPolymorphicParametersFromArray(IRGenFunction &IGF, const GenericParamList &generics, Address array) { unsigned nextIndex = 0; auto claimNext = [&](llvm::PointerType *desiredType) { Address addr = array; if (unsigned index = nextIndex++) { addr = IGF.Builder.CreateConstArrayGEP(array, index, index * IGF.IGM.getPointerSize()); } llvm::Value *value = IGF.Builder.CreateLoad(addr); return IGF.Builder.CreateBitCast(value, desiredType); }; // Bind all the argument archetypes. for (auto archetype : generics.getAllArchetypes()) { llvm::Value *metadata = claimNext(IGF.IGM.TypeMetadataPtrTy); metadata->setName(archetype->getFullName()); IGF.setUnscopedLocalTypeData(CanType(archetype), LocalTypeData::forMetatype(), metadata); } // Bind all the argument witness tables. for (auto archetype : generics.getAllArchetypes()) { unsigned nextProtocolIndex = 0; for (auto protocol : archetype->getConformsTo()) { LocalTypeData key = LocalTypeData::forArchetypeProtocolWitness(nextProtocolIndex); nextProtocolIndex++; if (!Lowering::TypeConverter::protocolRequiresWitnessTable(protocol)) continue; llvm::Value *wtable = claimNext(IGF.IGM.WitnessTablePtrTy); IGF.setUnscopedLocalTypeData(CanType(archetype), key, wtable); } } } static bool isMetadataIndirect(IRGenModule &IGM, NominalTypeDecl *theDecl) { // FIXME return false; } /// Attempts to return a constant heap metadata reference for a /// nominal type. llvm::Constant *irgen::tryEmitConstantHeapMetadataRef(IRGenModule &IGM, CanType type) { assert(isa(type) || isa(type)); // We can't do this for any types with generic parameters, either // directly or inherited from the context. // FIXME: Should be an isSpecialized check here. if (isa(type)) return nullptr; auto theDecl = cast(type)->getDecl(); if (theDecl->getGenericParamsOfContext()) return nullptr; if (auto theClass = dyn_cast(theDecl)) if (!hasKnownSwiftMetadata(IGM, theClass)) return IGM.getAddrOfObjCClass(theClass, NotForDefinition); if (isMetadataIndirect(IGM, theDecl)) return nullptr; return IGM.getAddrOfTypeMetadata(type, false, false); } /// 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 /// forwarded to the real class, if one exists) or (2) put it in /// various data sections where the ObjC runtime will properly arrange /// things. Therefore, we must typically force the initialization of /// a class when emitting a reference to it. llvm::Value *irgen::emitObjCHeapMetadataRef(IRGenFunction &IGF, ClassDecl *theClass, bool allowUninitialized) { auto classObject = IGF.IGM.getAddrOfObjCClass(theClass, NotForDefinition); if (allowUninitialized) return classObject; // TODO: memoize this the same way that we memoize Swift type metadata? return IGF.Builder.CreateCall(IGF.IGM.getGetInitializedObjCClassFn(), classObject); } /// Emit a reference to the type metadata for a foreign type. static llvm::Value *emitForeignTypeMetadataRef(IRGenFunction &IGF, CanType type) { llvm::Value *candidate = IGF.IGM.getAddrOfForeignTypeMetadataCandidate(type); auto call = IGF.Builder.CreateCall(IGF.IGM.getGetForeignTypeMetadataFn(), candidate); call->addAttribute(llvm::AttributeSet::FunctionIndex, llvm::Attribute::NoUnwind); call->addAttribute(llvm::AttributeSet::FunctionIndex, llvm::Attribute::ReadNone); return call; } /// Returns a metadata reference for a class type. static llvm::Value *emitNominalMetadataRef(IRGenFunction &IGF, NominalTypeDecl *theDecl, CanType theType) { // Non-native Swift classes need to be handled differently. if (auto theClass = dyn_cast(theDecl)) { // We emit a completely different pattern for foreign classes. if (theClass->isForeign()) { return emitForeignTypeMetadataRef(IGF, theType); } // Classes that might not have Swift metadata use a different // symbol name. if (!hasKnownSwiftMetadata(IGF.IGM, theClass)) { assert(!theDecl->getGenericParamsOfContext() && "ObjC class cannot be generic"); return emitObjCMetadataRef(IGF, theClass); } } else if (theDecl->hasClangNode()) { // Imported Clang types require foreign metadata uniquing too. return emitForeignTypeMetadataRef(IGF, theType); } auto generics = isa(theDecl) ? nullptr : theDecl->getGenericParamsOfContext(); bool isPattern = (generics != nullptr); assert(!isPattern || isa(theType)); assert(isPattern || isa(theType)); // If this is generic, check to see if we've maybe got a local // reference already. if (isPattern) { if (auto cache = IGF.tryGetLocalTypeData(theType, LocalTypeData::forMetatype())) return cache; } bool isIndirect = isMetadataIndirect(IGF.IGM, theDecl); // Grab a reference to the metadata or metadata template. CanType declaredType = theDecl->getDeclaredType()->getCanonicalType(); llvm::Value *metadata = IGF.IGM.getAddrOfTypeMetadata(declaredType, isIndirect, isPattern); // If it's indirected, go ahead and load the true value to use. // TODO: startup performance might force this to be some sort of // lazy check. if (isIndirect) { auto addr = Address(metadata, IGF.IGM.getPointerAlignment()); metadata = IGF.Builder.CreateLoad(addr, "metadata.direct"); } // If we don't have generic parameters, that's all we need. if (!generics) { assert(metadata->getType() == IGF.IGM.TypeMetadataPtrTy); // If this is a class, we need to force ObjC initialization, // but only if we're doing Objective-C interop. if (IGF.IGM.ObjCInterop && isa(theDecl)) { 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; } // Okay, we need to call swift_getGenericMetadata. assert(metadata->getType() == IGF.IGM.TypeMetadataPatternPtrTy); // Grab the substitutions. auto boundGeneric = cast(theType); assert(boundGeneric->getDecl() == theDecl); GenericArguments genericArgs; genericArgs.collect(IGF, boundGeneric); // If we have less than four arguments, use a fast entry point. assert(genericArgs.Values.size() > 0 && "no generic args?!"); if (genericArgs.Values.size() <= 4) { llvm::Constant *fastMetadataGetters[] = { nullptr, IGF.IGM.getGetGenericMetadata1Fn(), IGF.IGM.getGetGenericMetadata2Fn(), IGF.IGM.getGetGenericMetadata3Fn(), IGF.IGM.getGetGenericMetadata4Fn(), }; auto fastGetter = fastMetadataGetters[genericArgs.Values.size()]; SmallVector args; args.push_back(metadata); for (auto value : genericArgs.Values) args.push_back(IGF.Builder.CreateBitCast(value, IGF.IGM.Int8PtrTy)); auto result = IGF.Builder.CreateCall(fastGetter, args); result->setDoesNotThrow(); result->addAttribute(llvm::AttributeSet::FunctionIndex, llvm::Attribute::ReadNone); IGF.setScopedLocalTypeData(theType, LocalTypeData::forMetatype(), result); return result; } // Slam that information directly into the generic arguments buffer. auto argsBufferTy = llvm::StructType::get(IGF.IGM.LLVMContext, genericArgs.Types); Address argsBuffer = IGF.createAlloca(argsBufferTy, IGF.IGM.getPointerAlignment(), "generic.arguments"); for (unsigned i = 0, e = genericArgs.Values.size(); i != e; ++i) { Address elt = IGF.Builder.CreateStructGEP(argsBuffer, i, IGF.IGM.getPointerSize() * i); IGF.Builder.CreateStore(genericArgs.Values[i], elt); } // Cast to void*. llvm::Value *arguments = IGF.Builder.CreateBitCast(argsBuffer.getAddress(), IGF.IGM.Int8PtrTy); // Make the call. auto result = IGF.Builder.CreateCall2(IGF.IGM.getGetGenericMetadataFn(), metadata, arguments); result->setDoesNotThrow(); result->addAttribute(llvm::AttributeSet::FunctionIndex, llvm::Attribute::ReadOnly); IGF.setScopedLocalTypeData(theType, LocalTypeData::forMetatype(), result); return result; } bool irgen::hasKnownSwiftMetadata(IRGenModule &IGM, CanType type) { if (ClassDecl *theClass = type.getClassOrBoundGenericClass()) { return hasKnownSwiftMetadata(IGM, theClass); } if (auto archetype = dyn_cast(type)) { if (auto superclass = archetype->getSuperclass()) { return hasKnownSwiftMetadata(IGM, superclass->getCanonicalType()); } } // Class existentials, etc. return false; } /// Is the given class known to have Swift-compatible metadata? bool irgen::hasKnownSwiftMetadata(IRGenModule &IGM, ClassDecl *theClass) { // For now, the fact that a declaration was not implemented in Swift // is enough to conclusively force us into a slower path. // Eventually we might have an attribute here or something based on // the deployment target. return hasKnownSwiftImplementation(IGM, theClass); } /// Is the given class known to have an implementation in Swift? bool irgen::hasKnownSwiftImplementation(IRGenModule &IGM, ClassDecl *theClass) { return !theClass->hasClangNode(); } /// Is the given method known to be callable by vtable lookup? bool irgen::hasKnownVTableEntry(IRGenModule &IGM, AbstractFunctionDecl *theMethod) { auto theClass = dyn_cast(theMethod->getDeclContext()); // Extension methods don't get vtable entries. if (!theClass) { return false; } return hasKnownSwiftImplementation(IGM, theClass); } /// Return the standard access strategy for getting a non-dependent /// type metadata object. TypeMetadataAccessStrategy irgen::getTypeMetadataAccessStrategy(CanType type) { assert(!type->hasArchetype()); // Non-generic structs, enums, and classes are special cases. auto nominal = dyn_cast(type); if (nominal && !isa(nominal) && !nominal->getDecl()->isGenericContext()) { // Struct and enum metadata can be accessed directly. if (!isa(nominal)) return TypeMetadataAccessStrategy::Direct; // Classes require accessors. switch (getDeclLinkage(nominal->getDecl())) { case FormalLinkage::PublicUnique: return TypeMetadataAccessStrategy::PublicUniqueAccessor; case FormalLinkage::HiddenUnique: return TypeMetadataAccessStrategy::HiddenUniqueAccessor; case FormalLinkage::Private: return TypeMetadataAccessStrategy::PrivateAccessor; case FormalLinkage::PublicNonUnique: case FormalLinkage::HiddenNonUnique: return TypeMetadataAccessStrategy::NonUniqueAccessor; } llvm_unreachable("bad formal linkage"); } // Builtin types are assumed to be implemented with metadata in the runtime. if (isa(type)) return TypeMetadataAccessStrategy::Direct; // DynamicSelfType is actually local. if (isa(type)) return TypeMetadataAccessStrategy::Direct; // The zero-element tuple has special metadata in the runtime. if (auto tuple = dyn_cast(type)) if (tuple->getNumElements() == 0) return TypeMetadataAccessStrategy::Direct; // Everything else requires a shared accessor function. return TypeMetadataAccessStrategy::NonUniqueAccessor; } /// Emit a string encoding the labels in the given tuple type. static llvm::Constant *getTupleLabelsString(IRGenModule &IGM, CanTupleType type) { bool hasLabels = false; llvm::SmallString<128> buffer; for (auto &elt : type->getElements()) { if (elt.hasName()) { hasLabels = true; buffer.append(elt.getName().str()); } // Each label is space-terminated. buffer += ' '; } // If there are no labels, use a null pointer. if (!hasLabels) { return llvm::ConstantPointerNull::get(IGM.Int8PtrTy); } // Otherwise, create a new string literal. // This method implicitly adds a null terminator. return IGM.getAddrOfGlobalString(buffer); } namespace { /// A visitor class for emitting a reference to a metatype object. /// This implements a "raw" access, useful for implementing cache /// functions or for implementing dependent accesses. class EmitTypeMetadataRef : public CanTypeVisitor { private: IRGenFunction &IGF; public: EmitTypeMetadataRef(IRGenFunction &IGF) : IGF(IGF) {} #define TREAT_AS_OPAQUE(KIND) \ llvm::Value *visit##KIND##Type(KIND##Type *type) { \ return visitOpaqueType(CanType(type)); \ } TREAT_AS_OPAQUE(BuiltinInteger) TREAT_AS_OPAQUE(BuiltinFloat) TREAT_AS_OPAQUE(BuiltinRawPointer) #undef TREAT_AS_OPAQUE llvm::Value *emitDirectMetadataRef(CanType type) { return IGF.IGM.getAddrOfTypeMetadata(type, /*indirect*/ false, /*pattern*/ false); } /// The given type should use opaque type info. We assume that /// the runtime always provides an entry for such a type; right /// now, that mapping is as one of the integer types. llvm::Value *visitOpaqueType(CanType type) { auto &opaqueTI = cast(IGF.IGM.getTypeInfoForLowered(type)); assert(opaqueTI.getFixedSize() == Size(opaqueTI.getFixedAlignment().getValue())); assert(opaqueTI.getFixedSize().isPowerOf2()); auto numBits = 8 * opaqueTI.getFixedSize().getValue(); auto intTy = BuiltinIntegerType::get(numBits, IGF.IGM.Context); return emitDirectMetadataRef(CanType(intTy)); } llvm::Value *visitBuiltinNativeObjectType(CanBuiltinNativeObjectType type) { return emitDirectMetadataRef(type); } llvm::Value *visitBuiltinBridgeObjectType(CanBuiltinBridgeObjectType type) { return emitDirectMetadataRef(type); } llvm::Value *visitBuiltinUnknownObjectType(CanBuiltinUnknownObjectType type) { return emitDirectMetadataRef(type); } llvm::Value *visitBuiltinVectorType(CanBuiltinVectorType type) { return emitDirectMetadataRef(type); } llvm::Value *visitBuiltinUnsafeValueBufferType( CanBuiltinUnsafeValueBufferType type) { return emitDirectMetadataRef(type); } llvm::Value *visitNominalType(CanNominalType type) { assert(!type->isExistentialType()); return emitNominalMetadataRef(IGF, type->getDecl(), type); } llvm::Value *visitBoundGenericType(CanBoundGenericType type) { assert(!type->isExistentialType()); return emitNominalMetadataRef(IGF, type->getDecl(), type); } llvm::Value *visitTupleType(CanTupleType type) { if (auto cached = tryGetLocal(type)) return cached; // I think the sanest thing to do here is drop labels, but maybe // that's not correct. If so, that's really unfortunate in a // lot of ways. // Er, varargs bit? Should that go in? switch (type->getNumElements()) { case 0: {// Special case the empty tuple, just use the global descriptor. llvm::Constant *fullMetadata = IGF.IGM.getEmptyTupleMetadata(); llvm::Constant *indices[] = { llvm::ConstantInt::get(IGF.IGM.Int32Ty, 0), llvm::ConstantInt::get(IGF.IGM.Int32Ty, 1) }; return llvm::ConstantExpr::getInBoundsGetElementPtr(fullMetadata, indices); } case 1: // For metadata purposes, we consider a singleton tuple to be // isomorphic to its element type. return IGF.emitTypeMetadataRef(type.getElementType(0)); case 2: { // Find the metadata pointer for this element. auto elt0Metadata = IGF.emitTypeMetadataRef(type.getElementType(0)); auto elt1Metadata = IGF.emitTypeMetadataRef(type.getElementType(1)); llvm::Value *args[] = { elt0Metadata, elt1Metadata, getTupleLabelsString(IGF.IGM, type), llvm::ConstantPointerNull::get(IGF.IGM.WitnessTablePtrTy) // proposed }; auto call = IGF.Builder.CreateCall(IGF.IGM.getGetTupleMetadata2Fn(), args); call->setDoesNotThrow(); call->setCallingConv(IGF.IGM.RuntimeCC); return setLocal(CanType(type), call); } case 3: { // Find the metadata pointer for this element. auto elt0Metadata = IGF.emitTypeMetadataRef(type.getElementType(0)); auto elt1Metadata = IGF.emitTypeMetadataRef(type.getElementType(1)); auto elt2Metadata = IGF.emitTypeMetadataRef(type.getElementType(2)); llvm::Value *args[] = { elt0Metadata, elt1Metadata, elt2Metadata, getTupleLabelsString(IGF.IGM, type), llvm::ConstantPointerNull::get(IGF.IGM.WitnessTablePtrTy) // proposed }; auto call = IGF.Builder.CreateCall(IGF.IGM.getGetTupleMetadata3Fn(), args); call->setDoesNotThrow(); call->setCallingConv(IGF.IGM.RuntimeCC); return setLocal(CanType(type), call); } default: // TODO: use a caching entrypoint (with all information // out-of-line) for non-dependent tuples. llvm::Value *pointerToFirst = nullptr; // appease -Wuninitialized auto elements = type.getElementTypes(); auto arrayTy = llvm::ArrayType::get(IGF.IGM.TypeMetadataPtrTy, elements.size()); Address buffer = IGF.createAlloca(arrayTy,IGF.IGM.getPointerAlignment(), "tuple-elements"); for (unsigned i = 0, e = elements.size(); i != e; ++i) { // Find the metadata pointer for this element. llvm::Value *eltMetadata = IGF.emitTypeMetadataRef(elements[i]); // GEP to the appropriate element and store. Address eltPtr = IGF.Builder.CreateStructGEP(buffer, i, IGF.IGM.getPointerSize()); IGF.Builder.CreateStore(eltMetadata, eltPtr); // Remember the GEP to the first element. if (i == 0) pointerToFirst = eltPtr.getAddress(); } llvm::Value *args[] = { llvm::ConstantInt::get(IGF.IGM.SizeTy, elements.size()), pointerToFirst, getTupleLabelsString(IGF.IGM, type), llvm::ConstantPointerNull::get(IGF.IGM.WitnessTablePtrTy) // proposed }; auto call = IGF.Builder.CreateCall(IGF.IGM.getGetTupleMetadataFn(), args); call->setDoesNotThrow(); call->setCallingConv(IGF.IGM.RuntimeCC); return setLocal(type, call); } } llvm::Value *visitPolymorphicFunctionType(CanPolymorphicFunctionType type) { IGF.unimplemented(SourceLoc(), "metadata ref for polymorphic function type"); return llvm::UndefValue::get(IGF.IGM.TypeMetadataPtrTy); } llvm::Value *visitGenericFunctionType(CanGenericFunctionType type) { IGF.unimplemented(SourceLoc(), "metadata ref for generic function type"); return llvm::UndefValue::get(IGF.IGM.TypeMetadataPtrTy); } llvm::Value *extractAndMarkResultType(CanFunctionType type) { // If the function type throws, set the lower bit of the return type // address, so that we can carry this information over to the function // type metadata. auto metadata = IGF.emitTypeMetadataRef(type->getResult()-> getCanonicalType()); return metadata; } llvm::Value *extractAndMarkInOut(CanType type) { // If the type is inout, get the metadata for its inner object type // instead, and then set the lowest bit to help the runtime unique // the metadata type for this function. if (auto inoutType = dyn_cast(type)) { auto metadata = IGF.emitTypeMetadataRef(inoutType.getObjectType()); auto metadataInt = IGF.Builder.CreatePtrToInt(metadata, IGF.IGM.SizeTy); auto inoutFlag = llvm::ConstantInt::get(IGF.IGM.SizeTy, 1); auto marked = IGF.Builder.CreateOr(metadataInt, inoutFlag); return IGF.Builder.CreateIntToPtr(marked, IGF.IGM.Int8PtrTy); } auto metadata = IGF.emitTypeMetadataRef(type); return IGF.Builder.CreateBitCast(metadata, IGF.IGM.Int8PtrTy); } llvm::Value *visitFunctionType(CanFunctionType type) { if (auto metatype = tryGetLocal(type)) return metatype; auto resultMetadata = extractAndMarkResultType(type); CanTupleType inputTuple = dyn_cast(type.getInput()); size_t numArguments = 1; if (inputTuple && !inputTuple->isMaterializable()) numArguments = inputTuple->getNumElements(); // Map the convention to a runtime metadata value. FunctionMetadataConvention metadataConvention; switch (type->getRepresentation()) { case FunctionTypeRepresentation::Swift: metadataConvention = FunctionMetadataConvention::Swift; break; case FunctionTypeRepresentation::Thin: metadataConvention = FunctionMetadataConvention::Thin; break; case FunctionTypeRepresentation::Block: metadataConvention = FunctionMetadataConvention::Block; break; case FunctionTypeRepresentation::CFunctionPointer: metadataConvention = FunctionMetadataConvention::CFunctionPointer; break; } auto flagsVal = FunctionTypeFlags() .withNumArguments(numArguments) .withConvention(metadataConvention) .withThrows(type->throws()); auto flags = llvm::ConstantInt::get(IGF.IGM.SizeTy, flagsVal.getIntValue()); switch (numArguments) { case 1: { auto arg0 = (inputTuple && !inputTuple->isMaterializable()) ? extractAndMarkInOut(inputTuple.getElementType(0)) : extractAndMarkInOut(type.getInput()); auto call = IGF.Builder.CreateCall3( IGF.IGM.getGetFunctionMetadata1Fn(), flags, arg0, resultMetadata); call->setDoesNotThrow(); call->setCallingConv(IGF.IGM.RuntimeCC); return setLocal(CanType(type), call); } case 2: { auto arg0 = extractAndMarkInOut(inputTuple.getElementType(0)); auto arg1 = extractAndMarkInOut(inputTuple.getElementType(1)); auto call = IGF.Builder.CreateCall4( IGF.IGM.getGetFunctionMetadata2Fn(), flags, arg0, arg1, resultMetadata); call->setDoesNotThrow(); call->setCallingConv(IGF.IGM.RuntimeCC); return setLocal(CanType(type), call); } case 3: { auto arg0 = extractAndMarkInOut(inputTuple.getElementType(0)); auto arg1 = extractAndMarkInOut(inputTuple.getElementType(1)); auto arg2 = extractAndMarkInOut(inputTuple.getElementType(2)); auto call = IGF.Builder.CreateCall5( IGF.IGM.getGetFunctionMetadata3Fn(), flags, arg0, arg1, arg2, resultMetadata); call->setDoesNotThrow(); call->setCallingConv(IGF.IGM.RuntimeCC); return setLocal(CanType(type), call); } default: auto arguments = inputTuple.getElementTypes(); auto arrayTy = llvm::ArrayType::get(IGF.IGM.Int8PtrTy, arguments.size() + 2); Address buffer = IGF.createAlloca(arrayTy, IGF.IGM.getPointerAlignment(), "function-arguments"); Address pointerToFirstArg = IGF.Builder.CreateStructGEP(buffer, 0, Size(0)); Address flagsPtr = IGF.Builder.CreateBitCast(pointerToFirstArg, IGF.IGM.SizeTy->getPointerTo()); IGF.Builder.CreateStore(flags, flagsPtr); for (size_t i = 0; i < arguments.size(); ++i) { auto argMetadata = extractAndMarkInOut( inputTuple.getElementType(i)); Address argPtr = IGF.Builder.CreateStructGEP(buffer, i + 1, IGF.IGM.getPointerSize()); IGF.Builder.CreateStore(argMetadata, argPtr); } Address resultPtr = IGF.Builder.CreateStructGEP(buffer, arguments.size() + 1, IGF.IGM.getPointerSize()); resultPtr = IGF.Builder.CreateBitCast(resultPtr, IGF.IGM.TypeMetadataPtrTy->getPointerTo()); IGF.Builder.CreateStore(resultMetadata, resultPtr); auto call = IGF.Builder.CreateCall(IGF.IGM.getGetFunctionMetadataFn(), pointerToFirstArg.getAddress()); call->setDoesNotThrow(); call->setCallingConv(IGF.IGM.RuntimeCC); return setLocal(type, call); } } llvm::Value *visitAnyMetatypeType(CanAnyMetatypeType type) { // FIXME: We shouldn't accept a lowered metatype here, but we need to // represent Optional<@objc_metatype T.Type> as an AST type for ABI // reasons. // assert(!type->hasRepresentation() // && "should not be asking for a representation-specific metatype " // "metadata"); if (auto metatype = tryGetLocal(type)) return metatype; auto instMetadata = IGF.emitTypeMetadataRef(type.getInstanceType()); auto fn = isa(type) ? IGF.IGM.getGetMetatypeMetadataFn() : IGF.IGM.getGetExistentialMetatypeMetadataFn(); auto call = IGF.Builder.CreateCall(fn, instMetadata); call->setDoesNotThrow(); call->setCallingConv(IGF.IGM.RuntimeCC); return setLocal(type, call); } llvm::Value *visitModuleType(CanModuleType type) { IGF.unimplemented(SourceLoc(), "metadata ref for module type"); return llvm::UndefValue::get(IGF.IGM.TypeMetadataPtrTy); } llvm::Value *visitDynamicSelfType(CanDynamicSelfType type) { return IGF.getLocalSelfMetadata(); } llvm::Value *emitExistentialTypeMetadata(CanType type) { SmallVector protocols; type.getAnyExistentialTypeProtocols(protocols); // Collect references to the protocol descriptors. auto descriptorArrayTy = llvm::ArrayType::get(IGF.IGM.ProtocolDescriptorPtrTy, protocols.size()); Address descriptorArray = IGF.createAlloca(descriptorArrayTy, IGF.IGM.getPointerAlignment(), "protocols"); descriptorArray = IGF.Builder.CreateBitCast(descriptorArray, IGF.IGM.ProtocolDescriptorPtrTy->getPointerTo()); unsigned index = 0; for (auto *p : protocols) { llvm::Value *ref = emitProtocolDescriptorRef(IGF, p); Address slot = IGF.Builder.CreateConstArrayGEP(descriptorArray, index, IGF.IGM.getPointerSize()); IGF.Builder.CreateStore(ref, slot); ++index; } auto call = IGF.Builder.CreateCall2(IGF.IGM.getGetExistentialMetadataFn(), IGF.IGM.getSize(Size(protocols.size())), descriptorArray.getAddress()); call->setDoesNotThrow(); call->setCallingConv(IGF.IGM.RuntimeCC); return setLocal(type, call); } llvm::Value *visitProtocolType(CanProtocolType type) { return emitExistentialTypeMetadata(type); } llvm::Value *visitProtocolCompositionType(CanProtocolCompositionType type) { return emitExistentialTypeMetadata(type); } llvm::Value *visitReferenceStorageType(CanReferenceStorageType type) { llvm_unreachable("reference storage type should have been converted by " "SILGen"); } llvm::Value *visitSILFunctionType(CanSILFunctionType type) { llvm_unreachable("should not be asking for metadata of a lowered SIL " "function type--SILGen should have used the AST type"); } llvm::Value *visitArchetypeType(CanArchetypeType type) { return IGF.getLocalTypeData(type, LocalTypeData::forMetatype()); } llvm::Value *visitGenericTypeParamType(CanGenericTypeParamType type) { llvm_unreachable("dependent type should have been substituted by Sema or SILGen"); } llvm::Value *visitDependentMemberType(CanDependentMemberType type) { llvm_unreachable("dependent type should have been substituted by Sema or SILGen"); } llvm::Value *visitLValueType(CanLValueType type) { llvm_unreachable("lvalue type should have been lowered by SILGen"); } llvm::Value *visitInOutType(CanInOutType type) { llvm_unreachable("inout type should have been lowered by SILGen"); } llvm::Value *visitSILBlockStorageType(CanSILBlockStorageType type) { llvm_unreachable("cannot ask for metadata of block storage"); } /// Try to find the metatype in local data. llvm::Value *tryGetLocal(CanType type) { return IGF.tryGetLocalTypeData(type, LocalTypeData::forMetatype()); } /// Set the metatype in local data. llvm::Value *setLocal(CanType type, llvm::Instruction *metatype) { IGF.setScopedLocalTypeData(type, LocalTypeData::forMetatype(), metatype); return metatype; } }; } /// Emit a type metadata reference without using an accessor function. static llvm::Value *emitDirectTypeMetadataRef(IRGenFunction &IGF, CanType type) { return EmitTypeMetadataRef(IGF).visit(type); } /// Get or create an accessor function to the given non-dependent type. static llvm::Function *getTypeMetadataAccessFunction(IRGenModule &IGM, CanType type, ForDefinition_t shouldDefine) { assert(!type->hasArchetype()); llvm::Function *accessor = IGM.getAddrOfTypeMetadataAccessFunction(type, shouldDefine); // If we're not supposed to define the accessor, or if we already // have defined it, just return the pointer. if (!shouldDefine || !accessor->empty()) return accessor; // Okay, define the accessor. llvm::Constant *nullMetadata = llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy); accessor->setDoesNotThrow(); // This function is logically 'readnone': the caller does not need // to reason about any side effects or stores it might perform. accessor->setDoesNotAccessMemory(); // Set up the cache variable. auto cacheVariable = cast( IGM.getAddrOfTypeMetadataLazyCacheVariable(type, ForDefinition)); cacheVariable->setInitializer(nullMetadata); cacheVariable->setAlignment(IGM.getPointerAlignment().getValue()); Address cache(cacheVariable, IGM.getPointerAlignment()); IRGenFunction IGF(IGM, accessor); // Okay, first thing, check the cache variable. // // Conceptually, this needs to establish memory ordering with the // store we do later in the function: if the metadata value is // non-null, we must be able to see any stores performed by the // initialization of the metadata. However, any attempt to read // from the metadata will be address-dependent on the loaded // metadata pointer, which is sufficient to provide adequate // memory ordering guarantees on all the platforms we care about: // ARM has special rules about address dependencies, and x86's // memory ordering is strong enough to guarantee the visibility // even without the address dependency. // // And we do not need to worry about the compiler because the // address dependency naturally forces an order to the memory // accesses. // // Therefore, we can perform a completely naked load here. auto load = IGF.Builder.CreateLoad(cache); // Compare the load result against null. auto isNullBB = IGF.createBasicBlock("cacheIsNull"); auto contBB = IGF.createBasicBlock("cont"); llvm::Value *comparison = IGF.Builder.CreateICmpEQ(load, nullMetadata); IGF.Builder.CreateCondBr(comparison, isNullBB, contBB); auto loadBB = IGF.Builder.GetInsertBlock(); // If the load yielded null, emit the type metadata. IGF.Builder.emitBlock(isNullBB); llvm::Value *directResult = emitDirectTypeMetadataRef(IGF, type); // Store it back to the cache variable. This does require a // barrier on ARM; a 'dmb st' is sufficient. x86 does not require // a barrier here. auto store = IGF.Builder.CreateStore(directResult, cache); store->setAtomic(llvm::Release); IGF.Builder.CreateBr(contBB); auto storeBB = IGF.Builder.GetInsertBlock(); // Emit the continuation block. IGF.Builder.emitBlock(contBB); auto phi = IGF.Builder.CreatePHI(IGM.TypeMetadataPtrTy, 2); phi->addIncoming(load, loadBB); phi->addIncoming(directResult, storeBB); IGF.Builder.CreateRet(phi); return accessor; } /// Emit a call to the type metadata accessor for the given function. static llvm::Value *emitCallToTypeMetadataAccessFunction(IRGenFunction &IGF, CanType type, ForDefinition_t shouldDefine) { // If we already cached the metadata, use it. if (auto local = IGF.tryGetLocalTypeData(type, LocalTypeData::forMetatype())) return local; llvm::Constant *accessor = getTypeMetadataAccessFunction(IGF.IGM, type, shouldDefine); llvm::CallInst *call = IGF.Builder.CreateCall(accessor); call->setCallingConv(IGF.IGM.RuntimeCC); call->setDoesNotAccessMemory(); call->setDoesNotThrow(); // Save the metadata for future lookups. IGF.setScopedLocalTypeData(type, LocalTypeData::forMetatype(), call); return call; } /// Produce the type metadata pointer for the given type. llvm::Value *IRGenFunction::emitTypeMetadataRef(CanType type) { if (!type->hasArchetype()) { switch (getTypeMetadataAccessStrategy(type)) { case TypeMetadataAccessStrategy::Direct: return emitDirectTypeMetadataRef(*this, type); case TypeMetadataAccessStrategy::PublicUniqueAccessor: case TypeMetadataAccessStrategy::HiddenUniqueAccessor: case TypeMetadataAccessStrategy::PrivateAccessor: return emitCallToTypeMetadataAccessFunction(*this, type, NotForDefinition); case TypeMetadataAccessStrategy::NonUniqueAccessor: return emitCallToTypeMetadataAccessFunction(*this, type, ForDefinition); } llvm_unreachable("bad type metadata access strategy"); } return emitDirectTypeMetadataRef(*this, type); } namespace { /// A visitor class for emitting a reference to a metatype object. /// This implements a "raw" access, useful for implementing cache /// functions or for implementing dependent accesses. class EmitTypeMetadataRefForLayout : public CanTypeVisitor { private: IRGenFunction &IGF; public: EmitTypeMetadataRefForLayout(IRGenFunction &IGF) : IGF(IGF) {} llvm::Value *emitDirectMetadataRef(CanType type) { return IGF.IGM.getAddrOfTypeMetadata(type, /*indirect*/ false, /*pattern*/ false); } /// For most types, we can just emit the usual metadata. llvm::Value *visitType(CanType t) { return IGF.emitTypeMetadataRef(t); } llvm::Value *visitTupleType(CanTupleType type) { if (auto cached = tryGetLocal(type)) return cached; switch (type->getNumElements()) { case 0: {// Special case the empty tuple, just use the global descriptor. llvm::Constant *fullMetadata = IGF.IGM.getEmptyTupleMetadata(); llvm::Constant *indices[] = { llvm::ConstantInt::get(IGF.IGM.Int32Ty, 0), llvm::ConstantInt::get(IGF.IGM.Int32Ty, 1) }; return llvm::ConstantExpr::getInBoundsGetElementPtr(fullMetadata, indices); } case 1: // For layout purposes, we consider a singleton tuple to be // isomorphic to its element type. return visit(type.getElementType(0)); case 2: { // Find the layout metadata pointers for these elements. auto elt0Metadata = visit(type.getElementType(0)); auto elt1Metadata = visit(type.getElementType(1)); llvm::Value *args[] = { elt0Metadata, elt1Metadata, // labels don't matter for layout llvm::ConstantPointerNull::get(IGF.IGM.Int8PtrTy), llvm::ConstantPointerNull::get(IGF.IGM.WitnessTablePtrTy) // proposed }; auto call = IGF.Builder.CreateCall(IGF.IGM.getGetTupleMetadata2Fn(), args); call->setDoesNotThrow(); call->setCallingConv(IGF.IGM.RuntimeCC); return setLocal(CanType(type), call); } case 3: { // Find the layout metadata pointers for these elements. auto elt0Metadata = visit(type.getElementType(0)); auto elt1Metadata = visit(type.getElementType(1)); auto elt2Metadata = visit(type.getElementType(2)); llvm::Value *args[] = { elt0Metadata, elt1Metadata, elt2Metadata, // labels don't matter for layout llvm::ConstantPointerNull::get(IGF.IGM.Int8PtrTy), llvm::ConstantPointerNull::get(IGF.IGM.WitnessTablePtrTy) // proposed }; auto call = IGF.Builder.CreateCall(IGF.IGM.getGetTupleMetadata3Fn(), args); call->setDoesNotThrow(); call->setCallingConv(IGF.IGM.RuntimeCC); return setLocal(CanType(type), call); } default: // TODO: use a caching entrypoint (with all information // out-of-line) for non-dependent tuples. llvm::Value *pointerToFirst = nullptr; // appease -Wuninitialized auto elements = type.getElementTypes(); auto arrayTy = llvm::ArrayType::get(IGF.IGM.TypeMetadataPtrTy, elements.size()); Address buffer = IGF.createAlloca(arrayTy,IGF.IGM.getPointerAlignment(), "tuple-elements"); for (unsigned i = 0, e = elements.size(); i != e; ++i) { // Find the metadata pointer for this element. llvm::Value *eltMetadata = visit(elements[i]); // GEP to the appropriate element and store. Address eltPtr = IGF.Builder.CreateStructGEP(buffer, i, IGF.IGM.getPointerSize()); IGF.Builder.CreateStore(eltMetadata, eltPtr); // Remember the GEP to the first element. if (i == 0) pointerToFirst = eltPtr.getAddress(); } llvm::Value *args[] = { llvm::ConstantInt::get(IGF.IGM.SizeTy, elements.size()), pointerToFirst, // labels don't matter for layout llvm::ConstantPointerNull::get(IGF.IGM.Int8PtrTy), llvm::ConstantPointerNull::get(IGF.IGM.WitnessTablePtrTy) // proposed }; auto call = IGF.Builder.CreateCall(IGF.IGM.getGetTupleMetadataFn(), args); call->setDoesNotThrow(); call->setCallingConv(IGF.IGM.RuntimeCC); return setLocal(type, call); } } llvm::Value *visitAnyFunctionType(CanAnyFunctionType type) { llvm_unreachable("not a SIL type"); } llvm::Value *visitSILFunctionType(CanSILFunctionType type) { // All function types have the same layout regardless of arguments or // abstraction level. Use the metadata for () -> () for thick functions, // or Builtin.UnknownObject for block functions. auto &C = type->getASTContext(); switch (type->getRepresentation()) { case SILFunctionType::Representation::Thin: case SILFunctionType::Representation::Method: case SILFunctionType::Representation::WitnessMethod: case SILFunctionType::Representation::ObjCMethod: case SILFunctionType::Representation::CFunctionPointer: // A thin function looks like a plain pointer. // FIXME: Except for extra inhabitants? return emitDirectMetadataRef(C.TheRawPointerType); case SILFunctionType::Representation::Thick: // All function types look like () -> (). // FIXME: It'd be nice not to have to call through the runtime here. return IGF.emitTypeMetadataRef(CanFunctionType::get(C.TheEmptyTupleType, C.TheEmptyTupleType)); case SILFunctionType::Representation::Block: // All block types look like Builtin.UnknownObject. return emitDirectMetadataRef(C.TheUnknownObjectType); } } llvm::Value *visitAnyMetatypeType(CanAnyMetatypeType type) { assert(type->hasRepresentation() && "not a lowered metatype"); switch (type->getRepresentation()) { case MetatypeRepresentation::Thin: { // Thin metatypes are empty, so they look like the empty tuple type. llvm::Constant *fullMetadata = IGF.IGM.getEmptyTupleMetadata(); llvm::Constant *indices[] = { llvm::ConstantInt::get(IGF.IGM.Int32Ty, 0), llvm::ConstantInt::get(IGF.IGM.Int32Ty, 1) }; return llvm::ConstantExpr::getInBoundsGetElementPtr(fullMetadata, indices); } case MetatypeRepresentation::Thick: case MetatypeRepresentation::ObjC: // Thick and ObjC metatypes look like pointers with extra inhabitants. // Get the metatype metadata from the runtime. // FIXME: It'd be nice not to need a runtime call here. return IGF.emitTypeMetadataRef(type); } } /// Try to find the metatype in local data. llvm::Value *tryGetLocal(CanType type) { return IGF.tryGetLocalTypeDataForLayout( SILType::getPrimitiveObjectType(type), LocalTypeData::forMetatype()); } /// Set the metatype in local data. llvm::Value *setLocal(CanType type, llvm::Instruction *metatype) { IGF.setScopedLocalTypeDataForLayout(SILType::getPrimitiveObjectType(type), LocalTypeData::forMetatype(), metatype); return metatype; } }; } llvm::Value *IRGenFunction::emitTypeMetadataRefForLayout(SILType type) { return EmitTypeMetadataRefForLayout(*this).visit(type.getSwiftRValueType()); } /// Produce the heap metadata pointer for the given class type. For /// Swift-defined types, this is equivalent to the metatype for the /// class, but for Objective-C-defined types, this is the class /// object. llvm::Value *irgen::emitClassHeapMetadataRef(IRGenFunction &IGF, CanType type, MetadataValueType desiredType, bool allowUninitialized) { assert(type->mayHaveSuperclass()); // Archetypes may or may not be ObjC classes and need unwrapping to get at // the class object. if (auto archetype = dyn_cast(type)) { // Look up the Swift metadata from context. llvm::Value *archetypeMeta = IGF.emitTypeMetadataRef(type); // Get the class pointer. auto classPtr = emitClassHeapMetadataRefForMetatype(IGF, archetypeMeta, archetype); if (desiredType == MetadataValueType::ObjCClass) classPtr = IGF.Builder.CreateBitCast(classPtr, IGF.IGM.ObjCClassPtrTy); return classPtr; } // ObjC-defined classes will always be top-level non-generic classes. if (auto classType = dyn_cast(type)) { auto theClass = classType->getDecl(); if (!hasKnownSwiftMetadata(IGF.IGM, theClass)) { llvm::Value *result = emitObjCHeapMetadataRef(IGF, theClass, allowUninitialized); if (desiredType == MetadataValueType::TypeMetadata) result = IGF.Builder.CreateBitCast(result, IGF.IGM.TypeMetadataPtrTy); return result; } } else { auto genericType = cast(type); assert(hasKnownSwiftMetadata(IGF.IGM, genericType->getDecl())); (void) genericType; } llvm::Value *result = IGF.emitTypeMetadataRef(type); if (desiredType == MetadataValueType::ObjCClass) result = IGF.Builder.CreateBitCast(result, IGF.IGM.ObjCClassPtrTy); return result; } namespace { /// A CRTP type visitor for deciding whether the metatype for a type /// has trivial representation. struct HasTrivialMetatype : CanTypeVisitor { /// Class metatypes have non-trivial representation due to the /// possibility of subclassing. bool visitClassType(CanClassType type) { return false; } bool visitBoundGenericClassType(CanBoundGenericClassType type) { return false; } /// Archetype metatypes have non-trivial representation in case /// they instantiate to a class metatype. bool visitArchetypeType(CanArchetypeType type) { return false; } /// All levels of class metatypes support subtyping. bool visitMetatypeType(CanMetatypeType type) { return visit(type.getInstanceType()); } /// Everything else is trivial. bool visitType(CanType type) { return false; } }; } /// Does the metatype for the given type have a trivial representation? bool IRGenModule::isTrivialMetatype(CanMetatypeType metaTy) { // FIXME: We still need to handle unlowered metatypes from the AST for // IRGen protocol witnesses. This can go away (with the HasTrivialMetatype // visitor) when we enable SIL witnesses. if (!metaTy->hasRepresentation()) return HasTrivialMetatype().visit(metaTy.getInstanceType()); return metaTy->getRepresentation() == MetatypeRepresentation::Thin; } /// Emit a metatype value for a known type. void irgen::emitMetatypeRef(IRGenFunction &IGF, CanMetatypeType type, Explosion &explosion) { switch (type->getRepresentation()) { case MetatypeRepresentation::Thin: // Thin types have a trivial representation. break; case MetatypeRepresentation::Thick: explosion.add(IGF.emitTypeMetadataRef(type.getInstanceType())); break; case MetatypeRepresentation::ObjC: explosion.add(emitClassHeapMetadataRef(IGF, type.getInstanceType(), MetadataValueType::ObjCClass)); break; } } /*****************************************************************************/ /** Nominal Type Descriptor Emission *****************************************/ /*****************************************************************************/ namespace { class ConstantBuilderBase { protected: IRGenModule &IGM; ConstantBuilderBase(IRGenModule &IGM) : IGM(IGM) {} }; template class ConstantBuilder : public Base { protected: template ConstantBuilder(T &&...args) : Base(std::forward(args)...) {} IRGenModule &IGM = Base::IGM; private: llvm::SmallVector Fields; Size NextOffset = Size(0); protected: Size getNextOffset() const { return NextOffset; } /// Add a uintptr_t value that represents the given offset, but /// scaled to a number of words. void addConstantWordInWords(Size value) { addConstantWord(getOffsetInWords(IGM, value)); } /// Add a constant word-sized value. void addConstantWord(int64_t value) { addWord(llvm::ConstantInt::get(IGM.SizeTy, value)); } /// Add a word-sized value. void addWord(llvm::Constant *value) { assert(value->getType() == IGM.IntPtrTy || value->getType()->isPointerTy()); assert(NextOffset.isMultipleOf(IGM.getPointerSize())); Fields.push_back(value); NextOffset += IGM.getPointerSize(); } /// Add a uint32_t value that represents the given offset, but /// scaled to a number of words. void addConstantInt32InWords(Size value) { addConstantInt32(getOffsetInWords(IGM, value)); } /// Add a constant 32-bit value. void addConstantInt32(int32_t value) { addInt32(llvm::ConstantInt::get(IGM.Int32Ty, value)); } /// Add a 32-bit value. void addInt32(llvm::Constant *value) { assert(value->getType() == IGM.Int32Ty); assert(NextOffset.isMultipleOf(Size(4))); Fields.push_back(value); NextOffset += Size(4); } /// Add a constant 16-bit value. void addConstantInt16(int16_t value) { addInt16(llvm::ConstantInt::get(IGM.Int16Ty, value)); } /// Add a 16-bit value. void addInt16(llvm::Constant *value) { assert(value->getType() == IGM.Int16Ty); assert(NextOffset.isMultipleOf(Size(2))); Fields.push_back(value); NextOffset += Size(2); } /// Add a constant of the given size. void addStruct(llvm::Constant *value, Size size) { assert(size.getValue() == IGM.DataLayout.getTypeStoreSize(value->getType())); assert(NextOffset.isMultipleOf( Size(IGM.DataLayout.getABITypeAlignment(value->getType())))); Fields.push_back(value); NextOffset += size; } class ReservationToken { size_t Index; ReservationToken(size_t index) : Index(index) {} friend ConstantBuilder; }; ReservationToken reserveFields(unsigned numFields, Size size) { unsigned index = Fields.size(); Fields.append(numFields, nullptr); NextOffset += size; return ReservationToken(index); } MutableArrayRef claimReservation(ReservationToken token, unsigned numFields) { return MutableArrayRef(&Fields[0] + token.Index, numFields); } public: llvm::Constant *getInit() const { return llvm::ConstantStruct::getAnon(Fields); } /// An optimization of getInit for when we have a known type we /// can use when there aren't any extra fields. llvm::Constant *getInitWithSuggestedType(unsigned numFields, llvm::StructType *type) { if (Fields.size() == numFields) { return llvm::ConstantStruct::get(type, Fields); } else { return getInit(); } } }; template class NominalTypeDescriptorBuilderBase : public ConstantBuilder<> { Impl &asImpl() { return *static_cast(this); } public: NominalTypeDescriptorBuilderBase(IRGenModule &IGM) : ConstantBuilder(IGM) {} void layout() { asImpl().addKind(); asImpl().addName(); asImpl().addKindDependentFields(); asImpl().addGenericMetadataPattern(); asImpl().addGenericParams(); } void addKind() { addConstantWord(asImpl().getKind()); } void addName() { NominalTypeDecl *ntd = asImpl().getTarget(); addWord(getMangledTypeName(IGM, ntd->getDeclaredType()->getCanonicalType())); } void addGenericMetadataPattern() { NominalTypeDecl *ntd = asImpl().getTarget(); if (!ntd->getGenericParams()) { // If there are no generic parameters, there's no pattern to link. addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPatternPtrTy)); return; } addWord(IGM.getAddrOfTypeMetadata(ntd->getDeclaredType() ->getCanonicalType(), /*indirect*/ false, /*pattern*/ true)); } void addGenericParams() { NominalTypeDecl *ntd = asImpl().getTarget(); if (!ntd->getGenericParams()) { // If there are no generic parameters, there is no generic parameter // vector. addConstantInt32(0); addConstantInt32(0); addConstantInt32(0); return; } // uint32_t GenericParameterVectorOffset; addConstantInt32InWords(asImpl().getGenericParamsOffset()); // The archetype order here needs to be consistent with // MetadataLayout::addGenericFields. // Note that we intentionally don't forward the generic arguments. // Add all the primary archetypes. // TODO: only the *primary* archetypes. // TODO: not archetypes from outer contexts. auto allArchetypes = ntd->getGenericParams()->getAllArchetypes(); // uint32_t NumGenericParameters; addConstantInt32(allArchetypes.size()); // uint32_t NumPrimaryGenericParameters; addConstantInt32(ntd->getGenericParams()->getPrimaryArchetypes().size()); // GenericParameter Parameters[NumGenericParameters]; // struct GenericParameter { for (auto archetype : allArchetypes) { // uint32_t NumWitnessTables; // Count the protocol conformances that require witness tables. unsigned count = std::count_if( archetype->getConformsTo().begin(), archetype->getConformsTo().end(), Lowering::TypeConverter::protocolRequiresWitnessTable); addConstantInt32(count); } // }; } llvm::Constant *emit() { asImpl().layout(); auto init = getInit(); auto var = cast( IGM.getAddrOfNominalTypeDescriptor(asImpl().getTarget(), init->getType())); var->setConstant(true); var->setInitializer(init); return var; } // Derived class must provide: // NominalTypeDecl *getTarget(); // unsigned getKind(); // unsigned getGenericParamsOffset(); // void addKindDependentFields(); }; /// A CRTP helper for classes which are simply searching for a /// specific index within the metadata. /// /// The pattern is that subclasses should override an 'add' method /// from the appropriate layout class and ensure that they call /// setTargetOffset() when the appropriate location is reached. The /// subclass user then just calls getTargetOffset(), which performs /// the layout and returns the found index. /// /// \tparam Base the base class, which should generally be a CRTP /// class template applied to the most-derived class template class MetadataSearcher : public Base { Size TargetOffset = Size::invalid(); Size AddressPoint = Size::invalid(); protected: void setTargetOffset() { assert(TargetOffset.isInvalid() && "setting twice"); TargetOffset = this->NextOffset; } public: template MetadataSearcher(T &&...args) : Base(std::forward(args)...) {} void noteAddressPoint() { AddressPoint = this->NextOffset; } Size getTargetOffset() { assert(TargetOffset.isInvalid() && "computing twice"); this->layout(); assert(!TargetOffset.isInvalid() && "target not found!"); assert(!AddressPoint.isInvalid() && "address point not set"); return TargetOffset - AddressPoint; } Size::int_type getTargetIndex() { return getOffsetInWords(this->IGM, getTargetOffset()); } }; // A bunch of ugly macros to make it easy to declare certain // common kinds of searcher. #define BEGIN_METADATA_SEARCHER_0(SEARCHER, DECLKIND) \ struct SEARCHER \ : MetadataSearcher> { \ SEARCHER(IRGenModule &IGM, DECLKIND##Decl *target) \ : MetadataSearcher(IGM, target) {} #define BEGIN_METADATA_SEARCHER_1(SEARCHER, DECLKIND, TYPE_1, NAME_1) \ struct SEARCHER \ : MetadataSearcher> { \ using super = MetadataSearcher; \ TYPE_1 NAME_1; \ SEARCHER(IRGenModule &IGM, DECLKIND##Decl *target, TYPE_1 NAME_1) \ : super(IGM, target), NAME_1(NAME_1) {} #define BEGIN_METADATA_SEARCHER_2(SEARCHER, DECLKIND, TYPE_1, NAME_1, \ TYPE_2, NAME_2) \ struct SEARCHER \ : MetadataSearcher> { \ using super = MetadataSearcher; \ TYPE_1 NAME_1; \ TYPE_2 NAME_2; \ SEARCHER(IRGenModule &IGM, DECLKIND##Decl *target, TYPE_1 NAME_1, \ TYPE_2 NAME_2) \ : super(IGM, target), NAME_1(NAME_1), NAME_2(NAME_2) {} #define END_METADATA_SEARCHER() \ }; #define BEGIN_GENERIC_METADATA_SEARCHER_0(SEARCHER) \ template