<span class="hljs-comment">;; content with thanks to</span> <span class="hljs-comment">;; https://learnxinyminutes.com/docs/wasm/</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">module</span> <span class="hljs-comment">;; In WebAssembly, everything is included in a module. Moreover, everything</span> <span class="hljs-comment">;; can be expressed as an s-expression. Alternatively, there is the</span> <span class="hljs-comment">;; "stack machine" syntax, but that is not compatible with Binaryen</span> <span class="hljs-comment">;; intermediate representation (IR) syntax.</span> <span class="hljs-comment">;; The Binaryen IR format is *mostly* compatible with WebAssembly text format.</span> <span class="hljs-comment">;; There are some small differences:</span> <span class="hljs-comment">;; local_set -> local.set</span> <span class="hljs-comment">;; local_get -> local.get</span> <span class="hljs-comment">;; We have to enclose code in functions</span> <span class="hljs-comment">;; Data Types</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">func</span> <span class="hljs-title function_">$data_types</span> <span class="hljs-comment">;; WebAssembly has only four types:</span> <span class="hljs-comment">;; i32 - 32 bit integer</span> <span class="hljs-comment">;; i64 - 64 bit integer (not supported in JavaScript)</span> <span class="hljs-comment">;; f32 - 32 bit floating point</span> <span class="hljs-comment">;; f64 - 64 bit floating point</span> <span class="hljs-comment">;; We can declare local variables with the "local" keyword</span> <span class="hljs-comment">;; We have to declare all variables before we start doing anything</span> <span class="hljs-comment">;; inside the function</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local</span> <span class="hljs-variable">$int_32</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local</span> <span class="hljs-variable">$int_64</span> <span class="hljs-type">i64</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local</span> <span class="hljs-variable">$float_32</span> <span class="hljs-type">f32</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local</span> <span class="hljs-variable">$float_64</span> <span class="hljs-type">f64</span><span class="hljs-punctuation">)</span> <span class="hljs-comment">;; These values remain uninitialized.</span> <span class="hljs-comment">;; To set them to a value, we can use <type>.const:</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.set</span> <span class="hljs-variable">$int_32</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.const</span> <span class="hljs-number">16</span><span class="hljs-punctuation">))</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.set</span> <span class="hljs-variable">$int_32</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i64.const</span> <span class="hljs-number">128</span><span class="hljs-punctuation">))</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.set</span> <span class="hljs-variable">$float_32</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">f32.const</span> <span class="hljs-number">3.14</span><span class="hljs-punctuation">))</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.set</span> <span class="hljs-variable">$float_64</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">f64.const</span> <span class="hljs-number">1.28</span><span class="hljs-punctuation">))</span> <span class="hljs-punctuation">)</span> <span class="hljs-comment">;; Basic operations</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">func</span> <span class="hljs-title function_">$basic_operations</span> <span class="hljs-comment">;; In WebAssembly, everything is an s-expression, including</span> <span class="hljs-comment">;; doing math, or getting the value of some variable</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local</span> <span class="hljs-variable">$add_result</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local</span> <span class="hljs-variable">$mult_result</span> <span class="hljs-type">f64</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.set</span> <span class="hljs-variable">$add_result</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.add</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.const</span> <span class="hljs-number">2</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.const</span> <span class="hljs-number">4</span><span class="hljs-punctuation">)))</span> <span class="hljs-comment">;; the value of add_result is now 6!</span> <span class="hljs-comment">;; We have to use the right data type for each operation:</span> <span class="hljs-comment">;; (local.set $mult_result (f32.mul (f32.const 2.0) (f32.const 4.0))) ;; WRONG! mult_result is f64!</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.set</span> <span class="hljs-variable">$mult_result</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">f64.mul</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">f64.const</span> <span class="hljs-number">2.0</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">f64.const</span> <span class="hljs-number">4.0</span><span class="hljs-punctuation">)))</span> <span class="hljs-comment">;; WebAssembly has some builtin operations, like basic math and bitshifting.</span> <span class="hljs-comment">;; Notably, it does not have built in trigonometric functions.</span> <span class="hljs-comment">;; In order to get access to these functions, we have to either</span> <span class="hljs-comment">;; - implement them ourselves (not recommended)</span> <span class="hljs-comment">;; - import them from elsewhere (later on)</span> <span class="hljs-punctuation">)</span> <span class="hljs-comment">;; Functions</span> <span class="hljs-comment">;; We specify arguments with the `param` keyword, and specify return values</span> <span class="hljs-comment">;; with the `result` keyword</span> <span class="hljs-comment">;; The current value on the stack is the return value of a function</span> <span class="hljs-comment">;; We can call other functions we've defined with the `call` keyword</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">func</span> <span class="hljs-title function_">$get_16</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">result</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.const</span> <span class="hljs-number">16</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">func</span> <span class="hljs-title function_">$add</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">param</span> <span class="hljs-variable">$param0</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">param</span> <span class="hljs-variable">$param1</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">result</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.add</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.get</span> <span class="hljs-variable">$param0</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.get</span> <span class="hljs-variable">$param1</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">func</span> <span class="hljs-title function_">$double_16</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">result</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.mul</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.const</span> <span class="hljs-number">2</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">call</span> <span class="hljs-title function_">$get_16</span><span class="hljs-punctuation">))</span> <span class="hljs-punctuation">)</span> <span class="hljs-comment">;; Up until now, we haven't be able to print anything out, nor do we have</span> <span class="hljs-comment">;; access to higher level math functions (pow, exp, or trig functions).</span> <span class="hljs-comment">;; Moreover, we haven't been able to use any of the WASM functions in Javascript!</span> <span class="hljs-comment">;; The way we get those functions into WebAssembly</span> <span class="hljs-comment">;; looks different whether we're in a Node.js or browser environment.</span> <span class="hljs-comment">;; If we're in Node.js we have to do two steps. First we have to convert the</span> <span class="hljs-comment">;; WASM text representation into actual webassembly. If we're using Binyaren,</span> <span class="hljs-comment">;; we can do that with a command like the following:</span> <span class="hljs-comment">;; wasm-as learn-wasm.wast -o learn-wasm.wasm</span> <span class="hljs-comment">;; We can apply Binaryen optimizations to that file with a command like the</span> <span class="hljs-comment">;; following:</span> <span class="hljs-comment">;; wasm-opt learn-wasm.wasm -o learn-wasm.opt.wasm -O3 --rse</span> <span class="hljs-comment">;; With our compiled WebAssembly, we can now load it into Node.js:</span> <span class="hljs-comment">;; const fs = require('fs')</span> <span class="hljs-comment">;; const instantiate = async function (inFilePath, _importObject) {</span> <span class="hljs-comment">;; var importObject = {</span> <span class="hljs-comment">;; console: {</span> <span class="hljs-comment">;; log: (x) => console.log(x),</span> <span class="hljs-comment">;; },</span> <span class="hljs-comment">;; math: {</span> <span class="hljs-comment">;; cos: (x) => Math.cos(x),</span> <span class="hljs-comment">;; }</span> <span class="hljs-comment">;; }</span> <span class="hljs-comment">;; importObject = Object.assign(importObject, _importObject)</span> <span class="hljs-comment">;;</span> <span class="hljs-comment">;; var buffer = fs.readFileSync(inFilePath)</span> <span class="hljs-comment">;; var module = await WebAssembly.compile(buffer)</span> <span class="hljs-comment">;; var instance = await WebAssembly.instantiate(module, importObject)</span> <span class="hljs-comment">;; return instance.exports</span> <span class="hljs-comment">;; }</span> <span class="hljs-comment">;;</span> <span class="hljs-comment">;; const main = function () {</span> <span class="hljs-comment">;; var wasmExports = await instantiate('learn-wasm.wasm')</span> <span class="hljs-comment">;; wasmExports.print_args(1, 0)</span> <span class="hljs-comment">;; }</span> <span class="hljs-comment">;; The following snippet gets the functions from the importObject we defined</span> <span class="hljs-comment">;; in the JavaScript instantiate async function, and then exports a function</span> <span class="hljs-comment">;; "print_args" that we can call from Node.js</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">import</span> <span class="hljs-string">"console"</span> <span class="hljs-string">"log"</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">func</span> <span class="hljs-title function_">$print_i32</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">param</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)))</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">import</span> <span class="hljs-string">"math"</span> <span class="hljs-string">"cos"</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">func</span> <span class="hljs-title function_">$cos</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">param</span> <span class="hljs-type">f64</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">result</span> <span class="hljs-type">f64</span><span class="hljs-punctuation">)))</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">func</span> <span class="hljs-title function_">$print_args</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">param</span> <span class="hljs-variable">$arg0</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">param</span> <span class="hljs-variable">$arg1</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">call</span> <span class="hljs-title function_">$print_i32</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.get</span> <span class="hljs-variable">$arg0</span><span class="hljs-punctuation">))</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">call</span> <span class="hljs-title function_">$print_i32</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.get</span> <span class="hljs-variable">$arg1</span><span class="hljs-punctuation">))</span> <span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">export</span> <span class="hljs-string">"print_args"</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">func</span> <span class="hljs-title function_">$print_args</span><span class="hljs-punctuation">))</span> <span class="hljs-comment">;; Loading in data from WebAssembly memory.</span> <span class="hljs-comment">;; Say that we want to apply the cosine function to a Javascript array.</span> <span class="hljs-comment">;; We need to be able to access the allocated array, and iterate through it.</span> <span class="hljs-comment">;; This example will modify the input array inplace.</span> <span class="hljs-comment">;; f64.load and f64.store expect the location of a number in memory *in bytes*.</span> <span class="hljs-comment">;; If we want to access the 3rd element of an array, we have to pass something</span> <span class="hljs-comment">;; like (i32.mul (i32.const 8) (i32.const 2)) to the f64.store function.</span> <span class="hljs-comment">;; In JavaScript, we would call `apply_cos64` as follows</span> <span class="hljs-comment">;; (using the instantiate function from earlier):</span> <span class="hljs-comment">;;</span> <span class="hljs-comment">;; const main = function () {</span> <span class="hljs-comment">;; var wasm = await instantiate('learn-wasm.wasm')</span> <span class="hljs-comment">;; var n = 100</span> <span class="hljs-comment">;; const memory = new Float64Array(wasm.memory.buffer, 0, n)</span> <span class="hljs-comment">;; for (var i=0; i<n; i++) {</span> <span class="hljs-comment">;; memory[i] = i;</span> <span class="hljs-comment">;; }</span> <span class="hljs-comment">;; wasm.apply_cos64(n)</span> <span class="hljs-comment">;; }</span> <span class="hljs-comment">;;</span> <span class="hljs-comment">;; This function will not work if we allocate a Float32Array on the JavaScript</span> <span class="hljs-comment">;; side.</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">memory</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">export</span> <span class="hljs-string">"memory"</span><span class="hljs-punctuation">)</span> <span class="hljs-number">100</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">func</span> <span class="hljs-title function_">$apply_cos64</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">param</span> <span class="hljs-variable">$array_length</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-comment">;; declare the loop counter</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local</span> <span class="hljs-variable">$idx</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-comment">;; declare the counter that will allow us to access memory</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local</span> <span class="hljs-variable">$idx_bytes</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-comment">;; constant expressing the number of bytes in a f64 number.</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local</span> <span class="hljs-variable">$bytes_per_double</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-comment">;; declare a variable for storing the value loaded from memory</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local</span> <span class="hljs-variable">$temp_f64</span> <span class="hljs-type">f64</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.set</span> <span class="hljs-variable">$idx</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.const</span> <span class="hljs-number">0</span><span class="hljs-punctuation">))</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.set</span> <span class="hljs-variable">$idx_bytes</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.const</span> <span class="hljs-number">0</span><span class="hljs-punctuation">))</span> <span class="hljs-comment">;; not entirely necessary</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.set</span> <span class="hljs-variable">$bytes_per_double</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.const</span> <span class="hljs-number">8</span><span class="hljs-punctuation">))</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">block</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">loop</span> <span class="hljs-comment">;; this sets idx_bytes to bytes offset of the value we're interested in.</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.set</span> <span class="hljs-variable">$idx_bytes</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.mul</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.get</span> <span class="hljs-variable">$idx</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.get</span> <span class="hljs-variable">$bytes_per_double</span><span class="hljs-punctuation">)))</span> <span class="hljs-comment">;; get the value of the array from memory:</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.set</span> <span class="hljs-variable">$temp_f64</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">f64.load</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.get</span> <span class="hljs-variable">$idx_bytes</span><span class="hljs-punctuation">)))</span> <span class="hljs-comment">;; now apply the cosine function:</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.set</span> <span class="hljs-variable">$temp_64</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">call</span> <span class="hljs-title function_">$cos</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.get</span> <span class="hljs-variable">$temp_64</span><span class="hljs-punctuation">)))</span> <span class="hljs-comment">;; now store the result at the same location in memory:</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">f64.store</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.get</span> <span class="hljs-variable">$idx_bytes</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.get</span> <span class="hljs-variable">$temp_64</span><span class="hljs-punctuation">))</span> <span class="hljs-comment">;; do it all in one step instead</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">f64.store</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.get</span> <span class="hljs-variable">$idx_bytes</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">call</span> <span class="hljs-title function_">$cos</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">f64.load</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.get</span> <span class="hljs-variable">$idx_bytes</span><span class="hljs-punctuation">))))</span> <span class="hljs-comment">;; increment the loop counter</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.set</span> <span class="hljs-variable">$idx</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.add</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.get</span> <span class="hljs-variable">$idx</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.const</span> <span class="hljs-number">1</span><span class="hljs-punctuation">)))</span> <span class="hljs-comment">;; stop the loop if the loop counter is equal the array length</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">br_if</span> <span class="hljs-number">1</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.eq</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.get</span> <span class="hljs-variable">$idx</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local.get</span> <span class="hljs-variable">$array_length</span><span class="hljs-punctuation">)))</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">br</span> <span class="hljs-number">0</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">export</span> <span class="hljs-string">"apply_cos64"</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">func</span> <span class="hljs-title function_">$apply_cos64</span><span class="hljs-punctuation">))</span> <span class="hljs-comment">;; Wasm is a stack-based language, but for returning values more complicated</span> <span class="hljs-comment">;; than an int/float, a separate memory stack has to be manually managed. One</span> <span class="hljs-comment">;; approach is to use a mutable global to store the stack_ptr. We give</span> <span class="hljs-comment">;; ourselves 1MiB of memstack and grow it downwards.</span> <span class="hljs-comment">;;</span> <span class="hljs-comment">;; Below is a demonstration of how this C code **might** be written by hand</span> <span class="hljs-comment">;;</span> <span class="hljs-comment">;; typedef struct {</span> <span class="hljs-comment">;; int a;</span> <span class="hljs-comment">;; int b;</span> <span class="hljs-comment">;; } sum_struct_t;</span> <span class="hljs-comment">;;</span> <span class="hljs-comment">;; sum_struct_t sum_struct_create(int a, int b) {</span> <span class="hljs-comment">;; return (sum_struct_t){a, b};</span> <span class="hljs-comment">;; }</span> <span class="hljs-comment">;;</span> <span class="hljs-comment">;; int sum_local() {</span> <span class="hljs-comment">;; sum_struct_t s = sum_struct_create(40, 2);</span> <span class="hljs-comment">;; return s.a + s.b;</span> <span class="hljs-comment">;; }</span> <span class="hljs-comment">;; Unlike C, we must manage our own memory stack. We reserve 1MiB</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">global</span> <span class="hljs-variable">$memstack_ptr</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">mut</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.const</span> <span class="hljs-number">65536</span><span class="hljs-punctuation">))</span> <span class="hljs-comment">;; Structs can only be returned by reference</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">func</span> <span class="hljs-title function_">$sum_struct_create</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">param</span> <span class="hljs-variable">$sum_struct_ptr</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">param</span> <span class="hljs-variable">$var</span><span class="hljs-variable">$a</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">param</span> <span class="hljs-variable">$var</span><span class="hljs-variable">$b</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-comment">;; c// sum_struct_ptr->a = a;</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.store</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">get_local</span> <span class="hljs-variable">$sum_struct_ptr</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">get_local</span> <span class="hljs-variable">$var</span><span class="hljs-variable">$a</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span> <span class="hljs-comment">;; c// sum_struct_ptr->b = b;</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.store</span> <span class="hljs-keyword">offset</span><span class="hljs-operator">=</span><span class="hljs-number">4</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">get_local</span> <span class="hljs-variable">$sum_struct_ptr</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">get_local</span> <span class="hljs-variable">$var</span><span class="hljs-variable">$b</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">func</span> <span class="hljs-title function_">$sum_local</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">result</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local</span> <span class="hljs-variable">$var</span><span class="hljs-variable">$sum_struct</span><span class="hljs-variable">$a</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local</span> <span class="hljs-variable">$var</span><span class="hljs-variable">$sum_struct</span><span class="hljs-variable">$b</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">local</span> <span class="hljs-variable">$local_memstack_ptr</span> <span class="hljs-type">i32</span><span class="hljs-punctuation">)</span> <span class="hljs-comment">;; reserve memstack space</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.sub</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">get_global</span> <span class="hljs-variable">$memstack_ptr</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.const</span> <span class="hljs-number">8</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span> <span class="hljs-keyword">tee_local</span> <span class="hljs-variable">$local_memstack_ptr</span> <span class="hljs-comment">;; tee both stores and returns given value</span> <span class="hljs-keyword">set_global</span> <span class="hljs-variable">$memstack_ptr</span> <span class="hljs-comment">;; call the function, storing the result in the memstack</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">call</span> <span class="hljs-title function_">$sum_struct_create</span> <span class="hljs-punctuation">(</span><span class="hljs-comment">(;$sum_struct_ptr=;)</span> <span class="hljs-keyword">get_local</span> <span class="hljs-variable">$local_memstack_ptr</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-comment">(;$var$a=;)</span> <span class="hljs-keyword">i32.const</span> <span class="hljs-number">40</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-comment">(;$var$b=;)</span> <span class="hljs-keyword">i32.const</span> <span class="hljs-number">2</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span> <span class="hljs-comment">;; retrieve values from struct</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">set_local</span> <span class="hljs-variable">$var</span><span class="hljs-variable">$sum_struct</span><span class="hljs-variable">$a</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.load</span> <span class="hljs-keyword">offset</span><span class="hljs-operator">=</span><span class="hljs-number">0</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">get_local</span> <span class="hljs-variable">$local_memstack_ptr</span><span class="hljs-punctuation">))</span> <span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">set_local</span> <span class="hljs-variable">$var</span><span class="hljs-variable">$sum_struct</span><span class="hljs-variable">$b</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.load</span> <span class="hljs-keyword">offset</span><span class="hljs-operator">=</span><span class="hljs-number">4</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">get_local</span> <span class="hljs-variable">$local_memstack_ptr</span><span class="hljs-punctuation">))</span> <span class="hljs-punctuation">)</span> <span class="hljs-comment">;; unreserve memstack space</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">set_global</span> <span class="hljs-variable">$memstack_ptr</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.add</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">get_local</span> <span class="hljs-variable">$local_memstack_ptr</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.const</span> <span class="hljs-number">8</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">i32.add</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">get_local</span> <span class="hljs-variable">$var</span><span class="hljs-variable">$sum_struct</span><span class="hljs-variable">$a</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">get_local</span> <span class="hljs-variable">$var</span><span class="hljs-variable">$sum_struct</span><span class="hljs-variable">$b</span><span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span> <span class="hljs-punctuation">)</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">export</span> <span class="hljs-string">"sum_local"</span> <span class="hljs-punctuation">(</span><span class="hljs-keyword">func</span> <span class="hljs-title function_">$sum_local</span><span class="hljs-punctuation">))</span> <span class="hljs-punctuation">)</span>