summaryrefslogtreecommitdiffstats
path: root/lldb/source/Breakpoint
diff options
context:
space:
mode:
authorSean Callanan <scallanan@apple.com>2013-04-19 07:09:15 +0000
committerSean Callanan <scallanan@apple.com>2013-04-19 07:09:15 +0000
commit3dbf346ef358004c213774c7bb83e47687ced102 (patch)
treed9054f8c56042c3c843cd3d8557154b167e166d2 /lldb/source/Breakpoint
parentcf5e5bade1638d5f2e2f8c1f808a5150f4208ba2 (diff)
downloadbcm5719-llvm-3dbf346ef358004c213774c7bb83e47687ced102.tar.gz
bcm5719-llvm-3dbf346ef358004c213774c7bb83e47687ced102.zip
Optimized the way breakpoint conditions are evaluated.
Previously, the options for a breakopint or its locations stored only the text of the breakpoint condition (ironically, they used ClangUserExpression as a glorified std::string) and, each time the condition had to be evaluated in the StopInfo code, the expression parser would be invoked via a static method to parse and then execute the expression. I made several changes here: - Each breakpoint location now has its own ClangUserExpressionSP containing a version of the breakpoint expression compiled for that exact location. - Whenever the breakpoint is hit, the breakpoint condition expression is simply re-run to determine whether to stop. - If the process changes (e.g., it's re-run) or the source code of the expression changes (we use a hash so as to avoid doing string comparisons) the ClangUserExpressionSP is re-generated. This should improve performance of breakpoint conditions significantly, and takes advantage of the recent expression re-use work. llvm-svn: 179838
Diffstat (limited to 'lldb/source/Breakpoint')
-rw-r--r--lldb/source/Breakpoint/BreakpointLocation.cpp104
-rw-r--r--lldb/source/Breakpoint/BreakpointOptions.cpp43
2 files changed, 124 insertions, 23 deletions
diff --git a/lldb/source/Breakpoint/BreakpointLocation.cpp b/lldb/source/Breakpoint/BreakpointLocation.cpp
index 71e8eb7c868..04142b268e4 100644
--- a/lldb/source/Breakpoint/BreakpointLocation.cpp
+++ b/lldb/source/Breakpoint/BreakpointLocation.cpp
@@ -240,9 +240,109 @@ BreakpointLocation::SetCondition (const char *condition)
}
const char *
-BreakpointLocation::GetConditionText () const
+BreakpointLocation::GetConditionText (size_t *hash) const
{
- return GetOptionsNoCreate()->GetConditionText();
+ return GetOptionsNoCreate()->GetConditionText(hash);
+}
+
+bool
+BreakpointLocation::ConditionSaysStop (ExecutionContext &exe_ctx, Error &error)
+{
+ Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
+
+ size_t condition_hash;
+ const char *condition_text = GetConditionText(&condition_hash);
+
+ if (!condition_text)
+ return false;
+
+ if (condition_hash != m_condition_hash ||
+ !m_user_expression_sp ||
+ !m_user_expression_sp->MatchesContext(exe_ctx))
+ {
+ m_user_expression_sp.reset(new ClangUserExpression(condition_text,
+ NULL,
+ lldb::eLanguageTypeUnknown,
+ ClangUserExpression::eResultTypeAny));
+
+ StreamString errors;
+
+ if (!m_user_expression_sp->Parse(errors,
+ exe_ctx,
+ eExecutionPolicyOnlyWhenNeeded,
+ true))
+ {
+ error.SetErrorStringWithFormat("Couldn't parse conditional expression:\n%s",
+ errors.GetData());
+ m_user_expression_sp.reset();
+ return false;
+ }
+
+ m_condition_hash = condition_hash;
+ }
+
+ // We need to make sure the user sees any parse errors in their condition, so we'll hook the
+ // constructor errors up to the debugger's Async I/O.
+
+ ValueObjectSP result_value_sp;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ const bool try_all_threads = true;
+
+ Error expr_error;
+
+ StreamString execution_errors;
+
+ ClangExpressionVariableSP result_variable_sp;
+
+ ExecutionResults result_code =
+ m_user_expression_sp->Execute(execution_errors,
+ exe_ctx,
+ unwind_on_error,
+ ignore_breakpoints,
+ m_user_expression_sp,
+ result_variable_sp,
+ try_all_threads,
+ ClangUserExpression::kDefaultTimeout);
+
+ bool ret;
+
+ if (result_code == eExecutionCompleted)
+ {
+ result_value_sp = result_variable_sp->GetValueObject();
+
+ if (result_value_sp)
+ {
+ Scalar scalar_value;
+ if (result_value_sp->ResolveValue (scalar_value))
+ {
+ if (scalar_value.ULongLong(1) == 0)
+ ret = false;
+ else
+ ret = true;
+ if (log)
+ log->Printf("Condition successfully evaluated, result is %s.\n",
+ ret ? "true" : "false");
+ }
+ else
+ {
+ ret = false;
+ error.SetErrorString("Failed to get an integer result from the expression");
+ }
+ }
+ else
+ {
+ ret = false;
+ error.SetErrorString("Failed to get any result from the expression");
+ }
+ }
+ else
+ {
+ ret = false;
+ error.SetErrorStringWithFormat("Couldn't execute expression:\n%s", execution_errors.GetData());
+ }
+
+ return ret;
}
uint32_t
diff --git a/lldb/source/Breakpoint/BreakpointOptions.cpp b/lldb/source/Breakpoint/BreakpointOptions.cpp
index 11335fb1db9..d0aaf47d8a6 100644
--- a/lldb/source/Breakpoint/BreakpointOptions.cpp
+++ b/lldb/source/Breakpoint/BreakpointOptions.cpp
@@ -42,7 +42,8 @@ BreakpointOptions::BreakpointOptions() :
m_one_shot (false),
m_ignore_count (0),
m_thread_spec_ap (),
- m_condition_ap()
+ m_condition_text (),
+ m_condition_text_hash (0)
{
}
@@ -56,13 +57,12 @@ BreakpointOptions::BreakpointOptions(const BreakpointOptions& rhs) :
m_enabled (rhs.m_enabled),
m_one_shot (rhs.m_one_shot),
m_ignore_count (rhs.m_ignore_count),
- m_thread_spec_ap (),
- m_condition_ap ()
+ m_thread_spec_ap ()
{
if (rhs.m_thread_spec_ap.get() != NULL)
m_thread_spec_ap.reset (new ThreadSpec(*rhs.m_thread_spec_ap.get()));
- if (rhs.m_condition_ap.get())
- m_condition_ap.reset (new ClangUserExpression (rhs.m_condition_ap->GetUserText(), NULL, lldb::eLanguageTypeUnknown, ClangUserExpression::eResultTypeAny));
+ m_condition_text = rhs.m_condition_text;
+ m_condition_text_hash = rhs.m_condition_text_hash;
}
//----------------------------------------------------------------------
@@ -79,8 +79,8 @@ BreakpointOptions::operator=(const BreakpointOptions& rhs)
m_ignore_count = rhs.m_ignore_count;
if (rhs.m_thread_spec_ap.get() != NULL)
m_thread_spec_ap.reset(new ThreadSpec(*rhs.m_thread_spec_ap.get()));
- if (rhs.m_condition_ap.get())
- m_condition_ap.reset (new ClangUserExpression (rhs.m_condition_ap->GetUserText(), NULL, lldb::eLanguageTypeUnknown, ClangUserExpression::eResultTypeAny));
+ m_condition_text = rhs.m_condition_text;
+ m_condition_text_hash = rhs.m_condition_text_hash;
return *this;
}
@@ -162,24 +162,25 @@ BreakpointOptions::HasCallback ()
void
BreakpointOptions::SetCondition (const char *condition)
{
- if (condition == NULL || condition[0] == '\0')
- {
- if (m_condition_ap.get())
- m_condition_ap.reset();
- }
- else
- {
- m_condition_ap.reset(new ClangUserExpression (condition, NULL, lldb::eLanguageTypeUnknown, ClangUserExpression::eResultTypeAny));
- }
+ m_condition_text.assign(condition);
+ std::hash<std::string> hasher;
+ m_condition_text_hash = hasher(m_condition_text);
}
const char *
-BreakpointOptions::GetConditionText () const
+BreakpointOptions::GetConditionText (size_t *hash) const
{
- if (m_condition_ap.get())
- return m_condition_ap->GetUserText();
+ if (!m_condition_text.empty())
+ {
+ if (hash)
+ *hash = m_condition_text_hash;
+
+ return m_condition_text.c_str();
+ }
else
+ {
return NULL;
+ }
}
const ThreadSpec *
@@ -250,12 +251,12 @@ BreakpointOptions::GetDescription (Stream *s, lldb::DescriptionLevel level) cons
m_callback_baton_sp->GetDescription (s, level);
}
}
- if (m_condition_ap.get())
+ if (!m_condition_text.empty())
{
if (level != eDescriptionLevelBrief)
{
s->EOL();
- s->Printf("Condition: %s\n", m_condition_ap->GetUserText());
+ s->Printf("Condition: %s\n", m_condition_text.c_str());
}
}
}
OpenPOWER on IntegriCloud