跨端轻量JavaScript引擎的实现与探索
一、JavaScript
1.JavaScript语言
JavaScript是ECMAScript的实现,由ECMA 39(欧洲计算机制造商协会39号技术委员会)负责制定ECMAScript标准。
ECMAScript发展史:
| 时间 | 版本 | 说明 |
| 1997年7月 | ES1.0 发布 | 当年7月,ECMA262 标准出台 |
| 1998年6月 | ES2.0 发布 | 该版本修改完全符合ISO/IEC 16262国际标准。 |
| 1999年12月 | ES3.0 发布 | 成为 JavaScript 的通行标准,得到了广泛支持 |
| 2007年10月 | ES4.0草案发布 | 各大厂商意见分歧,该方案未通过 |
| 2008年7月 | 发布ES3.1,并改名为ECMAScript 5 | 废除ECMAScript 4.0,所以4.0版本不存在 |
| 2009年12月 | ESt 5.0 正式发布 | |
| 2011年6月 | ES5.1 发布 | 该版本成为了 ISO 国际标准(ISO/IEC 16262:2011) |
| 2013年12月 | ES6 草案发布 | |
| 2015年6月 | ES6 正式发布,并且更名为“ECMAScript 2015” | TC39委员会决定每年发布一个ECMAScript 的版本 |
2.JavaScript引擎
JavaScript引擎是指用于处理以及执行JavaScript脚本的虚拟机。
常见的JavaScript引擎:

| 引擎 | 所属机构/个人 | 浏览器 | 说明 |
| SpiderMonkey | Mozilla | Firefox | 第一款JavaScript引擎,早期用于 Netscape Navigator,现时用于 Mozilla Firefox。是用C语言实现的,还有一个Java版本叫Rhino;Rhino引擎由Mozilla基金会管理,开放源代码,完全以Java编写,用于 HTMLUnit;而后TraceMonkey引擎是基于实时编译的引擎,用于Mozilla Firefox 3.5~3.6版本;JaegerMonkey:结合追踪和组合码技术大幅提高性能,用于Mozilla Firefox 4.0以上版本 |
| JavaScriptCore | Apple | Safari | 简称JSC,开源,用于webkit内核浏览器,如 Safari ,2008 年实现了编译器和字节码解释器,升级为了SquirrelFish。苹果内部代号为Nitro的 JavaScript 引擎也是基于 JSC引擎的。至于具体时间,JSC是WebKit默认内嵌的JS引擎,而WebKit诞生于1998年,Nitro是为Safari 4编写,Safari 4是2009年6月发布。 |
| V8 | Chrome | 2008年9月,Google的V8引擎第一个版本随着Chrome的第一个版本发布。V8引擎用 C++编写,由 Google 丹麦开发,开源。除了Chrome,还被运用于Node.js以及运用于Android操作系统等 |
|
| Chakra | Microsoft | Edge、IE | 译名查克拉,用于IE9、10、11和Microsoft Edge,IE9发布时间2011年3月 |
| JerryScript | 三星 | 三星推出的适用于嵌入式设备的小型 JavaScript 引擎,2015年开源 | |
| Nashorn | Oracale | 从 JDK 1.8 开始,Nashorn取代Rhino(JDK 1.6, JDK1.7) 成为 Java 的嵌入式 JavaScript 引擎,JDK1.8发布于2014年 | |
| QuickJS | Fabrice Bellard | QuickJS 是一个小型的嵌入式 Javascript 引擎。 它支持 ES2023 规范,包括模块、异步生成器、代理和 BigInt。 它可以选择支持数学扩展,例如大十进制浮点数 (BigDecimal)、大二进制浮点数 (BigFloat) 和运算符重载。 | |
| Hermes | 引擎,Facebook在Chain React 2019 大会上发布的一个崭新JavaScript引擎,用于移动端React Native应用的集成,开源 |
3.JavaScript引擎工作原理
a.V8引擎工作原理

b.Turbofan技术实例说明
function sum(a, b) {
return a + b;
}
这里a和b可以是任意类型数据,当执行sum函数时,Ignition解释器会检查a和b的数据类型,并相应地执行加法或者连接字符串的操作。
如果 sum函数被调用多次,每次执行时都要检查参数的数据类型是很浪费时间的。此时TurboFan就出场了。它会分析函数的执行信息,如果以前每次调用sum函数时传递的参数类型都是数字,那么TurboFan就预设sum的参数类型是数字类型,然后将其编译为机器码。
但是如果某一次的调用传入的参数不再是数字时,表示TurboFan的假设是错误的,此时优化编译生成的机器代码就不能再使用了,于是就需要进行回退到字节码的操作。
三、QuickJS
1.QuickJS作者简介
法布里斯·貝拉 (Fabrice Bellard)


2.QuickJS简介
QuickJS 是一个小型的嵌入式 Javascript 引擎。 它支持 ES2023 规范,包括模块、异步生成器、代理和 BigInt。
它可以选择支持数学扩展,例如大十进制浮点数 (BigDecimal)、大二进制浮点数 (BigFloat) 和运算符重载。
•小且易于嵌入:只需几个 C 文件,无外部依赖项,一个简单的 hello world 程序的 210 KiB x86 代码。
•启动时间极短的快速解释器:在台式 PC 的单核上运行 ECMAScript 测试套件的 76000 次测试只需不到 2 分钟。 运行时实例的完整生命周期在不到 300 微秒的时间内完成。
•几乎完整的 ES2023 支持,包括模块、异步生成器和完整的附录 B 支持(旧版 Web 兼容性)。
•通过了近 100% 的 ECMAScript 测试套件测试: Test262 Report(https://test262.fyi/#)。
•可以将 Javascript 源代码编译为可执行文件,无需外部依赖。
•使用引用计数(以减少内存使用并具有确定性行为)和循环删除的垃圾收集。
•数学扩展:BigDecimal、BigFloat、运算符重载、bigint 模式、数学模式。
•用 Javascript 实现的带有上下文着色的命令行解释器。
•带有 C 库包装器的小型内置标准库。
3.QuickJS工程简介
5.94MB quickjs
├── 17.6kB cutils.c /// 辅助函数
├── 7.58kB cutils.h /// 辅助函数
├── 241kB libbf.c /// BigFloat相关
├── 17.9kB libbf.h /// BigFloat相关
├── 2.25kB libregexp-opcode.h /// 正则表达式操作符
├── 82.3kB libregexp.c /// 正则表达式相关
├── 3.26kB libregexp.h /// 正则表达式相关
├── 3.09kB list.h /// 链表实现
├── 16.7kB qjs.c /// QuickJS stand alone interpreter
├── 22kB qjsc.c /// QuickJS command line compiler
├── 73.1kB qjscalc.js /// 数学计算器
├── 7.97kB quickjs-atom.h /// 定义了javascript中的关键字
├── 114kB quickjs-libc.c
├── 2.57kB quickjs-libc.h /// C API
├── 15.9kB quickjs-opcode.h /// 字节码操作符定义
├── 1.81MB quickjs.c
├── 41.9kB quickjs.h /// QuickJS Engine
├── 49.8kB repl.js /// REPL
├── 218kB libunicode-table.