mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
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:
@@ -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
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
Reference in New Issue
Block a user