... can be used as a low-level,
efficient target language for compilers.The asm.js language provides an abstraction similar to the C/C++ virtual machine: a large binary heap with efficient loads and stores, integer and floating-point arithmetic, first-order function definitions, and function pointers.
asm.js spec (faq)
... a small, strict subset of JavaScript that only allows things like `while`, `if`, numbers and top level functions.
[...] It does not allow objects, strings, closures, and basically anything that requires heap allocation. mdn
function MyAsmModule(stdlib, foreign, heap) {
"use asm";
// module body...
return {
export1: f1,
// ...
};
}
function add1(x) {
x = x|0; // x : int
return (x+1)|0;
}
var heap = new ArrayBuffer(0x10000); // 64k heap
asm.js spec
so we're compiling some native language
to JavaScript
that looks something like C
so that
the JavaScript Engine can compile it in the Browser
after it has been downloaded
... a simple machine model and executable format with an extensive specification . It is designed to be portable, compact, and execute at or near native speeds
...low-level, assembly-like language rust wasm book
it's 30x FasterWebAssembly is β30Xβ Faster than JavaScript
...of the 24 benchmarks evaluated, seven run within 10% of native execution and almost all of them run less than 2Γ slower.
Bringing the web up to speedkudos steve klabnik
- it's part of the browser
- no plugins, no extra attack surface
- sandboxed just like JavaScript
- not owned by other companies like Flash or Java
- standard, ergo part of "the web"
... everything the Web has to offer
including DOM Apis, WebGL, WebAudio, Canvas, everything you can access from JavaScript
ππ Port your Desktop code to the Web
*here asm.js
(module
(func $i (import "imports" "i") (param i32))
(func (export "e")
i32.const 42
call $i))
almost but not quite entirely unlike TypeScript
any
or undefined
import "allocator/tlsf";
var ptr = memory.allocate(64);
//...
memory.free(ptr);
<html>
<head>
<script src="example.wasm" type="application/wasm"/>
</head>
</html>
.wasm
bytes into a typed array or ArrayBufferWebAssembly.Module
WebAssembly.Module
with imports to get the callable exportsfetch('simple.wasm')
.then(response => response.arrayBuffer())
.then(bytes => WebAssembly.instantiate(bytes, {}))
.then(results => results.instance.exports);
mdn
const obj = await WebAssembly.instantiateStreaming(
fetch('simple.wasm'),
importObject
);
obj.instance.exports.exported_func();
mdn
importObject
? const importObject = {
env: {
logger: (str) => console.info(str)
},
};
π Understanding the JS API
#[no_mangle]
pub fn add(a: i32, b: i32) -> i32 {
a + b + 100
}
// import { add } from 'rust-lib.wasm';
const { add } = await fetch('rust-lib.wasm')
.then(response => response.arrayBuffer())
.then(bytes => WebAssembly.instantiate(bytes))
.then(result => result.instance.exports);
console.dir(add(1,2)); // β 103
const importObject = { env: {
logger_num: (num) => console.info('logger_num', num),
logger_str: (str) => console.warn('logger_str', str),
}}
extern "C" {
fn logger_num(output: i32);
fn logger_str(output: &str);
}
#[no_mangle]
pub unsafe fn speak() {
logger_num(42); // 42
logger_str("42"); // 1048576 ????
}
codegen to the rescue
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet(name: &str) {
alert(&format!("Hello, {}!", name));
}
#[wasm_bindgen]
pub struct Person {
name: String, // UTF-8
}
#[wasm_bindgen]
impl Person {
#[wasm_bindgen(constructor)]
pub fn new(name: String) -> Person {
Self { name }
}
pub fn get_name(&self) -> String {
self.name.to_owned()
}
}
import { Foo } from './my_module';
const p = new Person('hendrik');
console.log(p.get_name());
#[wasm_bindgen(start)]
pub fn run() -> Result<(), JsValue> {
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let body = document.body().unwrap();
let val = document.create_element("p")?;
val.set_inner_html("Hello from Rust!");
body.append_child(&val)?;
Ok(())
}