Script Panel Refactoring

From FirebugWiki

(Difference between revisions)
Jump to: navigation, search
(Breakpoints)
(Breakpoints)
(5 intermediate revisions not shown)
Line 188: Line 188:
=== Breakpoints ===
=== Breakpoints ===
-
 
+
This section describes architecture design for debugger breakpoints.
-
TODO
+
[[File:Breakpoints-architecture.png]]
[[File:Breakpoints-architecture.png]]
-
[[Breakpoint-add-sequence.png]]
+
* '''BreakpointStore''' The main component implementing public API for breakpoint creation and removal. This object is also responsible for client side persistence and initialization. There is one instance of this object per browser window (i.e. per Firebug). So, if a breakpoint is created in one context it automatically appears in all contexts that are using the same URL.
 +
* '''FunctionMonitor''', '''ScriptPanel''', '''BreakpointPanel''', '''ConsolePanel''' These represent example objects that are dealing with breakpoints. There is and can be even more such objects in the future. All these objects use API implemented by '''BreakpointStore''' object. These objects also register themselves as ''DebuggerTool'' listeners to be notified about breakpoint related changes.
 +
* '''DebuggerTool''' is responsible for breakpoint creation/removal on the server side. '''DebuggerTool''' registers itself as '''BreakpointStore''' listener to be notified about breakpoint creation/removal and sync the server side (i.e. create or remove breakpoints on the server side). There is one instance of this object per context.
 +
 
 +
 
 +
See an example of a breakpoint creation (using the Script panel UI):
 +
 
 +
[[File:Breakpoint-add-sequence.png]]
 +
 
 +
* The user clicks on '''ScriptView''' breakpoint column. It's currently based on Orion, but it could be also CodeMirror in the future.
 +
* '''ScriptView''' notifies '''ScriptPanel''' about the action.
 +
* '''ScriptPanel''' is using '''BreakpointStore''' API to create a breakpoint. It calls ''addBreakpoint''. Breakpoint creation is asynchronous since the server side needs to be notified through TCP/IP. UI objects (e.g. panels) should wait for ''onBreakpointAdded'' event to update themselves.
 +
* '''BreakpointStore''' sends ''onAddBreakpoint'' event to all registered listeners. These listeners are mostly all '''DebuggerTool''' instances (one per context) and also all UI object that want to display a temporary waiting-icon at the place where the breakpoint will (asynchronously) appear.
 +
* '''DebuggerTool''' uses its associated '''ThreadClient''' to create a breakpoint on the server side. Each '''DebuggerTool''' instance will do it for its context. This way all contexts will be updated.
 +
* '''ThreadClient''' sends packet to the server side and waits for asynchronous response.
 +
* '''DebuggerTool''' has a direct (function) callback that is executed as soon as the response comes back from the server. Breakpoint's location is auto-corrected at this point if needed.
 +
* '''DebuggerTool''' notifies all registered listeners (usually panels coming from the same context) about added breakpoint. It sends "onBreakpointAdded" event to the ''ScriptPanel'' in this scenario.
 +
* '''ScriptPanel''' calls ''updateBreakpoint'' so, the '''ScriptView''' can update itself. Remove the waiting-icon and display the new breakpoint at the right location. It might also scroll to make sure that auto-corrected location is visible to the user.

Revision as of 10:57, 15 April 2013

This page summarizes refactoring the Firebug debugger to use JSD2 and adding support for remote JavaScript debugging. Issue 5421 tracks the actual changes done.

Contents

Resources

Firebug Wiki:

Mozilla Wiki:

Goals

  • Adopt JSD2 (get rid of all JSD1 APIs)
  • Support remote debugging

Related Issues

JSD2 API Requirements

The following list summarizes the high-level features that Firebug needs to support. It should be verified that all the features can re-implemented on top of JSD2 before starting the refactoring.

Not Ready in JSD2

  • There is not source for evals.
  • new Function scripts?
  • Meta bug: Implement a script Debugger
    • As soon as this one is fixed
    • Profiling is unrelated to JSD2. What is the plan here?
    • Tracking (break on) throw/catch/error; also what is the plan?
  • Conditional breakpoints (bug 740825)

Current Debugger Architecture

This section describes the current debugger architecture.

Current-debugger-architecture.png

There are several layers/objects so, let's describe them step by step starting from the bottom.

  • Backend: JSD1, FirebugService, Debugger
  • Frontend: JavaScriptTool, ScriptPanel

JSD1

This layer represents JSD1 platform API. These API allows to implement script debuggers and represent direct competition to JSD2 API. Of course this layer should entirely disappear and should be replaced by JSD2.

