| //===--- GenProto.cpp - Swift IR Generation for Protocols -----------------===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements IR generation for protocols in Swift. |
| // |
| // Protocols serve two masters: generic algorithms and existential |
| // types. In either case, the size and structure of a type is opaque |
| // to the code manipulating a value. Local values of the type must |
| // be stored in fixed-size buffers (which can overflow to use heap |
| // allocation), and basic operations on the type must be dynamically |
| // delegated to a collection of information that "witnesses" the |
| // truth that a particular type implements the protocol. |
| // |
| // In the comments throughout this file, three type names are used: |
| // 'B' is the type of a fixed-size buffer |
| // 'T' is the type which implements a protocol |
| // 'W' is the type of a witness to the protocol |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "swift/AST/ASTContext.h" |
| #include "swift/AST/CanTypeVisitor.h" |
| #include "swift/AST/Types.h" |
| #include "swift/AST/Decl.h" |
| #include "swift/AST/IRGenOptions.h" |
| #include "swift/AST/SubstitutionMap.h" |
| #include "swift/ClangImporter/ClangModule.h" |
| #include "swift/IRGen/Linking.h" |
| #include "swift/SIL/SILDeclRef.h" |
| #include "swift/SIL/SILModule.h" |
| #include "swift/SIL/SILValue.h" |
| #include "swift/SIL/SILWitnessVisitor.h" |
| #include "swift/SIL/TypeLowering.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include "llvm/IR/DerivedTypes.h" |
| #include "llvm/IR/Function.h" |
| #include "llvm/IR/Module.h" |
| |
| #include "CallEmission.h" |
| #include "ConstantBuilder.h" |
| #include "EnumPayload.h" |
| #include "Explosion.h" |
| #include "FixedTypeInfo.h" |
| #include "Fulfillment.h" |
| #include "GenArchetype.h" |
| #include "GenClass.h" |
| #include "GenEnum.h" |
| #include "GenHeap.h" |
| #include "GenMeta.h" |
| #include "GenOpaque.h" |
| #include "GenPoly.h" |
| #include "GenType.h" |
| #include "GenericRequirement.h" |
| #include "IRGenDebugInfo.h" |
| #include "IRGenFunction.h" |
| #include "IRGenModule.h" |
| #include "MetadataPath.h" |
| #include "NecessaryBindings.h" |
| #include "ProtocolInfo.h" |
| #include "TypeInfo.h" |
| |
| #include "GenProto.h" |
| |
| using namespace swift; |
| using namespace irgen; |
| |
| namespace { |
| |
| /// A class for computing how to pass arguments to a polymorphic |
| /// function. The subclasses of this are the places which need to |
| /// be updated if the convention changes. |
| class PolymorphicConvention { |
| protected: |
| IRGenModule &IGM; |
| ModuleDecl &M; |
| CanSILFunctionType FnType; |
| |
| CanGenericSignature Generics; |
| |
| std::vector<MetadataSource> Sources; |
| |
| FulfillmentMap Fulfillments; |
| |
| GenericSignature::ConformsToArray getConformsTo(Type t) { |
| return Generics->getConformsTo(t, M); |
| } |
| |
| public: |
| PolymorphicConvention(IRGenModule &IGM, CanSILFunctionType fnType); |
| |
| ArrayRef<MetadataSource> getSources() const { return Sources; } |
| |
| void enumerateRequirements(const RequirementCallback &callback); |
| |
| void enumerateUnfulfilledRequirements(const RequirementCallback &callback); |
| |
| /// Returns a Fulfillment for a type parameter requirement, or |
| /// nullptr if it's unfulfilled. |
| const Fulfillment *getFulfillmentForTypeMetadata(CanType type) const; |
| |
| /// Return the source of type metadata at a particular source index. |
| const MetadataSource &getSource(size_t SourceIndex) const { |
| return Sources[SourceIndex]; |
| } |
| |
| private: |
| void initGenerics(); |
| void considerNewTypeSource(MetadataSource::Kind kind, unsigned paramIndex, |
| CanType type, IsExact_t isExact); |
| bool considerType(CanType type, IsExact_t isExact, |
| unsigned sourceIndex, MetadataPath &&path); |
| |
| /// Testify to generic parameters in the Self type of a protocol |
| /// witness method. |
| void considerWitnessSelf(CanSILFunctionType fnType); |
| |
| /// Testify to generic parameters in the Self type of an @objc |
| /// generic or protocol method. |
| void considerObjCGenericSelf(CanSILFunctionType fnType); |
| |
| void considerParameter(SILParameterInfo param, unsigned paramIndex, |
| bool isSelfParameter); |
| |
| void addSelfMetadataFulfillment(CanType arg); |
| void addSelfWitnessTableFulfillment(CanType arg, ProtocolDecl *proto); |
| |
| void addPseudogenericFulfillments(); |
| }; |
| |
| } // end anonymous namespace |
| |
| PolymorphicConvention::PolymorphicConvention(IRGenModule &IGM, |
| CanSILFunctionType fnType) |
| : IGM(IGM), M(*IGM.getSwiftModule()), FnType(fnType) { |
| initGenerics(); |
| |
| auto rep = fnType->getRepresentation(); |
| |
| if (fnType->isPseudogeneric()) { |
| // Protocol witnesses still get Self metadata no matter what. The type |
| // parameters of Self are pseudogeneric, though. |
| if (rep == SILFunctionTypeRepresentation::WitnessMethod) |
| considerWitnessSelf(fnType); |
| |
| addPseudogenericFulfillments(); |
| return; |
| } |
| |
| if (rep == SILFunctionTypeRepresentation::WitnessMethod) { |
| // Protocol witnesses always derive all polymorphic parameter |
| // information from the Self argument. We also *cannot* consider other |
| // arguments; doing so would potentially make the signature |
| // incompatible with other witnesses for the same method. |
| considerWitnessSelf(fnType); |
| } else if (rep == SILFunctionTypeRepresentation::ObjCMethod) { |
| // Objective-C thunks for generic methods also always derive all |
| // polymorphic parameter information from the Self argument. |
| considerObjCGenericSelf(fnType); |
| } else { |
| // We don't need to pass anything extra as long as all of the |
| // archetypes (and their requirements) are producible from |
| // arguments. |
| unsigned selfIndex = ~0U; |
| auto params = fnType->getParameters(); |
| |
| // Consider 'self' first. |
| if (fnType->hasSelfParam()) { |
| selfIndex = params.size() - 1; |
| considerParameter(params[selfIndex], selfIndex, true); |
| } |
| |
| // Now consider the rest of the parameters. |
| for (auto index : indices(params)) { |
| if (index != selfIndex) |
| considerParameter(params[index], index, false); |
| } |
| } |
| } |
| |
| void PolymorphicConvention::addPseudogenericFulfillments() { |
| enumerateRequirements([&](GenericRequirement reqt) { |
| MetadataPath path; |
| path.addImpossibleComponent(); |
| |
| unsigned sourceIndex = 0; // unimportant, since impossible |
| Fulfillments.addFulfillment({reqt.TypeParameter, reqt.Protocol}, |
| sourceIndex, std::move(path)); |
| }); |
| } |
| |
| void |
| irgen::enumerateGenericSignatureRequirements(CanGenericSignature signature, |
| const RequirementCallback &callback) { |
| if (!signature) return; |
| |
| // Get all of the type metadata. |
| for (auto gp : signature->getSubstitutableParams()) { |
| callback({CanType(gp), nullptr}); |
| } |
| |
| // Get the protocol conformances. |
| for (auto &reqt : signature->getRequirements()) { |
| switch (reqt.getKind()) { |
| // Ignore these; they don't introduce extra requirements. |
| case RequirementKind::Superclass: |
| case RequirementKind::SameType: |
| case RequirementKind::Layout: |
| continue; |
| |
| case RequirementKind::Conformance: { |
| auto type = CanType(reqt.getFirstType()); |
| auto protocol = |
| cast<ProtocolType>(CanType(reqt.getSecondType()))->getDecl(); |
| if (Lowering::TypeConverter::protocolRequiresWitnessTable(protocol)) { |
| callback({type, protocol}); |
| } |
| continue; |
| } |
| } |
| llvm_unreachable("bad requirement kind"); |
| } |
| } |
| |
| void |
| PolymorphicConvention::enumerateRequirements(const RequirementCallback &callback) { |
| return enumerateGenericSignatureRequirements(Generics, callback); |
| } |
| |
| void PolymorphicConvention::enumerateUnfulfilledRequirements(const RequirementCallback &callback) { |
| enumerateRequirements([&](GenericRequirement requirement) { |
| if (requirement.Protocol) { |
| if (!Fulfillments.getWitnessTable(requirement.TypeParameter, |
| requirement.Protocol)) { |
| callback(requirement); |
| } |
| } else { |
| if (!Fulfillments.getTypeMetadata(requirement.TypeParameter)) { |
| callback(requirement); |
| } |
| } |
| }); |
| } |
| |
| void PolymorphicConvention::initGenerics() { |
| Generics = FnType->getGenericSignature(); |
| } |
| |
| void PolymorphicConvention::considerNewTypeSource(MetadataSource::Kind kind, |
| unsigned paramIndex, |
| CanType type, |
| IsExact_t isExact) { |
| if (!Fulfillments.isInterestingTypeForFulfillments(type)) return; |
| |
| // Prospectively add a source. |
| Sources.emplace_back(kind, paramIndex, type); |
| |
| // Consider the source. |
| if (!considerType(type, isExact, Sources.size() - 1, MetadataPath())) { |
| // If it wasn't used in any fulfillments, remove it. |
| Sources.pop_back(); |
| } |
| } |
| |
| bool PolymorphicConvention::considerType(CanType type, IsExact_t isExact, |
| unsigned sourceIndex, |
| MetadataPath &&path) { |
| struct Callback : FulfillmentMap::InterestingKeysCallback { |
| PolymorphicConvention &Self; |
| Callback(PolymorphicConvention &self) : Self(self) {} |
| |
| bool isInterestingType(CanType type) const override { |
| return type->isTypeParameter(); |
| } |
| bool hasInterestingType(CanType type) const override { |
| return type->hasTypeParameter(); |
| } |
| bool hasLimitedInterestingConformances(CanType type) const override { |
| return true; |
| } |
| GenericSignature::ConformsToArray |
| getInterestingConformances(CanType type) const override { |
| return Self.getConformsTo(type); |
| } |
| } callbacks(*this); |
| return Fulfillments.searchTypeMetadata(IGM, type, isExact, sourceIndex, |
| std::move(path), callbacks); |
| } |
| |
| void PolymorphicConvention::considerWitnessSelf(CanSILFunctionType fnType) { |
| CanType selfTy = fnType->getSelfInstanceType(); |
| |
| // First, bind type metadata for Self. |
| Sources.emplace_back(MetadataSource::Kind::SelfMetadata, |
| MetadataSource::InvalidSourceIndex, |
| selfTy); |
| |
| if (auto *proto = fnType->getDefaultWitnessMethodProtocol(M)) { |
| // The Self type is abstract, so we must pass in a witness table. |
| addSelfMetadataFulfillment(selfTy); |
| |
| // Look at the witness table for the conformance. |
| Sources.emplace_back(MetadataSource::Kind::SelfWitnessTable, |
| MetadataSource::InvalidSourceIndex, |
| selfTy); |
| addSelfWitnessTableFulfillment(selfTy, proto); |
| } else { |
| // If the Self type is concrete, we have a witness thunk with a |
| // fully substituted Self type. The witness table parameter is not |
| // used. |
| considerType(selfTy, IsInexact, Sources.size() - 1, MetadataPath()); |
| } |
| } |
| |
| void PolymorphicConvention::considerObjCGenericSelf(CanSILFunctionType fnType) { |
| // If this is a static method, get the instance type. |
| CanType selfTy = fnType->getSelfInstanceType(); |
| unsigned paramIndex = fnType->getParameters().size() - 1; |
| |
| // Bind type metadata for Self. |
| Sources.emplace_back(MetadataSource::Kind::ClassPointer, paramIndex, |
| selfTy); |
| |
| if (isa<GenericTypeParamType>(selfTy)) |
| addSelfMetadataFulfillment(selfTy); |
| else |
| considerType(selfTy, IsInexact, |
| Sources.size() - 1, MetadataPath()); |
| } |
| |
| void PolymorphicConvention::considerParameter(SILParameterInfo param, |
| unsigned paramIndex, |
| bool isSelfParameter) { |
| auto type = param.getType(); |
| switch (param.getConvention()) { |
| // Indirect parameters do give us a value we can use, but right now |
| // we don't bother, for no good reason. But if this is 'self', |
| // consider passing an extra metatype. |
| case ParameterConvention::Indirect_In: |
| case ParameterConvention::Indirect_In_Constant: |
| case ParameterConvention::Indirect_In_Guaranteed: |
| case ParameterConvention::Indirect_Inout: |
| case ParameterConvention::Indirect_InoutAliasable: |
| if (!isSelfParameter) return; |
| if (type->getNominalOrBoundGenericNominal()) { |
| considerNewTypeSource(MetadataSource::Kind::GenericLValueMetadata, |
| paramIndex, type, IsExact); |
| } |
| return; |
| |
| case ParameterConvention::Direct_Owned: |
| case ParameterConvention::Direct_Unowned: |
| case ParameterConvention::Direct_Guaranteed: |
| // Classes are sources of metadata. |
| if (type->getClassOrBoundGenericClass()) { |
| considerNewTypeSource(MetadataSource::Kind::ClassPointer, |
| paramIndex, type, IsInexact); |
| return; |
| } |
| |
| // Thick metatypes are sources of metadata. |
| if (auto metatypeTy = dyn_cast<MetatypeType>(type)) { |
| if (metatypeTy->getRepresentation() != MetatypeRepresentation::Thick) |
| return; |
| |
| // Thick metatypes for Objective-C parameterized classes are not |
| // sources of metadata. |
| CanType objTy = metatypeTy.getInstanceType(); |
| if (auto classDecl = objTy->getClassOrBoundGenericClass()) |
| if (classDecl->usesObjCGenericsModel()) |
| return; |
| |
| considerNewTypeSource(MetadataSource::Kind::Metadata, |
| paramIndex, objTy, IsInexact); |
| return; |
| } |
| |
| return; |
| } |
| llvm_unreachable("bad parameter convention"); |
| } |
| |
| void PolymorphicConvention::addSelfMetadataFulfillment(CanType arg) { |
| unsigned source = Sources.size() - 1; |
| Fulfillments.addFulfillment({arg, nullptr}, source, MetadataPath()); |
| } |
| |
| void PolymorphicConvention::addSelfWitnessTableFulfillment(CanType arg, ProtocolDecl *proto) { |
| unsigned source = Sources.size() - 1; |
| Fulfillments.addFulfillment({arg, proto}, source, MetadataPath()); |
| } |
| |
| const Fulfillment * |
| PolymorphicConvention::getFulfillmentForTypeMetadata(CanType type) const { |
| return Fulfillments.getTypeMetadata(type); |
| } |
| |
| void irgen::enumerateGenericParamFulfillments(IRGenModule &IGM, |
| CanSILFunctionType fnType, |
| GenericParamFulfillmentCallback callback) { |
| PolymorphicConvention convention(IGM, fnType); |
| |
| // Check if any requirements were fulfilled by metadata stored inside a |
| // captured value. |
| auto generics = fnType->getGenericSignature(); |
| |
| for (auto genericParam : generics->getGenericParams()) { |
| auto genericParamType = genericParam->getCanonicalType(); |
| |
| auto fulfillment |
| = convention.getFulfillmentForTypeMetadata(genericParamType); |
| if (fulfillment == nullptr) |
| continue; |
| |
| auto &source = convention.getSource(fulfillment->SourceIndex); |
| callback(genericParamType, source, fulfillment->Path); |
| } |
| } |
| |
| namespace { |
| |
| /// A class for binding type parameters of a generic function. |
| class EmitPolymorphicParameters : public PolymorphicConvention { |
| IRGenFunction &IGF; |
| SILFunction &Fn; |
| |
| public: |
| EmitPolymorphicParameters(IRGenFunction &IGF, SILFunction &Fn); |
| |
| void emit(Explosion &in, WitnessMetadata *witnessMetadata, |
| const GetParameterFn &getParameter); |
| |
| private: |
| CanType getTypeInContext(CanType type) const; |
| |
| CanType getArgTypeInContext(unsigned paramIndex) const; |
| |
| /// Fulfill local type data from any extra information associated with |
| /// the given source. |
| void bindExtraSource(const MetadataSource &source, Explosion &in, |
| WitnessMetadata *witnessMetadata); |
| |
| void bindParameterSources(const GetParameterFn &getParameter); |
| |
| void bindParameterSource(SILParameterInfo param, unsigned paramIndex, |
| const GetParameterFn &getParameter) ; |
| // Did the convention decide that the parameter at the given index |
| // was a class-pointer source? |
| bool isClassPointerSource(unsigned paramIndex); |
| }; |
| |
| } // end anonymous namespace |
| |
| EmitPolymorphicParameters::EmitPolymorphicParameters(IRGenFunction &IGF, |
| SILFunction &Fn) |
| : PolymorphicConvention(IGF.IGM, Fn.getLoweredFunctionType()), |
| IGF(IGF), Fn(Fn) {} |
| |
| |
| CanType EmitPolymorphicParameters::getTypeInContext(CanType type) const { |
| return Fn.mapTypeIntoContext(type)->getCanonicalType(); |
| } |
| |
| CanType EmitPolymorphicParameters::getArgTypeInContext(unsigned paramIndex) const { |
| return getTypeInContext(FnType->getParameters()[paramIndex].getType()); |
| } |
| |
| void EmitPolymorphicParameters::bindExtraSource(const MetadataSource &source, |
| Explosion &in, |
| WitnessMetadata *witnessMetadata) { |
| switch (source.getKind()) { |
| case MetadataSource::Kind::Metadata: |
| case MetadataSource::Kind::ClassPointer: |
| // Ignore these, we'll get to them when we walk the parameter list. |
| return; |
| |
| case MetadataSource::Kind::GenericLValueMetadata: { |
| CanType argTy = getArgTypeInContext(source.getParamIndex()); |
| |
| llvm::Value *metadata = in.claimNext(); |
| setTypeMetadataName(IGF.IGM, metadata, argTy); |
| |
| IGF.bindLocalTypeDataFromTypeMetadata(argTy, IsExact, metadata); |
| return; |
| } |
| |
| case MetadataSource::Kind::SelfMetadata: { |
| assert(witnessMetadata && "no metadata for witness method"); |
| llvm::Value *metadata = witnessMetadata->SelfMetadata; |
| assert(metadata && "no Self metadata for witness method"); |
| |
| // Mark this as the cached metatype for Self. |
| auto selfTy = FnType->getSelfInstanceType(); |
| CanType argTy = getTypeInContext(selfTy); |
| setTypeMetadataName(IGF.IGM, metadata, argTy); |
| auto *CD = selfTy.getClassOrBoundGenericClass(); |
| // The self metadata here corresponds to the conforming type. |
| // For an inheritable conformance, that may be a subclass of the static |
| // type, and so the self metadata will be inexact. Currently, all |
| // conformances are inheritable. |
| IGF.bindLocalTypeDataFromTypeMetadata( |
| argTy, (!CD || CD->isFinal()) ? IsExact : IsInexact, metadata); |
| return; |
| } |
| |
| case MetadataSource::Kind::SelfWitnessTable: { |
| assert(witnessMetadata && "no metadata for witness method"); |
| llvm::Value *wtable = witnessMetadata->SelfWitnessTable; |
| assert(wtable && "no Self witness table for witness method"); |
| |
| // Mark this as the cached witness table for Self. |
| |
| if (auto *proto = FnType->getDefaultWitnessMethodProtocol(M)) { |
| auto selfTy = FnType->getSelfInstanceType(); |
| CanType argTy = getTypeInContext(selfTy); |
| auto archetype = cast<ArchetypeType>(argTy); |
| |
| setProtocolWitnessTableName(IGF.IGM, wtable, argTy, proto); |
| IGF.setUnscopedLocalTypeData(archetype, |
| LocalTypeDataKind::forAbstractProtocolWitnessTable(proto), |
| wtable); |
| } |
| return; |
| } |
| } |
| llvm_unreachable("bad source kind!"); |
| } |
| |
| void EmitPolymorphicParameters::bindParameterSources(const GetParameterFn &getParameter) { |
| auto params = FnType->getParameters(); |
| |
| // Bind things from 'self' preferentially. |
| if (FnType->hasSelfParam()) { |
| bindParameterSource(params.back(), params.size() - 1, getParameter); |
| params = params.drop_back(); |
| } |
| |
| for (unsigned index : indices(params)) { |
| bindParameterSource(params[index], index, getParameter); |
| } |
| } |
| |
| void EmitPolymorphicParameters::bindParameterSource(SILParameterInfo param, unsigned paramIndex, |
| const GetParameterFn &getParameter) { |
| // Ignore indirect parameters for now. This is potentially dumb. |
| if (IGF.IGM.silConv.isSILIndirect(param)) |
| return; |
| |
| CanType paramType = getArgTypeInContext(paramIndex); |
| |
| // If the parameter is a thick metatype, bind it directly. |
| // TODO: objc metatypes? |
| if (auto metatype = dyn_cast<MetatypeType>(paramType)) { |
| if (metatype->getRepresentation() == MetatypeRepresentation::Thick) { |
| paramType = metatype.getInstanceType(); |
| llvm::Value *metadata = getParameter(paramIndex); |
| IGF.bindLocalTypeDataFromTypeMetadata(paramType, IsInexact, metadata); |
| } |
| return; |
| } |
| |
| // If the parameter is a class type, we only consider it interesting |
| // if the convention decided it was actually a source. |
| // TODO: if the class pointer is guaranteed, we can do this lazily, |
| // at which point it might make sense to do it for a wider selection |
| // of types. |
| if (isClassPointerSource(paramIndex)) { |
| llvm::Value *instanceRef = getParameter(paramIndex); |
| SILType instanceType = SILType::getPrimitiveObjectType(paramType); |
| llvm::Value *metadata = |
| emitDynamicTypeOfHeapObject(IGF, instanceRef, instanceType); |
| IGF.bindLocalTypeDataFromTypeMetadata(paramType, IsInexact, metadata); |
| return; |
| } |
| } |
| |
| bool EmitPolymorphicParameters::isClassPointerSource(unsigned paramIndex) { |
| for (auto &source : getSources()) { |
| if (source.getKind() == MetadataSource::Kind::ClassPointer && |
| source.getParamIndex() == paramIndex) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| namespace { |
| |
| /// A class for binding type parameters of a generic function. |
| class BindPolymorphicParameter : public PolymorphicConvention { |
| IRGenFunction &IGF; |
| CanSILFunctionType &SubstFnType; |
| |
| public: |
| BindPolymorphicParameter(IRGenFunction &IGF, CanSILFunctionType &origFnType, |
| CanSILFunctionType &SubstFnType) |
| : PolymorphicConvention(IGF.IGM, origFnType), IGF(IGF), |
| SubstFnType(SubstFnType) {} |
| |
| void emit(Explosion &in, unsigned paramIndex); |
| |
| private: |
| // Did the convention decide that the parameter at the given index |
| // was a class-pointer source? |
| bool isClassPointerSource(unsigned paramIndex); |
| }; |
| |
| } // end anonymous namespace |
| |
| bool BindPolymorphicParameter::isClassPointerSource(unsigned paramIndex) { |
| for (auto &source : getSources()) { |
| if (source.getKind() == MetadataSource::Kind::ClassPointer && |
| source.getParamIndex() == paramIndex) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| void BindPolymorphicParameter::emit(Explosion &nativeParam, unsigned paramIndex) { |
| if (!isClassPointerSource(paramIndex)) |
| return; |
| |
| assert(nativeParam.size() == 1); |
| auto paramType = SubstFnType->getParameters()[paramIndex].getType(); |
| llvm::Value *instanceRef = nativeParam.getAll()[0]; |
| SILType instanceType = SILType::getPrimitiveObjectType(paramType); |
| llvm::Value *metadata = |
| emitDynamicTypeOfHeapObject(IGF, instanceRef, instanceType); |
| IGF.bindLocalTypeDataFromTypeMetadata(paramType, IsInexact, metadata); |
| } |
| |
| void irgen::bindPolymorphicParameter(IRGenFunction &IGF, |
| CanSILFunctionType &OrigFnType, |
| CanSILFunctionType &SubstFnType, |
| Explosion &nativeParam, |
| unsigned paramIndex) { |
| BindPolymorphicParameter(IGF, OrigFnType, SubstFnType) |
| .emit(nativeParam, paramIndex); |
| } |
| |
| static bool shouldSetName(IRGenModule &IGM, llvm::Value *value, CanType type) { |
| // If value names are globally disabled, honor that. |
| if (!IGM.EnableValueNames) return false; |
| |
| // Suppress value names for values with opened existentials. |
| if (type->hasOpenedExistential()) return false; |
| |
| // If the value already has a name, honor that. |
| if (value->hasName()) return false; |
| |
| // Only do this for local values. |
| return (isa<llvm::Instruction>(value) || isa<llvm::Argument>(value)); |
| } |
| |
| void irgen::setTypeMetadataName(IRGenModule &IGM, llvm::Value *metadata, |
| CanType type) { |
| if (!shouldSetName(IGM, metadata, type)) return; |
| |
| SmallString<128> name; { |
| llvm::raw_svector_ostream out(name); |
| type.print(out); |
| } |
| metadata->setName(type->getString()); |
| } |
| |
| void irgen::setProtocolWitnessTableName(IRGenModule &IGM, llvm::Value *wtable, |
| CanType type, |
| ProtocolDecl *requirement) { |
| if (!shouldSetName(IGM, wtable, type)) return; |
| |
| SmallString<128> name; { |
| llvm::raw_svector_ostream out(name); |
| type.print(out); |
| out << '.' << requirement->getNameStr(); |
| } |
| wtable->setName(name); |
| } |
| |
| namespace { |
| /// A concrete witness table, together with its known layout. |
| class WitnessTable { |
| llvm::Value *Table; |
| const ProtocolInfo &Info; |
| public: |
| WitnessTable(llvm::Value *wtable, const ProtocolInfo &info) |
| : Table(wtable), Info(info) {} |
| |
| llvm::Value *getTable() const { return Table; } |
| const ProtocolInfo &getInfo() const { return Info; } |
| }; |
| |
| /// A class which lays out a witness table in the abstract. |
| class WitnessTableLayout : public SILWitnessVisitor<WitnessTableLayout> { |
| SmallVector<WitnessTableEntry, 16> Entries; |
| |
| public: |
| /// The next witness is an out-of-line base protocol. |
| void addOutOfLineBaseProtocol(ProtocolDecl *baseProto) { |
| Entries.push_back(WitnessTableEntry::forOutOfLineBase(baseProto)); |
| } |
| |
| void addMethod(FuncDecl *func) { |
| Entries.push_back(WitnessTableEntry::forFunction(func)); |
| } |
| |
| void addConstructor(ConstructorDecl *ctor) { |
| Entries.push_back(WitnessTableEntry::forFunction(ctor)); |
| } |
| |
| void addPlaceholder(MissingMemberDecl *placeholder) { |
| for (auto i : range(placeholder->getNumberOfVTableEntries())) { |
| (void)i; |
| Entries.push_back(WitnessTableEntry()); |
| } |
| } |
| |
| void addAssociatedType(AssociatedTypeDecl *ty) { |
| Entries.push_back(WitnessTableEntry::forAssociatedType(ty)); |
| } |
| |
| void addAssociatedConformance(CanType path, ProtocolDecl *protocol) { |
| Entries.push_back( |
| WitnessTableEntry::forAssociatedConformance(path, protocol)); |
| } |
| |
| ArrayRef<WitnessTableEntry> getEntries() const { return Entries; } |
| }; |
| |
| /// A path through a protocol hierarchy. |
| class ProtocolPath { |
| IRGenModule &IGM; |
| |
| /// The destination protocol. |
| ProtocolDecl *Dest; |
| |
| /// The path from the selected origin down to the destination |
| /// protocol. |
| SmallVector<WitnessIndex, 8> ReversePath; |
| |
| /// The origin index to use. |
| unsigned OriginIndex; |
| |
| /// The best path length we found. |
| unsigned BestPathLength; |
| |
| public: |
| /// Find a path from the given set of origins to the destination |
| /// protocol. |
| /// |
| /// T needs to provide a couple of member functions: |
| /// ProtocolDecl *getProtocol() const; |
| /// const ProtocolInfo &getInfo() const; |
| template <class T> |
| ProtocolPath(IRGenModule &IGM, ArrayRef<T> origins, ProtocolDecl *dest) |
| : IGM(IGM), Dest(dest), BestPathLength(~0U) { |
| |
| // Consider each of the origins in turn, breaking out if any of |
| // them yields a zero-length path. |
| for (unsigned i = 0, e = origins.size(); i != e; ++i) { |
| auto &origin = origins[i]; |
| if (considerOrigin(origin.getProtocol(), origin.getInfo(), i)) |
| break; |
| } |
| |
| // Sanity check that we actually found a path at all. |
| assert(BestPathLength != ~0U); |
| assert(BestPathLength == ReversePath.size()); |
| } |
| |
| /// Returns the index of the origin protocol we chose. |
| unsigned getOriginIndex() const { return OriginIndex; } |
| |
| /// Apply the path to the given witness table. |
| llvm::Value *apply(IRGenFunction &IGF, llvm::Value *wtable) const { |
| for (unsigned i = ReversePath.size(); i != 0; --i) { |
| wtable = emitInvariantLoadOfOpaqueWitness(IGF, wtable, |
| ReversePath[i-1]); |
| wtable = IGF.Builder.CreateBitCast(wtable, IGF.IGM.WitnessTablePtrTy); |
| } |
| return wtable; |
| } |
| |
| private: |
| /// Consider paths starting from a new origin protocol. |
| /// Returns true if there's no point in considering other origins. |
| bool considerOrigin(ProtocolDecl *origin, const ProtocolInfo &originInfo, |
| unsigned originIndex) { |
| assert(BestPathLength != 0); |
| |
| // If the origin *is* the destination, we can stop here. |
| if (origin == Dest) { |
| OriginIndex = originIndex; |
| BestPathLength = 0; |
| ReversePath.clear(); |
| return true; |
| } |
| |
| // Otherwise, if the origin gives rise to a better path, that's |
| // also cool. |
| if (findBetterPath(origin, originInfo, 0)) { |
| OriginIndex = originIndex; |
| return BestPathLength == 0; |
| } |
| |
| return false; |
| } |
| |
| /// Consider paths starting at the given protocol. |
| bool findBetterPath(ProtocolDecl *proto, const ProtocolInfo &protoInfo, |
| unsigned lengthSoFar) { |
| assert(lengthSoFar < BestPathLength); |
| assert(proto != Dest); |
| |
| // Keep track of whether we found a better path than the |
| // previous best. |
| bool foundBetter = false; |
| for (auto base : proto->getInheritedProtocols()) { |
| // ObjC protocols do not have witnesses. |
| if (!Lowering::TypeConverter::protocolRequiresWitnessTable(base)) |
| continue; |
| |
| auto baseIndex = protoInfo.getBaseIndex(base); |
| |
| // Compute the length down to this base. |
| unsigned lengthToBase = lengthSoFar; |
| if (!baseIndex.isPrefix()) { |
| lengthToBase++; |
| |
| // Don't consider this path if we reach a length that can't |
| // possibly be better than the best so far. |
| if (lengthToBase == BestPathLength) continue; |
| } |
| assert(lengthToBase < BestPathLength); |
| |
| // If this base *is* the destination, go ahead and start |
| // building the path into ReversePath. |
| if (base == Dest) { |
| // Reset the collected best-path information. |
| BestPathLength = lengthToBase; |
| ReversePath.clear(); |
| |
| // Otherwise, if there isn't a better path through this base, |
| // don't accumulate anything in the path. |
| } else if (!findBetterPath(base, IGM.getProtocolInfo(base), |
| lengthToBase)) { |
| continue; |
| } |
| |
| // Okay, we've found a better path, and ReversePath contains a |
| // path leading from base to Dest. |
| assert(BestPathLength >= lengthToBase); |
| foundBetter = true; |
| |
| // Add the link from proto to base if necessary. |
| if (!baseIndex.isPrefix()) { |
| ReversePath.push_back(baseIndex); |
| |
| // If it isn't necessary, then we might be able to |
| // short-circuit considering the bases of this protocol. |
| } else { |
| if (lengthSoFar == BestPathLength) |
| return true; |
| } |
| } |
| |
| return foundBetter; |
| } |
| }; |
| |
| } // end anonymous namespace |
| |
| /// Return true if the witness table requires runtime instantiation to |
| /// handle resiliently-added requirements with default implementations. |
| static bool isResilientConformance(const NormalProtocolConformance *conformance) { |
| // If the protocol is not resilient, the conformance is not resilient |
| // either. |
| if (conformance->getProtocol()->hasFixedLayout()) |
| return false; |
| |
| // If the protocol is in the same module as the conformance, we're |
| // not resilient. |
| if (conformance->getDeclContext()->getParentModule() |
| == conformance->getProtocol()->getParentModule()) |
| return false; |
| |
| // We have a resilient conformance. |
| return true; |
| } |
| |
| /// Is there anything about the given conformance that requires witness |
| /// tables to be dependently-generated? |
| static bool isDependentConformance(IRGenModule &IGM, |
| const NormalProtocolConformance *conformance, |
| ResilienceExpansion expansion) { |
| // If the conformance is resilient, this is always true. |
| if (isResilientConformance(conformance)) |
| return true; |
| |
| // Check whether any of the inherited conformances are dependent. |
| for (auto inherited : conformance->getProtocol()->getInheritedProtocols()) { |
| if (isDependentConformance(IGM, |
| conformance->getInheritedConformance(inherited) |
| ->getRootNormalConformance(), |
| expansion)) |
| return true; |
| } |
| |
| // If the conforming type isn't dependent, the below check is never true. |
| if (!conformance->getDeclContext()->isGenericContext()) |
| return false; |
| |
| // Check whether any of the associated types are dependent. |
| if (conformance->forEachTypeWitness(nullptr, |
| [&](AssociatedTypeDecl *requirement, Type type, |
| TypeDecl *explicitDecl) -> bool { |
| // RESILIENCE: this could be an opaque conformance |
| return type->hasArchetype(); |
| })) { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /// Detail about how an object conforms to a protocol. |
| class irgen::ConformanceInfo { |
| friend ProtocolInfo; |
| public: |
| virtual ~ConformanceInfo() {} |
| virtual llvm::Value *getTable(IRGenFunction &IGF, |
| CanType conformingType, |
| llvm::Value **conformingMetadataCache) const = 0; |
| /// Try to get this table as a constant pointer. This might just |
| /// not be supportable at all. |
| virtual llvm::Constant *tryGetConstantTable(IRGenModule &IGM, |
| CanType conformingType) const = 0; |
| }; |
| |
| static llvm::Value * |
| emitWitnessTableAccessorCall(IRGenFunction &IGF, |
| const NormalProtocolConformance *conformance, |
| CanType conformingType, |
| llvm::Value **srcMetadataCache) { |
| auto accessor = |
| IGF.IGM.getAddrOfWitnessTableAccessFunction(conformance, NotForDefinition); |
| |
| // If the conformance is generic, the accessor takes the metatype |
| // as an argument. |
| llvm::CallInst *call; |
| if (conformance->getDeclContext()->isGenericContext()) { |
| // Emit the source metadata if we haven't yet. |
| if (!*srcMetadataCache) { |
| *srcMetadataCache = IGF.emitTypeMetadataRef(conformingType); |
| } |
| call = IGF.Builder.CreateCall(accessor, {*srcMetadataCache}); |
| } else { |
| call = IGF.Builder.CreateCall(accessor, {}); |
| } |
| |
| call->setCallingConv(IGF.IGM.DefaultCC); |
| call->setDoesNotAccessMemory(); |
| call->setDoesNotThrow(); |
| |
| return call; |
| } |
| |
| /// Fetch the lazy access function for the given conformance of the |
| /// given type. |
| static llvm::Function * |
| getWitnessTableLazyAccessFunction(IRGenModule &IGM, |
| const NormalProtocolConformance *conformance, |
| CanType conformingType) { |
| assert(!conformingType->hasArchetype()); |
| llvm::Function *accessor = |
| IGM.getAddrOfWitnessTableLazyAccessFunction(conformance, conformingType, |
| ForDefinition); |
| |
| // If we're not supposed to define the accessor, or if we already |
| // have defined it, just return the pointer. |
| if (!accessor->empty()) |
| return accessor; |
| |
| // Okay, define the accessor. |
| auto cacheVariable = cast<llvm::GlobalVariable>( |
| IGM.getAddrOfWitnessTableLazyCacheVariable(conformance, conformingType, |
| ForDefinition)); |
| emitLazyCacheAccessFunction(IGM, accessor, cacheVariable, |
| [&](IRGenFunction &IGF) -> llvm::Value* { |
| llvm::Value *conformingMetadataCache = nullptr; |
| return emitWitnessTableAccessorCall(IGF, conformance, conformingType, |
| &conformingMetadataCache); |
| }); |
| |
| return accessor; |
| } |
| |
| namespace { |
| |
| /// Conformance info for a witness table that can be directly generated. |
| class DirectConformanceInfo : public ConformanceInfo { |
| friend ProtocolInfo; |
| |
| const NormalProtocolConformance *RootConformance; |
| public: |
| DirectConformanceInfo(const NormalProtocolConformance *C) |
| : RootConformance(C) {} |
| |
| llvm::Value *getTable(IRGenFunction &IGF, CanType conformingType, |
| llvm::Value **conformingMetadataCache) const override { |
| return IGF.IGM.getAddrOfWitnessTable(RootConformance); |
| } |
| |
| llvm::Constant *tryGetConstantTable(IRGenModule &IGM, |
| CanType conformingType) const override { |
| return IGM.getAddrOfWitnessTable(RootConformance); |
| } |
| }; |
| |
| /// Conformance info for a witness table that is (or may be) dependent. |
| class AccessorConformanceInfo : public ConformanceInfo { |
| friend ProtocolInfo; |
| |
| const NormalProtocolConformance *Conformance; |
| public: |
| AccessorConformanceInfo(const NormalProtocolConformance *C) |
| : Conformance(C) {} |
| |
| llvm::Value *getTable(IRGenFunction &IGF, CanType type, |
| llvm::Value **typeMetadataCache) const override { |
| // If we're looking up a dependent type, we can't cache the result. |
| if (type->hasArchetype()) { |
| return emitWitnessTableAccessorCall(IGF, Conformance, type, |
| typeMetadataCache); |
| } |
| |
| // Otherwise, call a lazy-cache function. |
| auto accessor = |
| getWitnessTableLazyAccessFunction(IGF.IGM, Conformance, type); |
| llvm::CallInst *call = IGF.Builder.CreateCall(accessor, {}); |
| call->setCallingConv(IGF.IGM.DefaultCC); |
| call->setDoesNotAccessMemory(); |
| call->setDoesNotThrow(); |
| |
| return call; |
| } |
| |
| llvm::Constant *tryGetConstantTable(IRGenModule &IGM, |
| CanType conformingType) const override { |
| return nullptr; |
| } |
| }; |
| |
| /// A class which lays out a specific conformance to a protocol. |
| class WitnessTableBuilder : public SILWitnessVisitor<WitnessTableBuilder> { |
| IRGenModule &IGM; |
| ConstantArrayBuilder &Table; |
| unsigned TableSize = ~0U; // will get overwritten unconditionally |
| CanType ConcreteType; |
| const NormalProtocolConformance &Conformance; |
| ArrayRef<SILWitnessTable::Entry> SILEntries; |
| const ProtocolInfo &PI; |
| Optional<FulfillmentMap> Fulfillments; |
| SmallVector<std::pair<size_t, const ConformanceInfo *>, 4> |
| SpecializedBaseConformances; |
| // Metadata caches are stored at negative offsets. |
| unsigned NextCacheIndex = 0; |
| bool RequiresSpecialization = false; |
| |
| public: |
| WitnessTableBuilder(IRGenModule &IGM, |
| ConstantArrayBuilder &table, |
| SILWitnessTable *SILWT) |
| : IGM(IGM), Table(table), |
| ConcreteType(SILWT->getConformance()->getType()->getCanonicalType()), |
| Conformance(*SILWT->getConformance()), |
| SILEntries(SILWT->getEntries()), |
| PI(IGM.getProtocolInfo(SILWT->getConformance()->getProtocol())) |
| { |
| // TODO: in conditional conformances, allocate space for the assumed |
| // conformances here. |
| |
| // If the conformance is resilient, we require runtime instantiation. |
| if (isResilientConformance(&Conformance)) |
| RequiresSpecialization = true; |
| } |
| |
| /// The top-level entry point. |
| void build(); |
| |
| /// Create the access function. |
| void buildAccessFunction(llvm::Constant *wtable); |
| |
| /// A base protocol is witnessed by a pointer to the conformance |
| /// of this type to that protocol. |
| void addOutOfLineBaseProtocol(ProtocolDecl *baseProto) { |
| #ifndef NDEBUG |
| auto &entry = SILEntries.front(); |
| assert(entry.getKind() == SILWitnessTable::BaseProtocol |
| && "sil witness table does not match protocol"); |
| assert(entry.getBaseProtocolWitness().Requirement == baseProto |
| && "sil witness table does not match protocol"); |
| auto piIndex = PI.getBaseIndex(baseProto); |
| assert(piIndex.getValue() == Table.size() |
| && "offset doesn't match ProtocolInfo layout"); |
| #endif |
| |
| SILEntries = SILEntries.slice(1); |
| |
| // TODO: Use the witness entry instead of falling through here. |
| |
| // Look for a protocol type info. |
| const ProtocolInfo &basePI = IGM.getProtocolInfo(baseProto); |
| const ProtocolConformance *astConf |
| = Conformance.getInheritedConformance(baseProto); |
| const ConformanceInfo &conf = |
| basePI.getConformance(IGM, baseProto, astConf); |
| |
| // If we can emit the base witness table as a constant, do so. |
| llvm::Constant *baseWitness = conf.tryGetConstantTable(IGM, ConcreteType); |
| if (baseWitness) { |
| Table.addBitCast(baseWitness, IGM.Int8PtrTy); |
| return; |
| } |
| |
| // Otherwise, we'll need to derive it at instantiation time. |
| RequiresSpecialization = true; |
| SpecializedBaseConformances.push_back({Table.size(), &conf}); |
| Table.addNullPointer(IGM.Int8PtrTy); |
| } |
| |
| void addMethodFromSILWitnessTable(AbstractFunctionDecl *requirement) { |
| auto &entry = SILEntries.front(); |
| SILEntries = SILEntries.slice(1); |
| |
| // Handle missing optional requirements. |
| if (entry.getKind() == SILWitnessTable::MissingOptional) { |
| Table.addNullPointer(IGM.Int8PtrTy); |
| return; |
| } |
| |
| #ifndef NDEBUG |
| assert(entry.getKind() == SILWitnessTable::Method |
| && "sil witness table does not match protocol"); |
| assert(entry.getMethodWitness().Requirement.getDecl() == requirement |
| && "sil witness table does not match protocol"); |
| auto piIndex = PI.getFunctionIndex(requirement); |
| assert(piIndex.getValue() == Table.size() |
| && "offset doesn't match ProtocolInfo layout"); |
| #endif |
| |
| SILFunction *Func = entry.getMethodWitness().Witness; |
| llvm::Constant *witness = nullptr; |
| if (Func) { |
| witness = IGM.getAddrOfSILFunction(Func, NotForDefinition); |
| } else { |
| // The method is removed by dead method elimination. |
| // It should be never called. We add a pointer to an error function. |
| witness = IGM.getDeletedMethodErrorFn(); |
| } |
| Table.addBitCast(witness, IGM.Int8PtrTy); |
| return; |
| } |
| |
| void addMethod(FuncDecl *requirement) { |
| return addMethodFromSILWitnessTable(requirement); |
| } |
| |
| void addConstructor(ConstructorDecl *requirement) { |
| return addMethodFromSILWitnessTable(requirement); |
| } |
| |
| void addPlaceholder(MissingMemberDecl *placeholder) { |
| llvm_unreachable("cannot emit a witness table with placeholders in it"); |
| } |
| |
| void addAssociatedType(AssociatedTypeDecl *requirement) { |
| #ifndef NDEBUG |
| auto &entry = SILEntries.front(); |
| assert(entry.getKind() == SILWitnessTable::AssociatedType |
| && "sil witness table does not match protocol"); |
| assert(entry.getAssociatedTypeWitness().Requirement == requirement |
| && "sil witness table does not match protocol"); |
| auto piIndex = PI.getAssociatedTypeIndex(requirement); |
| assert(piIndex.getValue() == Table.size() |
| && "offset doesn't match ProtocolInfo layout"); |
| #endif |
| |
| SILEntries = SILEntries.slice(1); |
| |
| CanType associate = |
| Conformance.getTypeWitness(requirement, nullptr)->getCanonicalType(); |
| |
| // This type will be expressed in terms of the archetypes |
| // of the conforming context. |
| assert(!associate->hasTypeParameter()); |
| |
| llvm::Constant *metadataAccessFunction = |
| getAssociatedTypeMetadataAccessFunction(requirement, associate); |
| Table.addBitCast(metadataAccessFunction, IGM.Int8PtrTy); |
| } |
| |
| void addAssociatedConformance(Type associatedType, ProtocolDecl *protocol) { |
| // FIXME: Add static witness tables for type conformances. |
| |
| CanType associate = Conformance.getAssociatedType(associatedType) |
| ->getCanonicalType(); |
| assert(!associate->hasTypeParameter()); |
| |
| ProtocolConformanceRef associatedConformance = |
| Conformance.getAssociatedConformance(associatedType, protocol); |
| |
| #ifndef NDEBUG |
| auto &entry = SILEntries.front(); |
| (void)entry; |
| assert(entry.getKind() == SILWitnessTable::AssociatedTypeProtocol |
| && "sil witness table does not match protocol"); |
| auto associatedWitness = entry.getAssociatedTypeProtocolWitness(); |
| assert(associatedWitness.Requirement->isEqual(associatedType) |
| && "sil witness table does not match protocol"); |
| assert(associatedWitness.Protocol == protocol |
| && "sil witness table does not match protocol"); |
| auto piIndex = |
| PI.getAssociatedConformanceIndex(associatedType->getCanonicalType(), |
| protocol); |
| assert(piIndex.getValue() == Table.size() |
| && "offset doesn't match ProtocolInfo layout"); |
| #endif |
| |
| SILEntries = SILEntries.slice(1); |
| |
| llvm::Constant *wtableAccessFunction = |
| getAssociatedTypeWitnessTableAccessFunction(CanType(associatedType), |
| associate, protocol, associatedConformance); |
| Table.addBitCast(wtableAccessFunction, IGM.Int8PtrTy); |
| } |
| |
| private: |
| llvm::Constant *buildInstantiationFunction(); |
| |
| llvm::Constant * |
| getAssociatedTypeMetadataAccessFunction(AssociatedTypeDecl *requirement, |
| CanType associatedType); |
| |
| llvm::Constant * |
| getAssociatedTypeWitnessTableAccessFunction(CanType depAssociatedType, |
| CanType associatedType, |
| ProtocolDecl *protocol, |
| ProtocolConformanceRef conformance); |
| |
| void emitReturnOfCheckedLoadFromCache(IRGenFunction &IGF, |
| Address destTable, |
| llvm::Value *selfMetadata, |
| llvm::function_ref<llvm::Value*()> body); |
| |
| /// Allocate another word of private data storage in the conformance table. |
| unsigned getNextCacheIndex() { |
| RequiresSpecialization = true; |
| return NextCacheIndex++; |
| } |
| |
| const FulfillmentMap &getFulfillmentMap() { |
| if (Fulfillments) return *Fulfillments; |
| |
| Fulfillments.emplace(); |
| if (ConcreteType->hasArchetype()) { |
| struct Callback : FulfillmentMap::InterestingKeysCallback { |
| bool isInterestingType(CanType type) const override { |
| return isa<ArchetypeType>(type); |
| } |
| bool hasInterestingType(CanType type) const override { |
| return type->hasArchetype(); |
| } |
| bool hasLimitedInterestingConformances(CanType type) const override { |
| return false; |
| } |
| GenericSignature::ConformsToArray |
| getInterestingConformances(CanType type) const override { |
| llvm_unreachable("no limits"); |
| } |
| } callback; |
| Fulfillments->searchTypeMetadata(IGM, ConcreteType, IsExact, |
| /*sourceIndex*/ 0, MetadataPath(), |
| callback); |
| } |
| return *Fulfillments; |
| } |
| }; |
| } // end anonymous namespace |
| |
| /// Build the witness table. |
| void WitnessTableBuilder::build() { |
| visitProtocolDecl(Conformance.getProtocol()); |
| TableSize = Table.size(); |
| } |
| |
| /// Return the address of a function which will return the type metadata |
| /// for an associated type. |
| llvm::Constant *WitnessTableBuilder:: |
| getAssociatedTypeMetadataAccessFunction(AssociatedTypeDecl *requirement, |
| CanType associatedType) { |
| // If the associated type is non-dependent, we can use an ordinary |
| // metadata access function. We'll just end up passing extra arguments. |
| if (!associatedType->hasArchetype()) { |
| return getOrCreateTypeMetadataAccessFunction(IGM, associatedType); |
| } |
| |
| // Otherwise, emit an access function. |
| llvm::Function *accessor = |
| IGM.getAddrOfAssociatedTypeMetadataAccessFunction(&Conformance, |
| requirement); |
| |
| IRGenFunction IGF(IGM, accessor); |
| if (IGM.DebugInfo) |
| IGM.DebugInfo->emitArtificialFunction(IGF, accessor); |
| |
| Explosion parameters = IGF.collectParameters(); |
| |
| llvm::Value *self = parameters.claimNext(); |
| setTypeMetadataName(IGM, self, ConcreteType); |
| |
| Address destTable(parameters.claimNext(), IGM.getPointerAlignment()); |
| setProtocolWitnessTableName(IGM, destTable.getAddress(), ConcreteType, |
| requirement->getProtocol()); |
| |
| // If the associated type is directly fulfillable from the type, |
| // we don't need a cache entry. |
| // TODO: maybe we should have a cache entry anyway if the fulfillment |
| // is expensive. |
| if (auto fulfillment = |
| getFulfillmentMap().getTypeMetadata(associatedType)) { |
| llvm::Value *metadata = |
| fulfillment->Path.followFromTypeMetadata(IGF, ConcreteType, self, |
| /*cache*/ nullptr); |
| IGF.Builder.CreateRet(metadata); |
| return accessor; |
| } |
| |
| // Bind local type data from the metadata argument. |
| IGF.bindLocalTypeDataFromTypeMetadata(ConcreteType, IsExact, self); |
| |
| // For now, assume that an associated type is cheap enough to access |
| // that it doesn't need a new cache entry. |
| if (auto archetype = dyn_cast<ArchetypeType>(associatedType)) { |
| llvm::Value *metadata = emitArchetypeTypeMetadataRef(IGF, archetype); |
| IGF.Builder.CreateRet(metadata); |
| return accessor; |
| } |
| |
| // Otherwise, we need a cache entry. |
| emitReturnOfCheckedLoadFromCache(IGF, destTable, self, |
| [&]() -> llvm::Value* { |
| return IGF.emitTypeMetadataRef(associatedType); |
| }); |
| |
| return accessor; |
| } |
| |
| /// Return a function which will return a particular witness table |
| /// conformance. The function will be passed the metadata for which |
| /// the conformance is being requested; it may ignore this (perhaps |
| /// implicitly by taking no arguments). |
| static llvm::Constant * |
| getOrCreateWitnessTableAccessFunction(IRGenModule &IGM, CanType type, |
| ProtocolConformance *conformance) { |
| assert(!type->hasArchetype() && "cannot do this for dependent type"); |
| |
| // We always emit an access function for conformances, and in principle |
| // it is always possible to just use that here directly. However, |
| // if it's dependent, doing so won't allow us to cache the result. |
| // For the specific use case of an associated type conformance, we could |
| // use a cache in the witness table; but that wastes space per conformance |
| // and won't let us re-use the cache with other non-dependent uses in |
| // the module. Therefore, in this case, we use the address of the lazy-cache |
| // function. |
| // |
| // FIXME: we will need to pass additional parameters if the target |
| // conformance is conditional. |
| auto rootConformance = conformance->getRootNormalConformance(); |
| if (rootConformance->getDeclContext()->isGenericContext()) { |
| return getWitnessTableLazyAccessFunction(IGM, rootConformance, type); |
| } else { |
| return IGM.getAddrOfWitnessTableAccessFunction( |
| conformance->getRootNormalConformance(), |
| NotForDefinition); |
| } |
| } |
| |
| static void buildAssociatedTypeValueName(CanType depAssociatedType, |
| SmallString<128> &name) { |
| if (auto memberType = dyn_cast<DependentMemberType>(depAssociatedType)) { |
| buildAssociatedTypeValueName(memberType.getBase(), name); |
| name += '.'; |
| name += memberType->getName().str(); |
| } else { |
| assert(isa<GenericTypeParamType>(depAssociatedType)); // Self |
| } |
| } |
| |
| llvm::Constant *WitnessTableBuilder:: |
| getAssociatedTypeWitnessTableAccessFunction(CanType depAssociatedType, |
| CanType associatedType, |
| ProtocolDecl *associatedProtocol, |
| ProtocolConformanceRef associatedConformance) { |
| if (!associatedType->hasArchetype()) { |
| assert(associatedConformance.isConcrete() && |
| "no concrete conformance for non-dependent type"); |
| return getOrCreateWitnessTableAccessFunction(IGM, associatedType, |
| associatedConformance.getConcrete()); |
| } |
| |
| // Otherwise, emit an access function. |
| llvm::Function *accessor = |
| IGM.getAddrOfAssociatedTypeWitnessTableAccessFunction(&Conformance, |
| depAssociatedType, |
| associatedProtocol); |
| |
| IRGenFunction IGF(IGM, accessor); |
| if (IGM.DebugInfo) |
| IGM.DebugInfo->emitArtificialFunction(IGF, accessor); |
| |
| Explosion parameters = IGF.collectParameters(); |
| |
| llvm::Value *associatedTypeMetadata = parameters.claimNext(); |
| |
| // We use a non-standard name for the type that states the association |
| // requirement rather than the concrete type. |
| if (IGM.EnableValueNames) { |
| SmallString<128> name; |
| name += ConcreteType->getString(); |
| buildAssociatedTypeValueName(depAssociatedType, name); |
| associatedTypeMetadata->setName(name); |
| } |
| |
| llvm::Value *self = parameters.claimNext(); |
| setTypeMetadataName(IGM, self, ConcreteType); |
| |
| Address destTable(parameters.claimNext(), IGM.getPointerAlignment()); |
| setProtocolWitnessTableName(IGM, destTable.getAddress(), ConcreteType, |
| Conformance.getProtocol()); |
| |
| const ConformanceInfo *conformanceI = nullptr; |
| if (associatedConformance.isConcrete()) { |
| const ProtocolInfo &protocolI = IGM.getProtocolInfo(associatedProtocol); |
| conformanceI = |
| &protocolI.getConformance(IGM, associatedProtocol, |
| associatedConformance.getConcrete()); |
| |
| // If we can emit a constant table, do so. |
| // In principle, any time we can do this, we should try to re-use this |
| // function for other conformances. But that should typically already |
| // be covered by the !hasArchetype() check above. |
| if (auto constantTable = |
| conformanceI->tryGetConstantTable(IGM, associatedType)) { |
| IGF.Builder.CreateRet(constantTable); |
| return accessor; |
| } |
| } |
| |
| // If the witness table is directly fulfillable from the type, |
| // we don't need a cache entry. |
| // TODO: maybe we should have a cache entry anyway if the fulfillment |
| // is expensive. |
| if (auto fulfillment = |
| getFulfillmentMap().getWitnessTable(associatedType, |
| associatedProtocol)) { |
| llvm::Value *wtable = |
| fulfillment->Path.followFromTypeMetadata(IGF, ConcreteType, self, |
| /*cache*/ nullptr); |
| IGF.Builder.CreateRet(wtable); |
| return accessor; |
| } |
| |
| // Bind local type data from the metadata arguments. |
| IGF.bindLocalTypeDataFromTypeMetadata(associatedType, IsExact, |
| associatedTypeMetadata); |
| IGF.bindLocalTypeDataFromTypeMetadata(ConcreteType, IsExact, self); |
| |
| // For now, assume that finding an abstract conformance is always |
| // fast enough that it's not worth caching. |
| // TODO: provide an API to find the best metadata path to the conformance |
| // and decide whether it's expensive enough to be worth caching. |
| if (!conformanceI) { |
| assert(associatedConformance.isAbstract()); |
| auto wtable = |
| emitArchetypeWitnessTableRef(IGF, cast<ArchetypeType>(associatedType), |
| associatedConformance.getAbstract()); |
| IGF.Builder.CreateRet(wtable); |
| return accessor; |
| } |
| |
| // Otherwise, we need a cache entry. |
| emitReturnOfCheckedLoadFromCache(IGF, destTable, self, |
| [&]() -> llvm::Value* { |
| return conformanceI->getTable(IGF, associatedType, &associatedTypeMetadata); |
| }); |
| |
| return accessor; |
| } |
| |
| void WitnessTableBuilder:: |
| emitReturnOfCheckedLoadFromCache(IRGenFunction &IGF, Address destTable, |
| llvm::Value *selfMetadata, |
| llvm::function_ref<llvm::Value*()> body) { |
| // Allocate a new cache slot and drill down to it. |
| int cacheIndex = -1 - getNextCacheIndex(); |
| Address cache = IGF.Builder.CreateConstArrayGEP(destTable, cacheIndex, |
| IGM.getPointerSize()); |
| |
| llvm::Type *expectedTy = IGF.CurFn->getReturnType(); |
| cache = IGF.Builder.CreateBitCast(cache, expectedTy->getPointerTo()); |
| |
| // Load and check whether it was null. |
| auto cachedResult = IGF.Builder.CreateLoad(cache); |
| // TODO: When LLVM supports Consume, we should use it here. |
| if (IGF.IGM.IRGen.Opts.Sanitize == SanitizerKind::Thread) |
| cachedResult->setOrdering(llvm::AtomicOrdering::Acquire); |
| auto cacheIsEmpty = IGF.Builder.CreateIsNull(cachedResult); |
| llvm::BasicBlock *fetchBB = IGF.createBasicBlock("fetch"); |
| llvm::BasicBlock *contBB = IGF.createBasicBlock("cont"); |
| llvm::BasicBlock *entryBB = IGF.Builder.GetInsertBlock(); |
| IGF.Builder.CreateCondBr(cacheIsEmpty, fetchBB, contBB); |
| |
| // Create a phi in the continuation block and use the loaded value if |
| // we branched directly here. Note that we arrange blocks so that we |
| // fall through into this. |
| IGF.Builder.emitBlock(contBB); |
| auto result = IGF.Builder.CreatePHI(expectedTy, 2); |
| result->addIncoming(cachedResult, entryBB); |
| IGF.Builder.CreateRet(result); |
| |
| // In the fetch block, bind the archetypes and evaluate the body. |
| IGF.Builder.emitBlock(fetchBB); |
| |
| llvm::Value *fetchedResult = body(); |
| |
| // Store the fetched result back to the cache. |
| // We need to transitively ensure that any stores initializing the result |
| // that are visible to us are visible to callers. |
| IGF.Builder.CreateStore(fetchedResult, cache)->setOrdering( |
| llvm::AtomicOrdering::Release); |
| |
| auto fetchedResultBB = IGF.Builder.GetInsertBlock(); |
| IGF.Builder.CreateBr(contBB); |
| result->addIncoming(fetchedResult, fetchedResultBB); |
| } |
| |
| /// Emit the access function for this witness table. |
| void WitnessTableBuilder::buildAccessFunction(llvm::Constant *wtable) { |
| llvm::Function *fn = |
| IGM.getAddrOfWitnessTableAccessFunction(&Conformance, ForDefinition); |
| |
| IRGenFunction IGF(IGM, fn); |
| if (IGM.DebugInfo) |
| IGM.DebugInfo->emitArtificialFunction(IGF, fn); |
| |
| wtable = llvm::ConstantExpr::getBitCast(wtable, IGM.WitnessTablePtrTy); |
| |
| // If specialization isn't required, just return immediately. |
| // TODO: allow dynamic specialization? |
| if (!RequiresSpecialization) { |
| IGF.Builder.CreateRet(wtable); |
| return; |
| } |
| |
| // The target metadata is the first argument. |
| assert(isDependentConformance(IGF.IGM, &Conformance, |
| ResilienceExpansion::Maximal)); |
| |
| Explosion params = IGF.collectParameters(); |
| llvm::Value *metadata; |
| |
| if (Conformance.getDeclContext()->isGenericContext()) |
| metadata = params.claimNext(); |
| else |
| metadata = llvm::ConstantPointerNull::get(IGF.IGM.TypeMetadataPtrTy); |
| |
| // Okay, we need a cache. Build the cache structure. |
| // struct GenericWitnessTable { |
| // /// The size of the witness table in words. |
| // uint16_t WitnessTableSizeInWords; |
| // |
| // /// The amount to copy from the pattern in words. The rest is zeroed. |
| // uint16_t WitnessTableSizeInWordsToCopy; |
| // |
| // /// The protocol. |
| // RelativeIndirectablePointer<ProtocolDescriptor> Protocol; |
| // |
| // /// The pattern. |
| // RelativeDirectPointer<WitnessTable> WitnessTable; |
| // |
| // /// The instantiation function, which is called after the template is copied. |
| // RelativeDirectPointer<void(WitnessTable *, const Metadata *)> Instantiator; |
| // |
| // void *PrivateData[swift::NumGenericMetadataPrivateDataWords]; |
| // }; |
| |
| // First, create the global. We have to build this in two phases because |
| // it contains relative pointers. |
| auto cache = cast<llvm::GlobalVariable>( |
| IGM.getAddrOfGenericWitnessTableCache(&Conformance, ForDefinition)); |
| |
| // We need an instantiation function if the base conformance |
| // is non-dependent. |
| // TODO: the conformance might be conditional. |
| llvm::Constant *instantiationFn; |
| llvm::Value *instantiationArgs = |
| llvm::ConstantPointerNull::get(IGM.Int8PtrPtrTy); |
| if (SpecializedBaseConformances.empty()) { |
| instantiationFn = llvm::ConstantInt::get(IGM.RelativeAddressTy, 0); |
| } else { |
| llvm::Constant *fn = buildInstantiationFunction(); |
| instantiationFn = IGM.emitDirectRelativeReference(fn, cache, { 4 }); |
| } |
| |
| auto descriptorRef = IGM.getAddrOfLLVMVariableOrGOTEquivalent( |
| LinkEntity::forProtocolDescriptor(Conformance.getProtocol()), |
| IGM.getPointerAlignment(), IGM.ProtocolDescriptorStructTy); |
| |
| // Fill in the global. |
| auto cacheTy = cast<llvm::StructType>(cache->getValueType()); |
| llvm::Constant *cacheData[] = { |
| // WitnessTableSizeInWords |
| llvm::ConstantInt::get(IGM.Int16Ty, TableSize), |
| // WitnessTablePrivateSizeInWords |
| llvm::ConstantInt::get(IGM.Int16Ty, NextCacheIndex), |
| // RelativeIndirectablePointer<ProtocolDescriptor> |
| IGM.emitRelativeReference(descriptorRef, cache, { 2 }), |
| // RelativePointer<WitnessTable> |
| IGM.emitDirectRelativeReference(wtable, cache, { 3 }), |
| // Instantiation function |
| instantiationFn, |
| // Private data |
| llvm::Constant::getNullValue(cacheTy->getStructElementType(5)) |
| }; |
| cache->setInitializer(llvm::ConstantStruct::get(cacheTy, cacheData)); |
| |
| auto call = IGF.Builder.CreateCall(IGM.getGetGenericWitnessTableFn(), |
| { cache, metadata, instantiationArgs }); |
| call->setDoesNotThrow(); |
| |
| IGF.Builder.CreateRet(call); |
| } |
| |
| llvm::Constant *WitnessTableBuilder::buildInstantiationFunction() { |
| llvm::Function *fn = |
| IGM.getAddrOfGenericWitnessTableInstantiationFunction(&Conformance); |
| IRGenFunction IGF(IGM, fn); |
| if (IGM.DebugInfo) |
| IGM.DebugInfo->emitArtificialFunction(IGF, fn); |
| |
| // Break out the parameters. |
| Explosion params = IGF.collectParameters(); |
| Address wtable(params.claimNext(), IGM.getPointerAlignment()); |
| llvm::Value *metadata = params.claimNext(); |
| llvm::Value *instantiationArgs = params.claimNext(); |
| (void) instantiationArgs; // unused for now |
| |
| // TODO: store any required conditional-conformance information |
| // in the private data. |
| |
| // Initialize all the specialized base conformances. |
| for (auto &base : SpecializedBaseConformances) { |
| // Ask the ConformanceInfo to emit the wtable. |
| // TODO: we may need to bind extra information in the IGF in order |
| // to make conditional conformances work. |
| llvm::Value *baseWTable = |
| base.second->getTable(IGF, ConcreteType, &metadata); |
| baseWTable = IGF.Builder.CreateBitCast(baseWTable, IGM.Int8PtrTy); |
| |
| // Store that to the appropriate slot in the new witness table. |
| Address slot = IGF.Builder.CreateConstArrayGEP(wtable, base.first, |
| IGM.getPointerSize()); |
| IGF.Builder.CreateStore(baseWTable, slot); |
| } |
| |
| IGF.Builder.CreateRetVoid(); |
| return fn; |
| } |
| |
| /// Do a memoized witness-table layout for a protocol. |
| const ProtocolInfo &IRGenModule::getProtocolInfo(ProtocolDecl *protocol) { |
| return Types.getProtocolInfo(protocol); |
| } |
| |
| /// Do a memoized witness-table layout for a protocol. |
| const ProtocolInfo &TypeConverter::getProtocolInfo(ProtocolDecl *protocol) { |
| // Check whether we've already translated this protocol. |
| auto it = Protocols.find(protocol); |
| if (it != Protocols.end()) return *it->second; |
| |
| // If not, lay out the protocol's witness table, if it needs one. |
| WitnessTableLayout layout; |
| if (Lowering::TypeConverter::protocolRequiresWitnessTable(protocol)) |
| layout.visitProtocolDecl(protocol); |
| |
| // Create a ProtocolInfo object from the layout. |
| ProtocolInfo *info = ProtocolInfo::create(layout.getEntries()); |
| info->NextConverted = FirstProtocol; |
| FirstProtocol = info; |
| |
| // Memoize. |
| Protocols.insert(std::make_pair(protocol, info)); |
| |
| // Done. |
| return *info; |
| } |
| |
| /// Allocate a new ProtocolInfo. |
| ProtocolInfo *ProtocolInfo::create(ArrayRef<WitnessTableEntry> table) { |
| size_t bufferSize = totalSizeToAlloc<WitnessTableEntry>(table.size()); |
| void *buffer = ::operator new(bufferSize); |
| return new(buffer) ProtocolInfo(table); |
| } |
| |
| ProtocolInfo::~ProtocolInfo() { |
| for (auto &conf : Conformances) { |
| delete conf.second; |
| } |
| } |
| |
| /// Find the conformance information for a protocol. |
| const ConformanceInfo & |
| ProtocolInfo::getConformance(IRGenModule &IGM, ProtocolDecl *protocol, |
| const ProtocolConformance *conformance) const { |
| assert(conformance->getProtocol() == protocol && |
| "conformance is for wrong protocol"); |
| |
| // Drill down to the root normal conformance. |
| auto normalConformance = conformance->getRootNormalConformance(); |
| |
| // Check whether we've already cached this. |
| auto it = Conformances.find(normalConformance); |
| if (it != Conformances.end()) return *it->second; |
| |
| ConformanceInfo *info; |
| |
| // If the conformance is dependent in any way, we need to unique it. |
| // TODO: maybe this should apply whenever it's out of the module? |
| // TODO: actually enable this |
| if (isDependentConformance(IGM, normalConformance, |
| ResilienceExpansion::Maximal)) { |
| info = new AccessorConformanceInfo(normalConformance); |
| |
| // Otherwise, we can use a direct-referencing conformance. |
| } else { |
| info = new DirectConformanceInfo(normalConformance); |
| } |
| |
| Conformances.insert({normalConformance, info}); |
| return *info; |
| } |
| |
| void IRGenModule::emitSILWitnessTable(SILWitnessTable *wt) { |
| // Don't emit a witness table if it is a declaration. |
| if (wt->isDeclaration()) |
| return; |
| |
| // Don't emit a witness table that is available externally. |
| // It can end up in having duplicate symbols for generated associated type |
| // metadata access functions. |
| // Also, it is not a big benefit for LLVM to emit such witness tables. |
| if (isAvailableExternally(wt->getLinkage())) |
| return; |
| |
| // Build the witnesses. |
| ConstantInitBuilder builder(*this); |
| auto witnesses = builder.beginArray(Int8PtrTy); |
| WitnessTableBuilder wtableBuilder(*this, witnesses, wt); |
| wtableBuilder.build(); |
| |
| assert(getProtocolInfo(wt->getConformance()->getProtocol()) |
| .getNumWitnesses() == witnesses.size() |
| && "witness table size doesn't match ProtocolInfo"); |
| |
| // Produce the initializer value. |
| auto initializer = witnesses.finishAndCreateFuture(); |
| |
| auto global = cast<llvm::GlobalVariable>( |
| getAddrOfWitnessTable(wt->getConformance(), initializer)); |
| global->setConstant(true); |
| global->setAlignment(getWitnessTableAlignment().getValue()); |
| |
| // FIXME: resilience; this should use the conformance's publishing scope. |
| wtableBuilder.buildAccessFunction(global); |
| |
| // Behavior conformances can't be reflected. |
| if (wt->getConformance()->isBehaviorConformance()) |
| return; |
| |
| NormalProtocolConformance *Conf = wt->getConformance(); |
| addProtocolConformanceRecord(Conf); |
| |
| CanType conformingType = Conf->getType()->getCanonicalType(); |
| if (!doesConformanceReferenceNominalTypeDescriptor(*this, conformingType)) { |
| // Trigger the lazy emission of the foreign type metadata. |
| NominalTypeDecl *Nominal = conformingType->getAnyNominal(); |
| if (auto *clas = dyn_cast<ClassDecl>(Nominal)) { |
| if (clas->isForeign()) |
| getAddrOfForeignTypeMetadataCandidate(conformingType); |
| } else if (isa<ClangModuleUnit>(Nominal->getModuleScopeContext())) { |
| getAddrOfForeignTypeMetadataCandidate(conformingType); |
| } |
| } |
| } |
| |
| |
| /// True if a function's signature in LLVM carries polymorphic parameters. |
| /// Generic functions and protocol witnesses carry polymorphic parameters. |
| bool irgen::hasPolymorphicParameters(CanSILFunctionType ty) { |
| switch (ty->getRepresentation()) { |
| case SILFunctionTypeRepresentation::Block: |
| // Should never be polymorphic. |
| assert(!ty->isPolymorphic() && "polymorphic C function?!"); |
| return false; |
| |
| case SILFunctionTypeRepresentation::Thick: |
| case SILFunctionTypeRepresentation::Thin: |
| case SILFunctionTypeRepresentation::Method: |
| case SILFunctionTypeRepresentation::Closure: |
| return ty->isPolymorphic(); |
| |
| case SILFunctionTypeRepresentation::CFunctionPointer: |
| case SILFunctionTypeRepresentation::ObjCMethod: |
| // May be polymorphic at the SIL level, but no type metadata is actually |
| // passed. |
| return false; |
| |
| case SILFunctionTypeRepresentation::WitnessMethod: |
| // Always carries polymorphic parameters for the Self type. |
| return true; |
| } |
| |
| llvm_unreachable("Not a valid SILFunctionTypeRepresentation."); |
| } |
| |
| /// Emit a polymorphic parameters clause, binding all the metadata necessary. |
| void EmitPolymorphicParameters::emit(Explosion &in, |
| WitnessMetadata *witnessMetadata, |
| const GetParameterFn &getParameter) { |
| // Collect any early sources and bind local type data from them. |
| for (auto &source : getSources()) { |
| bindExtraSource(source, in, witnessMetadata); |
| } |
| |
| auto getInContext = [&](CanType type) -> CanType { |
| return getTypeInContext(type); |
| }; |
| |
| // Collect any concrete type metadata that's been passed separately. |
| enumerateUnfulfilledRequirements([&](GenericRequirement requirement) { |
| auto value = in.claimNext(); |
| bindGenericRequirement(IGF, requirement, value, getInContext); |
| }); |
| |
| // Bind all the fulfillments we can from the formal parameters. |
| bindParameterSources(getParameter); |
| } |
| |
| llvm::Value * |
| MetadataPath::followFromTypeMetadata(IRGenFunction &IGF, |
| CanType sourceType, |
| llvm::Value *source, |
| Map<llvm::Value*> *cache) const { |
| LocalTypeDataKey key = { |
| sourceType, |
| LocalTypeDataKind::forTypeMetadata() |
| }; |
| return follow(IGF, key, source, Path.begin(), Path.end(), cache); |
| } |
| |
| llvm::Value * |
| MetadataPath::followFromWitnessTable(IRGenFunction &IGF, |
| CanType conformingType, |
| ProtocolConformanceRef conformance, |
| llvm::Value *source, |
| Map<llvm::Value*> *cache) const { |
| LocalTypeDataKey key = { |
| conformingType, |
| LocalTypeDataKind::forProtocolWitnessTable(conformance) |
| }; |
| return follow(IGF, key, source, Path.begin(), Path.end(), cache); |
| } |
| |
| /// Follow this metadata path. |
| /// |
| /// \param sourceKey - A description of the source value. Not necessarily |
| /// an appropriate caching key. |
| /// \param cache - If given, this cache will be used to short-circuit |
| /// the lookup; otherwise, the global (but dominance-sensitive) cache |
| /// in the IRGenFunction will be used. This caching system is somewhat |
| /// more efficient than what IGF provides, but it's less general, and it |
| /// should probably be removed. |
| llvm::Value *MetadataPath::follow(IRGenFunction &IGF, |
| LocalTypeDataKey sourceKey, |
| llvm::Value *source, |
| iterator begin, iterator end, |
| Map<llvm::Value*> *cache) { |
| assert(source && "no source metadata value!"); |
| |
| // The invariant is that this iterator starts a path from source and |
| // that sourceKey is correctly describes it. |
| iterator i = begin; |
| |
| // Before we begin emitting code to generate the actual path, try to find |
| // the latest point in the path that we've cached a value for. |
| |
| // If the caller gave us a cache to use, check that. This lookup is very |
| // efficient and doesn't even require us to parse the prefix. |
| if (cache) { |
| auto result = cache->findPrefix(begin, end); |
| if (result.first) { |
| source = *result.first; |
| |
| // If that was the end, there's no more work to do; don't bother |
| // adjusting the source key. |
| if (result.second == end) |
| return source; |
| |
| // Advance the source key past the cached prefix. |
| while (i != result.second) { |
| Component component = *i++; |
| (void) followComponent(IGF, sourceKey, /*source*/ nullptr, component); |
| } |
| } |
| |
| // Otherwise, make a pass over the path looking for available concrete |
| // entries in the IGF's local type data cache. |
| } else { |
| auto skipI = i; |
| LocalTypeDataKey skipKey = sourceKey; |
| while (skipI != end) { |
| Component component = *skipI++; |
| (void) followComponent(IGF, skipKey, /*source*/ nullptr, component); |
| |
| // Check the cache for a concrete value. We don't want an abstract |
| // entry because, if one exists, we'll just end up here again |
| // recursively. |
| if (auto skipSource = |
| IGF.tryGetConcreteLocalTypeData(skipKey.getCachingKey())) { |
| // If we found one, advance the info for the source to the current |
| // point in the path, then continue the search. |
| sourceKey = skipKey; |
| source = skipSource; |
| i = skipI; |
| } |
| } |
| } |
| |
| // Drill in on the actual source value. |
| while (i != end) { |
| auto component = *i++; |
| source = followComponent(IGF, sourceKey, source, component); |
| |
| // If we have a cache, remember this in the cache at the next position. |
| if (cache) { |
| cache->insertNew(begin, i, source); |
| |
| // Otherwise, insert it into the global cache. |
| } else { |
| IGF.setScopedLocalTypeData(sourceKey, source); |
| } |
| } |
| |
| return source; |
| } |
| |
| /// Call an associated-type witness table access function. Does not do |
| /// any caching or drill down to implied protocols. |
| static llvm::Value * |
| emitAssociatedTypeWitnessTableRef(IRGenFunction &IGF, |
| llvm::Value *parentMetadata, |
| llvm::Value *wtable, |
| WitnessIndex index, |
| llvm::Value *associatedTypeMetadata) { |
| llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable, index); |
| |
| // Cast the witness to the appropriate function type. |
| auto witnessTy = IGF.IGM.getAssociatedTypeWitnessTableAccessFunctionTy(); |
| witness = IGF.Builder.CreateBitCast(witness, witnessTy->getPointerTo()); |
| |
| // Call the accessor. |
| auto call = IGF.Builder.CreateCall(witness, |
| { associatedTypeMetadata, parentMetadata, wtable }); |
| call->setDoesNotThrow(); |
| call->setCallingConv(IGF.IGM.DefaultCC); |
| |
| return call; |
| } |
| |
| /// Drill down on a single stage of component. |
| /// |
| /// sourceType and sourceDecl will be adjusted to refer to the new |
| /// component. Source can be null, in which case this will be the only |
| /// thing done. |
| llvm::Value *MetadataPath::followComponent(IRGenFunction &IGF, |
| LocalTypeDataKey &sourceKey, |
| llvm::Value *source, |
| Component component) { |
| switch (component.getKind()) { |
| case Component::Kind::NominalTypeArgument: |
| case Component::Kind::NominalTypeArgumentConformance: { |
| assert(sourceKey.Kind == LocalTypeDataKind::forTypeMetadata()); |
| auto generic = cast<BoundGenericType>(sourceKey.Type); |
| auto reqtIndex = component.getPrimaryIndex(); |
| |
| GenericTypeRequirements requirements(IGF.IGM, generic->getDecl()); |
| auto &requirement = requirements.getRequirements()[reqtIndex]; |
| |
| auto module = IGF.getSwiftModule(); |
| auto subs = generic->getContextSubstitutionMap(module, |
| generic->getDecl()); |
| auto sub = requirement.TypeParameter.subst(subs)->getCanonicalType(); |
| |
| // In either case, we need to change the type. |
| sourceKey.Type = sub; |
| |
| // If this is a type argument, we've fully updated sourceKey. |
| if (component.getKind() == Component::Kind::NominalTypeArgument) { |
| assert(!requirement.Protocol && "index mismatch!"); |
| if (source) { |
| source = emitArgumentMetadataRef(IGF, generic->getDecl(), |
| requirements, reqtIndex, source); |
| setTypeMetadataName(IGF.IGM, source, sourceKey.Type); |
| } |
| |
| // Otherwise, we need to switch sourceKey.Kind to the appropriate |
| // conformance kind. |
| } else { |
| assert(requirement.Protocol && "index mismatch!"); |
| auto conformance = *subs.lookupConformance(requirement.TypeParameter, |
| requirement.Protocol); |
| assert(conformance.getRequirement() == requirement.Protocol); |
| sourceKey.Kind = LocalTypeDataKind::forProtocolWitnessTable(conformance); |
| |
| if (source) { |
| auto protocol = conformance.getRequirement(); |
| source = emitArgumentWitnessTableRef(IGF, generic->getDecl(), |
| requirements, reqtIndex, source); |
| setProtocolWitnessTableName(IGF.IGM, source, sourceKey.Type, protocol); |
| } |
| } |
| |
| return source; |
| } |
| |
| case Component::Kind::NominalParent: { |
| assert(sourceKey.Kind == LocalTypeDataKind::forTypeMetadata()); |
| NominalTypeDecl *nominalDecl; |
| if (auto nominal = dyn_cast<NominalType>(sourceKey.Type)) { |
| nominalDecl = nominal->getDecl(); |
| sourceKey.Type = nominal.getParent(); |
| } else { |
| auto generic = cast<BoundGenericType>(sourceKey.Type); |
| nominalDecl = generic->getDecl(); |
| sourceKey.Type = generic.getParent(); |
| } |
| |
| if (source) { |
| source = emitParentMetadataRef(IGF, nominalDecl, source); |
| setTypeMetadataName(IGF.IGM, source, sourceKey.Type); |
| } |
| return source; |
| } |
| |
| case Component::Kind::OutOfLineBaseProtocol: { |
| auto conformance = sourceKey.Kind.getProtocolConformance(); |
| auto protocol = conformance.getRequirement(); |
| auto &pi = IGF.IGM.getProtocolInfo(protocol); |
| |
| auto &entry = pi.getWitnessEntries()[component.getPrimaryIndex()]; |
| assert(entry.isOutOfLineBase()); |
| auto inheritedProtocol = entry.getBase(); |
| |
| sourceKey.Kind = |
| LocalTypeDataKind::forAbstractProtocolWitnessTable(inheritedProtocol); |
| if (conformance.isConcrete()) { |
| auto inheritedConformance = |
| conformance.getConcrete()->getInheritedConformance(inheritedProtocol); |
| if (inheritedConformance) { |
| sourceKey.Kind = LocalTypeDataKind::forConcreteProtocolWitnessTable( |
| inheritedConformance); |
| } |
| } |
| |
| if (source) { |
| WitnessIndex index(component.getPrimaryIndex(), /*prefix*/ false); |
| source = emitInvariantLoadOfOpaqueWitness(IGF, source, index); |
| source = IGF.Builder.CreateBitCast(source, IGF.IGM.WitnessTablePtrTy); |
| setProtocolWitnessTableName(IGF.IGM, source, sourceKey.Type, |
| inheritedProtocol); |
| } |
| return source; |
| } |
| |
| case Component::Kind::AssociatedConformance: { |
| auto sourceType = sourceKey.Type; |
| auto sourceConformance = sourceKey.Kind.getProtocolConformance(); |
| auto sourceProtocol = sourceConformance.getRequirement(); |
| auto &pi = IGF.IGM.getProtocolInfo(sourceProtocol); |
| |
| auto &entry = pi.getWitnessEntries()[component.getPrimaryIndex()]; |
| assert(entry.isAssociatedConformance()); |
| auto association = entry.getAssociatedConformancePath(); |
| auto associatedRequirement = entry.getAssociatedConformanceRequirement(); |
| |
| CanType associatedType = |
| sourceConformance.getAssociatedType(sourceType, association) |
| ->getCanonicalType(); |
| sourceKey.Type = associatedType; |
| |
| auto associatedConformance = |
| sourceConformance.getAssociatedConformance(sourceType, association, |
| associatedRequirement); |
| |
| // FIXME: this should be taken care of automatically by |
| // getAssociatedConformance. |
| if (!associatedConformance.isConcrete() && |
| !isa<ArchetypeType>(associatedType)) { |
| if (auto concreteConf = |
| IGF.IGM.getSwiftModule()->lookupConformance(associatedType, |
| associatedRequirement, nullptr)) { |
| associatedConformance = *concreteConf; |
| } |
| } |
| |
| sourceKey.Kind = |
| LocalTypeDataKind::forProtocolWitnessTable(associatedConformance); |
| |
| assert((associatedConformance.isConcrete() || |
| isa<ArchetypeType>(sourceKey.Type)) && |
| "couldn't find concrete conformance for concrete type"); |
| |
| if (source) { |
| WitnessIndex index(component.getPrimaryIndex(), /*prefix*/ false); |
| auto sourceMetadata = IGF.emitTypeMetadataRef(sourceType); |
| auto associatedMetadata = IGF.emitTypeMetadataRef(sourceKey.Type); |
| source = emitAssociatedTypeWitnessTableRef(IGF, sourceMetadata, source, |
| index, associatedMetadata); |
| |
| setProtocolWitnessTableName(IGF.IGM, source, sourceKey.Type, |
| associatedRequirement); |
| } |
| return source; |
| } |
| |
| case Component::Kind::Impossible: |
| llvm_unreachable("following an impossible path!"); |
| |
| } |
| llvm_unreachable("bad metadata path component"); |
| } |
| |
| void MetadataPath::dump() const { |
| auto &out = llvm::errs(); |
| print(out); |
| out << '\n'; |
| } |
| void MetadataPath::print(llvm::raw_ostream &out) const { |
| for (auto i = Path.begin(), e = Path.end(); i != e; ++i) { |
| if (i != Path.begin()) out << "."; |
| auto component = *i; |
| switch (component.getKind()) { |
| case Component::Kind::OutOfLineBaseProtocol: |
| out << "out_of_line_base_protocol[" << component.getPrimaryIndex() << "]"; |
| break; |
| case Component::Kind::AssociatedConformance: |
| out << "associated_conformance[" << component.getPrimaryIndex() << "]"; |
| break; |
| case Component::Kind::NominalTypeArgument: |
| out << "nominal_type_argument[" << component.getPrimaryIndex() << "]"; |
| break; |
| case Component::Kind::NominalTypeArgumentConformance: |
| out << "nominal_type_argument_conformance[" |
| << component.getPrimaryIndex() << "]"; |
| break; |
| case Component::Kind::NominalParent: |
| out << "nominal_parent"; |
| break; |
| case Component::Kind::Impossible: |
| out << "impossible"; |
| break; |
| } |
| } |
| } |
| |
| /// Collect any required metadata for a witness method from the end of |
| /// the given parameter list. |
| void irgen::collectTrailingWitnessMetadata(IRGenFunction &IGF, |
| SILFunction &fn, |
| Explosion ¶ms, |
| WitnessMetadata &witnessMetadata) { |
| assert(fn.getLoweredFunctionType()->getRepresentation() |
| == SILFunctionTypeRepresentation::WitnessMethod); |
| |
| llvm::Value *wtable = params.takeLast(); |
| assert(wtable->getType() == IGF.IGM.WitnessTablePtrTy && |
| "parameter signature mismatch: witness metadata didn't " |
| "end in witness table?"); |
| wtable->setName("SelfWitnessTable"); |
| witnessMetadata.SelfWitnessTable = wtable; |
| |
| llvm::Value *metatype = params.takeLast(); |
| assert(metatype->getType() == IGF.IGM.TypeMetadataPtrTy && |
| "parameter signature mismatch: witness metadata didn't " |
| "end in metatype?"); |
| metatype->setName("Self"); |
| witnessMetadata.SelfMetadata = metatype; |
| } |
| |
| /// Perform all the bindings necessary to emit the given declaration. |
| void irgen::emitPolymorphicParameters(IRGenFunction &IGF, |
| SILFunction &Fn, |
| Explosion &in, |
| WitnessMetadata *witnessMetadata, |
| const GetParameterFn &getParameter) { |
| EmitPolymorphicParameters(IGF, Fn).emit(in, witnessMetadata, getParameter); |
| } |
| |
| Size NecessaryBindings::getBufferSize(IRGenModule &IGM) const { |
| // We need one pointer for each archetype or witness table. |
| return IGM.getPointerSize() * Requirements.size(); |
| } |
| |
| void NecessaryBindings::restore(IRGenFunction &IGF, Address buffer) const { |
| bindFromGenericRequirementsBuffer(IGF, Requirements.getArrayRef(), buffer, |
| [&](CanType type) { return type;}); |
| } |
| |
| void NecessaryBindings::save(IRGenFunction &IGF, Address buffer) const { |
| emitInitOfGenericRequirementsBuffer(IGF, Requirements.getArrayRef(), buffer, |
| [&](GenericRequirement requirement) -> llvm::Value* { |
| CanType type = requirement.TypeParameter; |
| if (auto protocol = requirement.Protocol) { |
| auto wtable = |
| emitArchetypeWitnessTableRef(IGF, cast<ArchetypeType>(type), protocol); |
| return wtable; |
| } else { |
| auto metadata = IGF.emitTypeMetadataRef(type); |
| return metadata; |
| } |
| }); |
| } |
| |
| void NecessaryBindings::addTypeMetadata(CanType type) { |
| // Bindings are only necessary at all if the type is dependent. |
| if (!type->hasArchetype()) return; |
| |
| // Break down structural types so that we don't eagerly pass metadata |
| // for the structural type. Future considerations for this: |
| // - If we have the structural type lying around in some cheap fashion, |
| // maybe we *should* just pass it. |
| // - Passing a structural type should remove the need to pass its |
| // components separately. |
| if (auto tuple = dyn_cast<TupleType>(type)) { |
| for (auto elt : tuple.getElementTypes()) |
| addTypeMetadata(elt); |
| return; |
| } |
| if (auto fn = dyn_cast<FunctionType>(type)) { |
| addTypeMetadata(fn.getInput()); |
| addTypeMetadata(fn.getResult()); |
| return; |
| } |
| if (auto inout = dyn_cast<InOutType>(type)) { |
| addTypeMetadata(inout.getObjectType()); |
| return; |
| } |
| if (auto metatype = dyn_cast<MetatypeType>(type)) { |
| addTypeMetadata(metatype.getInstanceType()); |
| return; |
| } |
| // Generic types are trickier, because they can require conformances. |
| |
| // Otherwise, just record the need for this metadata. |
| Requirements.insert({type, nullptr}); |
| } |
| |
| void NecessaryBindings::addProtocolConformance(CanType type, |
| ProtocolConformanceRef conf) { |
| if (!conf.isAbstract()) return; |
| assert(isa<ArchetypeType>(type)); |
| |
| // TODO: pass something about the root conformance necessary to |
| // reconstruct this. |
| Requirements.insert({type, conf.getAbstract()}); |
| } |
| |
| llvm::Value *irgen::emitImpliedWitnessTableRef(IRGenFunction &IGF, |
| ArrayRef<ProtocolEntry> entries, |
| ProtocolDecl *target, |
| const GetWitnessTableFn &getWitnessTable) { |
| ProtocolPath path(IGF.IGM, entries, target); |
| auto wtable = getWitnessTable(path.getOriginIndex()); |
| wtable = path.apply(IGF, wtable); |
| return wtable; |
| } |
| |
| llvm::Value *irgen::emitWitnessTableRef(IRGenFunction &IGF, |
| CanType srcType, |
| ProtocolConformanceRef conformance) { |
| llvm::Value *srcMetadataCache = nullptr; |
| return emitWitnessTableRef(IGF, srcType, &srcMetadataCache, conformance); |
| } |
| |
| /// Emit a protocol witness table for a conformance. |
| llvm::Value *irgen::emitWitnessTableRef(IRGenFunction &IGF, |
| CanType srcType, |
| llvm::Value **srcMetadataCache, |
| ProtocolConformanceRef conformance) { |
| auto proto = conformance.getRequirement(); |
| assert(Lowering::TypeConverter::protocolRequiresWitnessTable(proto) |
| && "protocol does not have witness tables?!"); |
| |
| // If we don't have concrete conformance information, the type must be |
| // an archetype and the conformance must be via one of the protocol |
| // requirements of the archetype. Look at what's locally bound. |
| if (conformance.isAbstract()) { |
| auto archetype = cast<ArchetypeType>(srcType); |
| return emitArchetypeWitnessTableRef(IGF, archetype, proto); |
| } |
| |
| // All other source types should be concrete enough that we have |
| // conformance info for them. However, that conformance info might be |
| // more concrete than we're expecting. |
| // TODO: make a best effort to devirtualize, maybe? |
| auto concreteConformance = conformance.getConcrete(); |
| if (concreteConformance->getProtocol() != proto) { |
| concreteConformance = concreteConformance->getInheritedConformance(proto); |
| } |
| |
| // Check immediately for an existing cache entry. |
| auto wtable = IGF.tryGetLocalTypeData( |
| srcType, |
| LocalTypeDataKind::forConcreteProtocolWitnessTable(concreteConformance)); |
| if (wtable) return wtable; |
| |
| auto &protoI = IGF.IGM.getProtocolInfo(proto); |
| auto &conformanceI = |
| protoI.getConformance(IGF.IGM, proto, concreteConformance); |
| wtable = conformanceI.getTable(IGF, srcType, srcMetadataCache); |
| |
| IGF.setScopedLocalTypeData( |
| srcType, |
| LocalTypeDataKind::forConcreteProtocolWitnessTable(concreteConformance), |
| wtable); |
| return wtable; |
| } |
| |
| /// Emit the witness table references required for the given type |
| /// substitution. |
| void irgen::emitWitnessTableRefs(IRGenFunction &IGF, |
| const Substitution &sub, |
| llvm::Value **metadataCache, |
| SmallVectorImpl<llvm::Value*> &out) { |
| auto conformances = sub.getConformances(); |
| |
| // We don't need to do anything if we have no protocols to conform to. |
| if (conformances.empty()) return; |
| |
| // Look at the replacement type. |
| CanType replType = sub.getReplacement()->getCanonicalType(); |
| |
| for (auto &conformance : conformances) { |
| auto *proto = conformance.getRequirement(); |
| if (!Lowering::TypeConverter::protocolRequiresWitnessTable(proto)) |
| continue; |
| |
| auto wtable = emitWitnessTableRef(IGF, replType, metadataCache, |
| conformance); |
| |
| out.push_back(wtable); |
| } |
| } |
| |
| static CanType getSubstSelfType(CanSILFunctionType origFnType, |
| const SubstitutionMap &subs) { |
| // Grab the apparent 'self' type. If there isn't a 'self' type, |
| // we're not going to try to access this anyway. |
| assert(!origFnType->getParameters().empty()); |
| |
| auto selfParam = origFnType->getParameters().back(); |
| CanType inputType = selfParam.getType(); |
| // If the parameter is a direct metatype parameter, this is a static method |
| // of the instance type. We can assume this because: |
| // - metatypes cannot directly conform to protocols |
| // - even if they could, they would conform as a value type 'self' and thus |
| // be passed indirectly as an @in or @inout parameter. |
| if (auto meta = dyn_cast<MetatypeType>(inputType)) { |
| if (!selfParam.isFormalIndirect()) |
| inputType = meta.getInstanceType(); |
| } |
| |
| // Substitute the `self` type. |
| // FIXME: This has to be done as a formal AST type substitution rather than |
| // a SIL function type substitution, because some nominal types (viz |
| // Optional) have type lowering recursively applied to their type parameters. |
| // Substituting into the original lowered function type like this is still |
| // problematic if we ever allow methods or protocol conformances on structural |
| // types; we'd really need to separately record the formal Self type in the |
| // SIL function type to make that work, which could be managed by having a |
| // "substituted generic signature" concept. |
| if (!subs.empty()) { |
| inputType = inputType.subst(subs)->getCanonicalType(); |
| } |
| |
| return inputType; |
| } |
| |
| namespace { |
| class EmitPolymorphicArguments : public PolymorphicConvention { |
| IRGenFunction &IGF; |
| public: |
| EmitPolymorphicArguments(IRGenFunction &IGF, |
| CanSILFunctionType polyFn) |
| : PolymorphicConvention(IGF.IGM, polyFn), IGF(IGF) {} |
| |
| void emit(CanSILFunctionType substFnType, const SubstitutionMap &subs, |
| WitnessMetadata *witnessMetadata, Explosion &out); |
| |
| private: |
| void emitEarlySources(const SubstitutionMap &subs, Explosion &out) { |
| for (auto &source : getSources()) { |
| switch (source.getKind()) { |
| // Already accounted for in the parameters. |
| case MetadataSource::Kind::ClassPointer: |
| case MetadataSource::Kind::Metadata: |
| continue; |
| |
| // Needs a special argument. |
| case MetadataSource::Kind::GenericLValueMetadata: { |
| out.add(IGF.emitTypeMetadataRef(getSubstSelfType(FnType, subs))); |
| continue; |
| } |
| |
| // Witness 'Self' arguments are added as a special case in |
| // EmitPolymorphicArguments::emit. |
| case MetadataSource::Kind::SelfMetadata: |
| case MetadataSource::Kind::SelfWitnessTable: |
| continue; |
| } |
| llvm_unreachable("bad source kind!"); |
| } |
| } |
| }; |
| } // end anonymous namespace |
| |
| /// Pass all the arguments necessary for the given function. |
| void irgen::emitPolymorphicArguments(IRGenFunction &IGF, |
| CanSILFunctionType origFnType, |
| CanSILFunctionType substFnType, |
| const SubstitutionMap &subs, |
| WitnessMetadata *witnessMetadata, |
| Explosion &out) { |
| EmitPolymorphicArguments(IGF, origFnType).emit(substFnType, subs, |
| witnessMetadata, out); |
| } |
| |
| void EmitPolymorphicArguments::emit(CanSILFunctionType substFnType, |
| const SubstitutionMap &subs, |
| WitnessMetadata *witnessMetadata, |
| Explosion &out) { |
| // Add all the early sources. |
| emitEarlySources(subs, out); |
| |
| // For now, treat all archetypes independently. |
| enumerateUnfulfilledRequirements([&](GenericRequirement requirement) { |
| llvm::Value *requiredValue = |
| emitGenericRequirementFromSubstitutions(IGF, Generics, M, |
| requirement, subs); |
| out.add(requiredValue); |
| }); |
| |
| // For a witness call, add the Self argument metadata arguments last. |
| for (auto &source : getSources()) { |
| switch (source.getKind()) { |
| case MetadataSource::Kind::Metadata: |
| case MetadataSource::Kind::ClassPointer: |
| // Already accounted for in the arguments. |
| continue; |
| |
| case MetadataSource::Kind::GenericLValueMetadata: |
| // Added in the early phase. |
| continue; |
| |
| case MetadataSource::Kind::SelfMetadata: { |
| assert(witnessMetadata && "no metadata structure for witness method"); |
| auto self = IGF.emitTypeMetadataRef(getSubstSelfType(FnType, subs)); |
| witnessMetadata->SelfMetadata = self; |
| continue; |
| } |
| |
| case MetadataSource::Kind::SelfWitnessTable: { |
| // Added later. |
| continue; |
| } |
| } |
| llvm_unreachable("bad source kind"); |
| } |
| } |
| |
| NecessaryBindings |
| NecessaryBindings::forFunctionInvocations(IRGenModule &IGM, |
| CanSILFunctionType origType, |
| const SubstitutionMap &subs) { |
| NecessaryBindings bindings; |
| |
| // Bail out early if we don't have polymorphic parameters. |
| if (!hasPolymorphicParameters(origType)) |
| return bindings; |
| |
| // Figure out what we're actually required to pass: |
| PolymorphicConvention convention(IGM, origType); |
| |
| // - unfulfilled requirements |
| convention.enumerateUnfulfilledRequirements( |
| [&](GenericRequirement requirement) { |
| CanType type = requirement.TypeParameter.subst(subs)->getCanonicalType(); |
| |
| if (requirement.Protocol) { |
| auto conf = *subs.lookupConformance(requirement.TypeParameter, |
| requirement.Protocol); |
| bindings.addProtocolConformance(type, conf); |
| } else { |
| bindings.addTypeMetadata(type); |
| } |
| }); |
| |
| // - extra sources |
| for (auto &source : convention.getSources()) { |
| switch (source.getKind()) { |
| case MetadataSource::Kind::Metadata: |
| case MetadataSource::Kind::ClassPointer: |
| continue; |
| |
| case MetadataSource::Kind::GenericLValueMetadata: |
| bindings.addTypeMetadata(getSubstSelfType(origType, subs)); |
| continue; |
| |
| case MetadataSource::Kind::SelfMetadata: |
| bindings.addTypeMetadata(getSubstSelfType(origType, subs)); |
| continue; |
| |
| case MetadataSource::Kind::SelfWitnessTable: |
| // We'll just pass undef in cases like this. |
| continue; |
| } |
| llvm_unreachable("bad source kind"); |
| } |
| |
| return bindings; |
| } |
| |
| /// The information we need to record in generic type metadata |
| /// is the information in the type's generic signature, minus the |
| /// information recoverable from the type's parent type. This is |
| /// simply the information that would be passed to a generic function |
| /// that takes the (thick) parent metatype as an argument. |
| GenericTypeRequirements::GenericTypeRequirements(IRGenModule &IGM, |
| NominalTypeDecl *typeDecl) |
| : TheDecl(typeDecl) { |
| |
| // We only need to do something here if the declaration context is |
| // somehow generic. |
| auto ncGenerics = typeDecl->getGenericSignatureOfContext(); |
| if (!ncGenerics) return; |
| |
| // Construct a representative function type. |
| auto generics = ncGenerics->getCanonicalSignature(); |
| CanSILFunctionType fnType = [&]() -> CanSILFunctionType { |
| CanType type = typeDecl->getDeclaredInterfaceType()->getCanonicalType(); |
| if (auto nominal = dyn_cast<NominalType>(type)) { |
| ParentType = nominal.getParent(); |
| } else { |
| ParentType = cast<BoundGenericType>(type).getParent(); |
| } |
| |
| // Ignore the existence of the parent type if it has no type parameters. |
| if (ParentType && !ParentType->hasTypeParameter()) |
| ParentType = CanType(); |
| |
| SmallVector<SILParameterInfo, 1> params; |
| if (ParentType) { |
| auto parentMetatype = |
| CanMetatypeType::get(ParentType, MetatypeRepresentation::Thick); |
| params.push_back(SILParameterInfo(parentMetatype, |
| ParameterConvention::Direct_Unowned)); |
| } |
| |
| return SILFunctionType::get(generics, SILFunctionType::ExtInfo(), |
| /*callee*/ ParameterConvention::Direct_Unowned, |
| params, /*results*/ {}, /*error*/ None, |
| IGM.Context); |
| }(); |
| |
| // Figure out what we're actually still required to pass |
| PolymorphicConvention convention(IGM, fnType); |
| convention.enumerateUnfulfilledRequirements([&](GenericRequirement reqt) { |
| assert(generics->isCanonicalTypeInContext(reqt.TypeParameter, |
| *IGM.getSwiftModule())); |
| Requirements.push_back(reqt); |
| }); |
| |
| // We do not need to consider extra sources. |
| } |
| |
| void |
| GenericTypeRequirements::enumerateFulfillments(IRGenModule &IGM, |
| const SubstitutionMap &subs, |
| FulfillmentCallback callback) { |
| if (empty()) return; |
| |
| for (auto reqtIndex : indices(getRequirements())) { |
| auto &reqt = getRequirements()[reqtIndex]; |
| CanType type = reqt.TypeParameter.subst(subs)->getCanonicalType(); |
| if (reqt.Protocol) { |
| auto conformance = *subs.lookupConformance(reqt.TypeParameter, |
| reqt.Protocol); |
| callback(reqtIndex, type, conformance); |
| } else { |
| callback(reqtIndex, type, None); |
| } |
| } |
| } |
| |
| void GenericTypeRequirements::emitInitOfBuffer(IRGenFunction &IGF, |
| const SubstitutionMap &subs, |
| Address buffer) { |
| if (Requirements.empty()) return; |
| |
| auto generics = |
| TheDecl->getGenericSignatureOfContext()->getCanonicalSignature(); |
| auto &module = *TheDecl->getParentModule(); |
| emitInitOfGenericRequirementsBuffer(IGF, Requirements, buffer, |
| [&](GenericRequirement requirement) { |
| return emitGenericRequirementFromSubstitutions(IGF, generics, module, |
| requirement, subs); |
| }); |
| } |
| |
| void irgen::emitInitOfGenericRequirementsBuffer(IRGenFunction &IGF, |
| ArrayRef<GenericRequirement> requirements, |
| Address buffer, |
| EmitGenericRequirementFn emitRequirement) { |
| if (requirements.empty()) return; |
| |
| // Cast the buffer to %type**. |
| buffer = IGF.Builder.CreateElementBitCast(buffer, IGF.IGM.TypeMetadataPtrTy); |
| |
| for (auto index : indices(requirements)) { |
| // GEP to the appropriate slot. |
| Address slot = buffer; |
| if (index != 0) { |
| slot = IGF.Builder.CreateConstArrayGEP(slot, index, |
| IGF.IGM.getPointerSize()); |
| } |
| |
| llvm::Value *value = emitRequirement(requirements[index]); |
| if (requirements[index].Protocol) { |
| slot = IGF.Builder.CreateElementBitCast(slot, IGF.IGM.WitnessTablePtrTy); |
| } |
| IGF.Builder.CreateStore(value, slot); |
| } |
| } |
| |
| llvm::Value * |
| irgen::emitGenericRequirementFromSubstitutions(IRGenFunction &IGF, |
| CanGenericSignature generics, |
| ModuleDecl &module, |
| GenericRequirement requirement, |
| const SubstitutionMap &subs) { |
| CanType depTy = requirement.TypeParameter; |
| CanType argType = depTy.subst(subs)->getCanonicalType(); |
| |
| if (!requirement.Protocol) { |
| auto argMetadata = IGF.emitTypeMetadataRef(argType); |
| return argMetadata; |
| } |
| |
| auto proto = requirement.Protocol; |
| auto conformance = *subs.lookupConformance(depTy, proto); |
| assert(conformance.getRequirement() == proto); |
| llvm::Value *metadata = nullptr; |
| auto wtable = emitWitnessTableRef(IGF, argType, &metadata, conformance); |
| return wtable; |
| } |
| |
| void GenericTypeRequirements::bindFromBuffer(IRGenFunction &IGF, |
| Address buffer, |
| GetTypeParameterInContextFn getInContext) { |
| bindFromGenericRequirementsBuffer(IGF, Requirements, buffer, getInContext); |
| } |
| |
| void irgen::bindFromGenericRequirementsBuffer(IRGenFunction &IGF, |
| ArrayRef<GenericRequirement> requirements, |
| Address buffer, |
| GetTypeParameterInContextFn getInContext) { |
| if (requirements.empty()) return; |
| |
| // Cast the buffer to %type**. |
| buffer = IGF.Builder.CreateElementBitCast(buffer, IGF.IGM.TypeMetadataPtrTy); |
| |
| for (auto index : indices(requirements)) { |
| // GEP to the appropriate slot. |
| Address slot = buffer; |
| if (index != 0) { |
| slot = IGF.Builder.CreateConstArrayGEP(slot, index, |
| IGF.IGM.getPointerSize()); |
| } |
| |
| // Cast if necessary. |
| if (requirements[index].Protocol) { |
| slot = IGF.Builder.CreateElementBitCast(slot, IGF.IGM.WitnessTablePtrTy); |
| } |
| |
| llvm::Value *value = IGF.Builder.CreateLoad(slot); |
| bindGenericRequirement(IGF, requirements[index], value, getInContext); |
| } |
| } |
| |
| void irgen::bindGenericRequirement(IRGenFunction &IGF, |
| GenericRequirement requirement, |
| llvm::Value *value, |
| GetTypeParameterInContextFn getInContext) { |
| // Get the corresponding context type. |
| auto type = getInContext(requirement.TypeParameter); |
| |
| if (auto proto = requirement.Protocol) { |
| assert(isa<ArchetypeType>(type)); |
| assert(value->getType() == IGF.IGM.WitnessTablePtrTy); |
| setProtocolWitnessTableName(IGF.IGM, value, type, proto); |
| auto kind = LocalTypeDataKind::forAbstractProtocolWitnessTable(proto); |
| IGF.setUnscopedLocalTypeData(type, kind, value); |
| } else { |
| assert(value->getType() == IGF.IGM.TypeMetadataPtrTy); |
| setTypeMetadataName(IGF.IGM, value, type); |
| IGF.bindLocalTypeDataFromTypeMetadata(type, IsExact, value); |
| } |
| } |
| |
| namespace { |
| /// A class for expanding a polymorphic signature. |
| class ExpandPolymorphicSignature : public PolymorphicConvention { |
| public: |
| ExpandPolymorphicSignature(IRGenModule &IGM, CanSILFunctionType fn) |
| : PolymorphicConvention(IGM, fn) {} |
| |
| void expand(SmallVectorImpl<llvm::Type*> &out) { |
| for (auto &source : getSources()) |
| addEarlySource(source, out); |
| |
| enumerateUnfulfilledRequirements([&](GenericRequirement reqt) { |
| out.push_back(reqt.Protocol ? IGM.WitnessTablePtrTy |
| : IGM.TypeMetadataPtrTy); |
| }); |
| } |
| |
| private: |
| /// Add signature elements for the source metadata. |
| void addEarlySource(const MetadataSource &source, |
| SmallVectorImpl<llvm::Type*> &out) { |
| switch (source.getKind()) { |
| case MetadataSource::Kind::ClassPointer: return; // already accounted for |
| case MetadataSource::Kind::Metadata: return; // already accounted for |
| case MetadataSource::Kind::GenericLValueMetadata: |
| return out.push_back(IGM.TypeMetadataPtrTy); |
| case MetadataSource::Kind::SelfMetadata: |
| case MetadataSource::Kind::SelfWitnessTable: |
| return; // handled as a special case in expand() |
| } |
| llvm_unreachable("bad source kind"); |
| } |
| }; |
| } // end anonymous namespace |
| |
| /// Given a generic signature, add the argument types required in order to call it. |
| void irgen::expandPolymorphicSignature(IRGenModule &IGM, |
| CanSILFunctionType polyFn, |
| SmallVectorImpl<llvm::Type*> &out) { |
| ExpandPolymorphicSignature(IGM, polyFn).expand(out); |
| } |
| |
| void irgen::expandTrailingWitnessSignature(IRGenModule &IGM, |
| CanSILFunctionType polyFn, |
| SmallVectorImpl<llvm::Type*> &out) { |
| assert(polyFn->getRepresentation() |
| == SILFunctionTypeRepresentation::WitnessMethod); |
| |
| assert(getTrailingWitnessSignatureLength(IGM, polyFn) == 2); |
| |
| // A witness method always provides Self. |
| out.push_back(IGM.TypeMetadataPtrTy); |
| |
| // A witness method always provides the witness table for Self. |
| out.push_back(IGM.WitnessTablePtrTy); |
| } |
| |
| void |
| irgen::emitWitnessMethodValue(IRGenFunction &IGF, |
| CanType baseTy, |
| llvm::Value **baseMetadataCache, |
| SILDeclRef member, |
| ProtocolConformanceRef conformance, |
| Explosion &out) { |
| auto fn = cast<AbstractFunctionDecl>(member.getDecl()); |
| auto fnProto = cast<ProtocolDecl>(fn->getDeclContext()); |
| |
| conformance = conformance.getInherited(fnProto); |
| |
| // Find the witness table. |
| // FIXME conformance for concrete type |
| llvm::Value *wtable = emitWitnessTableRef(IGF, baseTy, baseMetadataCache, |
| conformance); |
| |
| // Find the witness we're interested in. |
| auto &fnProtoInfo = IGF.IGM.getProtocolInfo(conformance.getRequirement()); |
| auto index = fnProtoInfo.getFunctionIndex(fn); |
| llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable, index); |
| |
| // Cast the witness pointer to i8*. |
| witness = IGF.Builder.CreateBitCast(witness, IGF.IGM.Int8PtrTy); |
| |
| // Build the value. |
| out.add(witness); |
| } |
| |
| llvm::FunctionType *IRGenModule::getAssociatedTypeMetadataAccessFunctionTy() { |
| if (AssociatedTypeMetadataAccessFunctionTy) |
| return AssociatedTypeMetadataAccessFunctionTy; |
| |
| auto accessorTy = llvm::FunctionType::get(TypeMetadataPtrTy, |
| { TypeMetadataPtrTy, |
| WitnessTablePtrTy }, |
| /*varargs*/ false); |
| AssociatedTypeMetadataAccessFunctionTy = accessorTy; |
| return accessorTy; |
| } |
| |
| llvm::Value *irgen::emitAssociatedTypeMetadataRef(IRGenFunction &IGF, |
| llvm::Value *parentMetadata, |
| llvm::Value *wtable, |
| AssociatedTypeDecl *associatedType) { |
| auto &pi = IGF.IGM.getProtocolInfo(associatedType->getProtocol()); |
| auto index = pi.getAssociatedTypeIndex(associatedType); |
| llvm::Value *witness = emitInvariantLoadOfOpaqueWitness(IGF, wtable, index); |
| |
| // Cast the witness to the appropriate function type. |
| auto witnessTy = IGF.IGM.getAssociatedTypeMetadataAccessFunctionTy(); |
| witness = IGF.Builder.CreateBitCast(witness, witnessTy->getPointerTo()); |
| |
| // Call the accessor. |
| assert((!IGF.IGM.DebugInfo || IGF.Builder.getCurrentDebugLocation()) && |
| "creating a function call without a debug location"); |
| auto call = IGF.Builder.CreateCall(witness, { parentMetadata, wtable }); |
| call->setDoesNotThrow(); |
| call->setCallingConv(IGF.IGM.DefaultCC); |
| |
| return call; |
| } |
| |
| llvm::FunctionType * |
| IRGenModule::getAssociatedTypeWitnessTableAccessFunctionTy() { |
| if (AssociatedTypeWitnessTableAccessFunctionTy) |
| return AssociatedTypeWitnessTableAccessFunctionTy; |
| |
| // The associated type metadata is passed first so that this function is |
| // CC-compatible with a conformance's witness table access function. |
| auto accessorTy = llvm::FunctionType::get(WitnessTablePtrTy, |
| { TypeMetadataPtrTy, |
| TypeMetadataPtrTy, |
| WitnessTablePtrTy }, |
| /*varargs*/ false); |
| AssociatedTypeWitnessTableAccessFunctionTy = accessorTy; |
| return accessorTy; |
| } |