Layering refinements for selectors (suggested by Chris). Specifics...

- Add SelectorTable, which enables us to remove MultiKeywordSelector from the public header.
- Remove FoldingSet from IdentifierInfo.h and Preprocessor.h.
- Remove Parser::ObjcGetUnarySelector and Parser::ObjcGetKeywordSelector, they are subsumed by SelectorTable.
- Add MultiKeywordSelector to IdentifierInfo.cpp.
- Move a bunch of selector related methods from ParseObjC.cpp to IdentifierInfo.cpp.
- Added some comments.

llvm-svn: 42643
This commit is contained in:
Steve Naroff 2007-10-05 18:42:47 +00:00
parent aac0f8e351
commit e61bfa8bb4
7 changed files with 192 additions and 160 deletions

View File

@ -15,6 +15,7 @@
#include "clang/Lex/IdentifierTable.h"
#include "clang/Lex/MacroInfo.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/ADT/FoldingSet.h"
using namespace clang;
//===----------------------------------------------------------------------===//
@ -210,3 +211,150 @@ void IdentifierTable::PrintStats() const {
HashTable.getAllocator().PrintStats();
}
//===----------------------------------------------------------------------===//
// SelectorTable Implementation
//===----------------------------------------------------------------------===//
/// MultiKeywordSelector - One of these variable length records is kept for each
/// selector containing more than one keyword. We use a folding set
/// to unique aggregate names (keyword selectors in ObjC parlance). Access to
/// this class is provided strictly through Selector.
class MultiKeywordSelector : public llvm::FoldingSetNode {
public:
unsigned NumArgs;
// Constructor for keyword selectors.
MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) {
assert((nKeys > 1) && "not a multi-keyword selector");
NumArgs = nKeys;
// Fill in the trailing keyword array.
IdentifierInfo **KeyInfo = reinterpret_cast<IdentifierInfo **>(this+1);
for (unsigned i = 0; i != nKeys; ++i)
KeyInfo[i] = IIV[i];
}
// Derive the full selector name, placing the result into methodBuffer.
// As a convenience, a pointer to the first character is returned.
// Example usage: llvm::SmallString<128> mbuf; Selector->getName(mbuf);
char *getName(llvm::SmallVectorImpl<char> &methodBuffer);
unsigned getNumArgs() const { return NumArgs; }
typedef IdentifierInfo *const *keyword_iterator;
keyword_iterator keyword_begin() const {
return reinterpret_cast<keyword_iterator>(this+1);
}
keyword_iterator keyword_end() const {
return keyword_begin()+NumArgs;
}
IdentifierInfo *getIdentifierInfoForSlot(unsigned i) {
assert((i < NumArgs) && "getIdentifierInfoForSlot(): illegal index");
return keyword_begin()[i];
}
static void Profile(llvm::FoldingSetNodeID &ID,
keyword_iterator ArgTys, unsigned NumArgs) {
ID.AddInteger(NumArgs);
if (NumArgs) { // handle keyword selector.
for (unsigned i = 0; i != NumArgs; ++i)
ID.AddPointer(ArgTys[i]);
} else // handle unary selector.
ID.AddPointer(ArgTys[0]);
}
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, keyword_begin(), NumArgs);
}
};
unsigned Selector::getNumArgs() const {
unsigned IIF = getIdentifierInfoFlag();
if (IIF == ZeroArg)
return 0;
if (IIF == OneArg)
return 1;
// We point to a MultiKeywordSelector (pointer doesn't contain any flags).
MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr);
return SI->getNumArgs();
}
IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) {
IdentifierInfo *II = getAsIdentifierInfo();
if (II) {
assert(((argIndex == 0) || (argIndex == 1)) && "illegal keyword index");
return II;
}
// We point to a MultiKeywordSelector (pointer doesn't contain any flags).
MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr);
return SI->getIdentifierInfoForSlot(argIndex);
}
char *MultiKeywordSelector::getName(llvm::SmallVectorImpl<char> &methodName) {
methodName[0] = '\0';
keyword_iterator KeyIter = keyword_begin();
for (unsigned int i = 0; i < NumArgs; i++) {
if (KeyIter[i]) {
unsigned KeyLen = KeyIter[i]->getLength();
methodName.append(KeyIter[i]->getName(), KeyIter[i]->getName()+KeyLen);
}
methodName.push_back(':');
}
methodName.push_back('\0');
return &methodName[0];
}
char *Selector::getName(llvm::SmallVectorImpl<char> &methodName) {
methodName[0] = '\0';
IdentifierInfo *II = getAsIdentifierInfo();
if (II) {
unsigned NameLen = II->getLength();
methodName.append(II->getName(), II->getName()+NameLen);
if (getNumArgs() == 1)
methodName.push_back(':');
methodName.push_back('\0');
} else { // We have a multiple keyword selector (no embedded flags).
MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr);
SI->getName(methodName);
}
return &methodName[0];
}
Selector SelectorTable::getKeywordSelector(unsigned nKeys, IdentifierInfo **IIV)
{
llvm::FoldingSet<MultiKeywordSelector> *SelTab;
SelTab = static_cast<llvm::FoldingSet<MultiKeywordSelector> *>(Impl);
// Unique selector, to guarantee there is one per name.
llvm::FoldingSetNodeID ID;
MultiKeywordSelector::Profile(ID, IIV, nKeys);
void *InsertPos = 0;
if (MultiKeywordSelector *SI = SelTab->FindNodeOrInsertPos(ID, InsertPos)) {
return Selector(SI);
}
// MultiKeywordSelector objects are not allocated with new because they have a
// variable size array (for parameter types) at the end of them.
MultiKeywordSelector *SI =
(MultiKeywordSelector*)malloc(sizeof(MultiKeywordSelector) +
nKeys*sizeof(IdentifierInfo *));
new (SI) MultiKeywordSelector(nKeys, IIV);
SelTab->InsertNode(SI, InsertPos);
return Selector(SI);
}
Selector SelectorTable::getUnarySelector(IdentifierInfo *ID) {
return Selector(ID, 1);
}
Selector SelectorTable::getNullarySelector(IdentifierInfo *ID) {
return Selector(ID, 0);
}
SelectorTable::SelectorTable() {
Impl = new llvm::FoldingSet<MultiKeywordSelector>;
}
SelectorTable::~SelectorTable() {
delete static_cast<llvm::FoldingSet<MultiKeywordSelector> *>(Impl);
}

