[Lldb-commits] [lldb] r359773 - Inject only relevant local variables in the expression evaluation context

Raphael Isemann via lldb-commits lldb-commits at lists.llvm.org
Thu May 2 03:12:56 PDT 2019


Author: teemperor
Date: Thu May  2 03:12:56 2019
New Revision: 359773

URL: http://llvm.org/viewvc/llvm-project?rev=359773&view=rev
Log:
Inject only relevant local variables in the expression evaluation context

Summary:
In r259902, LLDB started injecting all the locals in every expression
evaluation. This fixed a bunch of issues, but also caused others, mostly
performance regressions on some codebases. The regressions were bad
enough that we added a setting in r274783 to control the behavior and
we have been shipping with the setting off to avoid the perf regressions.

This patch changes the logic injecting the local variables to only inject
the ones present in the expression typed by the user. The approach is
fairly simple and just scans the typed expression for every local name.
Hopefully this gives us the best of both world as it just realizes the
types of the variables really used by the expression.

Landing this requires the 2 other issues I pointed out today to be addressed
but I wanted to gather comments right away.

Original patch by Frédéric Riss!

Reviewers: jingham, clayborg, friss, shafik

Reviewed By: jingham, clayborg

Subscribers: teemperor, labath, lldb-commits

Tags: #lldb

Differential Revision: https://reviews.llvm.org/D46551

Modified:
    lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/member-and-local-vars-with-same-name/TestMembersAndLocalsWithSameName.py
    lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
    lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
    lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
    lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h

