paw*_*que 7 javascript stack v8 spidermonkey stack-trace
当我使用javascript生成器为小型方案解释器实现调试器时,我开始想知道例如chrome javascript引擎中的堆栈模型.通常,只有一个函数调用帧堆栈就足够了.在生成器的情况下,我可以让函数调用执行另一个路径,然后跳回到部分执行的生成器,即将堆栈的一部分放入剩下的生命中.
这是如何在chrome或firefox javascript引擎中实现的?整个虚拟堆栈是由多个虚拟堆栈组成还是堆叠在生成写入生成器对象时留下的部分?然后它可以在再次进入发电机时重新放回堆栈.
在 Chrome/V8 的当前实现中,作为yielding 的一部分,生成器稍后恢复执行所需的所有状态都被写入到一个对象中。函数调用帧只有一个堆栈。
细节很复杂;如果你想读的来源,开始在BytecodeGenerator::VisitYield中(V8)/src/interpreter/bytecode-generator.cc。
生成器仍然在与普通函数相同的单个调用堆栈上运行。评估之间没有跳转的多个堆栈。
当实例化一个生成器(通过调用生成器函数)然后调用其.next()方法时,它只是将该调用推入堆栈的顶部。然后它将运行生成器函数中的代码。
当遇到yield语句时,它只是从堆栈中弹出调用,然后从.next()方法中返回,在任何函数调用之后照常继续。
生成器调用和普通函数调用之间的区别在于输入和离开代码时发生的情况。
普通函数保留在函数主体或return/ throw语句的末尾,然后完成。生成器也会保留yield,但它必须记住状态(基本上将指令指针存储在生成器实例中),以便它可以在之后恢复执行yield。它还必须记住所有局部变量的状态,但是引擎已经知道如何从闭包的实现中做到这一点。
普通函数通过设置一个新环境并在函数主体顶部开始执行来进入调用。生成器调用将恢复状态,以便可以从中断处继续。
堆栈的正常行为不受此影响。
好我撒谎了 yield*使一切变得更加复杂。yield*进入或离开.next()调用时,一串递归生成器将需要推入并弹出多个堆栈帧。引擎可以通过使用多个堆栈来优化此上下文切换。仍然,人们会看到它们堆叠在一起,形成一个大的堆栈,并且在执行过程中,只有该单个堆栈的顶部被操纵。
| 归档时间: |
|
| 查看次数: |
289 次 |
| 最近记录: |