JS Debugger API Guide

  • Revision slug: SpiderMonkey/JS_Debugger_API_Guide
  • Revision title: JS Debugger API Guide
  • Revision id: 44549
  • Created:
  • Creator: Sheppy
  • Is current revision? No
  • Comment 318 words added, 3 words removed

Revision Content

{{ jsapi_minversion_header("1.8.6") }}

{{ draft() }}

The new JavaScript Debugger API introduced in SpiderMonkey 1.8.6 provides a convenient, easier-to-use API than the old JSDBGAPI for implementing JavaScript debugging features. This API provides the necessary hooks to allow chrome code to get an inside look into what the JavaScript engine is doing in order to implement debuggers and monitor the progress of the execution of code. It's not available to content code.

Note: This new debugging API is in addition to the older JSDBGAPI; you can hypothetically use both at the same time without having any problems, although you should choose one and stick with it.

Getting access to the Debugger

To access the JS Debugger API, you need to import the JavaScript code module that gives you access to the Debugger object. This is the jsdebugger.jsm code module, which you can import as follows:

Components.utils.import("resource://gre/modules/jsdebugger.jsm");

Having done this, you can now access the JavaScript Debugger API offered by the global Debugger constructor:

var myDebugger = new Debugger;

This creates a Debugger object with nothing targeted for debugging. If you want to specify a target for the debugger, you can specify one or more global objects whose compartments are to be debugged:

var myDebugger = new Debugger(object1, object2, object3);

You can also add target compartments to the debugger by calling Debugger.addDebuggee(), specifying a {{ anch("Global object") }} in the compartment to be debugged.

Glossary

There are a number of important terms used in the Debugger API documentation that you need to be familiar with.

Debuggee

A debuggee is a target for debugging; it's a collection of script running in a compartment.

Debuggee values

A debuggee value is either a primitive value or a Debugger.Object instance referring to an object in the debuggee's compartment. Debuggee values are passed between the debugger and debuggee.

Global object

In SpiderMonkey, a global object is the "walled garden" providing the environment in which scripts run. In Firefox, each DOM {{ domxref("window") }} is a global object and has its own set of all of the core JavaScript objects (Object, Array, Function, Math, etc.). This lets script in each window manipulate these objects without affecting script in other tabs and windows.

A global object and all of its contents are in a single compartment. Ideally, each compartment contains a single global object, although this isn't currently enforced.

When debugging, you choose one or more globals you want to observe, so that you only receive debugging notifications for scripts you're interested in.

Invocation functions

An invocation function is any function in the Debugger API that lets you invoke code in script being debugged, such as Debugger.Object.prototype.call() or Debugger.Frame.prototype.eval().

The general process by which an invocation function operates is as follows:

  1. Let older be the youngest debuggee frame on the stack, or null if there isn't one. This will never be one of the debugger's own frames.
  2. Push a Debugger.Frame of type "debugger" onto the stack, with its older property set as determined in step 1.
  3. Invoke the debuggee code as appropriate for the invocation function used, with the "debugger" frame as its continuation. For example, if you call Debugger.Frame.prototype.eval(), an "eval" frame is pushed for the code it runs, whereas Debugger.Object.prototype.call() will push a "call" frame.
  4. When the debuggee completes (whether by returning, throwing an exception, or being terminated), pop the "debugger" frame and return an appropriate completion value from the invocation function to the debugger.

Referent

A referent is an object referred to by another object, typically a Debugger.Object instance.

Inspecting debuggee objects

The Debugger API provides methods for inspecting and changing values in the debuggee.

The Debugger.DebuggeeWoundRun exception

In order to preserve the integrity of the debugger, the debugger doesn't let you perform accesses to debuggee data that might cause the debuggee to need to execute code. Instead, the debugger throws an instance of the Debugger.DebuggeeWouldRun exception.

Some examples of cases in which this happens include:

  • Reading a variable that runs a getter on the global.
  • Reading a variable with a with expression operand.
  • Getting an object's property descriptor when the object is a proxy; this would run a handler trap.

