Debugger.Frame

一个 Debugger.Frame 实例表示一个 可见的栈帧。给定一个 Debugger.Frame 实例,您可以找到该帧正在执行的脚本,遍历栈到较旧的帧,找到执行所在的词法环境,等等。

对于给定的 Debugger 实例,SpiderMonkey 仅为给定的可见帧创建一个 Debugger.Frame 实例。在调试对象在给定帧中运行期间调用的每个处理程序方法都使用相同的帧对象。类似地,遍历栈回到之前访问的帧会产生与之前相同的帧对象。Debugger 代码可以向帧对象添加自己的属性并期望稍后找到它们,使用 == 来确定两个表达式是否引用同一个帧,等等。

(如果多个 Debugger 实例正在调试相同的代码,则每个 Debugger 为给定的帧获得一个单独的 Debugger.Frame 实例。这允许使用每个 Debugger 实例的代码在其 Debugger.Frame 实例上放置任何它喜欢的属性,而无需担心干扰其他调试器。)

当调试对象弹出栈帧(例如,因为函数调用已返回或从中抛出异常)时,引用该帧的 Debugger.Frame 实例变为非活动状态:其 live 属性变为 false,并且访问其其他属性或调用其方法会抛出异常。请注意,帧仅在对调试器可预测的时间点变为非活动状态:当调试对象运行时,或者当调试器本身从栈中移除帧时。

可见帧

在检查调用栈时,Debugger 不会显示实际上存在于栈上的所有帧:虽然它确实显示了所有运行调试对象代码的帧,但它会省略运行调试器自身代码的帧,并省略大多数运行非调试对象代码的帧。我们将 Debugger 显示的这些栈帧称为可见帧

如果满足以下任何条件,则该帧为可见帧

  • 它正在运行调试对象代码;

  • 其直接调用者是运行调试对象代码的帧;或

  • 它是一个 “调试器”,表示由调试器调用的调试对象代码的延续。

“直接调用者”规则意味着,当调试对象代码调用非调试对象函数时,它看起来像对原语的调用:您会看到一个对调试对象可访问的非调试对象函数的帧,但该函数进行的任何进一步调用都被视为内部细节,并从栈跟踪中省略。如果非调试对象函数最终回调到调试对象代码,则这些帧是可见的。

(请注意,调试对象不被认为是其触发的处理程序方法的“直接调用者”。即使调试对象和调试器共享相同的 JavaScript 栈,为 SpiderMonkey 调用处理程序方法以报告调试对象中的事件而推送的帧永远不被视为可见帧。)

调用函数和 Debugger 帧

调用函数是指此接口中任何允许调试器在调试对象中调用代码的函数:Debugger.Object.prototype.callDebugger.Frame.prototype.eval,等等。

虽然调用函数在要运行的代码和如何向其传递值方面有所不同,但它们都遵循以下一般过程

  1. older 为栈上最年轻的可见帧,如果不存在此类帧,则为null。(这永远不是调试器自己的帧之一;这些帧永远不会作为 Debugger.Frame 实例出现。)

  2. 在栈上推送一个 "debugger" 帧,并以older 作为其 older 属性。

  3. 根据给定调用函数的需要,以 "debugger" 帧作为其延续来调用调试对象代码。例如,Debugger.Frame.prototype.eval 为其运行的代码推送一个 "eval" 帧,而 Debugger.Object.prototype.call 推送一个 "call" 帧。

  4. 当调试对象代码完成时,无论是通过返回、抛出异常还是被终止,都弹出 "debugger" 帧,并将适当的完成值从调用函数返回到调试器。

当调试器调用调用函数以运行调试对象代码时,该代码的延续是调试器,而不是下一个调试对象代码帧。推送 "debugger" 帧使此延续变得明确,并使其更容易找到为调用创建的栈的范围。

Debugger.Frame 原型对象的访问器属性

一个 Debugger.Frame 实例从其原型继承以下访问器属性

type

描述此帧类型的字符串

  • "call":运行函数调用的帧。(我们可能无法获得对主机函数调用的帧。)

  • "eval":运行传递给 eval 的代码的帧。

  • "global":运行全局代码(既不是上述两种的 JavaScript)的帧。

  • "module":在模块的顶层运行代码的帧。

  • "wasmcall":运行 WebAssembly 函数调用的帧。

  • "debugger":由调试器调用的用户代码调用的帧(请参见下面的 eval 方法)。

