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.