热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

字节码开发笔记:深入解析与应用技巧

篇首语:本文由编程笔记#小编为大家整理,主要介绍了字节码相关的知识,希望对你有一定的参考价值。 了解 V8 的字节码「译」Javascript 阅读约 9 分钟原文:Understandin

篇首语:本文由编程笔记#小编为大家整理,主要介绍了字节码相关的知识,希望对你有一定的参考价值。



了解 V8 的字节码「译」

Javascript

 阅读约 9 分钟


原文:Understanding V8’s Bytecode
作者:Franziska Hinkelmann
译者:justjavac


V8 是 Google 开发的开源 Javascript 引擎。 Chrome、Node.js和许多其他应用程序都在使用 V8。本文介绍了 V8 的字节码格式—— 如果你了解关于字节码的基本概念,读起来会更加轻松。

技术图片

当 V8 编译 Javascript 代码时,解析器(parser)将生成一个抽象语法树。语法树是 Javascript 代码的句法结构的树形表示形式。解释器 Ignition 根据语法树生成字节码。TurboFan 是 V8 的优化编译器,TurboFan 将字节码生成优化的机器代码。

技术图片

如果想知道为什么会有两种执行模式,可以从 JSConfEU 查看我(原作者)的视频(YouTube需fq上网):

Franziska Hinkelmann: Javascript engines - how do they even? | JSConf EU 2017

技术图片

字节码是机器代码的抽象。如果字节码采用和物理 CPU 相同的计算模型进行设计,则将字节码编译为机器代码更容易。这就是为什么解释器(interpreter)常常是寄存器或堆栈。 Ignition 是具有累加器的寄存器。

技术图片

您可以将 V8 的字节码看作是小型的构建块(bytecodes as small building blocks),这些构建块组合在一起构成任何 Javascript 功能。V8 有数以百计的字节码。比如 Add 或 TypeOf 这样的操作符,或者像 LdaNamedProperty 这样的属性加载符,还有很多类似的字节码。 V8还有一些非常特殊的字节码,如 CreateObjectLiteral 或 SuspendGenerator。头文件 bytecodes.h 定义了 V8 字节码的完整列表。

每个字节码指定其输入和输出作为寄存器操作数。Ignition 使用寄存器 r0r1r2,... 和累加器寄存器(accumulator register)。几乎所有的字节码都使用累加器寄存器。它像一个常规寄存器,除了字节码没有指定。 例如,Add r1 将寄存器 r1 中的值和累加器中的值进行加法运算。这使得字节码更短,节省内存。

许多字节码以 Lda 或 Sta 开头。Lda 和 Stastands 中的 a 为累加器(accumulator)。例如,LdaSmi [42] 将小整数(Smi)42 加载到累加器寄存器中。Star r0 将当前在累加器中的值存储在寄存器 r0 中。

以现在掌握的基础知识,花点时间来看一个具有实际功能的字节码。

function incrementX(obj) {
return 1 + obj.x;
}
incrementX({x: 42});
// V8 的编译器是惰性的,
// 如果一个函数没有运行,V8 将不会解释它

如果要查看 V8 的 Javascript 字节码,可以使用在命令行参数中添加 --print-bytecode 运行 D8 或Node.js(8.3 或更高版本)来打印。对于 Chrome,请从命令行启动 Chrome,使用 --js-flags="--print-bytecode",请参考 Run Chromium with flags。


$ node --print-bytecode incrementX.js
...
[generating bytecode for function: incrementX]
Parameter count 2
Frame size 8
12 E> 0x2ddf8802cf6e @ StackCheck
19 S> 0x2ddf8802cf6f @ LdaSmi [1]
0x2ddf8802cf71 @ Star r0
34 E> 0x2ddf8802cf73 @ LdaNamedProperty a0, [0], [4]
28 E> 0x2ddf8802cf77 @ Add r0, [6]
36 S> 0x2ddf8802cf7a @ Return
Constant pool (size = 1)
0x2ddf8802cf21: [FixedArray] in OldSpace
- map = 0x2ddfb2d02309
- length: 1
0: 0x2ddf8db91611 1]: x>
Handler Table (size = 16)