Firebug Service

Firebug service is implemented as js module on top of JSD1 layer. The object is called FBS and it's purpose is to wrap JSD1 API so, they are not directly accessed anywhere else. This layer also maintain list of registered debuggers (usually Firebug.Debugger module) and fires various events to them (e.g. onToggleBreakpoint, onToggleMonitor, etc.) or execute theirs callback (e.g. onBreak, onFunctionCall, onError, onThrow, onScriptCreated, etc.)

Main responsibilities:

  • Activate/deactivate JSD in the browser. The activation is global for all current browser windows.
  • Hook debugger events (interrupts, break on a breakpoint, etc.)
  • Maintains list of registered debuggers (there is usually just one - Firebug debugger) and sends events to them.
  • Manages nested event loop that is created for the debugger UI when page JS execution breaks.
  • Sets/removes/enables/disables/saves/loads breakpoints
  • Implements debugger stepping over/in/out/runUntil
  • Monitors function calls
  • Starts/stops profiling
  • Tracks exceptions and errors (not working well)
  • Tracks compiled scripts (not all of them)

Debugger

This object is derived from Firebug.Module and represents Firebug's debugger. It's also registered as a debugger into Firebug Service (FBS). This object should be the only one accessing FBS. It calls FBS API and receives various callbacks and events.

This object implements methods that can be used by the Script panel or other parts of Firebug (e.g. by those panels which implements BON).

Some examples of the API:

  • evaluate, evaluateInCallingFrame
  • breakNow, getCurrentStackTrace
  • rerun
  • stepOver, stepInto, stepOut, runUntil, resume
  • setBreakpoint, clearBrakpoint, etc.
  • monitorFunction, unmonitorFunction
  • monitorScript, unmonitorScript
  • activateDebugger, deactivateDebugger

Implementation of these methods is based on FBS API.

There is also Firebug.DebuggerListener that defines the interface used by FBS

  • onStop, onResume, onThrow, onError, onScriptCreated (there is more onScriptCreated events)

This object is observable and it activates the underlying JSD only if an observer exists. The observer is currently the Script panel even if it would make a bit more sense if it's actually the JavaScriptTool.

JavaScriptTool

This object is part or BTI and represents a javascript debugger tool. This object is like a proxy sitting between Firebug.Debugger and the ScriptPanel. The current implementation is in-process only so, based on direct Firebug.Debugger API calls.

API of the tool is as follows:

  • setBreakpoint, clearBreakpoint, enableBreakpoint, disableBreakpoint, isBreakpointDisabled, getBreakpointCondition
  • rerun
  • resumeJavaScript, stepOver, stepInto, stepOut, runUntil
  • onConnect, onDisconnect
  • onStartDebugging, onStopDebugging
  • onCompilationUnit

The BTI is used by Crossfire. Crossfire has the following structure:

   Crossfire Panel
       ↓
   Crossfire Module
       ↓
   Crossfire Server
       ↓
   Crossfire Socket Transport

When starting up it does the following.

  1. Register tools (e.g. console, inspector, ...)
  2. Start server
  3. Create socket transport
  4. Add BTI listener
  5. Set connection status

Script Panel