View File

@ -500,89 +500,6 @@ Parser::TypeTy *Parser::ParseObjCTypeName() {
return Ty;
}
unsigned Selector::getNumArgs() const {
unsigned IIF = getIdentifierInfoFlag();
if (IIF == ZeroArg)
return 0;
if (IIF == OneArg)
return 1;
// We point to a MultiKeywordSelector (pointer doesn't contain any flags).
MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr);
return SI->getNumArgs();
}
IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) {
IdentifierInfo *II = getAsIdentifierInfo();
if (II) {
assert(((argIndex == 0) || (argIndex == 1)) && "illegal keyword index");
return II;
}
// We point to a MultiKeywordSelector (pointer doesn't contain any flags).
MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr);
return SI->getIdentifierInfoForSlot(argIndex);
}
char *MultiKeywordSelector::getName(llvm::SmallVectorImpl<char> &methodName) {
methodName[0] = '\0';
keyword_iterator KeyIter = keyword_begin();
for (unsigned int i = 0; i < NumArgs; i++) {
if (KeyIter[i]) {
unsigned KeyLen = KeyIter[i]->getLength();
methodName.append(KeyIter[i]->getName(), KeyIter[i]->getName()+KeyLen);
}
methodName.push_back(':');
}
methodName.push_back('\0');
return &methodName[0];
}
char *Selector::getName(llvm::SmallVectorImpl<char> &methodName) {
methodName[0] = '\0';
IdentifierInfo *II = getAsIdentifierInfo();
if (II) {
unsigned NameLen = II->getLength();
methodName.append(II->getName(), II->getName()+NameLen);
if (getNumArgs() == 1)
methodName.push_back(':');
methodName.push_back('\0');
} else { // We have a multiple keyword selector (no embedded flags).
MultiKeywordSelector *SI = reinterpret_cast<MultiKeywordSelector *>(InfoPtr);
SI->getName(methodName);
}
return &methodName[0];
}
Selector Parser::ObjcGetUnarySelector(IdentifierInfo *unarySel)
{
return Selector(unarySel, 0);
}
Selector Parser::ObjcGetKeywordSelector(
llvm::SmallVectorImpl<IdentifierInfo *> &IIV)
{
if (IIV.size() == 1)
return Selector(IIV[0], 1);
llvm::FoldingSet<MultiKeywordSelector> &SelTab = PP.getSelectorTable();
// Unique selector, to guarantee there is one per name.
llvm::FoldingSetNodeID ID;
MultiKeywordSelector::Profile(ID, &IIV[0], IIV.size());
void *InsertPos = 0;
if (MultiKeywordSelector *SI = SelTab.FindNodeOrInsertPos(ID, InsertPos)) {
return Selector(SI);
}
// MultiKeywordSelector objects are not allocated with new because they have a
// variable size array (for parameter types) at the end of them.
MultiKeywordSelector *SI =
(MultiKeywordSelector*)malloc(sizeof(MultiKeywordSelector) +
IIV.size()*sizeof(IdentifierInfo *));
new (SI) MultiKeywordSelector(IIV.size(), &IIV[0]);
SelTab.InsertNode(SI, InsertPos);
return Selector(SI);
}
/// objc-method-decl:
/// objc-selector
/// objc-keyword-selector objc-parmlist[opt]
@ -680,8 +597,11 @@ Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType,
// If attributes exist after the method, parse them.
if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
methodAttrs = ParseAttributes();
Selector Sel = ObjcGetKeywordSelector(KeyIdents);
unsigned nKeys = KeyIdents.size();
Selector Sel = (nKeys == 1) ?
PP.getSelectorTable().getUnarySelector(KeyIdents[0]) :
PP.getSelectorTable().getKeywordSelector(nKeys, &KeyIdents[0]);
return Actions.ActOnMethodDeclaration(mLoc, mType, ReturnType, Sel,
&KeyTypes[0], &ArgNames[0],
methodAttrs, MethodImplKind);
@ -692,7 +612,7 @@ Parser::DeclTy *Parser::ParseObjCMethodDecl(tok::TokenKind mType,
if (getLang().ObjC2 && Tok.getKind() == tok::kw___attribute)
methodAttrs = ParseAttributes();
Selector Sel = ObjcGetUnarySelector(selIdent);
Selector Sel = PP.getSelectorTable().getNullarySelector(selIdent);
return Actions.ActOnMethodDeclaration(mLoc, mType, ReturnType, Sel,
0, 0, methodAttrs, MethodImplKind);
}
@ -1290,21 +1210,24 @@ Parser::ExprResult Parser::ParseObjCMessageExpression() {
}
SourceLocation RBracloc = ConsumeBracket(); // consume ']'
if (KeyIdents.size()) {
Selector sel = ObjcGetKeywordSelector(KeyIdents);
unsigned nKeys = KeyIdents.size();
if (nKeys) {
Selector Sel = (nKeys == 1) ?
PP.getSelectorTable().getUnarySelector(KeyIdents[0]) :
PP.getSelectorTable().getKeywordSelector(nKeys, &KeyIdents[0]);
// We've just parsed a keyword message.
if (ReceiverName)
return Actions.ActOnClassMessage(ReceiverName, sel, LBracloc, RBracloc,
return Actions.ActOnClassMessage(ReceiverName, Sel, LBracloc, RBracloc,
&KeyExprs[0]);
return Actions.ActOnInstanceMessage(ReceiverExpr, sel, LBracloc, RBracloc,
return Actions.ActOnInstanceMessage(ReceiverExpr, Sel, LBracloc, RBracloc,
&KeyExprs[0]);
}
Selector sel = ObjcGetUnarySelector(selIdent);
Selector Sel = PP.getSelectorTable().getNullarySelector(selIdent);
// We've just parsed a unary message (a message with no arguments).
if (ReceiverName)
return Actions.ActOnClassMessage(ReceiverName, sel, LBracloc, RBracloc, 0);
return Actions.ActOnInstanceMessage(ReceiverExpr, sel, LBracloc, RBracloc, 0);
return Actions.ActOnClassMessage(ReceiverName, Sel, LBracloc, RBracloc, 0);
return Actions.ActOnInstanceMessage(ReceiverExpr, Sel, LBracloc, RBracloc, 0);
}
Parser::ExprResult Parser::ParseObjCStringLiteral() {

View File

@ -737,7 +737,6 @@
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "clang" */;
compatibilityVersion = "Xcode 2.4";
hasScannedForEncodings = 1;
mainGroup = 08FB7794FE84155DC02AAC07 /* clang */;
projectDirPath = "";

View File

@ -47,7 +47,7 @@ public:
SourceManager &SourceMgr;
TargetInfo &Target;
IdentifierTable &Idents;
llvm::FoldingSet<MultiKeywordSelector> &Selectors;
SelectorTable &Selectors;
Builtin::Context BuiltinInfo;
// Builtin Types.
@ -61,7 +61,7 @@ public:
QualType FloatComplexTy, DoubleComplexTy, LongDoubleComplexTy;
ASTContext(SourceManager &SM, TargetInfo &t, IdentifierTable &idents,
llvm::FoldingSet<MultiKeywordSelector> &sels) :
SelectorTable &sels) :
CFConstantStringTypeDecl(0), SourceMgr(SM), Target(t),
Idents(idents), Selectors(sels) {
InitBuiltinTypes();

View File

@ -18,11 +18,12 @@
// this data is long-lived.
#include "clang/Basic/TokenKinds.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/SmallString.h"
#include <string>
#include <cassert>
class MultiKeywordSelector; // a private class used by Selector.
namespace clang {
class MacroInfo;
struct LangOptions;
@ -135,8 +136,6 @@ public:
void setFETokenInfo(void *T) { FETokenInfo = T; }
};
/// IdentifierTable - This table implements an efficient mapping from strings to
/// IdentifierInfo nodes. It has no other purpose, but this is an
/// extremely performance-critical piece of the code, as each occurrance of
@ -179,59 +178,11 @@ private:
void AddKeywords(const LangOptions &LangOpts);
};
/// MultiKeywordSelector - One of these variable length records is kept for each
/// selector containing more than one keyword. We use a folding set
/// to unique aggregate names (keyword selectors in ObjC parlance). Access to
/// this class is provided strictly through Selector. All methods are private.
/// The only reason it appears in this header is FoldingSet needs to see it:-(
class MultiKeywordSelector : public llvm::FoldingSetNode {
friend class Selector; // Only Selector can access me.
friend class Parser; // Only Parser can instantiate me.
unsigned NumArgs;
// Constructor for keyword selectors.
MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) {
assert((nKeys > 1) && "not a multi-keyword selector");
NumArgs = nKeys;
// Fill in the trailing keyword array.
IdentifierInfo **KeyInfo = reinterpret_cast<IdentifierInfo **>(this+1);
for (unsigned i = 0; i != nKeys; ++i)
KeyInfo[i] = IIV[i];
}
// Derive the full selector name, placing the result into methodBuffer.
// As a convenience, a pointer to the first character is returned.
// Example usage: llvm::SmallString<128> mbuf; Selector->getName(mbuf);
char *getName(llvm::SmallVectorImpl<char> &methodBuffer);
unsigned getNumArgs() const { return NumArgs; }
typedef IdentifierInfo *const *keyword_iterator;
keyword_iterator keyword_begin() const {
return reinterpret_cast<keyword_iterator>(this+1);
}
keyword_iterator keyword_end() const {
return keyword_begin()+NumArgs;
}
IdentifierInfo *getIdentifierInfoForSlot(unsigned i) {
assert((i < NumArgs) && "getIdentifierInfoForSlot(): illegal index");
return keyword_begin()[i];
}
friend class llvm::FoldingSet<MultiKeywordSelector>;
static void Profile(llvm::FoldingSetNodeID &ID,
keyword_iterator ArgTys, unsigned NumArgs) {
ID.AddInteger(NumArgs);
if (NumArgs) { // handle keyword selector.
for (unsigned i = 0; i != NumArgs; ++i)
ID.AddPointer(ArgTys[i]);
} else // handle unary selector.
ID.AddPointer(ArgTys[0]);
}
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, keyword_begin(), NumArgs);
}
};
/// Selector - This smart pointer class efficiently represents Objective-C
/// method names. This class will either point to an IdentifierInfo or a
/// MultiKeywordSelector (which is private). This enables us to optimize
/// selectors that no arguments and selectors that take 1 argument, which
/// accounts for 78% of all selectors in Cocoa.h.
class Selector {
enum IdentifierInfoFlag {
// MultiKeywordSelector = 0.
@ -251,14 +202,14 @@ class Selector {
InfoPtr = reinterpret_cast<uintptr_t>(SI);
assert((InfoPtr & ArgFlags) == 0 &&"Insufficiently aligned IdentifierInfo");
}
friend class Parser; // only the Parser can create these.
public:
friend class SelectorTable; // only the SelectorTable can create these.
IdentifierInfo *getAsIdentifierInfo() const {
if (getIdentifierInfoFlag())
return reinterpret_cast<IdentifierInfo *>(InfoPtr & ~ArgFlags);
return 0;
}
public:
unsigned getIdentifierInfoFlag() const {
return InfoPtr & ArgFlags;
}
@ -288,6 +239,21 @@ public:
char *getName(llvm::SmallVectorImpl<char> &methodBuffer);
};
/// SelectorTable - This table allows us to fully hide how we implement
/// multi-keyword caching.
class SelectorTable {
void *Impl; // Actually a FoldingSet<MultiKeywordSelector>*
SelectorTable(const SelectorTable&); // DISABLED: DO NOT IMPLEMENT
void operator=(const SelectorTable&); // DISABLED: DO NOT IMPLEMENT
public:
SelectorTable();
~SelectorTable();
Selector getKeywordSelector(unsigned nKeys, IdentifierInfo **IIV);
Selector getUnarySelector(IdentifierInfo *ID);
Selector getNullarySelector(IdentifierInfo *ID);
};
} // end namespace clang
#endif

