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

Разбираемся, как Wasm считает: на стеке операндов.

Стековая ВМ — машина, где инструкции кладут значения на стек и снимают их оттуда, а не работают с именованными регистрами.

Что такое стек операндов

Wasm — стековая виртуальная машина. Это значит, что вычисления идут через стопку значений, которая работает по принципу «последним пришёл — первым ушёл». Инструкция i32.const 5 кладёт (push) число 5 на вершину стека. Инструкция i32.add снимает (pop) два верхних числа, складывает их и кладёт результат обратно. Никаких имён переменных на этом уровне нет — всё через стек.

Считаем 2 + 3 по шагам

Допустим, мы хотим вычислить 2 + 3. В стековой машине это три инструкции:

i32.const 2    ;; стек: [2]
i32.const 3    ;; стек: [2, 3]
i32.add        ;; снимает 2 и 3, кладёт 5 -> стек: [5]

После выполнения на стеке остаётся ровно одно значение — 5. Так выглядит ядро любой Wasm-функции: последовательность push-инструкций и операций, которые потребляют значения со стека.

Смоделируем это на JavaScript

Чтобы прочувствовать модель, напишем крошечный «интерпретатор» стека на чистом JS.

const stack = [];
function constPush(x) { stack.push(x); }
function add() {
  const b = stack.pop();
  const a = stack.pop();
  stack.push(a + b);
}
constPush(2);
constPush(3);
add();
console.log("Результат на вершине стека:", stack[stack.length - 1]);

Вывод:

Результат на вершине стека: 5

Почему именно стек

У стековой модели три больших плюса для Wasm. Во-первых, компактность: инструкции не указывают регистры-операнды, они и так знают, что брать с вершины стека — байткод получается коротким. Во-вторых, простая валидация: браузер может за один проход проверить, что типы на стеке сходятся (нельзя сложить число с плавающей точкой и целое), и убедиться, что функция корректна. В-третьих, лёгкая компиляция: стековый байткод легко превращается в эффективный код для реальных регистровых процессоров.

Как работает под капотом

Важно: «стековая машина» — это модель, описанная в стандарте. Реальный браузер не держит медленный стек в памяти. При компиляции он анализирует поток инструкций, понимает, какие значения куда идут, и распределяет их по настоящим регистрам процессора. Стек существует логически, для проверки корректности и переносимости, а исполняется всё в регистрах — отсюда и скорость.

Частые ошибки в понимании

  • «Стек медленный, ведь это память» — логический стек компилируется в регистры, реального обращения к памяти на каждый push нет.
  • «Можно оставить лишние значения на стеке» — нет, валидатор требует, чтобы в конце блока стек имел ровно объявленную форму, иначе модуль не пройдёт проверку.
  • «Стек и линейная память — одно и то же» — нет. Стек операндов — для вычислений; линейная память (о ней позже) — отдельное большое хранилище байт.

Итоги

  • Wasm считает через стек операндов: const кладёт, операции снимают и возвращают.
  • Стековая модель даёт компактный байткод, быструю валидацию и лёгкую компиляцию.
  • Логический стек реально компилируется в регистры процессора.
Проверьте себя
1. Что делает инструкция i32.add в стековой машине Wasm?
AКладёт число на стек
BСнимает два верхних значения, складывает и кладёт результат обратно
CОбъявляет переменную
DОчищает весь стек
2. Почему стековая модель удобна для Wasm?
AОна самая быстрая на любом железе
BКомпактный байткод, простая валидация типов и лёгкая компиляция
CОна позволяет писать на любом языке
DОна не требует памяти вообще
3. Где реально исполняется «стек» после компиляции в браузере?
AВ линейной памяти
BВ регистрах процессора
CНа диске
DВ сети