implementation

描述此帧在哪个 JavaScript 引擎层中执行的字符串

  • "interpreter":在解释器中运行的帧。

  • "baseline":在未优化的基线 JIT 中运行的帧。

  • "ion":在优化 JIT 中运行的帧。

  • "wasm":在 WebAssembly 基线 JIT 中运行的帧。

this

此帧的 this 值(调试对象值)。对于 wasmcall 帧,此属性会抛出 TypeError

older

下一个较旧的可见帧,在此帧完成时控制权将恢复到该帧。如果不存在较旧的帧,则为 null

depth

此帧的深度,从最旧到最年轻计数;最旧的帧深度为零。

live

如果此 Debugger.Frame 实例引用的帧仍在栈上,则为 True;如果它已完成执行或以其他方式弹出,则为 False。

script

在此帧中执行的脚本(Debugger.Script 实例),或在不表示对调试对象代码调用的帧上为 null。在 callee 属性不为 null 的帧上,这等于 callee.script

offset

当前在 script 中执行的字节码指令的偏移量,或者如果帧的 script 属性为 null,则为 undefined。对于 wasmcall 帧,此属性会抛出 TypeError

environment

正在进行评估的词法环境(Debugger.Environment 实例),或在不表示调试对象代码评估的帧上为 null,例如对非调试对象函数、主机函数或 "debugger" 帧的调用。

callee

创建此帧的函数的应用,作为调试对象值,或者如果这不是 "call" 帧,则为 null

generator

如果此帧是生成器帧,则为 True,否则为 False。

constructing

如果此帧用于作为构造函数调用的函数,则为 True,否则为 False。

arguments

传递给当前帧的参数,或者如果这不是 "call" 帧,则为 null。当不为 null 时,这是一个对象,在与调试器相同的全局中分配,在原型链上具有 Array.prototype,一个不可写的 length 属性,以及名称为数组索引的属性。每个属性都是一个只读访问器属性,其 getter 返回相应参数的当前值。当引用帧弹出时,参数值的属性的 getter 会抛出错误。

Debugger.Frame 实例的处理程序方法

每个 Debugger.Frame 实例都继承了持有处理程序函数的访问器属性,供 SpiderMonkey 在发生给定事件时调用。

对帧的处理程序方法的调用是跨区段、线程内调用:调用发生在帧所属的线程中,并在处理程序方法所属的区段中运行。

Debugger.Frame 实例继承以下处理程序方法属性

onStep

此属性必须是 undefined 或一个函数。如果它是一个函数,则 SpiderMonkey 在此帧中的执行取得少量进展时调用它,不传递任何参数,并提供此 Debugger.Frame 实例作为 this 值。该函数应返回一个恢复值,指定调试目标的执行应如何继续。

“少量进展”的具体含义取决于实现,但它足够细粒度,可以实现有用的“单步执行”和“下一步”行为。

如果多个 Debugger 实例都为给定栈帧具有 Debugger.Frame 实例,且都设置了 onStep 处理程序,则它们的处理程序将按未指定的顺序运行。如果任何 onStep 处理程序强制帧提前返回(通过返回除 undefined 之外的恢复值),则任何剩余的调试器的 onStep 处理程序都不会运行。

此属性在未执行调试目标代码的帧上被忽略,例如主机函数调用的 "call" 帧和 "debugger" 帧。

onPop

此属性必须是 undefined 或一个函数。如果它是一个函数,则 SpiderMonkey 在此帧弹出之前调用它,传递一个完成值,指示此帧的执行如何完成,并提供此 Debugger.Frame 实例作为 this 值。该函数应返回一个恢复值,指示执行应如何继续。在新创建的帧上,此属性的值为 undefined

当调用此处理程序时,此帧的当前执行位置(反映在其 offsetenvironment 属性中)是导致其展开的操作。在返回或抛出异常的帧中,该位置通常是 return 或 throw 语句。在传播异常的帧中,该位置是调用。

