前言
此文章是我最近在看的【WebKit 技术内幕】一书的一些理解和做的笔记。
而【WebKit 技术内幕】是基于 WebKit 的 Chromium 项目的讲解。
书接上文 浏览器之硬件加速机制
本章主要讲解 WebKit 中广泛使用的 JavaScriptCore 引擎和 V8 引擎。
1. javaScript
简介
JavaScript 是一种脚本语言,主要用在 Web 的客户端,是控制网页客户端的逻辑,例如同用户的交互,异步通信等需求。
本质上它是一种解释语言,函数是它的第一等公民,也就是函数也能够当作参数或者返回值来传递。
JavaScript 语言的一个重大特点就是,它是一种无类型语言,或者说是动态类型语言。
这一特性导致我们没有办法有编译的时候知道变量的类型,所以只能在运行的时候才能确定。
推动 JavaScript 运行速度提高的另一大利器是 JIT(Just-In-Time)技术,它不是一项全新的技术,其作用是解决解释性语言的性能问题。
主要思想是当解释器将代码解释成内部表示的时候,JavaScript 的执行环境不仅是解释这些内部表示,而且将其中一些字节码(主要是使用率高的部分)转成本地代码(汇编代码),这样可以被 CPU 直接执行,而不是解释执行,从而极大提高性能。
1.2 JavaScript 引擎
JavaScript 引擎就是能够将 JavaScript 代码处理并执行的运行环境。
JavaScript 引擎包括以下部分:
- 编译器:将源代码编译成抽象语法树,在某些引擎中还包含将抽象语法树转换成字节码。
- 解释器:在某些引擎中,解释器主要是接收字节码,解释执行这个字节码,同时也依赖垃圾回收机制等。
- JIT 工具:一个能够 JIT 的工具,将字节码或者抽象语法树转换在本地代码,当然它也需要依赖牢记。
- 垃圾回收器和分析工具(Profiler):负责垃圾回收和 收集引擎中的信息,帮助改善引擎的性能和功效。
1.3 JavaScript 引擎和渲染引擎
从模块上看,它们是两个独立的模块,分别负责不同的事情:
JavaScript 引擎负责执行 JavaScript 代码,而渲染引擎负责渲染网页。
JavaScript 引擎提供调用接口给渲染引擎,以便让渲染引擎使用 JavaScript 引擎来处理JavaScript 代码并获取结果。
这并不是全部,JavaScript 引擎需要能够访问渲染引擎构建的 DOM 树,所以 JavaScript 引擎通常需要提供桥接的接口,而渲染引擎则根据桥接接口来提供让 JavaScript 访问 DOM 的能力。
在现在众多的 HTML5 能力中,很多是通过 JavaScript 接口提供给开发者的,所以这部分同样需要根据桥接接口来实现具体类,以便让 JavaScript 引擎能够回调渲染引擎的具体实现。
在 WebKit 中,两种引擎通过桥接接口来访问 DOM 结构,这对性能来说是一个重大的损失,因为每次 JavaScript 代码访问 DOM 都需要通过复杂和低效的桥接接口来完成。
1.2 V8 引擎
1.2.1 基础
V8 是一个开源项目,也是一个 JavaScript 引擎的实现。
V8 支持众多的操作系统。包括但是不限于 Windows、Liunx、Android、Mac OSX 等。同时它也能够支持众多的硬件架构,例如 IA32、X64、ARM 、MIPS 等。
1.2.1.1 代码结构
1.2.2 V8 工作过程
V8 工作过程有两个阶段,第一是编译,第二是运行。
鉴于 JavaScript 语言的工作方式,它们都是在用户使用它们的时候发生。
同时,V8 还有一个特点是 延迟(deferred)思想,这使得很多 JavaScript 代码的编译直到运行的时候被调用到才会发生,这样可以减少时间开销。
先看编译阶段:
从图中可以看出,首先它也是将源代码转变成抽象语法树,V8 引擎并不将抽象语法树转变成字节码或者其他中间表示,而是通过 JIT 编译器的全代码生成器(full code generator)从抽象语法树直接生成本地代码,这样子减少了转换时间。
再看运行阶段:
V8 支持 JavaScript 代码运行用到了一堆类。
V8 引擎是按照图 9-17 中描述的过程来执行的,实际过程更为复杂,而且还有垃圾回收等处理。
1.3 JavaScriptCore 引擎
JavaScriptCore 引擎是 WebKit 中默认的 JavaScript 引擎,也是苹果开源 WebKit 项目之后,开源的另外一个重要的项目。
1.3.2 架构和模块
1.3.2.1 代码结构
演进过程:
首先是词法和语法分析,然后使用底层解释器来解释那些字节码。
之后,通过简单的 JIT 编译器将它们转化成本地代码,最后就是引入 DFG JIT 编译器