HomeLập trìnhJavaScript深入理解 JavaScript 的...

深入理解 JavaScript 的 V8 引擎


Tác giả: Cách thức hoạt động của JavaScript: Under the Hood of the V8 Engine,作者: Ilya Lyamkin

Bạn có thể sử dụng JavaScript 看看 JavaScript 的 V8 引擎,弄清楚 JavaScript 到底是如何执行的。

在 之前 , , , , , , , , , 回顾 回顾 回顾 回顾 回顾 回顾 一下 一下 一下

背景

Web 标准 是浏览器实施的一套规则。它们定义并描述了万维网。

W3c 是 个 网络 制定 标准 社区。 每 个 人 遵循 遵循 相同 的 , , 必 支持 支持 支持 支持 几十 几十 完全 不同 环境。。。。

’现代 现代 现代 , 代码 代码 代码 代码 所以 的 的。。。。。

而浏览器中最重要的两个部分是 JavaScript 引擎和渲染引擎。

Chớp 是 是 , , , , , 、 样式 和 和 和 和 和 集成 集成 集成。 它 它 视觉 视觉 的 视觉 视觉 视觉 视觉 视觉 视觉 视觉 视觉 视觉

在 动画 不断 变化 的 , , , 屏幕 绘制。。 引擎 引擎 是 浏览器 一 个 部分 部分 部分 部分 但 但 我们 没有 进入 这些 这些 细节 细节 细节

Công cụ JavaScript

JavaScript 引擎 JavaScript 编译 地 代码 执行 每 每 主要 开发 开发 的 的 引擎 引擎 谷歌 的 chrome 使用 v8

Tôi muốn giới thiệu Node.js và Electron 中使用, 但其他引擎也是以同样的方式构建的。

每个步骤都将包括一一个负该步骤的代码链接,因此你可以熟悉代码库,并在本文之后继续研研研

Bạn có thể sử dụng GitHub 上的 V8 镜像,因为它提供了一个方便和知名的 UI 来浏览代码库。

准备代码

Các công nhân dịch vụ của V8 có thể được sử dụng làm công cụ hỗ trợ cho các công nhân dịch vụ của V8.

