Introduce a special memory arena in ASTContext for the type checker.

This introduces the notion of arenas into ASTContext, with two arenas
currently defined: one for 'permanent' storage, and another for the
current constraint checker. The latter is used when allocating any
types that involve type variables, which are only used temporarily
during type checking anyway.

This gives us a 1% speedup on swift.swift (because we're hitting
smaller hash tables when doing lookups) and < 1% memory reduction
(since that's not the main source of memory usage). It's more
important architecturally, so our memory usage doesn't grow with the
number of type-checks performed.

Note also that this arena scheme could be generalized, which we may
very well want to do in the future. For example, we could easily have
an arena for temporary nodes introduced by parsing (e.g.,
UnresolvedDeclRefExpr) or by name binding (OverloadedDeclRefExpr), and
clear that arena when we successfully move onto the next phase. Or, in
a REPL/debugger context, have a 'temporary' arena for
statements/expressions that can be removed.



Swift SVN r3175
This commit is contained in:
Doug Gregor
2012-11-14 06:57:16 +00:00
parent 048b50f3b9
commit 2183b57fa4
6 changed files with 349 additions and 156 deletions

View File

@@ -28,10 +28,12 @@
#include <utility>
namespace llvm {
class BumpPtrAllocator;
class SourceMgr;
}
namespace swift {
class ASTContext;
class BoundGenericType;
class SourceLoc;
class Type;
@@ -71,7 +73,53 @@ public:
/// the requirements of those protocols.
llvm::DenseMap<ProtocolDecl *, ProtocolConformance *> InheritedMapping;
};
/// \brief The arena in which a particular ASTContext allocation will go.
enum class AllocationArena {
/// \brief The permanent arena, which is tied to the lifetime of
/// the ASTContext.
///
/// All global declarations and types need to be allocated into this arena.
/// At present, everything that is not a type involving a type variable is
/// allocated in this arena.
Permanent,
/// \brief The constraint solver's temporary arena, which is tied to the
/// lifetime of a particular instance of the constraint solver.
///
/// Any type involving a type variable is allocated in this arena.
ConstraintSolver
};
/// \brief Introduces a new constraint checker arena, whose lifetime is
/// tied to the lifetime of this RAII object.
class ConstraintCheckerArenaRAII {
ASTContext &Self;
void *Data;
public:
/// \brief Introduces a new constraint checker arena, supplanting any
/// existing constraint checker arena.
///
/// \param self The ASTContext into which this constraint checker arena
/// will be installed.
///
/// \param allocator The allocator used for allocating any data that
/// goes into the constraint checker arena.
ConstraintCheckerArenaRAII(ASTContext &self,
llvm::BumpPtrAllocator &allocator);
ConstraintCheckerArenaRAII(const ConstraintCheckerArenaRAII &) = delete;
ConstraintCheckerArenaRAII(ConstraintCheckerArenaRAII &&) = delete;
ConstraintCheckerArenaRAII &
operator=(const ConstraintCheckerArenaRAII &) = delete;
ConstraintCheckerArenaRAII &
operator=(ConstraintCheckerArenaRAII &&) = delete;
~ConstraintCheckerArenaRAII();
};
/// ASTContext - This object creates and owns the AST objects.
class ASTContext {
ASTContext(const ASTContext&) = delete;
@@ -81,6 +129,8 @@ public:
// Members that should only be used by ASTContext.cpp.
struct Implementation;
Implementation &Impl;
friend class ConstraintCheckerArenaRAII;
public:
ASTContext(LangOptions &langOpts, llvm::SourceMgr &SourceMgr,
@@ -113,47 +163,63 @@ public:
/// ConformsTo - Caches the results of checking whether a given (canonical)
/// type conforms to a given protocol.
ConformsToMap ConformsTo;
/// \brief Retrieve the allocator for the given arena.
llvm::BumpPtrAllocator &
getAllocator(AllocationArena arena = AllocationArena::Permanent) const;
/// Allocate - Allocate memory from the ASTContext bump pointer.
void *Allocate(unsigned long Bytes, unsigned Alignment);
void *Allocate(unsigned long bytes, unsigned alignment,
AllocationArena arena = AllocationArena::Permanent) {
return getAllocator(arena).Allocate(bytes, alignment);
}
template <typename T>
T *Allocate(unsigned NElts) {
T *Res = (T*)Allocate(sizeof(T)*NElts, __alignof__(T));
for (unsigned i = 0; i != NElts; ++i)
new (Res+i) T();
return Res;
T *Allocate(unsigned numElts,
AllocationArena arena = AllocationArena::Permanent) {
T *res = (T*)Allocate(sizeof(T)*numElts, __alignof__(T), arena);
for (unsigned i = 0; i != numElts; ++i)
new (res+i) T();
return res;
}
template <typename T, typename It>
T *AllocateCopy(It Start, It End) {
T *Res = (T*)Allocate(sizeof(T)*(End-Start), __alignof__(T));
for (unsigned i = 0; Start != End; ++Start, ++i)
new (Res+i) T(*Start);
return Res;
T *AllocateCopy(It start, It end,
AllocationArena arena = AllocationArena::Permanent) {
T *res = (T*)Allocate(sizeof(T)*(end-start), __alignof__(T), arena);
for (unsigned i = 0; start != end; ++start, ++i)
new (res+i) T(*start);
return res;
}
template<typename T>
ArrayRef<T> AllocateCopy(ArrayRef<T> Arr) {
return ArrayRef<T>(AllocateCopy<T>(Arr.begin(), Arr.end()),
Arr.size());
ArrayRef<T> AllocateCopy(ArrayRef<T> array,
AllocationArena arena = AllocationArena::Permanent) {
return ArrayRef<T>(AllocateCopy<T>(array.begin(), array.end(), arena),
array.size());
}
template<typename T>
MutableArrayRef<T> AllocateCopy(MutableArrayRef<T> Arr) {
return MutableArrayRef<T>(AllocateCopy<T>(Arr.begin(), Arr.end()),
Arr.size());
MutableArrayRef<T>
AllocateCopy(MutableArrayRef<T> array,
AllocationArena arena = AllocationArena::Permanent) {
return MutableArrayRef<T>(AllocateCopy<T>(array.begin(), array.end(),arena),
array.size());
}
template<typename T>
ArrayRef<T> AllocateCopy(const SmallVectorImpl<T> &Vec) {
return AllocateCopy(ArrayRef<T>(Vec));
ArrayRef<T> AllocateCopy(const SmallVectorImpl<T> &vec,
AllocationArena arena = AllocationArena::Permanent) {
return AllocateCopy(ArrayRef<T>(vec), arena);
}
template<typename T>
MutableArrayRef<T> AllocateCopy(SmallVectorImpl<T> &Vec) {
return AllocateCopy(MutableArrayRef<T>(Vec));
MutableArrayRef<T>
AllocateCopy(SmallVectorImpl<T> &vec,
AllocationArena arena = AllocationArena::Permanent) {
return AllocateCopy(MutableArrayRef<T>(vec), arena);
}

View File

@@ -32,6 +32,7 @@ namespace llvm {
struct fltSemantics;
}
namespace swift {
enum class AllocationArena;
class ArchetypeType;
class ASTContext;
class ClassDecl;
@@ -249,8 +250,8 @@ private:
public:
// Only allow allocation of Types using the allocator in ASTContext
// or by doing a placement new.
void *operator new(size_t Bytes, ASTContext &C,
unsigned Alignment = 8);
void *operator new(size_t bytes, ASTContext &ctx, AllocationArena arena,
unsigned alignment = 8);
};
/// ErrorType - This represents a type that was erroneously constructed. This
@@ -715,10 +716,12 @@ public:
void print(raw_ostream &O) const;
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, TheDecl, Parent, GenericArgs);
bool hasTypeVariable = false;
Profile(ID, TheDecl, Parent, GenericArgs, hasTypeVariable);
}
static void Profile(llvm::FoldingSetNodeID &ID, NominalTypeDecl *TheDecl,
Type Parent, ArrayRef<Type> GenericArgs);
Type Parent, ArrayRef<Type> GenericArgs,
bool &hasTypeVariable);
// Implement isa/cast/dyncast/etc.
static bool classof(const TypeBase *T) {

View File

@@ -22,6 +22,8 @@
#include "llvm/Support/SourceMgr.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"
#include <memory>
using namespace swift;
struct ASTContext::Implementation {
@@ -30,34 +32,85 @@ struct ASTContext::Implementation {
llvm::BumpPtrAllocator Allocator; // used in later initializations
llvm::StringMap<char, llvm::BumpPtrAllocator&> IdentifierTable;
llvm::FoldingSet<TupleType> TupleTypes;
llvm::DenseMap<Type, MetaTypeType*> MetaTypeTypes;
/// \brief Structure that captures data that is segregated into different
/// arenas.
struct Arena {
llvm::FoldingSet<TupleType> TupleTypes;
llvm::DenseMap<Type, MetaTypeType*> MetaTypeTypes;
llvm::DenseMap<std::pair<Type,std::pair<Type,char>>, FunctionType*>
FunctionTypes;
llvm::DenseMap<std::pair<Type, uint64_t>, ArrayType*> ArrayTypes;
llvm::DenseMap<Type, ArraySliceType*> ArraySliceTypes;
llvm::DenseMap<Type, ParenType*> ParenTypes;
llvm::DenseMap<std::pair<Type, LValueType::Qual::opaque_type>, LValueType*>
LValueTypes;
llvm::DenseMap<std::pair<Type, Type>, SubstitutedType *> SubstitutedTypes;
llvm::FoldingSet<OneOfType> OneOfTypes;
llvm::FoldingSet<StructType> StructTypes;
llvm::FoldingSet<ClassType> ClassTypes;
llvm::FoldingSet<UnboundGenericType> UnboundGenericTypes;
llvm::FoldingSet<BoundGenericType> BoundGenericTypes;
};
llvm::DenseMap<Module*, ModuleType*> ModuleTypes;
llvm::DenseMap<std::pair<Type,std::pair<Type,char>>,
FunctionType*> FunctionTypes;
llvm::DenseMap<std::pair<Type, uint64_t>, ArrayType*> ArrayTypes;
llvm::DenseMap<Type, ArraySliceType*> ArraySliceTypes;
llvm::DenseMap<unsigned, BuiltinIntegerType*> IntegerTypes;
llvm::DenseMap<Type, ParenType*> ParenTypes;
llvm::DenseMap<std::pair<Type, LValueType::Qual::opaque_type>, LValueType*>
LValueTypes;
llvm::DenseMap<std::pair<Type, Type>, SubstitutedType *> SubstitutedTypes;
llvm::FoldingSet<OneOfType> OneOfTypes;
llvm::FoldingSet<StructType> StructTypes;
llvm::FoldingSet<ClassType> ClassTypes;
llvm::FoldingSet<ProtocolCompositionType> ProtocolCompositionTypes;
llvm::FoldingSet<UnboundGenericType> UnboundGenericTypes;
llvm::FoldingSet<BoundGenericType> BoundGenericTypes;
/// \brief The permanent arena.
Arena Permanent;
/// FIXME: Move into arena.
llvm::DenseMap<BoundGenericType *, ArrayRef<Substitution>>
BoundGenericSubstitutions;
/// \brief Temporary arena used for a constraint solver.
struct ConstraintSolverArena : public Arena {
/// \brief The allocator used for all allocations within this arena.
llvm::BumpPtrAllocator &Allocator;
ConstraintSolverArena(llvm::BumpPtrAllocator &Allocator)
: Allocator(Allocator) { }
ConstraintSolverArena(const ConstraintSolverArena &) = delete;
ConstraintSolverArena(ConstraintSolverArena &&) = delete;
ConstraintSolverArena &operator=(const ConstraintSolverArena &) = delete;
ConstraintSolverArena &operator=(ConstraintSolverArena &&) = delete;
};
/// \brief The current constraint solver arena, if any.
std::unique_ptr<ConstraintSolverArena> CurrentConstraintSolverArena;
Arena &getArena(AllocationArena arena) {
switch (arena) {
case AllocationArena::Permanent:
return Permanent;
case AllocationArena::ConstraintSolver:
assert(CurrentConstraintSolverArena && "No constraint solver active?");
return *CurrentConstraintSolverArena;
}
}
};
ASTContext::Implementation::Implementation()
: IdentifierTable(Allocator) {}
ASTContext::Implementation::~Implementation() {}
ConstraintCheckerArenaRAII::
ConstraintCheckerArenaRAII(ASTContext &self, llvm::BumpPtrAllocator &allocator)
: Self(self), Data(self.Impl.CurrentConstraintSolverArena.release())
{
Self.Impl.CurrentConstraintSolverArena.reset(
new ASTContext::Implementation::ConstraintSolverArena(allocator));
}
ConstraintCheckerArenaRAII::~ConstraintCheckerArenaRAII() {
Self.Impl.CurrentConstraintSolverArena.reset(
(ASTContext::Implementation::ConstraintSolverArena *)Data);
}
ASTContext::ASTContext(LangOptions &langOpts, llvm::SourceMgr &sourcemgr,
DiagnosticEngine &Diags)
: Impl(*new Implementation()),
@@ -65,19 +118,28 @@ ASTContext::ASTContext(LangOptions &langOpts, llvm::SourceMgr &sourcemgr,
SourceMgr(sourcemgr),
Diags(Diags),
TheBuiltinModule(new (*this) BuiltinModule(getIdentifier("Builtin"),*this)),
TheErrorType(new (*this) ErrorType(*this)),
TheErrorType(new (*this, AllocationArena::Permanent) ErrorType(*this)),
TheEmptyTupleType(TupleType::get(ArrayRef<TupleTypeElt>(), *this)),
TheObjectPointerType(new (*this) BuiltinObjectPointerType(*this)),
TheObjCPointerType(new (*this) BuiltinObjCPointerType(*this)),
TheRawPointerType(new (*this) BuiltinRawPointerType(*this)),
TheUnstructuredUnresolvedType(new (*this) UnstructuredUnresolvedType(*this)),
TheIEEE32Type(new (*this) BuiltinFloatType(BuiltinFloatType::IEEE32,*this)),
TheIEEE64Type(new (*this) BuiltinFloatType(BuiltinFloatType::IEEE64,*this)),
TheIEEE16Type(new (*this) BuiltinFloatType(BuiltinFloatType::IEEE16,*this)),
TheIEEE80Type(new (*this) BuiltinFloatType(BuiltinFloatType::IEEE80,*this)),
TheIEEE128Type(new (*this) BuiltinFloatType(BuiltinFloatType::IEEE128,
*this)),
ThePPC128Type(new (*this) BuiltinFloatType(BuiltinFloatType::PPC128,*this)){
TheObjectPointerType(new (*this, AllocationArena::Permanent)
BuiltinObjectPointerType(*this)),
TheObjCPointerType(new (*this, AllocationArena::Permanent)
BuiltinObjCPointerType(*this)),
TheRawPointerType(new (*this, AllocationArena::Permanent)
BuiltinRawPointerType(*this)),
TheUnstructuredUnresolvedType(new (*this, AllocationArena::Permanent)
UnstructuredUnresolvedType(*this)),
TheIEEE32Type(new (*this, AllocationArena::Permanent)
BuiltinFloatType(BuiltinFloatType::IEEE32,*this)),
TheIEEE64Type(new (*this, AllocationArena::Permanent)
BuiltinFloatType(BuiltinFloatType::IEEE64,*this)),
TheIEEE16Type(new (*this, AllocationArena::Permanent)
BuiltinFloatType(BuiltinFloatType::IEEE16,*this)),
TheIEEE80Type(new (*this, AllocationArena::Permanent)
BuiltinFloatType(BuiltinFloatType::IEEE80,*this)),
TheIEEE128Type(new (*this, AllocationArena::Permanent)
BuiltinFloatType(BuiltinFloatType::IEEE128, *this)),
ThePPC128Type(new (*this, AllocationArena::Permanent)
BuiltinFloatType(BuiltinFloatType::PPC128,*this)){
}
ASTContext::~ASTContext() {
@@ -87,8 +149,15 @@ ASTContext::~ASTContext() {
delete const_cast<ProtocolConformance*>(entry.second);
}
void *ASTContext::Allocate(unsigned long Bytes, unsigned Alignment) {
return Impl.Allocator.Allocate(Bytes, Alignment);
llvm::BumpPtrAllocator &ASTContext::getAllocator(AllocationArena arena) const {
switch (arena) {
case AllocationArena::Permanent:
return Impl.Allocator;
case AllocationArena::ConstraintSolver:
assert(Impl.CurrentConstraintSolverArena.get() != nullptr);
return Impl.CurrentConstraintSolverArena->Allocator;
}
}
/// getIdentifier - Return the uniqued and AST-Context-owned version of the
@@ -136,15 +205,23 @@ Type UnstructuredUnresolvedType::get(ASTContext &C) {
BuiltinIntegerType *BuiltinIntegerType::get(unsigned BitWidth, ASTContext &C) {
BuiltinIntegerType *&Result = C.Impl.IntegerTypes[BitWidth];
if (Result == 0)
Result = new (C) BuiltinIntegerType(BitWidth, C);
Result = new (C, AllocationArena::Permanent) BuiltinIntegerType(BitWidth,C);
return Result;
}
/// \brief Retrieve the arena from which we should allocate storage for a type.
static AllocationArena getArena(bool hasTypeVariable) {
return hasTypeVariable? AllocationArena::ConstraintSolver
: AllocationArena::Permanent;;
}
ParenType *ParenType::get(ASTContext &C, Type underlying) {
ParenType *&Result = C.Impl.ParenTypes[underlying];
bool hasTypeVariable = underlying->hasTypeVariable();
if (Result == 0)
Result = new (C) ParenType(underlying, hasTypeVariable);
auto arena = getArena(hasTypeVariable);
ParenType *&Result = C.Impl.getArena(arena).ParenTypes[underlying];
if (Result == 0) {
Result = new (C, arena) ParenType(underlying, hasTypeVariable);
}
return Result;
}
@@ -182,19 +259,23 @@ Type TupleType::get(ArrayRef<TupleTypeElt> Fields, ASTContext &C) {
}
}
auto arena = getArena(HasTypeVariable);
void *InsertPos = 0;
if (!HasAnyDefaultValues) {
// Check to see if we've already seen this tuple before.
llvm::FoldingSetNodeID ID;
TupleType::Profile(ID, Fields);
if (TupleType *TT = C.Impl.TupleTypes.FindNodeOrInsertPos(ID, InsertPos))
if (TupleType *TT
= C.Impl.getArena(arena).TupleTypes.FindNodeOrInsertPos(ID,InsertPos))
return TT;
}
// Make a copy of the fields list into ASTContext owned memory.
TupleTypeElt *FieldsCopy =
C.AllocateCopy<TupleTypeElt>(Fields.begin(), Fields.end());
C.AllocateCopy<TupleTypeElt>(Fields.begin(), Fields.end(), arena);
bool IsCanonical = true; // All canonical elts means this is canonical.
for (const TupleTypeElt &Elt : Fields) {
@@ -206,10 +287,10 @@ Type TupleType::get(ArrayRef<TupleTypeElt> Fields, ASTContext &C) {
Fields = ArrayRef<TupleTypeElt>(FieldsCopy, Fields.size());
TupleType *New = new (C) TupleType(Fields, IsCanonical ? &C : 0,
HasTypeVariable);
TupleType *New = new (C, arena) TupleType(Fields, IsCanonical ? &C : 0,
HasTypeVariable);
if (!HasAnyDefaultValues)
C.Impl.TupleTypes.InsertNode(New, InsertPos);
C.Impl.getArena(arena).TupleTypes.InsertNode(New, InsertPos);
return New;
}
@@ -226,24 +307,33 @@ UnboundGenericType* UnboundGenericType::get(NominalTypeDecl *TheDecl,
llvm::FoldingSetNodeID ID;
UnboundGenericType::Profile(ID, TheDecl, Parent);
void *InsertPos = 0;
if (auto unbound = C.Impl.UnboundGenericTypes.FindNodeOrInsertPos(ID,
InsertPos))
bool hasTypeVariable = Parent && Parent->hasTypeVariable();
auto arena = getArena(hasTypeVariable);
if (auto unbound = C.Impl.getArena(arena).UnboundGenericTypes
.FindNodeOrInsertPos(ID, InsertPos))
return unbound;
bool hasTypeVariable = Parent && Parent->hasTypeVariable();
auto result = new (C) UnboundGenericType(TheDecl, Parent, C, hasTypeVariable);
C.Impl.UnboundGenericTypes.InsertNode(result, InsertPos);
auto result = new (C, arena) UnboundGenericType(TheDecl, Parent, C,
hasTypeVariable);
C.Impl.getArena(arena).UnboundGenericTypes.InsertNode(result, InsertPos);
return result;
}
void BoundGenericType::Profile(llvm::FoldingSetNodeID &ID,
NominalTypeDecl *TheDecl, Type Parent,
ArrayRef<Type> GenericArgs) {
ArrayRef<Type> GenericArgs,
bool &hasTypeVariable) {
ID.AddPointer(TheDecl);
ID.AddPointer(Parent.getPointer());
if (Parent && Parent->hasTypeVariable())
hasTypeVariable = true;
ID.AddInteger(GenericArgs.size());
for (Type Arg : GenericArgs)
for (Type Arg : GenericArgs) {
ID.AddPointer(Arg.getPointer());
if (Arg->hasTypeVariable())
hasTypeVariable = true;
}
}
BoundGenericType::BoundGenericType(TypeKind theKind,
@@ -272,48 +362,44 @@ BoundGenericType *BoundGenericType::get(NominalTypeDecl *TheDecl,
ArrayRef<Type> GenericArgs) {
ASTContext &C = TheDecl->getDeclContext()->getASTContext();
llvm::FoldingSetNodeID ID;
BoundGenericType::Profile(ID, TheDecl, Parent, GenericArgs);
bool HasTypeVariable = false;
BoundGenericType::Profile(ID, TheDecl, Parent, GenericArgs, HasTypeVariable);
auto arena = getArena(HasTypeVariable);
void *InsertPos = 0;
if (BoundGenericType *BGT =
C.Impl.BoundGenericTypes.FindNodeOrInsertPos(ID, InsertPos))
C.Impl.getArena(arena).BoundGenericTypes.FindNodeOrInsertPos(ID,
InsertPos))
return BGT;
bool HasTypeVariable = Parent && Parent->hasTypeVariable();
ArrayRef<Type> ArgsCopy = C.AllocateCopy(GenericArgs);
ArrayRef<Type> ArgsCopy = C.AllocateCopy(GenericArgs, arena);
bool IsCanonical = !Parent || Parent->isCanonical();
if (IsCanonical || !HasTypeVariable) {
if (IsCanonical) {
for (Type Arg : GenericArgs) {
if (!Arg->isCanonical()) {
IsCanonical = false;
if (HasTypeVariable)
break;
}
if (Arg->hasTypeVariable()) {
HasTypeVariable = true;
if (!IsCanonical)
break;
break;
}
}
}
BoundGenericType *newType;
if (auto theClass = dyn_cast<ClassDecl>(TheDecl)) {
newType = new (C) BoundGenericClassType(theClass, Parent, ArgsCopy,
IsCanonical ? &C : 0,
HasTypeVariable);
newType = new (C, arena) BoundGenericClassType(theClass, Parent, ArgsCopy,
IsCanonical ? &C : 0,
HasTypeVariable);
} else if (auto theStruct = dyn_cast<StructDecl>(TheDecl)) {
newType = new (C) BoundGenericStructType(theStruct, Parent, ArgsCopy,
IsCanonical ? &C : 0,
HasTypeVariable);
newType = new (C, arena) BoundGenericStructType(theStruct, Parent, ArgsCopy,
IsCanonical ? &C : 0,
HasTypeVariable);
} else {
auto theOneOf = cast<OneOfDecl>(TheDecl);
newType = new (C) BoundGenericOneOfType(theOneOf, Parent, ArgsCopy,
IsCanonical ? &C : 0,
HasTypeVariable);
newType = new (C, arena) BoundGenericOneOfType(theOneOf, Parent, ArgsCopy,
IsCanonical ? &C : 0,
HasTypeVariable);
}
C.Impl.BoundGenericTypes.InsertNode(newType, InsertPos);
C.Impl.getArena(arena).BoundGenericTypes.InsertNode(newType, InsertPos);
return newType;
}
@@ -340,15 +426,18 @@ OneOfType::OneOfType(OneOfDecl *TheDecl, Type Parent, ASTContext &C,
OneOfType *OneOfType::get(OneOfDecl *D, Type Parent, ASTContext &C) {
llvm::FoldingSetNodeID id;
OneOfType::Profile(id, D,Parent);
void *insertPos = 0;
if (auto oneOfTy = C.Impl.OneOfTypes.FindNodeOrInsertPos(id, insertPos))
return oneOfTy;
OneOfType::Profile(id, D, Parent);
bool hasTypeVariable = Parent && Parent->hasTypeVariable();
auto oneOfTy = new (C) OneOfType(D, Parent, C, hasTypeVariable);
C.Impl.OneOfTypes.InsertNode(oneOfTy, insertPos);
auto arena = getArena(hasTypeVariable);
void *insertPos = 0;
if (auto oneOfTy
= C.Impl.getArena(arena).OneOfTypes.FindNodeOrInsertPos(id, insertPos))
return oneOfTy;
auto oneOfTy = new (C, arena) OneOfType(D, Parent, C, hasTypeVariable);
C.Impl.getArena(arena).OneOfTypes.InsertNode(oneOfTy, insertPos);
return oneOfTy;
}
@@ -365,13 +454,16 @@ StructType *StructType::get(StructDecl *D, Type Parent, ASTContext &C) {
llvm::FoldingSetNodeID id;
StructType::Profile(id, D, Parent);
bool hasTypeVariable = Parent && Parent->hasTypeVariable();
auto arena = getArena(hasTypeVariable);
void *insertPos = 0;
if (auto structTy = C.Impl.StructTypes.FindNodeOrInsertPos(id, insertPos))
if (auto structTy
= C.Impl.getArena(arena).StructTypes.FindNodeOrInsertPos(id, insertPos))
return structTy;
bool hasTypeVariable = Parent && Parent->hasTypeVariable();
auto structTy = new (C) StructType(D, Parent, C, hasTypeVariable);
C.Impl.StructTypes.InsertNode(structTy, insertPos);
auto structTy = new (C, arena) StructType(D, Parent, C, hasTypeVariable);
C.Impl.getArena(arena).StructTypes.InsertNode(structTy, insertPos);
return structTy;
}
@@ -388,13 +480,16 @@ ClassType *ClassType::get(ClassDecl *D, Type Parent, ASTContext &C) {
llvm::FoldingSetNodeID id;
ClassType::Profile(id, D, Parent);
bool hasTypeVariable = Parent && Parent->hasTypeVariable();
auto arena = getArena(hasTypeVariable);
void *insertPos = 0;
if (auto classTy = C.Impl.ClassTypes.FindNodeOrInsertPos(id, insertPos))
if (auto classTy
= C.Impl.getArena(arena).ClassTypes.FindNodeOrInsertPos(id, insertPos))
return classTy;
bool hasTypeVariable = Parent && Parent->hasTypeVariable();
auto classTy = new (C) ClassType(D, Parent, C, hasTypeVariable);
C.Impl.ClassTypes.InsertNode(classTy, insertPos);
auto classTy = new (C, arena) ClassType(D, Parent, C, hasTypeVariable);
C.Impl.getArena(arena).ClassTypes.InsertNode(classTy, insertPos);
return classTy;
}
@@ -406,7 +501,7 @@ void ClassType::Profile(llvm::FoldingSetNodeID &ID, ClassDecl *D, Type Parent) {
IdentifierType *IdentifierType::getNew(ASTContext &C,
MutableArrayRef<Component> Components) {
Components = C.AllocateCopy(Components);
return new (C) IdentifierType(Components);
return new (C, AllocationArena::Permanent) IdentifierType(Components);
}
ProtocolCompositionType *
@@ -426,21 +521,24 @@ ProtocolCompositionType::build(ASTContext &C, ArrayRef<Type> Protocols) {
}
// Create a new protocol composition type.
ProtocolCompositionType *New =
new (C) ProtocolCompositionType(isCanonical ? &C : nullptr,
C.AllocateCopy(Protocols));
ProtocolCompositionType *New
= new (C, AllocationArena::Permanent)
ProtocolCompositionType(isCanonical ? &C : nullptr,
C.AllocateCopy(Protocols));
C.Impl.ProtocolCompositionTypes.InsertNode(New, InsertPos);
return New;
}
MetaTypeType *MetaTypeType::get(Type T, ASTContext &C) {
MetaTypeType *&Entry = C.Impl.MetaTypeTypes[T];
bool hasTypeVariable = T->hasTypeVariable();
auto arena = getArena(hasTypeVariable);
MetaTypeType *&Entry = C.Impl.getArena(arena).MetaTypeTypes[T];
if (Entry) return Entry;
bool hasTypeVariable = T->hasTypeVariable();
return Entry = new (C) MetaTypeType(T, T->isCanonical() ? &C : 0,
hasTypeVariable);
return Entry = new (C, arena) MetaTypeType(T, T->isCanonical() ? &C : 0,
hasTypeVariable);
}
MetaTypeType::MetaTypeType(Type T, ASTContext *C, bool HasTypeVariable)
@@ -454,21 +552,21 @@ ModuleType *ModuleType::get(Module *M) {
ModuleType *&Entry = C.Impl.ModuleTypes[M];
if (Entry) return Entry;
return Entry = new (C) ModuleType(M, C);
return Entry = new (C, AllocationArena::Permanent) ModuleType(M, C);
}
/// FunctionType::get - Return a uniqued function type with the specified
/// input and result.
FunctionType *FunctionType::get(Type Input, Type Result, bool isAutoClosure,
ASTContext &C) {
FunctionType *&Entry =
C.Impl.FunctionTypes[std::make_pair(Input,
std::make_pair(Result,
(char)isAutoClosure))];
bool hasTypeVariable = Input->hasTypeVariable() || Result->hasTypeVariable();
auto arena = getArena(hasTypeVariable);
FunctionType *&Entry
= C.Impl.getArena(arena).FunctionTypes[{Input, {Result, isAutoClosure} }];
if (Entry) return Entry;
bool hasTypeVariable = Input->hasTypeVariable() || Result->hasTypeVariable();
return Entry = new (C) FunctionType(Input, Result, isAutoClosure,
return Entry = new (C, arena) FunctionType(Input, Result, isAutoClosure,
hasTypeVariable);
}
@@ -490,7 +588,10 @@ PolymorphicFunctionType *PolymorphicFunctionType::get(Type input, Type output,
GenericParamList *params,
ASTContext &C) {
// FIXME: one day we should do canonicalization properly.
return new (C) PolymorphicFunctionType(input, output, params, C);
bool hasTypeVariable = input->hasTypeVariable() || output->hasTypeVariable();
auto arena = getArena(hasTypeVariable);
return new (C, arena) PolymorphicFunctionType(input, output, params, C);
}
PolymorphicFunctionType::PolymorphicFunctionType(Type input, Type output,
@@ -511,11 +612,14 @@ PolymorphicFunctionType::PolymorphicFunctionType(Type input, Type output,
ArrayType *ArrayType::get(Type BaseType, uint64_t Size, ASTContext &C) {
assert(Size != 0);
ArrayType *&Entry = C.Impl.ArrayTypes[std::make_pair(BaseType, Size)];
bool hasTypeVariable = BaseType->hasTypeVariable();
auto arena = getArena(hasTypeVariable);
ArrayType *&Entry
= C.Impl.getArena(arena).ArrayTypes[std::make_pair(BaseType, Size)];
if (Entry) return Entry;
bool hasTypeVariable = BaseType->hasTypeVariable();
return Entry = new (C) ArrayType(BaseType, Size, hasTypeVariable);
return Entry = new (C, arena) ArrayType(BaseType, Size, hasTypeVariable);
}
ArrayType::ArrayType(Type base, uint64_t size, bool hasTypeVariable)
@@ -527,11 +631,13 @@ ArrayType::ArrayType(Type base, uint64_t size, bool hasTypeVariable)
/// Return a uniqued array slice type with the specified base type.
ArraySliceType *ArraySliceType::get(Type base, ASTContext &C) {
ArraySliceType *&entry = C.Impl.ArraySliceTypes[base];
bool hasTypeVariable = base->hasTypeVariable();
auto arena = getArena(hasTypeVariable);
ArraySliceType *&entry = C.Impl.getArena(arena).ArraySliceTypes[base];
if (entry) return entry;
bool hasTypeVariable = base->hasTypeVariable();
return entry = new (C) ArraySliceType(base, hasTypeVariable);
return entry = new (C, arena) ArraySliceType(base, hasTypeVariable);
}
ProtocolType::ProtocolType(ProtocolDecl *TheDecl, ASTContext &Ctx)
@@ -539,25 +645,30 @@ ProtocolType::ProtocolType(ProtocolDecl *TheDecl, ASTContext &Ctx)
/*HasTypeVariable=*/false) { }
LValueType *LValueType::get(Type objectTy, Qual quals, ASTContext &C) {
auto key = std::make_pair(objectTy, quals.getOpaqueData());
auto it = C.Impl.LValueTypes.find(key);
if (it != C.Impl.LValueTypes.end()) return it->second;
bool hasTypeVariable = objectTy->hasTypeVariable();
auto arena = getArena(hasTypeVariable);
auto key = std::make_pair(objectTy, quals.getOpaqueData());
auto &entry = C.Impl.getArena(arena).LValueTypes[key];
if (entry)
return entry;
ASTContext *canonicalContext = (objectTy->isCanonical() ? &C : nullptr);
LValueType *type = new (C) LValueType(objectTy, quals, canonicalContext,
hasTypeVariable);
C.Impl.LValueTypes.insert(std::make_pair(key, type));
return type;
return entry = new (C, arena) LValueType(objectTy, quals, canonicalContext,
hasTypeVariable);
}
/// Return a uniqued substituted type.
SubstitutedType *SubstitutedType::get(Type Original, Type Replacement,
ASTContext &C) {
SubstitutedType *&Known = C.Impl.SubstitutedTypes[{Original, Replacement}];
bool hasTypeVariable = Replacement->hasTypeVariable();
auto arena = getArena(hasTypeVariable);
SubstitutedType *&Known
= C.Impl.getArena(arena).SubstitutedTypes[{Original, Replacement}];
if (!Known) {
bool hasTypeVariable = Replacement->hasTypeVariable();
Known = new (C) SubstitutedType(Original, Replacement, hasTypeVariable);
Known = new (C, arena) SubstitutedType(Original, Replacement,
hasTypeVariable);
}
return Known;
}

View File

@@ -371,7 +371,7 @@ TypeAliasDecl::TypeAliasDecl(SourceLoc TypeAliasLoc, Identifier Name,
{
// Set the type of the TypeAlias to the right MetaTypeType.
ASTContext &Ctx = getASTContext();
AliasTy = new (Ctx) NameAliasType(this);
AliasTy = new (Ctx, AllocationArena::Permanent) NameAliasType(this);
setType(MetaTypeType::get(AliasTy, Ctx));
}
@@ -451,7 +451,7 @@ ProtocolDecl::ProtocolDecl(DeclContext *DC, SourceLoc ProtocolLoc,
{
// Compute the associated type for this ClassDecl.
ASTContext &Ctx = DC->getASTContext();
DeclaredTy = new (Ctx) ProtocolType(this, Ctx);
DeclaredTy = new (Ctx, AllocationArena::Permanent) ProtocolType(this, Ctx);
// Set the type of the ProtocolDecl to the right MetaTypeType.
setType(MetaTypeType::get(DeclaredTy, Ctx));
}

View File

@@ -28,9 +28,9 @@
using namespace swift;
// Only allow allocation of Stmts using the allocator in ASTContext.
void *TypeBase::operator new(size_t Bytes, ASTContext &C,
unsigned Alignment) {
return C.Allocate(Bytes, Alignment);
void *TypeBase::operator new(size_t bytes, ASTContext &ctx,
AllocationArena arena, unsigned alignment) {
return ctx.Allocate(bytes, alignment, arena);
}
bool CanType::isActuallyCanonicalOrNull() const {
@@ -896,9 +896,10 @@ ArchetypeType *ArchetypeType::getNew(ASTContext &Ctx, ArchetypeType *Parent,
llvm::array_pod_sort(ConformsToProtos.begin(), ConformsToProtos.end(),
compareProtocols);
return new (Ctx) ArchetypeType(Ctx, Parent, Name,
Ctx.AllocateCopy(ConformsToProtos),
Index);
auto arena = AllocationArena::Permanent;
return new (Ctx, arena) ArchetypeType(Ctx, Parent, Name,
Ctx.AllocateCopy(ConformsToProtos),
Index);
}
ArchetypeType *
@@ -910,8 +911,9 @@ ArchetypeType::getNew(ASTContext &Ctx, ArchetypeType *Parent,
minimizeProtocols(ConformsTo);
llvm::array_pod_sort(ConformsTo.begin(), ConformsTo.end(), compareProtocols);
return new (Ctx) ArchetypeType(Ctx, Parent, Name,
Ctx.AllocateCopy(ConformsTo), Index);
auto arena = AllocationArena::Permanent;
return new (Ctx, arena) ArchetypeType(Ctx, Parent, Name,
Ctx.AllocateCopy(ConformsTo), Index);
}
namespace {
@@ -974,7 +976,8 @@ DeducibleGenericParamType *
DeducibleGenericParamType::getNew(ASTContext &Ctx,
DeducibleGenericParamType *Parent,
ArchetypeType *Archetype) {
return new (Ctx) DeducibleGenericParamType(Ctx, Parent, Archetype);
auto arena = AllocationArena::Permanent;
return new (Ctx, arena) DeducibleGenericParamType(Ctx, Parent, Archetype);
}
void ProtocolCompositionType::Profile(llvm::FoldingSetNodeID &ID,

View File

@@ -762,6 +762,13 @@ namespace {
/// \brief Allocator used for all of the related constraint systems.
llvm::BumpPtrAllocator Allocator;
/// \brief Arena used for memory management of constraint-checker-related
/// allocations.
///
/// This arena will automatically be destroyed when the top constraint
/// system is destroyed.
ConstraintCheckerArenaRAII Arena;
/// \brief Counter for type variables introduced.
unsigned TypeCounter = 0;
@@ -774,6 +781,9 @@ namespace {
/// \brief Cached literal checks.
std::map<std::pair<TypeBase *, LiteralKind>, bool> LiteralChecks;
public:
SharedStateType(TypeChecker &tc) : Arena(tc.Context, Allocator) {}
};
/// \brief The state shared among all of the related constraint systems.
@@ -846,8 +856,8 @@ namespace {
friend class OverloadSet;
public:
ConstraintSystem(TypeChecker &TC)
: TC(TC), SharedState(new SharedStateType)
ConstraintSystem(TypeChecker &tc)
: TC(tc), SharedState(new SharedStateType(tc))
{
++NumExploredConstraintSystems;
}