【问题标题】:where does V8 actually consume the raw javascript code?V8 在哪里实际使用原始 javascript 代码?
【发布时间】:2020-07-07 15:19:13
【问题描述】:

我试图了解 v8 是如何工作的,但我无法找到它实际上在代码中的哪个位置获取输入的原始 js 脚本来解析它并将其编译成 c++。

我看过 api.cc 并尝试在编译器函数中设置断点,但没有运气(我使用 chromium 这样做),它永远不会命中这个函数。

MaybeLocal<Script> ScriptCompiler::Compile(Local<Context> context,
                                      Source* source,
                                      CompileOptions options,
                                      NoCacheReason no_cache_reason)

***** 更新 ****

@jmrk 回复后,我一直在试图弄清楚 JS 究竟从哪里开始,我真正感兴趣的是了解网站如何呈现,然后将脚本传递到 V8 进行编译。 我找到了很多关于该主题的信息,但我仍然无法理解整个画面:

原来第一步不是解析器而是扫描器,它获取一个 UTF-16 流作为输入。

源代码首先被分解成块;每个块可能是 与不同的编码相关联。一个流然后统一所有的块 UTF-16编码下。

在解析之前,扫描器将 UTF-16 流分解为 令牌。标记是具有语义的脚本的最小单元 意义。有几种类型的标记,包括空格 (用于自动分号插入)、标识符、关键字和 代理对(仅当该对为 不被识别为其他任何东西)。然后将这些令牌首先馈送到 预解析器,然后到解析器。

https://blog.logrocket.com/how-javascript-works-optimizing-for-parsing-efficiency/

我还发现它确实从 Blink 获得了这个流:

UTF16CharacterStream 提供了一个(可能是缓冲的)UTF-16 视图,以覆盖 V8 从 Chrome 接收到的底层 Latin1、UTF-8 或 UTF-16 编码,而 Chrome 又从网络接收到这些编码。除了支持多种编码之外,扫描器和字符流之间的分离允许 V8 透明地扫描,就好像整个源都可用一样,即使到目前为止我们可能只通过网络收到了一部分数据。

https://v8.dev/blog/scanner

扫描器似乎也将令牌提供给解析器:

V8 的解析器使用“扫描器”提供的“令牌”。代币是 具有单一语义含义的一个或多个字符块: 一个字符串、一个标识符、一个像 ++ 这样的运算符。扫描仪构造 这些标记通过组合底层的连续字符 字符流。

但问题仍然存在,从 Blink 进入 V8 的 Javascript 原始代码在哪里? 如何查看 chrome 读取的内容以及它在哪里初始化 v8?

【问题讨论】:

    标签: javascript chromium v8 blink embedded-v8


    【解决方案1】:

    这很复杂:-)

    ScriptCompiler::Compile 通常作为最外层入口点是正确的。请注意,它有两个重载。此外,Chrome 会在可能的情况下尝试进行流式编译,这采用了不同的路径。此外,在使用 Chrome/Chromium 时,请注意您必须在渲染器进程中设置断点,而不是在浏览器进程中。

    在查看 V8 时,使用 d8 shell 会更容易。在 d8.cc 中查找 Shell::ExecuteString(调用 ScriptCompiler::Compile)。

    另外,澄清一下,V8 不会将 JavaScript 编译为 C++。它首先将其编译为自己的内部字节码格式,由“Ignition”解释器执行;热函数随后由“Turbofan”优化编译器编译为机器码。

    如果您无法理解整个管道,请不要气馁。没有一个人这样做; V8 太大太复杂了。专注于您感兴趣的内容(解析器?解释器?优化编译器?)并深入研究。

    【讨论】:

    • 感谢@jmrk 的回复。上周我一直在研究 d8 并进行自己的测试。我现在更好地理解了 V8 的整个概念。但是我不明白的是,它实际上是如何加载 js 以使解析器在加载网站时开始工作,我假设它首先评估代码是否正确并且可以在执行任何其他操作之前进行编译。我应该查看解析器中的某些函数吗?
    • 所有的解析器都负责解析。语法错误检查在解析期间发生(因为无论如何它都是相同的工作,所以在单独的传递中这样做会效率低下)。 如果解析器产生一个 AST(而不是错误),然后解释器将该 AST 转换为字节码。一些更复杂的情况是首先对整个源进行预解析,然后再对各个函数进行完全解析。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-27
    • 2017-01-07
    • 1970-01-01
    • 2021-06-22
    • 2012-01-17
    • 1970-01-01
    相关资源
    最近更新 更多