Venkman Internals

  • Revision slug: Venkman_Internals
  • Revision title: Venkman Internals
  • Revision id: 187175
  • Created:
  • Creator: GijsKruitbosch
  • Is current revision? No
  • Comment

Revision Content

Start with Venkman Information.

Notes on Venkman source code. As with any complex application, aspects of the design may not be clear for new readers of the source. These notes are written by such readers: as you learn please correct any errors.

Questions

Why can't breakpoints be set on some source lines some of the time?

Sometimes the source has small ticks in the margin for every executable line in my JavaScript. Sometimes these ticks are missing on some or all lines of a file. Only lines with tick marks seem to break point properly.

Venkman asks the JS engine which lines are executable. It will mark these with a "tick" as you call it. If the file is not currently loaded, the JS engine doesn't know anything about the file. You can still set breakpoints, but they will be future breakpoints, which will be "real" breakpoints when/if the file is loaded (note that this may never happen!). Note also that this is just my knowledge of Venkman, which is quite limited. You would be better off asking Silver (James Ross). GijsKruitbosch 05:41, 7 March 2007 (PST)

{{wiki.template('Named-source', [ "extensions/venkman/resources/content/venkman-debugger.js", "venkman-debugger.js" ])}}

Sets hooks in to the jsdIDebuggerService. initDebugger().

ScriptManager

In initDebugger() the previous loaded scripts are passed to an onScriptCreated() method which binds them to a ScriptManager. There is one ScriptManager per url (web page). This method is set into jsdIScriptHook.onScriptCreated

{{wiki.template('Named-source', [ "extensions/venkman/resources/content/venkman-views.js", "venkman-views.js" ])}}

Views are the panels shown within the venkman window. For example, the "Open Windows" view shows the browser's windows.

{{wiki.template('Named-source', [ "extensions/venkman/resources/content/venkman-records.js", "venkman-records.js" ])}}

A "record" seems to be data underlying a view. For example, FrameRecord represents a JavaScript stack frame.

venkman-msg.js

Localization code, reads venkman.properties from a subdirectory of "locale" and injects variables. Things like msg.alert define variables MSG_ALERT.

venkman-utils.js

Defines the dd debug dump and friends

WindowRecord

Representation of the open windows.

  • FileContainerRecord - List of script tags found in the parent record's window.document property.
    • To obtain the antecedent files: doc.getElementsByTagName("script");
    • then extract the URLs from the src attributes.

ScriptWrapper

newsgroup, 2002, rgrinda

Here is a bit more information about how Venkman tracks files and functions...

A scriptWrapper is a pure JS object defined only inside Venkman. As you pointed out, there is a 1:1 relationship between scriptWrappers and functions. scriptWrapper has-a jsdScript property, which is an object which supports the jsdIScript interface. jsdIScript is a lower level access to the function than the scriptWrapper. In order to set a breakpoint in a particular function, you'll want to call scriptWrapper.setBreakpoint(pc{{mediawiki.external(', parentBP')}}); where |pc| is the program counter location to set the breakpoint, and |parentBP| is an optional "future breakpoint" object to use as the parent for this breakpoint. If you set the breakpoint right from the jsdScript instead, you wouldn't see it in the Venkman UI, and you might confuse Venkman when the actual breakpoint was hit and it couldn't find a matching breakpoint object.

You can see the prototype for this object at http://lxr.mozilla.org/mozilla/source/extensions/venkman/resources/content/venkman-debugger.js#914

scriptWrapper.jsdScript is the reference to the jsdIScript object for the function.

sourceContext is the 5 lines of source text before the last instance of the word "function" on the line where this function starts. (not in 2006, seems to be computed on the fly in getSourceContext()).

The full text of the file can be found in an array located at scriptWrapper.scriptInstance.sourceText.lines. This array is 0 based, of course.

The starting line of the function is scriptWrapper.jsdScript.baseLineNumber (one based).

The total length of the function is scriptWrapper.jsdScript.lineExtent.