一旦 , 我们 可以 理解 方式 这个 这个 过程 称为 解析 解析 解析 ((()) : : :

Đọc thêm  Cách viết hoa chữ cái đầu tiên của mỗi từ trong JavaScript – Hướng dẫn viết hoa JS

扫描器接收 JS 文件并将其转换为已知的标记列表。在 Keywords.txt 文件中有一个所有 JS 标记的列表。

解析器识别它并创建一个 抽象语法树 (AST)

让我们看一下一个简单的例子:

function foo() {
    let bar = 1;
    return bar;
}

这段代码将产生以下树状结构:

AST 树的例子
AST 树的例子

你可以通过执行前序遍历(根、左、右)来执行这段代码:

  1. 定义 foo 函数。
  2. 声明 bar 变量。
  3. 1 分配给 bar
  4. 从函数中返回 bar
    你还会看到 VariableProxy–一个将抽象变量连接到内存中某个地方的元素。解决 VariableProxy 的过程被称为 范围分析(Phân tích phạm vi)

在我们的例子中,这个过程的结果是所有 VariableProxy 都指向同一个 bar 变量。

Mô hình Đúng lúc(JIT(即时编译)

一般 , , , , , , 需要 转化 转化。。。。 如何 以及 何时 发生 这 这 种 种 种 种 种

最 最 : : : : : : : , 语言 语言 语言 语言 语言 语言 语言 语言 语言 语言 语言 语言。

在 在 在 在 : : 语言 语言 语言 语言 语言 和) 类型 确切 确切 确切 确切 确切 确切 确切 确切 确切 确切 确切

因为 提前 , , , , 并 并 并 高 高 的 的 代码 代码 代码 代码 , , , , , , ,

为了 快 更 为 动态 , , 种 称为 称为 即时 ((()) 编译 的 新。。 它 它 它 它 最好 地 了 解释 和 和 和 编译

在 使用 (() 基础 方法 , , , , 可以 比 其他 频繁 频繁 频繁 使用 的 , 并 并 使用 以前 以前 以前 的 类型 其 其 其 进行 进行 进行

然而 , 可能 变化 , , , , , , , , , 到 到 解释法 , , , ,

让我们更详细地探讨一下 JIT 编译的每个部分。

Thông dịch viên(解释器)

V8 使用一个叫做 Ignition 的解释器。最初,它接受一个抽象的语法树并生成字节码。

JS 的抅容字节码指令与 JS 的抅容字节码指令也有元数据,如源行位置

现在让我们以我们的例子为例,为它手动生成字节码:

LdaSmi #1 // write 1 to accumulator
Star r0   // read to r0 (bar) from accumulator
Ldar r0   // write from r0 (bar) to accumulator
Return    // returns accumulator

Ignition 有一个叫做累加器(acquy)的东西–一个可以存储/读取数值的地方。

Đọc thêm  JavaScript forEach() – Mảng JS cho mỗi ví dụ về vòng lặp

累加器 避免 和 的 的 , , , , , , , , , , , , , , , , 结果 结果 结果 地 地 地

你 可以 相应 中 中 字节码 字节码 你 你 (((((有用的。

Thi hành(执行)

生成 后 ign ign 将 个 以 字 为 处理 程序表 来。。 对于 每 每 , , , , , 的 提供 提供 提供 的 的 的 的

正如.

首先 , 讨论 在内存 中 表示 , , , , , , , , , , 为 为 为 每 个 对象 对象 对象 创建

保存对象的第一种方法
保存对象的第一种方法

然而,我们通常有很多具有相同结构的对象,所以存储大量重复的字典是没有效率的。

为了解决这个问题,V8 Hình dạng đối tượng(或内部映射 Bản đồ nội bộ)和内存中的值向量将对象的结构与值本身分开。

例如,我们创建一个对象字面:

let c = { x: 3 };
let d = { x: 5 };
c.y = 4;

在第一行,它将产生一个 hình dạng Map[c],其属性为x,偏移量为 0。

Đối với các nhà sản xuất động cơ V8, động cơ V8 không phải là hình dạng của động cơ V8.

在第三行之后,它将为属性yhình dạng 创建一个新的 Map[c1],偏移量为1,并创建一个与之前 hình dạng Map[c] 的引用。

hình dạng đối tượng
hình dạng đối tượng

在 上面 , , 可以 每 个 对象 有 有 一 个 指向 指向 的 , , , 每 个 属性 , , , , ,

Hình dạng đối tượng c.x,V8 会去到列表的头部,在那里找到 y,移动到连接的 shape,最后它得到 x 并从中读取偏移。然后它将进入内存向量并返回其中的第一个元素。

你 , , 大 大 , , 会 会 会 , , , , , , , , , , , , , ,

为了解决 V8 中的这个问题,你可以使用在线缓存 Inline Cache(IC)。它记住了在哪里可以找到对象的属性的信息,以减少查找的数。

你可以把它看作是你代码中的一个监听点:CALL_、_STORE_和_LOAD_事件,并记录shapes

保存 IC 的数据结构被称为反馈向量 Phản hồi Vector**。** Tôi muốn giới thiệu một số ứng dụng của IC.

function load(a) {
    return a.key;
}

对于上述函数,反馈向量将是这样的:

[{ slot: 0, icType: LOAD, value: UNINIT }];

这是一个简单的函数,只有一个 IC,它的类型是 LOAD,值是 UNINIT。这意味着它是未初始化的,我们不知道接下来会发生什么。

Bạn có thể sử dụng bộ nhớ cache nội tuyến cho bộ nhớ cache nội tuyến của mình không?

let first = { key: 'first' }; // shape A
let fast = { key: 'fast' }; // the same shape A
let slow = { foo: 'slow' }; // new shape B

在第一次调用load函数后,我们的内联缓存(bộ nhớ cache nội tuyến)将得到一个更新的值:

[{ slot: 0, icType: LOAD, value: MONO(A) }];

这个值现在变成了单态的,这意味着这个缓存只能解析为 hình dạng A。

Đọc thêm  Cách chèn mã JavaScript để thao tác trang web một cách tự động

Bạn có thể sử dụng IC trong động cơ V8 và IC trong động cơ V8. fast 变量的 shape 相同。所以它将迅速返回偏移量并解析它。

第三次,其形状与存储的 shape 不同。所以 V8 将手动解决它,并将其值更新为多态状态,有两个儯能 shape

[{ slot: 0, icType: LOAD, value: POLY[(A, B)] }];

现在我们每次调用这个函数时,V8 需要检查的不仅仅是一个 shape,而是在几种可能性中进行迭代。

Bạn có thể cho tôi biết bạn là ai, bạn có thể cho tôi biết điều đó không?

Lời khuyên dành cho bạn là: bạn không cần phải làm gì cả, bạn phải làm thế nào để trở thành một trong những người giỏi nhất?

Quạt động cơ Turbofan có khả năng điều chỉnh tốc độ và tốc độ truyền tải.

Trình biên dịch(编译器)

Đánh lửa 只 让 我们。 如果 个 函数 热 译者 译者 注 调用) , , 它 它 将 编译器 中 中 中

Turbofan 从 Ignition 中获取字节码和函数的类型反馈(Vector phản hồi),在此基础上应用一系列的缩减,并产生机器码

正如我们之前看到的,类型反馈并不能保证它在未来不发生变化。

例如,Turbofan 基于一些加法总是加整数的假设来优化代码。

但如果它收到的是一个字符串,会发生什么?这个过程被称为去优化, 我们扔掉优化的代码,回到解释的代码,恢复执行,并更新类型反馈。

总结

在这篇文章中,我们讨论了 JS 引擎的实现以及 JavaScript 如何执行的具体步骤。

总结一下,让我们从头看一下编译管道。

Động cơ V8
Động cơ V8

我们将一步一步地看下去:

  1. 这一切都始于从网络中获取 JavaScript 代码。
  2. V8 解析源代码并将其转化为抽象语法树(AST)。
  3. AST,Ignition 解释器可以开始做它的事情,并产生字节码。
  4. 在这一点上,引擎开始运行代码并收集类型反馈。
  5. 为了 使 , , , 优化 到 到 优化 优化 在 此 此 此 此 此 此 此 此 此
  6. 如果在某些时候,其中一个假设被证明是不正确的,优化编译器就会取消优化,并回到解释器中

就 是! 上面 个 , , , , , , 了解 了解 了解 更 多 , , , , Twitter 上联系我。

深入阅读





Zik.vn – Biên dịch & Biên soạn Lại

spot_img

Create a website from scratch

Just drag and drop elements in a page to get started with Newspaper Theme.

Buy Now ⟶

Bài viết liên quang

DMCA.com Protection Status