Only functions whose specific purpose is to execute debuggee code are permitted to do so; these are {{ anch("invocation functions") }}. Any other operation that would run debuggee code throws the Debugger.DebuggeeWouldRun exception.

Debuggee frames

Each stack frame within a debuggee is represented by exactly one Debugger.Frame instance; therefore, every hook object method called while the debuggee is running in a particular frame receives the same frame object. Similarly, walking the stack back to a previously-accessed debuggee frame gets you the same frame object as before. Debuggers can add additional properties to frame objects and expect to find them later. In addition, you can use the == operator to determine whether or not two expressions refer to the same frame.

When the debuggee pops a stack frame -- for example, because a function call has returned or an exception has been thrown -- the Debugger.Frame instance referring to that frame becomes inactive. You can detect this by checking its live property; if this property is false, the frame is inactive. Its other properties and methods all throw exceptions.

Note: Frames become inactive only at times the debugger can rely upon: when the debuggee runs or when it removes frames from the stack itself.

Although the debugger shares a JavaScript stack with the debuggee, the stack frames presented to the debugger by Debugger.Frame never include frames running the debugger's own code.

Note: Stack frames representing the control state of generator-iterator objects are represented using a special variety of Debugger.Frame.

Generator frames

SpiderMonkey supports generator-iterator objects. These produce a series of values by repeatedly suspending the execution of a function or expression. For example, calling a function that uses the yield() operator produces a generator-iterator object. So does evaluating a generator expression such as (i*i for each (i in [1, 2, 3])).

A generator-iterator object refers to a stack frame with no fixed continuation frame. While the generator's code is running, its continuation is whatever frame called its next() method (thereby requesting the next result from the generator). While the generator is suspended, it has no particular continuation frame, and when it resumes again, the continuation frame for that resumption may differ from the previous resumption.

Differences between generator frames and other frames

A Debugger.Frame instance representing a generator frame differs from an ordinary stack frame in the following ways:

  • The generator property is true.
  • The older property refers to the frame's continuation frame while the generator is running and is null while the generator is suspended.
  • The depth property reflects the frame's position on the stack when it's resumed and is null while the generator is suspended.
  • The live property remains true until the frame returns, throws an exception, or is terminated. That means generator frames can be live while not present on the stack.
  • A generator frame disappears from the stack each time the generator yields a value and is suspended. It reappears at the top of the stack when it's resumed to produce the generator's next value. The same Debugger.Frame instance refers to the generator frame until it returns, throws an exception, or is terminated.
Note: Whether or not the Debugger.Frame object on the stack when the generator is resumed is a new one or an existing one is not specified, and you should not rely on any particular behavior in this regard.

How generator frames and other frames are the same

All other Debugger.Frame methods and accessor properties work just like for other types of frames, even when the generator frame is suspended. You can examine a suspended generator frame's properties and use its script and offset properties to see which yield() operation it's suspended at, for example.

The lifespan of a generator frame

A Debugger.Frame instance referring to a generator-iterator frame holds a strong reference to the generator-iterator object. The frame and its object will live as long as the Debugger.Frame instance does. However, once the generator function returns, throws an exception, or is terminated (thereby ending the iteration), the Debugger.Frame instance becomes inactive and its live property becomes false, just like for any other kind of frame that is popped.

Once a generator frame is no longer live, it no longer holds a strong reference to the generator-iterator object.

Exception handling

Exception unwinding

After an exception is thrown, it's necessary to unwind the stack. This is the process of removing frames from the stack until a handler is found for the exception. For each frame that's reached during the unwinding process, SpiderMonkey looks to see if the current offset in the frame is in a try block, which indicates that there's an exception handler to deal with the thrown exception. If it is, control jumps to the corresponding catch/finally code. Otherwise, the frame is discarded and stack unwinding continues.

The Debugger API lets debuggers monitor the process of stack unwinding during exception handling by calling the Debugger.onExceptionUnwind() method for each debugger script frame that's reached during unwinding. That method returns a resumption value indicating how execution should proceed.

Scripts

