- 作者: 纯情
- 时间:
- 分类: 开源
Android ART虚拟机的编译能力是系统性能的核心支撑,其编译模块集中在art/compiler目录下,遵循“优化器+后端”的精简三段式架构,完美适配移动设备的性能与资源约束。在Android逆向层面,对Android编译时机的理解决定了是否可以进行更深层次的对抗。
一、art/compiler目录结构与核心定位
ART虚拟机省略了编译器前端(源码到Dex字节码的转换已在应用编译期完成),art/compiler目录聚焦优化器与后端实现,整体结构清晰,模块职责解耦,核心目录及功能如下:
核心目录
| 关键文件
| 核心功能
|
compiler/dex
| dex_compilation_unit.cc、dex_to_hir.cc
| Dex字节码解析与处理,将Dex字节码转换为ART自定义中间表示(HIR,核心为HInstruction),是优化器的输入入口
|
compiler/optimizing
| optimizing_compiler.cc、hir_optimizer.cc、pass_manager.cc
| 优化器核心实现,包含HIR优化、Pass管理、寄存器分配等逻辑,是提升代码执行效率的核心模块
|
compiler/codegen
| arm/、x86/、code_generator.cc
| 编译器后端,针对不同硬件架构(ARM、x86等)实现HIR到机器码的转换,适配硬件指令集与寄存器布局
|
compiler/jit
| jit_compiler.cc、jit_compilation_unit.cc
| JIT编译核心逻辑,实现运行时动态编译、热点代码识别与优化,与AOT编译协同工作
|
核心定位:art/compiler通过“Dex字节码→HIR优化→机器码生成”的全流程实现,承载ART虚拟机JIT+AOT混合编译的核心能力,既保证预编译的性能优势,又通过动态编译平衡资源占用。
二、从源码看ART编译核心流程:Dex→HIR→机器码
ART编译的核心链路可概括为“Dex字节码解析→HIR生成与优化→机器码生成”,每个环节均有明确的源码实现支撑,以下结合关键代码片段拆解流程细节。
2.1 第一步:Dex字节码解析与HIR生成(dex→hir)
该环节由dex_to_hir.cc核心驱动,负责将Dex字节码转换为ART自定义的HIR(以HInstruction为基本单位),为后续优化提供标准化中间表示。
源码关键逻辑
在compiler/dex/dex_to_hir.cc的DexToHir::ConvertDexInstruction方法中,通过遍历Dex字节码指令,逐一转换为对应的HInstruction对象:
核心说明
● Dex字节码的寄存器操作(如VRegA、VRegB)通过LoadRegister方法转换为HIR中的寄存器引用,实现Dex指令与HIR的语义对齐。
●不同类型的Dex指令对应不同的HInstruction子类(如加法对应HAdd、常量对应HConst、赋值对应HAssign),HInstruction封装了指令的操作类型、操作数与数据类型,是优化器的核心处理对象。
●该环节最终生成HIR图(Control Flow Graph,CFG),以图结构呈现指令间的依赖关系,为后续优化提供基础。
2.2 第二步:HIR优化(优化器核心)
优化器模块集中在compiler/optimizing目录,由PassManager管理优化任务(Pass)的执行顺序与逻辑,通过多轮Pass优化提升HIR的执行效率,核心优化手段均有对应的源码实现。
1. Pass管理机制(pass_manager.cc)
ART优化器通过PassManager::RunPasses方法调度各类优化Pass,严格控制执行顺序(如常量折叠先于死代码消除),部分源码逻辑如下:
此机制确保优化逻辑的有序执行,避免因顺序不当导致的优化失效(如先执行死代码消除,会遗漏常量折叠产生的无效代码)。
2. 核心优化Pass源码解析
常量折叠(ConstantFoldingPass):在compiler/optimizing/constant_folding.cc中实现,将常量表达式直接计算结果,替换原指令,减少运行时计算开销。
例如,Dex字节码中的10+20会被转换为HAdd指令,经常量折叠后直接替换为HConst(30),大幅简化指令。
死代码消除(DeadCodeEliminationPass):在compiler/optimizing/dead_code_elimination.cc中实现,删除未被引用或无效的HInstruction(如常量折叠后失效的加法指令),减少代码体积与执行冗余。
3. 寄存器分配(RegisterAllocationPass)
寄存器分配是优化器的关键环节,在compiler/optimizing/register_allocation.cc中实现,核心逻辑是将HIR中的虚拟寄存器映射到目标硬件的物理寄存器,未分配到物理寄存器的变量将被暂存到内存。ART采用线性扫描算法(Linear Scan Register Allocation)实现寄存器分配,兼顾效率与资源约束,适配移动设备的有限物理寄存器资源。
2.3 第三步:机器码生成(后端核心)
编译器后端集中在compiler/codegen目录,针对不同硬件架构(ARM、x86)实现CodeGenerator子类,将优化后的HIR转换为对应架构的机器码,核心逻辑由CodeGenerator::GenerateCode驱动。
ARM架构机器码生成示例
在compiler/codegen/arm/code_generator_arm.cc中,针对HAdd指令生成ARM汇编指令(机器码的文本形式):
核心说明
● 后端通过GetArmRegister方法将HIR中的虚拟寄存器位置(Location)映射为ARM架构的物理寄存器(如r0、r1),适配硬件寄存器布局。
● 不同架构的指令集差异通过子类实现屏蔽,如x86架构在code_generator_x86.cc中生成对应的x86汇编指令,实现多硬件架构适配。
●最终生成的机器码会被写入oat文件(AOT编译)或直接交付CPU执行(JIT编译),完成整个编译流程。
三、JIT+AOT混合编译的源码协同逻辑
Android 7.0后ART采用JIT+AOT混合编译,两者通过art/compiler目录下的模块协同工作,平衡性能与资源,核心协同逻辑如下:
AOT编译:应用安装时,由compiler/dex/compiler_driver.cc驱动,调用优化器与后端生成oat文件,将Dex字节码预编译为机器码,核心方法为CompilerDriver::CompileAll,适用于高频执行的核心代码。
JIT编译:运行时由compiler/jit/jit_compiler.cc的JitCompiler::CompileMethod方法驱动,针对热点代码(通过热点计数器识别)动态编译,生成机器码并缓存,避免预编译带来的安装延迟与存储开销。
协同机制:JIT编译生成的优化机器码可被写入oat文件(即“profile-guided compilation”),后续应用启动时直接复用,实现“动态优化→静态复用”的闭环,进一步提升性能。
四、核心总结
art/compiler目录是ART编译机制的核心载体,通过“Dex解析→HIR优化→机器码生成”的模块化设计,实现JIT+AOT混合编译的全流程,适配移动设备的性能与资源需求。
HInstruction作为ART自定义IR的核心,是连接Dex字节码与机器码的关键,优化器通过多轮Pass对HIR进行改造
附:art/compiler核心源码片段合集
以下汇总了全文核心源码片段,按编译流程分类整理,标注对应路径,便于集中对照Android源码学习,片段均保留核心逻辑与关键注释。
一、Dex字节码解析与HIR生成
路径:art/compiler/dex/dex_to_hir.cc(Dex指令转HIR核心方法)
二、HIR优化核心片段
1. Pass管理机制
路径:art/compiler/optimizing/pass_manager.cc(优化任务调度核心)
2. 常量折叠优化
路径:art/compiler/optimizing/constant_folding.cc(常量表达式预计算)
三、机器码生成核心片段(ARM架构)
路径:art/compiler/codegen/arm/code_generator_arm.cc(HIR转ARM机器码)
四、JIT+AOT协同核心片段
1. AOT编译驱动(应用安装期)
路径:art/compiler/dex/compiler_driver.cc(全量编译入口)
2. JIT编译驱动(运行时)
路径:art/compiler/jit/jit_compiler.cc(热点代码动态编译)
标签: 代码生成, ART, Android Runtime, 虚拟机编译, JIT编译, AOT编译, HIR优化, 寄存器分配, 编译器后端, 优化器