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