v8 - 如何调试 Map.prototype.set 和 OrderedHashTable?
v8 - how to debug Map.prototype.set and OrderedHashTable?
我正在学习有关 v8
内部结构的更多信息,这是一个业余爱好项目。对于这个例子,我试图调试和理解 Javascript Map.prototype.set
是如何在幕后工作的。
我正在使用 v8
标签 9.9.99
。
我首先在 Map
中创建一个新对象:
V8 version 9.9.99
d8> x = new Map()
[object Map]
d8> x.set(10,-10)
[object Map]
d8> %DebugPrint(x)
DebugPrint: 0x346c0804ad25: [JSMap]
- map: 0x346c08202771 <Map(HOLEY_ELEMENTS)> [FastProperties]
- prototype: 0x346c081c592d <Object map = 0x346c08202799>
- elements: 0x346c08002249 <FixedArray[0]> [HOLEY_ELEMENTS]
- table: 0x346c0804ad35 <OrderedHashMap[17]>
- properties: 0x346c08002249 <FixedArray[0]>
- All own properties (excluding elements): {}
当我从 d8
突破到 gdb
时,我查看了 table
属性
gef➤ job 0x346c0804ad35
0x346c0804ad35: [OrderedHashMap]
- FixedArray length: 17
- elements: 1
- deleted: 0
- buckets: 2
- capacity: 4
- buckets: {
0: -1
1: 0
}
- elements: {
0: 10 -> -10
}
翻阅 v8
源代码,我在 src/objects/ordered-hash-table.cc
中找到了我认为与 OrderedHashTable
和 OrderedHashMap
相关的代码。具体来说,第 368 行:
MaybeHandle<OrderedHashMap> OrderedHashMap::Add(Isolate* isolate,
Handle<OrderedHashMap> table,
Handle<Object> key,
Handle<Object> value) {
...
阅读代码后,我的假设是 OrderedHashMap::Add()
会在您执行 Map.Prototype.Set
时触发(即添加新元素)。所以我在这里设置断点并继续
gef➤ b v8::internal::OrderedHashMap::Add(v8::internal::Isolate*,
v8::internal::Handle<v8::internal::OrderedHashMap>,
v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>)
Breakpoint 1 at 0x557eb3b491e4
gef➤ c
Continuing.
然后我尝试设置一个新元素,但是断点没有触发
d8> x.set(11,-11)
[object Map]
再次闯入gdb
,看来元素已添加
gef➤ job 0x346c0804ad35
0x346c0804ad35: [OrderedHashMap]
- FixedArray length: 17
- elements: 2
- deleted: 0
- buckets: 2
- capacity: 4
- buckets: {
0: 1
1: 0
}
- elements: {
0: 10 -> -10
1: 11 -> -11
}
我断点设置错了吗?如果是这样,有人会在 v8
中有效地找到 JS 等价物吗?
(此处为 V8 开发人员。)
由于各种原因,V8 中的许多东西都有不止一种实现:在这种情况下,有一种 C++ 方法可以将条目添加到 OrderedHashMap
(你已经找到了),还有一个generated-code 这样做的方式。如果你对 MapPrototypeSet
进行 grep,你会在 builtins-collections-gen.cc 中找到 TF_BUILTIN(MapPrototypeSet, ...
,这是 Map.prototype.set
的规范实现。由于这是在 V8 构建时运行的一段代码,用于生成一个“存根”,然后将其嵌入到二进制文件中,因此没有直接的方法可以在该存根中设置断点。一种方法是在 stub-generating 代码中插入 DebugBreak()
调用,然后重新编译。
并非所有内置函数都以相同的方式实现:
- 一些(如 M.p.set)在
src/builtins/*-gen.cc
中生成“CSA builtins”
- 有些是
src/builtins/*.cc
中的常规 C++
- 有些是用 Torque (
src/builtins/*.tq
) 编写的,这是 V8 自己的 DSL,转换为 CSA
- 一些直接在编译器中有快速路径
- 有些在“运行时函数”中发挥作用 (
src/runtime/*.cc
)
许多有不止一种实现(通常是完全 spec-compliant“缓慢”的回退,通常但不总是在 C++ 中,然后是一个或多个为常见情况采用捷径的快速路径,通常但不总是以各种形式生成的代码)。我现在可能还忘记了一些特殊情况;随着这个 post 的老化,上面的枚举将变得过时(例如,手写汇编中曾经有内置函数,但我们摆脱了(几乎所有)它们;曾经有由旧的 Crankshaft 编译器,但我们替换了它;曾经有用 JavaScript 编写的内置函数,但我们摆脱了它们;CSA 在某些时候是新的;Torque 在某些时候是新的;谁知道接下来会发生什么).
所有这一切的一个后果是诸如“JavaScript 的功能 X 在幕后究竟是如何工作的?”之类的问题。经常没有一个简洁的答案。
祝您调查愉快!
我正在学习有关 v8
内部结构的更多信息,这是一个业余爱好项目。对于这个例子,我试图调试和理解 Javascript Map.prototype.set
是如何在幕后工作的。
我正在使用 v8
标签 9.9.99
。
我首先在 Map
中创建一个新对象:
V8 version 9.9.99
d8> x = new Map()
[object Map]
d8> x.set(10,-10)
[object Map]
d8> %DebugPrint(x)
DebugPrint: 0x346c0804ad25: [JSMap]
- map: 0x346c08202771 <Map(HOLEY_ELEMENTS)> [FastProperties]
- prototype: 0x346c081c592d <Object map = 0x346c08202799>
- elements: 0x346c08002249 <FixedArray[0]> [HOLEY_ELEMENTS]
- table: 0x346c0804ad35 <OrderedHashMap[17]>
- properties: 0x346c08002249 <FixedArray[0]>
- All own properties (excluding elements): {}
当我从 d8
突破到 gdb
时,我查看了 table
属性
gef➤ job 0x346c0804ad35
0x346c0804ad35: [OrderedHashMap]
- FixedArray length: 17
- elements: 1
- deleted: 0
- buckets: 2
- capacity: 4
- buckets: {
0: -1
1: 0
}
- elements: {
0: 10 -> -10
}
翻阅 v8
源代码,我在 src/objects/ordered-hash-table.cc
中找到了我认为与 OrderedHashTable
和 OrderedHashMap
相关的代码。具体来说,第 368 行:
MaybeHandle<OrderedHashMap> OrderedHashMap::Add(Isolate* isolate,
Handle<OrderedHashMap> table,
Handle<Object> key,
Handle<Object> value) {
...
阅读代码后,我的假设是 OrderedHashMap::Add()
会在您执行 Map.Prototype.Set
时触发(即添加新元素)。所以我在这里设置断点并继续
gef➤ b v8::internal::OrderedHashMap::Add(v8::internal::Isolate*,
v8::internal::Handle<v8::internal::OrderedHashMap>,
v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>)
Breakpoint 1 at 0x557eb3b491e4
gef➤ c
Continuing.
然后我尝试设置一个新元素,但是断点没有触发
d8> x.set(11,-11)
[object Map]
再次闯入gdb
,看来元素已添加
gef➤ job 0x346c0804ad35
0x346c0804ad35: [OrderedHashMap]
- FixedArray length: 17
- elements: 2
- deleted: 0
- buckets: 2
- capacity: 4
- buckets: {
0: 1
1: 0
}
- elements: {
0: 10 -> -10
1: 11 -> -11
}
我断点设置错了吗?如果是这样,有人会在 v8
中有效地找到 JS 等价物吗?
(此处为 V8 开发人员。)
由于各种原因,V8 中的许多东西都有不止一种实现:在这种情况下,有一种 C++ 方法可以将条目添加到 OrderedHashMap
(你已经找到了),还有一个generated-code 这样做的方式。如果你对 MapPrototypeSet
进行 grep,你会在 builtins-collections-gen.cc 中找到 TF_BUILTIN(MapPrototypeSet, ...
,这是 Map.prototype.set
的规范实现。由于这是在 V8 构建时运行的一段代码,用于生成一个“存根”,然后将其嵌入到二进制文件中,因此没有直接的方法可以在该存根中设置断点。一种方法是在 stub-generating 代码中插入 DebugBreak()
调用,然后重新编译。
并非所有内置函数都以相同的方式实现:
- 一些(如 M.p.set)在
src/builtins/*-gen.cc
中生成“CSA builtins”
- 有些是
src/builtins/*.cc
中的常规 C++
- 有些是用 Torque (
src/builtins/*.tq
) 编写的,这是 V8 自己的 DSL,转换为 CSA - 一些直接在编译器中有快速路径
- 有些在“运行时函数”中发挥作用 (
src/runtime/*.cc
)
许多有不止一种实现(通常是完全 spec-compliant“缓慢”的回退,通常但不总是在 C++ 中,然后是一个或多个为常见情况采用捷径的快速路径,通常但不总是以各种形式生成的代码)。我现在可能还忘记了一些特殊情况;随着这个 post 的老化,上面的枚举将变得过时(例如,手写汇编中曾经有内置函数,但我们摆脱了(几乎所有)它们;曾经有由旧的 Crankshaft 编译器,但我们替换了它;曾经有用 JavaScript 编写的内置函数,但我们摆脱了它们;CSA 在某些时候是新的;Torque 在某些时候是新的;谁知道接下来会发生什么).
所有这一切的一个后果是诸如“JavaScript 的功能 X 在幕后究竟是如何工作的?”之类的问题。经常没有一个简洁的答案。
祝您调查愉快!