[前端] V8引擎编译原理

文章目录

      • 1.什么是V8
        • 1.1 扫描器Scanner
        • 1.2 解析器parser
        • 1.3 预解析PreParser
        • 1.4 解释器Ignition
        • 1.5 编译器TurboFan

1.什么是V8

V8是谷歌的开源高性能JavaScript和WebAssembly引擎,用C++编写。它被用于Chrome和Node.js等。它实现ECMAScript和WebAssembly,并在Windows 7或更高版本、macOS 10.12+以及使用x64、IA-32、ARM或MIPS处理器的Linux系统上运行。V8可以独立运行,也可以嵌入到任何C++应用程序中。

在这里插入图片描述

  • 扫描器Scanner

  • 解析器Parser

  • 预解析PreParser

  • 解释器Ignition

  • 编译器TurboFan

在这里插入图片描述

1.1 扫描器Scanner

Blink(谷歌浏览器的渲染引擎,基于webkit分支开发)主要负责HTML DOM CSS 渲染,嵌入V8引擎,执行js,计算样式和布局,嵌入合成器,绘制图形。

Blink 拿到html代码分析,找到script代码交给V8引擎解析,注意Blink是通过流的形式传给V8的。

通过以流的形式传输数据,Blink可以逐步接收和处理来自网络的字节流,并在需要时将相应的数据传递给V8引擎执行。这种流式处理方式使得浏览器可以在数据到达的同时并行处理不同的任务,提高了页面的加载速度和用户体验

Scanner(扫描器)首先会进行词法分析:

