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

西宁市建设局网站网站信息系统建设

西宁市建设局网站,网站信息系统建设,学生个人网页制作 效果图,学做网站用到哪些知识简介#xff1a;本文是一个 V8 编译原理知识的介绍文章#xff0c;旨在让大家感性的了解 JavaScript 在 V8 中的解析过程。 作者 | 子弈 来源 | 阿里技术公众号 一 简介 本文是一个 V8 编译原理知识的介绍文章#xff0c;旨在让大家感性的了解 JavaScript 在 V8 中的解析过…简介本文是一个 V8 编译原理知识的介绍文章旨在让大家感性的了解 JavaScript 在 V8 中的解析过程。 作者 | 子弈 来源 | 阿里技术公众号 一 简介 本文是一个 V8 编译原理知识的介绍文章旨在让大家感性的了解 JavaScript 在 V8 中的解析过程。本文主要的撰写流程如下 解释器和编译器计算机编译原理的基础知识介绍V8 的编译原理基于计算机编译原理的知识了解 V8 对于 JavaScript 的解析流程V8 的运行时表现结合 V8 的编译原理实践 V8 在解析流程中的具体运行表现 本文仅代表个人观点文中若有错误欢迎指正。二 解释器和编译器 大家可能一直疑惑的问题JavaScript 是一门解释型语言吗要了解这个问题首先需要初步了解什么是解释器和编译器以及它们的特点是什么。 1 解释器 解释器的作用是将某种语言编写的源程序作为输入将该源程序执行的结果作为输出例如 Perl、Scheme、APL 等都是使用解释器进行转换执行 2 编译器 编译器的设计是一个非常庞大和复杂的软件系统设计在真正设计的时候需要解决两个相对重要的问题 如何分析不同高级程序语言设计的源程序如何将源程序的功能等价映射到不同指令系统的目标机器中间表示IR 中间表示Intermediate RepresentationIR是程序结构的一种表现方式它会比抽象语法树Abstract Syntax TreeAST更加接近汇编语言或者指令集同时也会保留源程序中的一些高级信息具体作用包括 易于编译器的错误调试容易识别是 IR 之前的前端还是之后的后端出的问题可以使得编译器的职责更加分离源程序的编译更多关注如何转换成 IR而不是去适配不同的指令集IR 更加接近指令集从而相对于源码可以更加节省内存空间优化编译器 IR 本身可以做到多趟迭代从而优化源程序在每一趟迭代的过程中可以研究代码并记录优化的细节方便后续的迭代查找并利用这些优化信息最终可以高效输出更优的目标程序 优化器可以对 IR 进行一趟或者多趟处理从而生成更快执行速度或者更小体积的目标程序例如找到循环中不变的计算并对其进行优化从而减少运算次数也可能用于产生更少异常或者更低功耗的目标程序。除此之外前端和后端内部还可以细分为多个处理步骤具体如下图所示 3 两者的特性比较 解释器和编译器的具体特性比较如下所示 需要注意早期的 Web 前端要求页面的启动速度快因此采用解释执行的方式但是页面在运行的过程中性能相对较低。为了解决这个问题需要在运行时对 JavaScript 代码进行优化因此在 JavaScript 的解析引擎中引入了 JIT 技术。 4 JIT 编译技术 JIT Just In Time编译器是一种动态编译技术相对于传统编译器而言最大的区别在于编译时和运行时不分离是一种在运行的过程中对代码进行动态编译的技术。 5 混合动态编译技术 为了解决 JavaScript 在运行时性能较慢的问题可以通过引入 JIT 技术并采用混合动态编译的方式来提升 JavaScript 的运行性能具体思路如下所示 采用上述编译框架后可以使得 JavaScript 语言 启动速度快在 JavaScript 启动的时候采用解释执行的方式运行利用了解释器启动速度快的特性运行性能高在 JavaScript 运行的过程中可以对代码进行监控从而使用 JIT 技术对代码进行编译优化 三 V8 的编译原理 V8 是一个开源的 JavaScript 虚拟机目前主要用在 Chrome 浏览器包括开源的 Chromium以及 Node.js 中核心功能是用于解析和执行 JavaScript 语言。为了解决早期 JavaScript 运行性能差的问题V8 经历了多个历史的编译框架衍变之后感兴趣的同学可以了解一下早期的 V8 编译框架设计引入混合动态编译的技术来解决问题具体详细的编译框架如下所示 1 Ignition 解释器 Ignition 的主要作用是将 AST 转换成 Bytecode字节码中间表示。在运行的过程中还会使用类型反馈TypeFeedback技术并计算热点代码HotSpot重复被运行的代码可以是方法也可以是循环体最终交给 TurboFan 进行动态运行时的编译优化。Ignition 的解释执行流程如下所示 在字节码解释执行的过程中会将需要进行性能优化的运行时信息指向对应的 Feedback Vector反馈向量之前也被称为 Type Feedback VectorFeeback Vector 中会包含根据内联缓存Inline CacheIC来存储的多种类型的插槽Feedback Vector Slot信息例如 BinaryOp 插槽二进制操作结果的数据类型、Invocation Count函数的调用次数以及 Optimized Code 信息等。 这里不会过多讲解每个执行流程的细节问题。2 TurboFan 优化编译器 TurboFan 利用了 JIT 编译技术主要作用是对 JavaScript 代码进行运行时编译优化具体的流程如下所示 图片出处 An Introduction to Speculative Optimization in V8。需要注意 Profiling Feedback 部分这里主要提供 Ignition 解释执行过程中生成的运行时反馈向量信息 Feedback Vector Turbofan 会结合字节码以及反馈向量信息生成图示数据结构中的图结构并将图传递给前端部分之后会根据反馈向量信息对代码进行优化和去优化。 这里的去优化是指让代码回退到 Ignition 进行解释执行去优化本质是因为机器码已经不能满足运行诉求例如一个变量从 string 类型转变成 number 类型机器码编译的是 string 类型此时已经无法再满足运行诉求因此 V8 会执行去优化动作将代码回退到 Ignition 进行解释执行。四 V8 的运行时表现 在了解 V8 的编译原理之后接下来需要使用 V8 的调试工具来具体查看 JavaScript 的编译和运行信息从而加深我们对 V8 的编译过程认知。 1 D8 调试工具 如果想了解 JavaScript 在 V8 中的编译时和运行时信息可以使用调试工具 D8。D8 是 V8 引擎的命令行 Shell可以查看 AST 生成、中间代码 ByteCode、优化代码、反优化代码、优化编译器的统计数据、代码的 GC 等信息。D8 的安装方式有很多如下所示 方法一根据 V8 官方文档 Using d8 以及 Building V8 with GN 进行工具链的下载和编译方法二使用别人已经编译好的 D8 工具可能版本会有滞后性例如 Mac 版方法三使用 JavaScript 引擎版本管理工具例如 jsvu可以下载到最新编译好的 JavaScript 引擎 本文使用方法三安装 v8-debug 工具安装完成后执行 v8-debug --help 可以查看有哪些命令 # 执行 help 命令查看支持的参数 v8-debug --helpSynopsis:shell [options] [--shell] [file...]d8 [options] [-e string] [--shell] [[--module|--web-snapshot] file...]-e execute a string in V8--shell run an interactive JavaScript shell--module execute a file as a JavaScript module--web-snapshot execute a file as a web snapshotSSE31 SSSE31 SSE4_11 SSE4_21 SAHF1 AVX1 AVX21 FMA31 BMI11 BMI21 LZCNT1 POPCNT1 ATOM0 The following syntax for options is accepted (both - and -- are ok):--flag (bool flags only)--no-flag (bool flags only)--flagvalue (non-bool flags only, no spaces around )--flag value (non-bool flags only)-- (captures all remaining args in JavaScript)Options:# 打印生成的字节码--print-bytecode (print bytecode generated by ignition interpreter)type: bool default: --noprint-bytecode# 跟踪被优化的信息--trace-opt (trace optimized compilation)type: bool default: --notrace-opt--trace-opt-verbose (extra verbose optimized compilation tracing)type: bool default: --notrace-opt-verbose--trace-opt-stats (trace optimized compilation statistics)type: bool default: --notrace-opt-stats# 跟踪去优化的信息--trace-deopt (trace deoptimization)type: bool default: --notrace-deopt--log-deopt (log deoptimization)type: bool default: --nolog-deopt--trace-deopt-verbose (extra verbose deoptimization tracing)type: bool default: --notrace-deopt-verbose--print-deopt-stress (print number of possible deopt points)# 查看编译生成的 AST--print-ast (print source AST)type: bool default: --noprint-ast# 查看编译生成的代码--print-code (print generated code)type: bool default: --noprint-code# 查看优化后的代码--print-opt-code (print optimized code)type: bool default: --noprint-opt-code# 允许在源代码中使用 V8 提供的原生 API 语法--allow-natives-syntax (allow natives syntax)type: bool default: --noallow-natives-syntax 2 生成 AST 我们编写一个 index.js 文件在文件中写入 JavaScript 代码执行一个简单的 add 函数 function add(x, y) {return x y }console.log(add(1, 2)); 使用 --print-ast 参数可以打印 add 函数的 AST 信息 v8-debug --print-ast ./index.js[generating bytecode for function: ] --- AST --- FUNC at 0 . KIND 0 . LITERAL ID 0 . SUSPEND COUNT 0 . NAME . INFERRED NAME . DECLS . . FUNCTION add function add . EXPRESSION STATEMENT at 41 . . ASSIGN at -1 . . . VAR PROXY local[0] (0x7fb8c080e630) (mode TEMPORARY, assigned true) .result . . . CALL . . . . PROPERTY at 49 . . . . . VAR PROXY unallocated (0x7fb8c080e6f0) (mode DYNAMIC_GLOBAL, assigned false) console . . . . . NAME log . . . . CALL . . . . . VAR PROXY unallocated (0x7fb8c080e470) (mode VAR, assigned true) add . . . . . LITERAL 1 . . . . . LITERAL 2 . RETURN at -1 . . VAR PROXY local[0] (0x7fb8c080e630) (mode TEMPORARY, assigned true) .result[generating bytecode for function: add] --- AST --- FUNC at 12 . KIND 0 . LITERAL ID 1 . SUSPEND COUNT 0 . NAME add . PARAMS . . VAR (0x7fb8c080e4d8) (mode VAR, assigned false) x . . VAR (0x7fb8c080e580) (mode VAR, assigned false) y . DECLS . . VARIABLE (0x7fb8c080e4d8) (mode VAR, assigned false) x . . VARIABLE (0x7fb8c080e580) (mode VAR, assigned false) y . RETURN at 25 . . ADD at 34 . . . VAR PROXY parameter[0] (0x7fb8c080e4d8) (mode VAR, assigned false) x . . . VAR PROXY parameter[1] (0x7fb8c080e580) (mode VAR, assigned false) y 我们以图形化的方式来描述生成的 AST 树 VAR PROXY 节点在真正的分析阶段会连接到对应地址的 VAR 节点。 3 生成字节码 AST 会经过 Ignition 解释器的 BytecodeGenerator 函数生成字节码中间表示我们可以通过 --print-bytecode 参数来打印字节码信息 v8-debug --print-bytecode ./index.js[generated bytecode for function: (0x3ab2082933f5 SharedFunctionInfo)] Bytecode length: 43 Parameter count 1 Register count 6 Frame size 48 OSR nesting level: 0 Bytecode Age: 00x3ab2082934be 0 : 13 00 LdaConstant [0]0x3ab2082934c0 2 : c3 Star1 0x3ab2082934c1 3 : 19 fe f8 Mov closure, r20x3ab2082934c4 6 : 65 52 01 f9 02 CallRuntime [DeclareGlobals], r1-r20x3ab2082934c9 11 : 21 01 00 LdaGlobal [1], [0]0x3ab2082934cc 14 : c2 Star2 0x3ab2082934cd 15 : 2d f8 02 02 LdaNamedProperty r2, [2], [2]0x3ab2082934d1 19 : c3 Star1 0x3ab2082934d2 20 : 21 03 04 LdaGlobal [3], [4]0x3ab2082934d5 23 : c1 Star3 0x3ab2082934d6 24 : 0d 01 LdaSmi [1]0x3ab2082934d8 26 : c0 Star4 0x3ab2082934d9 27 : 0d 02 LdaSmi [2]0x3ab2082934db 29 : bf Star5 0x3ab2082934dc 30 : 63 f7 f6 f5 06 CallUndefinedReceiver2 r3, r4, r5, [6]0x3ab2082934e1 35 : c1 Star3 0x3ab2082934e2 36 : 5e f9 f8 f7 08 CallProperty1 r1, r2, r3, [8]0x3ab2082934e7 41 : c4 Star0 0x3ab2082934e8 42 : a9 Return Constant pool (size 4) 0x3ab208293485: [FixedArray] in OldSpace- map: 0x3ab208002205 Map- length: 40: 0x3ab20829343d FixedArray[2]1: 0x3ab208202741 String[7]: #console2: 0x3ab20820278d String[3]: #log3: 0x3ab208003f09 String[3]: #add Handler Table (size 0) Source Position Table (size 0) [generated bytecode for function: add (0x3ab20829344d SharedFunctionInfo add)] Bytecode length: 6 // 接受 3 个参数 1 个隐式的 this以及显式的 x 和 y Parameter count 3 Register count 0 // 不需要局部变量因此帧大小为 0 Frame size 0 OSR nesting level: 0 Bytecode Age: 00x3ab2082935f6 0 : 0b 04 Ldar a10x3ab2082935f8 2 : 39 03 00 Add a0, [0]0x3ab2082935fb 5 : a9 Return Constant pool (size 0) Handler Table (size 0) Source Position Table (size 0) add 函数主要包含以下 3 个字节码序列 // Load Accumulator Register // 加载寄存器 a1 的值到累加器中 Ldar a1 // 读取寄存器 a0 的值并累加到累加器中相加之后的结果会继续放在累加器中 // [0] 指向 Feedback Vector SlotIgnition 会收集值的分析信息为后续的 TurboFan 优化做准备 Add a0, [0] // 转交控制权给调用者并返回累加器中的值 Return 这里 Ignition 的解释执行这些字节码采用的是一地址指令结构的寄存器架构。 关于更多字节码的信息可查看 Understanding V8’s Bytecode。4 优化和去优化 JavaScript 是弱类型语言不会像强类型语言那样需要限定函数调用的形参数据类型而是可以非常灵活的传入各种类型的参数进行处理如下所示 function add(x, y) { // 操作符是 JavaScript 中非常复杂的一个操作return x y }add(1, 2); add(1, 2); add(, 2); add(undefined, 2); add([], 2); add({}, 2); add([], {}); 为了可以进行 操作符运算在底层执行的时候往往需要调用很多 API比如 ToPrimitive判断是否是对象、ToString、ToNumber 等将传入的参数进行符合 操作符的数据转换处理。 在这里 V8 会对 JavaScript 像强类型语言那样对形参 x 和 y 进行推测这样就可以在运行的过程中排除一些副作用分支代码同时这里也会预测代码不会抛出异常因此可以对代码进行优化从而达到最高的运行性能。在 Ignition 中通过字节码来收集反馈信息Feedback Vector如下所示 为了查看 add 函数的运行时反馈信息我们可以通过 V8 提供的 Native API 来打印 add 函数的运行时信息具体如下所示 function add(x, y) {return x y }// 注意这里默认采用了 ClosureFeedbackCellArray为了查看效果强制开启 FeedbackVector // 更多信息查看 A lighter V8https://v8.dev/blog/v8-lite %EnsureFeedbackVectorForFunction(add); add(1, 2); // 打印 add 详细的运行时信息 %DebugPrint(add); 通过 --allow-natives-syntax 参数可以在 JavaScript 中调用 %DebugPrint 底层 Native API更多 API 可以查看 V8 的 runtime.h 头文件 这里的 SharedFunctionInfoSFI中保留了一个 InterpreterEntryTrampoline 指针信息每个函数都会有一个指向 Ignition 解释器的 trampoline 指针每当 V8 需要进去去优化时就会使用此指针使代码回退到解释器相应的函数执行位置。 为了使得 add 函数可以像 HotSpot 代码一样被优化在这里强制做一次函数优化 通过 --trace-opt 参数可以跟踪 add 函数的编译优化信息 需要注意的是 V8 会自动监测代码的结构变化从而执行去优化。例如下述代码 function add(x, y) {return x y }%EnsureFeedbackVectorForFunction(add);add(1, 2); %OptimizeFunctionOnNextCall(add); add(1, 2); // 改变 add 函数的传入参数类型之前都是 number 类型这里传入 string 类型 add(1, 2); %DebugPrint(add); 我们可以通过 --trace-deopt 参数跟踪 add 函数的去优化信息 需要注意的是代码在执行去优化的过程中会产生性能损耗因此在日常的开发中建议使用 TypeScript 对代码进行类型声明这样可以一定程度提升代码的性能。 五 总结 本文对于 V8 的研究还处在一个感性的认知阶段并没有深入到 V8 底层的源码。通过本文可以对 V8 的编译原理有一个感性的认知同时也建议大家可以使用 TypeScript它确实能在一定程度上对 JavaScript 代码的编写产生更好的指导作用。 原文链接 本文为阿里云原创内容未经允许不得转载。
http://www.pierceye.com/news/123406/

