Bug 135396

Summary: Web Inspector: breakpoints are always speculatively resolved when restored from local storage
Product: WebKit Reporter: Brian Burg <burg>
Component: Web InspectorAssignee: Brian Burg <burg>
Status: RESOLVED FIXED    
Severity: Normal CC: commit-queue, graouts, joepeck, timothy, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: 528+ (Nightly build)   
Hardware: All   
OS: All   
Bug Depends on:    
Bug Blocks: 135367    
Attachments:
Description Flags
Patch none

Description Brian Burg 2014-07-29 15:30:45 PDT
A long-time quirk/optimization in the frontend is that we immediately set a breakpoint as resolved if the breakpoint was successfully set in the backend. The purpose of this is to make clicking in the gutter immediately produce a resolved breakpoint, rather than waiting for several round trips (perceived as lag).

However, the logic is wrong such that any breakpoint that is set via DebuggerManager.addBreakpoint will be speculatively resolved, even if its corresponding source code has never been loaded. This can cause problems for later code that assumes a resolved breakpoint also has a valid sourceCodeLocation.sourceCode.
Comment 1 Radar WebKit Bug Importer 2014-07-29 15:33:12 PDT
<rdar://problem/17848753>
Comment 2 Brian Burg 2014-07-29 15:56:49 PDT
Created attachment 235707 [details]
Patch
Comment 3 WebKit Commit Bot 2014-07-29 20:49:11 PDT
Comment on attachment 235707 [details]
Patch

Clearing flags on attachment: 235707

Committed r171784: <http://trac.webkit.org/changeset/171784>
Comment 4 WebKit Commit Bot 2014-07-29 20:49:14 PDT
All reviewed patches have been landed.  Closing bug.
Comment 5 Joseph Pecoraro 2014-07-29 21:24:55 PDT
Comment on attachment 235707 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=235707&action=review

> Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js:257
> +        function speculativelyResolveBreakpoint(breakpoint) {
> +            breakpoint.resolved = true;
> +        }
> +
>          if (!breakpoint.disabled)
> -            this._setBreakpoint(breakpoint);
> +            this._setBreakpoint(breakpoint, shouldSpeculativelyResolve ? speculativelyResolveBreakpoint.bind(null, breakpoint) : null);

I think we can improve this.

The _setBreakpoint callback should be passed the breakpoint, so that we aren't creating all this bound functions.

    function speculativelyResolveBreakpoint(breakpoint) {
        breakpoint.resolved = true;
    }

    this._setBreakpoint(breakpoint, shouldSpeculativelyResolve ? speculativelyResolveBrekapoint : null);

> Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js:548
> +            for (var location of locations)
> +                this.breakpointResolved(breakpointIdentifier, location);
>  
>              if (typeof callback === "function")
>                  callback();

And here, callback would pass the breakpoint:

    callback(breakpoint);
Comment 6 Brian Burg 2014-07-30 09:50:07 PDT
(In reply to comment #5)
> (From update of attachment 235707 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=235707&action=review
> 
> > Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js:257
> > +        function speculativelyResolveBreakpoint(breakpoint) {
> > +            breakpoint.resolved = true;
> > +        }
> > +
> >          if (!breakpoint.disabled)
> > -            this._setBreakpoint(breakpoint);
> > +            this._setBreakpoint(breakpoint, shouldSpeculativelyResolve ? speculativelyResolveBreakpoint.bind(null, breakpoint) : null);
> 
> I think we can improve this.
> 
> The _setBreakpoint callback should be passed the breakpoint, so that we aren't creating all this bound functions.
> 
>     function speculativelyResolveBreakpoint(breakpoint) {
>         breakpoint.resolved = true;
>     }
> 
>     this._setBreakpoint(breakpoint, shouldSpeculativelyResolve ? speculativelyResolveBrekapoint : null);
> 
> > Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js:548
> > +            for (var location of locations)
> > +                this.breakpointResolved(breakpointIdentifier, location);
> >  
> >              if (typeof callback === "function")
> >                  callback();
> 
> And here, callback would pass the breakpoint:
> 
>     callback(breakpoint);

I was going to go full-blown promises here since this code doesn't handle errors well, but I'm trying to restrain myself from allocation and command optimizations until we have some useful profiling data.