我们忽略大部分输出,专注于实际的字节码。

这是每个字节码的意思,每一行:


LdaSmi [1]

LdaSmi [1] 将常量 1 加载到累加器中。

技术图片


Star r0

接下来,Star r0 将当前在累加器中的值 1 存储在寄存器 r0 中。

技术图片


LdaNamedProperty a0, [0], [4]

LdaNamedProperty 将 a0 的命名属性加载到累加器中。ai 指向 incrementX() 的第 i 个参数。在这个例子中,我们在 a0 上查找一个命名属性,这是 incrementX() 的第一个参数。该属性名由常量 0 确定。LdaNamedProperty 使用 0 在单独的表中查找名称:

- length: 1
0: 0x2ddf8db91611

可以看到,0 映射到了 x。因此这行字节码的意思是加载 obj.x

那么值为 4 的操作数是干什么的呢? 它是函数 incrementX() 的反馈向量的索引。反馈向量包含用于性能优化的 runtime 信息。

现在寄存器看起来是这样的:

技术图片


Add r0, [6]

最后一条指令将 r0 加到累加器,结果是 43。 6 是反馈向量的另一个索引。

技术图片


Return

Return 返回累加器中的值。返回语句是函数 incrementX() 的结束。此时 incrementX() 的调用者可以在累加器中获得值 43,并可以进一步处理此值。

乍一看,V8 的字节码看起来非常奇怪,特别是当我们打印出所有的额外信息。但是一旦你知道 Ignition 是一个带有累加器寄存器的寄存器,你就可以分析出大多数字节码都干了什么。

Learned something? Clap your ? to say “thanks!” and help others find this article.


注意:此处描述的字节码来自 V8 版本 6.2,Chrome 62 以及 Node 9(尚未发布)版本。我们始终致力于 V8 以提高性能和减少内存消耗。在其他 V8 版本中,细节可能会有所不同。




欢迎关注我的公众号,关注前端文章:

技术图片


