blob: 55ffc6f0d373dd486caa6855d017b502478dd37e [file] [log] [blame]
//===--- TypeLowering.h - Swift Type Lowering for Reflection ----*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// Implements logic for computing in-memory layouts from TypeRefs loaded from
// reflection metadata.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_REFLECTION_TYPELOWERING_H
#define SWIFT_REFLECTION_TYPELOWERING_H
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/Casting.h"
#include <iostream>
#include <memory>
namespace swift {
namespace reflection {
using llvm::cast;
using llvm::dyn_cast;
class TypeRef;
class TypeRefBuilder;
class BuiltinTypeDescriptor;
// Defined in TypeLowering.cpp, not public -- they're friends below
class LowerType;
class EnumTypeInfoBuilder;
class RecordTypeInfoBuilder;
class ExistentialTypeInfoBuilder;
enum class RecordKind : unsigned {
Invalid,
// A Swift tuple type.
Tuple,
// A Swift struct type.
Struct,
// An enum with no payload cases. The record will have no fields, but
// will have the correct size.
NoPayloadEnum,
// An enum with a single payload case. The record consists of a single
// field, being the enum payload.
SinglePayloadEnum,
// An enum with multiple payload cases. The record consists of a multiple
// fields, one for each enum payload.
MultiPayloadEnum,
// A Swift-native function is always a function pointer followed by a
// retainable, nullable context pointer.
ThickFunction,
// An existential is a three-word buffer followed by value metadata and
// witness tables.
OpaqueExistential,
// A class existential is a retainable pointer followed by witness
// tables.
ClassExistential,
// An existential metatype.
ExistentialMetatype,
// An error existential is a special kind of heap object, so is a retainable
// pointer, with no witness tables.
ErrorExistential,
// A class instance layout, consisting of the stored properties of
// one class, excluding superclasses.
ClassInstance,
// A closure context instance layout, consisting of the captured values.
// For now, captured values do not retain their names.
ClosureContext,
};
enum class ReferenceCounting : unsigned {
Native,
Unknown
};
enum class ReferenceKind : unsigned {
Strong,
#define REF_STORAGE(Name, ...) Name,
#include "swift/AST/ReferenceStorage.def"
};
enum class TypeInfoKind : unsigned {
Builtin,
Record,
Reference,
};
class TypeInfo {
TypeInfoKind Kind;
unsigned Size, Alignment, Stride, NumExtraInhabitants;
bool BitwiseTakable;
public:
TypeInfo(TypeInfoKind Kind,
unsigned Size, unsigned Alignment,
unsigned Stride, unsigned NumExtraInhabitants,
bool BitwiseTakable)
: Kind(Kind), Size(Size), Alignment(Alignment), Stride(Stride),
NumExtraInhabitants(NumExtraInhabitants),
BitwiseTakable(BitwiseTakable) {
assert(Alignment > 0);
}
TypeInfoKind getKind() const { return Kind; }
unsigned getSize() const { return Size; }
unsigned getAlignment() const { return Alignment; }
unsigned getStride() const { return Stride; }
unsigned getNumExtraInhabitants() const { return NumExtraInhabitants; }
bool isBitwiseTakable() const { return BitwiseTakable; }
void dump() const;
void dump(std::ostream &OS, unsigned Indent = 0) const;
};
struct FieldInfo {
std::string Name;
unsigned Offset;
const TypeRef *TR;
const TypeInfo &TI;
};
/// Builtins and (opaque) imported value types
class BuiltinTypeInfo : public TypeInfo {
std::string Name;
public:
explicit BuiltinTypeInfo(const BuiltinTypeDescriptor *descriptor);
const std::string &getMangledTypeName() const {
return Name;
}
static bool classof(const TypeInfo *TI) {
return TI->getKind() == TypeInfoKind::Builtin;
}
};
/// Class instances, structs, tuples
class RecordTypeInfo : public TypeInfo {
RecordKind SubKind;
std::vector<FieldInfo> Fields;
public:
RecordTypeInfo(unsigned Size, unsigned Alignment,
unsigned Stride, unsigned NumExtraInhabitants,
bool BitwiseTakable,
RecordKind SubKind, const std::vector<FieldInfo> &Fields)
: TypeInfo(TypeInfoKind::Record, Size, Alignment, Stride,
NumExtraInhabitants, BitwiseTakable),
SubKind(SubKind), Fields(Fields) {}
RecordKind getRecordKind() const { return SubKind; }
unsigned getNumFields() const { return Fields.size(); }
const std::vector<FieldInfo> &getFields() const { return Fields; }
static bool classof(const TypeInfo *TI) {
return TI->getKind() == TypeInfoKind::Record;
}
};
/// References to classes, closure contexts and anything else with an
/// 'isa' pointer
class ReferenceTypeInfo : public TypeInfo {
ReferenceKind SubKind;
ReferenceCounting Refcounting;
public:
ReferenceTypeInfo(unsigned Size, unsigned Alignment,
unsigned Stride, unsigned NumExtraInhabitants,
bool BitwiseTakable, ReferenceKind SubKind,
ReferenceCounting Refcounting)
: TypeInfo(TypeInfoKind::Reference, Size, Alignment, Stride,
NumExtraInhabitants, BitwiseTakable),
SubKind(SubKind), Refcounting(Refcounting) {}
ReferenceKind getReferenceKind() const {
return SubKind;
}
ReferenceCounting getReferenceCounting() const {
return Refcounting;
}
static bool classof(const TypeInfo *TI) {
return TI->getKind() == TypeInfoKind::Reference;
}
};
/// This class owns the memory for all TypeInfo instances that it vends.
class TypeConverter {
TypeRefBuilder &Builder;
std::vector<std::unique_ptr<const TypeInfo>> Pool;
llvm::DenseMap<const TypeRef *, const TypeInfo *> Cache;
llvm::DenseSet<const TypeRef *> RecursionCheck;
llvm::DenseMap<std::pair<unsigned, unsigned>,
const ReferenceTypeInfo *> ReferenceCache;
const TypeRef *RawPointerTR = nullptr;
const TypeRef *NativeObjectTR = nullptr;
const TypeRef *UnknownObjectTR = nullptr;
const TypeRef *ThinFunctionTR = nullptr;
const TypeRef *AnyMetatypeTR = nullptr;
const TypeInfo *ThinFunctionTI = nullptr;
const TypeInfo *ThickFunctionTI = nullptr;
const TypeInfo *AnyMetatypeTI = nullptr;
const TypeInfo *EmptyTI = nullptr;
public:
explicit TypeConverter(TypeRefBuilder &Builder) : Builder(Builder) {}
TypeRefBuilder &getBuilder() { return Builder; }
/// Tests if the type is concrete enough that its size is known.
/// For example, a bound generic class is fixed size even if some
/// of the generic argument types contain generic parameters.
bool hasFixedSize(const TypeRef *TR);
/// Returns layout information for a value of the given type.
/// For a class, this returns the lowering of the reference value.
///
/// The type must either be concrete, or at least fixed-size, as
/// determined by the isFixedSize() predicate.
const TypeInfo *getTypeInfo(const TypeRef *TR);
/// Returns layout information for an instance of the given
/// class.
///
/// Not cached.
const TypeInfo *getClassInstanceTypeInfo(const TypeRef *TR,
unsigned start);
private:
friend class swift::reflection::LowerType;
friend class swift::reflection::EnumTypeInfoBuilder;
friend class swift::reflection::RecordTypeInfoBuilder;
friend class swift::reflection::ExistentialTypeInfoBuilder;
const ReferenceTypeInfo *
getReferenceTypeInfo(ReferenceKind Kind,
ReferenceCounting Refcounting);
/// TypeRefs for special types for which we need to know the layout
/// intrinsically in order to layout anything else.
///
/// IRGen emits BuiltinTypeDescriptors for these when compiling the
/// standard library.
const TypeRef *getRawPointerTypeRef();
const TypeRef *getNativeObjectTypeRef();
const TypeRef *getUnknownObjectTypeRef();
const TypeRef *getThinFunctionTypeRef();
const TypeRef *getAnyMetatypeTypeRef();
const TypeInfo *getThinFunctionTypeInfo();
const TypeInfo *getThickFunctionTypeInfo();
const TypeInfo *getAnyMetatypeTypeInfo();
const TypeInfo *getEmptyTypeInfo();
template <typename TypeInfoTy, typename... Args>
const TypeInfoTy *makeTypeInfo(Args... args) {
auto TI = new TypeInfoTy(::std::forward<Args>(args)...);
Pool.push_back(std::unique_ptr<const TypeInfo>(TI));
return TI;
}
};
/// Utility class for performing universal layout for types such as
/// tuples, structs, thick functions, etc.
class RecordTypeInfoBuilder {
TypeConverter &TC;
unsigned Size, Alignment, NumExtraInhabitants;
bool BitwiseTakable;
RecordKind Kind;
std::vector<FieldInfo> Fields;
bool Empty;
bool Invalid;
public:
RecordTypeInfoBuilder(TypeConverter &TC, RecordKind Kind)
: TC(TC), Size(0), Alignment(1), NumExtraInhabitants(0),
BitwiseTakable(true), Kind(Kind), Empty(true), Invalid(false) {}
bool isInvalid() const {
return Invalid;
}
unsigned addField(unsigned fieldSize, unsigned fieldAlignment,
unsigned numExtraInhabitants,
bool bitwiseTakable);
// Add a field of a record type, such as a struct.
void addField(const std::string &Name, const TypeRef *TR);
const RecordTypeInfo *build();
unsigned getNumFields() const {
return Fields.size();
}
unsigned getFieldOffset(unsigned Index) const {
return Fields[Index].Offset;
}
};
}
}
#endif