Factorial

02 Dec 2017 0 Comments

The material is borrowed from Hello, Rust!
Files creation

<!DOCTYPE html>
<html lang="en">
  <head>
      <meta charset="utf-8">
      <title>WebAssembly</title>
      <script src="bundle.js"></script>
      <script src="script.js"></script>
  </head>
  <body>
    factorial(<input type="number" id="n" value="10" min="0" max="65">)=
    <output id="f">3628800</output>
  </body>
</html>

window.onload = function() {
    window.exports = {};

    let n = document.querySelector('#n'),
        f = document.querySelector('#f'),
        fact_str;

    let calc = function() {
        f.value = fact_str(n.value);
    };
    
    n.oninput = calc;

    fetchAndInstantiate("build/main.wasm")
    .then(mod => {
        exports = mod.exports;
        fact_str = function(n) {
            let outptr = exports.fact_str(n);
            let result = copyCStr(exports, outptr);
            return result;
        };
    });
};

use std::mem;
use std::ffi::CString;
use std::os::raw::{c_char, c_void};

fn main() {}

#[no_mangle]
pub extern "C" fn alloc(size: usize) -> *mut c_void {
    let mut buf = Vec::with_capacity(size);
    let ptr = buf.as_mut_ptr();
    mem::forget(buf);
    return ptr as *mut c_void;
}

#[no_mangle]
pub extern "C" fn dealloc_str(ptr: *mut c_char) {
    unsafe {
        let _ = CString::from_raw(ptr);
    }
}

#[no_mangle]
pub fn fact(n: u32) -> u64 {
    let mut n = n as u64;
    let mut result = 1;
    while n > 0 {
        result = result * n;
        n = n - 1;
    }
    result
}

#[no_mangle]
pub fn fact_str(n: u32) -> *mut c_char {
    let res = fact(n);
    let s = format!("{}", res);
    let s = CString::new(s).unwrap();
    s.into_raw()
}

Save this file as main.wasm in build folder.
Or generate this file by
rustc +nightly --target wasm32-unknown-unknown -O --crate-type=cdylib src\main.rs -o build\main.big.wasm

The helper functions are defined in bundle.js.
Result

WebAssembly text format with fn fact(n: u32) -> u64 only
(module
(type $t0 (func (param i32) (result i64)))
(func $fact (export "fact") (type $t0) (param $p0 i32) (result i64)
  (local $l0 i64) (local $l1 i64)
  (block $B0
    (block $B1
      (br_if $B1
        (i32.eqz
          (get_local $p0)))
      (set_local $l0
        (i64.extend_u/i32
          (get_local $p0)))
      (set_local $l1
        (i64.const 1))
      (loop $L2
        (set_local $l1
          (i64.mul
            (get_local $l0)
            (get_local $l1)))
        (br_if $L2
          (i32.eqz
            (i64.eqz
              (tee_local $l0
                (i64.add
                  (get_local $l0)
                  (i64.const -1))))))
        (br $B0))
      (unreachable))
    (set_local $l1
      (i64.const 1)))
  (get_local $l1))
(table $T0 0 anyfunc)
(memory $memory (export "memory") 17)
(data (i32.const 4) "\10\00\10\00"))