mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This is yet another waypoint on the path towards the final generic-metadata design. The immediate goal is to make the pattern a private implementation detail and to give the runtime more visibility into the allocation and caching of generic types.
866 lines
29 KiB
C++
866 lines
29 KiB
C++
//===--- Linking.h - Named declarations and how to link to them -*- C++ -*-===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_IRGEN_LINKING_H
|
|
#define SWIFT_IRGEN_LINKING_H
|
|
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/ProtocolAssociations.h"
|
|
#include "swift/AST/ProtocolConformance.h"
|
|
#include "swift/AST/Types.h"
|
|
#include "swift/IRGen/ValueWitness.h"
|
|
#include "swift/SIL/SILFunction.h"
|
|
#include "swift/SIL/SILGlobalVariable.h"
|
|
#include "swift/SIL/SILModule.h"
|
|
#include "llvm/ADT/DenseMapInfo.h"
|
|
#include "llvm/IR/GlobalValue.h"
|
|
|
|
namespace llvm {
|
|
class Triple;
|
|
}
|
|
|
|
namespace swift {
|
|
namespace irgen {
|
|
class IRGenModule;
|
|
|
|
/// Determine if the triple uses the DLL storage.
|
|
bool useDllStorage(const llvm::Triple &triple);
|
|
|
|
class UniversalLinkageInfo {
|
|
public:
|
|
bool IsELFObject;
|
|
bool UseDLLStorage;
|
|
|
|
/// True iff are multiple llvm modules.
|
|
bool HasMultipleIGMs;
|
|
|
|
bool IsWholeModule;
|
|
|
|
UniversalLinkageInfo(IRGenModule &IGM);
|
|
|
|
UniversalLinkageInfo(const llvm::Triple &triple, bool hasMultipleIGMs,
|
|
bool isWholeModule);
|
|
|
|
/// In case of multiple llvm modules (in multi-threaded compilation) all
|
|
/// private decls must be visible from other files.
|
|
bool shouldAllPrivateDeclsBeVisibleFromOtherFiles() const {
|
|
return HasMultipleIGMs;
|
|
}
|
|
/// In case of multipe llvm modules, private lazy protocol
|
|
/// witness table accessors could be emitted by two different IGMs during
|
|
/// IRGen into different object files and the linker would complain about
|
|
/// duplicate symbols.
|
|
bool needLinkerToMergeDuplicateSymbols() const { return HasMultipleIGMs; }
|
|
};
|
|
|
|
/// Selector for type metadata symbol kinds.
|
|
enum class TypeMetadataAddress {
|
|
AddressPoint,
|
|
FullMetadata,
|
|
};
|
|
|
|
/// A link entity is some sort of named declaration, combined with all
|
|
/// the information necessary to distinguish specific implementations
|
|
/// of the declaration from each other.
|
|
///
|
|
/// For example, functions may be uncurried at different levels, each of
|
|
/// which potentially creates a different top-level function.
|
|
class LinkEntity {
|
|
/// ValueDecl*, SILFunction*, or TypeBase*, depending on Kind.
|
|
void *Pointer;
|
|
|
|
/// ProtocolConformance*, depending on Kind.
|
|
void *SecondaryPointer;
|
|
|
|
/// A hand-rolled bitfield with the following layout:
|
|
unsigned Data;
|
|
|
|
enum : unsigned {
|
|
KindShift = 0, KindMask = 0xFF,
|
|
|
|
// This field appears in the ValueWitness kind.
|
|
ValueWitnessShift = 8, ValueWitnessMask = 0xFF00,
|
|
|
|
// This field appears in the TypeMetadata kind.
|
|
MetadataAddressShift = 8, MetadataAddressMask = 0x0300,
|
|
|
|
// This field appears in associated type access functions.
|
|
AssociatedTypeIndexShift = 8, AssociatedTypeIndexMask = ~KindMask,
|
|
|
|
// This field appears in associated conformance access functions.
|
|
AssociatedConformanceIndexShift = 8,
|
|
AssociatedConformanceIndexMask = ~KindMask,
|
|
};
|
|
#define LINKENTITY_SET_FIELD(field, value) (value << field##Shift)
|
|
#define LINKENTITY_GET_FIELD(value, field) ((value & field##Mask) >> field##Shift)
|
|
|
|
enum class Kind {
|
|
/// A method dispatch thunk. The pointer is a FuncDecl* inside a protocol
|
|
/// or a class.
|
|
DispatchThunk,
|
|
|
|
/// A method dispatch thunk for an initializing constructor. The pointer
|
|
/// is a ConstructorDecl* inside a class.
|
|
DispatchThunkInitializer,
|
|
|
|
/// A method dispatch thunk for an allocating constructor. The pointer is a
|
|
/// ConstructorDecl* inside a protocol or a class.
|
|
DispatchThunkAllocator,
|
|
|
|
/// A field offset. The pointer is a VarDecl*.
|
|
FieldOffset,
|
|
|
|
/// An Objective-C class reference. The pointer is a ClassDecl*.
|
|
ObjCClass,
|
|
|
|
/// An Objective-C class reference reference. The pointer is a ClassDecl*.
|
|
ObjCClassRef,
|
|
|
|
/// An Objective-C metaclass reference. The pointer is a ClassDecl*.
|
|
ObjCMetaclass,
|
|
|
|
/// A swift metaclass-stub reference. The pointer is a ClassDecl*.
|
|
SwiftMetaclassStub,
|
|
|
|
/// A class metadata base offset global variable. This stores the offset
|
|
/// of the immediate members of a class (generic parameters, field offsets,
|
|
/// vtable offsets) in the class's metadata. The immediate members begin
|
|
/// immediately after the superclass members end.
|
|
///
|
|
/// The pointer is a ClassDecl*.
|
|
ClassMetadataBaseOffset,
|
|
|
|
/// The property descriptor for a public property or subscript.
|
|
/// The pointer is an AbstractStorageDecl*.
|
|
PropertyDescriptor,
|
|
|
|
/// The nominal type descriptor for a nominal type.
|
|
/// The pointer is a NominalTypeDecl*.
|
|
NominalTypeDescriptor,
|
|
|
|
/// The metadata pattern for a generic nominal type.
|
|
/// The pointer is a NominalTypeDecl*.
|
|
TypeMetadataPattern,
|
|
|
|
/// The instantiation cache for a generic nominal type.
|
|
/// The pointer is a NominalTypeDecl*.
|
|
TypeMetadataInstantiationCache,
|
|
|
|
/// The instantiation function for a generic nominal type.
|
|
/// The pointer is a NominalTypeDecl*.
|
|
TypeMetadataInstantiationFunction,
|
|
|
|
/// The module descriptor for a module.
|
|
/// The pointer is a ModuleDecl*.
|
|
ModuleDescriptor,
|
|
|
|
/// The protocol descriptor for a protocol type.
|
|
/// The pointer is a ProtocolDecl*.
|
|
ProtocolDescriptor,
|
|
|
|
/// A SIL function. The pointer is a SILFunction*.
|
|
SILFunction,
|
|
|
|
/// The descriptor for an extension.
|
|
/// The pointer is an ExtensionDecl*.
|
|
ExtensionDescriptor,
|
|
|
|
/// The descriptor for a runtime-anonymous context.
|
|
/// The pointer is the DeclContext* of a child of the context that should
|
|
/// be considered private.
|
|
AnonymousDescriptor,
|
|
|
|
/// A SIL global variable. The pointer is a SILGlobalVariable*.
|
|
SILGlobalVariable,
|
|
|
|
// These next few are protocol-conformance kinds.
|
|
|
|
/// A direct protocol witness table. The secondary pointer is a
|
|
/// ProtocolConformance*.
|
|
DirectProtocolWitnessTable,
|
|
|
|
/// A witness accessor function. The secondary pointer is a
|
|
/// ProtocolConformance*.
|
|
ProtocolWitnessTableAccessFunction,
|
|
|
|
/// A generic protocol witness table cache. The secondary pointer is a
|
|
/// ProtocolConformance*.
|
|
GenericProtocolWitnessTableCache,
|
|
|
|
/// The instantiation function for a generic protocol witness table.
|
|
/// The secondary pointer is a ProtocolConformance*.
|
|
GenericProtocolWitnessTableInstantiationFunction,
|
|
|
|
/// A function which returns the type metadata for the associated type
|
|
/// of a protocol. The secondary pointer is a ProtocolConformance*.
|
|
/// The index of the associated type declaration is stored in the data.
|
|
AssociatedTypeMetadataAccessFunction,
|
|
|
|
/// A function which returns the witness table for a protocol-constrained
|
|
/// associated type of a protocol. The secondary pointer is a
|
|
/// ProtocolConformance*. The index of the associated conformance
|
|
/// requirement is stored in the data.
|
|
AssociatedTypeWitnessTableAccessFunction,
|
|
|
|
/// A reflection metadata descriptor for the associated type witnesses of a
|
|
/// nominal type in a protocol conformance.
|
|
ReflectionAssociatedTypeDescriptor,
|
|
|
|
/// The protocol conformance descriptor for a conformance.
|
|
/// The pointer is a NormalProtocolConformance*.
|
|
ProtocolConformanceDescriptor,
|
|
|
|
// These are both type kinds and protocol-conformance kinds.
|
|
|
|
/// A lazy protocol witness accessor function. The pointer is a
|
|
/// canonical TypeBase*, and the secondary pointer is a
|
|
/// ProtocolConformance*.
|
|
ProtocolWitnessTableLazyAccessFunction,
|
|
|
|
/// A lazy protocol witness cache variable. The pointer is a
|
|
/// canonical TypeBase*, and the secondary pointer is a
|
|
/// ProtocolConformance*.
|
|
ProtocolWitnessTableLazyCacheVariable,
|
|
|
|
// Everything following this is a type kind.
|
|
|
|
/// A value witness for a type.
|
|
/// The pointer is a canonical TypeBase*.
|
|
ValueWitness,
|
|
|
|
/// The value witness table for a type.
|
|
/// The pointer is a canonical TypeBase*.
|
|
ValueWitnessTable,
|
|
|
|
/// The metadata or metadata template for a type.
|
|
/// The pointer is a canonical TypeBase*.
|
|
TypeMetadata,
|
|
|
|
/// An access function for type metadata.
|
|
/// The pointer is a canonical TypeBase*.
|
|
TypeMetadataAccessFunction,
|
|
|
|
/// A lazy cache variable for type metadata.
|
|
/// The pointer is a canonical TypeBase*.
|
|
TypeMetadataLazyCacheVariable,
|
|
|
|
/// A foreign type metadata candidate.
|
|
/// The pointer is a canonical TypeBase*.
|
|
ForeignTypeMetadataCandidate,
|
|
|
|
/// A reflection metadata descriptor for a builtin or imported type.
|
|
ReflectionBuiltinDescriptor,
|
|
|
|
/// A reflection metadata descriptor for a struct, enum, class or protocol.
|
|
ReflectionFieldDescriptor,
|
|
|
|
/// A coroutine continuation prototype function.
|
|
CoroutineContinuationPrototype,
|
|
};
|
|
friend struct llvm::DenseMapInfo<LinkEntity>;
|
|
|
|
Kind getKind() const {
|
|
return Kind(LINKENTITY_GET_FIELD(Data, Kind));
|
|
}
|
|
|
|
static bool isDeclKind(Kind k) {
|
|
return k <= Kind::ProtocolDescriptor;
|
|
}
|
|
static bool isTypeKind(Kind k) {
|
|
return k >= Kind::ProtocolWitnessTableLazyAccessFunction;
|
|
}
|
|
|
|
static bool isProtocolConformanceKind(Kind k) {
|
|
return (k >= Kind::DirectProtocolWitnessTable &&
|
|
k <= Kind::ProtocolWitnessTableLazyCacheVariable);
|
|
}
|
|
|
|
void setForDecl(Kind kind, const ValueDecl *decl) {
|
|
assert(isDeclKind(kind));
|
|
Pointer = const_cast<void*>(static_cast<const void*>(decl));
|
|
SecondaryPointer = nullptr;
|
|
Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind));
|
|
}
|
|
|
|
void setForProtocolConformance(Kind kind, const ProtocolConformance *c) {
|
|
assert(isProtocolConformanceKind(kind) && !isTypeKind(kind));
|
|
Pointer = nullptr;
|
|
SecondaryPointer = const_cast<void*>(static_cast<const void*>(c));
|
|
Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind));
|
|
}
|
|
|
|
void setForProtocolConformanceAndType(Kind kind, const ProtocolConformance *c,
|
|
CanType type) {
|
|
assert(isProtocolConformanceKind(kind) && isTypeKind(kind));
|
|
Pointer = type.getPointer();
|
|
SecondaryPointer = const_cast<void*>(static_cast<const void*>(c));
|
|
Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind));
|
|
}
|
|
|
|
void setForProtocolConformanceAndAssociatedType(Kind kind,
|
|
const ProtocolConformance *c,
|
|
AssociatedTypeDecl *associate) {
|
|
assert(isProtocolConformanceKind(kind));
|
|
Pointer = nullptr;
|
|
SecondaryPointer = const_cast<void*>(static_cast<const void*>(c));
|
|
Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind)) |
|
|
LINKENTITY_SET_FIELD(AssociatedTypeIndex,
|
|
getAssociatedTypeIndex(c, associate));
|
|
}
|
|
|
|
void setForProtocolConformanceAndAssociatedConformance(Kind kind,
|
|
const ProtocolConformance *c,
|
|
CanType associatedType,
|
|
ProtocolDecl *associatedProtocol) {
|
|
assert(isProtocolConformanceKind(kind));
|
|
Pointer = associatedProtocol;
|
|
SecondaryPointer = const_cast<void*>(static_cast<const void*>(c));
|
|
Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind)) |
|
|
LINKENTITY_SET_FIELD(AssociatedConformanceIndex,
|
|
getAssociatedConformanceIndex(c, associatedType,
|
|
associatedProtocol));
|
|
}
|
|
|
|
// We store associated types using their index in their parent protocol
|
|
// in order to avoid bloating LinkEntity out to three key pointers.
|
|
static unsigned getAssociatedTypeIndex(const ProtocolConformance *conformance,
|
|
AssociatedTypeDecl *associate) {
|
|
assert(conformance->getProtocol() == associate->getProtocol());
|
|
unsigned result = 0;
|
|
for (auto requirement : associate->getProtocol()->getMembers()) {
|
|
if (requirement == associate) return result;
|
|
if (isa<AssociatedTypeDecl>(requirement)) result++;
|
|
}
|
|
llvm_unreachable("didn't find associated type in protocol?");
|
|
}
|
|
|
|
static AssociatedTypeDecl *
|
|
getAssociatedTypeByIndex(const ProtocolConformance *conformance,
|
|
unsigned index) {
|
|
for (auto requirement : conformance->getProtocol()->getMembers()) {
|
|
if (auto associate = dyn_cast<AssociatedTypeDecl>(requirement)) {
|
|
if (index == 0) return associate;
|
|
index--;
|
|
}
|
|
}
|
|
llvm_unreachable("didn't find associated type in protocol?");
|
|
}
|
|
|
|
// We store associated conformances using their index in the requirement
|
|
// list of the requirement signature of the conformance's protocol.
|
|
static unsigned getAssociatedConformanceIndex(
|
|
const ProtocolConformance *conformance,
|
|
CanType associatedType,
|
|
ProtocolDecl *requirement) {
|
|
unsigned index = 0;
|
|
for (const auto &reqt :
|
|
conformance->getProtocol()->getRequirementSignature()) {
|
|
if (reqt.getKind() == RequirementKind::Conformance &&
|
|
reqt.getFirstType()->getCanonicalType() == associatedType &&
|
|
reqt.getSecondType()->castTo<ProtocolType>()->getDecl() ==
|
|
requirement) {
|
|
return index;
|
|
}
|
|
++index;
|
|
}
|
|
llvm_unreachable("requirement not found in protocol");
|
|
}
|
|
|
|
static std::pair<CanType, ProtocolDecl*>
|
|
getAssociatedConformanceByIndex(const ProtocolConformance *conformance,
|
|
unsigned index) {
|
|
auto &reqt = conformance->getProtocol()->getRequirementSignature()[index];
|
|
assert(reqt.getKind() == RequirementKind::Conformance);
|
|
return { reqt.getFirstType()->getCanonicalType(),
|
|
reqt.getSecondType()->castTo<ProtocolType>()->getDecl() };
|
|
}
|
|
|
|
void setForType(Kind kind, CanType type) {
|
|
assert(isTypeKind(kind));
|
|
Pointer = type.getPointer();
|
|
SecondaryPointer = nullptr;
|
|
Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind));
|
|
}
|
|
|
|
LinkEntity() = default;
|
|
|
|
public:
|
|
static LinkEntity forDispatchThunk(SILDeclRef declRef) {
|
|
assert(!declRef.isForeign &&
|
|
!declRef.isDirectReference &&
|
|
!declRef.isCurried);
|
|
|
|
LinkEntity::Kind kind;
|
|
|
|
auto *decl = declRef.getDecl();
|
|
assert(isa<ClassDecl>(decl->getDeclContext()) ||
|
|
isa<ProtocolDecl>(decl->getDeclContext()));
|
|
|
|
switch (declRef.kind) {
|
|
case SILDeclRef::Kind::Func:
|
|
kind = Kind::DispatchThunk;
|
|
break;
|
|
case SILDeclRef::Kind::Initializer:
|
|
kind = Kind::DispatchThunkInitializer;
|
|
break;
|
|
case SILDeclRef::Kind::Allocator:
|
|
kind = Kind::DispatchThunkAllocator;
|
|
break;
|
|
default:
|
|
llvm_unreachable("Bad SILDeclRef for dispatch thunk");
|
|
}
|
|
|
|
LinkEntity entity;
|
|
entity.setForDecl(kind, decl);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forFieldOffset(VarDecl *decl) {
|
|
LinkEntity entity;
|
|
entity.setForDecl(Kind::FieldOffset, decl);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forObjCClassRef(ClassDecl *decl) {
|
|
LinkEntity entity;
|
|
entity.setForDecl(Kind::ObjCClassRef, decl);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forObjCClass(ClassDecl *decl) {
|
|
LinkEntity entity;
|
|
entity.setForDecl(Kind::ObjCClass, decl);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forObjCMetaclass(ClassDecl *decl) {
|
|
LinkEntity entity;
|
|
entity.setForDecl(Kind::ObjCMetaclass, decl);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forSwiftMetaclassStub(ClassDecl *decl) {
|
|
LinkEntity entity;
|
|
entity.setForDecl(Kind::SwiftMetaclassStub, decl);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forTypeMetadata(CanType concreteType,
|
|
TypeMetadataAddress addr) {
|
|
LinkEntity entity;
|
|
entity.Pointer = concreteType.getPointer();
|
|
entity.SecondaryPointer = nullptr;
|
|
entity.Data = LINKENTITY_SET_FIELD(Kind, unsigned(Kind::TypeMetadata))
|
|
| LINKENTITY_SET_FIELD(MetadataAddress, unsigned(addr));
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forTypeMetadataPattern(NominalTypeDecl *decl) {
|
|
LinkEntity entity;
|
|
entity.setForDecl(Kind::TypeMetadataPattern, decl);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forTypeMetadataAccessFunction(CanType type) {
|
|
LinkEntity entity;
|
|
entity.setForType(Kind::TypeMetadataAccessFunction, type);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forTypeMetadataInstantiationCache(NominalTypeDecl *decl) {
|
|
LinkEntity entity;
|
|
entity.setForDecl(Kind::TypeMetadataInstantiationCache, decl);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forTypeMetadataInstantiationFunction(NominalTypeDecl *decl){
|
|
LinkEntity entity;
|
|
entity.setForDecl(Kind::TypeMetadataInstantiationFunction, decl);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forTypeMetadataLazyCacheVariable(CanType type) {
|
|
LinkEntity entity;
|
|
entity.setForType(Kind::TypeMetadataLazyCacheVariable, type);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forForeignTypeMetadataCandidate(CanType type) {
|
|
LinkEntity entity;
|
|
entity.setForType(Kind::ForeignTypeMetadataCandidate, type);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forClassMetadataBaseOffset(ClassDecl *decl) {
|
|
LinkEntity entity;
|
|
entity.setForDecl(Kind::ClassMetadataBaseOffset, decl);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forNominalTypeDescriptor(NominalTypeDecl *decl) {
|
|
LinkEntity entity;
|
|
entity.setForDecl(Kind::NominalTypeDescriptor, decl);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forPropertyDescriptor(AbstractStorageDecl *decl) {
|
|
LinkEntity entity;
|
|
entity.setForDecl(Kind::PropertyDescriptor, decl);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forModuleDescriptor(ModuleDecl *decl) {
|
|
LinkEntity entity;
|
|
entity.setForDecl(Kind::ModuleDescriptor, decl);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forExtensionDescriptor(ExtensionDecl *decl) {
|
|
LinkEntity entity;
|
|
entity.Pointer = const_cast<void*>(static_cast<const void*>(decl));
|
|
entity.SecondaryPointer = nullptr;
|
|
entity.Data =
|
|
LINKENTITY_SET_FIELD(Kind, unsigned(Kind::ExtensionDescriptor));
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forAnonymousDescriptor(DeclContext *dc) {
|
|
LinkEntity entity;
|
|
entity.Pointer = const_cast<void*>(static_cast<const void*>(dc));
|
|
entity.SecondaryPointer = nullptr;
|
|
entity.Data =
|
|
LINKENTITY_SET_FIELD(Kind, unsigned(Kind::AnonymousDescriptor));
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forProtocolDescriptor(ProtocolDecl *decl) {
|
|
LinkEntity entity;
|
|
entity.setForDecl(Kind::ProtocolDescriptor, decl);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forValueWitness(CanType concreteType, ValueWitness witness) {
|
|
LinkEntity entity;
|
|
entity.Pointer = concreteType.getPointer();
|
|
entity.Data = LINKENTITY_SET_FIELD(Kind, unsigned(Kind::ValueWitness))
|
|
| LINKENTITY_SET_FIELD(ValueWitness, unsigned(witness));
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forValueWitnessTable(CanType type) {
|
|
LinkEntity entity;
|
|
entity.setForType(Kind::ValueWitnessTable, type);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forSILFunction(SILFunction *F)
|
|
{
|
|
LinkEntity entity;
|
|
entity.Pointer = F;
|
|
entity.SecondaryPointer = nullptr;
|
|
entity.Data = LINKENTITY_SET_FIELD(Kind, unsigned(Kind::SILFunction));
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forSILGlobalVariable(SILGlobalVariable *G) {
|
|
LinkEntity entity;
|
|
entity.Pointer = G;
|
|
entity.SecondaryPointer = nullptr;
|
|
entity.Data = LINKENTITY_SET_FIELD(Kind, unsigned(Kind::SILGlobalVariable));
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity
|
|
forDirectProtocolWitnessTable(const ProtocolConformance *C) {
|
|
LinkEntity entity;
|
|
entity.setForProtocolConformance(Kind::DirectProtocolWitnessTable, C);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity
|
|
forProtocolWitnessTableAccessFunction(const ProtocolConformance *C) {
|
|
LinkEntity entity;
|
|
entity.setForProtocolConformance(Kind::ProtocolWitnessTableAccessFunction,
|
|
C);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity
|
|
forGenericProtocolWitnessTableCache(const ProtocolConformance *C) {
|
|
LinkEntity entity;
|
|
entity.setForProtocolConformance(Kind::GenericProtocolWitnessTableCache, C);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity
|
|
forGenericProtocolWitnessTableInstantiationFunction(
|
|
const ProtocolConformance *C) {
|
|
LinkEntity entity;
|
|
entity.setForProtocolConformance(
|
|
Kind::GenericProtocolWitnessTableInstantiationFunction, C);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity
|
|
forProtocolWitnessTableLazyAccessFunction(const ProtocolConformance *C,
|
|
CanType type) {
|
|
LinkEntity entity;
|
|
entity.setForProtocolConformanceAndType(
|
|
Kind::ProtocolWitnessTableLazyAccessFunction, C, type);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity
|
|
forProtocolWitnessTableLazyCacheVariable(const ProtocolConformance *C,
|
|
CanType type) {
|
|
LinkEntity entity;
|
|
entity.setForProtocolConformanceAndType(
|
|
Kind::ProtocolWitnessTableLazyCacheVariable, C, type);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity
|
|
forAssociatedTypeMetadataAccessFunction(const ProtocolConformance *C,
|
|
AssociatedType association) {
|
|
LinkEntity entity;
|
|
entity.setForProtocolConformanceAndAssociatedType(
|
|
Kind::AssociatedTypeMetadataAccessFunction, C,
|
|
association.getAssociation());
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity
|
|
forAssociatedTypeWitnessTableAccessFunction(const ProtocolConformance *C,
|
|
const AssociatedConformance &association) {
|
|
LinkEntity entity;
|
|
entity.setForProtocolConformanceAndAssociatedConformance(
|
|
Kind::AssociatedTypeWitnessTableAccessFunction, C,
|
|
association.getAssociation(),
|
|
association.getAssociatedRequirement());
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forReflectionBuiltinDescriptor(CanType type) {
|
|
LinkEntity entity;
|
|
entity.setForType(Kind::ReflectionBuiltinDescriptor, type);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forReflectionFieldDescriptor(CanType type) {
|
|
LinkEntity entity;
|
|
entity.setForType(Kind::ReflectionFieldDescriptor, type);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity
|
|
forReflectionAssociatedTypeDescriptor(const ProtocolConformance *C) {
|
|
LinkEntity entity;
|
|
entity.setForProtocolConformance(
|
|
Kind::ReflectionAssociatedTypeDescriptor, C);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity
|
|
forProtocolConformanceDescriptor(const NormalProtocolConformance *C) {
|
|
LinkEntity entity;
|
|
entity.setForProtocolConformance(
|
|
Kind::ProtocolConformanceDescriptor, C);
|
|
return entity;
|
|
}
|
|
|
|
static LinkEntity forCoroutineContinuationPrototype(CanSILFunctionType type) {
|
|
LinkEntity entity;
|
|
entity.setForType(Kind::CoroutineContinuationPrototype, type);
|
|
return entity;
|
|
}
|
|
|
|
void mangle(llvm::raw_ostream &out) const;
|
|
void mangle(SmallVectorImpl<char> &buffer) const;
|
|
std::string mangleAsString() const;
|
|
SILLinkage getLinkage(ForDefinition_t isDefinition) const;
|
|
|
|
/// Returns true if this function or global variable is potentially defined
|
|
/// in a different module.
|
|
///
|
|
bool isAvailableExternally(IRGenModule &IGM) const;
|
|
|
|
const ValueDecl *getDecl() const {
|
|
assert(isDeclKind(getKind()));
|
|
return reinterpret_cast<ValueDecl*>(Pointer);
|
|
}
|
|
|
|
const ExtensionDecl *getExtension() const {
|
|
assert(getKind() == Kind::ExtensionDescriptor);
|
|
return reinterpret_cast<ExtensionDecl*>(Pointer);
|
|
}
|
|
|
|
const DeclContext *getDeclContext() const {
|
|
assert(getKind() == Kind::AnonymousDescriptor);
|
|
return reinterpret_cast<DeclContext*>(Pointer);
|
|
}
|
|
|
|
SILFunction *getSILFunction() const {
|
|
assert(getKind() == Kind::SILFunction);
|
|
return reinterpret_cast<SILFunction*>(Pointer);
|
|
}
|
|
|
|
SILGlobalVariable *getSILGlobalVariable() const {
|
|
assert(getKind() == Kind::SILGlobalVariable);
|
|
return reinterpret_cast<SILGlobalVariable*>(Pointer);
|
|
}
|
|
|
|
const ProtocolConformance *getProtocolConformance() const {
|
|
assert(isProtocolConformanceKind(getKind()));
|
|
return reinterpret_cast<ProtocolConformance*>(SecondaryPointer);
|
|
}
|
|
|
|
AssociatedTypeDecl *getAssociatedType() const {
|
|
assert(getKind() == Kind::AssociatedTypeMetadataAccessFunction);
|
|
return getAssociatedTypeByIndex(getProtocolConformance(),
|
|
LINKENTITY_GET_FIELD(Data, AssociatedTypeIndex));
|
|
}
|
|
|
|
std::pair<CanType, ProtocolDecl *> getAssociatedConformance() const {
|
|
assert(getKind() == Kind::AssociatedTypeWitnessTableAccessFunction);
|
|
return getAssociatedConformanceByIndex(getProtocolConformance(),
|
|
LINKENTITY_GET_FIELD(Data, AssociatedConformanceIndex));
|
|
}
|
|
|
|
ProtocolDecl *getAssociatedProtocol() const {
|
|
assert(getKind() == Kind::AssociatedTypeWitnessTableAccessFunction);
|
|
return reinterpret_cast<ProtocolDecl*>(Pointer);
|
|
}
|
|
|
|
bool isValueWitness() const { return getKind() == Kind::ValueWitness; }
|
|
CanType getType() const {
|
|
assert(isTypeKind(getKind()));
|
|
return CanType(reinterpret_cast<TypeBase*>(Pointer));
|
|
}
|
|
ValueWitness getValueWitness() const {
|
|
assert(getKind() == Kind::ValueWitness);
|
|
return ValueWitness(LINKENTITY_GET_FIELD(Data, ValueWitness));
|
|
}
|
|
TypeMetadataAddress getMetadataAddress() const {
|
|
assert(getKind() == Kind::TypeMetadata);
|
|
return (TypeMetadataAddress)LINKENTITY_GET_FIELD(Data, MetadataAddress);
|
|
}
|
|
bool isForeignTypeMetadataCandidate() const {
|
|
return getKind() == Kind::ForeignTypeMetadataCandidate;
|
|
}
|
|
bool isObjCClassRef() const {
|
|
return getKind() == Kind::ObjCClassRef;
|
|
}
|
|
|
|
/// Determine whether this entity will be weak-imported.
|
|
bool isWeakImported(ModuleDecl *module) const {
|
|
if (getKind() == Kind::SILGlobalVariable &&
|
|
getSILGlobalVariable()->getDecl())
|
|
return getSILGlobalVariable()->getDecl()->isWeakImported(module);
|
|
|
|
if (getKind() == Kind::SILFunction) {
|
|
if (auto clangOwner = getSILFunction()->getClangNodeOwner())
|
|
return clangOwner->isWeakImported(module);
|
|
if (getSILFunction()->isWeakLinked())
|
|
return getSILFunction()->isAvailableExternally();
|
|
}
|
|
|
|
if (!isDeclKind(getKind()))
|
|
return false;
|
|
|
|
return getDecl()->isWeakImported(module);
|
|
}
|
|
#undef LINKENTITY_GET_FIELD
|
|
#undef LINKENTITY_SET_FIELD
|
|
};
|
|
|
|
/// Encapsulated information about the linkage of an entity.
|
|
class LinkInfo {
|
|
LinkInfo() = default;
|
|
|
|
llvm::SmallString<32> Name;
|
|
llvm::GlobalValue::LinkageTypes Linkage;
|
|
llvm::GlobalValue::VisibilityTypes Visibility;
|
|
llvm::GlobalValue::DLLStorageClassTypes DLLStorageClass;
|
|
ForDefinition_t ForDefinition;
|
|
|
|
public:
|
|
/// Compute linkage information for the given
|
|
static LinkInfo get(const UniversalLinkageInfo &linkInfo,
|
|
ModuleDecl *swiftModule, const LinkEntity &entity,
|
|
ForDefinition_t forDefinition);
|
|
|
|
static LinkInfo get(IRGenModule &IGM, const LinkEntity &entity,
|
|
ForDefinition_t forDefinition);
|
|
|
|
static LinkInfo get(const UniversalLinkageInfo &linkInfo,
|
|
StringRef name,
|
|
SILLinkage linkage,
|
|
ForDefinition_t isDefinition,
|
|
bool isWeakImported);
|
|
|
|
StringRef getName() const {
|
|
return Name.str();
|
|
}
|
|
llvm::GlobalValue::LinkageTypes getLinkage() const {
|
|
return Linkage;
|
|
}
|
|
llvm::GlobalValue::VisibilityTypes getVisibility() const {
|
|
return Visibility;
|
|
}
|
|
llvm::GlobalValue::DLLStorageClassTypes getDLLStorage() const {
|
|
return DLLStorageClass;
|
|
}
|
|
|
|
bool isForDefinition() const {
|
|
return ForDefinition;
|
|
}
|
|
bool isUsed() const {
|
|
return ForDefinition && isUsed(Linkage, Visibility, DLLStorageClass);
|
|
}
|
|
|
|
static bool isUsed(llvm::GlobalValue::LinkageTypes Linkage,
|
|
llvm::GlobalValue::VisibilityTypes Visibility,
|
|
llvm::GlobalValue::DLLStorageClassTypes DLLStorage);
|
|
};
|
|
}
|
|
}
|
|
|
|
/// Allow LinkEntity to be used as a key for a DenseMap.
|
|
template <> struct llvm::DenseMapInfo<swift::irgen::LinkEntity> {
|
|
typedef swift::irgen::LinkEntity LinkEntity;
|
|
static LinkEntity getEmptyKey() {
|
|
LinkEntity entity;
|
|
entity.Pointer = nullptr;
|
|
entity.SecondaryPointer = nullptr;
|
|
entity.Data = 0;
|
|
return entity;
|
|
}
|
|
static LinkEntity getTombstoneKey() {
|
|
LinkEntity entity;
|
|
entity.Pointer = nullptr;
|
|
entity.SecondaryPointer = nullptr;
|
|
entity.Data = 1;
|
|
return entity;
|
|
}
|
|
static unsigned getHashValue(const LinkEntity &entity) {
|
|
return DenseMapInfo<void *>::getHashValue(entity.Pointer) ^
|
|
DenseMapInfo<void *>::getHashValue(entity.SecondaryPointer) ^
|
|
entity.Data;
|
|
}
|
|
static bool isEqual(const LinkEntity &LHS, const LinkEntity &RHS) {
|
|
return LHS.Pointer == RHS.Pointer &&
|
|
LHS.SecondaryPointer == RHS.SecondaryPointer && LHS.Data == RHS.Data;
|
|
}
|
|
};
|
|
|
|
#endif
|