diff --git a/interpreter/cling/include/cling/Interpreter/LookupHelper.h b/interpreter/cling/include/cling/Interpreter/LookupHelper.h
index 4dc5e114643cbf6dcaa025da73ba6a9c26e22174..5c344223c66c738f3306ea381d5091500232b16c 100644
--- a/interpreter/cling/include/cling/Interpreter/LookupHelper.h
+++ b/interpreter/cling/include/cling/Interpreter/LookupHelper.h
@@ -14,6 +14,7 @@
 #include "llvm/ADT/SmallVector.h"
 
 #include <array>
+#include <map>
 #include <memory>
 
 namespace clang {
@@ -54,11 +55,22 @@ namespace cling {
       NoDiagnostics,
       WithDiagnostics
     };
-
   private:
     std::unique_ptr<clang::Parser> m_Parser;
     Interpreter* m_Interpreter; // we do not own.
     std::array<const clang::Type*, kNumCachedStrings> m_StringTy = {};
+    /// A map containing the hash of the lookup buffer. This allows us to avoid
+    /// allocating memory for parsing when we know nothing has changed. Used by
+    /// StartParsingRAII.
+    // We do not want to include "clang/Basic/SourceLocation.h" because it makes
+    // the use of this header at runtime significantly slower.
+    // We really need llvm::hash_code->clang::FileID mapping but we put opaque
+    // source location as unsigned to compute the FileID when needed.
+    std::map<llvm::hash_code, unsigned> m_ParseBufferCache;
+    /// Number of times we hit the cache.
+    unsigned m_CacheHits = 0;
+    /// Number of times we missed the cache.
+    unsigned m_TotalParseRequests = 0;
 
   public:
     LookupHelper(clang::Parser* P, Interpreter* interp);
@@ -235,7 +247,10 @@ namespace cling {
                      DiagSetting diagOnOff) const;
 
     ///\brief Retrieve the StringType of given Type.
-     StringType getStringType(const clang::Type* Type);
+    StringType getStringType(const clang::Type* Type);
+
+    void printStats() const;
+    friend class StartParsingRAII;
   };
 
 } // end namespace
diff --git a/interpreter/cling/lib/Interpreter/LookupHelper.cpp b/interpreter/cling/lib/Interpreter/LookupHelper.cpp
index 4df32ba572a0fe6188bb88a3cf4d8594caa01b86..a863eb7db1289727f38cdc02213d5c712dc0d014 100644
--- a/interpreter/cling/lib/Interpreter/LookupHelper.cpp
+++ b/interpreter/cling/lib/Interpreter/LookupHelper.cpp
@@ -35,24 +35,29 @@ namespace cling {
      char fBuffer[sizeof(clang::OpaqueValueExpr)];
   };
 
