Замикання лінії курсу
VTFK · Системне програмування · Модуль 3
Фокус: WASM як компільований бекенд, а не мова для ручного письма
Компілятор Rust розв'язує ту саму задачу компіляції, що й gcc -S у Л8, лише для іншої машини
Той самий байт-код на виході; змінюється лише те, хто його пише — людина чи компілятор
Той самий rustc, що збирав x86-64 у Модулях 1–2, — інша ціль компіляції
| Частина | Значення | Що означає |
|---|---|---|
| архітектура | wasm32 | 32-бітна адресація лінійної пам'яті |
| виробник | unknown | для віртуальної машини не має сенсу |
| ОС | unknown | немає ОС: жодного libc, жодних системних викликів |
| сусідня ціль | wasm32-wasi (wasip1/wasip2) | POSIX-подібні виклики через WASI — поза браузером |
rustup target add wasm32-unknown-unknown — одноразово. Курс тримається unknown-unknown, бо мета — сторінка в браузері, а не окремий бінарник
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn greet(name: &str) -> String {
format!("Вітаю, {name}! Ядро на зв'язку.")
}Атрибут #[wasm_bindgen] позначає межу з JavaScript
Це і є маршалінг (marshalling) — перетворення значень при перетині межі між WASM-модулем (guest) і JS-хостом (host). i32/f64 проходять напряму — вони й так типи WASM
i32/f64 — типи самої машини WASM; JS-рядок у модуль не входить — входить лише (ptr, len)
wasm-pack — те саме, що cargo build, тільки для цілі wasm32 з додатковою генерацією обгортки
| Файл | Що це | Хто використовує |
|---|---|---|
sid_core_bg.wasm | сам бінарник модуля | браузер через init() |
sid_core.js | ES-модуль: init(), greet(), класи | <script type="module"> |
sid_core.d.ts | типи експортів | TypeScript, редактор |
package.json | метадані пакета | npm, бандлери |
--target web — ES-модуль без бандлера; --target bundler — Webpack/Vite; --target nodejs — CommonJS
<script type="module">
import init, { greet } from './pkg/sid_core.js';
await init();
document.querySelector('#btn').onclick = () => {
console.log(greet('С.І.Д.'));
};
</script>init() підвантажує і інстанціює .wasm; greet — вже звичайна JS-функція
| Rust-тип | Що передається фактично | Вартість |
|---|---|---|
i32, u32, f64, bool | напряму, як число WASM | нуль — нативний тип |
&str, String | (вказівник, довжина) + копія UTF-8 | TextEncoder/TextDecoder |
Vec<T> з числами | вказівник + довжина → TypedArray | одна копія через ArrayBuffer |
struct з #[wasm_bindgen] | непрозорий JS-клас із вказівником | геттери/сеттери від макроса |
| enum з даними, вкладені типи | серіалізація (serde-wasm-bindgen, JSON) | найдорожче |
Правило гарячого шляху: чим простіший тип на межі, тим дешевший виклик. Порівняти з Л8: там межею була угода ABI, тут — контракт wasm-bindgen
У WASM немає збирача сміття: JS-об'єкт зникне, а пам'ять усередині модуля — ні. Жоден JS-профайлер цей витік не покаже
Очікувано: Клік по кнопці друкує рядок, згенерований у Rust, скомпільований у WASM, викликаний із JS
Це замикає лінію курсу: контейнер (Модуль 1) знову стає інструментом гарантії, тепер для збірки WASM
FROM rust:1.82-slim
RUN rustup target add wasm32-unknown-unknown
RUN cargo install wasm-pack --version 0.13.1 --locked
WORKDIR /build
COPY Cargo.toml Cargo.lock ./
COPY src ./src
RUN wasm-pack build --target web --releaseФіксовані версії образу, wasm-pack і Cargo.lock — три складові відтворюваності
Дрібниця, яку легко забути й довго шукати в проді
Очікувано: Хеші .wasm-файлів з обох запусків збігаються побайтово — доказ відтворюваності
| Межа | Модуль | Що ізолює / перевіряє | Хто перевіряє |
|---|---|---|---|
| Процес у контейнері | М1 | простори імен, cgroups — те саме ядро Linux | ядро (namespaces) |
| Безпечний доступ до пам'яті | М2 | володіння й запозичення Rust | компілятор (borrow checker) |
| Переносний набір інструкцій | М3 | від x86-64 до WASM: один алгоритм, дві машини | рушій (валідація модуля) |
Спільний мотив: ізоляція й перевірка відбуваються якомога раніше — в ядрі, компіляторі або при завантаженні модуля, а не «десь у рантаймі, якщо пощастить»
Підсумковий слайд усього курсу, не лише лекції
Не можна довіряти коду, який ви не створили повністю самі. Жоден обсяг перевірки чи аналізу вихідного тексту не захистить вас від використання недовіреного коду.
— Кен Томпсон, «Reflections on Trusting Trust» (Тюрінгівська лекція, 1984)
🥚 У демо-терміналі хеш зібраного модуля починається з c1d0…: перші три шістнадцяткові цифри — 0xC1D, тобто 3101. Це число супроводжувало приклади від перших лекцій; тут воно замикає коло.