blob: b74101ac2d20d68b23282608f9491f266fc8c568 [file] [log] [blame]
//===--- Linking.h - Common declarations for link information ---*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines structures and routines used when creating global
// entities that are placed in the LLVM module, potentially with
// external linkage.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_IRGEN_LINKING_H
#define SWIFT_IRGEN_LINKING_H
#include "swift/AST/Types.h"
#include "swift/AST/Decl.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/SILFunction.h"
#include "swift/SIL/SILGlobalVariable.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/GlobalValue.h"
#include "DebugTypeInfo.h"
#include "IRGen.h"
#include "IRGenModule.h"
#include "ValueWitness.h"
namespace llvm {
class AttributeSet;
class Value;
class FunctionType;
}
namespace swift {
namespace irgen {
class TypeInfo;
class IRGenModule;
/// 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 exploded or 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,
// These fields appear in decl kinds.
ExplosionLevelShift = 8, ExplosionLevelMask = 0xFF00,
UncurryLevelShift = 16, UncurryLevelMask = 0xFF0000,
// This field appears in the ValueWitness kind.
ValueWitnessShift = 8, ValueWitnessMask = 0xFF00,
// These fields appear in the FieldOffset kind.
IsIndirectShift = 8, IsIndirectMask = 0x0100,
// These fields appear in the TypeMetadata kind.
MetadataAddressShift = 8, MetadataAddressMask = 0x0300,
IsPatternShift = 10, IsPatternMask = 0x0400,
};
#define LINKENTITY_SET_FIELD(field, value) (value << field##Shift)
#define LINKENTITY_GET_FIELD(value, field) ((value & field##Mask) >> field##Shift)
enum class Kind {
/// A function.
/// The pointer is a FuncDecl*.
Function,
/// The offset to apply to a witness table or metadata object
/// in order to find the information for a declaration. The
/// pointer is a ValueDecl*.
WitnessTableOffset,
/// A field offset. The pointer is a VarDecl*.
FieldOffset,
/// An Objective-C class reference. The pointer is a ClassDecl*.
ObjCClass,
/// An Objective-C metaclass reference. The pointer is a ClassDecl*.
ObjCMetaclass,
/// A swift metaclass-stub reference. The pointer is a ClassDecl*.
SwiftMetaclassStub,
/// The nominal type descriptor for a nominal type.
/// The pointer is a NominalTypeDecl*.
NominalTypeDescriptor,
/// The protocol descriptor for a protocol type.
/// The pointer is a ProtocolDecl*.
ProtocolDescriptor,
/// Some other kind of declaration.
/// The pointer is a Decl*.
Other,
/// A SIL function. The pointer is a SILFunction*.
SILFunction,
/// A SIL global variable. The pointer is a SILGlobalVariable*.
SILGlobalVariable,
/// A direct protocol witness table. The secondary pointer is a
/// ProtocolConformance*.
DirectProtocolWitnessTable,
/// A witness accessor function. The secondary pointer is a
/// ProtocolConformance*.
ProtocolWitnessTableAccessFunction,
/// A dependent protocol witness table instantiation function. The
/// secondary pointer is a ProtocolConformance*.
DependentProtocolWitnessTableGenerator,
/// A template for dependent protocol witness table instantiation. The
/// secondary pointer is a ProtocolConformance*.
DependentProtocolWitnessTableTemplate,
// 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 type which is being mangled just for its string.
/// The pointer is a canonical TypeBase*.
TypeMangling,
};
friend struct llvm::DenseMapInfo<LinkEntity>;
static bool isFunction(ValueDecl *decl) {
return (isa<FuncDecl>(decl) || isa<EnumElementDecl>(decl) ||
isa<ConstructorDecl>(decl));
}
static bool hasGetterSetter(ValueDecl *decl) {
return (isa<VarDecl>(decl) || isa<SubscriptDecl>(decl));
}
Kind getKind() const {
return Kind(LINKENTITY_GET_FIELD(Data, Kind));
}
static bool isDeclKind(Kind k) {
return k <= Kind::Other;
}
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,
ValueDecl *decl, ResilienceExpansion explosionKind,
unsigned uncurryLevel) {
assert(isDeclKind(kind));
Pointer = decl;
SecondaryPointer = nullptr;
Data = LINKENTITY_SET_FIELD(Kind, unsigned(kind))
| LINKENTITY_SET_FIELD(ExplosionLevel, unsigned(explosionKind))
| LINKENTITY_SET_FIELD(UncurryLevel, uncurryLevel);
}
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 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 forNonFunction(ValueDecl *decl) {
assert(!isFunction(decl));
LinkEntity entity;
entity.setForDecl(Kind::Other, decl, ResilienceExpansion(0), 0);
return entity;
}
static LinkEntity forWitnessTableOffset(ValueDecl *decl,
ResilienceExpansion explosionKind,
unsigned uncurryLevel) {
LinkEntity entity;
entity.setForDecl(Kind::WitnessTableOffset, decl,
explosionKind, uncurryLevel);
return entity;
}
static LinkEntity forFieldOffset(VarDecl *decl, bool isIndirect) {
LinkEntity entity;
entity.Pointer = decl;
entity.SecondaryPointer = nullptr;
entity.Data = LINKENTITY_SET_FIELD(Kind, unsigned(Kind::FieldOffset))
| LINKENTITY_SET_FIELD(IsIndirect, unsigned(isIndirect));
return entity;
}
static LinkEntity forObjCClass(ClassDecl *decl) {
LinkEntity entity;
entity.setForDecl(Kind::ObjCClass, decl, ResilienceExpansion::Minimal, 0);
return entity;
}
static LinkEntity forObjCMetaclass(ClassDecl *decl) {
LinkEntity entity;
entity.setForDecl(Kind::ObjCMetaclass, decl, ResilienceExpansion::Minimal, 0);
return entity;
}
static LinkEntity forSwiftMetaclassStub(ClassDecl *decl) {
LinkEntity entity;
entity.setForDecl(Kind::SwiftMetaclassStub,
decl, ResilienceExpansion::Minimal, 0);
return entity;
}
static LinkEntity forTypeMetadata(CanType concreteType,
TypeMetadataAddress addr,
bool isPattern) {
LinkEntity entity;
entity.Pointer = concreteType.getPointer();
entity.SecondaryPointer = nullptr;
entity.Data = LINKENTITY_SET_FIELD(Kind, unsigned(Kind::TypeMetadata))
| LINKENTITY_SET_FIELD(MetadataAddress, unsigned(addr))
| LINKENTITY_SET_FIELD(IsPattern, unsigned(isPattern));
return entity;
}
static LinkEntity forTypeMetadataAccessFunction(CanType type) {
LinkEntity entity;
entity.setForType(Kind::TypeMetadataAccessFunction, type);
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 forNominalTypeDescriptor(NominalTypeDecl *decl) {
LinkEntity entity;
entity.setForDecl(Kind::NominalTypeDescriptor,
decl, ResilienceExpansion::Minimal, 0);
return entity;
}
static LinkEntity forProtocolDescriptor(ProtocolDecl *decl) {
LinkEntity entity;
entity.setForDecl(Kind::ProtocolDescriptor,
decl, ResilienceExpansion::Minimal, 0);
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 forTypeMangling(CanType type) {
LinkEntity entity;
entity.setForType(Kind::TypeMangling, 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
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;
}
void mangle(llvm::raw_ostream &out) const;
void mangle(SmallVectorImpl<char> &buffer) const;
SILLinkage getLinkage(IRGenModule &IGM, ForDefinition_t isDefinition) const;
/// Returns true if this function or global variable may be inlined into
/// another module.
///
bool isFragile(IRGenModule &IGM) const;
ValueDecl *getDecl() const {
assert(isDeclKind(getKind()));
return reinterpret_cast<ValueDecl*>(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);
}
ResilienceExpansion getResilienceExpansion() const {
assert(isDeclKind(getKind()));
return ResilienceExpansion(LINKENTITY_GET_FIELD(Data, ExplosionLevel));
}
unsigned getUncurryLevel() const {
return LINKENTITY_GET_FIELD(Data, UncurryLevel);
}
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 isMetadataPattern() const {
assert(getKind() == Kind::TypeMetadata);
return LINKENTITY_GET_FIELD(Data, IsPattern);
}
bool isForeignTypeMetadataCandidate() const {
return getKind() == Kind::ForeignTypeMetadataCandidate;
}
bool isOffsetIndirect() const {
assert(getKind() == Kind::FieldOffset);
return LINKENTITY_GET_FIELD(Data, IsIndirect);
}
/// Determine whether this entity will be weak-imported.
bool isWeakImported(Module *module) const {
if (getKind() == Kind::SILGlobalVariable &&
getSILGlobalVariable()->getDecl())
return getSILGlobalVariable()->getDecl()->isWeakImported(module);
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;
ForDefinition_t ForDefinition;
public:
/// Compute linkage information for the given
static LinkInfo get(IRGenModule &IGM, const LinkEntity &entity,
ForDefinition_t forDefinition);
StringRef getName() const {
return Name.str();
}
llvm::GlobalValue::LinkageTypes getLinkage() const {
return Linkage;
}
llvm::GlobalValue::VisibilityTypes getVisibility() const {
return Visibility;
}
llvm::Function *createFunction(IRGenModule &IGM,
llvm::FunctionType *fnType,
llvm::CallingConv::ID cc,
const llvm::AttributeSet &attrs,
llvm::Function *insertBefore = nullptr);
llvm::GlobalVariable *createVariable(IRGenModule &IGM,
llvm::Type *objectType,
Alignment alignment,
DebugTypeInfo DebugType=DebugTypeInfo(),
Optional<SILLocation> DebugLoc = None,
StringRef DebugName = StringRef());
bool isUsed() const;
};
} // end namespace irgen
} // end namespace swift
/// 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