Bug 966720: Check Debugger docs into the SpiderMonkey tree. DONTBUILD r=jorendorff

This commit is contained in:
Jim Blandy 2014-04-02 13:44:07 -07:00
parent 1cfc05dded
commit 446dcb93fb
12 changed files with 3377 additions and 0 deletions

View File

@ -0,0 +1,163 @@
# General Conventions
This page describes general conventions used in the [`Debugger`][debugger] API,
and defines some terminology used throughout the specification.
## Properties
Properties of objects that comprise the `Debugger` interface, and those
that the interface creates, follow some general conventions:
- Instances and prototypes are extensible; you can add your own properties
and methods to them.
- Properties are configurable. This applies to both "own" and prototype
properties, and to both methods and data properties. (Leaving these
properties open to redefinition will hopefully make it easier for
JavaScript debugger code to cope with bugs, bug fixes, and changes in the
interface over time.)
- Method properties are writable.
- We prefer inherited accessor properties to own data properties. Both are
read using the same syntax, but inherited accessors seem like a more
accurate reflection of what's going on. Unless otherwise noted, these
properties have getters but no setters, as they cannot meaningfully be
assigned to.
## Debuggee Values
The `Debugger` interface follows some conventions to help debuggers safely
inspect and modify the debuggee's objects and values. Primitive values are
passed freely between debugger and debuggee; copying or wrapping is handled
transparently. Objects received from the debuggee (including host objects
like DOM elements) are fronted in the debugger by `Debugger.Object`
instances, which provide reflection-oriented methods for inspecting their
referents; see `Debugger.Object`, below.
Of the debugger's objects, only `Debugger.Object` instances may be passed
to the debuggee: when this occurs, the debuggee receives the
`Debugger.Object`'s referent, not the `Debugger.Object` instance itself.
In the descriptions below, the term "debuggee value" means either a
primitive value or a `Debugger.Object` instance; it is a value that might
be received from the debuggee, or that could be passed to the debuggee.
## Debuggee Code
Each `Debugger` instance maintains a set of global objects that, taken
together, comprise the debuggee. Code evaluated in the scope of a debuggee
global object, directly or indirectly, is considered *debuggee code*.
Similarly:
- a *debuggee frame* is a frame running debuggee code;
- a *debuggee function* is a function that closes over a debuggee
global object (and thus the function's code is debuggee code);
- a *debuggee environment* is an environment whose outermost
enclosing environment is a debuggee global object; and
- a *debuggee script* is a script containing debuggee code.
## Completion Values
When a debuggee stack frame completes its execution, or when some sort
of debuggee call initiated by the debugger finishes, the `Debugger`
interface provides a value describing how the code completed; these are
called *completion values*. A completion value has one of the
following forms:
<code>{ return: <i>value</i> }</code>
: The code completed normally, returning <i>value</i>. <i>Value</i> is a
debuggee value.
<code>{ yield: <i>value</i> }</code>
: <i>(Not yet implemented.)</i> The running code is a generator frame
which has yielded <i>value</i>. <i>Value</i> is a debuggee value.
<code>{ throw: <i>value</i> }</code>
: The code threw <i>value</i> as an exception. <i>Value</i> is a debuggee
value.
`null`
: The code was terminated, as if by the "slow script" dialog box.
If control reaches the end of a generator frame, the completion value is
<code>{ throw: <i>stop</i> }</code> where <i>stop</i> is a
`Debugger.Object` object representing the `StopIteration` object being
thrown.
## Resumption Values
As the debuggee runs, the `Debugger` interface calls various
debugger-provided handler functions to report the debuggee's behavior.
Some of these calls can return a value indicating how the debuggee's
execution should continue; these are called *resumption values*. A
resumption value has one of the following forms:
`undefined`
: The debuggee should continue execution normally.
<code>{ return: <i>value</i> }</code>
: Return <i>value</i> immediately as the current value of the function.
<i>Value</i> must be a debuggee value. (Most handler functions support
this, except those whose descriptions say otherwise.) If the function
was called as a constructor (that is, via a `new` expression), then
<i>value</i> serves as the value returned by the function's body, not
that produced by the `new` expression: if the value is not an object,
the `new` expression returns the frame's `this` value.
<code>{ yield: <i>value</i> }</code>
: <i>(Not yet implemented.)</i> Yield <i>value</i> immediately as the
next value of the current frame, which must be a generator frame.
<i>Value</i> is a debuggee value. The current frame must be a generator
frame that has not yet completed in some other way. You may use `yield`
resumption values to substitute a new value or one already yielded by a
generator, or to make a generator yield additional values.
<code>{ throw: <i>value</i> }</code>
: Throw <i>value</i> as an exception from the current bytecode
instruction. <i>Value</i> must be a debuggee value.
`null`
: Terminate the debuggee, as if it had been cancelled by the "slow script"
dialog box.
If a function that would normally return a resumption value to indicate
how the debuggee should continue instead throws an exception, we never
propagate such an exception to the debuggee; instead, we call the
associated `Debugger` instance's `uncaughtExceptionHook` property, as
described below.
## The `Debugger.DebuggeeWouldRun` Exception
Some debugger operations that appear to simply inspect the debuggee's state
may actually cause debuggee code to run. For example, reading a variable
might run a getter function on the global or on a `with` expression's
operand; and getting an object's property descriptor will run a handler
trap if the object is a proxy. To protect the debugger's integrity, only
methods whose stated purpose is to run debuggee code can do so. These
methods are called [invocation functions][inv fr], and they follow certain
common conventions to report the debuggee's behavior safely. For other
methods, if their normal operation would cause debuggee code to run, they
throw an instance of the `Debugger.DebuggeeWouldRun` exception.
A `Debugger.DebuggeeWouldRun` exception may have a `cause` property,
providing more detailed information on why the debuggee would have run. The
`cause` property's value is one of the following strings:
<i>cause</i> value meaning
-------------------- --------------------------------------------------------------------------------
"proxy" Carrying out the operation would have caused a proxy handler to run.
"getter" Carrying out the operation would have caused an object property getter to run.
"setter" Carrying out the operation would have caused an object property setter to run.
If the system can't determine why control attempted to enter the debuggee,
it will leave the exception's `cause` property undefined.

View File

@ -0,0 +1,186 @@
# The `Debugger` Interface
Mozilla's JavaScript engine, SpiderMonkey, provides a debugging interface
named `Debugger` which lets JavaScript code observe and manipulate the
execution of other JavaScript code. Both Firefox's built-in developer tools
and the Firebug add-on use `Debugger` to implement their JavaScript
debuggers. However, `Debugger` is quite general, and can be used to
implement other kinds of tools like tracers, coverage analysis,
patch-and-continue, and so on.
`Debugger` has three essential qualities:
- It is a *source level* interface: it operates in terms of the JavaScript
language, not machine language. It operates on JavaScript objects, stack
frames, environments, and code, and presents a consistent interface
regardless of whether the debuggee is interpreted, compiled, or
optimized. If you have a strong command of the JavaScript language, you
should have all the background you need to use `Debugger` successfully,
even if you have never looked into the language's implementation.
- It is for use *by JavaScript code*. JavaScript is both the debuggee
language and the tool implementation language, so the qualities that make
JavaScript effective on the web can be brought to bear in crafting tools
for developers. As is expected of JavaScript APIs, `Debugger` is a
*sound* interface: using (or even misusing) `Debugger` should never cause
Gecko to crash. Errors throw proper JavaScript exceptions.
- It is an *intra-thread* debugging API. Both the debuggee and the code
using `Debugger` to observe it must run in the same thread. Cross-thread,
cross-process, and cross-device tools must use `Debugger` to observe the
debuggee from within the same thread, and then handle any needed
communication themselves. (Firefox's builtin tools have a
[protocol][protocol] defined for this purpose.)
In Gecko, the `Debugger` API is available to chrome code only. By design,
it ought not to introduce security holes, so in principle it could be made
available to content as well; but it is hard to justify the security risks
of the additional attack surface.
## Debugger Instances and Shadow Objects
`Debugger` reflects every aspect of the debuggee's state as a JavaScript
value&mdash;not just actual JavaScript values like objects and primitives,
but also stack frames, environments, scripts, and compilation units, which
are not normally accessible as objects in their own right.
Here is a JavaScript program in the process of running a timer callback function:
![A running JavaScript program and its Debugger shadows][img-shadows]
This diagram shows the various types of shadow objects that make up the
Debugger API (which all follow some [general conventions][conventions]):
- A [`Debugger.Object`][object] represents a debuggee object, offering a
reflection-oriented API that protects the debugger from accidentally
invoking getters, setters, proxy traps, and so on.
- A [`Debugger.Script`][script] represents a block of JavaScript
code&mdash;either a function body or a top-level script. Given a
`Debugger.Script`, one can set breakpoints, translate between source
positions and bytecode offsets (a deviation from the "source level"
design principle), and find other static characteristics of the code.
- A [`Debugger.Frame`][frame] represents a running stack frame. You can use
these to walk the stack and find each frame's script and environment. You
can also set `onStep` and `onPop` handlers on frames.
- A [`Debugger.Environment`][environment] represents an environment,
associating variable names with storage locations. Environments may
belong to a running stack frame, captured by a function closure, or
reflect some global object's properties as variables.
The [`Debugger`][debugger-object] instance itself is not really a shadow of
anything in the debuggee; rather, it maintains the set of global objects
which are to be considered debuggees. A `Debugger` observes only execution
taking place in the scope of these global objects. You can set functions to
be called when new stack frames are pushed; when new code is loaded; and so
on.
Omitted from this picture are [`Debugger.Source`][source] instances, which
represent JavaScript compilation units. A `Debugger.Source` can furnish a
full copy of its source code, and explain how the code entered the system,
whether via a call to `eval`, a `<script>` element, or otherwise. A
`Debugger.Script` points to the `Debugger.Source` from which it is derived.
All these types follow some [general conventions][conventions], which you
should look through before drilling down into any particular type's
specification.
All shadow objects are unique per `Debugger` and per referent. For a given
`Debugger`, there is exactly one `Debugger.Object` that refers to a
particular debuggee object; exactly one `Debugger.Frame` for a particular
stack frame; and so on. Thus, a tool can store metadata about a shadow's
referent as a property on the shadow itself, and count on finding that
metadata again if it comes across the same referent. And since shadows are
per-`Debugger`, tools can do so without worrying about interfering with
other tools that use their own `Debugger` instances.
## Example
You can try out `Debugger` yourself in Firefox's Scratchpad.
1) Visit the URL `about:config`, and set the `devtools.chrome.enabled`
preference to `true`:
![Setting the 'devtools.chrome.enabled' preference][img-chrome-pref]
2) Save the following HTML text to a file, and visit the file in your
browser:
<div onclick="var x = 'snoo'; debugger;">Click me!</div>
3) Open a developer Scratchpad (Menu button > Developer > Scratchpad), and
select "Browser" from the "Environment" menu. (This menu will not be
present unless you have changed the preference as explained above.)
![Selecting the 'browser' context in the Scratchpad][img-scratchpad-browser]
4) Enter the following code in the Scratchpad:
// This simply defines 'Debugger' in this Scratchpad;
// it doesn't actually start debugging anything.
Cu.import("resource://gre/modules/jsdebugger.jsm");
addDebuggerToGlobal(window);
// Create a 'Debugger' instance.
var dbg = new Debugger;
// Get the current tab's content window, and make it a debuggee.
var w = gBrowser.selectedBrowser.contentWindow.wrappedJSObject;
dbg.addDebuggee(w);
// When the debuggee executes a 'debugger' statement, evaluate
// the expression 'x' in that stack frame, and show its value.
dbg.onDebuggerStatement = function (frame) {
alert('hit debugger statement; x = ' + frame.eval('x').return);
}
5) In the Scratchpad, ensure that no text is selected, and press the "Run"
button.
6) Now, click on the text that says "Click me!" in the web page. This runs
the `div` element's `onclick` handler. When control reaches the
`debugger;` statement, `Debugger` calls your callback function, passing
a `Debugger.Frame` instance. Your callback function evaluates the
expression `x` in the given stack frame, and displays the alert:
![The Debugger callback displaying an alert][img-example-alert]
7) Press "Run" in the Scratchpad again. Now, clicking on the "Click me!"
text causes *two* alerts to show&mdash;one for each `Debugger`
instance.
Multiple `Debugger` instances can observe the same debuggee. Re-running
the code in the Scratchpad created a fresh `Debugger` instance, added
the same web page as its debuggee, and then registered a fresh
`debugger;` statement handler with the new instance. When you clicked
on the `div` element, both of them ran. This shows how any number of
`Debugger`-based tools can observe a single web page
simultaneously&mdash;although, since the order in which their handlers
run is not specified, such tools should probably only observe, and not
influence, the debuggee's behavior.
8) Close the web page and the Scratchpad.
Since both the Scratchpad's global object and the debuggee window are
now gone, the `Debugger` instances will be garbage collected, since
they can no longer have any visible effect on Firefox's behavior. The
`Debugger` API tries to interact with garbage collection as
transparently as possible; for example, if both a `Debugger.Object`
instance and its referent are not reachable, they will both be
collected, even while the `Debugger` instance to which the shadow
belonged continues to exist.
## Gecko-specific features
While the `Debugger` core API deals only with concepts common to any
JavaScript implementation, it also includes some Gecko-specific features:
- [Global tracking][global] supports debugging all the code running in a
Gecko instance at once&mdash;the 'chrome debugging' model.
- [Object wrapper][wrapper] functions help manipulate object references
that cross privilege boundaries.

