Стековая виртуальная машина
Разбираемся, как 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 кладёт, операции снимают и возвращают.
- Стековая модель даёт компактный байткод, быструю валидацию и лёгкую компиляцию.
- Логический стек реально компилируется в регистры процессора.