Reduce malloc() traffic of clang_getOverridenCursors() by using a pool of SmallVector<CXCursor> objects

under the covers.

Fixes <rdar://problem/11289160>.

llvm-svn: 155841
This commit is contained in:
Ted Kremenek 2012-04-30 19:06:49 +00:00
parent 5b7e08c9d8
commit d77f6219de
4 changed files with 113 additions and 32 deletions

View File

@ -61,6 +61,7 @@ CXTranslationUnit cxtu::MakeCXTranslationUnit(CIndexer *CIdx, ASTUnit *TU) {
D->TUData = TU;
D->StringPool = createCXStringPool();
D->Diagnostics = 0;
D->OverridenCursorsPool = createOverridenCXCursorsPool();
return D;
}
@ -2734,6 +2735,7 @@ void clang_disposeTranslationUnit(CXTranslationUnit CTUnit) {
delete static_cast<ASTUnit *>(CTUnit->TUData);
disposeCXStringPool(CTUnit->StringPool);
delete static_cast<CXDiagnosticSetImpl *>(CTUnit->Diagnostics);
disposeOverridenCXCursorsPool(CTUnit->OverridenCursorsPool);
delete CTUnit;
}
}
@ -5549,34 +5551,6 @@ CXCursor clang_getCursorLexicalParent(CXCursor cursor) {
return clang_getNullCursor();
}
void clang_getOverriddenCursors(CXCursor cursor,
CXCursor **overridden,
unsigned *num_overridden) {
if (overridden)
*overridden = 0;
if (num_overridden)
*num_overridden = 0;
if (!overridden || !num_overridden)
return;
if (!clang_isDeclaration(cursor.kind))
return;
SmallVector<CXCursor, 8> Overridden;
cxcursor::getOverriddenCursors(cursor, Overridden);
// Don't allocate memory if we have no overriden cursors.
if (Overridden.size() == 0)
return;
*num_overridden = Overridden.size();
*overridden = new CXCursor [Overridden.size()];
std::copy(Overridden.begin(), Overridden.end(), *overridden);
}
void clang_disposeOverriddenCursors(CXCursor *overridden) {
delete [] overridden;
}
CXFile clang_getIncludedFile(CXCursor cursor) {
if (cursor.kind != CXCursor_InclusionDirective)
return 0;

View File

@ -30,9 +30,9 @@
using namespace clang;
using namespace cxcursor;
CXCursor cxcursor::MakeCXCursorInvalid(CXCursorKind K) {
CXCursor cxcursor::MakeCXCursorInvalid(CXCursorKind K, CXTranslationUnit TU) {
assert(K >= CXCursor_FirstInvalid && K <= CXCursor_LastInvalid);
CXCursor C = { K, 0, { 0, 0, 0 } };
CXCursor C = { K, 0, { 0, 0, TU } };
return C;
}
@ -1152,5 +1152,104 @@ CXCompletionString clang_getCursorCompletionString(CXCursor cursor) {
}
return NULL;
}
namespace {
struct OverridenCursorsPool {
typedef llvm::SmallVector<CXCursor, 2> CursorVec;
std::vector<CursorVec*> AllCursors;
std::vector<CursorVec*> AvailableCursors;
~OverridenCursorsPool() {
for (std::vector<CursorVec*>::iterator I = AllCursors.begin(),
E = AllCursors.end(); I != E; ++I) {
delete *I;
}
}
};
}
void *cxcursor::createOverridenCXCursorsPool() {
return new OverridenCursorsPool();
}
void cxcursor::disposeOverridenCXCursorsPool(void *pool) {
delete static_cast<OverridenCursorsPool*>(pool);
}
void clang_getOverriddenCursors(CXCursor cursor,
CXCursor **overridden,
unsigned *num_overridden) {
if (overridden)
*overridden = 0;
if (num_overridden)
*num_overridden = 0;
CXTranslationUnit TU = cxcursor::getCursorTU(cursor);
if (!overridden || !num_overridden || !TU)
return;
if (!clang_isDeclaration(cursor.kind))
return;
OverridenCursorsPool &pool =
*static_cast<OverridenCursorsPool*>(TU->OverridenCursorsPool);
OverridenCursorsPool::CursorVec *Vec = 0;
if (!pool.AvailableCursors.empty()) {
Vec = pool.AvailableCursors.back();
pool.AvailableCursors.pop_back();
}
else {
Vec = new OverridenCursorsPool::CursorVec();
pool.AllCursors.push_back(Vec);
}
// Clear out the vector, but don't free the memory contents. This
// reduces malloc() traffic.
Vec->clear();
// Use the first entry to contain a back reference to the vector.
// This is a complete hack.
CXCursor backRefCursor = MakeCXCursorInvalid(CXCursor_InvalidFile, TU);
backRefCursor.data[0] = Vec;
assert(cxcursor::getCursorTU(backRefCursor) == TU);
Vec->push_back(backRefCursor);
// Get the overriden cursors.
cxcursor::getOverriddenCursors(cursor, *Vec);
// Did we get any overriden cursors? If not, return Vec to the pool
// of available cursor vectors.
if (Vec->size() == 1) {
pool.AvailableCursors.push_back(Vec);
return;
}
// Now tell the caller about the overriden cursors.
assert(Vec->size() > 1);
*overridden = &((*Vec)[1]);
*num_overridden = Vec->size() - 1;
}
void clang_disposeOverriddenCursors(CXCursor *overridden) {
if (!overridden)
return;
// Use pointer arithmetic to get back the first faux entry
// which has a back-reference to the TU and the vector.
--overridden;
OverridenCursorsPool::CursorVec *Vec =
static_cast<OverridenCursorsPool::CursorVec*>(overridden->data[0]);
CXTranslationUnit TU = getCursorTU(*overridden);
assert(Vec && TU);
OverridenCursorsPool &pool =
*static_cast<OverridenCursorsPool*>(TU->OverridenCursorsPool);
pool.AvailableCursors.push_back(Vec);
}
} // end: extern "C"

View File

@ -55,7 +55,7 @@ CXCursor MakeCXCursor(clang::Decl *D, CXTranslationUnit TU,
CXCursor MakeCXCursor(clang::Stmt *S, clang::Decl *Parent,
CXTranslationUnit TU,
SourceRange RegionOfInterest = SourceRange());
CXCursor MakeCXCursorInvalid(CXCursorKind K);
CXCursor MakeCXCursorInvalid(CXCursorKind K, CXTranslationUnit TU = 0);
/// \brief Create an Objective-C superclass reference at the given location.
CXCursor MakeCursorObjCSuperClassRef(ObjCInterfaceDecl *Super,
@ -206,8 +206,15 @@ ASTUnit *getCursorASTUnit(CXCursor Cursor);
CXTranslationUnit getCursorTU(CXCursor Cursor);
void getOverriddenCursors(CXCursor cursor,
SmallVectorImpl<CXCursor> &overridden);
SmallVectorImpl<CXCursor> &overridden);
/// \brief Create an opaque pool used for fast generation of overriden
/// CXCursor arrays.
void *createOverridenCXCursorsPool();
/// \brief Dispose of the overriden CXCursors pool.
void disposeOverridenCXCursorsPool(void *pool);
/// \brief Returns a index/location pair for a selector identifier if the cursor
/// points to one.
std::pair<int, SourceLocation> getSelectorIdentifierIndexAndLoc(CXCursor);

View File

@ -20,6 +20,7 @@ struct CXTranslationUnitImpl {
void *TUData;
void *StringPool;
void *Diagnostics;
void *OverridenCursorsPool;
};
}