Tools/Debugger-API/Debugger.Script

by 1 contributor:

Debugger.Script

A Debugger.Script instance refers to a sequence of bytecode in the debuggee; it is the Debugger API’s presentation of a JSAPI JSScript object. Each of the following is represented by single JSScript object:

  • The body of a function—that is, all the code in the function that is not contained within some nested function.

  • The code passed to a single call to eval, excluding the bodies of any functions that code defines.

  • The contents of a <script> element.

  • A DOM event handler, whether embedded in HTML or attached to the element by other JavaScript code.

  • Code appearing in a javascript: URL.

The Debugger interface constructs Debugger.Script objects as scripts of debuggee code are uncovered by the debugger: via the onNewScript handler method; via Debugger.Frame’s script properties; via the functionScript method of Debugger.Object instances; and so on. For a given Debugger instance, SpiderMonkey constructs exactly one Debugger.Script instance for each underlying script object; debugger code can add its own properties to a script object and expect to find them later, use == to decide whether two expressions refer to the same script, and so on.

(If more than one Debugger instance is debugging the same code, each Debugger gets a separate Debugger.Script instance for a given script. This allows the code using each Debugger instance to place whatever properties it likes on its Debugger.Script instances, without worrying about interfering with other debuggers.)

A Debugger.Script instance is a strong reference to a JSScript object; it protects the script it refers to from being garbage collected.

Note that SpiderMonkey may use the same Debugger.Script instances for equivalent functions or evaluated code—that is, scripts representing the same source code, at the same position in the same source file, evaluated in the same lexical environment.

Accessor Properties of the Debugger.Script Prototype Object

A Debugger.Script instance inherits the following accessor properties from its prototype:

displayName

The script’s display name, if it has one. If the script has no display name — for example, if it is a top-level eval script — this is undefined.

If the script’s function has a given name, its display name is the same as its function’s given name.

If the script’s function has no name, SpiderMonkey attempts to infer an appropriate name for it given its context. For example:

function f() {}          // display name: f (the given name)
var g = function () {};  // display name: g
o.p = function () {};    // display name: o.p
var q = {
  r: function () {}      // display name: q.r
};

Note that the display name may not be a proper JavaScript identifier, or even a proper expression: we attempt to find helpful names even when the function is not immediately assigned as the value of some variable or property. Thus, we use a/b to refer to the b defined within a, and a< to refer to a function that occurs somewhere within an expression that is assigned to a. For example:

function h() {
  var i = function() {};    // display name: h/i
  f(function () {});        // display name: h/<
}
var s = f(function () {});  // display name: s<
url

The filename or URL from which this script’s code was loaded. If the source property is non-null, then this is equal to source.url.

startLine

The number of the line at which this script’s code starts, within the file or document named by url.

lineCount

The number of lines this script’s code occupies, within the file or document named by url.

source

The Debugger.Source instance representing the source code from which this script was produced. This is null if the source code was not retained.

sourceStart

The character within the Debugger.Source instance given by source at which this script’s code starts; zero-based. If this is a function’s script, this is the index of the start of the function token in the source code.

sourceLength

The length, in characters, of this script’s code within the Debugger.Source instance given by source.

global

A Debugger.Object instance referring to the global object in whose scope this script runs. The result refers to the global directly, not via a wrapper or a WindowProxy (“outer window”, in Firefox).

staticLevel

The number of function bodies enclosing this script’s code.

Global code is at level zero; bodies of functions defined at the top level in global code are at level one; bodies of functions nested within those are at level two; and so on.

A script for code passed to direct eval is at a static level one greater than that of the script containing the call to eval, because direct eval code runs within the caller’s scope. However, a script for code passed to an indirect eval call is at static level zero, since it is evaluated in the global scope.

Note that a generator’s expressions are considered to be part of the body of a synthetic function, produced by the compiler.

Scripts’ static level be useful in deciding where to set breakpoints. For example, a breakpoint set on line 3 in this code:

function f() {
  x = function g() {  // line 2
                      // line 3; no code here
    ...;
  }
}

should be set in g’s script, not in f’s, even though neither script contains code at that line. In such a case, the most deeply nested script—the one with the highest static level—should receive the breakpoint.

strictMode

This is true if this script’s code is ECMAScript strict mode code, and false otherwise.

Function Properties of the Debugger.Script Prototype Object

The functions described below may only be called with a this value referring to a Debugger.Script instance; they may not be used as methods of other kinds of objects.

decompile([pretty])

Return a string containing JavaScript source code equivalent to this script in its effect and result. If pretty is present and true, produce indented code with line breaks.