V8_INLINE Token::Value Scanner::ScanSingleToken() {Token::Value token;do {next().location.beg_pos = source_pos();if (V8_LIKELY(static_cast<unsigned>(c0_) <= kMaxAscii)) {token = one_char_tokens[c0_];switch (token) {case Token::LPAREN:case Token::RPAREN:case Token::LBRACE:case Token::RBRACE:case Token::LBRACK:case Token::RBRACK:case Token::COLON:case Token::SEMICOLON:case Token::COMMA:case Token::BIT_NOT:case Token::ILLEGAL:// One character tokens.return Select(token);case Token::CONDITIONAL:// ? ?. ?? ??=Advance();if (c0_ == '.') {Advance();if (!IsDecimalDigit(c0_)) return Token::QUESTION_PERIOD;PushBack('.');} else if (c0_ == '?') {return Select('=', Token::ASSIGN_NULLISH, Token::NULLISH);}return Token::CONDITIONAL;case Token::STRING:return ScanString();case Token::LT:// < <= << <<= <!--Advance();if (c0_ == '=') return Select(Token::LTE);if (c0_ == '<') return Select('=', Token::ASSIGN_SHL, Token::SHL);if (c0_ == '!') {token = ScanHtmlComment();continue;}return Token::LT;case Token::GT:// > >= >> >>= >>> >>>=Advance();if (c0_ == '=') return Select(Token::GTE);if (c0_ == '>') {// >> >>= >>> >>>=Advance();if (c0_ == '=') return Select(Token::ASSIGN_SAR);if (c0_ == '>') return Select('=', Token::ASSIGN_SHR, Token::SHR);return Token::SAR;}return Token::GT;case Token::ASSIGN:// = == === =>Advance();if (c0_ == '=') return Select('=', Token::EQ_STRICT, Token::EQ);if (c0_ == '>') return Select(Token::ARROW);return Token::ASSIGN;case Token::NOT:// ! != !==Advance();if (c0_ == '=') return Select('=', Token::NE_STRICT, Token::NE);return Token::NOT;case Token::ADD:// + ++ +=Advance();if (c0_ == '+') return Select(Token::INC);if (c0_ == '=') return Select(Token::ASSIGN_ADD);return Token::ADD;case Token::SUB:// - -- --> -=Advance();if (c0_ == '-') {Advance();if (c0_ == '>' && next().after_line_terminator) {// For compatibility with SpiderMonkey, we skip lines that// start with an HTML comment end '-->'.token = SkipSingleHTMLComment();continue;}return Token::DEC;}if (c0_ == '=') return Select(Token::ASSIGN_SUB);return Token::SUB;case Token::MUL:// * *=Advance();if (c0_ == '*') return Select('=', Token::ASSIGN_EXP, Token::EXP);if (c0_ == '=') return Select(Token::ASSIGN_MUL);return Token::MUL;case Token::MOD:// % %=return Select('=', Token::ASSIGN_MOD, Token::MOD);case Token::DIV:// /  // /* /=Advance();if (c0_ == '/') {uc32 c = Peek();if (c == '#' || c == '@') {Advance();Advance();token = SkipSourceURLComment();continue;}token = SkipSingleLineComment();continue;}if (c0_ == '*') {token = SkipMultiLineComment();continue;}if (c0_ == '=') return Select(Token::ASSIGN_DIV);return Token::DIV;case Token::BIT_AND:// & && &= &&=Advance();if (c0_ == '&') return Select('=', Token::ASSIGN_AND, Token::AND);if (c0_ == '=') return Select(Token::ASSIGN_BIT_AND);return Token::BIT_AND;case Token::BIT_OR:// | || |= ||=Advance();if (c0_ == '|') return Select('=', Token::ASSIGN_OR, Token::OR);if (c0_ == '=') return Select(Token::ASSIGN_BIT_OR);return Token::BIT_OR;case Token::BIT_XOR:// ^ ^=return Select('=', Token::ASSIGN_BIT_XOR, Token::BIT_XOR);case Token::PERIOD:// . NumberAdvance();if (IsDecimalDigit(c0_)) return ScanNumber(true);if (c0_ == '.') {if (Peek() == '.') {Advance();Advance();return Token::ELLIPSIS;}}return Token::PERIOD;case Token::TEMPLATE_SPAN:Advance();return ScanTemplateSpan();case Token::PRIVATE_NAME:if (source_pos() == 0 && Peek() == '!') {token = SkipSingleLineComment();continue;}return ScanPrivateName();case Token::WHITESPACE:token = SkipWhiteSpace();continue;case Token::NUMBER:return ScanNumber(false);case Token::IDENTIFIER:return ScanIdentifierOrKeyword();default:UNREACHABLE();}}if (IsIdentifierStart(c0_) ||(CombineSurrogatePair() && IsIdentifierStart(c0_))) {return ScanIdentifierOrKeyword();}if (c0_ == kEndOfInput) {return source_->has_parser_error() ? Token::ILLEGAL : Token::EOS;}token = SkipWhiteSpace();// Continue scanning for tokens as long as we're just skipping whitespace.} while (token == Token::WHITESPACE);return token;
}
  1. 首先获取当前字符c0_的值,并设置token为初始值。
  2. 判断c0_是否是ASCII字符,如果是,则根据c0_的值来确定token的类型,并返回相应的Token。
  3. 对于一些特殊情况,如条件运算符、字符串、小于号、大于号、等号、逻辑非、加号、减号、乘号、取模、除号、按位与、按位或等,根据当前字符和后续字符的组合来确定token的类型,并返回相应的Token。
  4. 如果c0_不是ASCII字符,或者不满足以上条件,则判断c0_是否是标识符的起始字符,如果是,则调用ScanIdentifierOrKeyword()函数来获取标识符或关键字的Token。
  5. 如果c0_是HTML注释的结束符’-',则调用SkipSingleHTMLComment()函数来跳过整个HTML注释。
  6. 如果扫描到文件末尾,则返回Token::EOS。
  7. 否则,如果遇到空白字符,则调用SkipWhiteSpace()函数来跳过连续的空白字符,并继续扫描下一个Token。
  8. 返回扫描到的Token。

js代码就会变成tokens 接下来进行语法分析。

1.2 解析器parser

parser 的作用就是将 tokens 转化为 AST 抽象语法树。

Program 
└── VariableDeclaration 
├── Identifier (name: "2") 
└── StringLiteral (value: "'1'")
1.3 预解析PreParser

作用是在 JavaScript 代码执行之前对代码进行可选的预处理。预解析器的存在是为了提高代码的执行效率。

V8 引擎采用了延迟解析(Lazy Parsing)的策略,它的原理是只解析当前需要的内容,而把其他内容推迟到函数被调用时再进行解析。这样可以减少不必要的解析工作,提高网页的运行效率。

例如,在一个函数 outer 内部定义了另一个函数 inner,那么 inner 函数就会进行预解析。这意味着在函数 outer 被调用之前,只会对 outer 函数的内容进行解析,而对于 inner 函数的解析会在 outer 函数调用到 inner 函数时才进行。

通过延迟解析的方式,V8 引擎可以避免解析和编译未被执行的函数,节省了不必要的时间和资源开销,提高了 JavaScript 代码的执行效率。这种优化策略在大型复杂的 JavaScript 应用程序中尤为重要,可以帮助提升整体性能和用户体验。

1.4 解释器Ignition

作用主要就是将AST 抽象语法树 转化成 字节码(bytecode)

  1. 跨平台执行:不同的硬件架构和操作系统有不同的机器码格式。通过将代码转换为字节码,可以使得同一份字节码在不同的平台上都能执行,实现跨平台的能力。
  2. 快速启动和解析:将代码转换为字节码可以比直接生成机器码更快速地进行启动和解析。字节码通常具有更简单的格式和结构,可以更快地被引擎加载和解释执行。
  3. 动态优化:现代的JavaScript引擎通常具有即时编译(JIT)功能,可以将热点代码编译成高效的机器码。通过首先将代码转换为字节码,引擎可以更好地进行动态优化和编译,根据实际执行情况生成最优的机器码。这种方式可以在运行时根据代码的实际执行情况进行优化,而不需要提前生成固定的机器码。
  4. 代码安全性:字节码作为中间表示形式,可以提供一定的代码安全性。字节码相对于源代码或机器码来说更难以理解和修改,可以提供一定程度的代码保护。
Program 
└── VariableDeclaration 
├── Identifier (name: "2") 
└── StringLiteral (value: "'1'")
0001: PushString "'1'" 
0002: StoreVar "2"

将字符串字面量 “‘1’” 推入堆栈(栈帧)。在这个例子中,它将字符串 “‘1’” 推入堆栈。

将栈顶的值存储到变量 “2” 中。在这个例子中,它将栈顶的字符串值存储到变量 “2”。

1.5 编译器TurboFan

编译器就是将字节码也可以叫中间代码 最后 转换成 机器码 能让我们的CPU识别。

CPU有不同的架构 ARM X86。

X86机器码

MOV EAX, '1' ; 将字符串 '1' 存储到寄存器 
EAX MOV [2], EAX ; 将寄存器 EAX 的值存储到变量 2 对应的内存地址中

ARM机器码。

LDR R0, ='1' ; 将字符串 '1' 的地址加载到寄存器
R0 STR R0, [2] ; 将寄存器 R0 中的值存储到变量 2 对应的内存地址中

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/180812.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网易区块链

目录 网易区块链 网易区块链 网易区块链成立于2017年,致力于Web3.0区块链技术的研发和应用。自主研发的区块链“天玄”引擎,在单链场景下支持每秒最高30万笔交易,单日可处理上链数据超10亿。 与国家信息中心、杭州互联网公证处等机构合作,支持公证信息存储与算法解决方案…

海康运行管理中心 RCE漏洞复现

0x01 产品简介 海康威视是以视频为核心的智能物联网解决方案和大数据服务提供商。海康运行管理中心是一款功能强大、易于使用的安防管理平台&#xff0c;能满足用户对视频监控、报警管理、设备配置和数据统计等方面的需求&#xff0c;帮助用户建立高效、智能的安防系统。 0x02…

大模型训练为什么用A100不用4090

这是一个好问题。先说结论&#xff0c;大模型的训练用 4090 是不行的&#xff0c;但推理&#xff08;inference/serving&#xff09;用 4090 不仅可行&#xff0c;在性价比上还能比 H100 稍高。4090 如果极致优化&#xff0c;性价比甚至可以达到 H100 的 2 倍。 事实上&#x…

2023/11/28JAVAweb学习

查找哪个进程占用了该端口号 跳过某一个阶段

配置zabbix-proxy主动式

IP地址对应关系如下&#xff1a; zabbix-server122.9.8.21zabbix-proxy122.9.4.102zabbix-agent2116.63.9.109 一、 安装zabbix-server https://blog.csdn.net/qq_50247813/article/details/132131774 二、 安装zabbix-proxy a. 安装zabbix源 rpm -Uvh https://repo.zabbix…

Linux 调试工具:gdb

调试复习 调试可谓是 “贯穿” 了程序员的一生&#xff0c;调试的重要性&#xff0c;就不再赘述啦&#xff01;如果你还不知道什么是调试&#xff0c;可以看看 Windows 系统的 Visual Studio 是如何调试的&#xff1a;➡️ visual stuudio 使用调试技巧 下载调试软件 gdb yu…

使用Accelerate库在多GPU上进行LLM推理

大型语言模型(llm)已经彻底改变了自然语言处理领域。随着这些模型在规模和复杂性上的增长&#xff0c;推理的计算需求也显著增加。为了应对这一挑战利用多个gpu变得至关重要。 所以本文将在多个gpu上并行执行推理&#xff0c;主要包括&#xff1a;Accelerate库介绍&#xff0c;…

Java核心知识点整理大全21-笔记

目录 18.1.5.1. upstream_module 和健康检测 18.1.5.1. proxy_pass 请求转发 18.1.6. HAProxy 19. 数据库 19.1.1. 存储引擎 19.1.1.1. 概念 19.1.1.2. InnoDB&#xff08;B树&#xff09; 适用场景&#xff1a; 19.1.1.3. TokuDB&#xff08;Fractal Tree-节点带数据&…

学生护眼灯怎么选?2023备考护眼台灯推荐

近期&#xff0c;许多“护眼台灯是否是智商税”的帖子频繁出现&#xff0c;引起了许多群众的关注&#xff0c;作为一名护眼台灯资深使用者&#xff0c;在这里声明一下&#xff0c;护眼台灯绝对不是智商税。护眼台灯是通过调节光线亮度和色温&#xff0c;降低蓝光辐射&#xff0…

【LeetCode】128. 最长连续序列——哈希的应用(3)

文章目录 1、思路2、解题方法3、复杂度时间复杂度:空间复杂度: 4、Code Problem: 128. 最长连续序列 1、思路 我会用一种做题者的思路来去看待这道题。 我们在乍一看到这道题的时候&#xff0c;看到它的时间复杂度要求为O(N)&#xff0c;然后又要求去找序列(就是让你判断这个…

Redis高可用集群架构

高可用集群架构 哨兵模式缺点 主从切换阶段&#xff0c; redis服务不可用&#xff0c;高可用不太友好只有单个主节点对外服务&#xff0c;不能支持高并发单节点如果设置内存过大&#xff0c;导致持久化文件很大&#xff0c;影响数据恢复&#xff0c;主从同步性能 高可用集群…

SSM项目管理系统开发oracle10g数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 SSM项目管理系统是一套完善的信息系统&#xff0c;结合springMVC框架完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统 主要采用B/S模式开…

自研基于Xilinx PCIe的高性能多路视频采集与显示控制器

1 概述 视频采集与显示子系统可以实时采集多路视频信号&#xff0c;并存储到视频采集队列中&#xff0c;借助高效的硬实时视频帧出入队列管理和PCIe C2H DMA引擎&#xff0c;将采集到的视频帧实时传递到上位机采集缓冲区。在超带宽视频采集情况下&#xff0c;支持采集丢帧操作…

重温 re:Invent,分享十年成长:我和 re:Invent的故事

文章目录 前言背景我和re:Invent的交际历届峰会主题2012 突破技术垄断2013 革新数据服务2014 更好用的云服务2015 打通最后一-公里2016 迈向云上数据湖时代2017 重构云计算基础2018 云能力的再进化2019 赋能企业云架构服务2020 推动行业数据库服务的演进2021 无可比拟的云架构2…

【开源】基于Vue和SpringBoot的企业项目合同信息系统

项目编号&#xff1a; S 046 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S046&#xff0c;文末获取源码。} 项目编号&#xff1a;S046&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 合同审批模块2.3 合…

LLM、ChatGPT与多模态必读论文150篇

为了写本 ChatGPT 笔记&#xff0c;我和10来位博士、业界大佬&#xff0c;在过去半年翻了大量中英文资料/paper&#xff0c;读完 ChatGPT 相关技术的150篇论文&#xff0c;当然还在不断深入。 由此而感慨&#xff1a; 读的论文越多&#xff0c;你会发现大部分人对ChatGPT的技…

java List集合(ArrayList,LinkedList,Vector)

Hi i,m JinXiang ⭐ 前言 ⭐ 本篇文章主要介绍java List集合的三种实现类ArrayList&#xff0c;LinkedList&#xff0c;Vector以及部分理论知识 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主收将持续更新学习…

HassOS使用nmcli设置静态IPv4地址及网关、DNS

目录 显示hass在使用的默认连接显示此连接的所有配置编辑hass默认连接添加静态IP地址添加DNS和网关删除DNS查看IPv4属性保存配置并退出nmcli重载配置 首先控制台登陆Home Assistant OS Welcome to Home Assistant homeassistant login:使用root用户登录&#xff08;无需密码&a…

【数据结构】树与二叉树(廿五):树搜索给定结点的父亲(算法FindFather)

文章目录 5.3.1 树的存储结构5. 左儿子右兄弟链接结构 5.3.2 获取结点的算法1. 获取大儿子、大兄弟结点2. 搜索给定结点的父亲a. 算法FindFatherb. 算法解析c. 代码实现 3. 代码整合 5.3.1 树的存储结构 5. 左儿子右兄弟链接结构 【数据结构】树与二叉树&#xff08;十九&…

vue实现动态路由菜单!!!

目录 总结一、步骤1.编写静态路由编写router.jsmain.js注册 2.编写permisstions.js权限文件编写permisstions.jsaxios封装的APIstore.js状态库system.js Axios-APIrequest.js axios请求实例封装 3.编写菜单树组件MenuTree.vue 4.主页中使用菜单树组件 总结 递归处理后端响应的…