(module …)корінь: усе з бінарного .wasm має текстовий відповідникОдин код — дві машини
VTFK · Системне програмування · Модуль 3
Фокус: та сама логіка обчислень, інша модель виконання
WASM успадкував ідею 'мова, близька до заліза', але заради переносності відмовився від регістрів
Кожна функція має явну сигнатуру; невідповідність типів на стеку — помилка ще під час завантаження, не виконання
2 + 3 записується як: i32.const 2; i32.const 3; i32.add — покажіть стан стека після кожної інструкції: [2] → [2, 3] → [5]
(module
(func $add (param $a i32) (param $b i32) (result i32)
local.get $a
local.get $b
i32.add)
(export "add" (func $add)))Той самий add, що і в Л8, тепер для стекової машини
(module …)корінь: усе з бінарного .wasm має текстовий відповідник(func $ім'я …)оголошення функції; типи параметрів і результату обов'язкові(param $a i32) (result i32)сигнатура — перевіряється валідатором до запускуlocal.get / local.setлокальні змінні й параметри — аналог -4(%rbp) з Л8(export "add" (func $add))що видно ззовні модуля, з JavaScript(import "env" "log" …)що модуль отримує від хоста — дзеркало exportS-вирази ((…)) — та сама нотація, що в Lisp: кожен вузол дерева синтаксису явний. wat = WebAssembly Text format
wat2wasm add.watтекст → бінарний .wasm без втрат (wasm2wat — назад)fetch('add.wasm')байти прибувають по мережі — компіляція починається одразуexports.add(2, 3)виклик із JS — звичайна функція, результат 5instantiateStreaming суміщає кроки 2–4: компілює, доки файл ще довантажується
(func $sum_to_n (param $n i32) (result i32)
(local $i i32) (local $acc i32)
(block $break
(loop $continue
local.get $i
local.get $n
i32.ge_s
br_if $break
local.get $acc
local.get $i
i32.add
local.set $acc
local.get $i
i32.const 1
i32.add
local.set $i
br $continue))
local.get $acc)block/loop замінюють мітки .L_cond/.L_end з x86-64
| Конструкція | x86-64 (Л8) | WebAssembly | Аналог у мові |
|---|---|---|---|
| Вихід із ділянки | jmp .L_end | block $b … br $b | break |
| Повтор | jmp .L_cond | loop $c … br $c | continue |
| Умовний перехід | cmp + jge | i32.ge_s + br_if | if (…) break |
| Розгалуження | jcc на мітку | if (result T) … else … end | if / else |
| Довільний стрибок | jmp на будь-яку адресу | неможливий | goto |
br_if знімає i32 зі стека: не нуль — перехід. Структурованість — не стиль, а гарантія: у чужу функцію стрибнути не можна; компілятор генерує ці конструкції з for/while сам
Місток до ЛР8, рівень 3: там студенти вручну пишуть i32.store8/i32.load8_u у лінійну пам'ять і бачать trap при виході за межі
Little-endian, як і в x86-64 (Л8); «база + зсув» тут — фіксована база 0 і i32-адреса. Межі перевіряються при кожному load/store
Той самий приклад, що у флоу вище: 42 лягає як 2a 00 00 00, за межею — trap, а не чужа пам'ять
Очікувано: Console друкує 5; той самий .wat відкривається і виконується без змін у Chrome, Firefox, Node.js
| x86-64 (Л8) | WebAssembly | |
|---|---|---|
| Обчислення | іменовані регістри | операційний стек значень |
| Керування потоком | довільний jmp/jcc на мітку | структуровані block/loop/br/if |
| Пам'ять | увесь адресний простір процесу | ізольована лінійна пам'ять з перевіркою меж |
| Виклик функції | ABI-угода про регістри/стек | типізована сигнатура, перевірена валідатором |
| Перевірка коректності | немає — байти є байти | валідація типів при завантаженні |
| Ціль виконання | конкретний фізичний CPU | будь-який рушій: браузер, Node.js, Wasmtime |
Обидва — «мова, близька до заліза»; різниця в тому, чиє залізо і скільки йому довіряють
Пісочниця (sandbox) — ізольоване середовище, з якого код не дістає до системи; хост (host) — браузер, Node.js, Wasmtime. Тому браузер безпечно запускає WASM з недовіреного сайту
Виняток із правила: memory.grow при відмові повертає -1, а не trap — перевірка на совісті коду
Модуль сам нічого не друкує: без явного import виклику console.log просто не існувало б
(module
(import "env" "log" (func $log (param i32)))
(func $report (param $code i32)
local.get $code
call $log)
(export "report" (func $report)))Модуль сам нічого не друкує — 'log' надає хост через import
Спільне: жодних «голих» міток — лише вкладені структуровані блоки; валідатор перевіряє тип на виході з кожної гілки
Очікувано: Студенти бачать живий приклад капабіліті-моделі: без явного import виклику console.log просто не існувало б
WebAssembly — це безпечний, переносний, низькорівневий формат коду, розроблений для ефективного виконання й компактного представлення.
— WebAssembly Core Specification (W3C), вступ
🥚 У демо-терміналі wasmtime --invoke pixel pixel.wasm 2 3 повертає 5. Спробуйте аргументи 3000 і 101: стекова машина поверне 3101 — 0xC1D. Це число не випадкове: у курсі воно трапляється не раз.