基于寄存器的 VM
将 VM 切换为基于寄存器的执行模型,以获得更快的运行时以及不同于默认的 VM 形态。
vmRegisterBased 选项将 VM 从其默认的基于栈的字节码切换为基于寄存器的执行模型。在某些情况下,这会将 VM 的运行时性能提升约 15-20 %,代价是混淆后的包体略有增大。
基于栈与基于寄存器
基于栈的 VM 将操作数保存在一个隐式栈上:每个值被压栈,被下一条指令消费,结果再压回栈中。基于寄存器的 VM 则直接寻址其操作数,因此同样的工作用更少的指令表达,指令之间也没有压栈/出栈的往返。运行时的收益正来源于此——这也是字节码略微增大的原因,因为现在每条指令都必须写明它读写哪些寄存器,而不是把它们隐式地留在栈上。
两种模型都不会改变你的代码所做的事,也不会改变 VM 所保护的内容。它们是同一套虚拟化逻辑的两种编码;基于寄存器只是用一点体积换取一点速度。
何时使用
当 VM 的运行时开销重要时再用它。 虚拟化代码按设计本就比普通 JavaScript 慢,因此在热路径上——动画循环、逐帧处理器、紧凑的解析例程——基于寄存器的执行器能省下的 ~15-20 % 值得更大的包体。而对于很少运行的代码,体积代价通常并不划算。
它还会改变 VM 的形态。 由于它生成结构上不同的字节码与执行器,其输出携带的指纹比默认的基于栈的 VM 更为独特。如果你希望交付的 VM 与常见的基于栈的那种不太相像——以便更难被通用的、基于模式的分析识别——这就是改变它的一种方式。
底层如何工作
这不是一个原生的基于寄存器的编译器。字节码仍由一如既往的基于栈的编译器生成,与不启用该选项时完全一样;随后由一个独立的转换阶段将该字节码改写为基于寄存器的形式。实际后果是,VM 混淆的其余一切——定向、字节码编码、调度器选项——行为都保持不变,因为基于寄存器的模式位于这一切的下游。
要求
- 需要
vmObfuscation——该选项只是对vmObfuscation生成的 VM 进行重新塑形。 - Obfuscator 版本 7.12.0 或更高。
示例
JavaScriptObfuscator.obfuscate(code, {
vmObfuscation: true,
vmRegisterBased: true
});
