跨端轻量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.