View File

@ -0,0 +1,231 @@
# Debugger.Environment
A `Debugger.Environment` instance represents a lexical environment,
associating names with variables. Each [`Debugger.Frame`][frame] instance
representing a debuggee frame has an associated environment object
describing the variables in scope in that frame; and each
[`Debugger.Object`][object] instance representing a debuggee function has an
environment object representing the environment the function has closed
over.
ECMAScript environments form a tree, in which each local environment is
parented by its enclosing environment (in ECMAScript terms, its 'outer'
environment). We say an environment <i>binds</i> an identifier if that
environment itself associates the identifier with a variable, independently
of its outer environments. We say an identifier is <i>in scope</i> in an
environment if the identifier is bound in that environment or any enclosing
environment.
SpiderMonkey creates `Debugger.Environment` instances as needed as the
debugger inspects stack frames and function objects; calling
`Debugger.Environment` as a function or constructor raises a `TypeError`
exception.
SpiderMonkey creates exactly one `Debugger.Environment` instance for each
environment it presents via a given [`Debugger`][debugger-object] instance:
if the debugger encounters the same environment through two different
routes (perhaps two functions have closed over the same environment),
SpiderMonkey presents the same `Debugger.Environment` instance to the
debugger each time. This means that the debugger can use the `==` operator
to recognize when two `Debugger.Environment` instances refer to the same
environment in the debuggee, and place its own properties on a
`Debugger.Environment` instance to store metadata about particular
environments.
(If more than one [`Debugger`][debugger-object] instance is debugging the
same code, each [`Debugger`][debugger-object] gets a separate
`Debugger.Environment` instance for a given environment. This allows the
code using each [`Debugger`][debugger-object] instance to place whatever
properties it likes on its own [`Debugger.Object`][object] instances,
without worrying about interfering with other debuggers.)
If a `Debugger.Environment` instance's referent is not a debuggee
environment, then attempting to access its properties (other than
`inspectable`) or call any its methods throws an instance of `Error`.
`Debugger.Environment` instances protect their referents from the
garbage collector; as long as the `Debugger.Environment` instance is
live, the referent remains live. Garbage collection has no visible
effect on `Debugger.Environment` instances.
## Accessor Properties of the Debugger.Environment Prototype Object
A `Debugger.Environment` instance inherits the following accessor
properties from its prototype:
`inspectable`
: True if this environment is a debuggee environment, and can therefore
be inspected. False otherwise. All other properties and methods of
`Debugger.Environment` instances throw if applied to a non-inspectable
environment.
`type`
: The type of this environment object, one of the following values:
* "declarative", indicating that the environment is a declarative
environment record. Function calls, calls to `eval`, `let` blocks,
`catch` blocks, and the like create declarative environment records.
* "object", indicating that the environment's bindings are the
properties of an object. The global object and DOM elements appear in
the chain of environments via object environments. (Note that `with`
statements have their own environment type.)
* "with", indicating that the environment was introduced by a `with`
statement.
`parent`
: The environment that encloses this one (the "outer" environment, in
ECMAScript terminology), or `null` if this is the outermost environment.
`object`
: A [`Debugger.Object`][object] instance referring to the object whose
properties this environment reflects. If this is a declarative
environment record, this accessor throws a `TypeError` (since
declarative environment records have no such object). Both `"object"`
and `"with"` environments have `object` properties that provide the
object whose properties they reflect as variable bindings.
`callee`
: If this environment represents the variable environment (the top-level
environment within the function, which receives `var` definitions) for
a call to a function <i>f</i>, then this property's value is a
[`Debugger.Object`][object] instance referring to <i>f</i>. Otherwise,
this property's value is `null`.
## Function Properties of the Debugger.Environment Prototype Object
The methods described below may only be called with a `this` value
referring to a `Debugger.Environment` instance; they may not be used as
methods of other kinds of objects.
`names()`
: Return an array of strings giving the names of the identifiers bound by
this environment. The result does not include the names of identifiers
bound by enclosing environments.
<code>getVariable(<i>name</i>)</code>
: Return the value of the variable bound to <i>name</i> in this
environment, or `undefined` if this environment does not bind
<i>name</i>. <i>Name</i> must be a string that is a valid ECMAScript
identifier name. The result is a debuggee value.
JavaScript engines often omit variables from environments, to save space
and reduce execution time. If the given variable should be in scope, but
`getVariable` is unable to produce its value, it returns an ordinary
JavaScript object (not a [`Debugger.Object`][object] instance) whose
`optimizedOut` property is `true`.
This is not an [invocation function][inv fr];
if this call would cause debuggee code to run (say, because the
environment is a `"with"` environment, and <i>name</i> refers to an
accessor property of the `with` statement's operand), this call throws a
[`Debugger.DebuggeeWouldRun`][wouldrun]
exception.
<code>setVariable(<i>name</i>, <i>value</i>)</code>
: Store <i>value</i> as the value of the variable bound to <i>name</i> in
this environment. <i>Name</i> must be a string that is a valid
ECMAScript identifier name; <i>value</i> must be a debuggee value.
If this environment binds no variable named <i>name</i>, throw a
`ReferenceError`.
This is not an [invocation function][inv fr];
if this call would cause debuggee code to run, this call throws a
[`Debugger.DebuggeeWouldRun`][wouldrun]
exception.
<code>getVariableDescriptor(<i>name</i>)</code>
: Return an property descriptor describing the variable bound to
<i>name</i> in this environment, of the sort returned by
`Debugger.Object.prototype.getOwnPropertyDescriptor`. <i>Name</i> must
be a string whose value is a valid ECMAScript identifier name.
If this is an `"object"` or `"with"` environment record, this simply
returns the descriptor for the given property of the environment's
object. If this is a declarative environment record, this returns a
descriptor reflecting the binding's mutability as the descriptor's
`writable` property, and its deletability as the descriptor's
`configurable` property. All declarative environment record bindings are
marked as `enumerable`. <i>(This isn't great; the semantics of variables
in declarative enviroments don't really match those of properties, so
writing code that operates properly on descriptors for either kind may
be difficult.)</i>
If this environment binds no variable named <i>name</i>, throw a
`ReferenceError`.
<code>defineVariable(<i>name</i>, <i>descriptor</i>)</code>
: Create or reconfigure the variable bound to <i>name</i> in this
environment according to <i>descriptor</i>. <i>Descriptor</i> is the
sort of value returned by `getVariableDescriptor`. On success, return
`undefined`; on failure, throw an appropriate exception. <i>Name</i>
must be a string whose value is a valid ECMAScript identifier name.
If implementation restrictions prevent SpiderMonkey from creating or
reconfiguring the variable as requested, this call throws an `Error`
exception.
<code>deleteVariable(<i>name</i>)</code>
: Delete this environment's binding for <i>name</i>.
If this environment binds no variable named <i>name</i>, throw a
`ReferenceError`.
If implementation restrictions prevent SpiderMonkey from deleting the
variable as requested, this call throws an `Error` exception.
<code>find(<i>name</i>)</code>
: Return a reference to the innermost environment, starting with this
environment, that binds <i>name</i>. If <i>name</i> is not in scope in
this environment, return `null`. <i>Name</i> must be a string whose
value is a valid ECMAScript identifier name.
<code>eval(<i>code</i>)</code> <i>(future plan)</i>
: Evaluate <i>code</i> in this environment, and return a
[completion value][cv] describing how it completed. <i>Code</i> is a
string. All extant handler methods, breakpoints, watchpoints, and so on
remain active during the call. This function follows the
[invocation function conventions][inv fr].
<i>Code</i> is interpreted as strict mode code when it contains a Use
Strict Directive.
If <i>code</i> is not strict mode code, then variable declarations in
<i>code</i> affect this environment. (In the terms used by the
ECMAScript specification, the `VariableEnvironment` of the execution
context for the eval code is the `VariableEnvironment` this
`Debugger.Environment` instance represents.) If implementation
restrictions prevent SpiderMonkey from extending this environment as
requested, this call throws an `Error` exception.
<code>evalWithBindings(<i>code</i>, <i>bindings</i>)</code> <i>(future plan)</i>
: Like `eval`, but evaluate <i>code</i> in this environment, extended with
bindings from the object <i>bindings</i>. For each own enumerable
property of <i>bindings</i> named <i>name</i> whose value is
<i>value</i>, include a variable in the environment in which <i>code</i>
is evaluated named <i>name</i>, whose value is <i>value</i>. Each
<i>value</i> must be a debuggee value. (This is not like a `with`
statement: <i>code</i> may access, assign to, and delete the introduced
bindings without having any effect on the <i>bindings</i> object.)
This method allows debugger code to introduce temporary bindings that
are visible to the given debuggee code and which refer to debugger-held
debuggee values, and do so without mutating any existing debuggee
environment.
Note that, like `eval`, declarations in the <i>code</i> passed to
`evalWithBindings` affect this environment, even as <i>code</i> is
evaluated with <i>bindings</i> visible. (In the terms used by the
ECMAScript specification, the `VariableEnvironment` of the execution
context for the eval code is the `VariableEnvironment` this environment
represents, and the <i>bindings</i> appear in a new declarative
environment, which is the eval code's `LexicalEnvironment`.) If
implementation restrictions prevent SpiderMonkey from extending this
environment as requested, this call throws an `Error` exception.

View File

@ -0,0 +1,421 @@
# Debugger.Frame
A `Debugger.Frame` instance represents a [visible stack frame][vf]. Given a
`Debugger.Frame` instance, you can find the script the frame is executing,
walk the stack to older frames, find the lexical environment in which the
execution is taking place, and so on.
For a given [`Debugger`][debugger-object] instance, SpiderMonkey creates
only one `Debugger.Frame` instance for a given visible frame. Every handler
method called while the debuggee is running in a given frame is given the
same frame object. Similarly, walking the stack back to a previously
accessed frame yields the same frame object as before. Debugger code can
add its own properties to a frame object and expect to find them later, use
`==` to decide whether two expressions refer to the same frame, and so on.
(If more than one [`Debugger`][debugger-object] instance is debugging the
same code, each [`Debugger`][debugger-object] gets a separate
`Debugger.Frame` instance for a given frame. This allows the code using
each [`Debugger`][debugger-object] instance to place whatever properties it
likes on its `Debugger.Frame` instances, without worrying about interfering
with other debuggers.)
When the debuggee pops a stack frame (say, because a function call has
returned or an exception has been thrown from it), the `Debugger.Frame`
instance referring to that frame becomes inactive: its `live` property
becomes `false`, and accessing its other properties or calling its methods
throws an exception. Note that frames only become inactive at times that
are predictable for the debugger: when the debuggee runs, or when the
debugger removes frames from the stack itself.
Stack frames that represent the control state of generator-iterator objects
behave in a special way, described in [Generator Frames][generator] below.
## Visible Frames
When inspecting the call stack, [`Debugger`][debugger-object] does not
reveal all the frames that are actually present on the stack: while it does
reveal all frames running debuggee code, it omits frames running the
debugger's own code, and omits most frames running non-debuggee code. We
call those stack frames a [`Debugger`][debugger-object] does reveal
<i>visible frames</i>.
A frame is a visible frame if any of the following are true:
* it is running [debuggee code][dbg code];
* its immediate caller is a frame running debuggee code; or
* it is a [`"debugger"` frame][inv fr],
representing the continuation of debuggee code invoked by the debugger.
The "immediate caller" rule means that, when debuggee code calls a
non-debuggee function, it looks like a call to a primitive: you see a frame
for the non-debuggee function that was accessible to the debuggee, but any
further calls that function makes are treated as internal details, and
omitted from the stack trace. If the non-debuggee function eventually calls
back into debuggee code, then those frames are visible.
(Note that the debuggee is not considered an "immediate caller" of handler
methods it triggers. Even though the debuggee and debugger share the same
JavaScript stack, frames pushed for SpiderMonkey's calls to handler methods
to report events in the debuggee are never considered visible frames.)
## Invocation Functions and "debugger" Frames
An <i>invocation function</i> is any function in this interface that allows
the debugger to invoke code in the debuggee:
`Debugger.Object.prototype.call`, `Debugger.Frame.prototype.eval`, and so
on.
While invocation functions differ in the code to be run and how to pass
values to it, they all follow this general procedure:
1. Let <i>older</i> be the youngest visible frame on the stack, or `null`
if there is no such frame. (This is never one of the the debugger's own
frames; those never appear as `Debugger.Frame` instances.)
2. Push a `"debugger"` frame on the stack, with <i>older</i> as its
`older` property.
3. Invoke the debuggee code as appropriate for the given invocation
function, with the `"debugger"` frame as its continuation. For example,
`Debugger.Frame.prototype.eval` pushes an `"eval"` frame for code it
runs, whereas `Debugger.Object.prototype.call` pushes a `"call"` frame.
4. When the debuggee code completes, whether by returning, throwing an
exception or being terminated, pop the `"debugger"` frame, and return an
appropriate [completion value][cv] from the invocation function to the
debugger.
When a debugger calls an invocation function to run debuggee code, that
code's continuation is the debugger, not the next debuggee code frame.
Pushing a `"debugger"` frame makes this continuation explicit, and makes it
easier to find the extent of the stack created for the invocation.
## Accessor Properties of the Debugger.Frame Prototype Object
A `Debugger.Frame` instance inherits the following accessor properties from
its prototype:
`type`
: A string describing what sort of frame this is:
* `"call"`: a frame running a function call. (We may not be able to obtain
frames for calls to host functions.)
* `"eval"`: a frame running code passed to `eval`.
* `"global"`: a frame running global code (JavaScript that is neither of
the above).
* `"debugger"`: a frame for a call to user code invoked by the debugger
(see the `eval` method below).
`this`
: The value of `this` for this frame (a debuggee value).
`older`
: The next-older visible frame, in which control will resume when this
frame completes. If there is no older frame, this is `null`. (On a
suspended generator frame, the value of this property is `null`; see
[Generator Frames][generator].)
`depth`
: The depth of this frame, counting from oldest to youngest; the oldest
frame has a depth of zero.
`live`
: True if the frame this `Debugger.Frame` instance refers to is still on
the stack (or, in the case of generator-iterator objects, has not yet
finished its iteration); false if it has completed execution or been
popped in some other way.
`script`
: The script being executed in this frame (a [`Debugger.Script`][script]
instance), or `null` on frames that do not represent calls to debuggee
code. On frames whose `callee` property is not null, this is equal to
`callee.script`.
`offset`
: The offset of the bytecode instruction currently being executed in
`script`, or `undefined` if the frame's `script` property is `null`.
`environment`
: The lexical environment within which evaluation is taking place (a
[`Debugger.Environment`][environment] instance), or `null` on frames
that do not represent the evaluation of debuggee code, like calls
non-debuggee functions, host functions or `"debugger"` frames.
`callee`
: The function whose application created this frame, as a debuggee value,
or `null` if this is not a `"call"` frame.
`generator`
: True if this frame is a generator frame, false otherwise.
`constructing`
: True if this frame is for a function called as a constructor, false
otherwise.
`arguments`
: The arguments passed to the current frame, or `null` if this is not a
`"call"` frame. When non-`null`, this is an object, allocated in the
same global as the debugger, with `Array.prototype` on its prototype
chain, a non-writable `length` property, and properties whose names are
array indices. Each property is a read-only accessor property whose
getter returns the current value of the corresponding parameter. When
the referent frame is popped, the argument value's properties' getters
throw an error.
## Handler Methods of Debugger.Frame Instances
Each `Debugger.Frame` instance inherits accessor properties holding handler
functions for SpiderMonkey to call when given events occur in the frame.
Calls to frames' handler methods are cross-compartment, intra-thread calls:
the call takes place in the thread to which the frame belongs, and runs in
the compartment to which the handler method belongs.
`Debugger.Frame` instances inherit the following handler method properties:
`onStep`
: This property must be either `undefined` or a function. If it is a
function, SpiderMonkey calls it when execution in this frame makes a
small amount of progress, passing no arguments and providing this
`Debugger.Frame` instance as the `this`value. The function should
return a [resumption value][rv] specifying how the debuggee's execution
should proceed.
What constitutes "a small amount of progress" varies depending on the
implementation, but it is fine-grained enough to implement useful
"step" and "next" behavior.
If multiple [`Debugger`][debugger-object] instances each have
`Debugger.Frame` instances for a given stack frame with `onStep`
handlers set, their handlers are run in an unspecified order. If any
`onStep` handler forces the frame to return early (by returning a
resumption value other than `undefined`), any remaining debuggers'
`onStep` handlers do not run.
This property is ignored on frames that are not executing debuggee
code, like `"call"` frames for calls to host functions and `"debugger"`
frames.
`onPop`
: This property must be either `undefined` or a function. If it is a
function, SpiderMonkey calls it just before this frame is popped,
passing a [completion value][cv] indicating how this frame's execution
completed, and providing this `Debugger.Frame` instance as the `this`
value. The function should return a [resumption value][rv] indicating
how execution should proceed. On newly created frames, this property's
value is `undefined`.
When an `onPop` call reports the completion of a construction call
(that is, a function called via the `new` operator), the completion
value passed to the handler describes the value returned by the
function body. If this value is not an object, it may be different from
the value produced by the `new` expression, which will be the value of
the frame's `this` property. (In ECMAScript terms, the `onPop` handler
receives the value returned by the `[[Call]]` method, not the value
returned by the `[[Construct]]` method.)
When a debugger handler function forces a frame to complete early, by
returning a `{ return:... }`, `{ throw:... }`, or `null` resumption
value, SpiderMonkey calls the frame's `onPop` handler, if any. The
completion value passed in this case reflects the resumption value that
caused the frame to complete.
When SpiderMonkey calls an `onPop` handler for a frame that is throwing
an exception or being terminated, and the handler returns `undefined`,
then SpiderMonkey proceeds with the exception or termination. That is,
an `undefined` resumption value leaves the frame's throwing and
termination process undisturbed.
<i>(Not yet implemented.)</i> When a generator frame yields a value,
SpiderMonkey calls its `Debugger.Frame` instance's `onPop` handler
method, if present, passing a `yield` resumption value; however, the
`Debugger.Frame` instance remains live.
If multiple [`Debugger`][debugger-object] instances each have
`Debugger.Frame` instances for a given stack frame with `onPop`
handlers set, their handlers are run in an unspecified order. The
resumption value each handler returns establishes the completion value
reported to the next handler.
This property is ignored on `"debugger"` frames.
`onResume`
: This property must be either `undefined` or a function. If it is a
function, SpiderMonkey calls it if the current frame is a generator
frame whose execution has just been resumed. The function should return
a [resumption value][rv] indicating how execution should proceed. On
newly created frames, this property's value is `undefined`.
If the program resumed the generator by calling its `send` method and
passing a value, then <i>value</i> is that value. Otherwise,
<i>value</i> is `undefined`.
## Function Properties of the Debugger.Frame Prototype Object
The functions described below may only be called with a `this` value
referring to a `Debugger.Frame` instance; they may not be used as
methods of other kinds of objects.
<code id="eval">eval(<i>code</i>, [<i>options</i>])</code>
: Evaluate <i>code</i> in the execution context of this frame, and return
a [completion value][cv] describing how it completed. <i>Code</i> is a
string. If this frame's `environment` property is `null`, throw a
`TypeError`. All extant handler methods, breakpoints, watchpoints, and
so on remain active during the call. This function follows the
[invocation function conventions][inv fr].
<i>Code</i> is interpreted as strict mode code when it contains a Use
Strict Directive, or the code executing in this frame is strict mode
code.
If <i>code</i> is not strict mode code, then variable declarations in
<i>code</i> affect the environment of this frame. (In the terms used by
the ECMAScript specification, the `VariableEnvironment` of the
execution context for the eval code is the `VariableEnvironment` of the
execution context that this frame represents.) If implementation
restrictions prevent SpiderMonkey from extending this frame's
environment as requested, this call throws an Error exception.
If given, <i>options</i> should be an object whose properties specify
details of how the evaluation should occur. The `eval` method
recognizes the following properties:
<code>url</code>
: The filename or URL to which we should attribute <i>code</i>. If this
property is omitted, the URL defaults to `"debugger eval code"`.
<code>lineNumber</code>
: The line number at which the evaluated code should be claimed to begin
within <i>url</i>.
<code>evalWithBindings(<i>code</i>, <i>bindings</i>, [<i>options</i>])</code>
: Like `eval`, but evaluate <i>code</i> in the environment of this frame,
extended with bindings from the object <i>bindings</i>. For each own
enumerable property of <i>bindings</i> named <i>name</i> whose value is
<i>value</i>, include a variable in the environment in which
<i>code</i> is evaluated named <i>name</i>, whose value is
<i>value</i>. Each <i>value</i> must be a debuggee value. (This is not
like a `with` statement: <i>code</i> may access, assign to, and delete
the introduced bindings without having any effect on the
<i>bindings</i> object.)
This method allows debugger code to introduce temporary bindings that
are visible to the given debuggee code and which refer to debugger-held
debuggee values, and do so without mutating any existing debuggee
environment.
Note that, like `eval`, declarations in the <i>code</i> passed to
`evalWithBindings` affect the environment of this frame, even as that
environment is extended by bindings visible within <i>code</i>. (In the
terms used by the ECMAScript specification, the `VariableEnvironment`
of the execution context for the eval code is the `VariableEnvironment`
of the execution context that this frame represents, and the
<i>bindings</i> appear in a new declarative environment, which is the
eval code's `LexicalEnvironment`.) If implementation restrictions
prevent SpiderMonkey from extending this frame's environment as
requested, this call throws an `Error` exception.
The <i>options</i> argument is as for
[`Debugger.Frame.prototype.eval`][fr eval], described above.
<code>pop(<i>completion</i>)</code> <i>(future plan)</i>
: Pop this frame (and any younger frames) from the stack as if this frame
had completed as specified by the completion value <i>completion</i>.
Note that this does <i>not</i> resume the debuggee's execution; it
merely adjusts the debuggee's state to what it would be if this frame's
execution had completed. The debuggee will only resume execution when
you return from the handler method that brought control to the debugger
originally.
This cannot remove any `"call"` frames for calls to host functions from
the stack. (We might be able to make this work eventually, but it will
take some cleverness.)
<code>replaceCall(<i>function</i>, <i>this</i>, <i>arguments</i>)</code> <i>(future plan)</i>
: Pop any younger frames from the stack, and then change this frame into
a frame for a call to <i>function</i>, with the given <i>this</i> value
and <i>arguments</i>. <i>This</i> should be a debuggee value, or
`{ asConstructor: true }` to invoke <i>function</i> as a constructor,
in which case SpiderMonkey provides an appropriate `this` value itself.
<i>Arguments</i> should be an array of debuggee values. This frame must
be a `"call"` frame.
This can be used as a primitive in implementing some forms of a "patch
and continue" debugger feature.
Note that this does <i>not</i> resume the debuggee's execution; it
merely adjusts the debuggee's state to what it would be if this frame
were about to make this call. The debuggee will only resume execution
when you return from the handler method that brought control to the
debugger originally.
Like `pop`, this cannot remove `"call"` frames for calls to host
functions from the stack.
## Generator Frames
<i>Not all behavior described in this section has been implemented
yet.</i>
SpiderMonkey supports generator-iterator objects, which produce a series of
values by repeatedly suspending the execution of a function or expression.
For example, calling a function that uses `yield` produces a
generator-iterator object, as does evaluating a generator expression like
`(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; while the generator is
suspended, it has no particular continuation frame; and when it resumes
again, the continuation frame for that resumption could be different from
that of the previous resumption.
A `Debugger.Frame` instance representing a generator frame differs from an
ordinary stack frame as follows:
* A generator frame's `generator` property is true.
* A generator frame disappears from the stack each time the generator
yields a value and is suspended, and reappears atop the stack when it is
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.
* A generator frame's `older` property refers to the frame's continuation
frame while the generator is running, and is `null` while the generator
is suspended.
* A generator frame's `depth` property reflects the frame's position on
the stack when the generator is resumed, and is `null` while the
generator is suspended.
* A generator frame's `live` property remains true until the frame
returns, throws an exception, or is terminated. Thus, generator frames
can be live while not present on the stack.
The other `Debugger.Frame` methods and accessor properties work as
described on generator frames, even when the generator frame is suspended.
You may examine a suspended generator frame's variables, and use its
`script` and `offset` members to see which `yield` it is suspended at.
A `Debugger.Frame` instance referring to a generator-iterator frame has a
strong reference to the generator-iterator object; the frame (and its
object) will live as long as the `Debugger.Frame` instance does. However,
when the generator function returns, throws an exception, or is terminated,
thus ending the iteration, the `Debugger.Frame` instance becomes inactive
and its `live` property becomes `false`, just as would occur for any other
sort of frame that is popped. A non-live `Debugger.Frame` instance no
longer holds a strong reference to the generator-iterator object.

View File

@ -0,0 +1,534 @@
# Debugger.Object
A `Debugger.Object` instance represents an object in the debuggee,
providing reflection-oriented methods to inspect and modify its referent.
The referent's properties do not appear directly as properties of the
`Debugger.Object` instance; the debugger can access them only through
methods like `Debugger.Object.prototype.getOwnPropertyDescriptor` and
`Debugger.Object.prototype.defineProperty`, ensuring that the debugger will
not inadvertently invoke the referent's getters and setters.
SpiderMonkey creates exactly one `Debugger.Object` instance for each
debuggee object it presents to a given [`Debugger`][debugger-object]
instance: if the debugger encounters the same object through two different
routes (perhaps two functions are called on the same object), SpiderMonkey
presents the same `Debugger.Object` instance to the debugger each time.
This means that the debugger can use the `==` operator to recognize when
two `Debugger.Object` instances refer to the same debuggee object, and
place its own properties on a `Debugger.Object` instance to store metadata
about particular debuggee objects.
JavaScript code in different compartments can have different views of the
same object. For example, in Firefox, code in privileged compartments sees
content DOM element objects without redefinitions or extensions made to
that object's properties by content code. (In Firefox terminology,
privileged code sees the element through an "xray wrapper".) To ensure that
debugger code sees each object just as the debuggee would, each
`Debugger.Object` instance presents its referent as it would be seen from a
particular compartment. This "viewing compartment" is chosen to match the
way the debugger came across the referent. As a consequence, a single
[`Debugger`][debugger-object] instance may actually have several
`Debugger.Object` instances: one for each compartment from which the
referent is viewed.
If more than one [`Debugger`][debugger-object] instance is debugging the
same code, each [`Debugger`][debugger-object] gets a separate
`Debugger.Object` instance for a given object. This allows the code using
each [`Debugger`][debugger-object] instance to place whatever properties it
likes on its own `Debugger.Object` instances, without worrying about
interfering with other debuggers.
While most `Debugger.Object` instances are created by SpiderMonkey in the
process of exposing debuggee's behavior and state to the debugger, the
debugger can use `Debugger.Object.prototype.makeDebuggeeValue` to create
`Debugger.Object` instances for given debuggee objects, or use
`Debugger.Object.prototype.copy` and `Debugger.Object.prototype.create` to
create new objects in debuggee compartments, allocated as if by particular
debuggee globals.
`Debugger.Object` instances protect their referents from the garbage
collector; as long as the `Debugger.Object` instance is live, the referent
remains live. This means that garbage collection has no visible effect on
`Debugger.Object` instances.
## Accessor Properties of the Debugger.Object prototype
A `Debugger.Object` instance inherits the following accessor properties
from its prototype:
`proto`
: The referent's prototype (as a new `Debugger.Object` instance), or
`null` if it has no prototype.
`class`
: A string naming the ECMAScript `[[Class]]` of the referent.
`callable`
: `true` if the referent is a callable object (such as a function or a
function proxy); false otherwise.
`name`
: The name of the referent, if it is a named function. If the referent is
an anonymous function, or not a function at all, this is `undefined`.
This accessor returns whatever name appeared after the `function`
keyword in the source code, regardless of whether the function is the
result of instantiating a function declaration (which binds the
function to its name in the enclosing scope) or evaluating a function
expression (which binds the function to its name only within the
function's body).
`displayName`
: The referent's display name, if the referent is a function with a
display name. If the referent is not a function, or if it has no display
name, this is `undefined`.
If a function has a given name, its display name is the same as its
given name. In this case, the `displayName` and `name` properties are
equal.
If a 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 <code><i>a</i>/<i>b</i></code> to refer to
the <i>b</i> defined within <i>a</i>, and <code><i>a</i>&lt;</code> to
refer to a function that occurs somewhere within an expression that is
assigned to <i>a</i>. For example:
function h() {
var i = function() {}; // display name: h/i
f(function () {}); // display name: h/<
}
var s = f(function () {}); // display name: s<
`parameterNames`
: If the referent is a debuggee function, the names of the its parameters,
as an array of strings. If the referent is not a debuggee function, or
not a function at all, this is `undefined`.
If the referent is a host function for which parameter names are not
available, return an array with one element per parameter, each of which
is `undefined`.
If the referent is a function proxy, return an empty array.
If the referent uses destructuring parameters, then the array's elements
reflect the structure of the parameters. For example, if the referent is
a function declared in this way:
function f(a, [b, c], {d, e:f}) { ... }
then this `Debugger.Object` instance's `parameterNames` property would
have the value:
["a", ["b", "c"], {d:"d", e:"f"}]
`script`
: If the referent is a function that is debuggee code, this is that
function's script, as a [`Debugger.Script`][script] instance. If the
referent is a function proxy or not debuggee code, this is `undefined`.
`environment`
: If the referent is a function that is debuggee code, a
[`Debugger.Environment`][environment] instance representing the lexical
environment enclosing the function when it was created. If the referent
is a function proxy or not debuggee code, this is `undefined`.
`proxyHandler`
: If the referent is a proxy whose handler object was allocated by
debuggee code, this is its handler object—the object whose methods are
invoked to implement accesses of the proxy's properties. If the referent
is not a proxy whose handler object was allocated by debuggee code, this
is `null`.
`proxyCallTrap`
: If the referent is a function proxy whose handler object was allocated
by debuggee code, this is its call trap function—the function called
when the function proxy is called. If the referent is not a function
proxy whose handler object was allocated by debuggee code, this is
`null`.
`proxyConstructTrap`
: If the referent is a function proxy whose handler object was allocated
by debuggee code, its construction trap function—the function called
when the function proxy is called via a `new` expression. If the
referent is not a function proxy whose handler object was allocated by
debuggee code, this is `null`.
`global`
: A `Debugger.Object` instance referring to the global object in whose
scope the referent was allocated. This does not unwrap cross-compartment
wrappers: if the referent is a wrapper, the result refers to the
wrapper's global, not the wrapped object's global. The result refers to
the global directly, not via a wrapper.
`hostAnnotations`
: A JavaScript object providing further metadata about the referent, or
`null` if none is available. The metadata object is in the same
compartment as this `Debugger.Object` instance. The same metadata
object is returned each time for a given `Debugger.Object` instance.
A typical JavaScript embedding provides "host objects" to expose
application-specific functionality to scripts. The `hostAnnotations`
accessor consults the embedding for additional information about the
referent that might be of interest to the debugger. The returned
object's properties' meanings are up to the embedding. For example, a
web browser might provide host annotations for global objects to
distinguish top-level windows, iframes, and internal JavaScript scopes.
By convention, host annotation objects have a string-valued `"type"`
property that, taken together with the object's class, indicate what
sort of thing the referent is. The host annotation object's other
properties provide further details, as appropriate for the type. For
example, in Firefox, a metadata object for a JavaScript Module's global
object might look like this:
{ "type":"jsm", "uri":"resource:://gre/modules/XPCOMUtils.jsm" }
Firefox provides [DebuggerHostAnnotationsForFirefox annotations] for its
host objects.
## Function Properties of the Debugger.Object prototype
The functions described below may only be called with a `this` value
referring to a `Debugger.Object` instance; they may not be used as methods
of other kinds of objects. The descriptions use "referent" to mean "the
referent of this `Debugger.Object` instance".
Unless otherwise specified, these methods are not
[invocation functions][inv fr]; if a call would cause debuggee code to run
(say, because it gets or sets an accessor property whose handler is
debuggee code, or because the referent is a proxy whose traps are debuggee
code), the call throws a [`Debugger.DebuggeeWouldRun`][wouldrun] exception.
<code>getProperty(<i>name</i>)</code>
: Return the value of the referent's property named <i>name</i>, or
`undefined` if it has no such property. <i>Name</i> must be a string.
The result is a debuggee value.
<code>setProperty(<i>name</i>, <i>value</i>)</code>
: Store <i>value</i> as the value of the referent's property named
<i>name</i>, creating the property if it does not exist. <i>Name</i>
must be a string; <i>value</i> must be a debuggee value.
<code>getOwnPropertyDescriptor(<i>name</i>)</code>
: Return a property descriptor for the property named <i>name</i> of the
referent. If the referent has no such property, return `undefined`.
(This function behaves like the standard
`Object.getOwnPropertyDescriptor` function, except that the object being
inspected is implicit; the property descriptor returned is allocated as
if by code scoped to the debugger's global object (and is thus in the
debugger's compartment); and its `value`, `get`, and `set` properties,
if present, are debuggee values.)
`getOwnPropertyNames()`
: Return an array of strings naming all the referent's own properties, as
if <code>Object.getOwnPropertyNames(<i>referent</i>)</code> had been
called in the debuggee, and the result copied in the scope of the
debugger's global object.
<code>defineProperty(<i>name</i>, <i>attributes</i>)</code>
: Define a property on the referent named <i>name</i>, as described by
the property descriptor <i>descriptor</i>. Any `value`, `get`, and
`set` properties of <i>attributes</i> must be debuggee values. (This
function behaves like `Object.defineProperty`, except that the target
object is implicit, and in a different compartment from the function
and descriptor.)
<code>defineProperties(<i>properties</i>)</code>
: Add the properties given by <i>properties</i> to the referent. (This
function behaves like `Object.defineProperties`, except that the target
object is implicit, and in a different compartment from the
<i>properties</i> argument.)
<code>deleteProperty(<i>name</i>)</code>
: Remove the referent's property named <i>name</i>. Return true if the
property was successfully removed, or if the referent has no such
property. Return false if the property is non-configurable.
`seal()`
: Prevent properties from being added to or deleted from the referent.
Return this `Debugger.Object` instance. (This function behaves like the
standard `Object.seal` function, except that the object to be sealed is
implicit and in a different compartment from the caller.)
`freeze()`
: Prevent properties from being added to or deleted from the referent, and
mark each property as non-writable. Return this `Debugger.Object`
instance. (This function behaves like the standard `Object.freeze`
function, except that the object to be sealed is implicit and in a
different compartment from the caller.)
`preventExtensions()`
: Prevent properties from being added to the referent. (This function
behaves like the standard `Object.preventExtensions` function, except
that the object to operate on is implicit and in a different compartment
from the caller.)
`isSealed()`
: Return true if the referent is sealed—that is, if it is not extensible,
and all its properties have been marked as non-configurable. (This
function behaves like the standard `Object.isSealed` function, except
that the object inspected is implicit and in a different compartment
from the caller.)
`isFrozen()`
: Return true if the referent is frozen—that is, if it is not extensible,
and all its properties have been marked as non-configurable and
read-only. (This function behaves like the standard `Object.isFrozen`
function, except that the object inspected is implicit and in a
different compartment from the caller.)
`isExtensible()`
: Return true if the referent is extensible—that is, if it can have new
properties defined on it. (This function behaves like the standard
`Object.isExtensible` function, except that the object inspected is
implicit and in a different compartment from the caller.)
<code>copy(<i>value</i>)</code>
: Apply the HTML5 "structured cloning" algorithm to create a copy of
<i>value</i> in the referent's global object (and thus in the referent's
compartment), and return a `Debugger.Object` instance referring to the
copy.
Note that this returns primitive values unchanged. This means you can
use `Debugger.Object.prototype.copy` as a generic "debugger value to
debuggee value" conversion function—within the limitations of the
"structured cloning" algorithm.
<code>create(<i>prototype</i>, [<i>properties</i>])</code>
: Create a new object in the referent's global (and thus in the
referent's compartment), and return a `Debugger.Object` referring to
it. The new object's prototype is <i>prototype</i>, which must be an
`Debugger.Object` instance. The new object's properties are as given by
<i>properties</i>, as if <i>properties</i> were passed to
`Debugger.Object.prototype.defineProperties`, with the new
`Debugger.Object` instance as the `this` value.
<code>makeDebuggeeValue(<i>value</i>)</code>
: Return the debuggee value that represents <i>value</i> in the debuggee.
If <i>value</i> is a primitive, we return it unchanged; if <i>value</i>
is an object, we return the `Debugger.Object` instance representing
that object, wrapped appropriately for use in this `Debugger.Object`'s
referent's compartment.
Note that, if <i>value</i> is an object, it need not be one allocated
in a debuggee global, nor even a debuggee compartment; it can be any
object the debugger wishes to use as a debuggee value.
As described above, each `Debugger.Object` instance presents its
referent as viewed from a particular compartment. Given a
`Debugger.Object` instance <i>d</i> and an object <i>o</i>, the call
<code><i>d</i>.makeDebuggeeValue(<i>o</i>)</code> returns a
`Debugger.Object` instance that presents <i>o</i> as it would be seen
by code in <i>d</i>'s compartment.
<code>decompile([<i>pretty</i>])</code>
: If the referent is a function that is debuggee code, return the
JavaScript source code for a function definition equivalent to the
referent function in its effect and result, as a string. If
<i>pretty</i> is present and true, produce indented code with line
breaks. If the referent is not a function that is debuggee code, return
`undefined`.
<code>call(<i>this</i>, <i>argument</i>, ...)</code>
: If the referent is callable, call it with the given <i>this</i> value
and <i>argument</i> values, and return a [completion value][cv]
describing how the call completed. <i>This</i> should be a debuggee
value, or `{ asConstructor: true }` to invoke the referent as a
constructor, in which case SpiderMonkey provides an appropriate `this`
value itself. Each <i>argument</i> must be a debuggee value. All extant
handler methods, breakpoints, watchpoints, and so on remain active
during the call. If the referent is not callable, throw a `TypeError`.
This function follows the [invocation function conventions][inv fr].
<code>apply(<i>this</i>, <i>arguments</i>)</code>
: If the referent is callable, call it with the given <i>this</i> value
and the argument values in <i>arguments</i>, and return a
[completion value][cv] describing how the call completed. <i>This</i>
should be a debuggee value, or `{ asConstructor: true }` to invoke
<i>function</i> as a constructor, in which case SpiderMonkey provides
an appropriate `this` value itself. <i>Arguments</i> must either be an
array (in the debugger) of debuggee values, or `null` or `undefined`,
which are treated as an empty array. All extant handler methods,
breakpoints, watchpoints, and so on remain active during the call. If
the referent is not callable, throw a `TypeError`. This function
follows the [invocation function conventions][inv fr].
<code>evalInGlobal(<i>code</i>, [<i>options</i>])</code>
: If the referent is a global object, evaluate <i>code</i> in that global
environment, and return a [completion value][cv] describing how it completed.
<i>Code</i> is a string. All extant handler methods, breakpoints,
watchpoints, and so on remain active during the call. This function
follows the [invocation function conventions][inv fr].
If the referent is not a global object, throw a `TypeError` exception.
<i>Code</i> is interpreted as strict mode code when it contains a Use
Strict Directive.
If <i>code</i> is not strict mode code, then variable declarations in
<i>code</i> affect the referent global object. (In the terms used by the
ECMAScript specification, the `VariableEnvironment` of the execution
context for the eval code is the referent.)
The <i>options</i> argument is as for [`Debugger.Frame.prototype.eval`][fr eval].
<code>evalInGlobalWithBindings(<i>code</i>, <i>bindings</i>, [<i>options</i>])</code>
: Like `evalInGlobal`, but evaluate <i>code</i> using the referent as the
variable object, but with a lexical environment extended with bindings
from the object <i>bindings</i>. For each own enumerable property of
<i>bindings</i> named <i>name</i> whose value is <i>value</i>, include a
variable in the lexical environment in which <i>code</i> is evaluated
named <i>name</i>, whose value is <i>value</i>. Each <i>value</i> must
be a debuggee value. (This is not like a `with` statement: <i>code</i>
may access, assign to, and delete the introduced bindings without having
any effect on the <i>bindings</i> object.)
This method allows debugger code to introduce temporary bindings that
are visible to the given debuggee code and which refer to debugger-held
debuggee values, and do so without mutating any existing debuggee
environment.
Note that, like `evalInGlobal`, if the code passed to
`evalInGlobalWithBindings` is not strict mode code, then any
declarations it contains affect the referent global object, even as
<i>code</i> is evaluated in an environment extended according to
<i>bindings</i>. (In the terms used by the ECMAScript specification, the
`VariableEnvironment` of the execution context for non-strict eval code
is the referent, and the <i>bindings</i> appear in a new declarative
environment, which is the eval code's `LexicalEnvironment`.)
The <i>options</i> argument is as for [`Debugger.Frame.prototype.eval`][fr eval].
`asEnvironment()`
: If the referent is a global object, return the [`Debugger.Environment`][environment]
instance representing the referent as a variable environment for
evaluating code. If the referent is not a global object, throw a
`TypeError`.
<code>setObjectWatchpoint(<i>handler</i>)</code> <i>(future plan)</i>
: Set a watchpoint on all the referent's own properties, reporting events
by calling <i>handler</i>'s methods. Any previous watchpoint handler on
this `Debugger.Object` instance is replaced. If <i>handler</i> is null,
the referent is no longer watched. <i>Handler</i> may have the following
methods, called under the given circumstances:
<code>add(<i>frame</i>, <i>name</i>, <i>descriptor</i>)</code>
: A property named <i>name</i> has been added to the referent.
<i>Descriptor</i> is a property descriptor of the sort accepted by
`Debugger.Object.prototype.defineProperty`, giving the newly added
property's attributes.
<code>delete(<i>frame</i>, <i>name</i>)</code>
: The property named <i>name</i> is about to be deleted from the referent.
<code>change(<i>frame</i>, <i>name</i>, <i>oldDescriptor</i>, <i>newDescriptor</i>)</code>
: The existing property named <i>name</i> on the referent is being changed
from those given by <i>oldDescriptor</i> to those given by
<i>newDescriptor</i>. This handler method is only called when attributes
of the property other than its value are being changed; if only the
value is changing, SpiderMonkey calls the handler's `set` method.
<code>set(<i>frame</i>, <i>oldValue</i>, <i>newValue</i>)</code>
: The data property named <i>name</i> of the referent is about to have its
value changed from <i>oldValue</i> to <i>newValue</i>.
SpiderMonkey only calls this method on assignments to data properties
that will succeed; assignments to un-writable data properties fail
without notifying the debugger.
<code>extensionsPrevented(<i>frame</i>)</code>
: The referent has been made non-extensible, as if by a call to
`Object.preventExtensions`.
For all watchpoint handler methods:
* Handler calls receive the handler object itself as the `this` value.
* The <i>frame</i> argument is the current stack frame, whose code is
about to perform the operation on the object being reported.
* If the method returns `undefined`, then SpiderMonkey makes the announced
change to the object, and continues execution normally. If the method
returns an object:
* If the object has a `superseded` property whose value is a true value,
then SpiderMonkey does not make the announced change.
* If the object has a `resume` property, its value is taken as a
[resumption value][rv], indicating how
execution should proceed. (However, `return` resumption values are not
supported.)
* If a given method is absent from <i>handler</i>, then events of that
sort are ignored. The watchpoint consults <i>handler</i>'s properties
each time an event occurs, so adding methods to or removing methods from
<i>handler</i> after setting the watchpoint enables or disables
reporting of the corresponding events.
* Values passed to <i>handler</i>'s methods are debuggee values.
Descriptors passed to <i>handler</i>'s methods are ordinary objects in
the debugger's compartment, except for `value`, `get`, and `set`
properties in descriptors, which are debuggee values; they are the sort
of value expected by `Debugger.Object.prototype.defineProperty`.
* Watchpoint handler calls are cross-compartment, intra-thread calls: the
call takes place in the same thread that changed the property, and in
<i>handler</i>'s method's compartment (typically the same as the
debugger's compartment).
The new watchpoint belongs to the [`Debugger`][debugger-object] instance to which this
`Debugger.Object` instance belongs; disabling the [`Debugger`][debugger-object] instance
disables this watchpoint.
`clearObjectWatchpoint()` <i>(future plan)</i>
: Remove any object watchpoint set on the referent.
<code>setPropertyWatchpoint(<i>name</i>, <i>handler</i>)</code> <i>(future plan)</i>
: Set a watchpoint on the referent's property named <i>name</i>, reporting
events by calling <i>handler</i>'s methods. Any previous watchpoint
handler on this property for this `Debugger.Object` instance is
replaced. If <i>handler</i> is null, the property is no longer watched.
<i>Handler</i> is as described for
`Debugger.Object.prototype.setObjectWatchpoint`, except that it does not
receive `extensionsPrevented` events.
<code>clearPropertyWatchpoint(<i>name</i>)</code> <i>(future plan)</i>
: Remove any watchpoint set on the referent's property named <i>name</i>.
`unwrap()`
: If the referent is a wrapper that this `Debugger.Object`'s compartment
is permitted to unwrap, return a `Debugger.Object` instance referring to
the wrapped object. If we are not permitted to unwrap the referent,
return `null`. If the referent is not a wrapper, return this
`Debugger.Object` instance unchanged.
`unsafeDereference()`
: Return the referent of this `Debugger.Object` instance.
If the referent is an inner object (say, an HTML5 `Window` object),
return the corresponding outer object (say, the HTML5 `WindowProxy`
object). This makes `unsafeDereference` more useful in producing values
appropriate for direct use by debuggee code, without using [invocation functions][inv fr].
This method pierces the membrane of `Debugger.Object` instances meant to
protect debugger code from debuggee code, and allows debugger code to
access debuggee objects through the standard cross-compartment wrappers,
rather than via `Debugger.Object`'s reflection-oriented interfaces. This
method makes it easier to gradually adapt large code bases to this
Debugger API: adapted portions of the code can use `Debugger.Object`
instances, but use this method to pass direct object references to code
that has not yet been updated.

View File

@ -0,0 +1,238 @@
# Debugger.Script
A `Debugger.Script` instance refers to a sequence of bytecode in the
debuggee; it is the [`Debugger`][debugger-object] 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`][debugger-object] interface constructs `Debugger.Script` objects as scripts
of debuggee code are uncovered by the debugger: via the `onNewScript`
handler method; via [`Debugger.Frame`][frame]'s `script` properties; via the
`functionScript` method of [`Debugger.Object`][object] instances; and so on. For a
given [`Debugger`][debugger-object] 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`][debugger-object] instance is debugging the same code, each
[`Debugger`][debugger-object] gets a separate `Debugger.Script` instance for a given
script. This allows the code using each [`Debugger`][debugger-object] 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:
`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`][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`][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`][source] instance given by `source`.
`global`
: A [`Debugger.Object`][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.
`sourceMapURL`
: If this script was produced by a minimizer or translated from some other
language, and we know the URL of a <b>source map</b> document relating
the source positions in this script to the corresponding source
positions in the original source, then this property's value is that
URL. Otherwise, this is `null`.
(On the web, the translator may provide the source map URL in a
specially formatted comment in the JavaScript source code, or via a
header in the HTTP reply that carried the generated JavaScript.)
## 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.
<code>decompile([<i>pretty</i>])</code>
: Return a string containing JavaScript source code equivalent to this
script in its effect and result. If <i>pretty</i> is present and true,
produce indented code with line breaks.
(Note that [`Debugger.Object`][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
<code><i>f</i>.decompile()</code> than to write
<code><i>f</i>.getFunctionScript().decompile()</code>.)
`getAllOffsets()`
: Return an array <i>L</i> describing the relationship between bytecode
instruction offsets and source code positions in this script. <i>L</i>
is sparse, and indexed by source line number. If a source line number
<i>line</i> has no code, then <i>L</i> has no <i>line</i> property. If
there is code for <i>line</i>, then <code><i>L</i>[<i>line</i>]</code> 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.
<code>getLineOffsets(<i>line</i>)</code>
: Return an array of bytecode instruction offsets representing the entry
points to source line <i>line</i>. If the script contains no executable
code at that line, the array returned is empty.
<code>getOffsetLine(<i>offset</i>)</code>
: Return the source code line responsible for the bytecode at
<i>offset</i> 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.
<code>setBreakpoint(<i>offset</i>, <i>handler</i>)</code>
: Set a breakpoint at the bytecode instruction at <i>offset</i> in this
script, reporting hits to the `hit` method of <i>handler</i>. If
<i>offset</i> is not a valid offset in this script, throw an error.
When execution reaches the given instruction, SpiderMonkey calls the
`hit<code> method of <i>handler</i>, passing a [</code>Debugger.Frame`][frame] instance
representing the currently executing stack frame. The `hit` method's
return value should be a [resumption value][rv], 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 <i>handler</i> 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`][debugger-object] instance to which this
script belongs; disabling the [`Debugger`][debugger-object] instance disables this
breakpoint.
<code>getBreakpoints([<i>offset</i>])</code>
: Return an array containing the handler objects for all the breakpoints
set at <i>offset</i> in this script. If <i>offset</i> is omitted, return
the handlers of all breakpoints set anywhere in this script. If
<i>offset</i> is present, but not a valid offset in this script, throw
an error.
<code>clearBreakpoints(handler, [<i>offset</i>])</code>
: Remove all breakpoints set in this [`Debugger`][debugger-object] instance that use
<i>handler</i> as their handler. If <i>offset</i> is given, remove only
those breakpoints set at <i>offset</i> that use <i>handler</i>; if
<i>offset</i> 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 <i>handler</i>, they remain in place.
<code>clearAllBreakpoints([<i>offset</i>])</code>
: Remove all breakpoints set in this script. If <i>offset</i> is present,
remove all breakpoints set at that offset in this script; if
<i>offset</i> is not a valid bytecode offset in this script, throw an
error.

View File

@ -0,0 +1,212 @@
# Debugger.Source
A `Debugger.Source` instance represents a piece of JavaScript source
code: its properties provide the source code itself as a string, and
describe where it came from. Each [`Debugger.Script`][script] instance refers to
the `Debugger.Source` instance holding the source code from which it was
produced.
If a single piece of source code contains both top-level code and
function definitions, perhaps with nested functions, then the
[`Debugger.Script`][script] instances for those all refer to the same
`Debugger.Source` instance. Each script indicates the substring of the
overall source to which it corresponds.
A `Debugger.Source` instance may represent only a portion of a larger
source document. For example, an HTML document can contain JavaScript in
multiple `<script>` elements and event handler content attributes.
In this case, there may be either a single `Debugger.Source` instance
for the entire HTML document, with each [`Debugger.Script`][script] referring to
its substring of the document; or there may be a separate
`Debugger.Source` instance for each `<script>` element and
attribute. The choice is left up to the implementation.
If a given piece of source code is presented to the JavaScript
implementation more than once, with the same origin metadata, the
JavaScript implementation may generate a fresh `Debugger.Source`
instance to represent each presentation, or it may use a single
`Debugger.Source` instance to represent them all.
Each [`Debugger`][debugger-object] instance has a separate collection of `Debugger.Source`
instances representing the source code that has been presented to the
system.
A debugger may place its own properties on `Debugger.Source` instances,
to store metadata about particular pieces of source code.
## Accessor Properties of the Debugger.Source Prototype Object
A `Debugger.Source` instance inherits the following accessor properties
from its prototype:
`text`
: The JavaScript source code, as a string. The value satisfies the
`Program`, `FunctionDeclaration`, or `FunctionExpression` productions in
the ECMAScript standard.
`enclosingStart` <i>(future plan)</i>
: The position within the enclosing document at which this source's text
starts. This is a zero-based character offset. (The length of this
script within the enclosing document is `source.length`.)
`lineCount` <i>(future plan)</i>
: The number of lines in the source code. If there are characters after
the last newline in the source code, those count as a final line;
otherwise, `lineCount` is equal to the number of newlines in the source
code.
`url`
: The URL from which this source was loaded, if this source was loaded
from a URL. Otherwise, this is `undefined`. Source may be loaded from a
URL in the following ways:
* The URL may appear as the `src` attribute of a `<script>` element
in markup text.
* The URL may be passed to the `Worker` web worker constructor, or the web
worker `importScripts` function.
* The URL may be the name of a XPCOM JavaScript module or subscript.
(Note that code passed to `eval`, the `Function` constructor, or a
similar function is <i>not</i> considered to be loaded from a URL; the
`url` accessor on `Debugger.Source` instances for such sources should
return `undefined`.)
`element`
: The [`Debugger.Object`][object] instance referring to the DOM element to which
this source code belongs, if any, or `undefined` if it belongs to no DOM
element. Source belongs to a DOM element in the following cases:
* Source belongs to a `<script>` element if it is the element's text
content (that is, it is written out as the body of the `<script>`
element in the markup text), or is the source document referenced by its
`src` attribute.
* Source belongs to a DOM element if it is an event handler content
attribute (that is, if it is written out in the markup text as an
attribute value).
* Source belongs to a DOM element if it was assigned to one of the
element's event handler IDL attributes as a string. (Note that one may
assign both strings and functions to DOM elements' event handler IDL
attributes. If one assigns a function, that function's script's source
does <i>not</i> belong to the DOM element; the function's definition
must appear elsewhere.)
(If the sources attached to a DOM element change, the `Debugger.Source`
instances representing superceded code still refer to the DOM element;
this accessor only reflects origins, not current relationships.)
`elementAttributeName`
: If this source belongs to a DOM element because it is an event handler
content attribute or an event handler IDL attribute, this is the name of
that attribute, a string. Otherwise, this is `undefined`.
`introductionType`
: A string indicating how this source code was introduced into the system.
This accessor returns one of the following values:
* `"eval"`, for code passed to `eval`.
* `"Function"`, for code passed to the `Function` constructor.
* `"Worker"`, for code loaded by calling the Web worker constructor—the
worker's main script.
* `"importScripts"`, for code by calling `importScripts` in a web worker.
* `"eventHandler"`, for code assigned to DOM elements' event handler IDL
attributes as a string.
* `"scriptElement"`, for code belonging to `<script>` elements.
* `"javascriptURL"`, for code presented in `javascript:` URLs.
* `"setTimeout"`, for code passed to `setTimeout` as a string.
* `"setInterval"`, for code passed to `setInterval` as a string.
* `undefined`, if the implementation doesn't know how the code was
introduced.
`introductionScript`, `introductionScriptOffset` <i>(future plan)</i>
: If this source was introduced by calling a function from debuggee code,
then `introductionScript` is the [`Debugger.Script`][script] instance referring to
the script containing that call, and `introductionScriptOffset` is the
call's bytecode offset within that script. Otherwise, these are both
`undefined`. Taken together, these properties indicate the location of
the introducing call.
For the purposes of these accessors, assignments to accessor properties
are treated as function calls. Thus, setting a DOM element's event
handler IDL attribute by assigning to the corresponding JavaScript
property creates a source whose `introductionScript` and
`introductionScriptOffset` refer to the property assignment.
Since a `<script>` element parsed from a web page's original HTML
was not introduced by any scripted call, its source's
`introductionScript` and `introductionScriptOffset` accessors both
return `undefined`.
If a `<script>` element was dynamically inserted into a document,
then these accessors refer to the call that actually caused the script
to run—usually the call that made the element part of the document.
Thus, they do <i>not</i> refer to the call that created the element;
stored the source as the element's text child; made the element a child
of some uninserted parent node that was later inserted; or the like.
Although the main script of a worker thread is introduced by a call to
`Worker` or `SharedWorker`, these accessors always return `undefined` on
such script's sources. A worker's main script source and the call that
created the worker are always in separate threads, but [`Debugger`][debugger-object] is an
inherently single-threaded facility: its debuggees must all run in the
same thread. Since the global that created the worker is in a different
thread, it is guaranteed not to be a debuggee of the [`Debugger`][debugger-object] instance
that owns this source; and thus the creating call is never "in debuggee
code". Relating a worker to its creator, and other multi-threaded
debugging concerns, are out of scope for [`Debugger`][debugger-object].
## Function Properties of the Debugger.Source Prototype Object
<code>substring(<i>start</i>, [<i>end</i>])</code> <i>(future plan)</i>
: Return a substring of this instance's `source` property, starting at
<i>start</i> and extending to, but not including, <i>end</i>. If
<i>end</i> is `undefined`, the substring returned extends to the end of
the source.
Both indices are zero-based. If either is `NaN` or negative, it is
replaced with zero. If either is greater than the length of the source,
it is replaced with the length of the source. If <i>start</i> is larger
than <i>end</i>, they are swapped. (This is meant to be consistent with
the way `String.prototype.substring` interprets its arguments.)
<code>lineToPosition(<i>line</i>)</code> <i>(future plan)</i>
: Return an object of the form
<code>{ line:<i>line</i>, start:<i>start</i>, length:<i>length</i> }</code>, where
<i>start</i> is the character index within `source` of the first
character of line number <i>line</i>, and <i>length</i> is the length of
that line in characters, including the final newline, if any. The first
line is numbered one. If <i>line</i> is negative or greater than the
number of lines in this `Debugger.Source` instance, then return `null`.
<code>positionToLine(<i>start</i>)</code> <i>(future plan)</i>
: Return an object of the form
<code>{ line:<i>line</i>, start:<i>start</i>, length:<i>length</i> }</code>, where
<i>line</i> is the line number containing the character position
<i>start</i>, and <i>length</i> is the length of that line in
characters, including the final newline, if any. The first line is
numbered one. If <i>start</i> is negative or greater than the length of
the source code, then return `null`.
<code>findScripts(<i>query</i>)</code> <i>(future plan)</i>
: Return an array of [`Debugger.Script`][script] instances for all debuggee scripts
matching <i>query</i> that are produced from this `Debugger.Source`
instance. Aside from the restriction to scripts produced from this
source, <i>query</i> is interpreted as for
`Debugger.prototype.findScripts`.