onPop 调用报告构造调用(即通过 new 运算符调用的函数)的完成时,传递给处理程序的完成值描述了函数体返回的值。如果此值不是对象,则它可能与 new 表达式生成的值不同,后者将是帧的 this 属性的值。(在 ECMAScript 术语中,onPop 处理程序接收 [[Call]] 方法返回的值,而不是 [[Construct]] 方法返回的值。)

当调试器处理程序函数通过返回 { return:... }{ throw:... }null 恢复值强制帧提前完成时,SpiderMonkey 会调用帧的 onPop 处理程序(如果有)。在这种情况下传递的完成值反映导致帧完成的恢复值。

当 SpiderMonkey 为正在抛出异常或被终止的帧调用 onPop 处理程序,并且处理程序返回 undefined 时,则 SpiderMonkey 将继续执行异常或终止。也就是说,undefined 恢复值不会干扰帧的抛出和终止过程。

如果多个 Debugger 实例都为给定栈帧具有 Debugger.Frame 实例,且都设置了 onPop 处理程序,则它们的处理程序将按未指定的顺序运行。每个处理程序返回的恢复值都将建立报告给下一个处理程序的完成值。

此处理程序不会在 "debugger" 帧上调用。当由于过度递归或内存不足异常而展开帧时,也不会调用它。

Debugger.Frame 原型对象的函数属性

下面描述的函数只能使用引用 Debugger.Frame 实例的 this 值来调用;它们不能用作其他类型对象的 方法。

eval(code, [options])

在此帧的执行上下文中评估 code,并返回一个完成值,描述其如何完成。Code 是一个字符串。如果此帧的 environment 属性为 nulltype 属性为 wasmcall,则抛出 TypeError。在调用期间,所有现有的处理程序方法、断点等都保持活动状态。此函数遵循 调用函数约定

code 包含 Use Strict 指令或在此帧中执行的代码是严格模式代码时,Code 被解释为严格模式代码。

如果 code 不是严格模式代码,则 code 中的变量声明会影响此帧的环境。(在 ECMAScript 规范中使用的术语中,eval 代码的执行上下文的 VariableEnvironment 是此帧表示的执行上下文的 VariableEnvironment。)如果实现限制阻止 SpiderMonkey 按要求扩展此帧的环境,则此调用将抛出 Error 异常。

如果给出,options 应为一个对象,其属性指定评估应如何发生的详细信息。eval 方法识别以下属性

url

我们应该将 code 归因于哪个文件名或 URL。如果省略此属性,则 URL 默认为 "debugger eval code"

lineNumber

评估的代码应声称在 url 中开始的行号。

evalWithBindings(*code*,*bindings*, [*options*])

类似于 eval,但在此帧的环境中评估 code,并扩展了来自对象 bindings 的绑定。对于 bindings 的每个自己的可枚举属性(名为 name,其值为 value),在评估 code 的环境中包含一个名为 name 的变量,其值为 value。每个 value 必须是调试目标值。(这不像 with 语句:code 可以访问、分配和删除引入的绑定,而不会对 bindings 对象产生任何影响。)

此方法允许调试器代码引入对给定调试目标代码可见的临时绑定,并且这些绑定引用调试器持有的调试目标值,并且这样做不会改变任何现有的调试目标环境。

请注意,与 eval 一样,传递给 evalWithBindingscode 中的声明会影响此帧的环境,即使该环境通过在 code 中可见的绑定进行扩展。(在 ECMAScript 规范中使用的术语中,eval 代码的执行上下文的 VariableEnvironment 是此帧表示的执行上下文的 VariableEnvironment,并且 bindings 出现在一个新的声明性环境中,它是 eval 代码的 LexicalEnvironment。)如果实现限制阻止 SpiderMonkey 按要求扩展此帧的环境,则此调用将抛出 Error 异常。

options 参数与上面描述的 Debugger.Frame.prototype.eval 相同。与 eval 一样,如果此帧的 environment 属性为 nulltype 属性为 wasmcall,则抛出 TypeError

源元数据

生成自文件

js/src/doc/Debugger/Debugger.Frame.md

水印

sha256:b1894f88b76b7afd661f3044a05690d76d1498c54c596ca729c6ee0d150d2da1

变更集

e91b2c85aacd