当前位置: 首页 > news >正文

[前端] 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 对应的内存地址中

相关文章:

[前端] V8引擎编译原理

文章目录 1.什么是V81.1 扫描器Scanner1.2 解析器parser1.3 预解析PreParser1.4 解释器Ignition1.5 编译器TurboFan 1.什么是V8 V8是谷歌的开源高性能JavaScript和WebAssembly引擎&#xff0c;用C编写。它被用于Chrome和Node.js等。它实现ECMAScript和WebAssembly&#xff0c;…...

使用Pytorch实现linear_regression

使用Pytorch实现线性回归 # import necessary packages import torch import torch.nn as nn import numpy as np import matplotlib.pyplot as plt# Set necessary Hyper-parameters. input_size 1 output_size 1 num_epochs 60 learning_rate 0.001# Define a Toy datas…...

网络安全等级保护收费标准?

不同省份价格会略有不同&#xff0c;二级等保一般不低于5万元;三级等保不低于9万元&#xff0c;个别省份也可能7万也能办理&#xff0c;根据企业实际情况和省市选定的代理机构确定。 等级保护二级? 第二级等保是指信息系统受到破坏后&#xff0c;会对公民、法人和其他组织的合…...

16 Go的反射

概述 在上一节的内容中&#xff0c;我们介绍了Go的并发&#xff0c;包括&#xff1a;Goroutines、Channels、WaitGroups、Mutex、Select等。在本节中&#xff0c;我们将介绍Go的反射。Go语言中的反射是一种在运行时检查类型信息并操作对象的能力&#xff0c;通过反射&#xff0…...

SQL Server 百万数据查询优化技巧三十则

点击上方蓝字关注我 互联网时代的进程越走越深&#xff0c;使用MySQL的人也越来越多&#xff0c;关于MySQL的数据库优化指南很多&#xff0c;而关于SQL SERVER的T-SQL优化指南看上去比较少&#xff0c;近期有学习SQLSERVER的同学问到SQL SERVER数据库有哪些优化建议&#xff1f…...

list转map(根据某个或多个属性分组)

需要将对应的list换成本地list&#xff0c;和对象换成本地对象 1、List转Map<String,List> // 根据一个字段分组 Map<String, List<String>> map objectLists.stream().collect(Collectors.groupingBy(Object::getName,Collectors.mapping(Object::getId, …...

常见树种(贵州省):012茶、花椒、八角、肉桂、杜仲、厚朴、枸杞、忍冬

摘要&#xff1a;本专栏树种介绍图片来源于PPBC中国植物图像库&#xff08;下附网址&#xff09;&#xff0c;本文整理仅做交流学习使用&#xff0c;同时便于查找&#xff0c;如有侵权请联系删除。 图片网址&#xff1a;PPBC中国植物图像库——最大的植物分类图片库 一、茶 灌…...

千云物流 - 使用k8s负载均衡openelb

openelb的介绍 具体根据官方文档进行安装官方文档,这里作为测试环境的安装使用. OpenELB 是一个开源的云原生负载均衡器实现,可以在基于裸金属服务器、边缘以及虚拟化的 Kubernetes 环境中使用 LoadBalancer 类型的 Service 对外暴露服务。OpenELB 项目最初由 KubeSphere 社区…...

C语言之字符串函数

C语言之字符串函数 文章目录 C语言之字符串函数1. strlen的使用和模拟实现1.1 strlen的使用1.2 strlen的模拟实现 2. strcpy的使用和模拟实现2.1 strcpy的使用2.2 strncpy的使用2.3 strcpy的模拟实现 3. strcat的使用和模拟实现3.1 strcat的使用3.2 strncat3.3 strcat的模拟实现…...

python中一个文件(A.py)怎么调用另一个文件(B.py)中定义的类AA详解和示例

本文主要讲解python文件中怎么调用另外一个py文件中定义的类&#xff0c;将通过代码和示例解读&#xff0c;帮助大家理解和使用。 目录 代码B.pyA.py 调用过程 代码 B.py 如在文件B.py,定义了类别Bottleneck&#xff0c;其包含卷积层、正则化和激活函数层&#xff0c;主要对…...

spark shuffle 剖析

ShuffleExchangeExec private lazy val writeMetrics SQLShuffleWriteMetricsReporter.createShuffleWriteMetrics(sparkContext)private[sql] lazy val readMetrics SQLShuffleReadMetricsReporter.createShuffleReadMetrics(sparkContext)用在了两个地方&#xff0c;承接的是…...

C语言之认识柔性数组(flexible array)