View File

@ -0,0 +1,395 @@
# The Debugger Object
When called as a constructor, the `Debugger` object creates a new
`Debugger` instance.
<code>new Debugger([<i>global</i>, ...])</code>
: Create a debugger object, and apply its [`addDebuggee`][add] method to
each of the given <i>global</i> objects to add them as the initial
debuggees.
## Accessor Properties of the Debugger Prototype Object
A `Debugger` instance inherits the following accessor properties from
its prototype:
`enabled`
: A boolean value indicating whether this `Debugger` instance's handlers,
breakpoints, watchpoints, and the like are currently enabled. It is an
accessor property with a getter and setter: assigning to it enables or
disables this `Debugger` instance; reading it produces true if the
instance is enabled, or false otherwise. This property is initially
`true` in a freshly created `Debugger` instance.
This property gives debugger code a single point of control for
disentangling itself from the debuggee, regardless of what sort of
events or handlers or "points" we add to the interface.
`uncaughtExceptionHook`
: Either `null` or a function that SpiderMonkey calls when a call to a
debug event handler, breakpoint handler, watchpoint handler, or similar
function throws some exception, which we refer to as
<i>debugger-exception</i> here. Exceptions thrown in the debugger are
not propagated to debuggee code; instead, SpiderMonkey calls this
function, passing <i>debugger-exception</i> as its sole argument and
the `Debugger` instance as the `this` value. This function should
return a [resumption value][rv], which determines how the debuggee
should continue.
If the uncaught exception hook itself throws an exception,
<i>uncaught-hook-exception</i>, SpiderMonkey throws a new error object,
<i>confess-to-debuggee-exception</i>, to the debuggee whose message
blames the debugger, and includes textual descriptions of
<i>uncaught-hook-exception</i> and the original
<i>debugger-exception</i>.
If `uncaughtExceptionHook`'s value is `null`, SpiderMonkey throws an
exception to the debuggee whose message blames the debugger, and
includes a textual description of <i>debugger-exception</i>.
Assigning anything other than a callable value or `null` to this
property throws a `TypeError` exception.
(This is not an ideal way to handle debugger bugs, but the hope here is
that some sort of backstop, even if imperfect, will make life easier for
debugger developers. For example, an uncaught exception hook may have
access to browser-level features like the `alert` function, which this
API's implementation does not, making it possible to present debugger
errors to the developer in a way suited to the context.)
## Debugger Handler Functions
Each `Debugger` instance inherits accessor properties with which you can
store handler functions for SpiderMonkey to call when given events occur
in debuggee code.
When one of the events described below occurs in debuggee code, the engine
pauses the debuggee and calls the corresponding debugging handler on each
`Debugger` instance that is observing the debuggee. The handler functions
receive the `Debugger` instance as their `this` value. Most handler
functions can return a [resumption value][rv] indicating how the debuggee's
execution should proceed.
On a new `Debugger` instance, each of these properties is initially
`undefined`. Any value assigned to a debugging handler must be either a
function or `undefined`; otherwise a `TypeError` is thrown.
Handler functions run in the same thread in which the event occurred.
They run in the compartment to which they belong, not in a debuggee
compartment.
<code>onNewScript(<i>script</i>, <i>global</i>)</code>
: New code, represented by the [`Debugger.Script`][script] instance
<i>script</i>, has been loaded in the scope of the debuggee global
object <i>global</i>. <i>global</i> is a [`Debugger.Object`][object]
instance whose referent is the global object.
This method's return value is ignored.
<code>onDebuggerStatement(<i>frame</i>)</code>
: Debuggee code has executed a <i>debugger</i> statement in <i>frame</i>.
This method should return a [resumption value][rv] specifying how the
debuggee's execution should proceed.
<code>onEnterFrame(<i>frame</i>)</code>
: The stack frame <i>frame</i> is about to begin executing code.
(Naturally, <i>frame</i> is currently the youngest
[visible frame][vf].) This method should return
a [resumption value][rv] specifying how the debuggee's execution should
proceed.
SpiderMonkey only calls `onEnterFrame` to report
[visible][vf], non-`"debugger"` frames.
<code>onThrow(<i>frame</i>, <i>value</i>) <i>(future plan)</i></code>
: The exception <i>value</i> is being thrown by <i>frame</i>, which is
running debuggee code. This method should return a
[resumption value][rv] specifying how the debuggee's execution should
proceed. If it returns `undefined`, the exception is thrown as normal.
A call to the `onThrow` handler is typically followed by one or more
calls to the `onExceptionUnwind` handler.
*(pending discussion)* If the debuggee executes
`try { throw 0; } finally { f(); }` and `f()` executes without error,
the `onThrow` handler is called only once. The debugger is not notified
when the exception is set aside in order to execute the `finally` block,
nor when it is restored after the `finally` block completes normally.
*(An alternative design here would be: onException(status, frame, value)
where status is one of the strings "throw", "unwind", "catch",
"finally", "rethrow". JS\_SaveExceptionState would trigger a "finally"
event, JS\_RestoreExceptionState would trigger a "rethrow",
JS\_ClearPendingException would trigger a "catch"; not sure what
JS\_DropExceptionState or a return/throw from a finally block should
do.)*
<code>onExceptionUnwind(<i>frame</i>, <i>value</i>)</code>
: The exception <i>value</i> has been thrown, and has propagated to
<i>frame</i>; <i>frame</i> is the youngest remaining stack frame, and is a
debuggee frame. This method should return a [resumption value][rv]
specifying how the debuggee's execution should proceed. If it returns
`undefined`, the exception continues to propagate as normal: if control in
`frame` is in a `try` block, control jumps to the corresponding `catch` or
`finally` block; otherwise, <i>frame</i> is popped, and the exception
propagates to <i>frame</i>'s caller.
When an exception's propagation causes control to enter a `finally`
block, the exception is temporarily set aside. If the `finally` block
finishes normally, the exception resumes propagation, and the debugger's
`onExceptionUnwind` handler is called again, in the same frame. (The
other possibility is for the `finally` block to exit due to a `return`,
`continue`, or `break` statement, or a new exception. In those cases the
old exception does not continue to propagate; it is discarded.)
<code>sourceHandler(<i>ASuffusionOfYellow</i>)</code>
: This method is never called. If it is ever called, a contradiction has
been proven, and the debugger is free to assume that everything is true.
<code>onError(<i>frame</i>, <i>report</i>)</code>
: SpiderMonkey is about to report an error in <i>frame</i>. <i>Report</i>
is an object describing the error, with the following properties:
`message`
: The fully formatted error message.
`file`
: If present, the source file name, URL, etc. (If this property is
present, the <i>line</i> property will be too, and vice versa.)
`line`
: If present, the source line number at which the error occurred.
`lineText`
: If present, this is the source code of the offending line.
`offset`
: The index of the character within lineText at which the error occurred.
`warning`
: Present and true if this is a warning; absent otherwise.
`strict`
: Present and true if this error or warning is due to the strict option
(not to be confused with ES strict mode)
`exception`
: Present and true if an exception will be thrown; absent otherwise.
`arguments`
: An array of strings, representing the arguments substituted into the
error message.
This method's return value is ignored.
`onNewGlobalObject(global)`
: A new global object, <i>global</i>, has been created. The application
embedding the JavaScript implementation may provide details about what
kind of global it is via <code><i>global</i>.hostAnnotations</code>.
This handler method should return a [resumption value][rv] specifying how
the debuggee's execution should proceed. However, note that a <code>{ return:
<i>value</i> }</code> resumption value is treated like `undefined` ("continue
normally"); <i>value</i> is ignored. (Allowing the handler to substitute
its own value for the new global object doesn't seem useful.)
This handler method is only available to debuggers running in privileged
code ("chrome", in Firefox). Most functions provided by this `Debugger`
API observe activity in only those globals that are reachable by the
API's user, thus imposing capability-based restrictions on a
`Debugger`'s reach. However, the `onNewGlobalObject` method allows the
API user to monitor all global object creation that occurs anywhere
within the JavaScript system (the "JSRuntime", in SpiderMonkey terms),
thereby escaping the capability-based limits. For this reason,
`onNewGlobalObject` is only available to privileged code.
## Function Properties of the Debugger Prototype Object
The functions described below may only be called with a `this` value
referring to a `Debugger` instance; they may not be used as methods of
other kinds of objects.
<code id="addDebuggee">addDebuggee(<i>global</i>)</code>
: Add the global object designated by <i>global</i> to the set of global
objects this `Debugger` instance is debugging. If the designated global
is already a debuggee, this has no effect. Return this `Debugger`'s
[`Debugger.Object`][object] instance referring to the designated global.
The value <i>global</i> may be any of the following:
* A global object.
* An HTML5 `WindowProxy` object (an "outer window", in Firefox
terminology), which is treated as if the `Window` object of the
browsing context's active document (the "inner window") were passed.
* A cross-compartment wrapper of an object; we apply the prior rules to
the wrapped object.
* A [`Debugger.Object`][object] instance belonging to this `Debugger` instance;
we apply the prior rules to the referent.
* Any other sort of value is treated as a `TypeError`. (Note that each
rule is only applied once in the process of resolving a given
<i>global</i> argument. Thus, for example, a [`Debugger.Object`][object]
referring to a second [`Debugger.Object`][object] which refers to a global does
not designate that global for the purposes of this function.)
The global designated by <i>global</i> must be in a different
compartment than this `Debugger` instance itself. If adding the
designated global's compartment would create a cycle of debugger and
debuggee compartments, this method throws an error.
This method returns the [`Debugger.Object`][object] instance whose referent is
the designated global object.
The `Debugger` instance does not hold a strong reference to its
debuggee globals: if a debuggee global is not otherwise reachable, then
it is dropped from the `Debugger`'s set of debuggees. (Naturally, the
[`Debugger.Object`][object] instance this method returns does hold a strong
reference to the added global.)
<code>removeDebuggee(<i>global</i>)</code>
: Remove the global object designated by <i>global</i> from this
`Debugger` instance's set of debuggees. Return `undefined`.
This method interprets <i>global</i> using the same rules that
[`addDebuggee`][add] does.
<code>hasDebuggee(<i>global</i>)</code>
: Return `true` if the global object designated by <i>global</i> is a
debuggee of this `Debugger` instance.
This method interprets <i>global</i> using the same rules that
[`addDebuggee`][add] does.
`getDebuggees()`
: Return an array of distinct [`Debugger.Object`][object] instances whose referents
are all the global objects this `Debugger` instance is debugging.
Since `Debugger` instances don't hold strong references to their
debuggee globals, if a debuggee global is otherwise unreachable, it may
be dropped at any moment from the array this method returns.
`getNewestFrame()`
: Return a [`Debugger.Frame`][frame] instance referring to the youngest
[visible frame][vf] currently on the calling thread's stack, or `null`
if there are no visible frames on the stack.
<code>findSources([<i>query</i>]) <i>(not yet implemented)</i></code>
: Return an array of all [`Debugger.Source`][source] instances matching
<i>query</i>. Each source appears only once in the array. <i>Query</i>
is an object whose properties restrict which sources are returned; a
source must meet all the criteria given by <i>query</i> to be returned.
If <i>query</i> is omitted, we return all sources of all debuggee
scripts.
<i>Query</i> may have the following properties:
`url`
: The source's `url` property must be equal to this value.
`global`
: The source must have been evaluated in the scope of the given global
object. If this property's value is a [`Debugger.Object`][object] instance
belonging to this `Debugger` instance, then its referent is used. If the
object is not a global object, then the global in whose scope it was
allocated is used.
Note that the result may include sources that can no longer ever be
used by the debuggee: say, eval code that has finished running, or
source for unreachable functions. Whether such sources appear can be
affected by the garbage collector's behavior, so this function's result
is not entirely deterministic.
<code>findScripts([<i>query</i>])</code>
: Return an array of [`Debugger.Script`][script] instances for all debuggee scripts
matching <i>query</i>. Each instance appears only once in the array.
<i>Query</i> is an object whose properties restrict which scripts are
returned; a script must meet all the criteria given by <i>query</i> to
be returned. If <i>query</i> is omitted, we return the [`Debugger.Script`][script]
instances for all debuggee scripts.
<i>Query</i> may have the following properties:
`url`
: The script's `url` property must be equal to this value.
`source` <i>(not yet implemented)</i>
: The script's `source` property must be equal to this value.
`line`
: The script must at least partially cover the given source line. If this
property is present, the `url` property must be present as well.
`column`
: The script must include given column on the line given by the `line`
property. If this property is present, the `url` and `line` properties
must both be present as well.
`innermost`
: If this property is present and true, the script must be the innermost
script covering the given source location; scripts of enclosing code are
omitted.
`global`
: The script must be in the scope of the given global object. If this
property's value is a [`Debugger.Object`][object] instance belonging to this
`Debugger` instance, then its referent is used. If the object is not a
global object, then the global in whose scope it was allocated is used.
All properties of <i>query</i> are optional. Passing an empty object
returns all debuggee code scripts.
Note that the result may include [`Debugger.Script`][script] instances for
scripts that can no longer ever be used by the debuggee, say, those for
eval code that has finished running, or unreachable functions. Whether
such scripts appear can be affected by the garbage collector's
behavior, so this function's behavior is not entirely deterministic.
<code>clearBreakpoint(<i>handler</i>)</code>
: Remove all breakpoints set in this `Debugger` instance that use
<i>handler</i> as their handler. Note that, if breakpoints using other
handler objects are set at the same location(s) as <i>handler</i>, they
remain in place.
`clearAllBreakpoints()`
: Remove all breakpoints set using this `Debugger` instance.
`clearAllWatchpoints()` <i>(future plan)</i>
: Clear all watchpoints owned by this `Debugger` instance.
`findAllGlobals()`
: Return an array of [`Debugger.Object`][object] instances referring to all the
global objects present in this JavaScript instance. The application may
provide details about what kind of globals they are via the
[`Debugger.Object`][object] instances' `hostAnnotations` accessors.
The results of this call can be affected in non-deterministic ways by
the details of the JavaScript implementation. The array may include
[`Debugger.Object`][object] instances referring to global objects that are not
actually reachable by the debuggee or any other code in the system.
(Naturally, once the function has returned, the array's
[`Debugger.Object`][object] instances strongly reference the globals they refer
to.)
This handler method is only available to debuggers running in privileged
code ("chrome", in Firefox). Most functions provided by this `Debugger`
API observe activity in only those globals that are reachable by the
API's user, thus imposing capability-based restrictions on a
`Debugger`'s reach. However, `findAllGlobals` allows the API user to
find all global objects anywhere within the JavaScript system (the
"JSRuntime", in SpiderMonkey terms), thereby escaping the
capability-based limits. For this reason, `findAllGlobals` is only
available to privileged code.
<code>makeGlobalObjectReference(<i>global</i>)</code>
: Return the [`Debugger.Object`][object] whose referent is the global object
designated by <i>global</i>, without adding the designated global as a
debuggee. If <i>global</i> does not designate a global object, throw a
`TypeError`. Determine which global is designated by <i>global</i>
using the same rules as [`Debugger.prototype.addDebuggee`][add].

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -0,0 +1,997 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="650"
height="400"
id="svg10302"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="shadows.svg"
viewBox="0 0 650 400">
<defs
id="defs10304">
<marker
inkscape:stockid="DotS"
orient="auto"
refY="0"
refX="0"
id="DotS"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3941"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.2,0,0,0.2,1.48,0.2)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3888"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<marker
inkscape:stockid="DotS"
orient="auto"
refY="0"
refX="0"
id="DotS-0"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3941-3"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.2,0,0,0.2,1.48,0.2)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-4"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3888-2"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<marker
inkscape:stockid="DotS"
orient="auto"
refY="0"
refX="0"
id="DotS-6"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3941-6"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.2,0,0,0.2,1.48,0.2)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-7"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3888-3"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<marker
inkscape:stockid="DotS"
orient="auto"
refY="0"
refX="0"
id="DotS-1"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3941-63"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.2,0,0,0.2,1.48,0.2)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3888-6"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<marker
inkscape:stockid="DotS"
orient="auto"
refY="0"
refX="0"
id="DotS-1-7"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3941-63-9"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.2,0,0,0.2,1.48,0.2)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-4"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3888-6-4"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<marker
inkscape:stockid="DotS"
orient="auto"
refY="0"
refX="0"
id="DotS-4"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3941-4"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.2,0,0,0.2,1.48,0.2)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-79"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3888-8"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<marker
inkscape:stockid="DotS"
orient="auto"
refY="0"
refX="0"
id="DotS-11"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3941-9"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.2,0,0,0.2,1.48,0.2)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-0"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3888-0"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<marker
inkscape:stockid="DotS"
orient="auto"
refY="0"
refX="0"
id="DotS-2"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3941-96"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.2,0,0,0.2,1.48,0.2)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-2"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3888-4"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<marker
inkscape:stockid="DotS"
orient="auto"
refY="0"
refX="0"
id="DotS-1-72"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3941-63-1"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.2,0,0,0.2,1.48,0.2)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-8"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3888-6-8"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<marker
inkscape:stockid="DotS"
orient="auto"
refY="0"
refX="0"
id="DotS-67"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3941-5"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.2,0,0,0.2,1.48,0.2)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-78"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3888-89"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<marker
inkscape:stockid="DotS"
orient="auto"
refY="0"
refX="0"
id="DotS-1-6"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3941-63-5"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.2,0,0,0.2,1.48,0.2)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-3"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3888-6-5"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
<marker
inkscape:stockid="DotS"
orient="auto"
refY="0"
refX="0"
id="DotS-1-8"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3941-63-18"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.2,0,0,0.2,1.48,0.2)" />
</marker>
<marker
inkscape:stockid="Arrow1Send"
orient="auto"
refY="0"
refX="0"
id="Arrow1Send-8-35"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3888-6-2"
d="M 0,0 5,-5 -12.5,0 5,5 0,0 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
transform="matrix(-0.2,0,0,-0.2,-1.2,0)" />
</marker>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.6369231"
inkscape:cx="338.70355"
inkscape:cy="200"
inkscape:document-units="px"
inkscape:current-layer="alertLater"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="1021"
inkscape:window-x="0"
inkscape:window-y="867"
inkscape:window-maximized="1" />
<metadata
id="metadata10307">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:groupmode="layer"
id="debuggeeset"
inkscape:label="debuggeeset"
style="display:inline"
class="flip">
<rect
style="fill:#c8c0c0;fill-opacity:1;stroke:#000000;stroke-width:2.18226266;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:4.36452564, 4.36452564;stroke-dashoffset:0;display:inline"
id="rect3755-3-0-6-1-8-6"
width="171.31711"
height="150.68491"
x="0.10979491"
y="248.55035"
ry="4.814189"
rx="4.0350175" />
<text
xml:space="preserve"
style="font-size:14.11999989px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="9.8749857"
y="268.84415"
id="text22690"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan22692"
x="9.8749857"
y="268.84415">Debugger</tspan></text>
</g>
<g
inkscape:groupmode="layer"
id="shadows"
inkscape:label="shadows"
style="display:inline"
class="flip">
<rect
style="fill:#969696;fill-opacity:1;stroke:none;display:inline"
id="rect3755-5-68"
width="119.42149"
height="42.397526"
x="25.236485"
y="160.0201"
ry="11.065418"
rx="11.065418" />
<rect
style="fill:#969696;fill-opacity:1;stroke:none;display:inline"
id="rect3755-3-0-6-1-8"
width="177.65483"
height="46.614746"
x="209.36084"
y="336.41965"
ry="4.0393105"
rx="4.0393105" />
<rect
style="fill:#969696;fill-opacity:1;stroke:none;display:inline"
id="rect3755-3-0-6-1-3-43"
width="149.12187"
height="46.614746"
x="237.8938"
y="287.1636"
ry="4.0393105"
rx="4.0393105" />
<rect
style="fill:#969696;fill-opacity:1;stroke:none;display:inline"
id="rect3755-5-6-1"
width="119.42149"
height="42.397526"
x="192.17702"
y="161.09923"
ry="11.065418"
rx="11.065418" />
<rect
style="fill:#969696;fill-opacity:1;stroke:none;display:inline"
id="rect3755-5-2-4"
width="136.4054"
height="46.614731"
x="26.006214"
y="336.41965"
ry="11.065418"
rx="11.065418" />
<rect
style="fill:#969696;fill-opacity:1;stroke:none;display:inline"
id="rect3755-1-5-9"
width="242.77243"
height="75.739441"
x="183.31783"
y="47.05508"
ry="6.1249413"
rx="6.1249394" />
<rect
style="fill:#969696;fill-opacity:1;stroke:#ffffff;stroke-width:2.92859435;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
id="rect3755-1-5-1-7-2"
width="186.27605"
height="18.674528"
x="285.59784"
y="66.98394"
ry="6.1249413"
rx="6.1249399" />
<rect
style="fill:#969696;fill-opacity:1;stroke:none;display:inline"
id="rect3755-3-0-6-1-1-0"
width="194.03011"
height="46.614746"
x="413.20236"
y="336.41989"
ry="4.0393105"
rx="4.0393105" />
<rect
style="fill:#969696;fill-opacity:1;stroke:none;display:inline"
id="rect3755-3-0-6-1-3-4-6"
width="90.035484"
height="46.614746"
x="296.98013"
y="237.91023"
ry="4.0393105"
rx="4.0393105" />
<text
xml:space="preserve"
style="font-size:12.93533993px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="33.257587"
y="378.20139"
id="text4037"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4039"
x="33.257587"
y="378.20139">Debugger.Object</tspan></text>
<text
xml:space="preserve"
style="font-size:12.93533993px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="218.72287"
y="377.52206"
id="text4041"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4043"
x="218.72287"
y="377.52206">Debugger.Environment</tspan></text>
<text
xml:space="preserve"
style="font-size:12.93533993px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="421.84915"
y="377.52206"
id="text4045"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4047"
x="421.84915"
y="377.52206">Debugger.Frame</tspan></text>
<text
xml:space="preserve"
style="font-size:12.93533993px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="29.181461"
y="196.81334"
id="text4049"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4051"
x="29.181461"
y="196.81334">Debugger.Object</tspan></text>
<text
xml:space="preserve"
style="font-size:12.93533993px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="199.2216"
y="197.89247"
id="text4053"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4055"
x="199.2216"
y="197.89247">Debugger.Object</tspan></text>
<text
xml:space="preserve"
style="font-size:12.93533993px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="190.1888"
y="118.00808"
id="text4057"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan4059"
x="190.1888"
y="118.00808">Debugger.Script</tspan></text>
<rect
style="fill:#969696;fill-opacity:1;stroke:none;display:inline"
id="rect3755-3-0-6-1-1-5-8"
width="194.03011"
height="46.614746"
x="413.20236"
y="287.1636"
ry="4.0393105"
rx="4.0393105" />
</g>
<g
inkscape:groupmode="layer"
id="global"
inkscape:label="global"
transform="translate(0,-344.09448)"
class="flip"
style="display:inline">
<rect
style="fill:#ffd257;fill-opacity:1;stroke:none;display:inline"
id="rect3755-3-0-6-1"
width="177.9265"
height="46.614887"
x="201.82011"
y="664.15881"
ry="4.0393105"
rx="4.0393105"
class="nonvalue" />
<text
xml:space="preserve"
style="font-size:14.12208748px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
x="210.6344"
y="691.88666"
id="text10970"
sodipodi:linespacing="125%"
transform="scale(1.0007628,0.99923778)"><tspan
sodipodi:role="line"
id="tspan10972"
x="210.6344"
y="691.88666">global environment</tspan></text>
<rect
style="fill:#83d4ff;fill-opacity:1;stroke:none"
id="rect3755-5-2"
width="136.61398"
height="46.614872"
x="18.810663"
y="664.15881"
ry="11.065418"
rx="11.065418" />
<path
style="fill:none;stroke:#000000;stroke-width:2.99999976;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#DotS-1);marker-end:url(#Arrow1Send-8)"
d="m 204.0527,687.46628 -46.26685,0"
id="path11163-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-size:14.12208748px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
x="3.020442"
y="659.44391"
id="text15699"
sodipodi:linespacing="125%"
transform="scale(1.0007628,0.99923778)"><tspan
sodipodi:role="line"
id="tspan15701"
x="3.020442"
y="659.44391">global object:</tspan></text>
<text
xml:space="preserve"
style="font-size:14.12208748px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
x="87.051254"
y="698.41443"
id="text15703"
sodipodi:linespacing="125%"
transform="scale(1.0007628,0.99923778)"><tspan
sodipodi:role="line"
x="87.051254"
y="698.41443"
id="tspan15707">Date; Math; ...</tspan></text>
</g>
<g
inkscape:groupmode="layer"
id="scripts"
inkscape:label="scripts"
style="display:inline"
class="flip">
<rect
transform="translate(0,-652.36218)"
style="fill:#83ff9a;fill-opacity:1;stroke:none;display:inline"
id="rect3755-1-5"
width="243.14369"
height="75.73967"
x="176.36284"
y="683.0611"
ry="6.1249409"
rx="6.1249394"
class="nonvalue" />
<rect
transform="translate(0,-652.36218)"
style="fill:#83ff9a;fill-opacity:1;stroke:#e6e4dd;stroke-width:2.92859435000000001;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
id="rect3755-1-5-1-7"
width="186.56091"
height="18.674585"
x="278.79929"
y="702.98999"
ry="6.1249409"
rx="6.1249399"
class="nonvalue" />
</g>
<g
inkscape:groupmode="layer"
id="code"
inkscape:label="code"
class="flip"
style="display:inline">
<text
xml:space="preserve"
style="font-size:14.12208748px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="182.99957"
y="699.52692"
id="text10314"
sodipodi:linespacing="125%"
transform="matrix(1.0007628,0,0,0.99923777,0,-652.36218)"><tspan
sodipodi:role="line"
x="182.99957"
y="699.52692"
id="tspan4518">function alertLater(msg, delay) {</tspan><tspan
sodipodi:role="line"
x="182.99957"
y="717.1795"
id="tspan4527"> setTimeout( function () { alert(msg); },</tspan><tspan
sodipodi:role="line"
x="182.99957"
y="734.83215"
id="tspan4529"> delay);</tspan><tspan
sodipodi:role="line"
x="182.99957"
y="752.48474"
id="tspan4531">}</tspan></text>
</g>
<g
inkscape:groupmode="layer"
id="alertLater"
inkscape:label="alertLater"
style="display:inline"
class="flip">
<rect
transform="translate(0,-652.36218)"
style="fill:#83d4ff;fill-opacity:1;stroke:none;display:inline"
id="rect3755-5"
width="119.60412"
height="42.397655"
x="18.039759"
y="796.02643"
ry="11.065418"
rx="11.065418" />
<text
xml:space="preserve"
style="font-size:13.91893291px;font-style:normal;font-weight:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="98.427589"
y="811.1579"
id="text3761-6"
sodipodi:linespacing="125%"
transform="matrix(1.0007628,0,0,0.99923778,0,-652.36218)"><tspan
sodipodi:role="line"
id="tspan3763-0"
x="98.427589"
y="811.1579">[[Code]]:</tspan></text>
<text
xml:space="preserve"
style="font-size:13.91893291px;font-style:normal;font-weight:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="98.427589"
y="831.64917"
id="text3765-0"
sodipodi:linespacing="125%"
transform="matrix(1.0007628,0,0,0.99923778,0,-652.36218)"><tspan
sodipodi:role="line"
id="tspan3767-2"
x="98.427589"
y="831.64917">[[Scope]]:</tspan></text>
<path
transform="translate(0,-652.36218)"
style="fill:none;stroke:#e6e4dd;stroke-width:2.95684338000000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
d="m 18.039736,817.89404 119.601824,0"
id="path3773-4-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-size:14.12208748px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="2.4066608"
y="791.50812"
id="text10404"
sodipodi:linespacing="125%"
transform="matrix(1.0007628,0,0,0.99923778,0,-652.36218)"><tspan
sodipodi:role="line"
id="tspan10406"
x="2.4066608"
y="791.50812">alertLater:</tspan></text>
<path
transform="translate(0,-652.36218)"
style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#DotS);marker-end:url(#Arrow1Send);display:inline"
d="m 113.60688,806.63271 c 0,-45.02374 23.466,-83.54273 59.2075,-83.54273"
id="path3868-4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
transform="translate(0,-652.36218)"
style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#DotS);marker-end:url(#Arrow1Send);display:inline"
d="m 113.60688,827.22105 c 51.73315,0 90.50566,99.84829 90.50566,141.32477"
id="path3868-4-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
xml:space="preserve"
style="font-size:14.12208748px;font-style:normal;font-weight:normal;text-align:center;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="87.051254"
y="991.61841"
id="text15703-4"
sodipodi:linespacing="125%"
transform="matrix(1.0007628,0,0,0.99923778,0,-652.36218)"><tspan
sodipodi:role="line"
x="89.299202"
y="991.61841"
id="tspan15707-0">alertLater; </tspan></text>
</g>
<g
inkscape:groupmode="layer"
id="call1env"
inkscape:label="call1env"
style="display:inline"
class="flip">
<rect
style="fill:#ffd257;fill-opacity:1;stroke:none;display:inline"
id="rect3755-3-0-6-1-3"
width="149.34991"
height="46.614887"
x="229.7888"
y="270.80811"
ry="4.0393105"
rx="4.0393105"
class="nonvalue" />
<g
style="display:inline"
id="g3550"
transform="matrix(0.58886915,0,0,0.58797179,4.5262952,-176.54364)">
<text
transform="scale(1.0009935,0.9990075)"
sodipodi:linespacing="125%"
id="text13153"
y="795.71594"
x="499.133"
style="font-size:22px;font-style:normal;font-weight:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
xml:space="preserve"><tspan
y="795.71594"
x="499.133"
id="tspan13155"
sodipodi:role="line">msg:</tspan><tspan
y="823.21594"
x="499.133"
sodipodi:role="line"
id="tspan3538">delay:</tspan></text>
<text
sodipodi:linespacing="125%"
id="text3540"
y="794.92615"
x="507"
style="font-size:22px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
xml:space="preserve"><tspan
y="794.92615"
x="507"
id="tspan3542"
sodipodi:role="line">'xlerb'</tspan><tspan
id="tspan3544"
y="822.42615"
x="507"
sodipodi:role="line">1000</tspan></text>
</g>
</g>
<g
inkscape:groupmode="layer"
id="anon"
inkscape:label="anon"
style="display:inline"
class="flip">
<rect
style="fill:#83d4ff;fill-opacity:1;stroke:none;display:inline"
id="rect3755-5-6"
width="119.60412"
height="42.397655"
x="185.84294"
y="143.66425"
ry="11.065418"
rx="11.065418" />
<text
xml:space="preserve"
style="font-size:13.91893291px;font-style:normal;font-weight:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="266.10284"
y="158.2981"
id="text3761-6-0"
sodipodi:linespacing="125%"
transform="scale(1.0007628,0.99923778)"><tspan
sodipodi:role="line"
id="tspan3763-0-7"
x="266.10284"
y="158.2981">[[Code]]:</tspan></text>
<text
xml:space="preserve"
style="font-size:13.91893291px;font-style:normal;font-weight:normal;text-align:end;line-height:125%;letter-spacing:0px;word-spacing:0px;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="266.10284"
y="178.78937"
id="text3765-0-7"
sodipodi:linespacing="125%"
transform="scale(1.0007628,0.99923778)"><tspan
sodipodi:role="line"
id="tspan3767-2-6"
x="266.10284"
y="178.78937">[[Scope]]:</tspan></text>
<path
style="fill:none;stroke:#e6e4dd;stroke-width:2.95684338000000002;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
d="m 185.84293,165.53187 119.60182,0"
id="path3773-4-3-4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#DotS);marker-end:url(#Arrow1Send);display:inline"
d="m 285.44496,176.59077 c 0,31.25836 -38.08897,59.76616 -38.08897,91.05227"
id="path3868-4-0-4-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#DotS);marker-end:url(#Arrow1Send);display:inline"
d="m 285.95088,154.47813 c 165.68371,0 170.77148,-32.93057 158.20494,-82.18402"
id="path3868-4-4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
<g
inkscape:groupmode="layer"
id="fire"
inkscape:label="fire"
style="display:inline"
class="flip">
<rect
style="fill:#ff9457;fill-opacity:1;stroke:none;display:inline"
id="rect3755-3-0-6-1-1-4"
width="194.03011"
height="46.614746"
x="406.38477"
y="320.06448"
ry="4.0393105"
rx="4.0393105"
class="nonvalue" />
<text
xml:space="preserve"
style="font-size:12.93533993px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="434.10962"
y="346.93411"
id="text10970-7-4"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="434.10962"
y="346.93411"
id="tspan3534-4"><tspan
style="font-style:italic;-inkscape-font-specification:Sans Italic"
id="tspan5754">anonymous</tspan>()</tspan></text>
<rect
style="fill:#ffd257;fill-opacity:1;stroke:none;display:inline"
id="rect3755-3-0-6-1-3-4"
width="90.035484"
height="46.614746"
x="289.10324"
y="221.55482"
ry="4.0393105"
rx="4.0393105"
class="nonvalue" />
<text
xml:space="preserve"
style="font-size:12.93533993px;font-style:italic;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans;-inkscape-font-specification:Sans Italic"
x="312.99686"
y="248.05814"
id="text5774"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan5776"
x="312.99686"
y="248.05814">empty</tspan></text>
<path
style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#DotS-1);marker-end:url(#Arrow1Send-8);display:inline"
d="m 415.85979,342.35006 c -51.09645,0 11.10573,-95.59507 -39.0289,-95.59507"
id="path11163-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#DotS-1);marker-end:url(#Arrow1Send-8);display:inline"
d="m 588.68444,343.33325 c 66.19678,0 27.60009,-283.14206 -117.22439,-283.14206"
id="path11163-1-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
</g>
<g
inkscape:groupmode="layer"
id="call2"
inkscape:label="call2"
class="flip"
style="display:inline">
<rect
style="fill:#ff9457;fill-opacity:1;stroke:none;display:inline"
id="rect3755-3-0-6-1-1-5-4"
width="194.03011"
height="46.614746"
x="406.38477"
y="270.80817"
ry="4.0393105"
rx="4.0393105"
class="nonvalue" />
<text
xml:space="preserve"
style="font-size:12.93533993px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="433.86328"
y="298.87103"
id="text6389"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan6391"
x="433.86328"
y="298.87103">alert('xlerb')</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 35 KiB