-  // pin *tor here so that we can have clang::Parser defined and be able to call
-  // the dtor on the OwningPtr
-  LookupHelper::LookupHelper(clang::Parser* P, Interpreter* interp)
-    : m_Parser(P), m_Interpreter(interp) {
+  class StartParsingRAII {
+    LookupHelper& m_LH;
+    ParserStateRAII ResetParserState;
+
+    void prepareForParsing(llvm::StringRef code, llvm::StringRef bufferName,
+                           LookupHelper::DiagSetting diagOnOff);
+  public:
+    StartParsingRAII(LookupHelper& LH, llvm::StringRef code,
+                     llvm::StringRef bufferName,
+                     LookupHelper::DiagSetting diagOnOff)
+      : m_LH(LH), ResetParserState(*LH.m_Parser.get(), true /*skipToEOF*/) {
+    prepareForParsing(code, bufferName, diagOnOff);
   }
 
-  LookupHelper::~LookupHelper() {}
-
-  static
-  DeclContext* getCompleteContext(const Decl* scopeDecl,
-                                  ASTContext& Context, Sema &S);
+    ~StartParsingRAII() { pop(); }
+    void pop() const {}
+  };
 
-  static void prepareForParsing(Parser& P,
-                                const Interpreter* Interp,
-                                llvm::StringRef code,
-                                llvm::StringRef bufferName,
-                                LookupHelper::DiagSetting diagOnOff) {
-    //Parser& P = *m_Parser;
+  void StartParsingRAII::prepareForParsing(llvm::StringRef code,
+                                           llvm::StringRef bufferName,
+                                          LookupHelper::DiagSetting diagOnOff) {
+    ++m_LH.m_TotalParseRequests;
+    Parser& P = *m_LH.m_Parser.get();
     Sema& S = P.getActions();
     Preprocessor& PP = P.getPreprocessor();
     //
@@ -81,17 +86,58 @@ namespace cling {
     }
     assert(!code.empty()&&"prepareForParsing should only be called when needd");
 
-    //
-    //  Create a fake file to parse the type name.
-    //
-    std::unique_ptr<llvm::MemoryBuffer>
-      SB = llvm::MemoryBuffer::getMemBufferCopy(code.str() + "\n",
-                                                bufferName.str());
-    SourceLocation NewLoc = Interp->getNextAvailableLoc();
-    FileID FID = S.getSourceManager().createFileID(std::move(SB),
-                                                   SrcMgr::C_User,
-                                                   /*LoadedID*/0,
-                                                   /*LoadedOffset*/0, NewLoc);
+    // Create a fake file to parse the type name.
+    FileID FID;
+    llvm::hash_code hashedCode = llvm::hash_value(code);
+    auto cacheItr = m_LH.m_ParseBufferCache.find(hashedCode);
+    SourceLocation NewLoc;
+    SourceManager& SM = S.getSourceManager();
+    bool CacheIsValid = false;
+    if (cacheItr != m_LH.m_ParseBufferCache.end()) {
+      SourceLocation FileStartLoc =
+        SourceLocation::getFromRawEncoding(cacheItr->second);
+      FID = SM.getFileID(FileStartLoc);
+
+      bool Invalid = true;
+      llvm::StringRef FIDContents = SM.getBuffer(FID, &Invalid)->getBuffer();
+
+      // A FileID is a (cached via ContentCache) SourceManager view of a
+      // FileManager::FileEntry (which is a wrapper on the file system file).
+      // In a subtle cases, code unloading can remove the cached region.
+      // However we are safe because it will empty the ContentCache and force
+      // the FileEntry to be re-read. It will keep the FileID intact and valid
+      // by design. When we reprocess the same (but modified) file it will get
+      // a new FileID. Then the Invalid flag will be false but the underlying
+      // buffer content will be empty. It will not compare equal to the lookup
+      // string and we will avoid using (a potentially broken) cache.
+      assert(!Invalid);
+
+      // Compare the contents of the cached buffer and the string we should
+      // process. If there are hash collisions this assert should trigger
+      // making it easier to debug.
+      CacheIsValid = FIDContents.equals(llvm::StringRef(code.str() + "\n"));
+      assert(CacheIsValid && "Hash collision!");
+      if (CacheIsValid) {
+        // We have already included this file once. Reuse the include loc.
+        NewLoc = SM.getIncludeLoc(FID);
+        // The Preprocessor will try to set the NumCreatedFIDs but we are
+        // reparsing and this value was already set. Force reset it to avoid
+        // triggering an assertion in the setNumCreatedFIDsForFileID routine.
+        SM.setNumCreatedFIDsForFileID(FID, 0, /*force*/ true);
+        ++m_LH.m_CacheHits;
+      }
+    }
+    if (!CacheIsValid) {
+      std::unique_ptr<llvm::MemoryBuffer> SB
+        = llvm::MemoryBuffer::getMemBufferCopy(code.str() + "\n",
+                                               bufferName.str());
+      NewLoc = m_LH.m_Interpreter->getNextAvailableLoc();
+      FID = SM.createFileID(std::move(SB), SrcMgr::C_User, /*LoadedID*/0,
+                            /*LoadedOffset*/0, NewLoc);
+      SourceLocation FileStartLoc = SM.getLocForStartOfFile(FID);
+      m_LH.m_ParseBufferCache[hashedCode] = FileStartLoc.getRawEncoding();
+    }
+
     //
     //  Switch to the new file the way #include does.
     //
@@ -101,6 +147,18 @@ namespace cling {
     PP.Lex(const_cast<Token&>(P.getCurToken()));
   }
 
+  // pin *tor here so that we can have clang::Parser defined and be able to call
+  // the dtor on the OwningPtr
+  LookupHelper::LookupHelper(clang::Parser* P, Interpreter* interp)
+    : m_Parser(P), m_Interpreter(interp) {
+  }
+
+  LookupHelper::~LookupHelper() {}
+
+  static
+  DeclContext* getCompleteContext(const Decl* scopeDecl,
+                                  ASTContext& Context, Sema &S);
+
   static const TagDecl* RequireCompleteDeclContext(Sema& S,
                                                    Preprocessor& PP,
                                                    const TagDecl *tobeCompleted,
@@ -417,10 +475,10 @@ namespace cling {
 
     // Use P for shortness
     Parser& P = *m_Parser;
-    ParserStateRAII ResetParserState(P, true /*skipToEOF*/);
-    prepareForParsing(P,m_Interpreter,
-                      typeName, llvm::StringRef("lookup.type.by.name.file"),
-                      diagOnOff);
+    StartParsingRAII ParseStarted(const_cast<LookupHelper&>(*this),
+                                  typeName,
+                                  llvm::StringRef("lookup.type.by.name.file"),
+                                  diagOnOff);
     //
     //  Try parsing the type name.
     //
@@ -526,10 +584,10 @@ namespace cling {
       }
     }
 
-    ParserStateRAII ResetParserState(P, true /*skipToEOF*/);
-    prepareForParsing(P,m_Interpreter,
-                      className.str() + "::",
-                      llvm::StringRef("lookup.class.by.name.file"), diagOnOff);
+    StartParsingRAII ParseStarted(const_cast<LookupHelper&>(*this),
+                                  className.str() + "::",
+                                  llvm::StringRef("lookup.class.by.name.file"),
+                                  diagOnOff);
     //
     //  Our return values.
     //
@@ -722,10 +780,10 @@ namespace cling {
     Parser& P = *m_Parser;
     Sema& S = P.getActions();
     ASTContext& Context = S.getASTContext();
-    ParserStateRAII ResetParserState(P, true /*skipToEOF*/);
-    prepareForParsing(P,m_Interpreter,
-                      Name.str(),
-                      llvm::StringRef("lookup.class.by.name.file"), diagOnOff);
+    StartParsingRAII ParseStarted(const_cast<LookupHelper&>(*this),
+                                  Name.str(),
+                                  llvm::StringRef("lookup.class.by.name.file"),
+                                  diagOnOff);
 
     //
     //  Prevent failing on an assert in TryAnnotateCXXScopeToken.
@@ -1417,6 +1475,7 @@ namespace cling {
   template <typename DigestArgsInput, typename returnType>
   returnType execFindFunction(Parser &P,
                               Interpreter* Interp,
+                              LookupHelper &LH,
                               const clang::Decl* scopeDecl,
                               llvm::StringRef funcName,
                               const typename DigestArgsInput::ArgsInput &funcArgs,
@@ -1452,7 +1511,7 @@ namespace cling {
 
     DigestArgsInput inputEval;
     llvm::SmallVector<Expr*, 4> GivenArgs;
-    if (!inputEval(GivenArgs,funcArgs,diagOnOff,P,Interp)) return 0;
+    if (!inputEval(GivenArgs,funcArgs,diagOnOff,P,Interp,LH)) return 0;
 
     Interpreter::PushTransactionRAII pushedT(Interp);
     return findFunction(foundDC,
@@ -1468,7 +1527,8 @@ namespace cling {
     bool operator()(llvm::SmallVectorImpl<Expr*> & /* GivenArgs */,
                     const ArgsInput &/* funcArgs */,
                     LookupHelper::DiagSetting /* diagOnOff */,
-                    Parser & /* P */, const Interpreter* /* Interp */)
+                    Parser & /* P */, const Interpreter* /* Interp */,
+                    const LookupHelper& /* LH */)
     {
       return true;
     }
@@ -1483,7 +1543,8 @@ namespace cling {
     bool operator()(llvm::SmallVectorImpl<Expr*> &GivenArgs,
                     const ArgsInput &GivenTypes,
                     LookupHelper::DiagSetting /* diagOnOff */,
-                    Parser & /* P */, const Interpreter* /* Interp */) {
+                    Parser & /* P */, const Interpreter* /* Interp */,
+                    LookupHelper& /* LH */) {
 
       if (GivenTypes.empty()) return true;
       else return getExprProto(GivenArgs,GivenTypes);
@@ -1526,24 +1587,26 @@ namespace cling {
     bool operator()(llvm::SmallVectorImpl<Expr*> &GivenArgs,
                     const ArgsInput &funcProto,
                     LookupHelper::DiagSetting diagOnOff,
-                    Parser &P, const Interpreter* Interp) {
+                    Parser& P, const Interpreter* Interp,
+                    LookupHelper& LH) {
 
       if (funcProto.empty()) return true;
-      else return Parse(GivenArgs,funcProto,diagOnOff,P,Interp);
+      else return Parse(GivenArgs,funcProto,diagOnOff, P, Interp, LH);
     }
 
     bool Parse(llvm::SmallVectorImpl<Expr*> &GivenArgs,
                const ArgsInput &funcProto,
                LookupHelper::DiagSetting diagOnOff,
-               Parser &P, const Interpreter* Interp) {
+               Parser& P, const Interpreter* Interp,
+               LookupHelper& LH) {
 
       //
       //  Parse the prototype now.
       //
 
-      ParserStateRAII ResetParserState(P, true /*skipToEOF*/);
-      prepareForParsing(P,Interp,
-                        funcProto, llvm::StringRef("func.prototype.file"), diagOnOff);
+      StartParsingRAII ParseStarted(LH, funcProto,
+                                    llvm::StringRef("func.prototype.file"),
+                                    diagOnOff);
 
       unsigned int nargs = 0;
       while (P.getCurToken().isNot(tok::eof)) {
@@ -1631,6 +1694,7 @@ namespace cling {
     // Lookup a function template based on its Decl(Context), name.
 
     return execFindFunction<NoParse>(*m_Parser, m_Interpreter,
+                                     const_cast<LookupHelper&>(*this),
                                      scopeDecl,
                                      templateName, "",
                                      objectIsConst,
@@ -1702,6 +1766,7 @@ namespace cling {
                                                     bool objectIsConst) const {
 
     return execFindFunction<NoParse>(*m_Parser, m_Interpreter,
+                                     const_cast<LookupHelper&>(*this),
                                      scopeDecl,
                                      funcName, "",
                                      objectIsConst,
@@ -1717,6 +1782,7 @@ namespace cling {
     assert(scopeDecl && "Decl cannot be null");
 
     return execFindFunction<ExprFromTypes>(*m_Parser, m_Interpreter,
+                                           const_cast<LookupHelper&>(*this),
                                            scopeDecl,
                                            funcName,
                                            funcProto,
@@ -1733,6 +1799,7 @@ namespace cling {
     assert(scopeDecl && "Decl cannot be null");
 
     return execFindFunction<ParseProto>(*m_Parser, m_Interpreter,
+                                        const_cast<LookupHelper&>(*this),
                                         scopeDecl,
                                         funcName,
                                         funcProto,
@@ -1750,6 +1817,7 @@ namespace cling {
     assert(scopeDecl && "Decl cannot be null");
 
     return execFindFunction<ParseProto>(*m_Parser, m_Interpreter,
+                                        const_cast<LookupHelper&>(*this),
                                         scopeDecl,
                                         funcName,
                                         funcProto,
@@ -1767,6 +1835,7 @@ namespace cling {
     assert(scopeDecl && "Decl cannot be null");
 
     return execFindFunction<ExprFromTypes>(*m_Parser, m_Interpreter,
+                                           const_cast<LookupHelper&>(*this),
                                            scopeDecl,
                                            funcName,
                                            funcProto,
@@ -1782,25 +1851,27 @@ namespace cling {
     bool operator()(llvm::SmallVectorImpl<Expr*> &GivenArgs,
                     const ArgsInput &funcArgs,
                     LookupHelper::DiagSetting diagOnOff,
-                    Parser &P, const Interpreter* Interp) {
+                    Parser &P, const Interpreter* Interp,
+                    LookupHelper& LH) {
 
       if (funcArgs.empty()) return true;
-      else return Parse(GivenArgs,funcArgs,diagOnOff,P,Interp);
+      else return Parse(GivenArgs,funcArgs,diagOnOff, P, Interp, LH);
     }
 
     bool Parse(llvm::SmallVectorImpl<Expr*> &GivenArgs,
-                 llvm::StringRef funcArgs,
-                 LookupHelper::DiagSetting diagOnOff,
-                 Parser &P, const Interpreter* Interp) {
+               llvm::StringRef funcArgs,
+               LookupHelper::DiagSetting diagOnOff,
+               Parser &P, const Interpreter* Interp,
+               LookupHelper& LH) {
 
       //
       //  Parse the arguments now.
       //
 
       Interpreter::PushTransactionRAII TforDeser(Interp);
-      ParserStateRAII ResetParserState(P, true /*skipToEOF*/);
-      prepareForParsing(P,Interp,
-                        funcArgs, llvm::StringRef("func.args.file"), diagOnOff);
+      StartParsingRAII ParseStarted(LH, funcArgs,
+                                    llvm::StringRef("func.args.file"),
+                                    diagOnOff);
 
       Sema& S = P.getActions();
       ASTContext& Context = S.getASTContext();
@@ -1860,6 +1931,7 @@ namespace cling {
     assert(scopeDecl && "Decl cannot be null");
 
     return execFindFunction<ParseArgs>(*m_Parser, m_Interpreter,
+                                       const_cast<LookupHelper&>(*this),
                                        scopeDecl,
                                        funcName,
                                        funcArgs,
@@ -1878,9 +1950,10 @@ namespace cling {
     //
     // Use P for shortness
     Parser& P = *m_Parser;
-    ParserStateRAII ResetParserState(P, true /*skipToEOF*/);
-    prepareForParsing(P,m_Interpreter,
-                      argList, llvm::StringRef("arg.list.file"), diagOnOff);
+    StartParsingRAII ParseStarted(const_cast<LookupHelper&>(*this),
+                                  argList,
+                                  llvm::StringRef("arg.list.file"),
+                                  diagOnOff);
     //
     //  Parse the arguments now.
     //
@@ -1931,6 +2004,7 @@ namespace cling {
                                  DiagSetting diagOnOff) const {
 
     return execFindFunction<NoParse>(*m_Parser, m_Interpreter,
+                                     const_cast<LookupHelper&>(*this),
                                      scopeDecl,
                                      funcName, "",
                                      false /* objectIsConst */,
@@ -1975,4 +2049,9 @@ namespace cling {
     return kNotAString;
   }
 
+  void LookupHelper::printStats() const {
+    llvm::errs() << "Cached entries: " << m_ParseBufferCache.size() << "\n";
+    llvm::errs() << "Total parse requests: " << m_TotalParseRequests << "\n";
+    llvm::errs() << "Cache hits: " << m_CacheHits << "\n";
+  }
 } // end namespace cling
diff --git a/interpreter/llvm/src/tools/clang/include/clang/Basic/SourceManager.h b/interpreter/llvm/src/tools/clang/include/clang/Basic/SourceManager.h
index 0b0534406f4c066fa61a848888fa93e5a592b1ea..6125692d4caab472b937c849ab44e122402992ef 100644
--- a/interpreter/llvm/src/tools/clang/include/clang/Basic/SourceManager.h
+++ b/interpreter/llvm/src/tools/clang/include/clang/Basic/SourceManager.h
@@ -989,13 +989,14 @@ public:
 
   /// \brief Set the number of FileIDs (files and macros) that were created
   /// during preprocessing of \p FID, including it.
-  void setNumCreatedFIDsForFileID(FileID FID, unsigned NumFIDs) const {
+  void setNumCreatedFIDsForFileID(FileID FID, unsigned NumFIDs,
+                                  bool Force = false) const {
     bool Invalid = false;
     const SrcMgr::SLocEntry &Entry = getSLocEntry(FID, &Invalid);
     if (Invalid || !Entry.isFile())
       return;
 
-    assert(Entry.getFile().NumCreatedFIDs == 0 && "Already set!");
+    assert(Force || Entry.getFile().NumCreatedFIDs == 0 && "Already set!");
     const_cast<SrcMgr::FileInfo &>(Entry.getFile()).NumCreatedFIDs = NumFIDs;
   }