sammccall created this revision.
sammccall added a reviewer: njames93.
Herald added subscribers: usaxena95, kadircet, arphaman.
sammccall requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang.

- reuse std::string we read messages into
- when reading line-wise, use SmallVector<128> and read in chunks of 128 (this 
affects headers, which are short, and tests, which don't matter)


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D93653

Files:
  clang-tools-extra/clangd/JSONTransport.cpp

Index: clang-tools-extra/clangd/JSONTransport.cpp
===================================================================
--- clang-tools-extra/clangd/JSONTransport.cpp
+++ clang-tools-extra/clangd/JSONTransport.cpp
@@ -10,6 +10,7 @@
 #include "support/Cancellation.h"
 #include "support/Logger.h"
 #include "support/Shutdown.h"
+#include "llvm/ADT/SmallString.h"
 #include "llvm/Support/Errno.h"
 #include "llvm/Support/Error.h"
 #include <system_error>
@@ -99,6 +100,7 @@
   }
 
   llvm::Error loop(MessageHandler &Handler) override {
+    std::string JSON; // Messages may be large, reuse same big buffer.
     while (!feof(In)) {
       if (shutdownRequested())
         return error(std::make_error_code(std::errc::operation_canceled),
@@ -106,14 +108,14 @@
       if (ferror(In))
         return llvm::errorCodeToError(
             std::error_code(errno, std::system_category()));
-      if (auto JSON = readRawMessage()) {
-        if (auto Doc = llvm::json::parse(*JSON)) {
+      if (readRawMessage(JSON)) {
+        if (auto Doc = llvm::json::parse(JSON)) {
           vlog(Pretty ? "<<< {0:2}\n" : "<<< {0}\n", *Doc);
           if (!handleMessage(std::move(*Doc), Handler))
             return llvm::Error::success(); // we saw the "exit" notification.
         } else {
           // Parse error. Log the raw message.
-          vlog("<<< {0}\n", *JSON);
+          vlog("<<< {0}\n", JSON);
           elog("JSON parse error: {0}", llvm::toString(Doc.takeError()));
         }
       }
@@ -136,12 +138,12 @@
   }
 
   // Read raw string messages from input stream.
-  llvm::Optional<std::string> readRawMessage() {
-    return Style == JSONStreamStyle::Delimited ? readDelimitedMessage()
-                                               : readStandardMessage();
+  bool readRawMessage(std::string &JSON) {
+    return Style == JSONStreamStyle::Delimited ? readDelimitedMessage(JSON)
+                                               : readStandardMessage(JSON);
   }
-  llvm::Optional<std::string> readDelimitedMessage();
-  llvm::Optional<std::string> readStandardMessage();
+  bool readDelimitedMessage(std::string &JSON);
+  bool readStandardMessage(std::string &JSON);
 
   std::FILE *In;
   llvm::raw_ostream &Out;
@@ -190,8 +192,10 @@
 
 // Tries to read a line up to and including \n.
 // If failing, feof(), ferror(), or shutdownRequested() will be set.
-bool readLine(std::FILE *In, std::string &Out) {
-  static constexpr int BufSize = 1024;
+bool readLine(std::FILE *In, llvm::SmallVectorImpl<char> &Out) {
+  // Big enough to hold any reasonable header line. May not fit content lines
+  // in delimited mode, but performance doesn't matter for that mode.
+  static constexpr int BufSize = 128;
   size_t Size = 0;
   Out.clear();
   for (;;) {
@@ -215,14 +219,14 @@
 // Returns None when:
 //  - ferror(), feof(), or shutdownRequested() are set.
 //  - Content-Length is missing or empty (protocol error)
-llvm::Optional<std::string> JSONTransport::readStandardMessage() {
+bool JSONTransport::readStandardMessage(std::string &JSON) {
   // A Language Server Protocol message starts with a set of HTTP headers,
   // delimited  by \r\n, and terminated by an empty line (\r\n).
   unsigned long long ContentLength = 0;
-  std::string Line;
+  llvm::SmallString<128> Line;
   while (true) {
     if (feof(In) || ferror(In) || !readLine(In, Line))
-      return llvm::None;
+      return false;
     InMirror << Line;
 
     llvm::StringRef LineRef(Line);
@@ -257,14 +261,14 @@
     elog("Refusing to read message with long Content-Length: {0}. "
          "Expect protocol errors",
          ContentLength);
-    return llvm::None;
+    return false;
   }
   if (ContentLength == 0) {
     log("Warning: Missing Content-Length header, or zero-length message.");
-    return llvm::None;
+    return false;
   }
 
-  std::string JSON(ContentLength, '\0');
+  JSON.resize(ContentLength);
   for (size_t Pos = 0, Read; Pos < ContentLength; Pos += Read) {
     // Handle EINTR which is sent when a debugger attaches on some platforms.
     Read = retryAfterSignalUnlessShutdown(0, [&]{
@@ -273,24 +277,24 @@
     if (Read == 0) {
       elog("Input was aborted. Read only {0} bytes of expected {1}.", Pos,
            ContentLength);
-      return llvm::None;
+      return false;
     }
     InMirror << llvm::StringRef(&JSON[Pos], Read);
     clearerr(In); // If we're done, the error was transient. If we're not done,
                   // either it was transient or we'll see it again on retry.
     Pos += Read;
   }
-  return std::move(JSON);
+  return true;
 }
 
 // For lit tests we support a simplified syntax:
 // - messages are delimited by '---' on a line by itself
 // - lines starting with # are ignored.
 // This is a testing path, so favor simplicity over performance here.
-// When returning None, feof(), ferror(), or shutdownRequested() will be set.
-llvm::Optional<std::string> JSONTransport::readDelimitedMessage() {
-  std::string JSON;
-  std::string Line;
+// When returning false: feof(), ferror(), or shutdownRequested() will be set.
+bool JSONTransport::readDelimitedMessage(std::string &JSON) {
+  JSON.clear();
+  llvm::SmallString<128> Line;
   while (readLine(In, Line)) {
     InMirror << Line;
     auto LineRef = llvm::StringRef(Line).trim();
@@ -305,12 +309,12 @@
   }
 
   if (shutdownRequested())
-    return llvm::None;
+    return false;
   if (ferror(In)) {
     elog("Input error while reading message!");
-    return llvm::None;
+    return false;
   }
-  return std::move(JSON); // Including at EOF
+  return true; // Including at EOF
 }
 
 } // namespace
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to