Mengenal WebAssembly Runtime

Ketika wasm tidak hanya berjalan di lingkungan web.

Sebagaimana yang sudah kita bahas sebelumnya disini, setiap "program" memiliki runtime nya sendiri. Seperti file JAR yang runtime nya adalah JVM, ataupun Node.js yang runtime nya adalah v8.

Begitupula dengan WebAssembly, sejauh yang kita tau runtime WebAssembly berada di browser yang sudah mendukung WebAssembly. Dan beruntungnya, mayoritas evergreen browsers sudah mendukung wasm.

Sebelum kita membahas ke topik utama, mari kita bahas tentang mengapa Runtime Wasm ini menarik!

Ergonomics™

Jika kamu seorang polyglot, tentunya membuat program menggunakan beragam bahasa program bukanlah hal yang lumayan sulit dan membuat frustasi.

Sekarang, berbagai (target bahasa) program sudah bisa berjalan diberbagai platform, contohnya adalah ehm JavaScript.

JavaScript bisa berjalan baik di lingkungan Desktop (via Node.js), lingkungan mobile (via JavaScriptCore atau Hermes, for future?), dsb yang masih banyak lagi.

Keuntungan di sisi ergonomi nya untuk "programmer" yang menulis kode JavaScript adalah mereka membuat program, dengan satu "bahasa" program, untuk lebih-dari-satu platform, dengan biaya yang tidak terlalu overhead.

Meskipun ini ada plus-minus nya—its like, wow we write anything in JavaScript!—tapi untuk sebagian kalangan, ini menjadi hal yang efisien. Khususnya untuk mereka yang memiliki sumber daya developers yang minim.

Sehingga developers bisa "bergerak cepat", dengan peluang "ke-frustasi-an" se-minimum mungkin.

Cost

Tidak ada yang gratis dalam sebuah keputusan, pasti ada "resiko" yang harus dihadapi.

Kita ambil contoh dari bagian sebelumnya—tentang cross-platform—yang mana program yang dibuat menggunakan JavaScript (kita ambil contoh via React Native) akan memiliki bundle-size yang lebih besar daripada yang dibuat menggunakan native.

Disini, cost nya adalah di Bundle size.

Dan seperti yang sudah kita tau, semakin besar bundle size nya berarti semakin banyak kode yang harus dieksekusi.

Aplikasi native—aplikasi/program yang dibuat menggunakan "bahasa resminya"—memiliki keuntungan baik di performa, app size, ataupun kompatibilitas API.

Namun sekali lagi, untuk kamu seorang "pembuat keputusan", kebijakanmu dalam mengalokasikan biaya di sisi engineering, berperan disini.

Sedang butuh efektivitas atau efisiensi?

Korelasi

Platform web, sedang "mem-push" kapabilitasnya dalam menjalankan sebuah aplikasi.

Yang mana, dengan "membandingkan" terhadap aplikasi native.

Seperti, WebGL yang mentenagai aplikasi web yang memiliki proses rendering yang kompleks namun agar tetap efisien.

Atau Web Worker untuk mentenagai aplikasi yang memiliki proses komputasi yang berat—dan tidak ingin mengganggu main thread dalam rendering—sehingga proses aplikasi terasa lebih smooth.

Dan juga Service Worker yang biasanya untuk mentenagai aplikasi agar bisa berjalan meskipun tanpa koneksi internet.

Sekarang, inovasi terbarunya adalah WebAssembly. Bila sebelumnya "kode native" diubah menjadi kode JavaScript via Asm.js—yang mana "masih" kode JavaScript juga—sekarang, kode tersebut bisa diubah menjadi...

Sebuah "instruksi" yang hampir sama dengan kode assembly yang mana kode tersebut di-optimasi untuk mesin.

Dan, ya, bukan menjadi kode JavaScript. Berarti tidak proses parsing, tokenization, dsb.

Sehingga program yang dibuat menjadi wasm, diasumsikan akan dieksekusi lebih cepat daripada yang dibuat menjadi kode JavaScript.

What if?

Kita sudah mulai masuk ke pembahasan inti.

Seperti yang kita tau, kode wasm untuk sekarang hanya bisa dieksekusi di browser.

Sekarang, mari kita bertanya. Bagaimana bila kode wasm tersebut bisa dieksekusi juga di platform selain browser?

Oke, mungkin kalian beranggapan "ini overhead, wasm kan relatif dibuat menggunakan 'system-level programming language', kenapa harus dikompilasi ke wasm kalau bisa langsung ke native/target mesin?"

Pertanyaan menarik.

Mari kita bahas dikit-dikit.

Prinsip utama yang ditawarkan WebAssembly adalah keamanan dan portabilitas.

Dan inilah poin inti yang kita bahas.

Security what

Ketika kita berbicara tentang security, pertanyaan nya adalah "untuk siapa?".

Dan di konteks ini adalah, baik untuk pengguna ataupun developers.

Di level pengguna, singkatnya, keamanan terjamin karena program berjalan di sandboxed environment yang terpisah dengan runtime utama.

