//===--- 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/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; /// 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); } /// 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 = IGF.IGM.getAddrOfObjCClass(theClass, NotForDefinition); // 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; } 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.Replacement->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); } }; } 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 the type metadata for a foreign type. static llvm::Value *emitForeignTypeMetadataRef(IRGenFunction &IGF, CanType type) { llvm::Value *candidate = IGF.IGM.getAddrOfForeignTypeMetadataCandidate(type); return IGF.Builder.CreateCall(IGF.IGM.getGetForeignTypeMetadataFn(), candidate); } /// 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); } } 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::Metatype)) 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); 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); // FIXME: Save scope type metadata. 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); // FIXME: Save scope type metadata. 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()); if (!theClass) { assert(theMethod->hasClangNode() && "overriding a non-imported method"); return false; } return hasKnownSwiftImplementation(IGM, theClass); } /// 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->getFields()) { 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. 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 *visitBuiltinUnknownObjectType(CanBuiltinUnknownObjectType type) { return emitDirectMetadataRef(type); } llvm::Value *visitBuiltinVectorType(CanBuiltinVectorType 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 visit(type.getElementType(0)); case 2: { // Find the metadata pointer for this element. llvm::Value *elt0Metadata = visit(type.getElementType(0)); llvm::Value *elt1Metadata = visit(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. llvm::Value *elt0Metadata = visit(type.getElementType(0)); llvm::Value *elt1Metadata = visit(type.getElementType(1)); llvm::Value *elt2Metadata = visit(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 = 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, 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 *visitFunctionType(CanFunctionType type) { if (auto metatype = tryGetLocal(type)) return metatype; // TODO: use a caching entrypoint (with all information // out-of-line) for non-dependent functions. auto argMetadata = visit(type.getInput()); auto resultMetadata = visit(type.getResult()); auto call = IGF.Builder.CreateCall2(IGF.IGM.getGetFunctionMetadataFn(), argMetadata, resultMetadata); call->setDoesNotThrow(); call->setCallingConv(IGF.IGM.RuntimeCC); return setLocal(CanType(type), call); } llvm::Value *visitAnyMetatypeType(CanAnyMetatypeType type) { if (auto metatype = tryGetLocal(type)) return metatype; auto instMetadata = visit(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) { IGF.unimplemented(SourceLoc(), "metadata ref for DynamicSelf type"); return llvm::UndefValue::get(IGF.IGM.TypeMetadataPtrTy); } 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::Metatype); } 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::Metatype); } /// Set the metatype in local data. llvm::Value *setLocal(CanType type, llvm::Value *metatype) { // FIXME: Save scope type metadata. return metatype; } }; } /// Produce the type metadata pointer for the given type. llvm::Value *IRGenFunction::emitTypeMetadataRef(CanType type) { return EmitTypeMetadataRef(*this).visit(type); } llvm::Value *IRGenFunction::emitTypeMetadataRef(SILType type) { return emitTypeMetadataRef(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) { assert(isa(type) || isa(type)); // 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)) return EmitTypeMetadataRef(IGF).visitClassType(classType); return IGF.IGM.getAddrOfObjCClass(theClass, NotForDefinition); } auto classType = cast(type); assert(hasKnownSwiftMetadata(IGF.IGM, classType->getDecl())); return EmitTypeMetadataRef(IGF).visitBoundGenericClassType(classType); } llvm::Value *irgen::emitClassHeapMetadataRef(IRGenFunction &IGF, SILType type) { return emitClassHeapMetadataRef(IGF, type.getSwiftRValueType()); } 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())); 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)...) {} using 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); } 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().addGenericParams(); } void addKind() { addConstantWord(asImpl().getKind()); } void addName() { NominalTypeDecl *ntd = asImpl().getTarget(); addWord(getMangledTypeName(IGM, ntd->getDeclaredType()->getCanonicalType())); } 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); 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()); // 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(), [](ProtocolDecl *p) { return requiresProtocolWitnessTable(p); }); 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> { \ using super = 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