By Casey Allred
@sbditto85
“WebAssembly (abbreviated Wasm) is a binary instruction format for a stack-based virtual machine. Wasm is designed as a portable target for compilation of high-level languages like C/C++/Rust, enabling deployment on the web for client and server applications.”
- WebAssembly Working Group (https://www.w3.org/wasm/)
(module)
“Lisp like” expressions where everything is surrounded in ()
Most simple WASM module is:
which is a module that has nothing and does nothing.
WebAssembly has the following value types:
The value types i32 and i64 are not inherently signed or unsigned. The interpretation of these types is determined by individual operators.
( func <signature> <locals> <body> )
(func $add (param $lhs i32) (param $rhs i32) (result i32)
get_local $lhs
get_local $rhs
i32.add
)
(func $add (param i32) (param i32) (result i32)
get_local 0
get_local 1
i32.add
)
(module
(global $glob (mut i32) (i32.const 100))
(func $add (param $lhs i32) (param $rhs i32) (result i32) (local $loc i32)
i32.const 10
set_local $loc
get_local $lhs
get_local $rhs
i32.add
get_local $loc
i32.add
get_global $glob
i32.add
)
(export "add" (func $add))
)
(module
(global $glob (import "js" "global") i32)
(import "console" "log" (func $log (param i32)))
(func (export "add") (param $lhs i32) (param $rhs i32) (result i32)
i32.const 100
call $log
get_local $lhs
get_local $rhs
i32.add
)
)
var importObject = {
console: {
log: function(arg) {
console.log(arg);
}
}
};
WebAssembly.instantiateStreaming(fetch('logger.wasm'), importObject)
.then(obj => {
console.log(obj.instance.exports.add(1,1));
});
(module
(import "console" "log" (func $log (param i32 i32)))
(import "js" "mem" (memory 1))
(data (i32.const 0) "Hi")
(func (export "writeHi")
i32.const 0 ;; pass offset 0 to log
i32.const 2 ;; pass length 2 to log
call $log))
function consoleLogString(offset, length) {
var bytes = new Uint8Array(memory.buffer, offset, length);
var string = new TextDecoder('utf8').decode(bytes);
console.log(string);
}
var memory = new WebAssembly.Memory({initial:1});
var importObject = { console: { log: consoleLogString }, js: { mem: memory } };
WebAssembly.instantiateStreaming(fetch('logger2.wasm'), importObject)
.then(obj => {
obj.instance.exports.writeHi();
});
(module
(table 2 funcref)
(func $f1 (result i32)
i32.const 42)
(func $f2 (result i32)
i32.const 13)
(elem (i32.const 0) $f1 $f2)
(type $return_i32 (func (result i32)))
(func (export "callByIndex") (param $i i32) (result i32)
local.get $i
call_indirect (type $return_i32))
)
WebAssembly.instantiateStreaming(fetch('wasm-table.wasm'))
.then(obj => {
// returns 42
console.log(obj.instance.exports.callByIndex(0));
// returns 13
console.log(obj.instance.exports.callByIndex(1));
// returns an error, because there is no index position 2 in the table
console.log(obj.instance.exports.callByIndex(2));
});
Let's get rust to do all that for us!