Untuk level developers, singkatnya, terjaminnya keamanan berada di bug memory safety.

Kasus yang paling umum adalah Buffer Overflow, yang singkatnya adalah sebuah celah ketika program mencoba menyimpan data ke memori namun melebihi kapasitas yang telah dialokasikan.

Yang mana bisa di-eksploitasi oleh penyerang untuk menjalankan program yang "berbahaya".

Dan Wasm menjanjikan memory safety.

Portability what

Design goals wasm adalah agar "program" wasm bisa berjalan di berbagai sistem operasi, dan baik itu di platform web ataupun bukan.

Di web sudah jelas, bagaimana untuk yang non-web? Apakah bisa menjalankan program wasm?

Sebagaimana dengan design goals nya, so yes.

Dan juga, selain portability disini yang berarti program bisa berjalan di berbagai host environment, juga agar fungsionalitas program yang dibuat ke wasm bisa dipanggil dari bahasa program lain.

Seperti yang biasa kita lakukan via WebAssembly.instantiate untuk di JavaScript. Mungkin di bahasa program lain (seperti Rust, C, C++) kita bisa juga melakukannya via API yang mungkin akan mengikuti non-web standar (seperti POSIX).

WebAssembly Runtime

Oke, sekarang kita masuk ke pembahasan inti.

Sejauh ini, ada 3 WebAssembly runtime (diluar lingkungan web) yang bisa digunakan:

  • Wasmer (Wasmer, Inc)
  • Lucet (Fastly, Inc)
  • Wasmtime (Bytecode Alliance)

Disini kita tidak membahas detailnya tentang perbedaan 3 runtime tersebut—mungkin akan kita bahas dipost selanjutnya—tapi disini kita akan mencoba menggunakan Wasmtime yang diinisiasi oleh Bytecode Alliance.

Instalasi Wasmtime

Kita mulai dari mengunduh runtime nya terlebih dahulu.

curl https://wasmtime.dev/install.sh -sSf | bash

Jika sudah, verifikasi hasil instalasi dengan menjalankan perintah berikut:

wasmtime --version

Jika muncul versi nya, berarti berhasil.

Membuat project

Kita akan menggunakan Rust disini, dengan versi 1.40.0.

Program yang dibuat adalah meng-konversi plain text menjadi md5 dengan bantuan crate bernama md5. Seperti biasa, buat project baru dengan template untuk binary:

cargo new --bin <nama_project>

Lalu ubah file src/main.rs menjadi seperti ini:

use std::env;

fn raw_to_md5(string: &str) -> String {
    let digest = md5::compute(string);
    format!("{:?}", digest)
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();

    if args.len() < 2 {
        eprintln!("{} <text>", program);
        return;
    }

    println!("Text : {}", &args[1]);
    println!("MD5  : {}", raw_to_md5(&args[1]));
}

Kode diatas diambil dari sini dengan sedikit modifikasi untuk menyesuaikan target compile.

Fungsi main hanya berguna untuk mengambil parameter yang dibawa ketika mengeksekusi, menampilkan pesan bila tidak membawa parameter, dan menampilkan hasil md5 nya.

Sebelum melakukan build, pastikan target wasm32-wasi sudah ter-install di mesin kamu. Jika belum, install dulu dong:

rustup target add wasm32-wasi

Oke jika sudah, mari kita build:

cargo build --target wasm32-wasi

File wasm akan berada di target/wasm32-wasi/debug/<nama_project>.wasm. Untuk sekarang kita tidak akan berbicara tentang "optimasi", mari kita coba jalankan program tersebut!

wasmtime target/wasm32-wasi/debug/ya.wasm "hello world"

Dan ini hasilnya:

Mari kita lihat perbedaan dengan tanpa wasmtime:

Dari sisi size lumayan besar juga perbedaan nya, mari kita lihat disisi performa dengan melakukan microbenchmark:

Pastinya menang native, tapi ini sangat menarik!

Tentang WASI

Hal menarik yang pertama disini adalah kita melakukan target kompilasi untuk wasi, bukan darwin ataupun linux.

WASI atau WebAssembly System Interface adalah sebuah "standar" untuk membuat runtime wasm diluar platform web yang bisa dipelajari lebih lanjut disini.

Ukuran sekitar ~2.1M sangatlah besar, mengingat program yang kita buat sangat sederhana. Namun dengan melakukan proses optimasi di level compiler, tentu ukuran tersebut akan menjadi lumayan kecil.

Penutup

Ini sangat menarik dan lumayan menantang.

Kita akan terus mengikuti perkembangan baik WASI maupun Wasm itu sendiri.

Jika Wasm yang kita kenal sebelumnya hanya berjalan di lingkungan web, sekarang bisa dibuat menjadi sebuah "aplikasi" CLI yang berjalan di lingkungan OS.

Ditulisan selanjutnya (mungkin) kita akan membandingkan antara Wasmer, Laucet, dan Wasmtime. Stay tune!

Thank you.