Documentation
/
VM Obfuscation
/

Register-Based VM

Register-Based VM

Pro
v7.12.0+

Switch the VM to a register-based execution model for faster runtime and a VM shape that differs from the default.

The vmRegisterBased option switches the VM from its default stack-based bytecode to a register-based execution model. In some cases this improves VM runtime performance by roughly 10-20%, at the cost of a slightly larger obfuscated bundle.

Enabling it turns Stateful Opcodes (vmStatefulOpcodes) off: the two are incompatible, so if vmStatefulOpcodes was on, the register-based build silently drops it.

Stack-based vs register-based

A stack-based VM keeps operands on an implicit stack: each value is pushed, consumed by the next instruction, and the result pushed back. A register-based VM addresses its operands directly instead, so the same work is expressed in fewer instructions with no push/pop traffic between them. That is where the runtime gain comes from - and also why the bytecode grows slightly, since every instruction now has to spell out which registers it reads and writes rather than leaving them implicit on the stack.

Neither model changes what your code does or what the VM protects. They are two encodings of the same virtualized logic; register-based simply trades a little size for a little speed.

When to use it

Reach for it when VM runtime cost matters. Virtualized code is slower than plain JavaScript by design, so on a hot path - an animation loop, a per-frame handler, a tight parsing routine - the ~10-20% the register-based executor can save is worth the larger bundle. On code that runs rarely, the size cost usually is not worth it. The gain depends on the code, so measure it on your own hot paths.

It also varies the VM's shape. Because it emits a structurally different bytecode and executor, the output carries a fingerprint that differs from the common stack-based VM. Generic, pattern-based analysis tuned to that stack-based shape recognizes a register-based build less easily, so this is one way to move the shipped VM away from the default.

How it works under the hood

This is not a native register-based compiler. The regular stack-based compiler still generates the bytecode exactly as it does without the option; a separate transformation stage then rewrites that bytecode into register-based form. Because register-based sits downstream of all of it, most of VM obfuscation - targeting, bytecode encoding, the dispatcher options - is unaffected (Stateful Opcodes aside, see above).

Requirements

  • Requires vmObfuscation - this option only reshapes the VM that vmObfuscation produces.
  • Obfuscator version 7.12.0 or later.

This option is experimental. The register-based rewrite is newer and less battle-tested than the default stack-based path, so test that your code runs correctly with vmRegisterBased enabled before shipping it - the same advice that applies to any VM option, but doubly so here.

Example

JavaScript

Register-based execution combines with the rest of VM obfuscation - Bytecode Encoding, Compact Dispatcher, VM Self Defending, and VM Domain Lock all work exactly as they do with the default stack-based VM. It changes how the bytecode is executed, not what protections wrap it.