我是靠谱客的博主 伶俐期待,最近开发中收集的这篇文章主要介绍JavaScript引擎实现,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

转自 http://rednaxelafx.iteye.com/


现代JavaScript引擎都有哪些特征呢?跟以前的JavaScript引擎有怎样的差别,为什么变快了那么多?这里简单写下我的理解吧。

有很多同学可能会想从JavaScript引擎的源码着手一探究竟。这里也顺便介绍一下JavaScript引擎大致的组成部分与工作流程。了解这其中涉及的各种术语都是什么意思的话,读源码就能事半功倍,很多时候光看文件名就足以定位到自己关心的那部分实现。 <- TODO

早期JavaScript引擎的实现普遍跟同时代的其它脚本语言一样,比较“偷懒”。反正是“脚本语言”,当时的JavaScript脚本通常只包含很简单的逻辑,只运行很短时间就完事。没啥性能压力,得不到足够的重视与开发资源,性能自然是好不到哪里去,却也足以满足当时的需求。

非常早期的“Mocha”引擎实现得确实非常偷懒。字节码解释器、引用计数方式的自动内存管理、fat discriminated union形式的值表现形式。现在随便找本教写玩具语言实现的书上或许就会这么教…但只能用来写玩具 犀牛书第4版写了点JavaScript与引用计数的历史。
到1996年,Brendan Eich新写的SpiderMonkey已经改为使用mark-and-sweep GC、tagged value。

于是其实早期的两个主要的JavaScript引擎实现,Mozilla SpiderMonkey和Microsoft JScript其实都一直在用mark-and-sweep GC。也没啥别的主流JavaScript引擎用过引用计数方式来实现自动内存管理的。这点别被忽悠了。在叫得出名字的JavaScript引擎里只有quad-wheel(没听说过么?不奇怪,非主流嘛)是用引用计数方式实现自动内存管理的。
(老版本IE里JScript虽说是有因为循环引用而导致内存泄漏的问题,但那不是因为JScript自身用引用计数。问题出在JScript与DOM交互的边界上:IE的DOM节点(及其它host对象)是COM对象,而COM对象自身是引用计数的。这导致JScript与DOM交互时有可能被连累引发循环引用->内存泄漏的问题。IE9/Chakra里已经通过把DOM对象变成由JavaScript一侧来管理解决了这个问题。)

几种较老的JavaScript引擎的特征:

 SpiderMonkeyJScriptKJS
实现语言CC++C++
执行模式解释执行解释执行解释执行
解释器字节码解释器:基于栈的字节码字节码解释器:基于栈的字节码树遍历解释器
动态编译器
自动内存管理mark-and-sweepmark-and-sweepmark-and-sweep
对象布局?基本上是HashTable?
针对密集数组的优化?无 (JScript < 5.7);有(JScript 5.8)?
Inline-cache???
值表现形式tagged-value堆对象堆对象
Function.prototype.toString()从字节码反编译??

(几个术语:
树遍历解释器:tree-walking interpreter。遍历抽象语法树来解释执行的解释器。
对象布局: object representation 或者 object layout。指在堆上分配的JavaScript对象的在内存中的布局。
值表现形式: value representation。注意跟“对象布局”说的不是一件事。这个指的是原始类型数据、指向堆上分配的对象的指针之类的值的表现形式。对某些JavaScript引擎来说这是指“JSValue”背后在内存中的表现形式。

TODO 加上对parser的描述
SpiderMonkeyKJSJavaScriptCoreV8Managed JScript
手写纯递归下降式bison生成LALR(1)bison生成的LALR(1)手写的递归下降+运算符优先级混合式手写的纯运算符优先级式


早期JavaScript引擎得到的投入实在不足,而当时的Java虚拟机(JVM)却得到了大量资源实现各种优化,包括JIT编译器之类。这使得用Java写的Rhino一度能比用C写的SpiderMonkey跑得还快,因为Rhino得益于JVM里优秀的JIT编译器和GC,而SpiderMonkey还在用简易的解释器和GC。

这个阶段中,JavaScript对象的布局或者说表现方式通常可以叫做“property bag”,本质上就跟hashmap一样。

在Google推出V8之后,业界受到巨大冲击。V8的性能远高于当时所有其它JavaScript引擎,可以有效支撑起当时兴起的大量使用JavaScript的Web应用。
各大JavaScript引擎的实现者都坐不住了,像打了鸡血似的使劲优化优化再优化。先是把已在其它HLLVM上得到充分验证的优化技术引入到JavaScript引擎中,然后再针对JavaScript语言的特点做专项优化。

现在(2013-04)几种主流的JavaScript引擎的特征:
 V8SpiderMonkeyChakraNitroNashorn
实现语言C++/汇编C++C++C++/汇编Java
执行模式纯编译: 两层编译解释/编译混合式: 3层执行模式解释/编译混合: 2层执行模式,后台编译解释/编译混合: 3层执行模式纯编译
解释器字节码解释器字节码解释器:基于寄存器的字节码字节码解释器 LLInt:基于寄存器的字节码
动态编译器初级编译器 + 优化编译器初级编译器 Baseline + 优化编译器 IonMonkey初级编译器 method JIT + 优化编译器 DFG JIT
自动内存管理分代式GC: 初生代: copying收集器; 年老代: 增量式mark-and-sweep, 可选compact分代式GC分代式GC: 初生代: copying收集; 年老代: 并发式mark-and-sweep分代式GC依赖于底层JVM的GC
对象布局紧凑+隐藏类 Map紧凑+隐藏类 Shape紧凑+隐藏类紧凑+隐藏类 Structure紧凑+隐藏类 PropertyMap
针对密集数组的优化
Inline-cacheMIC/PICPICPICPICMIC/PIC
值表现形式tagged-pointer / IEEE 754 double / integerpun-boxingtagged-valueNaN-boxing  堆对象 / integer
正则表达式编译 Irregexp编译编译编译 WREC混合
Function. prototype. toString()保留源码原文(2012年7月前) 从字节码反编译; (761723后) 保留源码原文 ??保留源码原文

(几个缩写:
copying GC: 也叫 scavenger。
MIC: monomorphic inline-cache
PIC: polymorphic inline-cache
pun-boxing: Packed NaN unboxing)

SpiderMonkey和LuaJIT似乎都在用pun boxing

所以说这年头是个JavaScript引擎都得有JIT编译器了…没有都不好意思出来混。受到平台限制(例如iOS、Windows Phone)而无法实现JIT编译器的“第三方JavaScript引擎“只好哭了。

TODO

最后

以上就是伶俐期待为你收集整理的JavaScript引擎实现的全部内容,希望文章能够帮你解决JavaScript引擎实现所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部