Each JSAPI JSScript object is represented by a Debugger.Script instance, which refers to a bytecode sequence in a debuggee. It may represent code from any of the following types of JSScript object:

  • The body of a function; that is, all the code in a function that's not contained within some nested function.
  • The code passed to a single call to eval(), excluding the bodies of any functions defined by that code.
  • The contents of a {{ HTMLElement("script") }} element.
  • A DOM event handler, whether embedded in HTML or attached to an element by other JavaScript code.
  • Code appearing in a javascript: URL.

How Debugger.Scripts are created

The Debugger interface constructs Debugger.Script objects as it discovers the existence of script objects. There are several ways in which this occurs; for example:

  • A call to the Debugger.onNewScript() hook object method.
  • A change to the Debugger.Frame.script property's value.
  • A call to the Debugger.Object.functionScript() method.
  • Any other mechanism that may change a script.

The Debugger interface creates 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; similarly, you can use the == operator to determine whether two expressions refer to the same script, and so on.

A Debugger.Script instance holds a strong reference to a JSScript object, thereby protecting the script to which it refers from being garbage collected. However, scripts representing code passed to eval() may be deleted when eval() returns, so you should check the value of the live property to determine whether or not the script still exists in the debuggee.

Note: SpiderMonkey may use the same Debugger.Script instance for multiple functions or evaluated code segments that represent the same source code at the same position in the same source file, executed in the same lexical environment.

Objects

A Debugger.Object instance represents an object in the script being debugged. Debugger code never directly accesses debuggee objects; instead, it operates on Debugger.Object instances that, in turn, refer to the objects in the debuggee.

Each Debugger.Object instance has reflection-oriented methods that let you inspect and modify the object to which it refers. You can use methods such as {{ manch("getOwnPropertyDescriptor") }} and {{ manch("defineProperty") }} to access the referent's properties. This ensures that the debugger won't inadvertently invoke getter or setter code in the debuggee while trying to look at its properties.

SpiderMonkey creates exactly one Debugger.Object instance for each object in the debuggee. If the debugger encounters the same object through multiple routes (such as when two functions are called on the same object), the same Debugger.Object instance is presented every time. That means you can use operators such as == to recognize when two Debugger.Object instances refer to the same object in the debuggee, and you can add your own properties to a Debugger.Object instance to store your own metadata about debuggee objects.

Although most Debugger.Object instances are created by SpiderMonkey while exposing debuggee behavior and state to the debugger, the debugger itself can use the {{ manch("copy") }} and {{ manch("create") }} methods to create objects in the debuggee's compartment as well.

Debugger.Object instances protect the objects to which they refer from garbage collection. As long as the Debugger.Object instance is live, its referent remains live as well. Therefore, garbage collection has no debugger-visible effect on Debugger.Object instances.

How values are passed between debugger and debuggee

In order to help debuggers safely inspect and modify objects and values in a debuggee's compartment, the Debugger interface follows some conventions:

  • Primitive values are passed freely between the debugger and debuggee. Any needed copying or wrapping of these values is handled transparently.
  • Objects received from the debuggee, including host objects such as DOM elements, are presented to the debugger as Debugger.Object instances; these provide reflection-oriented methods for inspecting their referents.
  • Of debugger objects, only Debugger.Object instances can be passed to the debuggee. When this occurs, the debuggee receives the Debugger.Object's referent, not the Debugger.Object itself.

See also

Revision Source

