《WebKit 技术内幕》学习之九(3): JavaScript引擎
3 JavaScriptCore引擎
3.1 原理
JavaScriptCore引擎是WebKit中的默认JavaScript引擎,也是苹果在开源WebKit项目之后,开源的另外一个重要的项目。同其他很多引擎一样,在刚开始的时候它的主要部分是一个基于抽象语法树的解释器,这使得它的性能实在太差。
从2008年开始,JavaScriptCore引擎开始一个新的优化工作,重新实现了编译器和字节码解释器,这就是SquirrelFish。该工作对于引擎的性能优化做了比较大的改进。随后,苹果内部代号为“Nitro”的JavaScript引擎也是基于JavaScriptCore项目的,它的性能还是非常出色的,鉴于其是内部项目,所以具体还有什么特别的处理就不得而知了。在这之后,开发者们又将内嵌缓存、基于正则表达式的JIT和简单的JIT引入到JavaScriptCore中。然后,又陆续加入了字节码解释器。可以看出,JavaScriptCore引擎也在不断地高速发展中。
3.2 架构和模块
3.2.1 代码结构
根据JavaScriptCore项目的代码结构和之前介绍的引擎的工作过程,读者大概可以猜测出代码结构中到底有哪些主要模块和基本的工作了,因为该结构划分的粒度比V8项目细致多了,还是比较容易理解的,如图9-20所示的代码结构目录。
图9-20 JavaScriptCore代码结构
从代码目录中,我们可以猜测并理解它的演进过程:首先是词法和语法分析,然后使用底层解释器来解释那些字节码。之后,通过简单的JIT编译器将它们转化成本地代码。还没结束,最后就是引入DFG JIT编译器。
这些目录直接跟即将介绍的各个技术有很好的对应关系,读者先有个大致的理解,这样对后面的介绍大有帮助,感兴趣的读者还可以去查找源码来有个基本的认识。
3.2.2 数据表示
JavaScriptCore引擎同样使用句柄来表示数据,对于简单类型的数据则直接包含在句柄中,而对于对象来说,则使用指针来指向数据在堆中的位置。同V8引擎不同的是,在32位和64位机器上,句柄都是使用64位来表示的,图9-21分别描述了两种平台上各种类型的表示和识别方式。
图9-21 句柄的定义和各种类型的表示方式
首先在32位平台上,每个句柄都是使用两个32位数据来表示。对于整数、布尔和指针而言,前面32位用来标记它们,后面32位用来表示这些数据。对于双浮点,前32位在区间FFFFFFF8~00000000都是用来表示浮点类型,可能稍微比原来的双浮点表示范围小一些,但是,这个范围已经足够使用了。同样在64位机器上,因为标记指针需要64位,只好使用前面16位(0000),而后面的48位用来表示地址,读者可能觉得这样就没有64位表示指针,但是实际上48位已经足够。
同V8引擎相比,JavaScriptCore引擎因为在32位上使用64位来表示句柄,所以除了小整数之外,对于浮点类型同样可以不需要访问堆中的数据,当然,缺点就是每个句柄都需要2倍的内存空间。
3.2.3 模块
同V8一样的是,JavaScriptCore引擎在开源之后也引入了众多新技术。不过,JavaScriptCore引擎与V8相比还是有很多不同之处的,最典型的就是它使用了字节码的中间表示,并加入了多层JIT编译器帮助改善性能,不停地优化编译之后的本地代码。当然JavaScriptCore在不停地演进的过程中,目前的实现跟之前的实现差别非常大,所以这里介绍的是基于目前的结构的,在未来,可能还会有很多其他的变化,让我们拭目以待。
第一,不同于V8引擎,JavaScriptCore引擎不是从抽象语法树生成本地代码,而是生成平台无关的字节码,如图9-22所示。JavaScriptCore引擎自己定义了一套字节码规范,该字节码与平台无关,而且有了该字节码,JavaScriptCore就可以基于其进行很多在抽象语法树之上不能或者很难做到的优化。读者需要记住的是,不同于V8,在这之后,因为有了字节码,所以JavaScriptCore就不再需要JavaScript源代码,而V8使用Crankshaft编译器进行进一步优化,则需要继续从JavaScript源代码重新开始。
图9-22 JavaScriptCore中从源代码到字节码
第二,在字节码之后,JavaScriptCore依然包含了字节码解释器,这点也类似于Java虚拟机中的解释器,它们都能够解释字节码然后生成结果。而不同于Java虚拟机中的解释器的是,JavaScriptCore是基于虚拟寄存器(Virtual Register)的虚拟机,而Java是基于栈式(Stack)的虚拟机。这一解释器很有必要,因为一些JavaScript代码不需要经过很强的优化,只需要直接执行即可,复杂的处理可能带来额外开销反而抵消了优化带来的全部好处,如图9-23所示。同时,在字节码执行期间,信息收集器会收集热点函数,以方便之后的JIT编译器做之后的优化处理。图中的信息收集器1之所以加上“1”,是为了区别JavaScriptCore中包含的各种各样的信息收集器。
图9-23 JavaScriptCore从字节码到解释器和信息收集器
第三,JavaScriptCore引擎在获悉热点函数后,需要对它们进行优化,就会使用到简单(Baseline)JIT编译器,该编译器根据信息收集器1中的信息,将对应函数的字节码翻译成本地代码,不仅因为时间问题,而且并不是所有代码都合适做深层次的优化,所以这里没有做特别多的优化,而是直接做转换。图9-24描述了这一过程。在实行这些本地代码的时候,会有信息收集器2来收集代码并作做一步的优化。
图9-24 JavaScriptCore的简单JIT编译器
第四,如果你认为只需要JIT编译器就够了,那就错了,简单的JIT编译器并不能满足性能的要求,特别是对V8的Crankshaft编译器来说,性能差距就显现出来了。为了提高性能,JavaScriptCore中又引入了DFG(Data-Flow Graph)JIT编译器,该编译器是在字节码基础上,生成基于SSA(Static Single Assignment)的中间表示(IR)。当然具体哪些字节码需要重新生成优化的本地代码,就依赖之前的信息收集器2,如图9-25所示。优化后的本地代码相比之前的代码,对于性能有很好的提升。
图9-25 JavaScriptCore的DFG JIT编译器
第五,要是你认为这样就足够了,那就更错了。在笔者介绍JavaScriptCore的时候,该项目依然在进行一项更为大胆的工作,就是将LLVM技术引入到JavaScriptCore。那么LLVM是什么呢?LLVM是一个由苹果公司发起的开源项目,其开发和灵活的架构受到越来越多人的关注。
LLVM是一个编译器,能够将多个不同的前端语言转化成不同的后端本地代码,图9-26描述了LLVM的基本结构,该编译器在前端和后端都能做优化,这些优化都是可配置的,所以非常灵活。同时,随着该项目越来越成功,加入的优化也越来越多。JavaScriptCore希望将LLVM编译器的中间表示引入其中,这样将很容易将这些优化使用在该引擎中,图9-27描述了这一过程。
图9-26 LLVM基本结构
图9-27 使用LLVM技术的JIT编译器
这一过程是基于DFG JIT中间表示开始的,为了节省时间,使用了并行编译算法。之后,生成LLVM的中间表示,这样就可以使用LLVM中间表示之后的众多优化,而且可以按需配置它们。这一过程仅仅对于那些最热点的函数使用,因为其层次太多,消耗的时间更多,所以慎用。这一技术目前还在开发中,未来效果如何还未可知,不过相信对于某些特定的例子会有不少好处。
为什么不直接使用优化性能最好的编译器呢?原因是优化越好通常需要的分析和生成代码的时间就越长。读者回忆之前介绍的应用场景就会发现,如果用户使用的是利用C/C++编译的代码,那么编译时间长一点问题不大,因为是开发者在编译他们。而对于JavaScript来说,编译时间越长,对用户来说同样,等待的时间更长,效果可能也未必会好。这就是一把双刃剑,所以该方法只限定在特定的范围内使用。
3.4 内存管理
在JavaScriptCore中,内存管理和垃圾回收机制也随着其他技术的改变而发生着很大的变化。对于垃圾回收机制来说,最重大的改变就是像V8一样,引入了分代垃圾回收机制。所以,堆也会被分成几个分代。这样,当进行垃圾回收的时候,就不需要对所有对象进行标记。分代技术前面也讨论过了,而且很早就在其他虚拟机中使用,如Java虚拟机,它们思想都是类似的,这里不再赘述。
在V8中使用Zone来一次性释放内存,JavaScriptCore中也有类似的机制,那就是JSGlobalData,这里也不再过多的描述。
3.5 绑定
JavaScriptCore同样能够提供绑定机制,目前渲染引擎同样是通过该机制访问DOM的操作函数,这点跟V8非常像。本质上,它们都是提供额外的JavaScript接口来扩展JavaScript引擎的能力。同样,我们将在下一章做详细介绍。
3.6 比较JavaScriptCore和V8
由于JavaScriptCore一直是Webkit的默认JavaScript引擎,所以被广泛应用。但是,随着Google发布Chrome的同时加上V8引擎,而且V8自出现后就是以性能作为目标,引入了众多新颖的技术,确实极大地推动了整个业界的JavaScript引擎性能的快速发展。但是,如果想用一句话说明V8和JavaScriptCore的优劣,这是很困难的。在很多领域,V8扮演着冲锋者的角色,但是JavaScriptCore依旧不断改进自己的技术和实现,同时在某些方面,因为使用了一些V8没有的东西,如字节码反而在某些情况下较容易优化。当然,这也不是绝对的。
关于各个技术细节,例如内部代码表示、解释器、JIT、句柄数据表示等方面,我们在前面都一一做了介绍,读者可以回忆一番。我们前面已经介绍了以上两个引擎的很多特点和好处,笔者还希望留一些想象的空间,让读者自己体会上面这些技术细节带来的潜在优势和缺点,以及潜在的发展方向。
相关文章:
《WebKit 技术内幕》学习之九(3): JavaScript引擎
3 JavaScriptCore引擎 3.1 原理 JavaScriptCore引擎是WebKit中的默认JavaScript引擎,也是苹果在开源WebKit项目之后,开源的另外一个重要的项目。同其他很多引擎一样,在刚开始的时候它的主要部分是一个基于抽象语法树的解释器,这…...
IS-IS:05 ISIS开销值和协议优先级
IS-IS 协议为路由器的每个 IS-IS 接口定义并维护了一个 level-1 开销值和一个 level-2开销值。开销值可以在接口上或者全局上手动配置,也可以使用 auto-cost自动计算确定。 修改接口cost: int g0/0/0 isis cost 50修改全局cost: isis cir…...
群辉NAS的远程访问
群辉NAS是私有云存储,局域网访问很容易【详见:网上邻居访问设置、其它设备的访问设置】,远程访问相对复杂,涉及很多关键因素,现将过程记录如下: 目录 1、互联网接入 2、绑定MAC与IP地址 3、路由器开启5…...
构建未来学堂:在线教育系统开发技术实践
在当今数字化时代,在线教育系统的开发越发显得至关重要。本文将带你深入了解在线教育系统的开发,涉及到关键的技术实践和代码示例。我们将采用现代化技术栈,为未来学堂的搭建提供实用的指南。 技术栈选择 在开始实际的开发之前,…...
EMQX 单机及集群搭建
目录 1. 通过 Yum 源安装(CentOS7 单机安装) 1.1. 通过以下命令配置 EMQX Yum 源: 1.2. 运行以下命令安装 EMQX: 1.3. 运行以下命令启动 EMQX: 1.4. 访问 http://192.168.88.130:18083,默认用户名: adm…...
SpringMVC-对静态资源的访问
1.工程中加入静态资源 在webapp下创建static文件夹,此文件夹专门放入静态资源 2.使项目可以处理静态资源的请求 在SpringMVC配置文件中添加以下语句 1.引入命名空间 xmlns:mvc"http://www.springframework.org/schema/mvc" xsi:schemaLocation“http…...
形参和实参
目录 形参(形式参数): 实参(实际参数): 形参和实参的区别和联系 具体实例: 当我们谈论"形参"和"实参"时,可以用以下类比来解释它们之间的关系: 形参…...
[git] windows系统安装git教程和配置
一、何为Git Git(读音为/gɪt/)是一个开源的分布式版本控制系统,可以有效、高速地处理从很小到非常大的项目版本管理。 二、git安装包 有2种版本,Git for Windows Setup和Git for Windows Portable(便携版)两个版本都可以。 三、Git for Windows Por…...
php的性能要比node.js高很多吗?
在当今的编程世界中,PHP和Node.js是两种广泛使用的服务器端编程语言。虽然它们都用于构建高效的网络应用程序,但关于它们性能的争论一直存在。有些人认为PHP的性能要比Node.js高很多,而另一些人则持相反意见。 性能通常指的是计算机程序或系…...
[极客大挑战 2019]BabySQL1
发现union select被过滤了,双写绕过 or、from被过滤 where被过滤 在b4bysql中找到flag...
机器视觉在OCR字符检测的应用
在产品质量 检测过程中,对于字符、条码等标识信息的识别、读取、检测是非常重要的一部分,比如在食品饮料包装检测中,生产日期 、保质期 、生产批号 、条码等字符信息是产品管理和追溯必不可缺的,因此利用机器视觉技术进行OCR字符采…...
讲清楚浅拷贝和深拷贝
先放出实现浅拷贝和深拷贝的一些方法(直接食用): 1.浅拷贝: 浅拷贝在拷贝对象的时候,对于对象最外一层实现的是普通的值拷贝,对于对象里面的对象是浅拷贝,只复制地址不复制地址对应的值。 /* 方法1.1:扩…...
[足式机器人]Part2 Dr. CAN学习笔记- 最优控制Optimal Control Ch07
本文仅供学习使用 本文参考: B站:DR_CAN Dr. CAN学习笔记 - 最优控制Optimal Control Ch07-1最优控制问题与性能指标 1. 最优控制问题与性能指标2. 动态规划 Dynamic Programming2.1 基本概念2.2 代码详解2.3 简单一维案例 3. 线性二次型调节器ÿ…...
RedisInsight详细安装教程
简介 RedisInsight 是一个直观高效的 Redis GUI 管理工具,它可以对 Redis 的内存、连接数、命中率以及正常运行时间进行监控,并且可以在界面上使用 CLI 和连接的 Redis 进行交互(RedisInsight 内置对 Redis 模块支持)。 RedisIn…...
maven组件升级报错经验汇总
1. NosuchMethodError org.springframework.beans.factory.support.genericBeanDefinition(xxxxx) 2. ClassNotFoundException: org.springframework.boot.SpringApplication 可能冲突的依赖是: <dependency><groupId>org.springframework.boot</g…...
JS 中的 async 与 await
课程地址 有 4 个返回 Promise 对象的函数 ABCD,现在想让这 4 个 Promise 顺序执行: const isA true; const isB true; const isC true; const isD true;function A() {return new Promise((resolve, reject) > {console.log("running A&q…...
SQL 系列教程(六)
目录 SQL FOREIGN KEY 约束 SQL FOREIGN KEY 约束 创建表时的 FOREIGN KEY 约束 修改表时的 FOREIGN KEY 约束 撤销 FOREIGN KEY 约束 SQL CHECK 约束 SQL CHECK 约束 创建表时的 CHECK 约束 修改表的 CHECK 约束 撤销 CHECK 约束 SQL DEFAULT 约束 SQL DEFAULT 约…...
CocoaPods的安装和使用
前言 本篇文章讲述CocoaPods的安装和使用 安装cocoaPods 如果电脑没有安装过cocoaPods,需要先安装,使用下面的命令: sudo gem install cocoapods输入密码后开始安装,需要等待。。。但是我这里报错了。 The last version of d…...
Linux下软件安装的命令【RPM,YUM】及常用服务安装【JDK,Tomcat,MySQL】
Linux下软件安装的命令 源码安装 以源代码安装软件,每次都需要配置操作系统、配置编译参数、实际编译,最后还要依据个人喜好的方式来安装软件。这个过程很麻烦很累人。 RPM软件包管理 RPM安装软件的默认路径: 注意: /etc 配置文件放置目录…...
【linux】-telnet服务安装
1. 说明 telnet 分为 :telnet 服务端 和 telnet 客户端 本文只演示安装 telnet服务端 2. 安装telnet服务端、以及守护服务xinetd 2.1 检测telnet-server的rpm包是否安装 rpm -qa telnet-server 2.2 若未安装,则安装telnet-server࿰…...
安卓开发——Activity及常用布局和控件的使用
Activity及常用布局和控件的使用 一、实验目的 掌握Android常用布局和控件的使用。 Activity组件使用和Intent机制,加强对Activity生命周期的理解 二、实验设备及器件 Android Studio,图标:http://10.37.59.210/download/icon/MobileShopI…...
.net访问oracle数据库性能问题
问题: 生产环境相同的inser语句在别的非.NET程序相应明显快于.NET程序,执行时间相差比较大,影响正常业务运行,测试环境反而正常。 问题详细诊断过程 问题初步判断诊断过程: 查询插入慢的sql_id 检查对应的执行计划…...
vue上传解析excel表格并修改字段名
目录 1.安装 xlsx 2.引入 3.使用 1.安装 xlsx npm install xlsx 2.引入 import * as XLSX from xlsx; 3.使用 <template><div class"UploadCptOutbox"><div class"Tooloutbox"><el-uploadclass"upload"ref"u…...
jupyter notebook删除kernel & conda 删除虚拟环境
jupyter kernelspec list #列出jupyter的所有kernel jupyter kernelspec remove kernel_name #删除特定的kerneljupyter kernelspec list 命令可以在任何激活的环境中运行,无论是 base 环境还是某个虚拟环境。该命令将列出所有已注册的 Jupyter 内核,包括…...
Redis在生产环境中可能遇到的问题与解决方案(三)
11. Redis高可用问题 问题描述 在Redis集群中,当主节点发生故障时,需要快速切换到备用主节点,确保系统高可用。 解决方案 Redis Sentinel: 使用Redis Sentinel进行主从节点的监控和自动故障转移。 备用主节点: 配置…...
【C++干货铺】 RAII实现智能指针
个人主页点击直达:小白不是程序媛 C系列专栏:C干货铺 代码仓库:Gitee 目录 为什么需要智能指针? 内存泄漏 什么是内存泄漏,内存泄露的危害 内存泄漏的分类 堆内存泄漏(Heap leak) 系统资…...
【竞技宝jjb.lol】LOL:xiaohu岩雀天命抢龙扭转乾坤 WBG2-0轻取RA
北京时间2024年1月26日,英雄联盟LPL2024春季赛在昨天迎来第一周第四个比赛日,本日首场比赛由WBG对阵RA。本场比赛RA虽然在首局前期给了WBG很大的压力,但WBG还是凭借后期出色的团战配合拿下胜利,最终WBG2-0轻取RA。以下是本场比赛的…...
GoZero微服务个人探究之路(九)api文件编写总结
参考来源go-zero官方文档https://go-zero.dev/docs/tutorials 前言 go-zero是目前star最多的go语言微服务框架,api 是 go-zero特殊的语言,类型文件,go-zero自带的goctl可以通过.api文件生成http服务代码 api文件内容编写 不可使用关键字 …...
泛型..
1.泛型 所谓泛型 在类定义处是一种类型参数(我们平常所见到的参数指的就是方法中的参数 他接收有外界传递来的值 然后在方法中进行使用) 在类内部的话 则充当一种占位符 并且还提高了代码的复用率 何以见得提高了代码的复用率 其实就是通过对比使用了泛型技术和没有使用泛型技…...
Android App开发基础(1)—— App的开发特点
本文介绍基于Android系统的App开发常识,包括以下几个方面:App开发与其他软件开发有什么不一样,App工程是怎样的组织结构又是怎样配置的,App开发的前后端分离设计是如何运作实现的,App的活动页面是如何创建又是如何跳转…...
wordpress个人博客动漫主题/互联网广告行业
第一种:解决HTML中中文乱码问题方法如果你的HTML文件文件出现了乱码问题,那么你可以在head标签里面加入UTF8编码(国际化编码):UTF-8是没有国家的编码,也就是独立于任何一种语言,任何语言都可以使用的。第二种ÿ…...
太原seo网站建设/自助建站网站哪个好
此为记录下我自己的爬虫学习过程。 利用url包抓取网页 import urllib.request #url包 def main(): url "http://www.douban.com/" response urllib.request.urlopen(url) #请求 html response.read() #获取 html html.decode("utf-8") #解码 print(htm…...
风景区网站建设项目建设可行性/培训机构网站制作
1.HTTPS对称加密 服务器每次发送真实数据前,会先生成一把密钥传输(以明文方式传输密钥容易被劫持)给客户端,服务器给客户端发送的真实数据会先用这把密钥进行加密,客户端收到加密数据后再用密钥进行解密(客户端给服务器发送数据同理) 2.HTTP…...
响应式网站制作软件/网络推广外包哪个公司做的比较好
东财《计算机应用基础》单元作业二pR6奥鹏作业学习网(aopeng123.cn)1.[单选题] 密码技术主要是用来( )pR6奥鹏作业学习网(aopeng123.cn)奥鹏 pR6奥鹏作业学习网(aopeng123.cn)A.实现信息的可控性pR6奥鹏作业学习网(aopeng123.cn)B.实现信息的保密性pR6奥鹏作业学习网(aopeng1…...
海外网站太慢/广告优化师发展前景
美颜相机---AI 发型管家效果的算法解析 ####前言 本文为去年写的Gitchat文章,由于Gitchat有时间版权限制,一年时间,所以今天才能发布到CSDN博客上来。 本文为大家介绍美颜相机中 AI 发型管家效果的算法解析,当然,本…...
高端网站开发建设/企业qq和个人qq有什么区别
一.如果项目采用的是动态数据源,根据配置检查是否存在依赖 <!-- 动态数据源 --><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>3.4.1</version><…...