Сервис развивается: тестируем формат, собираем идеи, улучшаем сервис. Есть идеи?

Написать
Войти
Дайджесты
Сравнение стековой и регистровой архитектуры виртуальных машин в WebAssembly и PolkaVM

Пределы WebAssembly за пределами браузера: почему регистровые виртуальные машины выигрывают у стекового байткода

Анализ архитектурных ограничений WebAssembly при исполнении вне браузера показывает, почему проекты вроде Polkadot переходят на регистровую модель PolkaVM на базе RISC-V. Рассматриваются особенности однопроходной компиляции, безопасность памяти, накладные расходы WASI и сценарии применения.

Пределы WebAssembly за пределами браузера: почему регистровые виртуальные машины выигрывают у стекового байткода

Технология WebAssembly (WASM) изначально проектировалась как компактный и безопасный формат байткода для выполнения высокопроизводительного кода внутри веб-браузеров. Благодаря строгой изоляции линейной памяти (Linear Memory) и поддержке со стороны ключевых разработчиков браузерных движков, WASM быстро обрел популярность и за пределами веба. Его стали активно применять в серверных бессерверных вычислениях (Serverless), системах плагинов и даже в среде исполнения смарт-контрактов для блокчейн-платформ.

Однако по мере расширения сферы применения инженеры начали сталкиваться с фундаментальными архитектурными ограничениями, заложенными в основу WebAssembly. В частности, экосистема Polkadot объявила о постепенном переходе в сфере смарт-контрактов со стандартного WASM на собственную виртуальную машину PolkaVM, построенную на базе регистровой архитектуры RISC-V. Разбор причин этого шага проливает свет на ключевые различия между стековыми и регистровыми виртуальными машинами в серверных средах с высокой нагрузкой.

Стековая vs Регистровая модель: Анатомия байткода

Главное архитектурное различие между классическим WASM и PolkaVM заключается в способе хранения и адресации операндов при выполнении инструкций.

Стековая виртуальная машина (WebAssembly)

В стековой VM инструкции не указывают явные адреса аргументов. Все операции выполняются над вершиной абстрактного стека данных:

  1. Инструкция i32.const 10 помещает число 10 на стек.
  2. Инструкция i32.const 20 помещает число 20 на стек.
  3. Инструкция i32.add извлечет два верхних элемента со стека, сложит их и поместит результат 30 обратно на стек.

Преимущество: Очень компактный размер бинарного байткода, так как инструкциям не нужно хранить индексы регистров. Это было ключевым требованием для передачи JS/WASM по сети в браузере. Недостаток: Длинный цепочки инструкций (high instruction count). Каждая банальная операция требует множества вызовов push/pop, что увеличивает количество циклов декодирования в интерпретаторе.

Регистровая виртуальная машина (PolkaVM / RISC-V)

В регистровой VM инструкции явно ссылаются на именованные ячейки памяти (регистры). Пример инструкции на базе RISC-V: add r3, r1, r2 (сложить содержимое регистров r1 и r2 и записать результат прямо в r3).

Преимущество: Меньшее количество инструкций для выполнения той же логической операции. Прямое соответствие между виртуальными регистрами байткода и физическими регистрами современных процессоров (x86-64, ARM64). Недостаток: Чуть больший размер инструкции в байтах.

Стековая модель (WASM):
 [Push A] -> [Push B] -> [ADD] -> [Pop Result]  (4 инструкции)

Регистровая модель (RISC-V / PolkaVM):
 [ADD R3, R1, R2]                                (1 инструкция)

Проблема однопроходной компиляции и защита от DoS-атак

В обычных серверных приложениях код компилируется один раз при деплое, после чего исполняется миллионы раз. Однако в распределенных сетях смарт-контрактов или в multi-tenant бессерверных средах ситуация принципиально иная: узел получает недоверенный байткод от стороннего пользователя и должен моментально скомпилировать и валидировать его перед исполнением.

Здесь вступает в силу проблема однопроходной JIT-компиляции (Single-pass Baseline Compilation):

  1. Стирание информации о потоке данных: Стековый байткод WebAssembly на этапах ветвления (if/else) или циклов (loop) не содержит явной информации о том, какие значения сохраняются на стеке между блоками.
  2. Накладные расходы компилятора: Быстрый однопроходный компилятор (например, Liftoff в V8 или Winch в Wasmtime) вынужден во время трансляции восстанавливать граф движения данных и генерировать дополнительный служебный код (shuffle code) для выравнивания стека.
  3. Уязвимость к DoS: Злоумышленник может специально сформировать запутанный WASM-файл с глубокой вложенностью стековых операций. Компиляция такого файла потребует огромных затрат CPU, что приведет к отказу в обслуживании (Denial of Service) узла сети еще до начала выполнения кода и списывания комиссии.

PolkaVM на базе RISC-V решает эту проблему. Поскольку регистровая архитектура хранит поток данных абсолютно явно, однопроходный компилятор транслирует байткод PolkaVM в нативный машинный код x86-64 почти с линейной скоростью без сложных вычислений графа состояний.

Границы песочницы, WASI и накладные расходы

Еще один важный аспект применения WebAssembly за пределами браузера — взаимодействие с внешним миром через спецификацию WASI (WebAssembly System Interface).

WASM-модуль не имеет прямого доступа к файловой системе, сети или системным вызовам ОС. Любое взаимодействие происходит через явно переданные импортируемые функции (Imports). В рамках спецификации Component Model при передаче сложных структур данных (например, строк или JSON) через границу песочницы происходит их сериализация, проверка типов и копирование в линейную память модуля.

Сценарий использованияНасколько подходит WebAssembly?Обоснование
Плагины для IDE и графических редакторовИдеальноВыделенная песочница, быстрый запуск, защита основного приложения от падения плагина.
Edge Serverless (Cloudflare Workers)ОтличноМинимальное время холодного старта по сравнению с тяжелыми Docker-контейнерами.
Смарт-контракты в блокчейнеОграниченноВысокие риски DoS при компиляции стекового кода; переходят на регистровые VM (PolkaVM).
Высоконагруженный бэкенд с БДНе подходитНакладные расходы на границах WASI и копирование памяти проигрывают нативному коду на Go/Rust.

Практические выводы для архитекторов

  1. WebAssembly — не замена Docker: Контейнеры изолируют операционную систему целиком, предоставляя полноценное окружение POSIX, в то время как WASM изолирует отдельный модуль на уровне инструкций и памяти.
  2. Модель угроз определяет выбор VM: Если ваша система принимает чужой код из внешнего мира, делайте ставку на предсказуемость времени компиляции и строгое ограничение ресурсов (metering).
  3. Учитывайте накладные расходы границы: Если ваше приложение постоянно прокачивает гигабайты данных через вызовы WASI, расходы на копирование памяти превысят выгоду от изоляции.