在学习之前&#xff0c;我们首先要了解柔性数组是放在结构体当中的&#xff0c;知道这一点&#xff0c;我们就开始今天的学习吧&#xff01; 1.柔性数组的声明 在C99中&#xff0c;结构中的最后一个元素允许是未知大小的数组&#xff0c;这就叫做柔性数组成员 这里的结构是结构…...

【MATLAB基础绘图第17棒】绘制玫瑰图

MATLAB绘制玫瑰图 玫瑰图&#xff08;Nightingale Rose Chart&#xff09;风玫瑰图&#xff08;WindRose&#xff09;准备工作&#xff1a;WindRose工具包下载案例案例1&#xff1a;基础绘图 参考 玫瑰图&#xff08;Nightingale Rose Chart&#xff09; 玫瑰图&#xff08;Ni…...

Qt 基于海康相机的视频绘图

需求 在视频窗口上进行绘图&#xff0c;包括圆&#xff0c;矩形&#xff0c;扇形等 效果&#xff1a; 思路&#xff1a; 自己取图然后转成QImage &#xff0c;再向QWidget 进行渲染&#xff0c;根据以往的经验&#xff0c;无法达到很高的帧率。因此决定使用相机SDK自带的渲染…...

FlinkCDC实现主数据与各业务系统数据的一致性(瀚高、TIDB)

文章末尾附有flinkcdc对应瀚高数据库flink-cdc-connector代码下载地址 1、业务需求 目前项目有主数据系统和N个业务系统,为保障“一数一源”,各业务系统表涉及到主数据系统的字段都需用主数据系统表中的字段进行实时覆盖,这里以某个业务系统的一张表举例说明:业务系统表Ta…...

JSP:Servlet

Servlet处理请求过程 B/S请求响应模型 Servlet介绍 JSP是Servlet的一个成功应用&#xff0c;其子集。 JSP页面负责前台用户界面&#xff0c;JavaBean负责后台数据处理&#xff0c;一般的Web应用采用JSPJavaBean就可以设计得很好了。 JSPServletJavaBean是MVC Servlet的核心…...

react中的state

没想到hooks中也有state这一说法 看下面的两个案例 1、无state变化不会执行父子函数 2、有state更改执行父子函数...

VR全景航拍要注意什么,航拍图片如何处理

引言: VR全景航拍技术是当前摄影和航拍领域的新潮流。它采用虚拟现实技术&#xff0c;通过360度全景镜头捕捉画面&#xff0c;可以为观众提供身临其境的视觉体验。在宣传展示中&#xff0c;利用VR全景航拍技术可以为品牌宣传带来更加生动、震撼的视觉效果。 一、航拍注意事项 …...

Spark---集群搭建

Standalone集群搭建与Spark on Yarn配置 1、Standalone Standalone集群是Spark自带的资源调度框架&#xff0c;支持分布式搭建&#xff0c;这里建议搭建Standalone节点数为3台&#xff0c;1台master节点&#xff0c;2台worker节点&#xff0c;这虚拟机中每台节点的内存至少给…...

Linux上通过SSL/TLS和start tls连接到LDAP服务器

一&#xff0c;大致流程。 1.首先在Linux上搭建一个LDAP服务器 2.在LDAP服务器上安装CA证书&#xff0c;服务器证书&#xff0c;因为SSL/TLS&#xff0c;start tls都属于机密通信&#xff0c;需要客户端和服务器都存在一个相同的证书认证双方的身份。3.安装phpldapadmin工具&am…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

Python实现prophet 理论及参数优化

文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候&#xff0c;写过一篇简单实现&#xff0c;后期随着对该模型的深入研究&#xff0c;本次记录涉及到prophet 的公式以及参数调优&#xff0c;从公式可以更直观…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

Caliper 配置文件解析:config.yaml

Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

GO协程(Goroutine)问题总结

在使用Go语言来编写代码时&#xff0c;遇到的一些问题总结一下 [参考文档]&#xff1a;https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现&#xff1a; 今天在看到这个教程的时候&#xff0c;在自己的电…...

算法—栈系列

一&#xff1a;删除字符串中的所有相邻重复项 class Solution { public:string removeDuplicates(string s) {stack<char> st;for(int i 0; i < s.size(); i){char target s[i];if(!st.empty() && target st.top())st.pop();elsest.push(s[i]);}string ret…...

Python爬虫实战:研究Restkit库相关技术

1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的有价值数据。如何高效地采集这些数据并将其应用于实际业务中,成为了许多企业和开发者关注的焦点。网络爬虫技术作为一种自动化的数据采集工具,可以帮助我们从网页中提取所需的信息。而 RESTful API …...