The Script Panel sits at the top of the whole stack of layers/objects. It represents the debugger UI (a view + a controller). The implementation of this object is quite extensive since it also includes the source code view and viewport (see firebug/js/sourceBox.js module.

The Script panel should never access the Firebug.Debugger directly. It should always use the JavaScriptTool.

So, for example, if the user clicks on the Breakpoint Column, the action is handled by the Script panel, forwarded to the JavaScriptTool, which forwards it to the Firebug.Debugger, which forwards it to FBS. Finally, FBS is using JSD1 API to set the breakpoint.

There are side panels (Breakpoints, Watch and Stack), which are synchronized automatically with the Script panel. They should all use JavaScriptTool to get appropriate data to display.

The synchronization happens through basic Firebug mechanisms like, updateSelection and updateLocation.


New Debugger Architecture

Panels

The Script panel needs to be built on top of JSD2, remote protocol and Firebug remoting API. Remoting is already supported by HTTP Monitor.

First of all, take a look a the following diagram.

New-script-panel-architecture.png

  • DebuggerClient This object comes from Firefox platform and is responsible for connection to the server back-end. The object maintains the underlying transport layer, it's responsible for tab attach/detach, it implements basic packets send and receive logic. The implementation is currently within resource://gre/modules/devtools/dbg-client.jsm module.
  • DebuggerClientModule This module (singleton, one per Firebug instance) represents a wrapper around DebuggerClient. It implements connection setup and initialization (e.g. port number). This object represents the connection in Firebug and should be shared by all remotable tools (e.g. the Script panel, Net panel, Profiler, etc.). Name of this module isn't probably descriptive enough, it could be changed. This object (or related object) could also replace the TabWatcher.
  • DebuggerTool This object implements API related to debugging (typical methods: stepIn, stepOut, setBreakpoint, etc.). The Script panel should always consume debugger API through this object. DebuggerTool registers itself as a DebuggerClientModule and thus gets all necessary events from the back-end (e.g. onConnect, onThreadAttached, etc.)
  • ScriptPanel Represents debugger UI and listens mostly to onStartDebugging and onStopDebugging events. Those are used to properly updated the panel's UI.
  • ScriptView This object is currently based on Orion (but could be replaced by CodeMirror, see bug 816756). The main responsibility of this object is displaying the source code (using color syntax highlight).
  • CallstackPanel This panel displays list of frames when the debugger is halted. The frame list is synchronized with ThreadClient's stack frame cache using framesadded and framescleared events.
  • ThreadClient This object comes from Firefox platform and is responsible for tab-thread related logic.
  • BreakpointStore Responsible for breakpoint persistence across Firefox restarts (in breakpoint.json file).


Grips

A grip represents handle to server side object (see RDP for more details).

Firebug framework introduces several objects that deals with these handles, see the next diagram.

Grips-architecture.jpg

  • GripFactory This is the place where grips instances are created. Every grip object is associated with a class (see RDP) and uses Firebug.registerGrip to register itself. This factory uses a list of registered types and instantiates the right one according to the server side grip class attribute.
  • GripCache The cache is the place where panels and other parts of Firebug should ask for grip-objects. If the requested object is not in the cache a request is sent to the backend and a promise synchronously returned and asynchronously resolved. If the object is already in the cache a promise is returned and synchronously resolved. GripCache is the only place, which uses GripFactory. See more about asynchronous data access.
  • ObjectGrip Represents a wrapper for RDP Grip
  • Property Represents a wrapper for RDP Property
  • FunctionGrip Represents a wrapper for a function object.
  • ScopeGrip Represents a wrapper for a scope object. This object is used by the Watch panel to show chain of current scopes.

Breakpoints

This section describes architecture design for debugger breakpoints.

Breakpoints-architecture.png

  • BreakpointStore The main component implementing public API for breakpoint creation and removal. This object is also responsible for client side persistence and initialization. There is one instance of this object per browser window (i.e. per Firebug). So, if a breakpoint is created in one context it automatically appears in all contexts that are using the same URL.
  • FunctionMonitor, ScriptPanel, BreakpointPanel, ConsolePanel These represent example objects that are dealing with breakpoints. There is and can be even more such objects in the future. All these objects use API implemented by BreakpointStore object. These objects also register themselves as DebuggerTool listeners to be notified about breakpoint related changes.
  • DebuggerTool is responsible for breakpoint creation/removal on the server side. DebuggerTool registers itself as BreakpointStore listener to be notified about breakpoint creation/removal and sync the server side (i.e. create or remove breakpoints on the server side). There is one instance of this object per context.


See an example of a breakpoint creation (using the Script panel UI):

Breakpoint-add-sequence.png

  • The user clicks on ScriptView breakpoint column. It's currently based on Orion, but it could be also CodeMirror in the future.
  • ScriptView notifies ScriptPanel about the action.
  • ScriptPanel is using BreakpointStore API to create a breakpoint. It calls addBreakpoint. Breakpoint creation is asynchronous since the server side needs to be notified through TCP/IP. UI objects (e.g. panels) should wait for onBreakpointAdded event to update themselves.
  • BreakpointStore sends onAddBreakpoint event to all registered listeners. These listeners are mostly all DebuggerTool instances (one per context) and also all UI object that want to display a temporary waiting-icon at the place where the breakpoint will (asynchronously) appear.
  • DebuggerTool uses its associated ThreadClient to create a breakpoint on the server side. Each DebuggerTool instance will do it for its context. This way all contexts will be updated.
  • ThreadClient sends packet to the server side and waits for asynchronous response.
  • DebuggerTool has a direct (function) callback that is executed as soon as the response comes back from the server. Breakpoint's location is auto-corrected at this point if needed.
  • DebuggerTool notifies all registered listeners (usually panels coming from the same context) about added breakpoint. It sends "onBreakpointAdded" event to the ScriptPanel in this scenario.
  • ScriptPanel calls updateBreakpoint so, the ScriptView can update itself. Remove the waiting-icon and display the new breakpoint at the right location. It might also scroll to make sure that auto-corrected location is visible to the user.
Personal tools