Debugger.Script¶
一个 Debugger.Script
实例可能引用被调试程序中的字节码序列或 WebAssembly 代码块。对于前者,它是 Debugger
API 对 JSAPI JSScript
对象的表示。这两种情况可以通过它们的 format
属性是 "js"
还是 "wasm"
来区分。
Debugger.Script 用于 JSScripts¶
对于引用 JSScript
的 Debugger.Script
实例,它们通过它们的 format
属性是 "js"
来区分。
以下每个都由一个 JSScript
对象表示
函数体——即函数中所有不包含在任何嵌套函数中的代码。
传递给
eval
的单个调用的代码,不包括该代码定义的任何函数体。<script>
元素的内容。DOM 事件处理程序,无论是在 HTML 中嵌入还是由其他 JavaScript 代码附加到元素上。
出现在
javascript:
URL 中的代码。
The Debugger
接口在调试器发现被调试代码的脚本时构造 Debugger.Script
对象:通过 onNewScript
处理程序方法;通过 Debugger.Frame
的 script
属性;通过 Debugger.Object
实例的 functionScript
方法;等等。对于给定的 Debugger
实例,SpiderMonkey 为每个底层脚本对象构建一个 Debugger.Script
实例;调试器代码可以向脚本对象添加自己的属性并期望以后找到它们,使用 ==
来确定两个表达式是否引用相同的脚本,等等。
(如果多个 Debugger
实例正在调试相同的代码,则每个 Debugger
为给定的脚本获取一个单独的 Debugger.Script
实例。这允许使用每个 Debugger
实例的代码在其 Debugger.Script
实例上放置任何它喜欢的属性,而无需担心干扰其他调试器。)
一个 Debugger.Script
实例是对 JSScript 对象的强引用;它保护它引用的脚本不被垃圾回收。
请注意,SpiderMonkey 可能会对等效的函数或已计算的代码使用相同的 Debugger.Script
实例——即表示相同源代码、在相同源文件中的相同位置、在相同词法环境中计算的脚本。
Debugger.Script 用于 WebAssembly¶
对于引用 WebAssembly 代码块的 Debugger.Script
实例,它们通过它们的 format
属性是 "wasm"
来区分。
目前仅表示通过 new WebAssembly.Module
计算的整个模块。
用于 WebAssembly 的 Debugger.Script
对象在实例化新的 WebAssembly 模块时通过 onNewScript
发现,并通过 Debugger
实例上的 findScripts
方法发现。SpiderMonkey 为每个底层 WebAssembly 模块(每个 Debugger
实例)构建一个 Debugger.Script
。
一个 Debugger.Script
实例是对底层 WebAssembly 模块的强引用;它保护它引用的模块不被垃圾回收。
请注意,在撰写本文时,对 WebAssembly 的支持还处于非常初期的阶段。下面许多属性和方法都会抛出异常。
约定¶
对于下面属性和方法的描述,如果属性或方法的行为在引用 JSScript
或 WebAssembly 代码块的实例之间存在差异,则文本将分为两个部分,分别以“如果实例引用 JSScript
”和“如果实例引用 WebAssembly 代码”为标题。如果行为没有差异,则不会出现此类强调的标题。
Debugger.Script 原型对象的访问器属性¶
一个 Debugger.Script
实例从其原型继承以下访问器属性
isGeneratorFunction
¶
如果此实例引用使用 function*
表达式或语句定义的函数的 JSScript
,则为真。否则为假。
isAsyncFunction
¶
如果此实例引用使用 async function
表达式或语句定义的异步函数的 JSScript
,则为真。否则为假。
isFunction
¶
如果此实例引用函数的 JSScript
,则为真。否则为假。
isModule
¶
如果此实例引用作为 ECMAScript 模块解析和加载的 JSScript
,则为真。否则为假。
displayName
¶
如果实例引用 JSScript
,则为脚本的显示名称(如果存在)。如果脚本没有显示名称——例如,如果它是顶级 eval
脚本——则为 undefined
。
如果脚本的函数具有给定的名称,则其显示名称与其函数的给定名称相同。
如果脚本的函数没有名称,SpiderMonkey 会尝试根据其上下文推断一个合适的名称。例如
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
};
请注意,显示名称可能不是有效的 JavaScript 标识符,甚至不是有效的表达式:我们尝试找到有用的名称,即使函数没有立即分配为某个变量或属性的值。因此,我们使用 a/b
来引用在 a 中定义的 b,并使用 a<
来引用出现在分配给 a 的表达式的某个位置的函数。例如
function h() {
var i = function() {}; // display name: h/i
f(function () {}); // display name: h/<
}
var s = f(function () {}); // display name: s<
如果实例引用 WebAssembly 代码,则抛出 TypeError
。
parameterNames
¶
如果实例引用 JSScript
,则为其参数的名称,作为字符串数组。如果脚本不是函数脚本,则为 undefined
。
如果函数使用解构参数,则相应的数组元素为 undefined
。例如,如果引用是一个以这种方式声明的函数脚本
function f(a, [b, c], {d, e:f}) { ... }
那么这个 Debugger.Script
实例的 parameterNames
属性将具有以下值
["a", undefined, undefined]
如果实例引用 WebAssembly 代码,则抛出 TypeError
。
url
¶
如果实例引用 JSScript
,则为加载此脚本代码的文件名或 URL。对于由 eval
或 Function
构造函数创建的脚本,这可能是一个合成的文件名,以有效的 URL 开头,后跟跟踪代码如何引入系统的信息;整个字符串不是有效的 URL。对于 Function.prototype
的脚本,这为 null
。如果此 Debugger.Script
的 source
属性非 null
,则这等于 source.url
。
如果实例引用 WebAssembly 代码,则抛出 TypeError
。
startLine
¶
如果实例引用的是 JSScript
,则表示此脚本代码在由 url
指定的文件或文档中开始的行号(从 1 开始)。
startColumn
¶
如果实例引用的是 JSScript
,则表示此脚本代码在由 url
指定的文件或文档中开始的列号(从 1 开始)。对于函数,这是函数参数的起始位置。
function f() { ... }
// ^ start (column 11)
let g = x => x*x;
// ^ start (column 9)
let h = (x) => x*x;
// ^ start (column 9)
对于默认类构造函数,它是 class
关键字的起始位置。
let MyClass = class { };
// ^ start (column 15)
对于来自其他来源的脚本,例如 eval
或 Function
构造函数,它通常为 0。
let f = new Function(" console.log('hello world');");
// ^ start (column 1, from the string's perspective)
lineCount
¶
如果实例引用的是 JSScript
,则表示此脚本代码在由 url
指定的文件或文档中所占的行数(从 1 开始)。
source
¶
如果实例引用的是 JSScript
,则表示 Debugger.Source
实例,代表生成此脚本的源代码。如果未保留源代码,则为 null
。
如果实例引用的是 WebAssembly 代码,则表示 Debugger.Source
实例,代表 WebAssembly 代码的序列化文本格式。
sourceStart
¶
如果实例引用的是 JSScript
,则表示由 source
给出的 Debugger.Source
实例中此脚本代码开始的字符位置(从 0 开始)。如果是函数的脚本,则表示源代码中 function
标记的起始索引。
如果实例引用 WebAssembly 代码,则抛出 TypeError
。
sourceLength
¶
如果实例引用的是 JSScript
,则表示此脚本代码在由 source
给出的 Debugger.Source
实例中的长度(以字符为单位)。
如果实例引用 WebAssembly 代码,则抛出 TypeError
。
mainOffset
¶
如果实例引用的是 JSScript
,则表示脚本主入口点的偏移量(从 0 开始),不包括任何序言。
如果实例引用 WebAssembly 代码,则抛出 TypeError
。
global
¶
如果实例引用的是 JSScript
,则表示 Debugger.Object
实例,引用此脚本在其作用域内运行的全局对象。结果直接引用全局对象,而不是通过包装器或 WindowProxy
(在 Firefox 中称为“外部窗口”)。
如果实例引用 WebAssembly 代码,则抛出 TypeError
。
format
¶
如果实例引用的是 JSScript
,则为 "js"
。
如果实例引用的是 WebAssembly 代码,则为 "wasm"
。
Debugger.Script 原型对象的功能属性¶
下面描述的函数只能在 this
值引用 Debugger.Script
实例的情况下调用;不能用作其他类型对象的函数。
getChildScripts()
¶
如果实例引用的是 JSScript
,则返回一个新数组,其元素是此脚本中每个函数的 Debugger.Script 对象。只包含直接子节点;嵌套子节点可以通过遍历树来访问。
如果实例引用 WebAssembly 代码,则抛出 TypeError
。
getPossibleBreakpoints(query)
¶
查询 SpiderMonkey 中可用的推荐断点位置。返回一个结果数组,其中包含以下属性的对象
offset: number
- 断点的偏移量(从 0 开始)。lineNumber: number
- 断点的行号(从 1 开始)。columnNumber: number
- 断点的列号(从 1 开始)。isStepStart: boolean
- 如果 SpiderMonkey 建议在调试器用户单步执行到下一个项目时将断点视为单步执行位置,则为 true。这大致对应于每个语句的开头,但并非完全如此。
query
参数可用于筛选断点集。query
对象可以包含以下属性
minOffset: number
- 要包含的offset
值的下界(包含下界,从 0 开始)。maxOffset: number
- 要包含的offset
值的上界(不包含上界,从 0 开始)。line: number
- 限制在给定行上的断点(从 1 开始)。minLine: number
- 要包含的行数的下界(包含下界,从 1 开始)。minColumn: number
- 要包含的行/minLine 列的下界(包含下界,从 1 开始)。maxLine: number
- 要包含的行数的上界(不包含上界,从 1 开始)。maxColumn: number
- 要包含的行/maxLine 列的上界(不包含上界,从 1 开始)。
getPossibleBreakpointOffsets(query)
¶
查询 SpiderMonkey 中可用的推荐断点位置。与 getPossibleBreakpoints 相同,只是返回的是 offset
值的数组,而不是偏移量元数据对象。
getOffsetMetadata(offset)
¶
获取给定字节码偏移量(从 0 开始)的元数据。返回一个包含以下属性的对象
lineNumber: number
- 断点的行号(从 1 开始)。columnNumber: number
- 断点的列号(从 1 开始)。isBreakpoint: boolean
- 如果此偏移量符合断点条件,则为 true,定义方式与getPossibleBreakpoints()
中使用的语义相同。isStepStart: boolean
- 如果 SpiderMonkey 建议在调试器用户单步执行到下一个项目时将断点视为单步执行位置,则为 true。这大致对应于每个语句的开头,但并非完全如此。
setBreakpoint(offset, handler)
¶
如果实例引用的是 JSScript
,则在此脚本的offset(从 0 开始)处的字节码指令处设置断点,并将命中情况报告给handler的 hit
方法。如果offset在此脚本中不是有效的偏移量,则抛出错误。此外,即使offset在此脚本中是有效的偏移量,引擎内部操作的一些指令(例如,生成器函数初始化中的 SetAliasedVar)也不允许设置断点,在这种情况下,也会抛出错误。
当执行到达给定指令时,SpiderMonkey 会调用handler的 hit
方法,并传递一个 Debugger.Frame
实例,表示当前正在执行的堆栈帧。hit
方法的返回值应为 恢复值,确定执行应如何继续。
可以在一个位置设置任意数量的断点;当控制权到达该点时,SpiderMonkey 会以未指定的顺序调用它们的处理程序。
任意数量的断点可以使用相同的handler对象。
断点处理程序方法调用是跨隔间、线程内调用:调用发生在命中断点的同一线程中,以及包含处理程序函数的隔间(通常是调试器的隔间)。
新断点属于此脚本所属的 Debugger
实例。从 Debugger
实例的被调试者集中删除全局对象会清除该 Debugger
实例在该全局的脚本中设置的所有断点。
getBreakpoints([offset])
¶
如果实例引用的是 JSScript
,则返回一个数组,其中包含在此脚本的offset(从 0 开始)处设置的所有断点的处理程序对象。如果省略了offset,则返回在此脚本中任何位置设置的所有断点的处理程序。如果offset存在,但不是此脚本中的有效偏移量,则抛出错误。
如果实例引用 WebAssembly 代码,则抛出 TypeError
。
clearBreakpoint(handler, [offset])
¶
如果实例引用的是 JSScript
,则删除在此 Debugger
实例中使用handler作为其处理程序的所有断点。如果给出了offset(从 0 开始),则仅删除在offset处设置并使用handler的断点;如果offset不是此脚本中的有效偏移量,则抛出错误。
请注意,如果使用其他处理程序对象的断点与handler在同一位置设置,则它们将保留。
clearAllBreakpoints([offset])
¶
如果实例引用的是 JSScript
,则删除在此脚本中设置的所有断点。如果存在offset(从 0 开始),则删除在此脚本的该偏移量处设置的所有断点;如果offset不是此脚本中的有效字节码偏移量,则抛出错误。
getEffectfulOffsets()
¶
如果实例引用的是 JSScript
,则返回一个数组,其中包含脚本中所有可能产生直接副作用(在当前执行的帧之外可见)的字节码的偏移量(从 0 开始)。例如,这包括设置对象属性或元素的操作,或可能在帧外部创建的环境中设置名称的操作。
这并不包括引擎内部操作的一些指令(例如,生成器函数初始化中的 SetAliasedVar)。这些指令在引擎内部方面可能是有效果的,但这对用户不可见,在这里可以被视为没有效果。
getOffsetsCoverage()
:¶
如果实例引用的是 JSScript
,则返回 null
或一个包含所有操作码覆盖率信息的数组。数组的元素是对象,每个对象描述一个操作码,并包含以下属性
lineNumber
: 当前操作码的行号(从 1 开始)。columnNumber
: 当前操作码的列号(从 1 开始)。offset
: 当前操作码的字节码指令偏移量(从 0 开始)。count
: 当前操作码执行的次数。
如果此脚本没有覆盖率,或者没有被检测,则此函数将返回 null
。要确保被调试者被检测,应将标志 Debugger.collectCoverageInfo
设置为 true
。
如果实例引用 WebAssembly 代码,则抛出 TypeError
。
isInCatchScope([offset])
¶
如果实例引用的是 JSScript
,如果此偏移量(从 0 开始)位于 try 块的作用域内,则为 true
,否则为 false
。
如果实例引用 WebAssembly 代码,则抛出 TypeError
。
已弃用的 Debugger.Script 原型函数¶
以下函数均已弃用,建议使用 getOffsetMetadata
、getPossibleBreakpoints
和 getPossibleBreakpointOffsets
。这些函数对结果中包含哪些偏移量以及不包含哪些偏移量都存在定义不明确的问题。
getAllOffsets()
¶
如果实例引用的是一个 JSScript
,则返回一个数组 L,描述字节码指令偏移量(从 0 开始)与脚本中源代码位置之间的关系。L 是稀疏数组,并以源代码行号为索引。如果某个源代码行号 line 没有代码,则 L 中没有 line 属性。如果 line 存在代码,则 L[line]
是一个数组,包含指向该行的字节码指令的入口点的偏移量。
例如,假设我们有一个脚本,其源代码如下所示:
a=[]
for (i=1; i < 10; i++)
// It's hip to be square.
a[i] = i*i;
对该代码调用 getAllOffsets()
可能得到如下所示的数组:
[, [0], [16, 75], , [52]]
此数组表示:
第一行代码从脚本中的偏移量 0 开始;
for
语句头有两个入口点,偏移量分别为 16 和 75(分别对应于仅执行一次的初始化和每次迭代开始时执行的循环测试);第三行没有代码;
第四行从偏移量 52 开始。
如果实例引用 WebAssembly 代码,则抛出 TypeError
。
getAllColumnOffsets()
¶
如果实例引用的是一个 JSScript
,则返回一个数组,描述字节码指令偏移量与脚本中源代码位置之间的关系。与返回每行所有入口点偏移量的 getAllOffsets() 不同,getAllColumnOffsets() 返回每个 (行,列) 对的所有入口点偏移量。
数组的元素是对象,每个对象描述一个入口点,并包含以下属性:
lineNumber:偏移量为入口点的行号(从 1 开始);
columnNumber:偏移量为入口点的列号(从 1 开始);
offset:入口点的字节码指令偏移量(从 0 开始)。
例如,假设我们有一个脚本,其源代码如下所示:
a=[]
for (i=1; i < 10; i++)
// It's hip to be square.
a[i] = i*i;
对该代码调用 getAllColumnOffsets()
可能得到如下所示的数组:
[{ lineNumber: 1, columnNumber: 1, offset: 0 },
{ lineNumber: 2, columnNumber: 6, offset: 16 },
{ lineNumber: 2, columnNumber: 11, offset: 28 },
{ lineNumber: 4, columnNumber: 5, offset: 52 },
{ lineNumber: 4, columnNumber: 14, offset: 67 },
{ lineNumber: 2, columnNumber: 19, offset: 75 }]
如果实例引用 WebAssembly 代码,则抛出 TypeError
。
getLineOffsets(line)
¶
如果实例引用的是一个 JSScript
,则返回一个字节码指令偏移量数组,表示源代码行 line(从 1 开始)的入口点。如果脚本在该行没有可执行代码,则返回的数组为空。
getOffsetLocation(offset)
¶
如果实例引用的是一个 JSScript
,则返回一个对象,描述脚本中 offset 处的字节码对应的源代码位置。该对象具有以下属性:
lineNumber
:偏移量为入口点的行号(从 1 开始);columnNumber
:偏移量为入口点的列号(从 1 开始);isEntryPoint
:如果偏移量是列入口点(如 getAllColumnOffsets() 所报告的那样),则为 true;否则为 false。