推荐阅读
  • 基址获取与驱动开发:内核中提取ntoskrnl模块的基地址方法解析
    基址获取与驱动开发:内核中提取ntoskrnl模块的基地址方法解析 ... [详细]
  • 在使用Keil C51创建51单片机项目时,启动代码中包含多个关键元素,这些元素确保了系统的正确初始化和运行。主要包括复位向量、中断向量表、系统时钟配置、寄存器初始化以及主函数入口等。这些组件共同协作,为后续的应用程序执行提供稳定的基础。 ... [详细]
  • 在PHP的设计中,预定义了9个超级全局变量、8个魔术变量和13个魔术函数,这些变量和函数无需声明即可在脚本的任意位置使用。这些特性在PHP开发中极为常见,能够显著提升开发效率和代码的灵活性。相比之下,Java并没有类似的内置机制,但通过其他方式如上下文对象和反射机制,也可以实现类似的功能。本文将详细探讨这两种语言中这些特殊变量和函数的使用方法及其应用场景。 ... [详细]
  • 本文作为“实现简易版Spring系列”的第五篇,继前文深入探讨了Spring框架的核心技术之一——控制反转(IoC)之后,将重点转向另一个关键技术——面向切面编程(AOP)。对于使用Spring框架进行开发的开发者来说,AOP是一个不可或缺的概念。了解AOP的背景及其基本原理,对于掌握这一技术至关重要。本文将通过具体示例,详细解析AOP的实现机制,帮助读者更好地理解和应用这一技术。 ... [详细]
  • 本文详细探讨了Zebra路由软件中的线程机制及其实际应用。通过对Zebra线程模型的深入分析,揭示了其在高效处理网络路由任务中的关键作用。文章还介绍了线程同步与通信机制,以及如何通过优化线程管理提升系统性能。此外,结合具体应用场景,展示了Zebra线程机制在复杂网络环境下的优势和灵活性。 ... [详细]
  • 针对NOJ1102黑白图像问题,本文采用深度优先搜索算法进行详细分析与实现。该问题要求在给定的时间限制(普通Java为1000-3000毫秒)和内存限制(65536KByte)内,处理一个n×n的黑白图像。通过对图像的逐像素遍历,利用深度优先搜索算法有效地识别并标记相连的黑色区域,从而实现图像的高效处理。实验结果显示,该方法在多种测试用例中均能稳定达到预期效果,具有较高的准确性和效率。 ... [详细]
  • 利用 Spring BeanUtils 实现 JavaBean 的深度克隆与属性复制 ... [详细]
  • Java 模式原型在游戏服务器架构中的应用与优化 ... [详细]
  • 在PHP扩展开发中,常用宏的合理运用能够显著提升代码的可读性和效率。本文总结并解析了多个关键宏,如 `ZEND_STRL` 用于字符串长度计算,`TSRMLS_D` 用于线程安全资源管理,以及 `TSRMLS_DC` 用于函数参数传递。通过详细解释这些宏的功能和使用场景,帮助开发者更好地理解和应用它们,提高开发效率和代码质量。 ... [详细]
  • 本文详细探讨了Java中Unicode编码的二进制转换方法及其具体实现。通过分析\u开头的字符串,解释了每组\uxxxx如何对应一个特定的Unicode字符,并提供了相关代码示例以加深理解。希望读者在实际开发中能有效应用这些知识。 ... [详细]
  • 本文详细探讨了OpenCV中人脸检测算法的实现原理与代码结构。通过分析核心函数和关键步骤,揭示了OpenCV如何高效地进行人脸检测。文章不仅提供了代码示例,还深入解释了算法背后的数学模型和优化技巧,为开发者提供了全面的理解和实用的参考。 ... [详细]
  • 深入解析JavaScript中的函数防抖与节流技术及其应用场景
    本文深入探讨了JavaScript中函数防抖和节流技术的原理及应用场景。通过详细的示例代码,全面解析了这两种优化方法在实际开发中的重要作用,为开发者提供了宝贵的参考和实践指导。 ... [详细]
  • 分布式开源任务调度框架 TBSchedule 深度解析与应用实践
    本文深入解析了分布式开源任务调度框架 TBSchedule 的核心原理与应用场景,并通过实际案例详细介绍了其部署与使用方法。首先,从源码下载开始,详细阐述了 TBSchedule 的安装步骤和配置要点。接着,探讨了该框架在大规模分布式环境中的性能优化策略,以及如何通过灵活的任务调度机制提升系统效率。最后,结合具体实例,展示了 TBSchedule 在实际项目中的应用效果,为开发者提供了宝贵的实践经验。 ... [详细]
  • Spring Boot 实战(一):基础的CRUD操作详解
    在《Spring Boot 实战(一)》中,详细介绍了基础的CRUD操作,涵盖创建、读取、更新和删除等核心功能,适合初学者快速掌握Spring Boot框架的应用开发技巧。 ... [详细]
  • 本文深入探讨了 MXOTDLL.dll 在 C# 环境中的应用与优化策略。针对近期公司从某生物技术供应商采购的指纹识别设备,该设备提供的 DLL 文件是用 C 语言编写的。为了更好地集成到现有的 C# 系统中,我们对原生的 C 语言 DLL 进行了封装,并利用 C# 的互操作性功能实现了高效调用。此外,文章还详细分析了在实际应用中可能遇到的性能瓶颈,并提出了一系列优化措施,以确保系统的稳定性和高效运行。 ... [详细]
author-avatar
藏A组合别_577
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有