diff options
| author | Sean Callanan <scallanan@apple.com> | 2013-04-19 07:09:15 +0000 |
|---|---|---|
| committer | Sean Callanan <scallanan@apple.com> | 2013-04-19 07:09:15 +0000 |
| commit | 3dbf346ef358004c213774c7bb83e47687ced102 (patch) | |
| tree | d9054f8c56042c3c843cd3d8557154b167e166d2 /lldb/source/Breakpoint | |
| parent | cf5e5bade1638d5f2e2f8c1f808a5150f4208ba2 (diff) | |
| download | bcm5719-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.cpp | 104 | ||||
| -rw-r--r-- | lldb/source/Breakpoint/BreakpointOptions.cpp | 43 |
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()); } } } |