<p>{{ jsapi_minversion_header("1.8.6") }}</p>
<p>{{ draft() }}</p>
<p>The new JavaScript Debugger API introduced in SpiderMonkey 1.8.6 provides a convenient, easier-to-use API than the old <a href="/en/JSDBGAPI_Reference" title="JSDBGAPI Reference">JSDBGAPI</a> for implementing JavaScript debugging features. This API provides the necessary hooks to allow chrome code to get an inside look into what the JavaScript engine is doing in order to implement debuggers and monitor the progress of the execution of code. It's not available to content code.</p>
<div class="note"><strong>Note:</strong> This new debugging API is in addition to the older <a href="/en/JSDBGAPI_Reference" title="JSDBGAPI Reference">JSDBGAPI</a>; you can hypothetically use both at the same time without having any problems, although you should choose one and stick with it.</div>
<h2>Getting access to the Debugger</h2>
<p>To access the JS Debugger API, you need to import the JavaScript code module that gives you access to the <code>Debugger</code> object. This is the <code>jsdebugger.jsm</code> code module, which you can import as follows:</p>
<pre class="plain">Components.utils.import("resource://gre/modules/jsdebugger.jsm");
</pre>
<p>Having done this, you can now access the JavaScript Debugger API offered by the global <code>Debugger</code> constructor:</p>
<pre>var myDebugger = new Debugger;
</pre>
<p>This creates a <code>Debugger</code> object with nothing targeted for debugging. If you want to specify a target for the debugger, you can specify one or more <strong>global</strong> objects whose compartments are to be debugged:</p>
<pre>var myDebugger = new Debugger(object1, object2, object3);
</pre>
<p>You can also add target compartments to the debugger by calling <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger#addDebuggee()" title="en/SpiderMonkey/JS_Debugger_API_Reference/Debugger#addDebuggee()"><code>Debugger.addDebuggee()</code></a>, specifying a {{ anch("Global object") }} in the compartment to be debugged.</p>
<h2>Glossary</h2>
<p>There are a number of important terms used in the Debugger API documentation that you need to be familiar with.</p>
<h3>Debuggee</h3>
<p>A <strong>debuggee</strong> is a target for debugging; it's a collection of script running in a compartment.</p>
<h3>Debuggee values</h3>
<p>A <strong>debuggee value</strong> is either a primitive value or a <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger.Object" title="Debugger.Object"><code>Debugger.Object</code></a> instance referring to an object in the debuggee's compartment. Debuggee values are passed between the debugger and debuggee.</p>
<h3>Global object</h3>
<p>In SpiderMonkey, a <strong>global object</strong> is the "walled garden" providing the environment in which scripts run. In Firefox, each DOM {{ domxref("window") }} is a global object and has its own set of all of the core JavaScript objects (<a href="/en/JavaScript/Reference/Global_Objects/Object" title="Object"><code>Object</code></a>, <a href="/en/JavaScript/Reference/Global_Objects/Array" title="Array"><code>Array</code></a>, <a href="/en/JavaScript/Reference/Global_Objects/Function" title="Function"><code>Function</code></a>, <a href="/en/JavaScript/Reference/Global_Objects/Math" title="Math"><code>Math</code></a>, etc.). This lets script in each window manipulate these objects without affecting script in other tabs and windows.</p>
<p>A global object and all of its contents are in a single <a href="/en/SpiderMonkey/SpiderMonkey_compartments" title="en/SpiderMonkey/SpiderMonkey_compartments">compartment</a>. Ideally, each compartment contains a single global object, although this isn't currently enforced.</p>
<p>When debugging, you choose one or more globals you want to observe, so that you only receive debugging notifications for scripts you're interested in.</p>
<h3>Invocation functions</h3>
<p>An <strong>invocation function</strong> is any function in the Debugger API that lets you invoke code in script being debugged, such as <code>Debugger.Object.prototype.call()</code> or <code>Debugger.Frame.prototype.eval()</code>.</p>
<p>The general process by which an invocation function operates is as follows:</p>
<ol> <li>Let <code>older</code> be the youngest debuggee frame on the stack, or <code>null</code> if there isn't one. This will never be one of the debugger's own frames.</li> <li>Push a <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger.Frame" title="Debugger"><code>Debugger.Frame</code></a> of type "debugger" onto the stack, with its <code>older</code> property set as determined in step 1.</li> <li>Invoke the debuggee code as appropriate for the invocation function used, with the "debugger" frame as its continuation. For example, if you call <code>Debugger.Frame.prototype.eval()</code>, an "eval" frame is pushed for the code it runs, whereas <code>Debugger.Object.prototype.call()</code> will push a "call" frame.</li> <li>When the debuggee completes (whether by returning, throwing an exception, or being terminated), pop the "debugger" frame and return an appropriate <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Completion_values" title="Completion values">completion value</a> from the invocation function to the debugger.</li>
</ol>
<h3>Referent</h3>
<p>A <strong>referent</strong> is an object referred to by another object, typically a <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger.Object" title="Debugger.Object"><code>Debugger.Object</code></a> instance.</p>
<h2>Inspecting debuggee objects</h2>
<p>The Debugger API provides methods for inspecting and changing values in the debuggee.</p>
<h3>The Debugger.DebuggeeWoundRun exception</h3>
<p>In order to preserve the integrity of the debugger, the debugger doesn't let you perform accesses to debuggee data that might cause the debuggee to need to execute code. Instead, the debugger throws an instance of the <code>Debugger.DebuggeeWouldRun</code> exception.</p>
<p>Some examples of cases in which this happens include:</p>
<ul> <li>Reading a variable that runs a getter on the global.</li> <li>Reading a variable with a <a href="/en/JavaScript/Reference/Statements/with" title="with"><code>with</code></a> expression operand.</li> <li>Getting an object's property descriptor when the object is a proxy; this would run a handler trap.</li>
</ul>
<p>Only functions whose specific purpose is to execute debuggee code are permitted to do so; these are {{ anch("invocation functions") }}. Any other operation that would run debuggee code throws the <code>Debugger.DebuggeeWouldRun</code> exception.</p>
<h2>Debuggee frames</h2>
<p>Each stack frame within a debuggee is represented by exactly one <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger.Frame" title="Debugger"><code>Debugger.Frame</code></a> instance; therefore, every hook object method called while the debuggee is running in a particular frame receives the same frame object. Similarly, walking the stack back to a previously-accessed debuggee frame gets you the same frame object as before. Debuggers can add additional properties to frame objects and expect to find them later. In addition, you can use the <code>==</code> operator to determine whether or not two expressions refer to the same frame.</p>
<p>When the debuggee pops a stack frame -- for example, because a function call has returned or an exception has been thrown -- the <code>Debugger.Frame</code> instance referring to that frame becomes inactive. You can detect this by checking its live property; if this property is false, the frame is inactive. Its other properties and methods all throw exceptions.</p>
<div class="note"><strong>Note:</strong> Frames become inactive only at times the debugger can rely upon: when the debuggee runs or when it removes frames from the stack itself.</div>
<p>Although the debugger shares a JavaScript stack with the debuggee, the stack frames presented to the debugger by <code>Debugger.Frame</code> never include frames running the debugger's own code.</p>
<div class="note"><strong>Note:</strong> Stack frames representing the control state of generator-iterator objects are represented using a special variety of <code>Debugger.Frame</code>.</div>
<h3>Generator frames</h3>
<p>SpiderMonkey supports generator-iterator objects. These produce a series of values by repeatedly suspending the execution of a function or expression. For example, calling a function that uses the <a href="/en/JavaScript/Reference/Operators/yield" title="yield"><code>yield()</code></a> operator produces a generator-iterator object. So does evaluating a generator expression such as <code>(i*i for each (i in [1, 2, 3]))</code>.</p>
<p>A generator-iterator object refers to a stack frame with no fixed continuation frame. While the generator's code is running, its continuation is whatever frame called its <code>next()</code> method (thereby requesting the next result from the generator). While the generator is suspended, it has no particular continuation frame, and when it resumes again, the continuation frame for that resumption may differ from the previous resumption.</p>
<h4>Differences between generator frames and other frames</h4>
<p>A <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger.Frame" title="Debugger"><code>Debugger.Frame</code></a> instance representing a generator frame differs from an ordinary stack frame in the following ways:</p>
<ul> <li>The <code>generator</code> property is true.</li> <li>The <code>older</code> property refers to the frame's continuation frame while the generator is running and is <code>null</code> while the generator is suspended.</li> <li>The <code>depth</code> property reflects the frame's position on the stack when it's resumed and is <code>null</code> while the generator is suspended.</li> <li>The <code>live</code> property remains true until the frame returns, throws an exception, or is terminated. That means generator frames can be live while not present on the stack.</li> <li>A generator frame disappears from the stack each time the generator yields a value and is suspended. It reappears at the top of the stack when it's resumed to produce the generator's next value. The same <code>Debugger.Frame</code> instance refers to the generator frame until it returns, throws an exception, or is terminated.</li>
</ul>
<div class="note"><strong>Note:</strong> Whether or not the <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger.Frame" title="Debugger"><code>Debugger.Frame</code></a> object on the stack when the generator is resumed is a new one or an existing one is not specified, and you should not rely on any particular behavior in this regard.</div>
<h4>How generator frames and other frames are the same</h4>
<p>All other <code>Debugger.Frame</code> methods and accessor properties work just like for other types of frames, even when the generator frame is suspended. You can examine a suspended generator frame's properties and use its <code>script</code> and <code>offset</code> properties to see which <a href="/en/JavaScript/Reference/Operators/yield" title="yield"><code>yield()</code></a> operation it's suspended at, for example.</p>
<h4>The lifespan of a generator frame</h4>
<p>A <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger.Frame" title="Debugger"><code>Debugger.Frame</code></a> instance referring to a generator-iterator frame holds a strong reference to the generator-iterator object. The frame and its object will live as long as the <code>Debugger.Frame</code> instance does. However, once the generator function returns, throws an exception, or is terminated (thereby ending the iteration), the <code>Debugger.Frame</code> instance becomes inactive and its <code>live</code> property becomes false, just like for any other kind of frame that is popped.</p>
<p>Once a generator frame is no longer live, it no longer holds a strong reference to the generator-iterator object.</p>
<h3>Exception handling</h3>
<h4>Exception unwinding</h4>
<p>After an exception is thrown, it's necessary to unwind the stack. This is the process of removing frames from the stack until a handler is found for the exception. For each frame that's reached during the unwinding process, SpiderMonkey looks to see if the current offset in the frame is in a <a href="/en/JavaScript/Reference/Statements/try...catch" title="try...catch"><code>try</code></a> block, which indicates that there's an exception handler to deal with the thrown exception. If it is, control jumps to the corresponding <code>catch</code>/<code>finally</code> code. Otherwise, the frame is discarded and stack unwinding continues.</p>
<p>The Debugger API lets debuggers monitor the process of stack unwinding during exception handling by calling the <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger#onExceptionUnwind()" title="en/SpiderMonkey/JS_Debugger_API_Reference/Debugger#onExceptionUnwind()"><code>Debugger.onExceptionUnwind()</code></a> method for each debugger script frame that's reached during unwinding. That method returns a <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Resumption_values" title="en/SpiderMonkey/JS_Debugger_API_Reference/Resumption_values">resumption value</a> indicating how execution should proceed.</p>
<h2>Scripts</h2>
<p>Each JSAPI <a href="/en/JSScript" title="en/JSScript"><code>JSScript</code></a> object is represented by a <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger.Script" title="Debugger.Object"><code>Debugger.Script</code></a> instance, which refers to a bytecode sequence in a debuggee. It may represent code from any of the following types of <a href="/en/JSScript" title="en/JSScript"><code>JSScript</code></a> object:</p>
<ul> <li>The body of a function; that is, all the code in a function that's not contained within some nested function.</li> <li>The code passed to a single call to <a href="/en/JavaScript/Reference/Global_Objects/Object/eval" title="eval"><code>eval()</code></a>, excluding the bodies of any functions defined by that code.</li> <li>The contents of a {{ HTMLElement("script") }} element.</li> <li>A DOM event handler, whether embedded in HTML or attached to an element by other JavaScript code.</li> <li>Code appearing in a <code>javascript:</code> URL.</li>
</ul>
<h4>How Debugger.Scripts are created</h4>
<p>The <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger" title="Debugger"><code>Debugger</code></a> interface constructs <code>Debugger.Script</code> objects as it discovers the existence of script objects. There are several ways in which this occurs; for example:</p>
<ul> <li>A call to the <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger#onNewScript()" title="en/SpiderMonkey/JS_Debugger_API_Reference/Debugger#onNewScript()"><code>Debugger.onNewScript()</code></a> hook object method.</li> <li>A change to the <code>Debugger.Frame.script</code> property's value.</li> <li>A call to the <code>Debugger.Object.functionScript()</code> method.</li> <li>Any other mechanism that may change a script.</li>
</ul>
<p>The <code>Debugger</code> interface creates exactly one <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger.Script" title="Debugger.Object"><code>Debugger.Script</code></a> instance for each underlying script object. Debugger code can add its own properties to a script object and expect to find them later; similarly, you can use the <code>==</code> operator to determine whether two expressions refer to the same script, and so on.</p>
<p>A <code>Debugger.Script</code> instance holds a strong reference to a <a href="/en/JSScript" title="en/JSScript"><code>JSScript</code></a> object, thereby protecting the script to which it refers from being garbage collected. However, scripts representing code passed to <a href="/en/JavaScript/Reference/Global_Objects/Object/eval" title="eval"><code>eval()</code></a> may be deleted when <code>eval()</code> returns, so you should check the value of the <code>live</code> property to determine whether or not the script still exists in the debuggee.</p>
<div class="note"><strong>Note:</strong> SpiderMonkey may use the same <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger.Script" title="Debugger.Object"><code>Debugger.Script</code></a> instance for multiple functions or evaluated code segments that represent the same source code at the same position in the same source file, executed in the same lexical environment.</div>
<h2>Objects</h2>
<p>A <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger.Object" title="Debugger.Object"><code>Debugger.Object</code></a> instance represents an object in the script being debugged. Debugger code never directly accesses debuggee objects; instead, it operates on <code>Debugger.Object</code> instances that, in turn, refer to the objects in the debuggee.</p>
<p>Each <code>Debugger.Object</code> instance has reflection-oriented methods that let you inspect and modify the object to which it refers. You can use methods such as {{ manch("getOwnPropertyDescriptor") }} and {{ manch("defineProperty") }} to access the referent's properties. This ensures that the debugger won't inadvertently invoke getter or setter code in the debuggee while trying to look at its properties.</p>
<p>SpiderMonkey creates exactly one <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger.Object" title="Debugger.Object"><code>Debugger.Object</code></a> instance for each object in the debuggee. If the debugger encounters the same object through multiple routes (such as when two functions are called on the same object), the same <code>Debugger.Object</code> instance is presented every time. That means you can use operators such as == to recognize when two <code>Debugger.Object</code> instances refer to the same object in the debuggee, and you can add your own properties to a <code>Debugger.Object</code> instance to store your own metadata about debuggee objects.</p>
<p>Although most <a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger.Object" title="Debugger.Object"><code>Debugger.Object</code></a> instances are created by SpiderMonkey while exposing debuggee behavior and state to the debugger, the debugger itself can use the {{ manch("copy") }} and {{ manch("create") }} methods to create objects in the debuggee's compartment as well.</p>
<p><a href="/en/SpiderMonkey/JS_Debugger_API_Reference/Debugger.Object" title="Debugger.Object"><code>Debugger.Object</code></a> instances protect the objects to which they refer from garbage collection. As long as the <code>Debugger.Object</code> instance is live, its referent remains live as well. Therefore, garbage collection has no debugger-visible effect on <code>Debugger.Object</code> instances.</p><h2>How values are passed between debugger and debuggee</h2>
<p>In order to help debuggers safely inspect and modify objects and values in a debuggee's compartment, the <code>Debugger</code> interface follows some conventions:</p>
<ul> <li>Primitive values are passed freely between the debugger and debuggee. Any needed copying or wrapping of these values is handled transparently.</li> <li>Objects received from the debuggee, including host objects such as DOM elements, are presented to the debugger as <code>Debugger.Object</code> instances; these provide reflection-oriented methods for inspecting their referents.</li> <li>Of debugger objects, only <code>Debugger.Object</code> instances can be passed to the debuggee. When this occurs, the debuggee receives the <code>Debugger.Object</code>'s referent, not the <code>Debugger.Object</code> itself.</li>
</ul>
<h2>See also</h2>
<ul> <li><a href="/en/SpiderMonkey/JS_Debugger_API_Reference" title="en/SpiderMonkey/JS_Debugger_API_Reference">JS Debugger API Reference</a></li>
</ul>
Revert to this revision