diff --git a/Lex/MacroExpander.cpp b/Lex/MacroExpander.cpp index 45d4611233d461973afccbc506a9f2a8e48ca486..7a46b1429724aab3547c9035e7ef93c820ca70f7 100644 --- a/Lex/MacroExpander.cpp +++ b/Lex/MacroExpander.cpp @@ -233,13 +233,17 @@ const LexerToken &MacroArgs::getStringifiedArgument(unsigned ArgNo, /// Create a macro expander for the specified macro with the specified actual /// arguments. Note that this ctor takes ownership of the ActualArgs pointer. -MacroExpander::MacroExpander(LexerToken &Tok, MacroArgs *Actuals, - Preprocessor &pp) - : Macro(Tok.getIdentifierInfo()->getMacroInfo()), - ActualArgs(Actuals), PP(pp), CurToken(0), - InstantiateLoc(Tok.getLocation()), - AtStartOfLine(Tok.isAtStartOfLine()), - HasLeadingSpace(Tok.hasLeadingSpace()) { +void MacroExpander::Init(LexerToken &Tok, MacroArgs *Actuals) { + // If the client is reusing a macro expander, make sure to free any memory + // associated with it. + destroy(); + + Macro = Tok.getIdentifierInfo()->getMacroInfo(); + ActualArgs = Actuals; + CurToken = 0; + InstantiateLoc = Tok.getLocation(); + AtStartOfLine = Tok.isAtStartOfLine(); + HasLeadingSpace = Tok.hasLeadingSpace(); MacroTokens = &*Macro->tokens_begin(); NumMacroTokens = Macro->tokens_end()-Macro->tokens_begin(); @@ -254,14 +258,23 @@ MacroExpander::MacroExpander(LexerToken &Tok, MacroArgs *Actuals, Macro->DisableMacro(); } + + /// Create a macro expander for the specified token stream. This does not /// take ownership of the specified token vector. -MacroExpander::MacroExpander(const LexerToken *TokArray, unsigned NumToks, - Preprocessor &pp) - : Macro(0), ActualArgs(0), PP(pp), MacroTokens(TokArray), - NumMacroTokens(NumToks), CurToken(0), - InstantiateLoc(SourceLocation()), AtStartOfLine(false), - HasLeadingSpace(false) { +void MacroExpander::Init(const LexerToken *TokArray, unsigned NumToks) { + // If the client is reusing a macro expander, make sure to free any memory + // associated with it. + destroy(); + + Macro = 0; + ActualArgs = 0; + MacroTokens = TokArray; + NumMacroTokens = NumToks; + CurToken = 0; + InstantiateLoc = SourceLocation(); + AtStartOfLine = false; + HasLeadingSpace = false; // Set HasLeadingSpace/AtStartOfLine so that the first token will be // returned unmodified. @@ -272,7 +285,7 @@ MacroExpander::MacroExpander(const LexerToken *TokArray, unsigned NumToks, } -MacroExpander::~MacroExpander() { +void MacroExpander::destroy() { // If this was a function-like macro that actually uses its arguments, delete // the expanded tokens. if (Macro && MacroTokens != &*Macro->tokens_begin()) diff --git a/Lex/Preprocessor.cpp b/Lex/Preprocessor.cpp index 4e3f68e1a11c39685e60229326cd15cf1e37ef1d..8376b9f8a30b39ca5f3a88c27c39890c5150b556 100644 --- a/Lex/Preprocessor.cpp +++ b/Lex/Preprocessor.cpp @@ -48,7 +48,7 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, SourceMgr(SM), HeaderInfo(Headers), Identifiers(opts), CurLexer(0), CurDirLookup(0), CurMacroExpander(0), Callbacks(0) { ScratchBuf = new ScratchBuffer(SourceMgr); - + // Clear stats. NumDirectives = NumDefined = NumUndefined = NumPragma = 0; NumIf = NumElse = NumEndif = 0; @@ -65,6 +65,7 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, // Macro expansion is enabled. DisableMacroExpansion = false; InMacroArgs = false; + NumCachedMacroExpanders = 0; // "Poison" __VA_ARGS__, which can only appear in the expansion of a macro. // This gets unpoisoned where it is allowed. @@ -88,6 +89,10 @@ Preprocessor::~Preprocessor() { IncludeMacroStack.pop_back(); } + // Free any cached macro expanders. + for (unsigned i = 0, e = NumCachedMacroExpanders; i != e; ++i) + delete MacroExpanderCache[i]; + // Release pragma information. delete PragmaHandlers; @@ -386,7 +391,12 @@ void Preprocessor::EnterMacro(LexerToken &Tok, MacroArgs *Args) { CurLexer = 0; CurDirLookup = 0; - CurMacroExpander = new MacroExpander(Tok, Args, *this); + if (NumCachedMacroExpanders == 0) { + CurMacroExpander = new MacroExpander(Tok, Args, *this); + } else { + CurMacroExpander = MacroExpanderCache[--NumCachedMacroExpanders]; + CurMacroExpander->Init(Tok, Args); + } } /// EnterTokenStream - Add a "macro" context to the top of the include stack, @@ -402,7 +412,12 @@ void Preprocessor::EnterTokenStream(const LexerToken *Toks, unsigned NumToks) { CurDirLookup = 0; // Create a macro expander to expand from the specified token stream. - CurMacroExpander = new MacroExpander(Toks, NumToks, *this); + if (NumCachedMacroExpanders == 0) { + CurMacroExpander = new MacroExpander(Toks, NumToks, *this); + } else { + CurMacroExpander = MacroExpanderCache[--NumCachedMacroExpanders]; + CurMacroExpander->Init(Toks, NumToks); + } } /// RemoveTopOfLexerStack - Pop the current lexer/macro exp off the top of the @@ -410,8 +425,16 @@ void Preprocessor::EnterTokenStream(const LexerToken *Toks, unsigned NumToks) { /// state of the top-of-stack lexer is known. void Preprocessor::RemoveTopOfLexerStack() { assert(!IncludeMacroStack.empty() && "Ran out of stack entries to load"); - delete CurLexer; - delete CurMacroExpander; + + if (CurMacroExpander) { + // Delete or cache the now-dead macro expander. + if (NumCachedMacroExpanders == MacroExpanderCacheSize) + delete CurMacroExpander; + else + MacroExpanderCache[NumCachedMacroExpanders++] = CurMacroExpander; + } else { + delete CurLexer; + } CurLexer = IncludeMacroStack.back().TheLexer; CurDirLookup = IncludeMacroStack.back().TheDirLookup; CurMacroExpander = IncludeMacroStack.back().TheMacroExpander; @@ -1047,7 +1070,11 @@ bool Preprocessor::HandleEndOfMacro(LexerToken &Result) { assert(CurMacroExpander && !CurLexer && "Ending a macro when currently in a #include file!"); - delete CurMacroExpander; + // Delete or cache the now-dead macro expander. + if (NumCachedMacroExpanders == MacroExpanderCacheSize) + delete CurMacroExpander; + else + MacroExpanderCache[NumCachedMacroExpanders++] = CurMacroExpander; // Handle this like a #include file being popped off the stack. CurMacroExpander = 0; diff --git a/include/clang/Lex/MacroExpander.h b/include/clang/Lex/MacroExpander.h index 8bb4ebfd5d02c5a5f2d81287e1b9f33de8716135..d888f868614d9f07acf9ab730462e7c1f62baecd 100644 --- a/include/clang/Lex/MacroExpander.h +++ b/include/clang/Lex/MacroExpander.h @@ -141,12 +141,28 @@ class MacroExpander { public: /// Create a macro expander for the specified macro with the specified actual /// arguments. Note that this ctor takes ownership of the ActualArgs pointer. - MacroExpander(LexerToken &Tok, MacroArgs *ActualArgs, Preprocessor &PP); + MacroExpander(LexerToken &Tok, MacroArgs *ActualArgs, Preprocessor &pp) + : Macro(0), ActualArgs(0), PP(pp) { + Init(Tok, ActualArgs); + } + + /// Init - Initialize this macro expander to expand from the specified macro + /// with the specified argument information. Note that this ctor takes + /// ownership of the ActualArgs pointer. + void Init(LexerToken &Tok, MacroArgs *ActualArgs); /// Create a macro expander for the specified token stream. This does not /// take ownership of the specified token vector. - MacroExpander(const LexerToken *TokArray, unsigned NumToks, Preprocessor &PP); - ~MacroExpander(); + MacroExpander(const LexerToken *TokArray, unsigned NumToks, Preprocessor &pp) + : Macro(0), ActualArgs(0), PP(pp) { + Init(TokArray, NumToks); + } + + /// Init - Initialize this macro expander with the specified token stream. + /// This does not take ownership of the specified token vector. + void Init(const LexerToken *TokArray, unsigned NumToks); + + ~MacroExpander() { destroy(); } /// isNextTokenLParen - If the next token lexed will pop this macro off the /// expansion stack, return 2. If the next unexpanded token is a '(', return @@ -157,6 +173,8 @@ public: void Lex(LexerToken &Tok); private: + void destroy(); + /// isAtEnd - Return true if the next lex call will pop this macro off the /// include stack. bool isAtEnd() const { diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index e3aff7601200866d09efdda189739db741db005e..4b6ea1f436db07ecf3b3dc05c7c1b9feb8295072 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -114,6 +114,11 @@ class Preprocessor { unsigned NumMacroExpanded, NumFnMacroExpanded, NumBuiltinMacroExpanded; unsigned NumFastMacroExpanded, NumTokenPaste, NumFastTokenPaste; unsigned NumSkipped; + + /// MacroExpanderCache - Cache macro expanders to reduce malloc traffic. + enum { MacroExpanderCacheSize = 8 }; + unsigned NumCachedMacroExpanders; + MacroExpander *MacroExpanderCache[MacroExpanderCacheSize]; public: Preprocessor(Diagnostic &diags, const LangOptions &opts, TargetInfo &target, SourceManager &SM, HeaderSearch &Headers);