Files
swift-mirror/lib/IRGen/GenMeta.cpp
John McCall f1682cd9a8 Use real types instead of "Self" for the IR value names of local type data.
Since that's somewhat expensive, allow the generation of meaningful
IR value names to be efficiently controlled in IRGen.  By default,
enable meaningful value names only when generating .ll output.

I considered giving protocol witness tables the name T:Protocol
instead of T.Protocol, but decided that I didn't want to update that
many test cases.
2016-01-13 19:26:18 -08:00

5114 lines
196 KiB
C++

//===--- GenMeta.cpp - IR generation for metadata constructs --------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements IR generation for metadata constructs like
// metatypes and modules. These is presently always trivial, but in
// the future we will likely have some sort of physical
// representation for at least some metatypes.
//
//===----------------------------------------------------------------------===//
#include "swift/AST/ArchetypeBuilder.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/CanTypeVisitor.h"
#include "swift/AST/Decl.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/AST/Substitution.h"
#include "swift/AST/Types.h"
#include "swift/SIL/FormalLinkage.h"
#include "swift/SIL/SILModule.h"
#include "swift/SIL/TypeLowering.h"
#include "swift/ABI/MetadataValues.h"
#include "llvm/IR/InlineAsm.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/Module.h"
#include "llvm/ADT/SmallString.h"
#include "Address.h"
#include "Callee.h"
#include "ClassMetadataLayout.h"
#include "FixedTypeInfo.h"
#include "GenClass.h"
#include "GenPoly.h"
#include "GenArchetype.h"
#include "GenStruct.h"
#include "HeapTypeInfo.h"
#include "IRGenModule.h"
#include "IRGenDebugInfo.h"
#include "Linking.h"
#include "ScalarTypeInfo.h"
#include "StructMetadataLayout.h"
#include "StructLayout.h"
#include "EnumMetadataLayout.h"
#include "GenMeta.h"
using namespace swift;
using namespace irgen;
static llvm::Value *emitLoadOfObjCHeapMetadataRef(IRGenFunction &IGF,
llvm::Value *object);
static llvm::LoadInst *
emitLoadFromMetadataAtIndex(IRGenFunction &IGF,
llvm::Value *metadata,
int index,
llvm::Type *objectTy,
const llvm::Twine &suffix = "");
/// Produce a constant to place in a metatype's isa field
/// corresponding to the given metadata kind.
static llvm::ConstantInt *getMetadataKind(IRGenModule &IGM,
MetadataKind kind) {
return llvm::ConstantInt::get(IGM.MetadataKindTy, uint8_t(kind));
}
static Size::int_type getOffsetInWords(IRGenModule &IGM, Size offset) {
assert(offset.isMultipleOf(IGM.getPointerSize()));
return offset / IGM.getPointerSize();
}
static Address createPointerSizedGEP(IRGenFunction &IGF,
Address base,
Size offset) {
return IGF.Builder.CreateConstArrayGEP(base,
getOffsetInWords(IGF.IGM, offset),
offset);
}
static llvm::Constant *getMangledTypeName(IRGenModule &IGM, CanType type) {
auto name = LinkEntity::forTypeMangling(type);
llvm::SmallString<32> mangling;
name.mangle(mangling);
return IGM.getAddrOfGlobalString(mangling);
}
llvm::Value *irgen::emitObjCMetadataRefForMetadata(IRGenFunction &IGF,
llvm::Value *classPtr) {
classPtr = IGF.Builder.CreateBitCast(classPtr, IGF.IGM.ObjCClassPtrTy);
// Fetch the metadata for that class.
auto call = IGF.Builder.CreateCall(IGF.IGM.getGetObjCClassMetadataFn(),
classPtr);
call->setDoesNotThrow();
call->setDoesNotAccessMemory();
call->setCallingConv(IGF.IGM.RuntimeCC);
return call;
}
/// Emit a reference to the Swift metadata for an Objective-C class.
static llvm::Value *emitObjCMetadataRef(IRGenFunction &IGF,
ClassDecl *theClass) {
// Derive a pointer to the Objective-C class.
auto classPtr = emitObjCHeapMetadataRef(IGF, theClass);
return emitObjCMetadataRefForMetadata(IGF, classPtr);
}
namespace {
/// A structure for collecting generic arguments for emitting a
/// nominal metadata reference. The structure produced here is
/// consumed by swift_getGenericMetadata() and must correspond to
/// the fill operations that the compiler emits for the bound decl.
struct GenericArguments {
/// The values to use to initialize the arguments structure.
SmallVector<llvm::Value *, 8> Values;
SmallVector<llvm::Type *, 8> Types;
void collect(IRGenFunction &IGF, BoundGenericType *type) {
auto subs = type->getSubstitutions(/*FIXME:*/nullptr, nullptr);
// Add all the argument archetypes.
// TODO: only the *primary* archetypes
// TODO: not archetypes from outer contexts
// TODO: but we are partially determined by the outer context!
for (auto &sub : subs) {
CanType subbed = sub.getReplacement()->getCanonicalType();
Values.push_back(IGF.emitTypeMetadataRef(subbed));
}
// All of those values are metadata pointers.
Types.append(Values.size(), IGF.IGM.TypeMetadataPtrTy);
// Add protocol witness tables for all those archetypes.
for (auto i : indices(subs)) {
llvm::Value *metadata = Values[i];
emitWitnessTableRefs(IGF, subs[i], &metadata, Values);
}
// All of those values are witness table pointers.
Types.append(Values.size() - Types.size(), IGF.IGM.WitnessTablePtrTy);
}
};
}
/// Given an array of polymorphic arguments as might be set up by
/// GenericArguments, bind the polymorphic parameters.
static void emitPolymorphicParametersFromArray(IRGenFunction &IGF,
const GenericParamList &generics,
Address array) {
unsigned nextIndex = 0;
auto claimNext = [&](llvm::PointerType *desiredType) {
Address addr = array;
if (unsigned index = nextIndex++) {
addr = IGF.Builder.CreateConstArrayGEP(array, index,
index * IGF.IGM.getPointerSize());
}
llvm::Value *value = IGF.Builder.CreateLoad(addr);
return IGF.Builder.CreateBitCast(value, desiredType);
};
// Bind all the argument archetypes.
for (auto archetype : generics.getAllArchetypes()) {
llvm::Value *metadata = claimNext(IGF.IGM.TypeMetadataPtrTy);
metadata->setName(archetype->getFullName());
IGF.setUnscopedLocalTypeData(CanType(archetype),
LocalTypeDataKind::forTypeMetadata(),
metadata);
}
// Bind all the argument witness tables.
for (auto archetype : generics.getAllArchetypes()) {
for (auto protocol : archetype->getConformsTo()) {
if (!Lowering::TypeConverter::protocolRequiresWitnessTable(protocol))
continue;
llvm::Value *wtable = claimNext(IGF.IGM.WitnessTablePtrTy);
auto key = LocalTypeDataKind::forAbstractProtocolWitnessTable(protocol);
IGF.setUnscopedLocalTypeData(CanType(archetype), key, wtable);
}
}
}
/// If true, we lazily initialize metadata at runtime because the layout
/// is only partially known. Otherwise, we can emit a direct reference a
/// constant metadata symbol.
static bool hasMetadataPattern(IRGenModule &IGM, NominalTypeDecl *theDecl) {
// Protocols must be special-cased in a few places.
assert(!isa<ProtocolDecl>(theDecl));
// For classes, we already computed this when we did the layout.
// FIXME: Try not to call this for classes of other modules, by referencing
// the metadata accessor instead.
if (auto *theClass = dyn_cast<ClassDecl>(theDecl))
return getClassHasMetadataPattern(IGM, theClass);
// Ok, we have a value type. If it is generic, it is always initialized
// at runtime.
if (theDecl->isGenericContext())
return true;
// If the type is not fixed-size, its size depends on resilient types,
// and the metadata is initialized at runtime.
if (!IGM.getTypeInfoForUnlowered(theDecl->getDeclaredType()).isFixedSize())
return true;
return false;
}
/// Attempts to return a constant heap metadata reference for a
/// nominal type.
llvm::Constant *irgen::tryEmitConstantTypeMetadataRef(IRGenModule &IGM,
CanType type) {
auto theDecl = type->getAnyNominal();
assert(theDecl && "emitting constant metadata ref for non-nominal type?");
if (hasMetadataPattern(IGM, theDecl))
return nullptr;
if (auto theClass = type->getClassOrBoundGenericClass())
if (!hasKnownSwiftMetadata(IGM, theClass))
return IGM.getAddrOfObjCClass(theClass, NotForDefinition);
return IGM.getAddrOfTypeMetadata(type, false);
}
/// Emit a reference to an ObjC class. In general, the only things
/// you're allowed to do with the address of an ObjC class symbol are
/// (1) send ObjC messages to it (in which case the message will be
/// forwarded to the real class, if one exists) or (2) put it in
/// various data sections where the ObjC runtime will properly arrange
/// things. Therefore, we must typically force the initialization of
/// a class when emitting a reference to it.
llvm::Value *irgen::emitObjCHeapMetadataRef(IRGenFunction &IGF,
ClassDecl *theClass,
bool allowUninitialized) {
auto classObject = IGF.IGM.getAddrOfObjCClass(theClass, NotForDefinition);
if (allowUninitialized) return classObject;
// TODO: memoize this the same way that we memoize Swift type metadata?
return IGF.Builder.CreateCall(IGF.IGM.getGetInitializedObjCClassFn(),
classObject);
}
/// Emit a reference to the type metadata for a foreign type.
static llvm::Value *emitForeignTypeMetadataRef(IRGenFunction &IGF,
CanType type) {
llvm::Value *candidate = IGF.IGM.getAddrOfForeignTypeMetadataCandidate(type);
auto call = IGF.Builder.CreateCall(IGF.IGM.getGetForeignTypeMetadataFn(),
candidate);
call->addAttribute(llvm::AttributeSet::FunctionIndex,
llvm::Attribute::NoUnwind);
call->addAttribute(llvm::AttributeSet::FunctionIndex,
llvm::Attribute::ReadNone);
return call;
}
/// Returns a metadata reference for a nominal type.
static llvm::Value *emitNominalMetadataRef(IRGenFunction &IGF,
NominalTypeDecl *theDecl,
CanType theType) {
assert(!isa<ProtocolDecl>(theDecl));
// Non-native Swift classes need to be handled differently.
if (auto theClass = dyn_cast<ClassDecl>(theDecl)) {
// We emit a completely different pattern for foreign classes.
if (theClass->isForeign()) {
return emitForeignTypeMetadataRef(IGF, theType);
}
// Classes that might not have Swift metadata use a different
// symbol name.
if (!hasKnownSwiftMetadata(IGF.IGM, theClass)) {
assert(!theDecl->getGenericParamsOfContext() &&
"ObjC class cannot be generic");
return emitObjCMetadataRef(IGF, theClass);
}
} else if (theDecl->hasClangNode()) {
// Imported Clang types require foreign metadata uniquing too.
return emitForeignTypeMetadataRef(IGF, theType);
}
bool isPattern = hasMetadataPattern(IGF.IGM, theDecl);
// If this is generic, check to see if we've maybe got a local
// reference already.
if (isPattern) {
if (auto cache = IGF.tryGetLocalTypeData(theType,
LocalTypeDataKind::forTypeMetadata()))
return cache;
}
// Grab a reference to the metadata or metadata template.
CanType declaredType = theDecl->getDeclaredType()->getCanonicalType();
llvm::Value *metadata = IGF.IGM.getAddrOfTypeMetadata(declaredType,isPattern);
// If we don't have a metadata pattern, that's all we need.
if (!isPattern) {
assert(metadata->getType() == IGF.IGM.TypeMetadataPtrTy);
// If this is a class, we need to force ObjC initialization,
// but only if we're doing Objective-C interop.
if (IGF.IGM.ObjCInterop && isa<ClassDecl>(theDecl)) {
metadata = IGF.Builder.CreateBitCast(metadata, IGF.IGM.ObjCClassPtrTy);
metadata = IGF.Builder.CreateCall(IGF.IGM.getGetInitializedObjCClassFn(),
metadata);
metadata = IGF.Builder.CreateBitCast(metadata, IGF.IGM.TypeMetadataPtrTy);
}
return metadata;
}
// Okay, we need to call swift_getGenericMetadata.
assert(metadata->getType() == IGF.IGM.TypeMetadataPatternPtrTy);
// If we have a pattern but no generic substitutions, we're just
// doing resilient type layout.
if (isPattern && !theDecl->isGenericContext()) {
llvm::Constant *getter = IGF.IGM.getGetResilientMetadataFn();
auto result = IGF.Builder.CreateCall(getter, {metadata});
result->setDoesNotThrow();
result->addAttribute(llvm::AttributeSet::FunctionIndex,
llvm::Attribute::ReadNone);
IGF.setScopedLocalTypeData(theType, LocalTypeDataKind::forTypeMetadata(),
result);
return result;
}
// Grab the substitutions.
auto boundGeneric = cast<BoundGenericType>(theType);
assert(boundGeneric->getDecl() == theDecl);
GenericArguments genericArgs;
genericArgs.collect(IGF, boundGeneric);
// If we have less than four arguments, use a fast entry point.
assert(genericArgs.Values.size() > 0 && "no generic args?!");
if (genericArgs.Values.size() <= 4) {
llvm::Constant *fastGetter;
switch (genericArgs.Values.size()) {
case 1: fastGetter = IGF.IGM.getGetGenericMetadata1Fn(); break;
case 2: fastGetter = IGF.IGM.getGetGenericMetadata2Fn(); break;
case 3: fastGetter = IGF.IGM.getGetGenericMetadata3Fn(); break;
case 4: fastGetter = IGF.IGM.getGetGenericMetadata4Fn(); break;
default: llvm_unreachable("bad number of generic arguments");
}
SmallVector<llvm::Value *, 5> args;
args.push_back(metadata);
for (auto value : genericArgs.Values)
args.push_back(IGF.Builder.CreateBitCast(value, IGF.IGM.Int8PtrTy));
auto result = IGF.Builder.CreateCall(fastGetter, args);
result->setDoesNotThrow();
result->addAttribute(llvm::AttributeSet::FunctionIndex,
llvm::Attribute::ReadNone);
IGF.setScopedLocalTypeData(theType, LocalTypeDataKind::forTypeMetadata(),
result);
return result;
}
// Slam that information directly into the generic arguments buffer.
auto argsBufferTy =
llvm::StructType::get(IGF.IGM.LLVMContext, genericArgs.Types);
Address argsBuffer = IGF.createAlloca(argsBufferTy,
IGF.IGM.getPointerAlignment(),
"generic.arguments");
IGF.Builder.CreateLifetimeStart(argsBuffer,
IGF.IGM.getPointerSize() * genericArgs.Values.size());
for (unsigned i = 0, e = genericArgs.Values.size(); i != e; ++i) {
Address elt = IGF.Builder.CreateStructGEP(argsBuffer, i,
IGF.IGM.getPointerSize() * i);
IGF.Builder.CreateStore(genericArgs.Values[i], elt);
}
// Cast to void*.
llvm::Value *arguments =
IGF.Builder.CreateBitCast(argsBuffer.getAddress(), IGF.IGM.Int8PtrTy);
// Make the call.
auto result = IGF.Builder.CreateCall(IGF.IGM.getGetGenericMetadataFn(),
{metadata, arguments});
result->setDoesNotThrow();
result->addAttribute(llvm::AttributeSet::FunctionIndex,
llvm::Attribute::ReadOnly);
IGF.Builder.CreateLifetimeEnd(argsBuffer,
IGF.IGM.getPointerSize() * genericArgs.Values.size());
IGF.setScopedLocalTypeData(theType, LocalTypeDataKind::forTypeMetadata(), result);
return result;
}
bool irgen::hasKnownSwiftMetadata(IRGenModule &IGM, CanType type) {
if (ClassDecl *theClass = type.getClassOrBoundGenericClass()) {
return hasKnownSwiftMetadata(IGM, theClass);
}
if (auto archetype = dyn_cast<ArchetypeType>(type)) {
if (auto superclass = archetype->getSuperclass()) {
return hasKnownSwiftMetadata(IGM, superclass->getCanonicalType());
}
}
// Class existentials, etc.
return false;
}
/// Is the given class known to have Swift-compatible metadata?
bool irgen::hasKnownSwiftMetadata(IRGenModule &IGM, ClassDecl *theClass) {
// For now, the fact that a declaration was not implemented in Swift
// is enough to conclusively force us into a slower path.
// Eventually we might have an attribute here or something based on
// the deployment target.
return hasKnownSwiftImplementation(IGM, theClass);
}
/// Is the given class known to have an implementation in Swift?
bool irgen::hasKnownSwiftImplementation(IRGenModule &IGM, ClassDecl *theClass) {
return !theClass->hasClangNode();
}
/// Is the given method known to be callable by vtable lookup?
bool irgen::hasKnownVTableEntry(IRGenModule &IGM,
AbstractFunctionDecl *theMethod) {
auto theClass = dyn_cast<ClassDecl>(theMethod->getDeclContext());
// Extension methods don't get vtable entries.
if (!theClass) {
return false;
}
return hasKnownSwiftImplementation(IGM, theClass);
}
static bool hasBuiltinTypeMetadata(CanType type) {
// The empty tuple type has a singleton metadata.
if (auto tuple = dyn_cast<TupleType>(type))
return tuple->getNumElements() == 0;
// The builtin types generally don't require metadata, but some of them
// have nodes in the runtime anyway.
if (isa<BuiltinType>(type))
return true;
// SIL box types are artificial, but for the purposes of dynamic layout,
// we use the NativeObject metadata.
if (isa<SILBoxType>(type))
return true;
return false;
}
/// Is it basically trivial to access the given metadata? If so, we don't
/// need a cache variable in its accessor.
static bool isTypeMetadataAccessTrivial(IRGenModule &IGM, CanType type) {
// Value type metadata only requires dynamic initialization on first
// access if it contains a resilient type.
if (isa<StructType>(type) || isa<EnumType>(type)) {
assert(!cast<NominalType>(type)->getDecl()->isGenericContext() &&
"shouldn't be called for a generic type");
return (IGM.getTypeInfoForLowered(type).isFixedSize());
}
if (hasBuiltinTypeMetadata(type)) {
return true;
}
return false;
}
/// Return the standard access strategy for getting a non-dependent
/// type metadata object.
MetadataAccessStrategy
irgen::getTypeMetadataAccessStrategy(IRGenModule &IGM, CanType type,
bool preferDirectAccess) {
assert(!type->hasArchetype());
// Non-generic structs, enums, and classes are special cases.
//
// Note that while protocol types don't have a metadata pattern,
// we still require an accessor since we actually want to get
// the metadata for the existential type.
auto nominal = dyn_cast<NominalType>(type);
if (nominal && !isa<ProtocolType>(nominal)) {
if (nominal->getDecl()->isGenericContext())
return MetadataAccessStrategy::NonUniqueAccessor;
if (preferDirectAccess &&
isTypeMetadataAccessTrivial(IGM, type))
return MetadataAccessStrategy::Direct;
// If the type doesn't guarantee that it has an access function,
// we might have to use a non-unique accessor.
// Everything else requires accessors.
switch (getDeclLinkage(nominal->getDecl())) {
case FormalLinkage::PublicUnique:
return MetadataAccessStrategy::PublicUniqueAccessor;
case FormalLinkage::HiddenUnique:
return MetadataAccessStrategy::HiddenUniqueAccessor;
case FormalLinkage::Private:
return MetadataAccessStrategy::PrivateAccessor;
case FormalLinkage::PublicNonUnique:
case FormalLinkage::HiddenNonUnique:
return MetadataAccessStrategy::NonUniqueAccessor;
}
llvm_unreachable("bad formal linkage");
}
// DynamicSelfType is actually local.
if (type->hasDynamicSelfType())
return MetadataAccessStrategy::Direct;
// Some types have special metadata in the runtime.
if (hasBuiltinTypeMetadata(type))
return MetadataAccessStrategy::Direct;
// Everything else requires a shared accessor function.
return MetadataAccessStrategy::NonUniqueAccessor;
}
/// Emit a string encoding the labels in the given tuple type.
static llvm::Constant *getTupleLabelsString(IRGenModule &IGM,
CanTupleType type) {
bool hasLabels = false;
llvm::SmallString<128> buffer;
for (auto &elt : type->getElements()) {
if (elt.hasName()) {
hasLabels = true;
buffer.append(elt.getName().str());
}
// Each label is space-terminated.
buffer += ' ';
}
// If there are no labels, use a null pointer.
if (!hasLabels) {
return llvm::ConstantPointerNull::get(IGM.Int8PtrTy);
}
// Otherwise, create a new string literal.
// This method implicitly adds a null terminator.
return IGM.getAddrOfGlobalString(buffer);
}
namespace {
/// A visitor class for emitting a reference to a metatype object.
/// This implements a "raw" access, useful for implementing cache
/// functions or for implementing dependent accesses.
///
/// If the access requires runtime initialization, that initialization
/// must be dependency-ordered-before any load that carries a dependency
/// from the resulting metadata pointer.
class EmitTypeMetadataRef
: public CanTypeVisitor<EmitTypeMetadataRef, llvm::Value *> {
private:
IRGenFunction &IGF;
public:
EmitTypeMetadataRef(IRGenFunction &IGF) : IGF(IGF) {}
#define TREAT_AS_OPAQUE(KIND) \
llvm::Value *visit##KIND##Type(KIND##Type *type) { \
return visitOpaqueType(CanType(type)); \
}
TREAT_AS_OPAQUE(BuiltinInteger)
TREAT_AS_OPAQUE(BuiltinFloat)
TREAT_AS_OPAQUE(BuiltinVector)
TREAT_AS_OPAQUE(BuiltinRawPointer)
#undef TREAT_AS_OPAQUE
llvm::Value *emitDirectMetadataRef(CanType type) {
return IGF.IGM.getAddrOfTypeMetadata(type,
/*pattern*/ false);
}
/// The given type should use opaque type info. We assume that
/// the runtime always provides an entry for such a type; right
/// now, that mapping is as one of the power-of-two integer types.
llvm::Value *visitOpaqueType(CanType type) {
auto &opaqueTI = cast<FixedTypeInfo>(IGF.IGM.getTypeInfoForLowered(type));
unsigned numBits = opaqueTI.getFixedSize().getValueInBits();
if (!llvm::isPowerOf2_32(numBits))
numBits = llvm::NextPowerOf2(numBits);
auto intTy = BuiltinIntegerType::get(numBits, IGF.IGM.Context);
return emitDirectMetadataRef(CanType(intTy));
}
llvm::Value *visitBuiltinNativeObjectType(CanBuiltinNativeObjectType type) {
return emitDirectMetadataRef(type);
}
llvm::Value *visitBuiltinBridgeObjectType(CanBuiltinBridgeObjectType type) {
return emitDirectMetadataRef(type);
}
llvm::Value *visitBuiltinUnknownObjectType(CanBuiltinUnknownObjectType type) {
return emitDirectMetadataRef(type);
}
llvm::Value *visitBuiltinUnsafeValueBufferType(
CanBuiltinUnsafeValueBufferType type) {
return emitDirectMetadataRef(type);
}
llvm::Value *visitNominalType(CanNominalType type) {
assert(!type->isExistentialType());
return emitNominalMetadataRef(IGF, type->getDecl(), type);
}
llvm::Value *visitBoundGenericType(CanBoundGenericType type) {
assert(!type->isExistentialType());
return emitNominalMetadataRef(IGF, type->getDecl(), type);
}
llvm::Value *visitTupleType(CanTupleType type) {
if (auto cached = tryGetLocal(type))
return cached;
// I think the sanest thing to do here is drop labels, but maybe
// that's not correct. If so, that's really unfortunate in a
// lot of ways.
// Er, varargs bit? Should that go in?
switch (type->getNumElements()) {
case 0: {// Special case the empty tuple, just use the global descriptor.
llvm::Constant *fullMetadata = IGF.IGM.getEmptyTupleMetadata();
llvm::Constant *indices[] = {
llvm::ConstantInt::get(IGF.IGM.Int32Ty, 0),
llvm::ConstantInt::get(IGF.IGM.Int32Ty, 1)
};
return llvm::ConstantExpr::getInBoundsGetElementPtr(
/*Ty=*/nullptr, fullMetadata, indices);
}
case 1:
// For metadata purposes, we consider a singleton tuple to be
// isomorphic to its element type.
return IGF.emitTypeMetadataRef(type.getElementType(0));
case 2: {
// Find the metadata pointer for this element.
auto elt0Metadata = IGF.emitTypeMetadataRef(type.getElementType(0));
auto elt1Metadata = IGF.emitTypeMetadataRef(type.getElementType(1));
llvm::Value *args[] = {
elt0Metadata, elt1Metadata,
getTupleLabelsString(IGF.IGM, type),
llvm::ConstantPointerNull::get(IGF.IGM.WitnessTablePtrTy) // proposed
};
auto call = IGF.Builder.CreateCall(IGF.IGM.getGetTupleMetadata2Fn(),
args);
call->setDoesNotThrow();
call->setCallingConv(IGF.IGM.RuntimeCC);
return setLocal(CanType(type), call);
}
case 3: {
// Find the metadata pointer for this element.
auto elt0Metadata = IGF.emitTypeMetadataRef(type.getElementType(0));
auto elt1Metadata = IGF.emitTypeMetadataRef(type.getElementType(1));
auto elt2Metadata = IGF.emitTypeMetadataRef(type.getElementType(2));
llvm::Value *args[] = {
elt0Metadata, elt1Metadata, elt2Metadata,
getTupleLabelsString(IGF.IGM, type),
llvm::ConstantPointerNull::get(IGF.IGM.WitnessTablePtrTy) // proposed
};
auto call = IGF.Builder.CreateCall(IGF.IGM.getGetTupleMetadata3Fn(),
args);
call->setDoesNotThrow();
call->setCallingConv(IGF.IGM.RuntimeCC);
return setLocal(CanType(type), call);
}
default:
// TODO: use a caching entrypoint (with all information
// out-of-line) for non-dependent tuples.
llvm::Value *pointerToFirst = nullptr; // appease -Wuninitialized
auto elements = type.getElementTypes();
auto arrayTy = llvm::ArrayType::get(IGF.IGM.TypeMetadataPtrTy,
elements.size());
Address buffer = IGF.createAlloca(arrayTy,IGF.IGM.getPointerAlignment(),
"tuple-elements");
IGF.Builder.CreateLifetimeStart(buffer,
IGF.IGM.getPointerSize() * elements.size());
for (unsigned i = 0, e = elements.size(); i != e; ++i) {
// Find the metadata pointer for this element.
llvm::Value *eltMetadata = IGF.emitTypeMetadataRef(elements[i]);
// GEP to the appropriate element and store.
Address eltPtr = IGF.Builder.CreateStructGEP(buffer, i,
IGF.IGM.getPointerSize());
IGF.Builder.CreateStore(eltMetadata, eltPtr);
// Remember the GEP to the first element.
if (i == 0) pointerToFirst = eltPtr.getAddress();
}
llvm::Value *args[] = {
llvm::ConstantInt::get(IGF.IGM.SizeTy, elements.size()),
pointerToFirst,
getTupleLabelsString(IGF.IGM, type),
llvm::ConstantPointerNull::get(IGF.IGM.WitnessTablePtrTy) // proposed
};
auto call = IGF.Builder.CreateCall(IGF.IGM.getGetTupleMetadataFn(),
args);
call->setDoesNotThrow();
call->setCallingConv(IGF.IGM.RuntimeCC);
IGF.Builder.CreateLifetimeEnd(buffer,
IGF.IGM.getPointerSize() * elements.size());
return setLocal(type, call);
}
}
llvm::Value *visitPolymorphicFunctionType(CanPolymorphicFunctionType type) {
IGF.unimplemented(SourceLoc(),
"metadata ref for polymorphic function type");
return llvm::UndefValue::get(IGF.IGM.TypeMetadataPtrTy);
}
llvm::Value *visitGenericFunctionType(CanGenericFunctionType type) {
IGF.unimplemented(SourceLoc(),
"metadata ref for generic function type");
return llvm::UndefValue::get(IGF.IGM.TypeMetadataPtrTy);
}
llvm::Value *extractAndMarkResultType(CanFunctionType type) {
// If the function type throws, set the lower bit of the return type
// address, so that we can carry this information over to the function
// type metadata.
auto metadata = IGF.emitTypeMetadataRef(type->getResult()->
getCanonicalType());
return metadata;
}
llvm::Value *extractAndMarkInOut(CanType type) {
// If the type is inout, get the metadata for its inner object type
// instead, and then set the lowest bit to help the runtime unique
// the metadata type for this function.
if (auto inoutType = dyn_cast<InOutType>(type)) {
auto metadata = IGF.emitTypeMetadataRef(inoutType.getObjectType());
auto metadataInt = IGF.Builder.CreatePtrToInt(metadata, IGF.IGM.SizeTy);
auto inoutFlag = llvm::ConstantInt::get(IGF.IGM.SizeTy, 1);
auto marked = IGF.Builder.CreateOr(metadataInt, inoutFlag);
return IGF.Builder.CreateIntToPtr(marked, IGF.IGM.Int8PtrTy);
}
auto metadata = IGF.emitTypeMetadataRef(type);
return IGF.Builder.CreateBitCast(metadata, IGF.IGM.Int8PtrTy);
}
llvm::Value *visitFunctionType(CanFunctionType type) {
if (auto metatype = tryGetLocal(type))
return metatype;
auto resultMetadata = extractAndMarkResultType(type);
CanTupleType inputTuple = dyn_cast<TupleType>(type.getInput());
size_t numArguments = 1;
if (inputTuple && !inputTuple->isMaterializable())
numArguments = inputTuple->getNumElements();
// Map the convention to a runtime metadata value.
FunctionMetadataConvention metadataConvention;
switch (type->getRepresentation()) {
case FunctionTypeRepresentation::Swift:
metadataConvention = FunctionMetadataConvention::Swift;
break;
case FunctionTypeRepresentation::Thin:
metadataConvention = FunctionMetadataConvention::Thin;
break;
case FunctionTypeRepresentation::Block:
metadataConvention = FunctionMetadataConvention::Block;
break;
case FunctionTypeRepresentation::CFunctionPointer:
metadataConvention = FunctionMetadataConvention::CFunctionPointer;
break;
}
auto flagsVal = FunctionTypeFlags()
.withNumArguments(numArguments)
.withConvention(metadataConvention)
.withThrows(type->throws());
auto flags = llvm::ConstantInt::get(IGF.IGM.SizeTy,
flagsVal.getIntValue());
switch (numArguments) {
case 1: {
auto arg0 = (inputTuple && !inputTuple->isMaterializable()) ?
extractAndMarkInOut(inputTuple.getElementType(0))
: extractAndMarkInOut(type.getInput());
auto call = IGF.Builder.CreateCall(
IGF.IGM.getGetFunctionMetadata1Fn(),
{flags, arg0, resultMetadata});
call->setDoesNotThrow();
call->setCallingConv(IGF.IGM.RuntimeCC);
return setLocal(CanType(type), call);
}
case 2: {
auto arg0 = extractAndMarkInOut(inputTuple.getElementType(0));
auto arg1 = extractAndMarkInOut(inputTuple.getElementType(1));
auto call = IGF.Builder.CreateCall(
IGF.IGM.getGetFunctionMetadata2Fn(),
{flags, arg0, arg1, resultMetadata});
call->setDoesNotThrow();
call->setCallingConv(IGF.IGM.RuntimeCC);
return setLocal(CanType(type), call);
}
case 3: {
auto arg0 = extractAndMarkInOut(inputTuple.getElementType(0));
auto arg1 = extractAndMarkInOut(inputTuple.getElementType(1));
auto arg2 = extractAndMarkInOut(inputTuple.getElementType(2));
auto call = IGF.Builder.CreateCall(
IGF.IGM.getGetFunctionMetadata3Fn(),
{flags, arg0, arg1, arg2,
resultMetadata});
call->setDoesNotThrow();
call->setCallingConv(IGF.IGM.RuntimeCC);
return setLocal(CanType(type), call);
}
default:
auto arguments = inputTuple.getElementTypes();
auto arrayTy = llvm::ArrayType::get(IGF.IGM.Int8PtrTy,
arguments.size() + 2);
Address buffer = IGF.createAlloca(arrayTy,
IGF.IGM.getPointerAlignment(),
"function-arguments");
IGF.Builder.CreateLifetimeStart(buffer,
IGF.IGM.getPointerSize() * arguments.size());
Address pointerToFirstArg = IGF.Builder.CreateStructGEP(buffer, 0,
Size(0));
Address flagsPtr = IGF.Builder.CreateBitCast(pointerToFirstArg,
IGF.IGM.SizeTy->getPointerTo());
IGF.Builder.CreateStore(flags, flagsPtr);
for (size_t i = 0; i < arguments.size(); ++i) {
auto argMetadata = extractAndMarkInOut(
inputTuple.getElementType(i));
Address argPtr = IGF.Builder.CreateStructGEP(buffer, i + 1,
IGF.IGM.getPointerSize());
IGF.Builder.CreateStore(argMetadata, argPtr);
}
Address resultPtr = IGF.Builder.CreateStructGEP(buffer,
arguments.size() + 1,
IGF.IGM.getPointerSize());
resultPtr = IGF.Builder.CreateBitCast(resultPtr,
IGF.IGM.TypeMetadataPtrTy->getPointerTo());
IGF.Builder.CreateStore(resultMetadata, resultPtr);
auto call = IGF.Builder.CreateCall(IGF.IGM.getGetFunctionMetadataFn(),
pointerToFirstArg.getAddress());
call->setDoesNotThrow();
call->setCallingConv(IGF.IGM.RuntimeCC);
IGF.Builder.CreateLifetimeEnd(buffer,
IGF.IGM.getPointerSize() * arguments.size());
return setLocal(type, call);
}
}
llvm::Value *visitAnyMetatypeType(CanAnyMetatypeType type) {
// FIXME: We shouldn't accept a lowered metatype here, but we need to
// represent Optional<@objc_metatype T.Type> as an AST type for ABI
// reasons.
// assert(!type->hasRepresentation()
// && "should not be asking for a representation-specific metatype "
// "metadata");
if (auto metatype = tryGetLocal(type))
return metatype;
auto instMetadata = IGF.emitTypeMetadataRef(type.getInstanceType());
auto fn = isa<MetatypeType>(type)
? IGF.IGM.getGetMetatypeMetadataFn()
: IGF.IGM.getGetExistentialMetatypeMetadataFn();
auto call = IGF.Builder.CreateCall(fn, instMetadata);
call->setDoesNotThrow();
call->setCallingConv(IGF.IGM.RuntimeCC);
return setLocal(type, call);
}
llvm::Value *visitModuleType(CanModuleType type) {
IGF.unimplemented(SourceLoc(), "metadata ref for module type");
return llvm::UndefValue::get(IGF.IGM.TypeMetadataPtrTy);
}
llvm::Value *visitDynamicSelfType(CanDynamicSelfType type) {
return IGF.getLocalSelfMetadata();
}
llvm::Value *emitExistentialTypeMetadata(CanType type) {
SmallVector<ProtocolDecl*, 2> protocols;
type.getAnyExistentialTypeProtocols(protocols);
// Collect references to the protocol descriptors.
auto descriptorArrayTy
= llvm::ArrayType::get(IGF.IGM.ProtocolDescriptorPtrTy,
protocols.size());
Address descriptorArray = IGF.createAlloca(descriptorArrayTy,
IGF.IGM.getPointerAlignment(),
"protocols");
IGF.Builder.CreateLifetimeStart(descriptorArray,
IGF.IGM.getPointerSize() * protocols.size());
descriptorArray = IGF.Builder.CreateBitCast(descriptorArray,
IGF.IGM.ProtocolDescriptorPtrTy->getPointerTo());
unsigned index = 0;
for (auto *p : protocols) {
llvm::Value *ref = emitProtocolDescriptorRef(IGF, p);
Address slot = IGF.Builder.CreateConstArrayGEP(descriptorArray,
index, IGF.IGM.getPointerSize());
IGF.Builder.CreateStore(ref, slot);
++index;
}
auto call = IGF.Builder.CreateCall(IGF.IGM.getGetExistentialMetadataFn(),
{IGF.IGM.getSize(Size(protocols.size())),
descriptorArray.getAddress()});
call->setDoesNotThrow();
call->setCallingConv(IGF.IGM.RuntimeCC);
IGF.Builder.CreateLifetimeEnd(descriptorArray,
IGF.IGM.getPointerSize() * protocols.size());
return setLocal(type, call);
}
llvm::Value *visitProtocolType(CanProtocolType type) {
return emitExistentialTypeMetadata(type);
}
llvm::Value *visitProtocolCompositionType(CanProtocolCompositionType type) {
return emitExistentialTypeMetadata(type);
}
llvm::Value *visitReferenceStorageType(CanReferenceStorageType type) {
llvm_unreachable("reference storage type should have been converted by "
"SILGen");
}
llvm::Value *visitSILFunctionType(CanSILFunctionType type) {
llvm_unreachable("should not be asking for metadata of a lowered SIL "
"function type--SILGen should have used the AST type");
}
llvm::Value *visitArchetypeType(CanArchetypeType type) {
return IGF.getLocalTypeData(type, LocalTypeDataKind::forTypeMetadata());
}
llvm::Value *visitGenericTypeParamType(CanGenericTypeParamType type) {
llvm_unreachable("dependent type should have been substituted by Sema or SILGen");
}
llvm::Value *visitDependentMemberType(CanDependentMemberType type) {
llvm_unreachable("dependent type should have been substituted by Sema or SILGen");
}
llvm::Value *visitLValueType(CanLValueType type) {
llvm_unreachable("lvalue type should have been lowered by SILGen");
}
llvm::Value *visitInOutType(CanInOutType type) {
llvm_unreachable("inout type should have been lowered by SILGen");
}
llvm::Value *visitSILBlockStorageType(CanSILBlockStorageType type) {
llvm_unreachable("cannot ask for metadata of block storage");
}
llvm::Value *visitSILBoxType(CanSILBoxType type) {
// The Builtin.NativeObject metadata can stand in for boxes.
return emitDirectMetadataRef(type->getASTContext().TheNativeObjectType);
}
/// Try to find the metatype in local data.
llvm::Value *tryGetLocal(CanType type) {
return IGF.tryGetLocalTypeData(type, LocalTypeDataKind::forTypeMetadata());
}
/// Set the metatype in local data.
llvm::Value *setLocal(CanType type, llvm::Instruction *metatype) {
IGF.setScopedLocalTypeData(type, LocalTypeDataKind::forTypeMetadata(),
metatype);
return metatype;
}
};
}
/// Emit a type metadata reference without using an accessor function.
static llvm::Value *emitDirectTypeMetadataRef(IRGenFunction &IGF,
CanType type) {
return EmitTypeMetadataRef(IGF).visit(type);
}
static Address emitAddressOfSuperclassRefInClassMetadata(IRGenFunction &IGF,
llvm::Value *metadata) {
// The superclass field in a class type is the first field past the isa.
unsigned index = 1;
Address addr(metadata, IGF.IGM.getPointerAlignment());
addr = IGF.Builder.CreateBitCast(addr,
IGF.IGM.TypeMetadataPtrTy->getPointerTo());
return IGF.Builder.CreateConstArrayGEP(addr, index, IGF.IGM.getPointerSize());
}
/// Emit the body of a lazy cache accessor.
///
/// If cacheVariable is null, we perform the direct access every time.
/// This is used for metadata accessors that come about due to resilience,
/// where the direct access is completely trivial.
void irgen::emitLazyCacheAccessFunction(IRGenModule &IGM,
llvm::Function *accessor,
llvm::GlobalVariable *cacheVariable,
const llvm::function_ref<llvm::Value*(IRGenFunction &IGF)> &getValue) {
accessor->setDoesNotThrow();
// This function is logically 'readnone': the caller does not need
// to reason about any side effects or stores it might perform.
accessor->setDoesNotAccessMemory();
IRGenFunction IGF(IGM, accessor);
if (IGM.DebugInfo)
IGM.DebugInfo->emitArtificialFunction(IGF, IGF.CurFn);
if (IGM.DebugInfo)
IGM.DebugInfo->emitArtificialFunction(IGF, accessor);
// If there's no cache variable, just perform the direct access.
if (cacheVariable == nullptr) {
IGF.Builder.CreateRet(getValue(IGF));
return;
}
// Set up the cache variable.
llvm::Constant *null =
llvm::ConstantPointerNull::get(
cast<llvm::PointerType>(cacheVariable->getValueType()));
cacheVariable->setInitializer(null);
cacheVariable->setAlignment(IGM.getPointerAlignment().getValue());
Address cache(cacheVariable, IGM.getPointerAlignment());
// Okay, first thing, check the cache variable.
//
// Conceptually, this needs to establish memory ordering with the
// store we do later in the function: if the metadata value is
// non-null, we must be able to see any stores performed by the
// initialization of the metadata. However, any attempt to read
// from the metadata will be address-dependent on the loaded
// metadata pointer, which is sufficient to provide adequate
// memory ordering guarantees on all the platforms we care about:
// ARM has special rules about address dependencies, and x86's
// memory ordering is strong enough to guarantee the visibility
// even without the address dependency.
//
// And we do not need to worry about the compiler because the
// address dependency naturally forces an order to the memory
// accesses.
//
// Therefore, we can perform a completely naked load here.
// FIXME: Technically should be "consume", but that introduces barriers in the
// current LLVM ARM backend.
auto load = IGF.Builder.CreateLoad(cache);
// Compare the load result against null.
auto isNullBB = IGF.createBasicBlock("cacheIsNull");
auto contBB = IGF.createBasicBlock("cont");
llvm::Value *comparison = IGF.Builder.CreateICmpEQ(load, null);
IGF.Builder.CreateCondBr(comparison, isNullBB, contBB);
auto loadBB = IGF.Builder.GetInsertBlock();
// If the load yielded null, emit the type metadata.
IGF.Builder.emitBlock(isNullBB);
llvm::Value *directResult = getValue(IGF);
// Store it back to the cache variable. The direct metadata lookup is
// required to have already dependency-ordered any initialization
// it triggered before loads from the pointer it returned.
IGF.Builder.CreateStore(directResult, cache);
IGF.Builder.CreateBr(contBB);
auto storeBB = IGF.Builder.GetInsertBlock();
// Emit the continuation block.
IGF.Builder.emitBlock(contBB);
auto phi = IGF.Builder.CreatePHI(null->getType(), 2);
phi->addIncoming(load, loadBB);
phi->addIncoming(directResult, storeBB);
IGF.Builder.CreateRet(phi);
}
/// Get or create an accessor function to the given non-dependent type.
static llvm::Function *getTypeMetadataAccessFunction(IRGenModule &IGM,
CanType type,
ForDefinition_t shouldDefine) {
assert(!type->hasArchetype());
llvm::Function *accessor =
IGM.getAddrOfTypeMetadataAccessFunction(type, shouldDefine);
// If we're not supposed to define the accessor, or if we already
// have defined it, just return the pointer.
if (!shouldDefine || !accessor->empty())
return accessor;
// Okay, define the accessor.
llvm::GlobalVariable *cacheVariable = nullptr;
// If our preferred access method is to go via an accessor, it means
// there is some non-trivial computation that needs to be cached.
if (!isTypeMetadataAccessTrivial(IGM, type)) {
cacheVariable = cast<llvm::GlobalVariable>(
IGM.getAddrOfTypeMetadataLazyCacheVariable(type, ForDefinition));
}
emitLazyCacheAccessFunction(IGM, accessor, cacheVariable,
[&](IRGenFunction &IGF) -> llvm::Value* {
return emitDirectTypeMetadataRef(IGF, type);
});
return accessor;
}
/// Force a public metadata access function into existence if necessary
/// for the given type.
static void maybeEmitTypeMetadataAccessFunction(IRGenModule &IGM,
NominalTypeDecl *theDecl) {
// Currently, we always emit type metadata access functions for
// the non-generic types we define.
if (theDecl->isGenericContext()) return;
CanType declaredType = theDecl->getDeclaredType()->getCanonicalType();
(void) getTypeMetadataAccessFunction(IGM, declaredType, ForDefinition);
}
/// Emit a call to the type metadata accessor for the given function.
static llvm::Value *emitCallToTypeMetadataAccessFunction(IRGenFunction &IGF,
CanType type,
ForDefinition_t shouldDefine) {
// If we already cached the metadata, use it.
if (auto local =
IGF.tryGetLocalTypeData(type, LocalTypeDataKind::forTypeMetadata()))
return local;
llvm::Constant *accessor =
getTypeMetadataAccessFunction(IGF.IGM, type, shouldDefine);
llvm::CallInst *call = IGF.Builder.CreateCall(accessor, {});
call->setCallingConv(IGF.IGM.RuntimeCC);
call->setDoesNotAccessMemory();
call->setDoesNotThrow();
// Save the metadata for future lookups.
IGF.setScopedLocalTypeData(type, LocalTypeDataKind::forTypeMetadata(), call);
return call;
}
/// Produce the type metadata pointer for the given type.
llvm::Value *IRGenFunction::emitTypeMetadataRef(CanType type) {
if (!type->hasArchetype()) {
switch (getTypeMetadataAccessStrategy(IGM, type,
/*preferDirectAccess=*/true)) {
case MetadataAccessStrategy::Direct:
return emitDirectTypeMetadataRef(*this, type);
case MetadataAccessStrategy::PublicUniqueAccessor:
case MetadataAccessStrategy::HiddenUniqueAccessor:
case MetadataAccessStrategy::PrivateAccessor:
return emitCallToTypeMetadataAccessFunction(*this, type, NotForDefinition);
case MetadataAccessStrategy::NonUniqueAccessor:
return emitCallToTypeMetadataAccessFunction(*this, type, ForDefinition);
}
llvm_unreachable("bad type metadata access strategy");
}
return emitDirectTypeMetadataRef(*this, type);
}
/// Return the address of a function that will return type metadata
/// for the given non-dependent type.
llvm::Function *irgen::getOrCreateTypeMetadataAccessFunction(IRGenModule &IGM,
CanType type) {
assert(!type->hasArchetype() &&
"cannot create global function to return dependent type metadata");
switch (getTypeMetadataAccessStrategy(IGM, type,
/*preferDirectAccess=*/false)) {
case MetadataAccessStrategy::PublicUniqueAccessor:
case MetadataAccessStrategy::HiddenUniqueAccessor:
case MetadataAccessStrategy::PrivateAccessor:
return getTypeMetadataAccessFunction(IGM, type, NotForDefinition);
case MetadataAccessStrategy::Direct:
case MetadataAccessStrategy::NonUniqueAccessor:
return getTypeMetadataAccessFunction(IGM, type, ForDefinition);
}
llvm_unreachable("bad type metadata access strategy");
}
namespace {
/// A visitor class for emitting a reference to a metatype object.
/// This implements a "raw" access, useful for implementing cache
/// functions or for implementing dependent accesses.
class EmitTypeMetadataRefForLayout
: public CanTypeVisitor<EmitTypeMetadataRefForLayout, llvm::Value *> {
private:
IRGenFunction &IGF;
public:
EmitTypeMetadataRefForLayout(IRGenFunction &IGF) : IGF(IGF) {}
llvm::Value *emitDirectMetadataRef(CanType type) {
return IGF.IGM.getAddrOfTypeMetadata(type, /*pattern*/ false);
}
/// For most types, we can just emit the usual metadata.
llvm::Value *visitType(CanType t) {
return IGF.emitTypeMetadataRef(t);
}
llvm::Value *visitTupleType(CanTupleType type) {
if (auto cached = tryGetLocal(type))
return cached;
switch (type->getNumElements()) {
case 0: {// Special case the empty tuple, just use the global descriptor.
llvm::Constant *fullMetadata = IGF.IGM.getEmptyTupleMetadata();
llvm::Constant *indices[] = {
llvm::ConstantInt::get(IGF.IGM.Int32Ty, 0),
llvm::ConstantInt::get(IGF.IGM.Int32Ty, 1)
};
return llvm::ConstantExpr::getInBoundsGetElementPtr(
/*Ty=*/nullptr, fullMetadata, indices);
}
case 1:
// For layout purposes, we consider a singleton tuple to be
// isomorphic to its element type.
return visit(type.getElementType(0));
case 2: {
// Find the layout metadata pointers for these elements.
auto elt0Metadata = visit(type.getElementType(0));
auto elt1Metadata = visit(type.getElementType(1));
llvm::Value *args[] = {
elt0Metadata, elt1Metadata,
// labels don't matter for layout
llvm::ConstantPointerNull::get(IGF.IGM.Int8PtrTy),
llvm::ConstantPointerNull::get(IGF.IGM.WitnessTablePtrTy) // proposed
};
auto call = IGF.Builder.CreateCall(IGF.IGM.getGetTupleMetadata2Fn(),
args);
call->setDoesNotThrow();
call->setCallingConv(IGF.IGM.RuntimeCC);
return setLocal(CanType(type), call);
}
case 3: {
// Find the layout metadata pointers for these elements.
auto elt0Metadata = visit(type.getElementType(0));
auto elt1Metadata = visit(type.getElementType(1));
auto elt2Metadata = visit(type.getElementType(2));
llvm::Value *args[] = {
elt0Metadata, elt1Metadata, elt2Metadata,
// labels don't matter for layout
llvm::ConstantPointerNull::get(IGF.IGM.Int8PtrTy),
llvm::ConstantPointerNull::get(IGF.IGM.WitnessTablePtrTy) // proposed
};
auto call = IGF.Builder.CreateCall(IGF.IGM.getGetTupleMetadata3Fn(),
args);
call->setDoesNotThrow();
call->setCallingConv(IGF.IGM.RuntimeCC);
return setLocal(CanType(type), call);
}
default:
// TODO: use a caching entrypoint (with all information
// out-of-line) for non-dependent tuples.
llvm::Value *pointerToFirst = nullptr; // appease -Wuninitialized
auto elements = type.getElementTypes();
auto arrayTy = llvm::ArrayType::get(IGF.IGM.TypeMetadataPtrTy,
elements.size());
Address buffer = IGF.createAlloca(arrayTy,IGF.IGM.getPointerAlignment(),
"tuple-elements");
IGF.Builder.CreateLifetimeStart(buffer,
IGF.IGM.getPointerSize() * elements.size());
for (unsigned i = 0, e = elements.size(); i != e; ++i) {
// Find the metadata pointer for this element.
llvm::Value *eltMetadata = visit(elements[i]);
// GEP to the appropriate element and store.
Address eltPtr = IGF.Builder.CreateStructGEP(buffer, i,
IGF.IGM.getPointerSize());
IGF.Builder.CreateStore(eltMetadata, eltPtr);
// Remember the GEP to the first element.
if (i == 0) pointerToFirst = eltPtr.getAddress();
}
llvm::Value *args[] = {
llvm::ConstantInt::get(IGF.IGM.SizeTy, elements.size()),
pointerToFirst,
// labels don't matter for layout
llvm::ConstantPointerNull::get(IGF.IGM.Int8PtrTy),
llvm::ConstantPointerNull::get(IGF.IGM.WitnessTablePtrTy) // proposed
};
auto call = IGF.Builder.CreateCall(IGF.IGM.getGetTupleMetadataFn(),
args);
call->setDoesNotThrow();
call->setCallingConv(IGF.IGM.RuntimeCC);
IGF.Builder.CreateLifetimeEnd(buffer,
IGF.IGM.getPointerSize() * elements.size());
return setLocal(type, call);
}
}
llvm::Value *visitAnyFunctionType(CanAnyFunctionType type) {
llvm_unreachable("not a SIL type");
}
llvm::Value *visitSILFunctionType(CanSILFunctionType type) {
// All function types have the same layout regardless of arguments or
// abstraction level. Use the metadata for () -> () for thick functions,
// or Builtin.UnknownObject for block functions.
auto &C = type->getASTContext();
switch (type->getRepresentation()) {
case SILFunctionType::Representation::Thin:
case SILFunctionType::Representation::Method:
case SILFunctionType::Representation::WitnessMethod:
case SILFunctionType::Representation::ObjCMethod:
case SILFunctionType::Representation::CFunctionPointer:
// A thin function looks like a plain pointer.
// FIXME: Except for extra inhabitants?
return emitDirectMetadataRef(C.TheRawPointerType);
case SILFunctionType::Representation::Thick:
// All function types look like () -> ().
// FIXME: It'd be nice not to have to call through the runtime here.
return IGF.emitTypeMetadataRef(CanFunctionType::get(C.TheEmptyTupleType,
C.TheEmptyTupleType));
case SILFunctionType::Representation::Block:
// All block types look like Builtin.UnknownObject.
return emitDirectMetadataRef(C.TheUnknownObjectType);
}
}
llvm::Value *visitAnyMetatypeType(CanAnyMetatypeType type) {
assert(type->hasRepresentation()
&& "not a lowered metatype");
switch (type->getRepresentation()) {
case MetatypeRepresentation::Thin: {
// Thin metatypes are empty, so they look like the empty tuple type.
llvm::Constant *fullMetadata = IGF.IGM.getEmptyTupleMetadata();
llvm::Constant *indices[] = {
llvm::ConstantInt::get(IGF.IGM.Int32Ty, 0),
llvm::ConstantInt::get(IGF.IGM.Int32Ty, 1)
};
return llvm::ConstantExpr::getInBoundsGetElementPtr(
/*Ty=*/nullptr, fullMetadata, indices);
}
case MetatypeRepresentation::Thick:
case MetatypeRepresentation::ObjC:
// Thick and ObjC metatypes look like pointers with extra inhabitants.
// Get the metatype metadata from the runtime.
// FIXME: It'd be nice not to need a runtime call here.
return IGF.emitTypeMetadataRef(type);
}
}
/// Try to find the metatype in local data.
llvm::Value *tryGetLocal(CanType type) {
return IGF.tryGetLocalTypeDataForLayout(
SILType::getPrimitiveObjectType(type),
LocalTypeDataKind::forTypeMetadata());
}
/// Set the metatype in local data.
llvm::Value *setLocal(CanType type, llvm::Instruction *metatype) {
IGF.setScopedLocalTypeDataForLayout(SILType::getPrimitiveObjectType(type),
LocalTypeDataKind::forTypeMetadata(),
metatype);
return metatype;
}
};
}
llvm::Value *IRGenFunction::emitTypeMetadataRefForLayout(SILType type) {
return EmitTypeMetadataRefForLayout(*this).visit(type.getSwiftRValueType());
}
namespace {
/// A visitor class for emitting a reference to a type layout struct.
/// There are a few ways we can emit it:
///
/// - If the type is fixed-layout and we have visibility of its value
/// witness table (or one close enough), we can project the layout struct
/// from it.
/// - If the type is fixed layout, we can emit our own copy of the layout
/// struct.
/// - If the type is dynamic-layout, we have to instantiate its metadata
/// and project out its metadata. (FIXME: This leads to deadlocks in
/// recursive cases, though we can avoid many deadlocks because most
/// valid recursive types bottom out in fixed-sized types like classes
/// or pointers.)
class EmitTypeLayoutRef
: public CanTypeVisitor<EmitTypeLayoutRef, llvm::Value *> {
private:
IRGenFunction &IGF;
public:
EmitTypeLayoutRef(IRGenFunction &IGF) : IGF(IGF) {}
llvm::Value *emitFromValueWitnessTablePointer(llvm::Value *vwtable) {
llvm::Value *indexConstant = llvm::ConstantInt::get(IGF.IGM.Int32Ty,
(unsigned)ValueWitness::First_TypeLayoutWitness);
return IGF.Builder.CreateInBoundsGEP(IGF.IGM.Int8PtrTy, vwtable,
indexConstant);
}
/// Emit the type layout by projecting it from a value witness table to
/// which we have linkage.
llvm::Value *emitFromValueWitnessTable(CanType t) {
auto *vwtable = IGF.IGM.getAddrOfValueWitnessTable(t);
return emitFromValueWitnessTablePointer(vwtable);
}
/// Emit the type layout by projecting it from dynamic type metadata.
llvm::Value *emitFromTypeMetadata(CanType t) {
auto *vwtable = IGF.emitValueWitnessTableRefForLayout(
SILType::getPrimitiveObjectType(t));
return emitFromValueWitnessTablePointer(vwtable);
}
bool hasVisibleValueWitnessTable(CanType t) const {
// Some builtin and structural types have value witnesses exported from
// the runtime.
auto &C = IGF.IGM.Context;
if (t == C.TheEmptyTupleType
|| t == C.TheNativeObjectType
|| t == C.TheUnknownObjectType
|| t == C.TheBridgeObjectType)
return true;
if (auto intTy = dyn_cast<BuiltinIntegerType>(t)) {
auto width = intTy->getWidth();
if (width.isPointerWidth())
return true;
if (width.isFixedWidth()) {
switch (width.getFixedWidth()) {
case 8:
case 16:
case 32:
case 64:
case 128:
case 256:
return true;
default:
return false;
}
}
return false;
}
// TODO: If a nominal type is in the same source file as we're currently
// emitting, we would be able to see its value witness table.
return false;
}
/// Fallback default implementation.
llvm::Value *visitType(CanType t) {
auto silTy = SILType::getPrimitiveObjectType(t);
auto &ti = IGF.getTypeInfo(silTy);
// If the type is in the same source file, or has a common value
// witness table exported from the runtime, we can project from the
// value witness table instead of emitting a new record.
if (hasVisibleValueWitnessTable(t))
return emitFromValueWitnessTable(t);
// If the type is a singleton aggregate, the field's layout is equivalent
// to the aggregate's.
if (SILType singletonFieldTy = getSingletonAggregateFieldType(IGF.IGM,
silTy, ResilienceExpansion::Maximal))
return visit(singletonFieldTy.getSwiftRValueType());
// If the type is fixed-layout, emit a copy of its layout.
if (auto fixed = dyn_cast<FixedTypeInfo>(&ti)) {
return IGF.IGM.emitFixedTypeLayout(t, *fixed);
}
return emitFromTypeMetadata(t);
}
llvm::Value *visitAnyFunctionType(CanAnyFunctionType type) {
llvm_unreachable("not a SIL type");
}
llvm::Value *visitSILFunctionType(CanSILFunctionType type) {
// All function types have the same layout regardless of arguments or
// abstraction level. Use the value witness table for
// @convention(blah) () -> () from the runtime.
auto &C = type->getASTContext();
switch (type->getRepresentation()) {
case SILFunctionType::Representation::Thin:
case SILFunctionType::Representation::Method:
case SILFunctionType::Representation::WitnessMethod:
case SILFunctionType::Representation::ObjCMethod:
case SILFunctionType::Representation::CFunctionPointer:
// A thin function looks like a plain pointer.
// FIXME: Except for extra inhabitants?
return emitFromValueWitnessTable(C.TheRawPointerType);
case SILFunctionType::Representation::Thick:
// All function types look like () -> ().
return emitFromValueWitnessTable(
CanFunctionType::get(C.TheEmptyTupleType, C.TheEmptyTupleType));
case SILFunctionType::Representation::Block:
// All block types look like Builtin.UnknownObject.
return emitFromValueWitnessTable(C.TheUnknownObjectType);
}
}
llvm::Value *visitAnyMetatypeType(CanAnyMetatypeType type) {
assert(type->hasRepresentation()
&& "not a lowered metatype");
switch (type->getRepresentation()) {
case MetatypeRepresentation::Thin: {
// Thin metatypes are empty, so they look like the empty tuple type.
return emitFromValueWitnessTable(IGF.IGM.Context.TheEmptyTupleType);
}
case MetatypeRepresentation::Thick:
case MetatypeRepresentation::ObjC:
// Thick metatypes look like pointers with spare bits.
return emitFromValueWitnessTable(
CanMetatypeType::get(IGF.IGM.Context.TheNativeObjectType));
}
}
llvm::Value *visitAnyClassType(ClassDecl *classDecl) {
// All class types have the same layout.
switch (getReferenceCountingForClass(IGF.IGM, classDecl)) {
case ReferenceCounting::Native:
return emitFromValueWitnessTable(IGF.IGM.Context.TheNativeObjectType);
case ReferenceCounting::ObjC:
case ReferenceCounting::Block:
case ReferenceCounting::Unknown:
return emitFromValueWitnessTable(IGF.IGM.Context.TheUnknownObjectType);
case ReferenceCounting::Bridge:
case ReferenceCounting::Error:
llvm_unreachable("classes shouldn't have this kind of refcounting");
}
}
llvm::Value *visitClassType(CanClassType type) {
return visitAnyClassType(type->getClassOrBoundGenericClass());
}
llvm::Value *visitBoundGenericClassType(CanBoundGenericClassType type) {
return visitAnyClassType(type->getClassOrBoundGenericClass());
}
llvm::Value *visitReferenceStorageType(CanReferenceStorageType type) {
// Other reference storage types all have the same layout for their
// storage qualification and the reference counting of their underlying
// object.
auto &C = IGF.IGM.Context;
CanType referent;
switch (type->getOwnership()) {
case Ownership::Strong:
llvm_unreachable("shouldn't be a ReferenceStorageType");
case Ownership::Weak:
referent = type.getReferentType().getAnyOptionalObjectType();
break;
case Ownership::Unmanaged:
case Ownership::Unowned:
referent = type.getReferentType();
break;
}
// Reference storage types with witness tables need open-coded layouts.
// TODO: Maybe we could provide prefabs for 1 witness table.
SmallVector<ProtocolDecl*, 2> protocols;
if (referent.isAnyExistentialType(protocols))
for (auto *proto : protocols)
if (IGF.IGM.SILMod->Types.protocolRequiresWitnessTable(proto))
return visitType(type);
// Unmanaged references are plain pointers with extra inhabitants,
// which look like thick metatypes.
if (type->getOwnership() == Ownership::Unmanaged) {
auto metatype = CanMetatypeType::get(C.TheNativeObjectType);
return emitFromValueWitnessTable(metatype);
}
auto getReferenceCountingForReferent
= [&](CanType referent) -> ReferenceCounting {
// If Objective-C interop is enabled, generic types might contain
// Objective-C references, so we have to use unknown reference
// counting.
if (isa<ArchetypeType>(referent) ||
referent->isExistentialType())
return (IGF.IGM.ObjCInterop ?
ReferenceCounting::Unknown :
ReferenceCounting::Native);
if (auto classDecl = referent->getClassOrBoundGenericClass())
return getReferenceCountingForClass(IGF.IGM, classDecl);
llvm_unreachable("unexpected referent for ref storage type");
};
CanType valueWitnessReferent;
switch (getReferenceCountingForReferent(referent)) {
case ReferenceCounting::Unknown:
case ReferenceCounting::Block:
case ReferenceCounting::ObjC:
valueWitnessReferent = C.TheUnknownObjectType;
break;
case ReferenceCounting::Native:
valueWitnessReferent = C.TheNativeObjectType;
break;
case ReferenceCounting::Bridge:
valueWitnessReferent = C.TheBridgeObjectType;
break;
case ReferenceCounting::Error:
llvm_unreachable("shouldn't be possible");
}
// Get the reference storage type of the builtin object whose value
// witness we can borrow.
if (type->getOwnership() == Ownership::Weak)
valueWitnessReferent = OptionalType::get(valueWitnessReferent)
->getCanonicalType();
auto valueWitnessType = CanReferenceStorageType::get(valueWitnessReferent,
type->getOwnership());
return emitFromValueWitnessTable(valueWitnessType);
}
};
} // end anonymous namespace
llvm::Value *IRGenFunction::emitTypeLayoutRef(SILType type) {
return EmitTypeLayoutRef(*this).visit(type.getSwiftRValueType());
}
/// Produce the heap metadata pointer for the given class type. For
/// Swift-defined types, this is equivalent to the metatype for the
/// class, but for Objective-C-defined types, this is the class
/// object.
llvm::Value *irgen::emitClassHeapMetadataRef(IRGenFunction &IGF, CanType type,
MetadataValueType desiredType,
bool allowUninitialized) {
assert(type->mayHaveSuperclass());
// Archetypes may or may not be ObjC classes and need unwrapping to get at
// the class object.
if (auto archetype = dyn_cast<ArchetypeType>(type)) {
// Look up the Swift metadata from context.
llvm::Value *archetypeMeta = IGF.emitTypeMetadataRef(type);
// Get the class pointer.
auto classPtr = emitClassHeapMetadataRefForMetatype(IGF, archetypeMeta,
archetype);
if (desiredType == MetadataValueType::ObjCClass)
classPtr = IGF.Builder.CreateBitCast(classPtr, IGF.IGM.ObjCClassPtrTy);
return classPtr;
}
// ObjC-defined classes will always be top-level non-generic classes.
if (auto classType = dyn_cast<ClassType>(type)) {
auto theClass = classType->getDecl();
if (!hasKnownSwiftMetadata(IGF.IGM, theClass)) {
llvm::Value *result =
emitObjCHeapMetadataRef(IGF, theClass, allowUninitialized);
if (desiredType == MetadataValueType::TypeMetadata)
result = IGF.Builder.CreateBitCast(result, IGF.IGM.TypeMetadataPtrTy);
return result;
}
} else {
auto genericType = cast<BoundGenericClassType>(type);
assert(hasKnownSwiftMetadata(IGF.IGM, genericType->getDecl()));
(void) genericType;
}
llvm::Value *result = IGF.emitTypeMetadataRef(type);
if (desiredType == MetadataValueType::ObjCClass)
result = IGF.Builder.CreateBitCast(result, IGF.IGM.ObjCClassPtrTy);
return result;
}
namespace {
/// A CRTP type visitor for deciding whether the metatype for a type
/// has trivial representation.
struct HasTrivialMetatype : CanTypeVisitor<HasTrivialMetatype, bool> {
/// Class metatypes have non-trivial representation due to the
/// possibility of subclassing.
bool visitClassType(CanClassType type) {
return false;
}
bool visitBoundGenericClassType(CanBoundGenericClassType type) {
return false;
}
/// Archetype metatypes have non-trivial representation in case
/// they instantiate to a class metatype.
bool visitArchetypeType(CanArchetypeType type) {
return false;
}
/// All levels of class metatypes support subtyping.
bool visitMetatypeType(CanMetatypeType type) {
return visit(type.getInstanceType());
}
/// Everything else is trivial.
bool visitType(CanType type) {
return false;
}
};
}
/// Emit a metatype value for a known type.
void irgen::emitMetatypeRef(IRGenFunction &IGF, CanMetatypeType type,
Explosion &explosion) {
switch (type->getRepresentation()) {
case MetatypeRepresentation::Thin:
// Thin types have a trivial representation.
break;
case MetatypeRepresentation::Thick:
explosion.add(IGF.emitTypeMetadataRef(type.getInstanceType()));
break;
case MetatypeRepresentation::ObjC:
explosion.add(emitClassHeapMetadataRef(IGF, type.getInstanceType(),
MetadataValueType::ObjCClass));
break;
}
}
/*****************************************************************************/
/** Nominal Type Descriptor Emission *****************************************/
/*****************************************************************************/
namespace {
class ConstantBuilderBase {
protected:
IRGenModule &IGM;
ConstantBuilderBase(IRGenModule &IGM) : IGM(IGM) {}
};
template <class Base = ConstantBuilderBase>
class ConstantBuilder : public Base {
protected:
template <class... T>
ConstantBuilder(T &&...args) : Base(std::forward<T>(args)...) {}
IRGenModule &IGM = Base::IGM;
private:
llvm::SmallVector<llvm::Constant*, 16> Fields;
Size NextOffset = Size(0);
protected:
Size getNextOffset() const { return NextOffset; }
/// Add a uintptr_t value that represents the given offset, but
/// scaled to a number of words.
void addConstantWordInWords(Size value) {
addConstantWord(getOffsetInWords(IGM, value));
}
/// Add a constant word-sized value.
void addConstantWord(int64_t value) {
addWord(llvm::ConstantInt::get(IGM.SizeTy, value));
}
/// Add a word-sized value.
void addWord(llvm::Constant *value) {
assert(value->getType() == IGM.IntPtrTy ||
value->getType()->isPointerTy());
assert(NextOffset.isMultipleOf(IGM.getPointerSize()));
Fields.push_back(value);
NextOffset += IGM.getPointerSize();
}
/// Add a uint32_t value that represents the given offset, but
/// scaled to a number of words.
void addConstantInt32InWords(Size value) {
addConstantInt32(getOffsetInWords(IGM, value));
}
/// Add a constant 32-bit value.
void addConstantInt32(int32_t value) {
addInt32(llvm::ConstantInt::get(IGM.Int32Ty, value));
}
/// Add a 32-bit value.
void addInt32(llvm::Constant *value) {
assert(value->getType() == IGM.Int32Ty);
assert(NextOffset.isMultipleOf(Size(4)));
Fields.push_back(value);
NextOffset += Size(4);
}
/// Add a constant 16-bit value.
void addConstantInt16(int16_t value) {
addInt16(llvm::ConstantInt::get(IGM.Int16Ty, value));
}
/// Add a 16-bit value.
void addInt16(llvm::Constant *value) {
assert(value->getType() == IGM.Int16Ty);
assert(NextOffset.isMultipleOf(Size(2)));
Fields.push_back(value);
NextOffset += Size(2);
}
/// Add a constant of the given size.
void addStruct(llvm::Constant *value, Size size) {
assert(size.getValue()
== IGM.DataLayout.getTypeStoreSize(value->getType()));
assert(NextOffset.isMultipleOf(
Size(IGM.DataLayout.getABITypeAlignment(value->getType()))));
Fields.push_back(value);
NextOffset += size;
}
class ReservationToken {
size_t Index;
ReservationToken(size_t index) : Index(index) {}
friend ConstantBuilder<Base>;
};
ReservationToken reserveFields(unsigned numFields, Size size) {
unsigned index = Fields.size();
Fields.append(numFields, nullptr);
NextOffset += size;
return ReservationToken(index);
}
MutableArrayRef<llvm::Constant*> claimReservation(ReservationToken token,
unsigned numFields) {
return MutableArrayRef<llvm::Constant*>(&Fields[0] + token.Index,
numFields);
}
public:
llvm::Constant *getInit() const {
return llvm::ConstantStruct::getAnon(Fields);
}
/// An optimization of getInit for when we have a known type we
/// can use when there aren't any extra fields.
llvm::Constant *getInitWithSuggestedType(unsigned numFields,
llvm::StructType *type) {
if (Fields.size() == numFields) {
return llvm::ConstantStruct::get(type, Fields);
} else {
return getInit();
}
}
};
template<class Impl>
class NominalTypeDescriptorBuilderBase : public ConstantBuilder<> {
Impl &asImpl() { return *static_cast<Impl*>(this); }
public:
NominalTypeDescriptorBuilderBase(IRGenModule &IGM) : ConstantBuilder(IGM) {}
void layout() {
asImpl().addKind();
asImpl().addName();
asImpl().addKindDependentFields();
asImpl().addGenericMetadataPattern();
asImpl().addGenericParams();
}
void addKind() {
addConstantWord(asImpl().getKind());
}
void addName() {
NominalTypeDecl *ntd = asImpl().getTarget();
addWord(getMangledTypeName(IGM,
ntd->getDeclaredType()->getCanonicalType()));
}
void addGenericMetadataPattern() {
NominalTypeDecl *ntd = asImpl().getTarget();
if (!hasMetadataPattern(IGM, ntd)) {
// If there are no generic parameters, there's no pattern to link.
addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPatternPtrTy));
return;
}
addWord(IGM.getAddrOfTypeMetadata(ntd->getDeclaredType()
->getCanonicalType(),
/*pattern*/ true));
}
void addGenericParams() {
NominalTypeDecl *ntd = asImpl().getTarget();
if (!ntd->getGenericParams()) {
// If there are no generic parameters, there is no generic parameter
// vector.
addConstantInt32(0);
addConstantInt32(0);
addConstantInt32(0);
return;
}
// uint32_t GenericParameterVectorOffset;
addConstantInt32InWords(asImpl().getGenericParamsOffset());
// The archetype order here needs to be consistent with
// MetadataLayout::addGenericFields.
// Note that we intentionally don't forward the generic arguments.
// Add all the primary archetypes.
// TODO: only the *primary* archetypes.
// TODO: not archetypes from outer contexts.
auto allArchetypes = ntd->getGenericParams()->getAllArchetypes();
// uint32_t NumGenericParameters;
addConstantInt32(allArchetypes.size());
// uint32_t NumPrimaryGenericParameters;
addConstantInt32(ntd->getGenericParams()->getPrimaryArchetypes().size());
// GenericParameter Parameters[NumGenericParameters];
// struct GenericParameter {
for (auto archetype : allArchetypes) {
// uint32_t NumWitnessTables;
// Count the protocol conformances that require witness tables.
unsigned count = std::count_if(
archetype->getConformsTo().begin(),
archetype->getConformsTo().end(),
Lowering::TypeConverter::protocolRequiresWitnessTable);
addConstantInt32(count);
}
// };
}
llvm::Constant *emit() {
asImpl().layout();
auto init = getInit();
auto var = cast<llvm::GlobalVariable>(
IGM.getAddrOfNominalTypeDescriptor(asImpl().getTarget(),
init->getType()));
var->setConstant(true);
var->setInitializer(init);
return var;
}
// Derived class must provide:
// NominalTypeDecl *getTarget();
// unsigned getKind();
// unsigned getGenericParamsOffset();
// void addKindDependentFields();
};
/// A CRTP helper for classes which are simply searching for a
/// specific index within the metadata.
///
/// The pattern is that subclasses should override an 'add' method
/// from the appropriate layout class and ensure that they call
/// setTargetOffset() when the appropriate location is reached. The
/// subclass user then just calls getTargetOffset(), which performs
/// the layout and returns the found index.
///
/// \tparam Base the base class, which should generally be a CRTP
/// class template applied to the most-derived class
template <class Base> class MetadataSearcher : public Base {
Size TargetOffset = Size::invalid();
Size AddressPoint = Size::invalid();
protected:
void setTargetOffset() {
assert(TargetOffset.isInvalid() && "setting twice");
TargetOffset = this->NextOffset;
}
public:
template <class... T> MetadataSearcher(T &&...args)
: Base(std::forward<T>(args)...) {}
void noteAddressPoint() { AddressPoint = this->NextOffset; }
Size getTargetOffset() {
assert(TargetOffset.isInvalid() && "computing twice");
this->layout();
assert(!TargetOffset.isInvalid() && "target not found!");
assert(!AddressPoint.isInvalid() && "address point not set");
return TargetOffset - AddressPoint;
}
Size::int_type getTargetIndex() {
return getOffsetInWords(this->IGM, getTargetOffset());
}
};
// A bunch of ugly macros to make it easy to declare certain
// common kinds of searcher.
#define BEGIN_METADATA_SEARCHER_0(SEARCHER, DECLKIND) \
struct SEARCHER \
: MetadataSearcher<DECLKIND##MetadataScanner<SEARCHER>> { \
using super = MetadataSearcher; \
SEARCHER(IRGenModule &IGM, DECLKIND##Decl *target) \
: super(IGM, target) {}
#define BEGIN_METADATA_SEARCHER_1(SEARCHER, DECLKIND, TYPE_1, NAME_1) \
struct SEARCHER \
: MetadataSearcher<DECLKIND##MetadataScanner<SEARCHER>> { \
using super = MetadataSearcher; \
TYPE_1 NAME_1; \
SEARCHER(IRGenModule &IGM, DECLKIND##Decl *target, TYPE_1 NAME_1) \
: super(IGM, target), NAME_1(NAME_1) {}
#define BEGIN_METADATA_SEARCHER_2(SEARCHER, DECLKIND, TYPE_1, NAME_1, \
TYPE_2, NAME_2) \
struct SEARCHER \
: MetadataSearcher<DECLKIND##MetadataScanner<SEARCHER>> { \
using super = MetadataSearcher; \
TYPE_1 NAME_1; \
TYPE_2 NAME_2; \
SEARCHER(IRGenModule &IGM, DECLKIND##Decl *target, TYPE_1 NAME_1, \
TYPE_2 NAME_2) \
: super(IGM, target), NAME_1(NAME_1), NAME_2(NAME_2) {}
#define END_METADATA_SEARCHER() \
};
#define BEGIN_GENERIC_METADATA_SEARCHER_0(SEARCHER) \
template <template <class Impl> class Scanner> \
struct SEARCHER : MetadataSearcher<Scanner<SEARCHER<Scanner>>> { \
using super = MetadataSearcher<Scanner<SEARCHER<Scanner>>>; \
using super::Target; \
using TargetType = decltype(Target); \
SEARCHER(IRGenModule &IGM, TargetType target) \
: super(IGM, target) {}
#define BEGIN_GENERIC_METADATA_SEARCHER_1(SEARCHER, TYPE_1, NAME_1) \
template <template <class Impl> class Scanner> \
struct SEARCHER : MetadataSearcher<Scanner<SEARCHER<Scanner>>> { \
using super = MetadataSearcher<Scanner<SEARCHER<Scanner>>>; \
using super::Target; \
using TargetType = decltype(Target); \
TYPE_1 NAME_1; \
SEARCHER(IRGenModule &IGM, TargetType target, TYPE_1 NAME_1) \
: super(IGM, target), NAME_1(NAME_1) {}
#define BEGIN_GENERIC_METADATA_SEARCHER_2(SEARCHER, TYPE_1, NAME_1, \
TYPE_2, NAME_2) \
template <template <class Impl> class Scanner> \
struct SEARCHER : MetadataSearcher<Scanner<SEARCHER<Scanner>>> { \
using super = MetadataSearcher<Scanner<SEARCHER<Scanner>>>; \
using super::Target; \
using TargetType = decltype(Target); \
TYPE_1 NAME_1; \
TYPE_2 NAME_2; \
SEARCHER(IRGenModule &IGM, TargetType target, \
TYPE_1 NAME_1, TYPE_2 NAME_2) \
: super(IGM, target), NAME_1(NAME_1), NAME_2(NAME_2) {}
#define END_GENERIC_METADATA_SEARCHER(SOUGHT) \
}; \
using FindClass##SOUGHT = FindType##SOUGHT<ClassMetadataScanner>; \
using FindStruct##SOUGHT = FindType##SOUGHT<StructMetadataScanner>; \
using FindEnum##SOUGHT = FindType##SOUGHT<EnumMetadataScanner>;
/// The total size and address point of a metadata object.
struct MetadataSize {
Size FullSize;
Size AddressPoint;
/// Return the offset from the address point to the end of the
/// metadata object.
Size getOffsetToEnd() const {
return FullSize - AddressPoint;
}
};
/// A template for computing the size of a metadata record.
template <template <class T> class Scanner>
class MetadataSizer : public Scanner<MetadataSizer<Scanner>> {
typedef Scanner<MetadataSizer<Scanner>> super;
using super::Target;
using TargetType = decltype(Target);
Size AddressPoint = Size::invalid();
public:
MetadataSizer(IRGenModule &IGM, TargetType target)
: super(IGM, target) {}
void noteAddressPoint() {
AddressPoint = super::NextOffset;
super::noteAddressPoint();
}
static MetadataSize compute(IRGenModule &IGM, TargetType target) {
MetadataSizer sizer(IGM, target);
sizer.layout();
assert(!sizer.AddressPoint.isInvalid()
&& "did not find address point?!");
assert(sizer.AddressPoint < sizer.NextOffset
&& "address point is after end?!");
return { sizer.NextOffset, sizer.AddressPoint };
}
};
static MetadataSize getSizeOfMetadata(IRGenModule &IGM, StructDecl *decl) {
return MetadataSizer<StructMetadataScanner>::compute(IGM, decl);
}
static MetadataSize getSizeOfMetadata(IRGenModule &IGM, ClassDecl *decl) {
return MetadataSizer<ClassMetadataScanner>::compute(IGM, decl);
}
static MetadataSize getSizeOfMetadata(IRGenModule &IGM, EnumDecl *decl) {
return MetadataSizer<EnumMetadataScanner>::compute(IGM, decl);
}
/// Return the total size and address point of a metadata record.
static MetadataSize getSizeOfMetadata(IRGenModule &IGM,
NominalTypeDecl *decl) {
if (auto theStruct = dyn_cast<StructDecl>(decl)) {
return getSizeOfMetadata(IGM, theStruct);
} else if (auto theClass = dyn_cast<ClassDecl>(decl)) {
return getSizeOfMetadata(IGM, theClass);
} else if (auto theEnum = dyn_cast<EnumDecl>(decl)) {
return getSizeOfMetadata(IGM, theEnum);
} else {
llvm_unreachable("not implemented for other nominal types");
}
}
/// Build a doubly-null-terminated list of field names.
template<typename ValueDeclRange>
unsigned getFieldNameString(const ValueDeclRange &fields,
llvm::SmallVectorImpl<char> &out) {
unsigned numFields = 0;
{
llvm::raw_svector_ostream os(out);
for (ValueDecl *prop : fields) {
os << prop->getName().str() << '\0';
++numFields;
}
// The final null terminator is provided by getAddrOfGlobalString.
}
return numFields;
}
/// Build the field type vector accessor for a nominal type. This is a
/// function that lazily instantiates the type metadata for all of the
/// types of the stored properties of an instance of a nominal type.
static llvm::Function *
getFieldTypeAccessorFn(IRGenModule &IGM,
NominalTypeDecl *type,
ArrayRef<FieldTypeInfo> fieldTypes) {
// The accessor function has the following signature:
// const Metadata * const *(*GetFieldTypes)(const Metadata *T);
auto metadataArrayPtrTy = IGM.TypeMetadataPtrTy->getPointerTo();
auto fnTy = llvm::FunctionType::get(metadataArrayPtrTy,
IGM.TypeMetadataPtrTy,
/*vararg*/ false);
auto fn = llvm::Function::Create(fnTy, llvm::GlobalValue::PrivateLinkage,
llvm::Twine("get_field_types_")
+ type->getName().str(),
IGM.getModule());
fn->setAttributes(IGM.constructInitialAttributes());
// Emit the body of the field type accessor later. We need to access
// the type metadata for the fields, which could lead to infinite recursion
// in recursive types if we build the field type accessor during metadata
// generation.
IGM.addLazyFieldTypeAccessor(type, fieldTypes, fn);
return fn;
}
/// Build a field type accessor for stored properties.
static llvm::Function *
getFieldTypeAccessorFn(IRGenModule &IGM,
NominalTypeDecl *type,
NominalTypeDecl::StoredPropertyRange storedProperties){
SmallVector<FieldTypeInfo, 4> types;
for (VarDecl *prop : storedProperties) {
types.push_back(FieldTypeInfo(prop->getType()->getCanonicalType(),
/*indirect*/ false));
}
return getFieldTypeAccessorFn(IGM, type, types);
}
/// Build a case type accessor for enum payloads.
static llvm::Function *
getFieldTypeAccessorFn(IRGenModule &IGM,
NominalTypeDecl *type,
ArrayRef<EnumImplStrategy::Element> enumElements) {
SmallVector<FieldTypeInfo, 4> types;
for (auto &elt : enumElements) {
assert(elt.decl->hasArgumentType() && "enum case doesn't have arg?!");
auto caseType = elt.decl->getArgumentType()->getCanonicalType();
bool isIndirect = elt.decl->isIndirect()
|| elt.decl->getParentEnum()->isIndirect();
types.push_back(FieldTypeInfo(caseType, isIndirect));
}
return getFieldTypeAccessorFn(IGM, type, types);
}
class StructNominalTypeDescriptorBuilder
: public NominalTypeDescriptorBuilderBase<StructNominalTypeDescriptorBuilder>
{
using super
= NominalTypeDescriptorBuilderBase<StructNominalTypeDescriptorBuilder>;
// Offsets of key fields in the metadata records.
Size FieldVectorOffset, GenericParamsOffset;
StructDecl *Target;
public:
StructNominalTypeDescriptorBuilder(IRGenModule &IGM,
StructDecl *s)
: super(IGM), Target(s)
{
struct ScanForDescriptorOffsets
: StructMetadataScanner<ScanForDescriptorOffsets>
{
ScanForDescriptorOffsets(IRGenModule &IGM, StructDecl *Target)
: StructMetadataScanner(IGM, Target) {}
Size AddressPoint = Size::invalid();
Size FieldVectorOffset = Size::invalid();
Size GenericParamsOffset = Size::invalid();
void noteAddressPoint() { AddressPoint = NextOffset; }
void noteStartOfFieldOffsets() { FieldVectorOffset = NextOffset; }
void addGenericFields(const GenericParamList &g) {
GenericParamsOffset = NextOffset;
StructMetadataScanner::addGenericFields(g);
}
};
ScanForDescriptorOffsets scanner(IGM, Target);
scanner.layout();
assert(!scanner.AddressPoint.isInvalid()
&& !scanner.FieldVectorOffset.isInvalid()
&& "did not find required fields in struct metadata?!");
assert(scanner.FieldVectorOffset >= scanner.AddressPoint
&& "found field offset vector after address point?!");
assert(scanner.GenericParamsOffset >= scanner.AddressPoint
&& "found generic param vector after address point?!");
FieldVectorOffset = scanner.FieldVectorOffset - scanner.AddressPoint;
GenericParamsOffset = scanner.GenericParamsOffset.isInvalid()
? Size(0) : scanner.GenericParamsOffset - scanner.AddressPoint;
}
StructDecl *getTarget() { return Target; }
unsigned getKind() {
return unsigned(NominalTypeKind::Struct);
}
Size getGenericParamsOffset() {
return GenericParamsOffset;
}
void addKindDependentFields() {
// Build the field name list.
llvm::SmallString<64> fieldNames;
unsigned numFields = getFieldNameString(Target->getStoredProperties(),
fieldNames);
addConstantInt32(numFields);
addConstantInt32InWords(FieldVectorOffset);
addWord(IGM.getAddrOfGlobalString(fieldNames));
// Build the field type accessor function.
llvm::Function *fieldTypeVectorAccessor
= getFieldTypeAccessorFn(IGM, Target,
Target->getStoredProperties());
addWord(fieldTypeVectorAccessor);
}
};
class ClassNominalTypeDescriptorBuilder
: public NominalTypeDescriptorBuilderBase<ClassNominalTypeDescriptorBuilder>
{
using super
= NominalTypeDescriptorBuilderBase<ClassNominalTypeDescriptorBuilder>;
// Offsets of key fields in the metadata records.
Size FieldVectorOffset, GenericParamsOffset;
ClassDecl *Target;
public:
ClassNominalTypeDescriptorBuilder(IRGenModule &IGM,
ClassDecl *c)
: super(IGM), Target(c)
{
// Scan the metadata layout for the class to find the key offsets to
// put in our descriptor.
struct ScanForDescriptorOffsets
: ClassMetadataScanner<ScanForDescriptorOffsets>
{
ScanForDescriptorOffsets(IRGenModule &IGM, ClassDecl *Target)
: ClassMetadataScanner(IGM, Target) {}
Size AddressPoint = Size::invalid();
Size FieldVectorOffset = Size::invalid();
Size GenericParamsOffset = Size::invalid();
void noteAddressPoint() { AddressPoint = NextOffset; }
void noteStartOfFieldOffsets(ClassDecl *c) {
if (c == Target) {
FieldVectorOffset = NextOffset;
}
}
void addGenericFields(const GenericParamList &g, ClassDecl *c) {
if (c == Target) {
GenericParamsOffset = NextOffset;
}
ClassMetadataScanner::addGenericFields(g, c);
}
};
ScanForDescriptorOffsets scanner(IGM, Target);
scanner.layout();
assert(!scanner.AddressPoint.isInvalid()
&& !scanner.FieldVectorOffset.isInvalid()
&& "did not find required fields in struct metadata?!");
assert(scanner.FieldVectorOffset >= scanner.AddressPoint
&& "found field offset vector after address point?!");
assert(scanner.GenericParamsOffset >= scanner.AddressPoint
&& "found generic param vector after address point?!");
FieldVectorOffset = scanner.FieldVectorOffset - scanner.AddressPoint;
GenericParamsOffset = scanner.GenericParamsOffset - scanner.AddressPoint;
}
ClassDecl *getTarget() { return Target; }
unsigned getKind() {
return unsigned(NominalTypeKind::Class);
}
Size getGenericParamsOffset() {
return GenericParamsOffset;
}
void addKindDependentFields() {
// Build the field name list.
llvm::SmallString<64> fieldNames;
unsigned numFields = getFieldNameString(Target->getStoredProperties(),
fieldNames);
addConstantInt32(numFields);
addConstantInt32InWords(FieldVectorOffset);
addWord(IGM.getAddrOfGlobalString(fieldNames));
// Build the field type accessor function.
llvm::Function *fieldTypeVectorAccessor
= getFieldTypeAccessorFn(IGM, Target,
Target->getStoredProperties());
addWord(fieldTypeVectorAccessor);
}
};
class EnumNominalTypeDescriptorBuilder
: public NominalTypeDescriptorBuilderBase<EnumNominalTypeDescriptorBuilder>
{
using super
= NominalTypeDescriptorBuilderBase<EnumNominalTypeDescriptorBuilder>;
// Offsets of key fields in the metadata records.
Size GenericParamsOffset;
Size PayloadSizeOffset;
EnumDecl *Target;
public:
EnumNominalTypeDescriptorBuilder(IRGenModule &IGM, EnumDecl *c)
: super(IGM), Target(c)
{
// Scan the metadata layout for the class to find the key offsets to
// put in our descriptor.
struct ScanForDescriptorOffsets
: EnumMetadataScanner<ScanForDescriptorOffsets>
{
ScanForDescriptorOffsets(IRGenModule &IGM, EnumDecl *Target)
: EnumMetadataScanner(IGM, Target) {}
Size AddressPoint = Size::invalid();
Size GenericParamsOffset = Size::invalid();
Size PayloadSizeOffset = Size::invalid();
void noteAddressPoint() { AddressPoint = NextOffset; }
void addPayloadSize() {
PayloadSizeOffset = NextOffset;
EnumMetadataScanner::addPayloadSize();
}
void addGenericFields(const GenericParamList &g) {
GenericParamsOffset = NextOffset;
EnumMetadataScanner::addGenericFields(g);
}
};
ScanForDescriptorOffsets scanner(IGM, Target);
scanner.layout();
assert(!scanner.AddressPoint.isInvalid()
&& "did not find fields in Enum metadata?!");
assert(scanner.GenericParamsOffset >= scanner.AddressPoint
&& "found generic param vector after address point?!");
GenericParamsOffset = scanner.GenericParamsOffset.isInvalid()
? Size(0) : scanner.GenericParamsOffset - scanner.AddressPoint;
PayloadSizeOffset = scanner.PayloadSizeOffset.isInvalid()
? Size(0) : scanner.PayloadSizeOffset - scanner.AddressPoint;
}
EnumDecl *getTarget() { return Target; }
unsigned getKind() {
return unsigned(NominalTypeKind::Enum);
}
Size getGenericParamsOffset() {
return GenericParamsOffset;
}
void addKindDependentFields() {
auto &strategy = getEnumImplStrategy(IGM,
Target->getDeclaredTypeInContext()->getCanonicalType());
// # payload cases in the low 24 bits, payload size offset in the high 8.
unsigned numPayloads = strategy.getElementsWithPayload().size();
assert(numPayloads < (1<<24) && "too many payload elements for runtime");
assert(PayloadSizeOffset % IGM.getPointerAlignment() == Size(0)
&& "payload size not word-aligned");
unsigned PayloadSizeOffsetInWords
= PayloadSizeOffset / IGM.getPointerSize();
assert(PayloadSizeOffsetInWords < 0x100 &&
"payload size offset too far from address point for runtime");
addConstantInt32(numPayloads | (PayloadSizeOffsetInWords << 24));
// # empty cases
addConstantInt32(strategy.getElementsWithNoPayload().size());
addWord(strategy.emitCaseNames());
// Build the case type accessor.
llvm::Function *caseTypeVectorAccessor
= getFieldTypeAccessorFn(IGM, Target,
strategy.getElementsWithPayload());
addWord(caseTypeVectorAccessor);
}
};
}
void
IRGenModule::addLazyFieldTypeAccessor(NominalTypeDecl *type,
ArrayRef<FieldTypeInfo> fieldTypes,
llvm::Function *fn) {
dispatcher.addLazyFieldTypeAccessor(type, fieldTypes, fn, this);
}
void
irgen::emitFieldTypeAccessor(IRGenModule &IGM,
NominalTypeDecl *type,
llvm::Function *fn,
ArrayRef<FieldTypeInfo> fieldTypes)
{
IRGenFunction IGF(IGM, fn);
auto metadataArrayPtrTy = IGM.TypeMetadataPtrTy->getPointerTo();
CanType formalType = type->getDeclaredTypeInContext()->getCanonicalType();
llvm::Value *metadata = IGF.collectParameters().claimNext();
setTypeMetadataName(IGM, metadata, formalType);
// Get the address at which the field type vector reference should be
// cached.
llvm::Value *vectorPtr;
auto nullVector = llvm::ConstantPointerNull::get(metadataArrayPtrTy);
// If the type is not generic, we can use a global variable to cache the
// address of the field type vector for the single instance.
if (!type->getGenericParamsOfContext()) {
vectorPtr = new llvm::GlobalVariable(*IGM.getModule(),
metadataArrayPtrTy,
/*constant*/ false,
llvm::GlobalValue::PrivateLinkage,
nullVector,
llvm::Twine("field_type_vector_")
+ type->getName().str());
// For a generic type, use a slot we saved in the generic metadata pattern
// immediately after the metadata object itself, which should be
// instantiated with every generic metadata instance.
} else {
Size offset = getSizeOfMetadata(IGM, type).getOffsetToEnd();
vectorPtr = IGF.Builder.CreateBitCast(metadata,
metadataArrayPtrTy->getPointerTo());
vectorPtr = IGF.Builder.CreateConstInBoundsGEP1_32(
/*Ty=*/nullptr, vectorPtr, getOffsetInWords(IGM, offset));
}
// First, see if the field type vector has already been populated. This
// load can be nonatomic; if we race to build the field offset vector, we
// will detect so when we try to commit our pointer and simply discard the
// redundant work.
llvm::Value *initialVector
= IGF.Builder.CreateLoad(vectorPtr, IGM.getPointerAlignment());
auto entryBB = IGF.Builder.GetInsertBlock();
auto buildBB = IGF.createBasicBlock("build_field_types");
auto raceLostBB = IGF.createBasicBlock("race_lost");
auto doneBB = IGF.createBasicBlock("done");
llvm::Value *isNull
= IGF.Builder.CreateICmpEQ(initialVector, nullVector);
IGF.Builder.CreateCondBr(isNull, buildBB, doneBB);
// Build the field type vector if we didn't already.
IGF.Builder.emitBlock(buildBB);
// Bind the metadata instance to our local type data so we
// use it to provide metadata for generic parameters in field types.
IGF.bindLocalTypeDataFromTypeMetadata(formalType, IsExact, metadata);
// Allocate storage for the field vector.
unsigned allocSize = fieldTypes.size() * IGM.getPointerSize().getValue();
auto allocSizeVal = llvm::ConstantInt::get(IGM.IntPtrTy, allocSize);
auto allocAlignMaskVal =
IGM.getSize(IGM.getPointerAlignment().asSize() - Size(1));
llvm::Value *builtVectorAlloc
= IGF.emitAllocRawCall(allocSizeVal, allocAlignMaskVal);
llvm::Value *builtVector
= IGF.Builder.CreateBitCast(builtVectorAlloc, metadataArrayPtrTy);
// Emit type metadata for the fields into the vector.
for (unsigned i : indices(fieldTypes)) {
auto fieldTy = fieldTypes[i].getType();
auto slot = IGF.Builder.CreateInBoundsGEP(builtVector,
llvm::ConstantInt::get(IGM.Int32Ty, i));
// Strip reference storage qualifiers like unowned and weak.
// FIXME: Some clients probably care about them.
if (auto refStorTy = dyn_cast<ReferenceStorageType>(fieldTy))
fieldTy = refStorTy.getReferentType();
auto metadata = IGF.emitTypeMetadataRef(fieldTy);
// Mix in flag bits.
if (fieldTypes[i].isIndirect()) {
auto flags = FieldType().withIndirect(true);
auto metadataBits = IGF.Builder.CreatePtrToInt(metadata, IGF.IGM.SizeTy);
metadataBits = IGF.Builder.CreateOr(metadataBits,
llvm::ConstantInt::get(IGF.IGM.SizeTy, flags.getIntValue()));
metadata = IGF.Builder.CreateIntToPtr(metadataBits, metadata->getType());
}
IGF.Builder.CreateStore(metadata, slot, IGM.getPointerAlignment());
}
// Atomically compare-exchange a pointer to our vector into the slot.
auto vectorIntPtr = IGF.Builder.CreateBitCast(vectorPtr,
IGM.IntPtrTy->getPointerTo());
auto builtVectorInt = IGF.Builder.CreatePtrToInt(builtVector,
IGM.IntPtrTy);
auto zero = llvm::ConstantInt::get(IGM.IntPtrTy, 0);
llvm::Value *raceVectorInt = IGF.Builder.CreateAtomicCmpXchg(vectorIntPtr,
zero, builtVectorInt,
llvm::AtomicOrdering::SequentiallyConsistent,
llvm::AtomicOrdering::SequentiallyConsistent);
// The pointer in the slot should still have been null.
auto didStore = IGF.Builder.CreateExtractValue(raceVectorInt, 1);
raceVectorInt = IGF.Builder.CreateExtractValue(raceVectorInt, 0);
IGF.Builder.CreateCondBr(didStore, doneBB, raceLostBB);
// If the cmpxchg failed, someone beat us to landing their field type
// vector. Deallocate ours and return the winner.
IGF.Builder.emitBlock(raceLostBB);
IGF.emitDeallocRawCall(builtVectorAlloc, allocSizeVal, allocAlignMaskVal);
auto raceVector = IGF.Builder.CreateIntToPtr(raceVectorInt,
metadataArrayPtrTy);
IGF.Builder.CreateBr(doneBB);
// Return the result.
IGF.Builder.emitBlock(doneBB);
auto phi = IGF.Builder.CreatePHI(metadataArrayPtrTy, 3);
phi->addIncoming(initialVector, entryBB);
phi->addIncoming(builtVector, buildBB);
phi->addIncoming(raceVector, raceLostBB);
IGF.Builder.CreateRet(phi);
}
/*****************************************************************************/
/** Metadata Emission ********************************************************/
/*****************************************************************************/
namespace {
/// An adapter class which turns a metadata layout class into a
/// generic metadata layout class.
template <class Impl, class Base>
class GenericMetadataBuilderBase : public Base {
typedef Base super;
/// The number of generic witnesses in the type we're emitting.
/// This is not really something we need to track.
unsigned NumGenericWitnesses = 0;
struct FillOp {
CanArchetypeType Archetype;
ProtocolDecl *Protocol;
Size ToOffset;
};
SmallVector<FillOp, 8> FillOps;
enum { TemplateHeaderFieldCount = 5 };
enum { NumPrivateDataWords = swift::NumGenericMetadataPrivateDataWords };
Size TemplateHeaderSize;
protected:
/// The offset of the address point in the type we're emitting.
Size AddressPoint = Size::invalid();
IRGenModule &IGM = super::IGM;
using super::asImpl;
/// Set to true if the metadata record for the generic type has fields
/// outside of the generic parameter vector.
bool HasDependentMetadata = false;
/// Set to true if the value witness table for the generic type is dependent
/// on its generic parameters. If true, the value witness will be
/// tail-emplaced inside the metadata pattern and initialized by the fill
/// function. Implies HasDependentMetadata.
bool HasDependentVWT = false;
/// The offset of the tail-allocated dependent VWT, if any.
Size DependentVWTPoint = Size::invalid();
template <class... T>
GenericMetadataBuilderBase(IRGenModule &IGM, T &&...args)
: super(IGM, std::forward<T>(args)...) {}
/// Emit the create function for the template.
llvm::Function *emitCreateFunction() {
// Metadata *(*CreateFunction)(GenericMetadata*, const void * const *)
llvm::Type *argTys[] = {IGM.TypeMetadataPatternPtrTy, IGM.Int8PtrPtrTy};
auto ty = llvm::FunctionType::get(IGM.TypeMetadataPtrTy,
argTys, /*isVarArg*/ false);
llvm::Function *f = llvm::Function::Create(ty,
llvm::GlobalValue::PrivateLinkage,
llvm::Twine("create_generic_metadata_")
+ super::Target->getName().str(),
&IGM.Module);
f->setAttributes(IGM.constructInitialAttributes());
IRGenFunction IGF(IGM, f);
if (IGM.DebugInfo)
IGM.DebugInfo->emitArtificialFunction(IGF, f);
Explosion params = IGF.collectParameters();
llvm::Value *metadataPattern = params.claimNext();
llvm::Value *args = params.claimNext();
// Bind the generic arguments.
auto generics = super::Target->getGenericParamsOfContext();
Address argsArray(args, IGM.getPointerAlignment());
if (generics)
emitPolymorphicParametersFromArray(IGF, *generics, argsArray);
// Allocate the metadata.
llvm::Value *metadataValue =
asImpl().emitAllocateMetadata(IGF, metadataPattern, args);
// Execute the fill ops. Cast the parameters to word pointers because the
// fill indexes are word-indexed.
Address metadataWords(IGF.Builder.CreateBitCast(metadataValue, IGM.Int8PtrPtrTy),
IGM.getPointerAlignment());
for (auto &fillOp : FillOps) {
llvm::Value *value;
if (fillOp.Protocol) {
value = emitArchetypeWitnessTableRef(IGF, fillOp.Archetype,
fillOp.Protocol);
} else {
value = IGF.getLocalTypeData(fillOp.Archetype,
LocalTypeDataKind::forTypeMetadata());
}
value = IGF.Builder.CreateBitCast(value, IGM.Int8PtrTy);
auto dest = createPointerSizedGEP(IGF, metadataWords,
fillOp.ToOffset - AddressPoint);
IGF.Builder.CreateStore(value, dest);
}
// Initialize the instantiated dependent value witness table, if we have
// one.
llvm::Value *vwtableValue = nullptr;
if (HasDependentVWT) {
assert(!AddressPoint.isInvalid() && "did not set valid address point!");
assert(!DependentVWTPoint.isInvalid() && "did not set dependent VWT point!");
// Fill in the pointer from the metadata to the VWT. The VWT pointer
// always immediately precedes the address point.
auto vwtAddr = createPointerSizedGEP(IGF, metadataWords,
DependentVWTPoint - AddressPoint);
vwtableValue = IGF.Builder.CreateBitCast(vwtAddr.getAddress(),
IGF.IGM.WitnessTablePtrTy);
auto vwtAddrVal = IGF.Builder.CreateBitCast(vwtableValue, IGM.Int8PtrTy);
auto vwtRefAddr = createPointerSizedGEP(IGF, metadataWords,
Size(0) - IGM.getPointerSize());
IGF.Builder.CreateStore(vwtAddrVal, vwtRefAddr);
HasDependentMetadata = true;
}
if (HasDependentMetadata) {
asImpl().emitInitializeMetadata(IGF, metadataValue, vwtableValue);
}
// The metadata is now complete.
IGF.Builder.CreateRet(metadataValue);
return f;
}
public:
void layout() {
TemplateHeaderSize =
((NumPrivateDataWords + 1) * IGM.getPointerSize()) + Size(8);
// Leave room for the header.
auto header = this->reserveFields(TemplateHeaderFieldCount,
TemplateHeaderSize);
// Lay out the template data.
super::layout();
// Save a slot for the field type vector address to be instantiated into.
asImpl().addFieldTypeVectorReferenceSlot();
// If we have a dependent value witness table, emit its template.
if (HasDependentVWT) {
// Note the dependent VWT offset.
DependentVWTPoint = getNextOffset();
asImpl().addDependentValueWitnessTablePattern();
}
asImpl().addDependentData();
// Fill in the header:
unsigned Field = 0;
auto headerFields =
this->claimReservation(header, TemplateHeaderFieldCount);
// Metadata *(*CreateFunction)(GenericMetadata *, const void*);
headerFields[Field++] = emitCreateFunction();
// uint32_t MetadataSize;
// We compute this assuming that every entry in the metadata table
// is a pointer in size.
Size size = getNextOffset();
headerFields[Field++] =
llvm::ConstantInt::get(IGM.Int32Ty, size.getValue());
// uint16_t NumArguments;
// TODO: ultimately, this should be the number of actual template
// arguments, not the number of witness tables required.
headerFields[Field++]
= llvm::ConstantInt::get(IGM.Int16Ty, NumGenericWitnesses);
// uint16_t AddressPoint;
assert(!AddressPoint.isInvalid() && "address point not noted!");
headerFields[Field++]
= llvm::ConstantInt::get(IGM.Int16Ty, AddressPoint.getValue());
// void *PrivateData[NumPrivateDataWords];
headerFields[Field++] = getPrivateDataInit();
assert(TemplateHeaderFieldCount == Field);
}
/// Write down the index of the address point.
void noteAddressPoint() {
AddressPoint = getNextOffset();
super::noteAddressPoint();
}
/// Ignore the preallocated header.
Size getNextOffset() const {
// Note that the header fields are all pointer-sized.
return super::getNextOffset() - TemplateHeaderSize;
}
template <class... T>
void addGenericArgument(ArchetypeType *type, T &&...args) {
NumGenericWitnesses++;
FillOps.push_back({ CanArchetypeType(type), nullptr, getNextOffset() });
super::addGenericArgument(type, std::forward<T>(args)...);
}
template <class... T>
void addGenericWitnessTable(ArchetypeType *type, ProtocolDecl *protocol,
T &&...args) {
NumGenericWitnesses++;
FillOps.push_back({ CanArchetypeType(type), protocol, getNextOffset() });
super::addGenericWitnessTable(type, protocol, std::forward<T>(args)...);
}
void addFieldTypeVectorReferenceSlot() {
this->addWord(
llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy->getPointerTo()));
}
// Can be overridden by subclassers to emit other dependent metadata.
void addDependentData() {}
private:
static llvm::Constant *makeArray(llvm::Type *eltTy,
ArrayRef<llvm::Constant*> elts) {
auto arrayTy = llvm::ArrayType::get(eltTy, elts.size());
return llvm::ConstantArray::get(arrayTy, elts);
}
/// Produce the initializer for the private-data field of the
/// template header.
llvm::Constant *getPrivateDataInit() {
auto null = llvm::ConstantPointerNull::get(IGM.Int8PtrTy);
llvm::Constant *privateData[NumPrivateDataWords];
for (auto &element : privateData)
element = null;
return makeArray(IGM.Int8PtrTy, privateData);
}
};
}
// Classes
namespace {
/// An adapter for laying out class metadata.
template <class Impl>
class ClassMetadataBuilderBase
: public ConstantBuilder<ClassMetadataLayout<Impl>> {
using super = ConstantBuilder<ClassMetadataLayout<Impl>>;
Optional<MetadataSize> ClassObjectExtents;
protected:
IRGenModule &IGM = super::IGM;
ClassDecl * const& Target = super::Target;
using super::addWord;
using super::addConstantWord;
using super::addInt16;
using super::addConstantInt16;
using super::addInt32;
using super::addConstantInt32;
using super::addStruct;
using super::getNextOffset;
const StructLayout &Layout;
const ClassLayout &FieldLayout;
SILVTable *VTable;
ClassMetadataBuilderBase(IRGenModule &IGM, ClassDecl *theClass,
const StructLayout &layout,
const ClassLayout &fieldLayout)
: super(IGM, theClass), Layout(layout), FieldLayout(fieldLayout) {
VTable = IGM.SILMod->lookUpVTable(Target);
}
void computeClassObjectExtents() {
if (ClassObjectExtents.hasValue()) return;
ClassObjectExtents = getSizeOfMetadata(IGM, Target);
}
bool HasRuntimeParent = false;
public:
/// The 'metadata flags' field in a class is actually a pointer to
/// the metaclass object for the class.
///
/// NONAPPLE: This is only really required for ObjC interop; maybe
/// suppress this for classes that don't need to be exposed to
/// ObjC, e.g. for non-Apple platforms?
void addMetadataFlags() {
static_assert(unsigned(MetadataKind::Class) == 0,
"class metadata kind is non-zero?");
if (IGM.ObjCInterop) {
// Get the metaclass pointer as an intptr_t.
auto metaclass = IGM.getAddrOfMetaclassObject(Target,
NotForDefinition);
auto flags = llvm::ConstantExpr::getPtrToInt(metaclass, IGM.IntPtrTy);
addWord(flags);
} else {
// On non-objc platforms just fill it with a null, there
// is no objective-c metaclass.
// FIXME: Remove this to save metadata space.
// rdar://problem/18801263
addWord(llvm::ConstantExpr::getNullValue(IGM.IntPtrTy));
}
}
/// The runtime provides a value witness table for Builtin.NativeObject.
void addValueWitnessTable() {
ClassDecl *cls = Target;
auto type = (cls->checkObjCAncestry() != ObjCClassKind::NonObjC
? this->IGM.Context.TheUnknownObjectType
: this->IGM.Context.TheNativeObjectType);
auto wtable = this->IGM.getAddrOfValueWitnessTable(type);
addWord(wtable);
}
void addDestructorFunction() {
auto expansion = ResilienceExpansion::Minimal;
auto dtorRef = SILDeclRef(Target->getDestructor(),
SILDeclRef::Kind::Deallocator,
expansion);
SILFunction *dtorFunc = IGM.SILMod->lookUpFunction(dtorRef);
if (dtorFunc) {
addWord(IGM.getAddrOfSILFunction(dtorFunc, NotForDefinition));
} else {
// In case the optimizer removed the function. See comment in
// addMethod().
addWord(llvm::ConstantPointerNull::get(IGM.FunctionPtrTy));
}
}
void addNominalTypeDescriptor() {
addWord(ClassNominalTypeDescriptorBuilder(IGM, Target).emit());
}
void addIVarDestroyer() {
auto dtorFunc = IGM.getAddrOfIVarInitDestroy(Target,
/*isDestroyer=*/ true,
/*isForeign=*/ false,
NotForDefinition);
if (dtorFunc) {
addWord(*dtorFunc);
} else {
addWord(llvm::ConstantPointerNull::get(IGM.FunctionPtrTy));
}
}
void addParentMetadataRef(ClassDecl *forClass) {
// FIXME: this is wrong for multiple levels of generics; we need
// to apply substitutions through.
Type parentType =
forClass->getDeclContext()->getDeclaredTypeInContext();
if (!addReferenceToType(parentType->getCanonicalType()))
HasRuntimeParent = true;
}
bool addReferenceToType(CanType type) {
if (llvm::Constant *metadata
= tryEmitConstantTypeMetadataRef(IGM, type)) {
addWord(metadata);
return true;
} else {
// Leave a null pointer placeholder to be filled at runtime
addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy));
return false;
}
}
void addClassFlags() {
// Always set a flag saying that this is a Swift 1.0 class.
ClassFlags flags = ClassFlags::IsSwift1;
// Set a flag if the class uses Swift 1.0 refcounting.
if (getReferenceCountingForClass(IGM, Target)
== ReferenceCounting::Native) {
flags |= ClassFlags::UsesSwift1Refcounting;
}
addConstantInt32((uint32_t) flags);
}
void addInstanceAddressPoint() {
// Right now, we never allocate fields before the address point.
addConstantInt32(0);
}
void addInstanceSize() {
if (llvm::Constant *size
= tryEmitClassConstantFragileInstanceSize(IGM, Target)) {
// We only support a maximum 32-bit instance size.
if (IGM.SizeTy != IGM.Int32Ty)
size = llvm::ConstantExpr::getTrunc(size, IGM.Int32Ty);
addInt32(size);
} else {
// Leave a zero placeholder to be filled at runtime
addConstantInt32(0);
}
}
void addInstanceAlignMask() {
if (llvm::Constant *align
= tryEmitClassConstantFragileInstanceAlignMask(IGM, Target)) {
if (IGM.SizeTy != IGM.Int16Ty)
align = llvm::ConstantExpr::getTrunc(align, IGM.Int16Ty);
addInt16(align);
} else {
// Leave a zero placeholder to be filled at runtime
addConstantInt16(0);
}
}
void addRuntimeReservedBits() {
addConstantInt16(0);
}
void addClassSize() {
computeClassObjectExtents();
addConstantInt32(ClassObjectExtents->FullSize.getValue());
}
void addClassAddressPoint() {
computeClassObjectExtents();
addConstantInt32(ClassObjectExtents->AddressPoint.getValue());
}
void addClassCacheData() {
// We initially fill in these fields with addresses taken from
// the ObjC runtime.
// FIXME: Remove null data altogether rdar://problem/18801263
addWord(IGM.getObjCEmptyCachePtr());
addWord(IGM.getObjCEmptyVTablePtr());
}
void addClassDataPointer() {
if (!IGM.ObjCInterop) {
// with no objective-c runtime, just give an empty pointer with the
// swift bit set.
addWord(llvm::ConstantInt::get(IGM.IntPtrTy, 1));
return;
}
// Derive the RO-data.
llvm::Constant *data = emitClassPrivateData(IGM, Target);
// We always set the low bit to indicate this is a Swift class.
data = llvm::ConstantExpr::getPtrToInt(data, IGM.IntPtrTy);
data = llvm::ConstantExpr::getAdd(data,
llvm::ConstantInt::get(IGM.IntPtrTy, 1));
addWord(data);
}
void addFieldOffset(VarDecl *var) {
assert(var->hasStorage());
unsigned fieldIndex = FieldLayout.getFieldIndex(var);
llvm::Constant *fieldOffsetOrZero;
auto &element = Layout.getElement(fieldIndex);
if (element.getKind() == ElementLayout::Kind::Fixed) {
// Use a fixed offset if we have one.
fieldOffsetOrZero = IGM.getSize(element.getByteOffset());
} else {
// Otherwise, leave a placeholder for the runtime to populate at runtime.
fieldOffsetOrZero = llvm::ConstantInt::get(IGM.IntPtrTy, 0);
}
addWord(fieldOffsetOrZero);
if (var->getDeclContext() == Target) {
auto access = FieldLayout.AllFieldAccesses[fieldIndex];
switch (access) {
case FieldAccess::ConstantDirect:
case FieldAccess::NonConstantDirect: {
// Emit a global variable storing the constant field offset.
// If the superclass was imported from Objective-C, the offset
// does not include the superclass size; we rely on the
// Objective-C runtime sliding it down.
//
// TODO: Don't emit the symbol if field has a fixed offset and size
// in all resilience domains
auto offsetAddr = IGM.getAddrOfFieldOffset(var, /*indirect*/ false,
ForDefinition);
auto offsetVar = cast<llvm::GlobalVariable>(offsetAddr.getAddress());
offsetVar->setInitializer(fieldOffsetOrZero);
// If we know the offset won't change, make it a constant.
offsetVar->setConstant(access == FieldAccess::ConstantDirect);
break;
}
case FieldAccess::ConstantIndirect:
// No global variable is needed.
break;
case FieldAccess::NonConstantIndirect:
// Emit a global variable storing an offset into the field offset
// vector within the class metadata. This access pattern is used
// when the field offset depends on generic parameters. As above,
// the Objective-C runtime will slide the field offsets within the
// class metadata to adjust for the superclass size.
//
// TODO: This isn't plumbed through all the way yet.
auto offsetAddr = IGM.getAddrOfFieldOffset(var, /*indirect*/ true,
ForDefinition);
auto offsetVar = cast<llvm::GlobalVariable>(offsetAddr.getAddress());
offsetVar->setConstant(false);
auto offset = getClassFieldOffset(IGM, Target, var).getValue();
auto offsetVal = llvm::ConstantInt::get(IGM.IntPtrTy, offset);
offsetVar->setInitializer(offsetVal);
break;
}
}
}
void addMethod(SILDeclRef fn) {
// If this function is associated with the target class, go
// ahead and emit the witness offset variable.
if (fn.getDecl()->getDeclContext() == Target) {
Address offsetVar = IGM.getAddrOfWitnessTableOffset(fn, ForDefinition);
auto global = cast<llvm::GlobalVariable>(offsetVar.getAddress());
auto offset = getNextOffset();
auto offsetV = llvm::ConstantInt::get(IGM.SizeTy, offset.getValue());
global->setInitializer(offsetV);
}
// Find the vtable entry.
assert(VTable && "no vtable?!");
if (SILFunction *func = VTable->getImplementation(*IGM.SILMod, fn)) {
addWord(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.
addWord(llvm::ConstantExpr::getBitCast(IGM.getDeletedMethodErrorFn(),
IGM.FunctionPtrTy));
}
}
void addGenericArgument(ArchetypeType *archetype, ClassDecl *forClass) {
addWord(llvm::Constant::getNullValue(IGM.TypeMetadataPtrTy));
}
void addGenericWitnessTable(ArchetypeType *archetype,
ProtocolDecl *protocol, ClassDecl *forClass) {
addWord(llvm::Constant::getNullValue(IGM.WitnessTablePtrTy));
}
};
class ClassMetadataBuilder :
public ClassMetadataBuilderBase<ClassMetadataBuilder> {
public:
ClassMetadataBuilder(IRGenModule &IGM, ClassDecl *theClass,
const StructLayout &layout,
const ClassLayout &fieldLayout)
: ClassMetadataBuilderBase(IGM, theClass, layout, fieldLayout) {
assert(layout.isFixedLayout() &&
"non-fixed layout classes require a template");
// FIXME: Distinguish Objective-C sliding from resilient layout
assert((fieldLayout.MetadataAccess == FieldAccess::ConstantDirect ||
fieldLayout.MetadataAccess == FieldAccess::NonConstantDirect) &&
"resilient superclasses require a template");
}
llvm::Constant *getInit() {
return getInitWithSuggestedType(NumHeapMetadataFields,
IGM.FullHeapMetadataStructTy);
}
void addSuperClass() {
// If this is a root class, use SwiftObject as our formal parent.
if (!Target->hasSuperclass()) {
// This is only required for ObjC interoperation.
if (!IGM.ObjCInterop) {
addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy));
return;
}
// We have to do getAddrOfObjCClass ourselves here because
// the ObjC runtime base needs to be ObjC-mangled but isn't
// actually imported from a clang module.
addWord(IGM.getAddrOfObjCClass(
IGM.getObjCRuntimeBaseForSwiftRootClass(Target),
NotForDefinition));
return;
}
Type superclassTy
= ArchetypeBuilder::mapTypeIntoContext(Target,
Target->getSuperclass());
bool constantSuperclass =
addReferenceToType(superclassTy->getCanonicalType());
assert(constantSuperclass && "need template if superclass is dependent");
(void) constantSuperclass;
}
};
Address emitAddressOfFieldOffsetVectorInClassMetadata(IRGenFunction &IGF,
ClassDecl *theClass,
llvm::Value *metadata) {
BEGIN_METADATA_SEARCHER_0(GetOffsetToFieldOffsetVector, Class)
void noteStartOfFieldOffsets(ClassDecl *whichClass) {
if (whichClass == Target)
setTargetOffset();
}
END_METADATA_SEARCHER()
auto offset =
GetOffsetToFieldOffsetVector(IGF.IGM, theClass).getTargetOffset();
Address addr(metadata, IGF.IGM.getPointerAlignment());
addr = IGF.Builder.CreateBitCast(addr,
IGF.IGM.SizeTy->getPointerTo());
return createPointerSizedGEP(IGF, addr, offset);
}
/// A builder for metadata templates.
class GenericClassMetadataBuilder :
public GenericMetadataBuilderBase<GenericClassMetadataBuilder,
ClassMetadataBuilderBase<GenericClassMetadataBuilder>>
{
typedef GenericMetadataBuilderBase super;
Size MetaclassPtrOffset = Size::invalid();
Size ClassRODataPtrOffset = Size::invalid();
Size MetaclassRODataPtrOffset = Size::invalid();
Size DependentMetaclassPoint = Size::invalid();
Size DependentClassRODataPoint = Size::invalid();
Size DependentMetaclassRODataPoint = Size::invalid();
public:
GenericClassMetadataBuilder(IRGenModule &IGM, ClassDecl *theClass,
const StructLayout &layout,
const ClassLayout &fieldLayout)
: super(IGM, theClass, layout, fieldLayout)
{
// We need special initialization of metadata objects to trick the ObjC
// runtime into initializing them.
HasDependentMetadata = true;
}
void addSuperClass() {
// Filled in by the runtime.
addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy));
}
llvm::Value *emitAllocateMetadata(IRGenFunction &IGF,
llvm::Value *metadataPattern,
llvm::Value *arguments) {
llvm::Value *superMetadata;
if (Target->hasSuperclass()) {
Type superclass = Target->getSuperclass();
superclass = ArchetypeBuilder::mapTypeIntoContext(Target, superclass);
superMetadata =
emitClassHeapMetadataRef(IGF, superclass->getCanonicalType(),
MetadataValueType::ObjCClass);
} else if (IGM.ObjCInterop) {
superMetadata = emitObjCHeapMetadataRef(IGF,
IGM.getObjCRuntimeBaseForSwiftRootClass(Target));
} else {
superMetadata
= llvm::ConstantPointerNull::get(IGF.IGM.ObjCClassPtrTy);
}
return IGF.Builder.CreateCall(IGM.getAllocateGenericClassMetadataFn(),
{metadataPattern, arguments, superMetadata});
}
void addMetadataFlags() {
// The metaclass pointer will be instantiated here.
MetaclassPtrOffset = getNextOffset();
addWord(llvm::ConstantInt::get(IGM.IntPtrTy, 0));
}
void addClassDataPointer() {
// The rodata pointer will be instantiated here.
// Make sure we at least set the 'is Swift class' bit, though.
ClassRODataPtrOffset = getNextOffset();
addWord(llvm::ConstantInt::get(IGM.IntPtrTy, 1));
}
void addDependentData() {
if (!IGM.ObjCInterop) {
// Every piece of data in the dependent data appears to be related to
// Objective-C information. If we're not doing Objective-C interop, we
// can just skip adding it to the class.
return;
}
// Emit space for the dependent metaclass.
DependentMetaclassPoint = getNextOffset();
// isa
ClassDecl *rootClass = getRootClassForMetaclass(IGM, Target);
auto isa = IGM.getAddrOfMetaclassObject(rootClass, NotForDefinition);
addWord(isa);
// super, which is dependent if the superclass is generic
addWord(llvm::ConstantPointerNull::get(IGM.ObjCClassPtrTy));
// cache
addWord(IGM.getObjCEmptyCachePtr());
// vtable
addWord(IGM.getObjCEmptyVTablePtr());
// rodata, which is always dependent
MetaclassRODataPtrOffset = getNextOffset();
addConstantWord(0);
// Emit the dependent rodata.
llvm::Constant *classData, *metaclassData;
Size rodataSize;
std::tie(classData, metaclassData, rodataSize)
= emitClassPrivateDataFields(IGM, Target);
DependentClassRODataPoint = getNextOffset();
addStruct(classData, rodataSize);
DependentMetaclassRODataPoint = getNextOffset();
addStruct(metaclassData, rodataSize);
}
void addDependentValueWitnessTablePattern() {
llvm_unreachable("classes should never have dependent vwtables");
}
void noteStartOfFieldOffsets(ClassDecl *whichClass) {
HasDependentMetadata = true;
}
void noteEndOfFieldOffsets(ClassDecl *whichClass) {}
// Suppress GenericMetadataBuilderBase's default behavior of introducing
// fill ops for generic arguments unless they belong directly to the target
// class and not its ancestors.
void addGenericArgument(ArchetypeType *type, ClassDecl *forClass) {
if (forClass == Target) {
// Introduce the fill op.
GenericMetadataBuilderBase::addGenericArgument(type, forClass);
} else {
// Lay out the field, but don't fill it in, we will copy it from
// the superclass.
HasDependentMetadata = true;
ClassMetadataBuilderBase::addGenericArgument(type, forClass);
}
}
void addGenericWitnessTable(ArchetypeType *type, ProtocolDecl *protocol,
ClassDecl *forClass) {
if (forClass == Target) {
// Introduce the fill op.
GenericMetadataBuilderBase::addGenericWitnessTable(type, protocol,
forClass);
} else {
// Lay out the field, but don't provide the fill op, which we'll get
// from the superclass.
HasDependentMetadata = true;
ClassMetadataBuilderBase::addGenericWitnessTable(type, protocol,
forClass);
}
}
// The Objective-C runtime will copy field offsets from the field offset
// vector into field offset globals for us, if present. If there's no
// Objective-C runtime, we have to do this ourselves.
void emitInitializeFieldOffsets(IRGenFunction &IGF,
llvm::Value *metadata) {
unsigned index = FieldLayout.InheritedStoredProperties.size();
for (auto prop : Target->getStoredProperties()) {
auto access = FieldLayout.AllFieldAccesses[index];
if (access == FieldAccess::NonConstantDirect) {
Address offsetA = IGF.IGM.getAddrOfFieldOffset(prop,
/*indirect*/ false,
ForDefinition);
// We can't use emitClassFieldOffset() here because that creates
// an invariant load, which could be hoisted above the point
// where the metadata becomes fully initialized
Size offset = getClassFieldOffset(IGF.IGM, Target, prop);
int index = getOffsetInWords(IGF.IGM, offset);
auto offsetVal = emitLoadFromMetadataAtIndex(IGF, metadata, index,
IGF.IGM.SizeTy);
IGF.Builder.CreateStore(offsetVal, offsetA);
}
index++;
}
}
void emitInitializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
llvm::Value *vwtable) {
assert(!HasDependentVWT && "class should never have dependent VWT");
// Fill in the metaclass pointer.
Address metadataPtr(IGF.Builder.CreateBitCast(metadata, IGF.IGM.Int8PtrPtrTy),
IGF.IGM.getPointerAlignment());
llvm::Value *metaclass;
if (IGF.IGM.ObjCInterop) {
assert(!DependentMetaclassPoint.isInvalid());
assert(!MetaclassPtrOffset.isInvalid());
Address metaclassPtrSlot = createPointerSizedGEP(IGF, metadataPtr,
MetaclassPtrOffset - AddressPoint);
metaclassPtrSlot = IGF.Builder.CreateBitCast(metaclassPtrSlot,
IGF.IGM.ObjCClassPtrTy->getPointerTo());
Address metaclassRawPtr = createPointerSizedGEP(IGF, metadataPtr,
DependentMetaclassPoint - AddressPoint);
metaclass = IGF.Builder.CreateBitCast(metaclassRawPtr,
IGF.IGM.ObjCClassPtrTy)
.getAddress();
IGF.Builder.CreateStore(metaclass, metaclassPtrSlot);
} else {
// FIXME: Remove altogether rather than injecting a NULL value.
// rdar://problem/18801263
assert(!MetaclassPtrOffset.isInvalid());
Address metaclassPtrSlot = createPointerSizedGEP(IGF, metadataPtr,
MetaclassPtrOffset - AddressPoint);
metaclassPtrSlot = IGF.Builder.CreateBitCast(metaclassPtrSlot,
IGF.IGM.ObjCClassPtrTy->getPointerTo());
IGF.Builder.CreateStore(
llvm::ConstantPointerNull::get(IGF.IGM.ObjCClassPtrTy),
metaclassPtrSlot);
}
// Fill in the rodata reference in the class.
Address classRODataPtr;
if (IGF.IGM.ObjCInterop) {
assert(!DependentClassRODataPoint.isInvalid());
assert(!ClassRODataPtrOffset.isInvalid());
Address rodataPtrSlot = createPointerSizedGEP(IGF, metadataPtr,
ClassRODataPtrOffset - AddressPoint);
rodataPtrSlot = IGF.Builder.CreateBitCast(rodataPtrSlot,
IGF.IGM.IntPtrTy->getPointerTo());
classRODataPtr = createPointerSizedGEP(IGF, metadataPtr,
DependentClassRODataPoint - AddressPoint);
// Set the low bit of the value to indicate "compiled by Swift".
llvm::Value *rodata = IGF.Builder.CreatePtrToInt(
classRODataPtr.getAddress(), IGF.IGM.IntPtrTy);
rodata = IGF.Builder.CreateOr(rodata, 1);
IGF.Builder.CreateStore(rodata, rodataPtrSlot);
} else {
// NOTE: Unlike other bits of the metadata that should later be removed,
// this one is important because things check this value's flags to
// determine what kind of object it is. That said, if those checks
// are determined to be removable, we can remove this as well per
// rdar://problem/18801263
assert(!ClassRODataPtrOffset.isInvalid());
Address rodataPtrSlot = createPointerSizedGEP(IGF, metadataPtr,
ClassRODataPtrOffset - AddressPoint);
rodataPtrSlot = IGF.Builder.CreateBitCast(rodataPtrSlot,
IGF.IGM.IntPtrTy->getPointerTo());
IGF.Builder.CreateStore(llvm::ConstantInt::get(IGF.IGM.IntPtrTy, 1),
rodataPtrSlot);
}
// Fill in the rodata reference in the metaclass.
Address metaclassRODataPtr;
if (IGF.IGM.ObjCInterop) {
assert(!DependentMetaclassRODataPoint.isInvalid());
assert(!MetaclassRODataPtrOffset.isInvalid());
Address rodataPtrSlot = createPointerSizedGEP(IGF, metadataPtr,
MetaclassRODataPtrOffset - AddressPoint);
rodataPtrSlot = IGF.Builder.CreateBitCast(rodataPtrSlot,
IGF.IGM.IntPtrTy->getPointerTo());
metaclassRODataPtr = createPointerSizedGEP(IGF, metadataPtr,
DependentMetaclassRODataPoint - AddressPoint);
llvm::Value *rodata = IGF.Builder.CreatePtrToInt(
metaclassRODataPtr.getAddress(), IGF.IGM.IntPtrTy);
IGF.Builder.CreateStore(rodata, rodataPtrSlot);
}
// If we have fields that are not fixed-size, ask the runtime to
// populate the offset vector.
//
// FIXME: if only the superclass is resilient, we can get away
// with sliding field offsets instead of doing the entire layout all
// over again.
if (!Layout.isFixedLayout()) {
llvm::Value *fieldVector
= emitAddressOfFieldOffsetVectorInClassMetadata(IGF,
Target, metadata)
.getAddress();
// Collect the stored properties of the type.
llvm::SmallVector<VarDecl*, 4> storedProperties;
for (auto prop : Target->getStoredProperties()) {
storedProperties.push_back(prop);
}
// Fill out an array with the field type metadata records.
Address fields = IGF.createAlloca(
llvm::ArrayType::get(IGF.IGM.SizeTy,
storedProperties.size() * 2),
IGF.IGM.getPointerAlignment(), "classFields");
IGF.Builder.CreateLifetimeStart(fields,
IGF.IGM.getPointerSize() * storedProperties.size() * 2);
Address firstField;
unsigned index = 0;
for (auto prop : storedProperties) {
auto propFormalTy = prop->getType()->getCanonicalType();
SILType propLoweredTy = IGM.SILMod->Types.getLoweredType(propFormalTy);
auto &propTI = IGF.getTypeInfo(propLoweredTy);
auto sizeAndAlignMask
= propTI.getSizeAndAlignmentMask(IGF, propLoweredTy);
llvm::Value *size = sizeAndAlignMask.first;
Address sizeAddr =
IGF.Builder.CreateStructGEP(fields, index, IGF.IGM.getPointerSize());
IGF.Builder.CreateStore(size, sizeAddr);
if (index == 0) firstField = sizeAddr;
llvm::Value *alignMask = sizeAndAlignMask.second;
Address alignMaskAddr =
IGF.Builder.CreateStructGEP(fields, index + 1,
IGF.IGM.getPointerSize());
IGF.Builder.CreateStore(alignMask, alignMaskAddr);
index += 2;
}
if (storedProperties.empty()) {
firstField = IGF.Builder.CreateStructGEP(fields, 0, Size(0));
}
// Ask the runtime to lay out the class.
auto numFields = IGF.IGM.getSize(Size(storedProperties.size()));
IGF.Builder.CreateCall(IGF.IGM.getInitClassMetadataUniversalFn(),
{metadata, numFields,
firstField.getAddress(), fieldVector});
IGF.Builder.CreateLifetimeEnd(fields,
IGF.IGM.getPointerSize() * storedProperties.size() * 2);
} else {
// If we have any ancestor generic parameters or field offset vectors,
// copy them from the superclass metadata.
auto initFn = IGF.IGM.getInitializeSuperclassFn();
bool copyFieldOffsetVectors = false;
if (FieldLayout.MetadataAccess != FieldAccess::ConstantDirect)
copyFieldOffsetVectors = true;
IGF.Builder.CreateCall(initFn,
{metadata,
llvm::ConstantInt::get(IGF.IGM.Int1Ty,
copyFieldOffsetVectors)});
}
if (!IGF.IGM.ObjCInterop)
emitInitializeFieldOffsets(IGF, metadata);
}
};
}
/// Emit the ObjC-compatible class symbol for a class.
/// Since LLVM and many system linkers do not have a notion of relative symbol
/// references, we emit the symbol as a global asm block.
static void emitObjCClassSymbol(IRGenModule &IGM,
ClassDecl *classDecl,
llvm::GlobalValue *metadata) {
llvm::SmallString<32> classSymbol;
LinkEntity::forObjCClass(classDecl).mangle(classSymbol);
// Create the alias.
auto *metadataTy = cast<llvm::PointerType>(metadata->getType());
// Create the alias.
llvm::GlobalAlias::create(metadataTy->getElementType(),
metadataTy->getAddressSpace(),
metadata->getLinkage(), classSymbol.str(),
metadata, IGM.getModule());
}
/// Emit the type metadata or metadata template for a class.
void irgen::emitClassMetadata(IRGenModule &IGM, ClassDecl *classDecl,
const StructLayout &layout,
const ClassLayout &fieldLayout) {
assert(!classDecl->isForeign());
// TODO: classes nested within generic types
llvm::Constant *init;
bool isPattern;
if (hasMetadataPattern(IGM, classDecl)) {
GenericClassMetadataBuilder builder(IGM, classDecl, layout, fieldLayout);
builder.layout();
init = builder.getInit();
isPattern = true;
} else {
ClassMetadataBuilder builder(IGM, classDecl, layout, fieldLayout);
builder.layout();
init = builder.getInit();
isPattern = false;
}
maybeEmitTypeMetadataAccessFunction(IGM, classDecl);
CanType declaredType = classDecl->getDeclaredType()->getCanonicalType();
// For now, all type metadata is directly stored.
bool isIndirect = false;
StringRef section{};
if (classDecl->isObjC())
section = "__DATA,__objc_data, regular";
auto var = IGM.defineTypeMetadata(declaredType, isIndirect, isPattern,
// TODO: the metadata global can actually be constant in a very
// special case: it's not a pattern, ObjC interoperation isn't
// required, there are no class fields, and there is nothing that
// needs to be runtime-adjusted.
/*isConstant*/ false, init, section);
// Add non-generic classes to the ObjC class list.
if (IGM.ObjCInterop && !isPattern && !isIndirect) {
// Emit the ObjC class symbol to make the class visible to ObjC.
if (classDecl->isObjC()) {
emitObjCClassSymbol(IGM, classDecl, var);
}
IGM.addObjCClass(var,
classDecl->getAttrs().hasAttribute<ObjCNonLazyRealizationAttr>());
}
}
void IRGenFunction::setInvariantLoad(llvm::LoadInst *load) {
load->setMetadata(IGM.InvariantMetadataID, IGM.InvariantNode);
}
void IRGenFunction::setDereferenceableLoad(llvm::LoadInst *load,
unsigned size) {
auto sizeConstant = llvm::ConstantInt::get(IGM.Int64Ty, size);
auto sizeNode = llvm::MDNode::get(IGM.LLVMContext,
llvm::ConstantAsMetadata::get(sizeConstant));
load->setMetadata(IGM.DereferenceableID, sizeNode);
}
/// Emit a load from the given metadata at a constant index.
static llvm::LoadInst *emitLoadFromMetadataAtIndex(IRGenFunction &IGF,
llvm::Value *metadata,
int index,
llvm::Type *objectTy,
const llvm::Twine &suffix) {
// Require the metadata to be some type that we recognize as a
// metadata pointer.
assert(metadata->getType() == IGF.IGM.TypeMetadataPtrTy);
// We require objectType to be a pointer type so that the GEP will
// scale by the right amount. We could load an arbitrary type using
// some extra bitcasting.
assert(IGF.IGM.DataLayout.getTypeStoreSize(objectTy) ==
IGF.IGM.DataLayout.getTypeStoreSize(IGF.IGM.SizeTy));
// Cast to T*.
auto objectPtrTy = objectTy->getPointerTo();
auto metadataWords = IGF.Builder.CreateBitCast(metadata, objectPtrTy);
auto indexV = llvm::ConstantInt::getSigned(IGF.IGM.SizeTy, index);
// GEP to the slot.
Address slot(IGF.Builder.CreateInBoundsGEP(metadataWords, indexV),
IGF.IGM.getPointerAlignment());
// Load.
return IGF.Builder.CreateLoad(slot, metadata->getName() + suffix);
}
/// Emit a load from the given metadata at a constant index.
///
/// The load is marked invariant. This function should not be called
/// on metadata objects that are in the process of being initialized.
static llvm::LoadInst *
emitInvariantLoadFromMetadataAtIndex(IRGenFunction &IGF,
llvm::Value *metadata,
int index,
llvm::Type *objectTy,
const Twine &suffix = Twine::createNull()) {
auto result = emitLoadFromMetadataAtIndex(IGF, metadata, index, objectTy,
suffix);
IGF.setInvariantLoad(result);
return result;
}
/// Given an AST type, load its value witness table.
llvm::Value *
IRGenFunction::emitValueWitnessTableRef(CanType type) {
// See if we have a cached projection we can use.
if (auto cached = tryGetLocalTypeData(type,
LocalTypeDataKind::forValueWitnessTable())) {
return cached;
}
auto metadata = emitTypeMetadataRef(type);
auto vwtable = emitValueWitnessTableRefForMetadata(metadata);
setScopedLocalTypeData(type, LocalTypeDataKind::forValueWitnessTable(),
vwtable);
return vwtable;
}
/// Given a type metadata pointer, load its value witness table.
llvm::Value *
IRGenFunction::emitValueWitnessTableRefForMetadata(llvm::Value *metadata) {
auto witness = emitInvariantLoadFromMetadataAtIndex(*this, metadata, -1,
IGM.WitnessTablePtrTy,
".valueWitnesses");
// A value witness table is dereferenceable to the number of value witness
// pointers.
// TODO: If we know the type statically has extra inhabitants, we know
// there are more witnesses.
auto numValueWitnesses
= unsigned(ValueWitness::Last_RequiredValueWitness) + 1;
setDereferenceableLoad(witness,
IGM.getPointerSize().getValue() * numValueWitnesses);
return witness;
}
/// Given a lowered SIL type, load a value witness table that represents its
/// layout.
llvm::Value *
IRGenFunction::emitValueWitnessTableRefForLayout(SILType type) {
// See if we have a cached projection we can use.
if (auto cached = tryGetLocalTypeDataForLayout(type,
LocalTypeDataKind::forValueWitnessTable())) {
return cached;
}
auto metadata = emitTypeMetadataRefForLayout(type);
auto vwtable = emitValueWitnessTableRefForMetadata(metadata);
setScopedLocalTypeDataForLayout(type,
LocalTypeDataKind::forValueWitnessTable(),
vwtable);
return vwtable;
}
/// Load the metadata reference at the given index.
static llvm::Value *emitLoadOfMetadataRefAtIndex(IRGenFunction &IGF,
llvm::Value *metadata,
int index) {
return emitInvariantLoadFromMetadataAtIndex(IGF, metadata, index,
IGF.IGM.TypeMetadataPtrTy);
}
/// Load the protocol witness table reference at the given index.
static llvm::Value *emitLoadOfWitnessTableRefAtIndex(IRGenFunction &IGF,
llvm::Value *metadata,
int index) {
return emitInvariantLoadFromMetadataAtIndex(IGF, metadata, index,
IGF.IGM.WitnessTablePtrTy);
}
namespace {
/// A class for finding the 'parent' index in a class metadata object.
BEGIN_METADATA_SEARCHER_0(FindClassParentIndex, Class)
void addParentMetadataRef(ClassDecl *forClass) {
if (forClass == Target) setTargetOffset();
super::addParentMetadataRef(forClass);
}
END_METADATA_SEARCHER()
}
/// Given a reference to some metadata, derive a reference to the
/// type's parent type.
llvm::Value *irgen::emitParentMetadataRef(IRGenFunction &IGF,
NominalTypeDecl *decl,
llvm::Value *metadata) {
assert(decl->getDeclContext()->isTypeContext());
switch (decl->getKind()) {
#define NOMINAL_TYPE_DECL(id, parent)
#define DECL(id, parent) \
case DeclKind::id:
#include "swift/AST/DeclNodes.def"
llvm_unreachable("not a nominal type");
case DeclKind::Protocol:
llvm_unreachable("protocols never have parent types!");
case DeclKind::Class: {
int index =
FindClassParentIndex(IGF.IGM, cast<ClassDecl>(decl)).getTargetIndex();
return emitLoadOfMetadataRefAtIndex(IGF, metadata, index);
}
case DeclKind::Enum:
case DeclKind::Struct:
// In both of these cases, 'Parent' is always the third field.
return emitLoadOfMetadataRefAtIndex(IGF, metadata, 2);
}
llvm_unreachable("bad decl kind!");
}
namespace {
/// A class for finding a type argument in a type metadata object.
BEGIN_GENERIC_METADATA_SEARCHER_1(FindTypeArgumentIndex,
ArchetypeType *, TargetArchetype)
template <class... T>
void addGenericArgument(ArchetypeType *argument, T &&...args) {
if (argument == TargetArchetype)
this->setTargetOffset();
super::addGenericArgument(argument, std::forward<T>(args)...);
}
END_GENERIC_METADATA_SEARCHER(ArgumentIndex)
}
/// Given a reference to nominal type metadata of the given type,
/// derive a reference to the nth argument metadata. The type must
/// have generic arguments.
llvm::Value *irgen::emitArgumentMetadataRef(IRGenFunction &IGF,
NominalTypeDecl *decl,
unsigned argumentIndex,
llvm::Value *metadata) {
assert(decl->getGenericParams() != nullptr);
auto targetArchetype =
decl->getGenericParams()->getAllArchetypes()[argumentIndex];
switch (decl->getKind()) {
#define NOMINAL_TYPE_DECL(id, parent)
#define DECL(id, parent) \
case DeclKind::id:
#include "swift/AST/DeclNodes.def"
llvm_unreachable("not a nominal type");
case DeclKind::Protocol:
llvm_unreachable("protocols are never generic!");
case DeclKind::Class: {
int index =
FindClassArgumentIndex(IGF.IGM, cast<ClassDecl>(decl), targetArchetype)
.getTargetIndex();
return emitLoadOfMetadataRefAtIndex(IGF, metadata, index);
}
case DeclKind::Struct: {
int index =
FindStructArgumentIndex(IGF.IGM, cast<StructDecl>(decl), targetArchetype)
.getTargetIndex();
return emitLoadOfMetadataRefAtIndex(IGF, metadata, index);
}
case DeclKind::Enum: {
int index =
FindEnumArgumentIndex(IGF.IGM, cast<EnumDecl>(decl), targetArchetype)
.getTargetIndex();
return emitLoadOfMetadataRefAtIndex(IGF, metadata, index);
}
}
llvm_unreachable("bad decl kind!");
}
namespace {
/// A class for finding a protocol witness table for a type argument
/// in a value type metadata object.
BEGIN_GENERIC_METADATA_SEARCHER_2(FindTypeWitnessTableIndex,
ArchetypeType *, TargetArchetype,
ProtocolDecl *, TargetProtocol)
template <class... T>
void addGenericWitnessTable(ArchetypeType *argument,
ProtocolDecl *protocol,
T &&...args) {
if (argument == TargetArchetype && protocol == TargetProtocol)
this->setTargetOffset();
super::addGenericWitnessTable(argument, protocol,
std::forward<T>(args)...);
}
END_GENERIC_METADATA_SEARCHER(WitnessTableIndex)
}
/// Given a reference to nominal type metadata of the given type,
/// derive a reference to a protocol witness table for the nth
/// argument metadata. The type must have generic arguments.
llvm::Value *irgen::emitArgumentWitnessTableRef(IRGenFunction &IGF,
NominalTypeDecl *decl,
unsigned argumentIndex,
ProtocolDecl *targetProtocol,
llvm::Value *metadata) {
assert(decl->getGenericParams() != nullptr);
auto targetArchetype =
decl->getGenericParams()->getAllArchetypes()[argumentIndex];
switch (decl->getKind()) {
#define NOMINAL_TYPE_DECL(id, parent)
#define DECL(id, parent) \
case DeclKind::id:
#include "swift/AST/DeclNodes.def"
llvm_unreachable("not a nominal type");
case DeclKind::Protocol:
llvm_unreachable("protocols are never generic!");
case DeclKind::Class: {
int index =
FindClassWitnessTableIndex(IGF.IGM, cast<ClassDecl>(decl),
targetArchetype, targetProtocol)
.getTargetIndex();
return emitLoadOfWitnessTableRefAtIndex(IGF, metadata, index);
}
case DeclKind::Enum: {
int index =
FindEnumWitnessTableIndex(IGF.IGM, cast<EnumDecl>(decl),
targetArchetype, targetProtocol)
.getTargetIndex();
return emitLoadOfWitnessTableRefAtIndex(IGF, metadata, index);
}
case DeclKind::Struct: {
int index =
FindStructWitnessTableIndex(IGF.IGM, cast<StructDecl>(decl),
targetArchetype, targetProtocol)
.getTargetIndex();
return emitLoadOfWitnessTableRefAtIndex(IGF, metadata, index);
}
}
llvm_unreachable("bad decl kind!");
}
irgen::Size irgen::getClassFieldOffset(IRGenModule &IGM,
ClassDecl *theClass,
VarDecl *field) {
/// A class for finding a field offset in a class metadata object.
BEGIN_METADATA_SEARCHER_1(FindClassFieldOffset, Class,
VarDecl *, TargetField)
void addFieldOffset(VarDecl *field) {
if (field == TargetField)
setTargetOffset();
super::addFieldOffset(field);
}
END_METADATA_SEARCHER()
return FindClassFieldOffset(IGM, theClass, field).getTargetOffset();
}
/// Given a reference to class metadata of the given type,
/// derive a reference to the field offset for a stored property.
/// The type must have dependent generic layout.
llvm::Value *irgen::emitClassFieldOffset(IRGenFunction &IGF,
ClassDecl *theClass,
VarDecl *field,
llvm::Value *metadata) {
irgen::Size offset = getClassFieldOffset(IGF.IGM, theClass, field);
int index = getOffsetInWords(IGF.IGM, offset);
return emitInvariantLoadFromMetadataAtIndex(IGF, metadata, index,
IGF.IGM.SizeTy);
}
/// Given a reference to class metadata of the given type,
/// load the fragile instance size and alignment of the class.
std::pair<llvm::Value *, llvm::Value *>
irgen::emitClassFragileInstanceSizeAndAlignMask(IRGenFunction &IGF,
ClassDecl *theClass,
llvm::Value *metadata) {
// If the class has fragile fixed layout, return the constant size and
// alignment.
if (llvm::Constant *size
= tryEmitClassConstantFragileInstanceSize(IGF.IGM, theClass)) {
llvm::Constant *alignMask
= tryEmitClassConstantFragileInstanceAlignMask(IGF.IGM, theClass);
assert(alignMask && "static size without static align");
return {size, alignMask};
}
// Otherwise, load it from the metadata.
return emitClassResilientInstanceSizeAndAlignMask(IGF, theClass, metadata);
}
std::pair<llvm::Value *, llvm::Value *>
irgen::emitClassResilientInstanceSizeAndAlignMask(IRGenFunction &IGF,
ClassDecl *theClass,
llvm::Value *metadata) {
class FindClassSize
: public ClassMetadataScanner<FindClassSize> {
using super = ClassMetadataScanner<FindClassSize>;
public:
FindClassSize(IRGenModule &IGM, ClassDecl *theClass)
: ClassMetadataScanner(IGM, theClass) {}
Size InstanceSize = Size::invalid();
Size InstanceAlignMask = Size::invalid();
void noteAddressPoint() {
assert(InstanceSize.isInvalid() && InstanceAlignMask.isInvalid()
&& "found size or alignment before address point?!");
NextOffset = Size(0);
}
void addInstanceSize() {
InstanceSize = NextOffset;
super::addInstanceSize();
}
void addInstanceAlignMask() {
InstanceAlignMask = NextOffset;
super::addInstanceAlignMask();
}
};
FindClassSize scanner(IGF.IGM, theClass);
scanner.layout();
assert(!scanner.InstanceSize.isInvalid()
&& !scanner.InstanceAlignMask.isInvalid()
&& "didn't find size or alignment in metadata?!");
Address metadataAsBytes(IGF.Builder.CreateBitCast(metadata, IGF.IGM.Int8PtrTy),
IGF.IGM.getPointerAlignment());
auto loadZExtInt32AtOffset = [&](Size offset) {
Address slot = IGF.Builder.CreateConstByteArrayGEP(metadataAsBytes, offset);
slot = IGF.Builder.CreateBitCast(slot, IGF.IGM.Int32Ty->getPointerTo());
llvm::Value *result = IGF.Builder.CreateLoad(slot);
if (IGF.IGM.SizeTy != IGF.IGM.Int32Ty)
result = IGF.Builder.CreateZExt(result, IGF.IGM.SizeTy);
return result;
};
llvm::Value *size = loadZExtInt32AtOffset(scanner.InstanceSize);
llvm::Value *alignMask = loadZExtInt32AtOffset(scanner.InstanceAlignMask);
return {size, alignMask};
}
/// Given a non-tagged object pointer, load a pointer to its class object.
static llvm::Value *emitLoadOfObjCHeapMetadataRef(IRGenFunction &IGF,
llvm::Value *object) {
if (IGF.IGM.TargetInfo.hasISAMasking()) {
object = IGF.Builder.CreateBitCast(object,
IGF.IGM.IntPtrTy->getPointerTo());
llvm::Value *metadata =
IGF.Builder.CreateLoad(Address(object, IGF.IGM.getPointerAlignment()));
llvm::Value *mask = IGF.Builder.CreateLoad(IGF.IGM.getAddrOfObjCISAMask());
metadata = IGF.Builder.CreateAnd(metadata, mask);
metadata = IGF.Builder.CreateIntToPtr(metadata, IGF.IGM.TypeMetadataPtrTy);
return metadata;
} else {
object = IGF.Builder.CreateBitCast(object,
IGF.IGM.TypeMetadataPtrTy->getPointerTo());
llvm::Value *metadata =
IGF.Builder.CreateLoad(Address(object, IGF.IGM.getPointerAlignment()));
return metadata;
}
}
/// Given a pointer to a heap object (i.e. definitely not a tagged
/// pointer), load its heap metadata pointer.
static llvm::Value *emitLoadOfHeapMetadataRef(IRGenFunction &IGF,
llvm::Value *object,
IsaEncoding isaEncoding,
bool suppressCast) {
switch (isaEncoding) {
case IsaEncoding::Pointer: {
// Drill into the object pointer. Rather than bitcasting, we make
// an effort to do something that should explode if we get something
// mistyped.
llvm::StructType *structTy =
cast<llvm::StructType>(
cast<llvm::PointerType>(object->getType())->getElementType());
llvm::Value *slot;
// We need a bitcast if we're dealing with an opaque class.
if (structTy->isOpaque()) {
auto metadataPtrPtrTy = IGF.IGM.TypeMetadataPtrTy->getPointerTo();
slot = IGF.Builder.CreateBitCast(object, metadataPtrPtrTy);
// Otherwise, make a GEP.
} else {
auto zero = llvm::ConstantInt::get(IGF.IGM.Int32Ty, 0);
SmallVector<llvm::Value*, 4> indexes;
indexes.push_back(zero);
do {
indexes.push_back(zero);
// Keep drilling down to the first element type.
auto eltTy = structTy->getElementType(0);
assert(isa<llvm::StructType>(eltTy) || eltTy == IGF.IGM.TypeMetadataPtrTy);
structTy = dyn_cast<llvm::StructType>(eltTy);
} while (structTy != nullptr);
slot = IGF.Builder.CreateInBoundsGEP(object, indexes);
if (!suppressCast) {
slot = IGF.Builder.CreateBitCast(slot,
IGF.IGM.TypeMetadataPtrTy->getPointerTo());
}
}
auto metadata = IGF.Builder.CreateLoad(Address(slot,
IGF.IGM.getPointerAlignment()));
if (IGF.IGM.EnableValueNames && object->hasName())
metadata->setName(llvm::Twine(object->getName()) + ".metadata");
return metadata;
}
case IsaEncoding::ObjC: {
// Feed the object pointer to object_getClass.
llvm::Value *objcClass = emitLoadOfObjCHeapMetadataRef(IGF, object);
objcClass = IGF.Builder.CreateBitCast(objcClass, IGF.IGM.TypeMetadataPtrTy);
return objcClass;
}
}
}
/// Given an object of class type, produce the heap metadata reference
/// as an %objc_class*.
llvm::Value *irgen::emitHeapMetadataRefForHeapObject(IRGenFunction &IGF,
llvm::Value *object,
CanType objectType,
bool suppressCast) {
ClassDecl *theClass = objectType.getClassOrBoundGenericClass();
if (theClass && isKnownNotTaggedPointer(IGF.IGM, theClass))
return emitLoadOfHeapMetadataRef(IGF, object,
getIsaEncodingForType(IGF.IGM, objectType),
suppressCast);
// OK, ask the runtime for the class pointer of this potentially-ObjC object.
return emitHeapMetadataRefForUnknownHeapObject(IGF, object);
}
llvm::Value *irgen::emitHeapMetadataRefForHeapObject(IRGenFunction &IGF,
llvm::Value *object,
SILType objectType,
bool suppressCast) {
return emitHeapMetadataRefForHeapObject(IGF, object,
objectType.getSwiftRValueType(),
suppressCast);
}
/// Given an opaque class instance pointer, produce the type metadata reference
/// as a %type*.
llvm::Value *irgen::emitDynamicTypeOfOpaqueHeapObject(IRGenFunction &IGF,
llvm::Value *object) {
object = IGF.Builder.CreateBitCast(object, IGF.IGM.ObjCPtrTy);
auto metadata = IGF.Builder.CreateCall(IGF.IGM.getGetObjectTypeFn(),
object,
object->getName() + ".Type");
metadata->setCallingConv(IGF.IGM.RuntimeCC);
metadata->setDoesNotThrow();
metadata->setDoesNotAccessMemory();
return metadata;
}
llvm::Value *irgen::
emitHeapMetadataRefForUnknownHeapObject(IRGenFunction &IGF,
llvm::Value *object) {
object = IGF.Builder.CreateBitCast(object, IGF.IGM.ObjCPtrTy);
auto metadata = IGF.Builder.CreateCall(IGF.IGM.getGetObjectClassFn(),
object,
object->getName() + ".Type");
metadata->setCallingConv(llvm::CallingConv::C);
metadata->setDoesNotThrow();
metadata->addAttribute(llvm::AttributeSet::FunctionIndex,
llvm::Attribute::ReadOnly);
return metadata;
}
/// Given an object of class type, produce the type metadata reference
/// as a %type*.
llvm::Value *irgen::emitDynamicTypeOfHeapObject(IRGenFunction &IGF,
llvm::Value *object,
SILType objectType,
bool suppressCast) {
// If it is known to have swift metadata, just load.
if (hasKnownSwiftMetadata(IGF.IGM, objectType.getSwiftRValueType())) {
return emitLoadOfHeapMetadataRef(IGF, object,
getIsaEncodingForType(IGF.IGM, objectType.getSwiftRValueType()),
suppressCast);
}
// Okay, ask the runtime for the type metadata of this
// potentially-ObjC object.
return emitDynamicTypeOfOpaqueHeapObject(IGF, object);
}
/// Given a class metatype, produce the necessary heap metadata
/// reference. This is generally the metatype pointer, but may
/// instead be a reference type.
llvm::Value *irgen::emitClassHeapMetadataRefForMetatype(IRGenFunction &IGF,
llvm::Value *metatype,
CanType type) {
// If the type is known to have Swift metadata, this is trivial.
if (hasKnownSwiftMetadata(IGF.IGM, type))
return metatype;
// Otherwise, we inline a little operation here.
// Load the metatype kind.
auto metatypeKindAddr =
Address(IGF.Builder.CreateStructGEP(/*Ty=*/nullptr, metatype, 0),
IGF.IGM.getPointerAlignment());
auto metatypeKind =
IGF.Builder.CreateLoad(metatypeKindAddr, metatype->getName() + ".kind");
// Compare it with the class wrapper kind.
auto classWrapperKind =
llvm::ConstantInt::get(IGF.IGM.MetadataKindTy,
unsigned(MetadataKind::ObjCClassWrapper));
auto isObjCClassWrapper =
IGF.Builder.CreateICmpEQ(metatypeKind, classWrapperKind,
"isObjCClassWrapper");
// Branch based on that.
llvm::BasicBlock *contBB = IGF.createBasicBlock("metadataForClass.cont");
llvm::BasicBlock *wrapBB = IGF.createBasicBlock("isWrapper");
IGF.Builder.CreateCondBr(isObjCClassWrapper, wrapBB, contBB);
llvm::BasicBlock *origBB = IGF.Builder.GetInsertBlock();
// If it's a wrapper, load from the 'Class' field, which is at index 1.
// TODO: if we guaranteed that this load couldn't crash, we could use
// a select here instead, which might be profitable.
IGF.Builder.emitBlock(wrapBB);
auto classFromWrapper =
emitInvariantLoadFromMetadataAtIndex(IGF, metatype, 1,
IGF.IGM.TypeMetadataPtrTy);
IGF.Builder.CreateBr(contBB);
// Continuation block.
IGF.Builder.emitBlock(contBB);
auto phi = IGF.Builder.CreatePHI(IGF.IGM.TypeMetadataPtrTy, 2,
metatype->getName() + ".class");
phi->addIncoming(metatype, origBB);
phi->addIncoming(classFromWrapper, wrapBB);
return phi;
}
namespace {
/// A class for finding a vtable entry offset for a method argument
/// in a class metadata object.
BEGIN_METADATA_SEARCHER_1(FindClassMethodIndex, Class,
SILDeclRef, TargetMethod)
void addMethod(SILDeclRef fn) {
if (TargetMethod == fn)
setTargetOffset();
super::addMethod(fn);
}
END_METADATA_SEARCHER()
}
/// Provide the abstract parameters for virtual calls to the given method.
AbstractCallee irgen::getAbstractVirtualCallee(IRGenFunction &IGF,
FuncDecl *method) {
// TODO: maybe use better versions in the v-table sometimes?
ResilienceExpansion bestExplosion = ResilienceExpansion::Minimal;
unsigned naturalUncurry = method->getNaturalArgumentCount() - 1;
return AbstractCallee(SILFunctionTypeRepresentation::Method, bestExplosion,
naturalUncurry, naturalUncurry, ExtraData::None);
}
/// Load the correct virtual function for the given class method.
llvm::Value *irgen::emitVirtualMethodValue(IRGenFunction &IGF,
llvm::Value *base,
SILType baseType,
SILDeclRef method,
CanSILFunctionType methodType,
bool useSuperVTable) {
AbstractFunctionDecl *methodDecl
= cast<AbstractFunctionDecl>(method.getDecl());
// Find the function that's actually got an entry in the metadata.
SILDeclRef overridden = method.getBaseOverriddenVTableEntry();
// Find the metadata.
llvm::Value *metadata;
if (useSuperVTable) {
auto instanceTy = baseType;
if (auto metaTy = dyn_cast<MetatypeType>(baseType.getSwiftRValueType()))
instanceTy = SILType::getPrimitiveObjectType(metaTy.getInstanceType());
if (IGF.IGM.isResilient(instanceTy.getClassOrBoundGenericClass(),
ResilienceExpansion::Maximal)) {
// The derived type that is making the super call is resilient,
// for example we may be in an extension of a class outside of our
// resilience domain. So, we need to load the superclass metadata
// dynamically.
metadata = emitClassHeapMetadataRef(IGF, instanceTy.getSwiftRValueType(),
MetadataValueType::TypeMetadata);
auto superField = emitAddressOfSuperclassRefInClassMetadata(IGF, metadata);
metadata = IGF.Builder.CreateLoad(superField);
} else {
// Otherwise, we can directly load the statically known superclass's
// metadata.
auto superTy = instanceTy.getSuperclass(/*resolver=*/nullptr);
metadata = emitClassHeapMetadataRef(IGF, superTy.getSwiftRValueType(),
MetadataValueType::TypeMetadata);
}
} else {
if ((isa<FuncDecl>(methodDecl) && cast<FuncDecl>(methodDecl)->isStatic()) ||
(isa<ConstructorDecl>(methodDecl) &&
method.kind == SILDeclRef::Kind::Allocator)) {
metadata = base;
} else {
metadata = emitHeapMetadataRefForHeapObject(IGF, base, baseType,
/*suppress cast*/ true);
}
}
// Use the type of the method we were type-checked against, not the
// type of the overridden method.
llvm::AttributeSet attrs;
auto fnTy = IGF.IGM.getFunctionType(methodType, attrs)->getPointerTo();
auto declaringClass = cast<ClassDecl>(overridden.getDecl()->getDeclContext());
auto index = FindClassMethodIndex(IGF.IGM, declaringClass, overridden)
.getTargetIndex();
return emitInvariantLoadFromMetadataAtIndex(IGF, metadata, index, fnTy);
}
//===----------------------------------------------------------------------===//
// Structs
//===----------------------------------------------------------------------===//
namespace {
/// An adapter for laying out struct metadata.
template <class Impl>
class StructMetadataBuilderBase
: public ConstantBuilder<StructMetadataLayout<Impl>> {
using super = ConstantBuilder<StructMetadataLayout<Impl>>;
protected:
using super::IGM;
using super::Target;
using super::addConstantWord;
using super::addWord;
StructMetadataBuilderBase(IRGenModule &IGM, StructDecl *theStruct)
: super(IGM, theStruct) {}
public:
void addMetadataFlags() {
addWord(getMetadataKind(IGM, MetadataKind::Struct));
}
void addNominalTypeDescriptor() {
addWord(StructNominalTypeDescriptorBuilder(IGM, Target).emit());
}
void addParentMetadataRef() {
// FIXME!
addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy));
}
void addFieldOffset(VarDecl *var) {
assert(var->hasStorage() &&
"storing field offset for computed property?!");
SILType structType =
SILType::getPrimitiveAddressType(
Target->getDeclaredTypeInContext()->getCanonicalType());
llvm::Constant *offset =
emitPhysicalStructMemberFixedOffset(IGM, structType, var);
// If we have a fixed offset, add it. Otherwise, leave zero as a
// placeholder.
if (offset)
addWord(offset);
else
addConstantWord(0);
}
void addGenericArgument(ArchetypeType *type) {
addWord(llvm::Constant::getNullValue(IGM.TypeMetadataPtrTy));
}
void addGenericWitnessTable(ArchetypeType *type, ProtocolDecl *protocol) {
addWord(llvm::Constant::getNullValue(IGM.WitnessTablePtrTy));
}
llvm::Constant *getInit() {
return this->getInitWithSuggestedType(NumHeapMetadataFields,
IGM.FullHeapMetadataStructTy);
}
};
class StructMetadataBuilder :
public StructMetadataBuilderBase<StructMetadataBuilder> {
public:
StructMetadataBuilder(IRGenModule &IGM, StructDecl *theStruct)
: StructMetadataBuilderBase(IGM, theStruct) {}
void addValueWitnessTable() {
auto type = this->Target->getDeclaredType()->getCanonicalType();
addWord(emitValueWitnessTable(IGM, type));
}
};
/// Emit a value witness table for a fixed-layout generic type, or a null
/// placeholder if the value witness table is dependent on generic parameters.
/// Returns nullptr if the value witness table is dependent.
static llvm::Constant *
getValueWitnessTableForGenericValueType(IRGenModule &IGM,
NominalTypeDecl *decl,
bool &dependent) {
CanType unboundType
= decl->getDeclaredTypeOfContext()->getCanonicalType();
dependent = hasDependentValueWitnessTable(IGM, unboundType);
if (dependent)
return llvm::ConstantPointerNull::get(IGM.Int8PtrTy);
else
return emitValueWitnessTable(IGM, unboundType);
}
/// A builder for metadata templates.
class GenericStructMetadataBuilder :
public GenericMetadataBuilderBase<GenericStructMetadataBuilder,
StructMetadataBuilderBase<GenericStructMetadataBuilder>> {
typedef GenericMetadataBuilderBase super;
public:
GenericStructMetadataBuilder(IRGenModule &IGM, StructDecl *theStruct)
: super(IGM, theStruct) {}
llvm::Value *emitAllocateMetadata(IRGenFunction &IGF,
llvm::Value *metadataPattern,
llvm::Value *arguments) {
return IGF.Builder.CreateCall(IGM.getAllocateGenericValueMetadataFn(),
{metadataPattern, arguments});
}
void addValueWitnessTable() {
addWord(getValueWitnessTableForGenericValueType(IGM, Target,
HasDependentVWT));
}
void addDependentValueWitnessTablePattern() {
SmallVector<llvm::Constant*, 20> pattern;
emitDependentValueWitnessTablePattern(IGM,
Target->getDeclaredTypeOfContext()->getCanonicalType(),
pattern);
for (auto witness: pattern)
addWord(witness);
}
void emitInitializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
llvm::Value *vwtable) {
// Nominal types are always preserved through SIL lowering.
auto structTy = Target->getDeclaredTypeInContext()->getCanonicalType();
IGM.getTypeInfoForLowered(CanType(Target->getDeclaredTypeInContext()))
.initializeMetadata(IGF, metadata, vwtable,
SILType::getPrimitiveAddressType(structTy));
}
};
}
/// Emit the type metadata or metadata template for a struct.
void irgen::emitStructMetadata(IRGenModule &IGM, StructDecl *structDecl) {
// TODO: structs nested within generic types
llvm::Constant *init;
bool isPattern;
if (hasMetadataPattern(IGM, structDecl)) {
GenericStructMetadataBuilder builder(IGM, structDecl);
builder.layout();
init = builder.getInit();
isPattern = true;
} else {
StructMetadataBuilder builder(IGM, structDecl);
builder.layout();
init = builder.getInit();
isPattern = false;
}
maybeEmitTypeMetadataAccessFunction(IGM, structDecl);
CanType declaredType = structDecl->getDeclaredType()->getCanonicalType();
// For now, all type metadata is directly stored.
bool isIndirect = false;
IGM.defineTypeMetadata(declaredType, isIndirect, isPattern,
/*isConstant*/!isPattern, init);
}
// Enums
namespace {
template<class Impl>
class EnumMetadataBuilderBase
: public ConstantBuilder<EnumMetadataLayout<Impl>> {
using super = ConstantBuilder<EnumMetadataLayout<Impl>>;
protected:
using super::IGM;
using super::Target;
using super::addWord;
public:
EnumMetadataBuilderBase(IRGenModule &IGM, EnumDecl *theEnum)
: super(IGM, theEnum) {}
void addMetadataFlags() {
addWord(getMetadataKind(IGM, Target->classifyAsOptionalType()
? MetadataKind::Optional : MetadataKind::Enum));
}
void addNominalTypeDescriptor() {
// FIXME!
addWord(EnumNominalTypeDescriptorBuilder(IGM, Target).emit());
}
void addParentMetadataRef() {
// FIXME!
addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy));
}
void addGenericArgument(ArchetypeType *type) {
addWord(llvm::Constant::getNullValue(IGM.TypeMetadataPtrTy));
}
void addGenericWitnessTable(ArchetypeType *type, ProtocolDecl *protocol) {
addWord(llvm::Constant::getNullValue(IGM.WitnessTablePtrTy));
}
};
class EnumMetadataBuilder
: public EnumMetadataBuilderBase<EnumMetadataBuilder>
{
public:
EnumMetadataBuilder(IRGenModule &IGM, EnumDecl *theEnum)
: EnumMetadataBuilderBase(IGM, theEnum) {}
void addValueWitnessTable() {
auto type = Target->getDeclaredType()->getCanonicalType();
addWord(emitValueWitnessTable(IGM, type));
}
void addPayloadSize() {
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();
auto &enumTI = IGM.getTypeInfoForLowered(enumTy);
(void) enumTI;
assert(enumTI.isFixedSize(ResilienceExpansion::Maximal) &&
"emitting constant enum metadata for resilient-sized type?");
assert(!enumTI.isFixedSize(ResilienceExpansion::Minimal) &&
"non-generic, non-resilient enums don't need payload size in metadata");
auto &strategy = getEnumImplStrategy(IGM, enumTy);
addConstantWord(strategy.getPayloadSizeForMetadata());
}
};
class GenericEnumMetadataBuilder
: public GenericMetadataBuilderBase<GenericEnumMetadataBuilder,
EnumMetadataBuilderBase<GenericEnumMetadataBuilder>>
{
public:
GenericEnumMetadataBuilder(IRGenModule &IGM, EnumDecl *theEnum)
: GenericMetadataBuilderBase(IGM, theEnum) {}
llvm::Value *emitAllocateMetadata(IRGenFunction &IGF,
llvm::Value *metadataPattern,
llvm::Value *arguments) {
return IGF.Builder.CreateCall(IGM.getAllocateGenericValueMetadataFn(),
{metadataPattern, arguments});
}
void addValueWitnessTable() {
addWord(getValueWitnessTableForGenericValueType(IGM, Target,
HasDependentVWT));
}
void addDependentValueWitnessTablePattern() {
SmallVector<llvm::Constant*, 20> pattern;
emitDependentValueWitnessTablePattern(IGM,
Target->getDeclaredTypeOfContext()->getCanonicalType(),
pattern);
for (auto witness: pattern)
addWord(witness);
}
void addPayloadSize() {
// In all cases where a payload size is demanded in the metadata, it's
// runtime-dependent, so fill in a zero here.
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();
auto &enumTI = IGM.getTypeInfoForLowered(enumTy);
(void) enumTI;
assert(!enumTI.isFixedSize(ResilienceExpansion::Minimal) &&
"non-generic, non-resilient enums don't need payload size in metadata");
addConstantWord(0);
}
void emitInitializeMetadata(IRGenFunction &IGF,
llvm::Value *metadata,
llvm::Value *vwtable) {
// Nominal types are always preserved through SIL lowering.
auto enumTy = Target->getDeclaredTypeInContext()->getCanonicalType();
IGM.getTypeInfoForLowered(enumTy)
.initializeMetadata(IGF, metadata, vwtable,
SILType::getPrimitiveAddressType(enumTy));
}
};
}
void irgen::emitEnumMetadata(IRGenModule &IGM, EnumDecl *theEnum) {
// TODO: enums nested inside generic types
llvm::Constant *init;
bool isPattern;
if (hasMetadataPattern(IGM, theEnum)) {
GenericEnumMetadataBuilder builder(IGM, theEnum);
builder.layout();
init = builder.getInit();
isPattern = true;
} else {
EnumMetadataBuilder builder(IGM, theEnum);
builder.layout();
init = builder.getInit();
isPattern = false;
}
maybeEmitTypeMetadataAccessFunction(IGM, theEnum);
CanType declaredType = theEnum->getDeclaredType()->getCanonicalType();
// For now, all type metadata is directly stored.
bool isIndirect = false;
IGM.defineTypeMetadata(declaredType, isIndirect, isPattern,
/*isConstant*/!isPattern, init);
}
llvm::Value *IRGenFunction::emitObjCSelectorRefLoad(StringRef selector) {
llvm::Constant *loadSelRef = IGM.getAddrOfObjCSelectorRef(selector);
llvm::Value *loadSel =
Builder.CreateLoad(Address(loadSelRef, IGM.getPointerAlignment()));
// When generating JIT'd code, we need to call sel_registerName() to force
// the runtime to unique the selector. For non-JIT'd code, the linker will
// do it for us.
if (IGM.Opts.UseJIT) {
loadSel = Builder.CreateCall(IGM.getObjCSelRegisterNameFn(), loadSel);
}
return loadSel;
}
//===----------------------------------------------------------------------===//
// Foreign types
//===----------------------------------------------------------------------===//
namespace {
/// A CRTP layout class for foreign class metadata.
template <class Impl>
class ForeignClassMetadataLayout
: public MetadataLayout<Impl> {
using super = MetadataLayout<Impl>;
protected:
ClassDecl *Target;
using super::asImpl;
public:
ForeignClassMetadataLayout(IRGenModule &IGM, ClassDecl *target)
: super(IGM), Target(target) {}
void layout() {
super::layout();
asImpl().addSuperClass();
asImpl().addReservedWord();
asImpl().addReservedWord();
asImpl().addReservedWord();
}
bool requiresInitializationFunction() {
// TODO: superclasses?
return false;
}
CanType getTargetType() const {
return Target->getDeclaredType()->getCanonicalType();
}
};
/// An adapter that turns a metadata layout class into a foreign metadata
/// layout class. Foreign metadata has an additional header that
template<typename Impl, typename Base>
class ForeignMetadataBuilderBase : public Base {
typedef Base super;
protected:
IRGenModule &IGM = super::IGM;
using super::asImpl;
template <class... T>
ForeignMetadataBuilderBase(IRGenModule &IGM,
T &&...args)
: super(IGM, std::forward<T>(args)...) {}
Size AddressPoint = Size::invalid();
public:
void layout() {
if (asImpl().requiresInitializationFunction())
asImpl().addInitializationFunction();
asImpl().addForeignName();
asImpl().addUniquePointer();
asImpl().addForeignFlags();
super::layout();
}
void addForeignFlags() {
int64_t flags = 0;
if (asImpl().requiresInitializationFunction()) flags |= 1;
asImpl().addConstantWord(flags);
}
void addForeignName() {
CanType targetType = asImpl().getTargetType();
asImpl().addWord(getMangledTypeName(IGM, targetType));
}
void addUniquePointer() {
asImpl().addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy));
}
void addInitializationFunction() {
asImpl().addWord(llvm::ConstantPointerNull::get(IGM.Int8PtrTy));
}
void noteAddressPoint() {
AddressPoint = asImpl().getNextOffset();
}
Size getOffsetOfAddressPoint() const { return AddressPoint; }
};
/// A builder for ForeignClassMetadata.
class ForeignClassMetadataBuilder :
public ForeignMetadataBuilderBase<ForeignClassMetadataBuilder,
ConstantBuilder<ForeignClassMetadataLayout<ForeignClassMetadataBuilder>>>{
public:
ForeignClassMetadataBuilder(IRGenModule &IGM, ClassDecl *target)
: ForeignMetadataBuilderBase(IGM, target) {}
// Visitor methods.
void addValueWitnessTable() {
// Without Objective-C interop, foreign classes must still use
// Swift native reference counting.
auto type = (IGM.ObjCInterop
? IGM.Context.TheUnknownObjectType
: IGM.Context.TheNativeObjectType);
auto wtable = IGM.getAddrOfValueWitnessTable(type);
addWord(wtable);
}
void addMetadataFlags() {
addConstantWord((unsigned) MetadataKind::ForeignClass);
}
void addSuperClass() {
// TODO: superclasses
addWord(llvm::ConstantPointerNull::get(IGM.TypeMetadataPtrTy));
}
void addReservedWord() {
addWord(llvm::ConstantPointerNull::get(IGM.Int8PtrTy));
}
};
/// A builder for ForeignStructMetadata.
class ForeignStructMetadataBuilder :
public ForeignMetadataBuilderBase<ForeignStructMetadataBuilder,
StructMetadataBuilderBase<ForeignStructMetadataBuilder>>
{
public:
ForeignStructMetadataBuilder(IRGenModule &IGM, StructDecl *target)
: ForeignMetadataBuilderBase(IGM, target)
{}
CanType getTargetType() const {
return Target->getDeclaredType()->getCanonicalType();
}
bool requiresInitializationFunction() const {
return false;
}
void addValueWitnessTable() {
auto type = this->Target->getDeclaredType()->getCanonicalType();
addWord(emitValueWitnessTable(IGM, type));
}
};
/// A builder for ForeignEnumMetadata.
class ForeignEnumMetadataBuilder :
public ForeignMetadataBuilderBase<ForeignEnumMetadataBuilder,
EnumMetadataBuilderBase<ForeignEnumMetadataBuilder>>
{
public:
ForeignEnumMetadataBuilder(IRGenModule &IGM, EnumDecl *target)
: ForeignMetadataBuilderBase(IGM, target)
{}
CanType getTargetType() const {
return Target->getDeclaredType()->getCanonicalType();
}
bool requiresInitializationFunction() const {
return false;
}
void addValueWitnessTable() {
auto type = this->Target->getDeclaredType()->getCanonicalType();
addWord(emitValueWitnessTable(IGM, type));
}
void addPayloadSize() const {
llvm_unreachable("nongeneric enums shouldn't need payload size in metadata");
}
};
}
llvm::Constant *
irgen::emitForeignTypeMetadataInitializer(IRGenModule &IGM, CanType type,
Size &offsetOfAddressPoint) {
if (auto classType = dyn_cast<ClassType>(type)) {
assert(!classType.getParent());
auto classDecl = classType->getDecl();
assert(classDecl->isForeign());
ForeignClassMetadataBuilder builder(IGM, classDecl);
builder.layout();
offsetOfAddressPoint = builder.getOffsetOfAddressPoint();
return builder.getInit();
} else if (auto structType = dyn_cast<StructType>(type)) {
auto structDecl = structType->getDecl();
assert(structDecl->hasClangNode());
ForeignStructMetadataBuilder builder(IGM, structDecl);
builder.layout();
offsetOfAddressPoint = builder.getOffsetOfAddressPoint();
return builder.getInit();
} else if (auto enumType = dyn_cast<EnumType>(type)) {
auto enumDecl = enumType->getDecl();
assert(enumDecl->hasClangNode());
ForeignEnumMetadataBuilder builder(IGM, enumDecl);
builder.layout();
offsetOfAddressPoint = builder.getOffsetOfAddressPoint();
return builder.getInit();
} else {
llvm_unreachable("foreign metadata for unexpected type?!");
}
}
// Protocols
/// Get the runtime identifier for a special protocol, if any.
SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) {
auto known = P->getKnownProtocolKind();
if (!known)
return SpecialProtocol::None;
switch (*known) {
case KnownProtocolKind::AnyObject:
return SpecialProtocol::AnyObject;
case KnownProtocolKind::ErrorType:
return SpecialProtocol::ErrorType;
// The other known protocols aren't special at runtime.
case KnownProtocolKind::SequenceType:
case KnownProtocolKind::GeneratorType:
case KnownProtocolKind::BooleanType:
case KnownProtocolKind::RawRepresentable:
case KnownProtocolKind::Equatable:
case KnownProtocolKind::Hashable:
case KnownProtocolKind::Comparable:
case KnownProtocolKind::ObjectiveCBridgeable:
case KnownProtocolKind::DestructorSafeContainer:
case KnownProtocolKind::ArrayLiteralConvertible:
case KnownProtocolKind::BooleanLiteralConvertible:
case KnownProtocolKind::DictionaryLiteralConvertible:
case KnownProtocolKind::ExtendedGraphemeClusterLiteralConvertible:
case KnownProtocolKind::FloatLiteralConvertible:
case KnownProtocolKind::IntegerLiteralConvertible:
case KnownProtocolKind::StringInterpolationConvertible:
case KnownProtocolKind::StringLiteralConvertible:
case KnownProtocolKind::NilLiteralConvertible:
case KnownProtocolKind::UnicodeScalarLiteralConvertible:
case KnownProtocolKind::ColorLiteralConvertible:
case KnownProtocolKind::ImageLiteralConvertible:
case KnownProtocolKind::FileReferenceLiteralConvertible:
case KnownProtocolKind::BuiltinBooleanLiteralConvertible:
case KnownProtocolKind::BuiltinExtendedGraphemeClusterLiteralConvertible:
case KnownProtocolKind::BuiltinFloatLiteralConvertible:
case KnownProtocolKind::BuiltinIntegerLiteralConvertible:
case KnownProtocolKind::BuiltinStringLiteralConvertible:
case KnownProtocolKind::BuiltinUTF16StringLiteralConvertible:
case KnownProtocolKind::BuiltinUnicodeScalarLiteralConvertible:
case KnownProtocolKind::OptionSetType:
case KnownProtocolKind::BridgedNSError:
return SpecialProtocol::None;
}
}
namespace {
class ProtocolDescriptorBuilder {
IRGenModule &IGM;
ProtocolDecl *Protocol;
SmallVector<llvm::Constant*, 8> Fields;
public:
ProtocolDescriptorBuilder(IRGenModule &IGM, ProtocolDecl *protocol)
: IGM(IGM), Protocol(protocol) {}
void layout() {
addObjCCompatibilityIsa();
addName();
addInherited();
addObjCCompatibilityTables();
addSize();
addFlags();
}
llvm::Constant *null() {
return llvm::ConstantPointerNull::get(IGM.Int8PtrTy);
}
void addObjCCompatibilityIsa() {
// The ObjC runtime will drop a reference to its magic Protocol class
// here.
Fields.push_back(null());
}
void addName() {
// Include the _Tt prefix. Since Swift protocol descriptors are laid
// out to look like ObjC Protocol* objects, the name has to clearly be
// a Swift mangled name.
SmallString<32> mangling;
mangling += "_Tt";
auto name = LinkEntity::forTypeMangling(
Protocol->getDeclaredType()->getCanonicalType());
name.mangle(mangling);
auto global = IGM.getAddrOfGlobalString(mangling);
Fields.push_back(global);
}
void addInherited() {
// If there are no inherited protocols, produce null.
auto inherited = Protocol->getInheritedProtocols(nullptr);
if (inherited.empty()) {
Fields.push_back(null());
return;
}
// Otherwise, collect references to all of the inherited protocol
// descriptors.
SmallVector<llvm::Constant*, 4> inheritedDescriptors;
inheritedDescriptors.push_back(IGM.getSize(Size(inherited.size())));
for (ProtocolDecl *p : inherited) {
auto descriptor = IGM.getAddrOfProtocolDescriptor(p, NotForDefinition);
inheritedDescriptors.push_back(descriptor);
}
auto inheritedInit = llvm::ConstantStruct::getAnon(inheritedDescriptors);
auto inheritedVar = new llvm::GlobalVariable(IGM.Module,
inheritedInit->getType(),
/*isConstant*/ true,
llvm::GlobalValue::PrivateLinkage,
inheritedInit);
llvm::Constant *inheritedVarPtr
= llvm::ConstantExpr::getBitCast(inheritedVar, IGM.Int8PtrTy);
Fields.push_back(inheritedVarPtr);
}
void addObjCCompatibilityTables() {
// Required instance methods
Fields.push_back(null());
// Required class methods
Fields.push_back(null());
// Optional instance methods
Fields.push_back(null());
// Optional class methods
Fields.push_back(null());
// Properties
Fields.push_back(null());
}
void addSize() {
// The number of fields so far in words, plus 4 bytes for size and
// 4 bytes for flags.
unsigned sz = (Fields.size() * IGM.getPointerSize()).getValue() + 4 + 4;
Fields.push_back(llvm::ConstantInt::get(IGM.Int32Ty, sz));
}
void addFlags() {
auto flags = ProtocolDescriptorFlags()
.withSwift(true)
.withClassConstraint(Protocol->requiresClass()
? ProtocolClassConstraint::Class
: ProtocolClassConstraint::Any)
.withDispatchStrategy(
Lowering::TypeConverter::getProtocolDispatchStrategy(Protocol))
.withSpecialProtocol(getSpecialProtocolID(Protocol));
Fields.push_back(llvm::ConstantInt::get(IGM.Int32Ty,
flags.getIntValue()));
}
llvm::Constant *getInit() {
return llvm::ConstantStruct::get(IGM.ProtocolDescriptorStructTy,
Fields);
}
};
} // end anonymous namespace
/// Emit global structures associated with the given protocol. This comprises
/// the protocol descriptor, and for ObjC interop, references to the descriptor
/// that the ObjC runtime uses for uniquing.
void IRGenModule::emitProtocolDecl(ProtocolDecl *protocol) {
// If the protocol is Objective-C-compatible, go through the path that
// produces an ObjC-compatible protocol_t.
if (protocol->isObjC()) {
// In JIT mode, we need to create protocol descriptors using the ObjC
// runtime in JITted code.
if (Opts.UseJIT)
return;
// Native ObjC protocols are emitted on-demand in ObjC and uniqued by the
// runtime; we don't need to try to emit a unique descriptor symbol for them.
if (protocol->hasClangNode())
return;
getObjCProtocolGlobalVars(protocol);
return;
}
ProtocolDescriptorBuilder builder(*this, protocol);
builder.layout();
auto init = builder.getInit();
auto var = cast<llvm::GlobalVariable>(
getAddrOfProtocolDescriptor(protocol, ForDefinition));
var->setConstant(true);
var->setInitializer(init);
}
/// \brief Load a reference to the protocol descriptor for the given protocol.
///
/// For Swift protocols, this is a constant reference to the protocol descriptor
/// symbol.
/// For ObjC protocols, descriptors are uniqued at runtime by the ObjC runtime.
/// We need to load the unique reference from a global variable fixed up at
/// startup.
llvm::Value *irgen::emitProtocolDescriptorRef(IRGenFunction &IGF,
ProtocolDecl *protocol) {
if (!protocol->isObjC())
return IGF.IGM.getAddrOfProtocolDescriptor(protocol, NotForDefinition);
auto refVar = IGF.IGM.getAddrOfObjCProtocolRef(protocol, NotForDefinition);
llvm::Value *val
= IGF.Builder.CreateLoad(refVar, IGF.IGM.getPointerAlignment());
val = IGF.Builder.CreateBitCast(val,
IGF.IGM.ProtocolDescriptorStructTy->getPointerTo());
return val;
}
//===----------------------------------------------------------------------===//
// Other metadata.
//===----------------------------------------------------------------------===//
llvm::Value *irgen::emitMetatypeInstanceType(IRGenFunction &IGF,
llvm::Value *metatypeMetadata) {
// The instance type field of MetatypeMetadata is immediately after
// the isa field.
return emitInvariantLoadFromMetadataAtIndex(IGF, metatypeMetadata, 1,
IGF.IGM.TypeMetadataPtrTy);
}