If you want to get at the pretty printed source text, instead of the actual source text, use scriptWrapper.jsdScript.functionSource.

ScriptInstance

All scriptWrappers are parented by a single scriptInstance, which holds all of the scriptWrappers for a particular URL. From here, you can set and clear breakpoints by line number (instead of by program counter), locate a scriptWrapper for a given line number, and do a few other useful things. scriptInstance.functions is a hash of all of the functions in the script instance, keyed by the tag property of the jsdScript. scriptInstance.topLevel is the top-level script for the instance.

ScriptManager

Sometimes the same URL is loaded more than once in the browser. To deal with this, all scriptInstances are parented by a single scriptManager. A scriptManager keeps all of the loaded instances of a particular URL in the scriptManager.instances array, in the order that they were loaded. From here, you can set and clear breakpoints in all instances. scriptManager.transients is a hash of all of the "transient" scripts from this URL, where a transient script is something compiled as a the result of an eval, setTimeout, or setInterval.

Try starting up Venkman and type "/watch-expr client.scriptManagers", make sure to turn on "Include Functions". This tree should give you a pretty good idea of how it all fits together.

Revision Source

<p>Start with <a href="en/Venkman">Venkman</a> Information.
</p><p>Notes on Venkman source code.  As with any complex application, aspects of the design may not be clear for new readers of the source. These notes are written by such readers: as you learn please correct any errors.
</p>
<h3 name="Questions"> Questions </h3>
<p><i>Why can't breakpoints be set on some source lines some of the time?</i>
</p><p>Sometimes the source has small ticks in the margin for every executable line in my JavaScript.  Sometimes these ticks are missing on some or all lines of a file. Only lines with tick marks seem to break point properly.
</p>
<dl><dd> Venkman asks the JS engine which lines are executable. It will mark these with a "tick" as you call it. If the file is not currently loaded, the JS engine doesn't know anything about the file. You can still set breakpoints, but they will be future breakpoints, which will be "real" breakpoints when/if the file is loaded (note that this may never happen!). Note also that this is just my knowledge of Venkman, which is quite limited. You would be better off asking Silver (James Ross). <a href="User:GijsKruitbosch">GijsKruitbosch</a> 05:41, 7 March 2007 (PST)
</dd></dl>
<h3 name="Named-sourceextensions.2Fvenkman.2Fresources.2Fcontent.2Fvenkman-debugger.jsvenkman-debugger.js"> {{wiki.template('Named-source', [ "extensions/venkman/resources/content/venkman-debugger.js", "venkman-debugger.js" ])}} </h3>
<p>Sets hooks in to the jsdIDebuggerService. initDebugger().
</p>
<h4 name="ScriptManager"> ScriptManager </h4>
<p>In <code>initDebugger()</code> the previous loaded scripts are passed to an <code>onScriptCreated()</code> method which binds them to a ScriptManager. There is one ScriptManager per url (web page). This method is set into <a class="external" href="http://www.xulplanet.com/references/xpcomref/ifaces/jsdIScriptHook.html">jsdIScriptHook.</a>onScriptCreated 
</p>
<h3 name="Named-sourceextensions.2Fvenkman.2Fresources.2Fcontent.2Fvenkman-views.jsvenkman-views.js"> {{wiki.template('Named-source', [ "extensions/venkman/resources/content/venkman-views.js", "venkman-views.js" ])}} </h3>
<p>Views are the panels shown within the venkman window.  For example, the "Open Windows" view shows the browser's windows.
</p>
<h3 name="Named-sourceextensions.2Fvenkman.2Fresources.2Fcontent.2Fvenkman-records.jsvenkman-records.js"> {{wiki.template('Named-source', [ "extensions/venkman/resources/content/venkman-records.js", "venkman-records.js" ])}} </h3>
<p>A "record" seems to be data underlying a view. For example, <code>FrameRecord</code> represents a JavaScript stack frame.
</p>
<h3 name="venkman-msg.js"> venkman-msg.js </h3>
<p>Localization code, reads venkman.properties from a subdirectory of "locale" and injects variables.  Things like msg.alert define variables MSG_ALERT.
</p>
<h3 name="venkman-utils.js"> venkman-utils.js </h3>
<p>Defines the dd debug dump and friends
</p>
<h4 name="WindowRecord"> WindowRecord </h4>
<p>Representation of the open windows.
</p>
<ul><li> <code>FileContainerRecord</code> - List of script tags found in the parent record's <code>window.document</code> property.
<ul><li> To obtain the antecedent files:   <code>doc.getElementsByTagName("script");</code>
</li><li> then extract the URLs from the <code>src</code> attributes.
</li></ul>
</li></ul>
<h4 name="ScriptWrapper"> ScriptWrapper </h4>
<p><a class="external" href="http://article.gmane.org/gmane.comp.mozilla.devel.jsdebugger/140/match=feature+request">newsgroup, 2002, rgrinda</a>
</p><p>Here is a bit more information about how Venkman tracks files and 
functions...
</p><p>A scriptWrapper is a pure JS object defined only inside Venkman.  As you 
pointed out, there is a 1:1 relationship between scriptWrappers and 
functions.  scriptWrapper has-a jsdScript property, which is an object 
which supports the jsdIScript interface.  jsdIScript is a lower level 
access to the function than the scriptWrapper.  In order to set a 
breakpoint in a particular function, you'll want to call 
scriptWrapper.setBreakpoint(pc{{mediawiki.external(', parentBP')}});  where |pc| is the program 
counter location to set the breakpoint, and |parentBP| is an optional 
"future breakpoint" object to use as the parent for this breakpoint.  If 
you set the breakpoint right from the jsdScript instead, you wouldn't 
see it in the Venkman UI, and you might confuse Venkman when the actual 
breakpoint was hit and it couldn't find a matching breakpoint object.
</p><p>You can see the prototype for this object at
http://lxr.mozilla.org/mozilla/source/extensions/venkman/resources/content/venkman-debugger.js#914
</p><p>scriptWrapper.jsdScript is the reference to the jsdIScript object for 
the function.
</p><p>sourceContext is the 5 lines of source text before the last instance of 
the word "function" on the line where this function starts. (not in 2006, seems to be computed on the fly in getSourceContext()).
</p><p>The full text of the file can be found in an array located at 
scriptWrapper.scriptInstance.sourceText.lines.  This array is 0 based, 
of course.
</p><p>The starting line of the function is 
scriptWrapper.jsdScript.baseLineNumber (one based).
</p><p>The total length of the function is scriptWrapper.jsdScript.lineExtent.
</p><p>If you want to get at the pretty printed source text, instead of the 
actual source text, use scriptWrapper.jsdScript.functionSource.
</p>
<h4 name="ScriptInstance"> ScriptInstance </h4>
<p>All scriptWrappers are parented by a single scriptInstance, which holds 
all of the scriptWrappers for a particular URL.  From here, you can set 
and clear breakpoints by line number (instead of by program counter), 
locate a scriptWrapper for a given line number, and do a few other 
useful things.  scriptInstance.functions is a hash of all of the 
functions in the script instance, keyed by the tag property of the 
jsdScript.  scriptInstance.topLevel is the top-level script for the 
instance.
</p>
<h4 name="ScriptManager_2"> ScriptManager </h4>
<p>Sometimes the same URL is loaded more than once in the browser.  To deal 
with this, all scriptInstances are parented by a single scriptManager. 
A scriptManager keeps all of the loaded instances of a particular URL in 
the scriptManager.instances array, in the order that they were loaded. 
From here, you can set and clear breakpoints in all instances. 
scriptManager.transients is a hash of all of the "transient" scripts 
from this URL, where a transient script is something compiled as a the 
result of an eval, setTimeout, or setInterval.
</p><p>Try starting up Venkman and type "/watch-expr client.scriptManagers", 
make sure to turn on "Include Functions".  This tree should give you a 
pretty good idea of how it all fits together.
</p>
Revert to this revision