Modified: lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/member-and-local-vars-with-same-name/TestMembersAndLocalsWithSameName.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/member-and-local-vars-with-same-name/TestMembersAndLocalsWithSameName.py?rev=359773&r1=359772&r2=359773&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/member-and-local-vars-with-same-name/TestMembersAndLocalsWithSameName.py (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/lang/cpp/member-and-local-vars-with-same-name/TestMembersAndLocalsWithSameName.py Thu May  2 03:12:56 2019
@@ -155,7 +155,9 @@ class TestMembersAndLocalsWithSameName(T
         frame = thread.GetSelectedFrame()
         self.assertTrue(frame.IsValid())
 
+        self.enable_expression_log()
         val = frame.EvaluateExpression("a")
+        self.disable_expression_log_and_check_for_locals(['a'])
         self.assertTrue(val.IsValid())
         self.assertEqual(val.GetValueAsUnsigned(), 12345)
 
@@ -189,6 +191,12 @@ class TestMembersAndLocalsWithSameName(T
         self.assertTrue(val.IsValid())
         self.assertEqual(val.GetValueAsUnsigned(), 10003)
 
+        self.enable_expression_log()
+        val = frame.EvaluateExpression("c-b")
+        self.disable_expression_log_and_check_for_locals(['c','b'])
+        self.assertTrue(val.IsValid())
+        self.assertEqual(val.GetValueAsUnsigned(), 1)
+
         self.process.Continue()
         self.assertTrue(
             self.process.GetState() == lldb.eStateStopped,
@@ -211,6 +219,13 @@ class TestMembersAndLocalsWithSameName(T
         self.assertTrue(val.IsValid())
         self.assertEqual(val.GetValueAsUnsigned(), 778899)
 
+        self.enable_expression_log()
+        val = frame.EvaluateExpression("a+b")
+        self.disable_expression_log_and_check_for_locals(['a','b'])
+        self.assertTrue(val.IsValid())
+        self.assertEqual(val.GetValueAsUnsigned(), 3)
+
+
     def _load_exe(self):
         self.build()
 
@@ -234,7 +249,9 @@ class TestMembersAndLocalsWithSameName(T
         frame = thread.GetSelectedFrame()
         self.assertTrue(frame.IsValid())
 
+        self.enable_expression_log()
         val = frame.EvaluateExpression("a")
+        self.disable_expression_log_and_check_for_locals([])
         self.assertTrue(val.IsValid())
         self.assertEqual(val.GetValueAsUnsigned(), 112233)
 
@@ -245,3 +262,23 @@ class TestMembersAndLocalsWithSameName(T
         val = frame.EvaluateExpression("c")
         self.assertTrue(val.IsValid())
         self.assertEqual(val.GetValueAsUnsigned(), 778899)
+
+    def enable_expression_log(self):
+        log_file = os.path.join(self.getBuildDir(), "expr.log")
+        self.runCmd("log enable  -f '%s' lldb expr" % (log_file))
+
+    def disable_expression_log_and_check_for_locals(self, variables):
+        log_file = os.path.join(self.getBuildDir(), "expr.log")
+        self.runCmd("log disable lldb expr")
+        local_var_regex = re.compile(r".*__lldb_local_vars::(.*);")
+        matched = []
+        with open(log_file, 'r') as log:
+            for line in log:
+                if line.find('LLDB_BODY_START') != -1:
+                    break
+                m = re.match(local_var_regex, line)
+                if m:
+                    self.assertIn(m.group(1), variables)
+                    matched.append(m.group(1))
+        self.assertEqual([item for item in variables if item not in matched],
+                         [])

Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp?rev=359773&r1=359772&r2=359773&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp (original)
+++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp Thu May  2 03:12:56 2019
@@ -8,6 +8,9 @@
 
 #include "ClangExpressionSourceCode.h"
 
+#include "clang/Basic/CharInfo.h"
+#include "llvm/ADT/StringRef.h"
+
 #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
 #include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h"
 #include "lldb/Symbol/Block.h"
@@ -161,8 +164,43 @@ static void AddMacros(const DebugMacros
   }
 }
 
+/// Checks if the expression body contains the given variable as a token.
+/// \param body The expression body.
+/// \param var The variable token we are looking for.
+/// \return True iff the expression body containes the variable as a token.
+static bool ExprBodyContainsVar(llvm::StringRef body, llvm::StringRef var) {
+  assert(var.find_if([](char c) { return !clang::isIdentifierBody(c); }) ==
+             llvm::StringRef::npos &&
+         "variable contains non-identifier chars?");
+
+  size_t start = 0;
+  // Iterate over all occurences of the variable string in our expression.
+  while ((start = body.find(var, start)) != llvm::StringRef::npos) {
+    // We found our variable name in the expression. Check that the token
+    // that contains our needle is equal to our variable and not just contains
+    // the character sequence by accident.
+    // Prevents situations where we for example inlcude the variable 'FOO' in an
+    // expression like 'FOObar + 1'.
+    bool has_characters_before =
+        start != 0 && clang::isIdentifierBody(body[start - 1]);
+    bool has_characters_after =
+        start + var.size() < body.size() &&
+        clang::isIdentifierBody(body[start + var.size()]);
+
+    // Our token just contained the variable name as a substring. Continue
+    // searching the rest of the expression.
+    if (has_characters_before || has_characters_after) {
+      ++start;
+      continue;
+    }
+    return true;
+  }
+  return false;
+}
+
 static void AddLocalVariableDecls(const lldb::VariableListSP &var_list_sp,
-                                  StreamString &stream) {
+                                  StreamString &stream,
+                                  const std::string &expr) {
   for (size_t i = 0; i < var_list_sp->GetSize(); i++) {
     lldb::VariableSP var_sp = var_list_sp->GetVariableAtIndex(i);
 
@@ -170,15 +208,17 @@ static void AddLocalVariableDecls(const
     if (!var_name || var_name == "this" || var_name == ".block_descriptor")
       continue;
 
+    if (!expr.empty() && !ExprBodyContainsVar(expr, var_name.GetStringRef()))
+      continue;
+
     stream.Printf("using $__lldb_local_vars::%s;\n", var_name.AsCString());
   }
 }
 
-bool ClangExpressionSourceCode::GetText(std::string &text,
-                                   lldb::LanguageType wrapping_language,
-                                   bool static_method,
-                                   ExecutionContext &exe_ctx, bool add_locals,
-                                   llvm::ArrayRef<std::string> modules) const {
+bool ClangExpressionSourceCode::GetText(
+    std::string &text, lldb::LanguageType wrapping_language, bool static_method,
+    ExecutionContext &exe_ctx, bool add_locals, bool force_add_all_locals,
+    llvm::ArrayRef<std::string> modules) const {
   const char *target_specific_defines = "typedef signed char BOOL;\n";
   std::string module_macros;
 
@@ -256,7 +296,8 @@ bool ClangExpressionSourceCode::GetText(
         if (target->GetInjectLocalVariables(&exe_ctx)) {
           lldb::VariableListSP var_list_sp =
               frame->GetInScopeVariableList(false, true);
-          AddLocalVariableDecls(var_list_sp, lldb_local_var_decls);
+          AddLocalVariableDecls(var_list_sp, lldb_local_var_decls,
+                                force_add_all_locals ? "" : m_body);
         }
       }
     }

Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h?rev=359773&r1=359772&r2=359773&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h (original)
+++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h Thu May  2 03:12:56 2019
@@ -43,13 +43,14 @@ public:
   ///        evaluated.
   /// \param add_locals True iff local variables should be injected into the
   ///        expression source code.
+  /// \param force_add_all_locals True iff all local variables should be
+  ///        injected even if they are not used in the expression.
   /// \param modules A list of (C++) modules that the expression should import.
   ///
   /// \return true iff the source code was successfully generated.
   bool GetText(std::string &text, lldb::LanguageType wrapping_language,
-               bool static_method,
-               ExecutionContext &exe_ctx,
-               bool add_locals,
+               bool static_method, ExecutionContext &exe_ctx, bool add_locals,
+               bool force_add_all_locals,
                llvm::ArrayRef<std::string> modules) const;
 
   // Given a string returned by GetText, find the beginning and end of the body

Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp?rev=359773&r1=359772&r2=359773&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp (original)
+++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp Thu May  2 03:12:56 2019
@@ -386,7 +386,7 @@ static void SetupDeclVendor(ExecutionCon
 
 void ClangUserExpression::UpdateLanguageForExpr(
     DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
-    std::vector<std::string> modules_to_import) {
+    std::vector<std::string> modules_to_import, bool for_completion) {
   m_expr_lang = lldb::LanguageType::eLanguageTypeUnknown;
 
   std::string prefix = m_expr_prefix;
@@ -407,7 +407,7 @@ void ClangUserExpression::UpdateLanguage
 
     if (!source_code->GetText(m_transformed_text, m_expr_lang,
                               m_in_static_method, exe_ctx, !m_ctx_obj,
-                              modules_to_import)) {
+                              for_completion, modules_to_import)) {
       diagnostic_manager.PutString(eDiagnosticSeverityError,
                                    "couldn't construct expression body");
       return;
@@ -482,7 +482,8 @@ ClangUserExpression::GetModulesToImport(
 }
 
 bool ClangUserExpression::PrepareForParsing(
-    DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) {
+    DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
+    bool for_completion) {
   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
 
   InstallContext(exe_ctx);
@@ -511,7 +512,8 @@ bool ClangUserExpression::PrepareForPars
   LLDB_LOG(log, "List of imported modules in expression: {0}",
            llvm::make_range(used_modules.begin(), used_modules.end()));
 
-  UpdateLanguageForExpr(diagnostic_manager, exe_ctx, used_modules);
+  UpdateLanguageForExpr(diagnostic_manager, exe_ctx, used_modules,
+                        for_completion);
   return true;
 }
 
@@ -522,7 +524,7 @@ bool ClangUserExpression::Parse(Diagnost
                                 bool generate_debug_info) {
   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
 
-  if (!PrepareForParsing(diagnostic_manager, exe_ctx))
+  if (!PrepareForParsing(diagnostic_manager, exe_ctx, /*for_completion*/ false))
     return false;
 
   if (log)
@@ -721,7 +723,7 @@ bool ClangUserExpression::Complete(Execu
   // correct.
   DiagnosticManager diagnostic_manager;
 
-  if (!PrepareForParsing(diagnostic_manager, exe_ctx))
+  if (!PrepareForParsing(diagnostic_manager, exe_ctx, /*for_completion*/ true))
     return false;
 
   if (log)

Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h?rev=359773&r1=359772&r2=359773&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h (original)
+++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h Thu May  2 03:12:56 2019
@@ -178,11 +178,12 @@ private:
   std::vector<std::string> GetModulesToImport(ExecutionContext &exe_ctx);
   void UpdateLanguageForExpr(DiagnosticManager &diagnostic_manager,
                              ExecutionContext &exe_ctx,
-                             std::vector<std::string> modules_to_import);
+                             std::vector<std::string> modules_to_import,
+                             bool for_completion);
   bool SetupPersistentState(DiagnosticManager &diagnostic_manager,
                                    ExecutionContext &exe_ctx);
   bool PrepareForParsing(DiagnosticManager &diagnostic_manager,
-                         ExecutionContext &exe_ctx);
+                         ExecutionContext &exe_ctx, bool for_completion);
 
   ClangUserExpressionHelper m_type_system_helper;
 




More information about the lldb-commits mailing list