Fabrice 又一新作 QuickJs
作者简介
Fabrice Bellard 是个神一般的程序员,这是他的个人主页 https://bellard.org/ ,里面的每一个作品都惊为天人而且对计算机科学领域具有深远影响,以下是他的生平:
- 1972年生于法国格勒诺布尔(Grenoble)。在高中就读期间开发了著名的可执行压缩程序LZEXE,这是当年DOS上第一个广泛使用的文件压缩程序。大学就读于巴黎综合理工学院,后在巴黎高等电信学校攻读。
- 1996年,他编写了一个简洁但是完整的C编译器和一个Java虚拟机Harissa。Fabrice Bellard发明的TinyCC是GNU/Linux环境下最小的ANSI C语言编译器,是目前号称编译速度最快的C编译器。
- 1997年他提出了最快速的计算圆周率的算法,是贝利-波尔温-普劳夫公式的变体。在计算圆周率的过程中,Fabrice Bellard使用改良后的查德诺夫斯基方程算法来进行圆周率的计算,并使用贝利-波尔温-普劳夫公式来验证计算的结果。为了纪念他对圆周率算法所作出的杰出贡献,Fabrice Bellard所使用的改良型算法被命名为Fabrice Bellard算法,这种算法是目前所有圆周率算法中最快的一种,这个计算N位PI的公式比传统的BBQ算法要快47%。
- 1998年编写了一个简洁的OpenGL实现TinyGL。
- 2000年,他化名Gérard Lantau,创建了FFmpeg项目。FFmpeg单词中的FF指的是Fast Forward,FFmpeg这个2000年发起著名的开源多媒体播放器项目,是MPlayer的姊妹项目。这是一个如此重要的成就。这个多平台、多功能的多媒体编码解码器由Fabrice Bellard发起并管理,现在是由Michael Niedermayer在进行维护。
- 2003年,开发了Emacs克隆QEmacs。
- 2004年,他编写了一个只有138KB的启动加载程序TCCBOOT,可以在15秒内从源代码编译并启动Linux系统。
- 2005年,用普通PC和VGA卡设计了一个数字电视系统。
- 2009年12月31日,他声称打破了圆周率计算的世界纪录,算出小数点后2.7万亿位,仅用一台普通个人电脑。他使用的个人PC价格不到2000欧元,仅用了116天,就计算出了PI的小数点后第2.7万亿位,超过了由目前排名世界第47位的T2K Open超级计算机于2009年8月17日创造的世界纪录。新纪录比原纪录多出1200亿位,然而,他使用的这台桌面电脑的配置仅为:2.93GHz Core i7 CPU,6GB内存,7.5TB硬盘。
- 2011年,他使用JavaScript写了一个PC虚拟机Jslinux。这个虚拟机仿真了一个32位的x86兼容处理器,一个8259可编程中断控制器,一个8254可编程中断计时器,和一个16450 UART。
- 2012年,在PC上用软件实现4G LTE基站。
QuickJs
最近,这位大佬的新作品 QuickJs
又火了,这个用 C89 写的只有几万行代码的 JS 引擎,居然通过了 Test262 96% 的测试,仅次于 V8 的 97%,ChakraCore (Edge) 只有 65%。新特性的通过率高达 89%, 仅次于 V8 的 90%,ChakraCore (又躺枪) 只有 16%。

QuickJs Runtime 使用的是 栈虚拟机,内部采用引用计数的方式实现 gc。
Quick Start
去大佬的主页下载压缩包(大佬的页面就是这么朴实无华且枯燥)
https://bellard.org/quickjs/根目录下有 Makefile,直接 make 编译即可
编译完生成了一个
qjs
,一个qjsc
,中文说明可以参考这篇文档
https://github.com/quickjs-zh/QuickJS/blob/master/README.md
qjs
qjs 本身可以直接执行 Javscript 代码:
$ ./qjs test.js
也可以像 d8、node 那样运行 REPL:
$ ./qjs
QuickJS - Type "\h" for help
qjs > const a = 5;
undefined
qjs > a++;
TypeError: 'a' is read-only
at <eval> (<evalScript>)
qjsc
qjsc 可以把 JavaScript 编译成字节码,然后输出成 C 文件,像这样:
./qjsc -e -o hello.cc examples/hello.js
/* File generated automatically by the QuickJS compiler. */
#include "quickjs-libc.h"
const uint32_t qjsc_hello_size = 87;
const uint8_t qjsc_hello[87] = {
0x02, 0x04, 0x0e, 0x63, 0x6f, 0x6e, 0x73, 0x6f,
0x6c, 0x65, 0x06, 0x6c, 0x6f, 0x67, 0x16, 0x48,
0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72,
0x6c, 0x64, 0x22, 0x65, 0x78, 0x61, 0x6d, 0x70,
0x6c, 0x65, 0x73, 0x2f, 0x68, 0x65, 0x6c, 0x6c,
0x6f, 0x2e, 0x6a, 0x73, 0x0e, 0x00, 0x06, 0x00,
0xa0, 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00,
0x14, 0x01, 0xa2, 0x01, 0x00, 0x00, 0x00, 0x38,
0xe0, 0x00, 0x00, 0x00, 0x42, 0xe1, 0x00, 0x00,
0x00, 0x04, 0xe2, 0x00, 0x00, 0x00, 0x24, 0x01,
0x00, 0xce, 0x28, 0xc6, 0x03, 0x01, 0x00,
};
int main(int argc, char **argv)
{
JSRuntime *rt;
JSContext *ctx;
rt = JS_NewRuntime();
js_std_init_handlers(rt);
ctx = JS_NewContextRaw(rt);
JS_AddIntrinsicBaseObjects(ctx);
js_std_add_helpers(ctx, argc, argv);
js_std_eval_binary(ctx, qjsc_hello, qjsc_hello_size, 0);
js_std_loop(ctx);
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
return 0;
}
或者直接编译成一个可执行文件:
$ ./qjsc -o hello examples/hello.js
详细参数参考这篇 中文文档