相关文章:

  • 轻量级网站开发在线旅游网站平台有哪些
  • 怎么用vs做网站推广优化网站排名
  • 免费推广网站软件常宁网站建设常宁网站建设
  • 冀州市网站建设html编辑器安卓版手机版软件
  • 广州专业网站改版方案网站建设要做ui和什么
  • 做网站显示上次登录时间代码h5素材库
  • 比较有名的网站建设公司谷歌网站优化
  • 企业网站改版计划书中国制造网是做什么的
  • 非主营电子商务企业网站有哪些企业网项目建设实践
  • 颍东网站建设手机vi设计公司
  • 林哥seo网络营销seo培训
  • 如何面试网站开发网站制作交易流程
  • 绍兴网站建设冯炳良互联网营销
  • 制作企业网站怎么报价可以做我女朋友吗网站
  • 广西玉林网站建设正规公司建手机网站
  • 乐清网站制作公司招聘做私人网站 违法
  • 珠海电脑自己建网站电子商务排名
  • 怎样做网站的背景图片安卓原生开发
  • 现代电子商务网站建设技术wordpress采用的mvc
  • 台州网站建设团队如何申请建设网站域名
  • 资料查询网站建设桂林微代码网络科技有限公司
  • 做暖视频网站免费番禺网站制作技术
  • 如何做网站百度排名优化深圳市住房和建设网站
  • 汉沽做网站简单网站建设
  • 建信建设投资有限公司网站网站建设app小程序
  • wordpress文章所有图片seo中文含义
  • 免费网站建设开发个人 网站备案 幕布
  • 公司网站设计 优帮云网站开发合同注意事件有哪些
  • 网站建设费用用温州建设局老网站
  • 做网站全部乱码怎么办网络平台销售