| Index: runtime/vm/debugger.cc
|
| ===================================================================
|
| --- runtime/vm/debugger.cc (revision 42362)
|
| +++ runtime/vm/debugger.cc (working copy)
|
| @@ -64,6 +64,7 @@
|
| end_token_pos_(end_token_pos),
|
| is_resolved_(false),
|
| is_enabled_(false),
|
| + is_one_shot_(false),
|
| next_(NULL),
|
| function_(Function::null()),
|
| line_number_(-1) {
|
| @@ -1138,48 +1139,8 @@
|
| }
|
|
|
|
|
| -RawError* Debugger::SetInternalBreakpoints(const Function& target_function) {
|
| - if (target_function.is_native()) {
|
| - // Can't instrument native functions. Fail silently.
|
| - return Error::null();
|
| - }
|
| - Isolate* isolate = Isolate::Current();
|
| - if (!target_function.HasCode()) {
|
| - const Error& error = Error::Handle(
|
| - Compiler::CompileFunction(isolate, target_function));
|
| - if (!error.IsNull()) {
|
| - return error.raw();
|
| - }
|
| - }
|
| - // Hang on to the code object before deoptimizing, in case deoptimization
|
| - // might cause the GC to run.
|
| - Code& code = Code::Handle(isolate, target_function.unoptimized_code());
|
| - ASSERT(!code.IsNull());
|
| - DeoptimizeWorld();
|
| - ASSERT(!target_function.HasOptimizedCode());
|
| - PcDescriptors& desc = PcDescriptors::Handle(isolate, code.pc_descriptors());
|
| - PcDescriptors::Iterator iter(desc, kSafepointKind);
|
| - while (iter.MoveNext()) {
|
| - if (iter.TokenPos() != Scanner::kNoSourcePos) {
|
| - CodeBreakpoint* bpt = GetCodeBreakpoint(iter.Pc());
|
| - if (bpt != NULL) {
|
| - // There is already a breakpoint for this address. Make sure
|
| - // it is enabled.
|
| - bpt->Enable();
|
| - continue;
|
| - }
|
| - bpt = new CodeBreakpoint(code, iter.TokenPos(),
|
| - iter.Pc(), iter.Kind());
|
| - RegisterCodeBreakpoint(bpt);
|
| - bpt->Enable();
|
| - }
|
| - }
|
| - return Error::null();
|
| -}
|
| -
|
| -
|
| void Debugger::SignalBpResolved(SourceBreakpoint* bpt) {
|
| - if (HasEventHandler()) {
|
| + if (HasEventHandler() && !bpt->IsOneShot()) {
|
| DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointResolved);
|
| event.set_breakpoint(bpt);
|
| InvokeEventHandler(&event);
|
| @@ -1418,9 +1379,23 @@
|
| }
|
|
|
|
|
| +static intptr_t LastTokenOnLine(const TokenStream& tokens, intptr_t pos) {
|
| + TokenStream::Iterator iter(tokens, pos, TokenStream::Iterator::kAllTokens);
|
| + ASSERT(iter.IsValid());
|
| + intptr_t last_pos = pos;
|
| + while ((iter.CurrentTokenKind() != Token::kNEWLINE) &&
|
| + (iter.CurrentTokenKind() != Token::kEOS)) {
|
| + last_pos = iter.CurrentPosition();
|
| + iter.Advance();
|
| + }
|
| + return last_pos;
|
| +}
|
| +
|
| +
|
| // Given a function and a token range, return the best fit
|
| // token position to set a breakpoint. The best fit is the safe point
|
| -// with the lowest compiled code address within the token range.
|
| +// in the line closest to the beginning of the token range, and within
|
| +// that line, the safe point with the lowest compiled code address.
|
| intptr_t Debugger::ResolveBreakpointPos(const Function& func,
|
| intptr_t requested_token_pos,
|
| intptr_t last_token_pos) {
|
| @@ -1437,41 +1412,45 @@
|
| Code& code = Code::Handle(func.unoptimized_code());
|
| ASSERT(!code.IsNull());
|
| PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors());
|
| +
|
| + // First pass: find the safe point which is closest to the beginning
|
| + // of the given token range.
|
| intptr_t best_fit_pos = INT_MAX;
|
| - uword lowest_pc = kUwordMax;
|
| - intptr_t lowest_pc_token_pos = INT_MAX;
|
| PcDescriptors::Iterator iter(desc, kSafepointKind);
|
| while (iter.MoveNext()) {
|
| const intptr_t desc_token_pos = iter.TokenPos();
|
| - ASSERT(desc_token_pos >= 0);
|
| - if (desc_token_pos != Scanner::kNoSourcePos) {
|
| - if ((desc_token_pos < requested_token_pos) ||
|
| - (desc_token_pos > last_token_pos)) {
|
| - // This descriptor is outside the desired token range.
|
| - continue;
|
| - }
|
| - if (desc_token_pos < best_fit_pos) {
|
| - // So far, this descriptor has the lowest token position after
|
| - // the first acceptable token position.
|
| - best_fit_pos = desc_token_pos;
|
| - }
|
| - if (iter.Pc() < lowest_pc) {
|
| - // This descriptor so far has the lowest code address.
|
| + if ((desc_token_pos != Scanner::kNoSourcePos) &&
|
| + (desc_token_pos < best_fit_pos) &&
|
| + (desc_token_pos >= requested_token_pos) &&
|
| + (desc_token_pos <= last_token_pos)) {
|
| + best_fit_pos = desc_token_pos;
|
| + }
|
| + }
|
| + // Second pass (if we found a safe point in the first pass):
|
| + // For all token positions on the same line, select the one
|
| + // with the lowest compiled code address. E.g., in a line with
|
| + // the nested function calls f(g(x)), the call g() will have a lower
|
| + // compiled code address but is not the lowest token position in the
|
| + // line.
|
| + if (best_fit_pos != INT_MAX) {
|
| + const Script& script = Script::Handle(func.script());
|
| + const TokenStream& tokens = TokenStream::Handle(script.tokens());
|
| + const intptr_t begin_pos = best_fit_pos;
|
| + const intptr_t end_of_line_pos = LastTokenOnLine(tokens, begin_pos);
|
| + uword lowest_pc = kUwordMax;
|
| + PcDescriptors::Iterator iter(desc, kSafepointKind);
|
| + while (iter.MoveNext()) {
|
| + const intptr_t pos = iter.TokenPos();
|
| + if ((pos != Scanner::kNoSourcePos) &&
|
| + (begin_pos <= pos) && (pos <= end_of_line_pos) &&
|
| + (iter.Pc() < lowest_pc)) {
|
| lowest_pc = iter.Pc();
|
| - lowest_pc_token_pos = desc_token_pos;
|
| + best_fit_pos = pos;
|
| }
|
| }
|
| - }
|
| - if (lowest_pc_token_pos != INT_MAX) {
|
| - // We found the pc descriptor that has the lowest execution address.
|
| - // This is the first possible breakpoint after the requested token
|
| - // position. We use this instead of the nearest PC descriptor
|
| - // measured in token index distance.
|
| - return lowest_pc_token_pos;
|
| - }
|
| - if (best_fit_pos != INT_MAX) {
|
| return best_fit_pos;
|
| }
|
| +
|
| // We didn't find a safe point in the given token range. Try and find
|
| // a safe point in the remaining source code of the function.
|
| if (last_token_pos < func.end_token_pos()) {
|
| @@ -1554,12 +1533,12 @@
|
| if ((function.token_pos() == start_pos)
|
| && (function.end_token_pos() == end_pos)
|
| && (function.script() == script.raw())) {
|
| - if (function.HasCode()) {
|
| + if (function.HasCode() && !function.IsAsyncFunction()) {
|
| function_list->Add(function);
|
| }
|
| if (function.HasImplicitClosureFunction()) {
|
| function = function.ImplicitClosureFunction();
|
| - if (function.HasCode()) {
|
| + if (function.HasCode() && !function.IsAsyncFunction()) {
|
| function_list->Add(function);
|
| }
|
| }
|
| @@ -1575,12 +1554,12 @@
|
| if ((function.token_pos() == start_pos)
|
| && (function.end_token_pos() == end_pos)
|
| && (function.script() == script.raw())) {
|
| - if (function.HasCode()) {
|
| + if (function.HasCode() && !function.IsAsyncFunction()) {
|
| function_list->Add(function);
|
| }
|
| if (function.HasImplicitClosureFunction()) {
|
| function = function.ImplicitClosureFunction();
|
| - if (function.HasCode()) {
|
| + if (function.HasCode() && !function.IsAsyncFunction()) {
|
| function_list->Add(function);
|
| }
|
| }
|
| @@ -1723,7 +1702,7 @@
|
| if (FLAG_verbose_debug) {
|
| intptr_t line_number;
|
| script.GetTokenLocation(breakpoint_pos, &line_number, NULL);
|
| - OS::Print("Resolved breakpoint for "
|
| + OS::Print("Resolved BP for "
|
| "function '%s' at line %" Pd "\n",
|
| func.ToFullyQualifiedCString(),
|
| line_number);
|
| @@ -1770,14 +1749,11 @@
|
|
|
|
|
| RawError* Debugger::OneTimeBreakAtEntry(const Function& target_function) {
|
| - Error& err = Error::Handle();
|
| - err = SetInternalBreakpoints(target_function);
|
| - if (err.IsNull() && target_function.HasImplicitClosureFunction()) {
|
| - const Function& closure_func =
|
| - Function::Handle(target_function.ImplicitClosureFunction());
|
| - err = SetInternalBreakpoints(closure_func);
|
| + SourceBreakpoint* bpt = SetBreakpointAtEntry(target_function);
|
| + if (bpt != NULL) {
|
| + bpt->SetIsOneShot();
|
| }
|
| - return err.raw();
|
| + return Error::null();
|
| }
|
|
|
|
|
| @@ -2136,6 +2112,10 @@
|
| isolate_->set_single_step(false);
|
| ASSERT(!IsPaused());
|
| ASSERT(obj_cache_ == NULL);
|
| + if ((bpt != NULL) && bpt->IsOneShot()) {
|
| + RemoveBreakpoint(bpt->id());
|
| + bpt = NULL;
|
| + }
|
| DebuggerEvent event(isolate_, DebuggerEvent::kBreakpointReached);
|
| event.set_top_frame(top_frame);
|
| event.set_breakpoint(bpt);
|
|
|