View File

@ -18,7 +18,6 @@
#include "clang/Lex/Lexer.h"
#include "clang/Lex/MacroExpander.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/FoldingSet.h"
namespace clang {
@ -81,7 +80,7 @@ class Preprocessor {
/// flow (in clang::ParseAST()), make it convenient to put here.
/// FIXME: Make sure the lifetime of Identifiers/Selectors *isn't* tied to
/// the lifetime fo the preprocessor.
llvm::FoldingSet<MultiKeywordSelector> Selectors;
SelectorTable Selectors;
/// PragmaHandlers - This tracks all of the pragmas that the client registered
/// with this preprocessor.
@ -142,7 +141,7 @@ public:
HeaderSearch &getHeaderSearchInfo() const { return HeaderInfo; }
IdentifierTable &getIdentifierTable() { return Identifiers; }
llvm::FoldingSet<MultiKeywordSelector> &getSelectorTable() { return Selectors; }
SelectorTable &getSelectorTable() { return Selectors; }
/// SetCommentRetentionState - Control whether or not the preprocessor retains
/// comments in output.

View File

@ -303,9 +303,6 @@ private:
void ParseObjCInstanceMethodDefinition();
void ParseObjCClassMethodDefinition();
Selector ObjcGetUnarySelector(IdentifierInfo *unarySel);
Selector ObjcGetKeywordSelector(llvm::SmallVectorImpl<IdentifierInfo *> &IIV);
//===--------------------------------------------------------------------===//
// C99 6.5: Expressions.