Chromium Code Reviews| Index: runtime/vm/debugger.cc |
| diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc |
| index 5f14a55b5d82ae539b3440296112a5859ed59bce..f61b06d27a8f6f533e66ba56d16525ef8dde7392 100644 |
| --- a/runtime/vm/debugger.cc |
| +++ b/runtime/vm/debugger.cc |
| @@ -20,6 +20,7 @@ |
| #include "vm/object.h" |
| #include "vm/object_store.h" |
| #include "vm/os.h" |
| +#include "vm/parser.h" |
| #include "vm/port.h" |
| #include "vm/runtime_entry.h" |
| #include "vm/service.h" |
| @@ -2708,6 +2709,52 @@ RawFunction* Debugger::FindBestFit(const Script& script, |
| } |
| +// Return true if |token_pos| is within the token range of a function |
| +// literal initializer of a field. |
| +bool Debugger::MatchesLiteralFunctionPos(const Script& script, |
| + TokenPosition token_pos, |
| + TokenPosition last_token_pos) { |
| + Zone* zone = Thread::Current()->zone(); |
| + Class& cls = Class::Handle(zone); |
| + Array& fields = Array::Handle(zone); |
| + Field& field = Field::Handle(zone); |
| + Error& error = Error::Handle(zone); |
| + |
| + const ClassTable& class_table = *isolate_->class_table(); |
| + const intptr_t num_classes = class_table.NumCids(); |
| + for (intptr_t i = 1; i < num_classes; i++) { |
| + if (class_table.HasValidClassAt(i)) { |
| + cls = class_table.At(i); |
| + ASSERT(!cls.IsNull()); |
| + if (cls.script() != script.raw()) { |
| + continue; |
| + } |
| + error = cls.EnsureIsFinalized(Thread::Current()); |
| + if (!error.IsNull()) { |
| + continue; |
| + } |
| + fields = cls.fields(); |
| + if (!fields.IsNull()) { |
| + const intptr_t num_fields = fields.Length(); |
| + for (intptr_t pos = 0; pos < num_fields; pos++) { |
| + TokenPosition start; |
| + TokenPosition end; |
| + field ^= fields.At(pos); |
| + ASSERT(!field.IsNull()); |
| + if (Parser::FieldHasFunctionLiteralInitializer(field, &start, &end)) { |
| + if ((start <= token_pos && token_pos <= end) || |
| + (token_pos <= start && start <= last_token_pos)) { |
|
siva
2017/05/24 19:51:23
Not sure why this last_token_pos check needs to be
sivachandra
2017/05/26 07:17:58
We want the field initializer to start within the
|
| + return true; |
| + } |
| + } |
| + } |
| + } |
| + } |
|
siva
2017/05/24 19:51:23
Can the loop above be folded into Debugger::FindBe
sivachandra
2017/05/26 07:17:58
I have removed this new method and folded the esse
|
| + } |
| + return false; |
| +} |
| + |
| + |
| BreakpointLocation* Debugger::SetBreakpoint(const Script& script, |
| TokenPosition token_pos, |
| TokenPosition last_token_pos, |
| @@ -2715,67 +2762,78 @@ BreakpointLocation* Debugger::SetBreakpoint(const Script& script, |
| intptr_t requested_column) { |
| Function& func = Function::Handle(); |
| func = FindBestFit(script, token_pos); |
| - if (func.IsNull()) { |
| - return NULL; |
| - } |
| - // There may be more than one function object for a given function |
| - // in source code. There may be implicit closure functions, and |
| - // there may be copies of mixin functions. Collect all compiled |
| - // functions whose source code range matches exactly the best fit |
| - // function we found. |
| - GrowableObjectArray& functions = |
| - GrowableObjectArray::Handle(GrowableObjectArray::New()); |
| - FindCompiledFunctions(script, func.token_pos(), func.end_token_pos(), |
| - &functions); |
| - |
| - if (functions.Length() > 0) { |
| - // One or more function object containing this breakpoint location |
| - // have already been compiled. We can resolve the breakpoint now. |
| - DeoptimizeWorld(); |
| - func ^= functions.At(0); |
| - TokenPosition breakpoint_pos = |
| - ResolveBreakpointPos(func, token_pos, last_token_pos, requested_column); |
| - if (breakpoint_pos.IsReal()) { |
| - BreakpointLocation* bpt = |
| - GetBreakpointLocation(script, breakpoint_pos, requested_column); |
| - if (bpt != NULL) { |
| - // A source breakpoint for this location already exists. |
| + if (!func.IsNull()) { |
| + // There may be more than one function object for a given function |
| + // in source code. There may be implicit closure functions, and |
| + // there may be copies of mixin functions. Collect all compiled |
| + // functions whose source code range matches exactly the best fit |
| + // function we found. |
| + GrowableObjectArray& functions = |
| + GrowableObjectArray::Handle(GrowableObjectArray::New()); |
| + FindCompiledFunctions(script, func.token_pos(), func.end_token_pos(), |
| + &functions); |
| + |
| + if (functions.Length() > 0) { |
| + // One or more function object containing this breakpoint location |
| + // have already been compiled. We can resolve the breakpoint now. |
| + DeoptimizeWorld(); |
| + func ^= functions.At(0); |
| + TokenPosition breakpoint_pos = ResolveBreakpointPos( |
| + func, token_pos, last_token_pos, requested_column); |
| + if (breakpoint_pos.IsReal()) { |
| + BreakpointLocation* bpt = |
| + GetBreakpointLocation(script, breakpoint_pos, requested_column); |
| + if (bpt != NULL) { |
| + // A source breakpoint for this location already exists. |
| + return bpt; |
| + } |
| + bpt = new BreakpointLocation(script, token_pos, last_token_pos, |
| + requested_line, requested_column); |
| + bpt->SetResolved(func, breakpoint_pos); |
| + RegisterBreakpointLocation(bpt); |
| + |
| + // Create code breakpoints for all compiled functions we found. |
| + const intptr_t num_functions = functions.Length(); |
| + for (intptr_t i = 0; i < num_functions; i++) { |
| + func ^= functions.At(i); |
| + ASSERT(func.HasCode()); |
| + MakeCodeBreakpointAt(func, bpt); |
| + } |
| + if (FLAG_verbose_debug) { |
| + intptr_t line_number; |
| + intptr_t column_number; |
| + script.GetTokenLocation(breakpoint_pos, &line_number, &column_number); |
| + OS::Print( |
| + "Resolved BP for " |
| + "function '%s' at line %" Pd " col %" Pd "\n", |
| + func.ToFullyQualifiedCString(), line_number, column_number); |
| + } |
| return bpt; |
| } |
| - bpt = new BreakpointLocation(script, token_pos, last_token_pos, |
| - requested_line, requested_column); |
| - bpt->SetResolved(func, breakpoint_pos); |
| - RegisterBreakpointLocation(bpt); |
| - |
| - // Create code breakpoints for all compiled functions we found. |
| - const intptr_t num_functions = functions.Length(); |
| - for (intptr_t i = 0; i < num_functions; i++) { |
| - func ^= functions.At(i); |
| - ASSERT(func.HasCode()); |
| - MakeCodeBreakpointAt(func, bpt); |
| - } |
| - if (FLAG_verbose_debug) { |
| - intptr_t line_number; |
| - intptr_t column_number; |
| - script.GetTokenLocation(breakpoint_pos, &line_number, &column_number); |
| - OS::Print( |
| - "Resolved BP for " |
| - "function '%s' at line %" Pd " col %" Pd "\n", |
| - func.ToFullyQualifiedCString(), line_number, column_number); |
| - } |
| - return bpt; |
| } |
| + } else if (!MatchesLiteralFunctionPos(script, token_pos, last_token_pos)) { |
| + // |token_pos| is not within the range of a function literal initializer of |
| + // a field. |
| + return NULL; |
| } |
| - // There is no compiled function at this token position. |
| - // Register an unresolved breakpoint. |
| - if (FLAG_verbose_debug && !func.IsNull()) { |
| + // There is either an uncompiled function, or an uncompiled function literal |
| + // initializer of a field at |token_pos|. Hence, Register an unresolved |
| + // breakpoint. |
| + if (FLAG_verbose_debug) { |
| intptr_t line_number; |
| intptr_t column_number; |
| script.GetTokenLocation(token_pos, &line_number, &column_number); |
| - OS::Print( |
| - "Registering pending breakpoint for " |
| - "uncompiled function '%s' at line %" Pd " col %" Pd "\n", |
| - func.ToFullyQualifiedCString(), line_number, column_number); |
| + if (func.IsNull()) { |
| + OS::Print( |
| + "Registering pending breakpoint for " |
| + "an uncompiled function literal at line %" Pd " col %" Pd "\n", |
| + line_number, column_number); |
| + } else { |
| + OS::Print( |
| + "Registering pending breakpoint for " |
| + "uncompiled function '%s' at line %" Pd " col %" Pd "\n", |
| + func.ToFullyQualifiedCString(), line_number, column_number); |
| + } |
| } |
| BreakpointLocation* bpt = |
| GetBreakpointLocation(script, token_pos, requested_column); |