Cache the class hierarchy construction.

Before this commit we scanned the vtables every time we wanted to know who are the subclasses of a class. Now we scan the vtables just once.



Swift SVN r20847
This commit is contained in:
Nadav Rotem
2014-07-31 21:07:11 +00:00
parent a627411b43
commit 1b980052b1
3 changed files with 24 additions and 34 deletions

View File

@@ -18,6 +18,7 @@
#include "swift/SIL/SILValue.h" #include "swift/SIL/SILValue.h"
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/Debug.h" #include "llvm/Support/Debug.h"
namespace swift { namespace swift {
@@ -26,6 +27,10 @@ class SILModule;
class ClassDecl; class ClassDecl;
class ClassHierarchyAnalysis : public SILAnalysis { class ClassHierarchyAnalysis : public SILAnalysis {
public: public:
typedef llvm::SmallVector<ClassDecl*, 8> ClassList;
typedef llvm::SmallPtrSet<ClassDecl *, 32> ClassSet;
ClassHierarchyAnalysis(SILModule *Mod) : ClassHierarchyAnalysis(SILModule *Mod) :
SILAnalysis(AnalysisKind::ClassHierarchyAnalysis), M(Mod) { SILAnalysis(AnalysisKind::ClassHierarchyAnalysis), M(Mod) {
init(); init();
@@ -39,18 +44,19 @@ public:
virtual void invalidate(InvalidationKind K) { virtual void invalidate(InvalidationKind K) {
if (K >= InvalidationKind::All) { if (K >= InvalidationKind::All) {
InheritedClasses.clear(); SubclassesCache.clear();
init(); init();
} }
} }
/// \brief Collect all of the known direct subclasses of a class \p C in the
/// current module. /// \returns a list of the known direct subclasses of a class \p C in
void collectSubClasses(ClassDecl *C, std::vector<ClassDecl*> &Sub); /// the current module.
ClassList& getSubClasses(ClassDecl *C) { return SubclassesCache[C]; }
/// \returns True if the class is inherited by another class in this module. /// \returns True if the class is inherited by another class in this module.
bool inheritedInModule(ClassDecl *CD) { bool inheritedInModule(ClassDecl *CD) {
return InheritedClasses.count(CD); return SubclassesCache.count(CD);
} }
virtual void invalidate(SILFunction *F, InvalidationKind K) { virtual void invalidate(SILFunction *F, InvalidationKind K) {
@@ -58,16 +64,15 @@ public:
} }
private: private:
// Compute inheritance properties. /// Compute inheritance properties.
void init(); void init();
// The module /// The module
SILModule *M; SILModule *M;
// Stores the set of inherited classes. /// A cache that maps a class to all of its known subclasses.
llvm::SmallPtrSet<ClassDecl *, 32> InheritedClasses; llvm::DenseMap<ClassDecl*, ClassList> SubclassesCache;
}; };
} }
#endif #endif

View File

@@ -29,28 +29,10 @@ void ClassHierarchyAnalysis::init() {
// Add the superclass to the list of inherited classes. // Add the superclass to the list of inherited classes.
ClassDecl *Super = C->getSuperclass()->getClassOrBoundGenericClass(); ClassDecl *Super = C->getSuperclass()->getClassOrBoundGenericClass();
InheritedClasses.insert(Super); auto &K = SubclassesCache[Super];
} assert(std::find(K.begin(), K.end(), C) == K.end() &&
} "Class vector must be unique");
K.push_back(C);
void ClassHierarchyAnalysis::collectSubClasses(ClassDecl *C,
std::vector<ClassDecl*> &Sub) {
// TODO: Cache this search.
assert(Sub.empty() && "Incoming list is not empty");
SmallVector<ClassDecl*, 4> Path;
for (auto &VT : M->getVTableList()) {
ClassDecl *CD = VT.getClass();
while (CD->hasSuperclass()) {
Path.push_back(CD);
// Add the superclass to the list of inherited classes.
ClassDecl *Super = CD->getSuperclass()->getClassOrBoundGenericClass();
if (Super == C) {
Sub.insert(Sub.end(), Path.begin(), Path.end());
break;
}
CD = Super;
}
Path.clear();
} }
} }

View File

@@ -955,8 +955,8 @@ static bool insertInlineCaches(ApplyInst *AI, ClassHierarchyAnalysis *CHA) {
return insertMonomorphicInlineCaches(AI, InstanceType); return insertMonomorphicInlineCaches(AI, InstanceType);
} }
std::vector<ClassDecl*> Subs; // Collect the subclasses for the class.
CHA->collectSubClasses(CD, Subs); ClassHierarchyAnalysis::ClassList &Subs = CHA->getSubClasses(CD);
if (Subs.size() > MaxNumPolymorphicInlineCaches) { if (Subs.size() > MaxNumPolymorphicInlineCaches) {
DEBUG(llvm::dbgs() << "Class " << CD->getName() << " has too many (" << DEBUG(llvm::dbgs() << "Class " << CD->getName() << " has too many (" <<
@@ -969,6 +969,9 @@ static bool insertInlineCaches(ApplyInst *AI, ClassHierarchyAnalysis *CHA) {
// Generate the polymorphic inline cache using multiple monomorphic caches. // Generate the polymorphic inline cache using multiple monomorphic caches.
for (auto S : Subs) { for (auto S : Subs) {
DEBUG(llvm::dbgs() << "Inserting a cache for class " << CD->getName() <<
" and subclass " << S->getName() << "\n");
CanType CanClassType = S->getDeclaredType()->getCanonicalType(); CanType CanClassType = S->getDeclaredType()->getCanonicalType();
SILType InstanceType = SILType::getPrimitiveObjectType(CanClassType); SILType InstanceType = SILType::getPrimitiveObjectType(CanClassType);
if (!InstanceType.getClassOrBoundGenericClass()) if (!InstanceType.getClassOrBoundGenericClass())