(Note that Debugger.Object instances referring to functions also have a decompile method, whose result includes the function header and parameter names, so it is probably better to write f.decompile() than to write f.getFunctionScript().decompile().)

getAllOffsets()

Return an array L describing the relationship between bytecode instruction offsets and source code positions in this script. L is sparse, and indexed by source line number. If a source line number line has no code, then L has no line property. If there is code for line, then L[line] is an array of offsets of byte code instructions that are entry points to that line.

For example, suppose we have a script for the following source code:

a=[]
for (i=1; i < 10; i++)
    // It's hip to be square.
    a[i] = i*i;

Calling getAllOffsets() on that code might yield an array like this:

[[0], [5, 20], , [10]]

This array indicates that:

  • the first line’s code starts at offset 0 in the script;

  • the for statement head has two entry points at offsets 5 and 20 (for the initialization, which is performed only once, and the loop test, which is performed at the start of each iteration);

  • the third line has no code;

  • and the fourth line begins at offset 10.

getAllColumnOffsets():

Return an array describing the relationship between bytecode instruction offsets and source code positions in this script. Unlike getAllOffsets(), which returns all offsets that are entry points for each line, getAllColumnOffsets() returns all offsets that are entry points for each (line, column) pair.

The elements of the array are objects, each of which describes a single entry point, and contains the following properties:

  • lineNumber: the line number for which offset is an entry point

  • columnNumber: the column number for which offset is an entry point

  • offset: the bytecode instruction offset of the entry point

For example, suppose we have a script for the following source code:

a=[]
for (i=1; i < 10; i++)
    // It's hip to be square.
    a[i] = i*i;

Calling getAllColumnOffsets() on that code might yield an array like this:

```language-js [{ lineNumber: 0, columnNumber: 0, offset: 0 }, { lineNumber: 1, columnNumber: 5, offset: 5 }, { lineNumber: 1, columnNumber: 10, offset: 20 }, { lineNumber: 3, columnNumber: 4, offset: 10 }]

getLineOffsets(line)

Return an array of bytecode instruction offsets representing the entry points to source line line. If the script contains no executable code at that line, the array returned is empty.

getOffsetLine(offset)

Return the source code line responsible for the bytecode at offset in this script.

getChildScripts()

Return a new array whose elements are Debugger.Script objects for each function and each generator expression in this script. Only direct children are included; nested children can be reached by walking the tree.

setBreakpoint(offset, handler)

Set a breakpoint at the bytecode instruction at offset in this script, reporting hits to the hit method of handler. If offset is not a valid offset in this script, throw an error.

When execution reaches the given instruction, SpiderMonkey calls the hit method of handler, passing a Debugger.Frame instance representing the currently executing stack frame. The hit method’s return value should be a resumption value, determining how execution should continue.

Any number of breakpoints may be set at a single location; when control reaches that point, SpiderMonkey calls their handlers in an unspecified order.

Any number of breakpoints may use the same handler object.

Breakpoint handler method calls are cross-compartment, intra-thread calls: the call takes place in the same thread that hit the breakpoint, and in the compartment containing the handler function (typically the debugger’s compartment).

The new breakpoint belongs to the Debugger instance to which this script belongs. Disabling the Debugger instance disables this breakpoint; and removing a global from the Debugger instance’s set of debuggees clears all the breakpoints belonging to that Debugger instance in that global’s scripts.

getBreakpoints([offset])

Return an array containing the handler objects for all the breakpoints set at offset in this script. If offset is omitted, return the handlers of all breakpoints set anywhere in this script. If offset is present, but not a valid offset in this script, throw an error.

clearBreakpoints(handler, [offset])

Remove all breakpoints set in this Debugger instance that use handler as their handler. If offset is given, remove only those breakpoints set at offset that use handler; if offset is not a valid offset in this script, throw an error.

Note that, if breakpoints using other handler objects are set at the same location(s) as handler, they remain in place.

clearAllBreakpoints([offset])

Remove all breakpoints set in this script. If offset is present, remove all breakpoints set at that offset in this script; if offset is not a valid bytecode offset in this script, throw an error.

isInCatchScope([offset])

This is true if this offset falls within the scope of a try block, and false otherwise.

Source Metadata

Generated from file:
js/src/doc/Debugger/Debugger.Script.md
Watermark:
sha256:5304206a44a4d51064a69e9d18b286c1f0f7100a9c3c9be998c0c427875c640a
Changeset:
c36186e18a6b+

Document Tags and Contributors

Contributors to this page: jimblandy
Last updated by: jimblandy,