Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasm2js output from AssemblyScript input hangs #7245

Closed
guest271314 opened this issue Jan 28, 2025 · 15 comments
Closed

wasm2js output from AssemblyScript input hangs #7245

guest271314 opened this issue Jan 28, 2025 · 15 comments

Comments

@guest271314
Copy link

I compiled AssemblyScript to WASM, then compiled WASM to JavaScript with wasm2js. The WASM works as expected with wasmtime. The resulting JavaScript hangs when running with node, deno, and bun.

I've done the same process described above with Rust source code, Bytecode Alliance's Javy, and Facebook's Static Hermes; that is, source code to WASM, WASM to JavaScript using wasm2js, then running that JavaScript with WASI support with a JavaScript runtime.

This is the first time I have encountered code output by wasm2js hanging. I don't know if the issue is AssemblyScript source, wasm2js output, or the WASI (preview1) implementation I'm using.

The code

module.ts

export function array_nth_permutation(len: i32, n: i32): void { //Array<f64>
  let lex = n;
  let b: number[] = []; // copy of the set a.slice()
  for (let x: i32 = 0; x < len; x++) {
    b[x] = x;
  }
  // let len = a; // length of the set
  const res: number[] = []; // return value, undefined
  let i: i32 = 1;
  let f: i32 = 1;

  // compute f = factorial(len)
  for (; i <= len; i++) {
    f *= i;
  }

  let fac = f;
  // if the permutation number is within range
  if (n >= 0 && n < f) {
    // start with the empty set, loop for len elements
    // let result_len = 0;
    for (; len > 0; len--) {
      // determine the next element:
      // there are f/len subsets for each possible element,
      f /= len;
      // a simple division gives the leading element index
      i = (n - n % f) / f; // Math.floor(n / f);
      // alternately: i = (n - n % f) / f;
      // res[(result_len)++] = b[i];
      // for (let j = i; j < len; j++) {
      //   b[j] = b[j + 1]; // shift elements left
      // }
      res.push(b.splice(i, 1)[0]);
      // reduce n for the remaining subset:
      // compute the remainder of the above division
      n %= f;
      // extract the i-th element from b and push it at the end of res
    }

    let result: string = "[";
    for (let x: i32 = 0; x < res.length; x++) {
      let m: string = res[x].toString();
      let i: i32 = 0;
      do {
        result += m[i];
        i++;
      } while (m[i] !== ".");
      if (x < res.length -1) {
        result += ",";
      }
    }
    result += "]";
    process.stdout.write(
      `${lex} of ${fac - 1} (0-indexed, factorial ${fac}) => ${result}\n`,
    );

    process.exit(0);
  } else {
    if (n === 0) {
      process.stdout.write(`${n} = 0`);
    }
    process.stdout.write(`${n} >= 0 && ${n} < ${f}: ${n >= 0 && n < f}`);
    process.exit(1);
  }
}

let input: string = "0";
let lex: string = "0";

if (process.argv.length > 1) {
  input = process.argv.at(-2);
  lex = process.argv.at(-1);
} else {
  let stdin = process.stdin;
  let buffer = new ArrayBuffer(64);
  let n: number = stdin.read(buffer);
  if (n > 0) {
    let data = String.UTF8.decode(buffer);
    input = data.slice(0, data.indexOf(" "));
    lex = data.slice(data.indexOf(" "), data.length);
  }
}

input = input.trim();
lex = lex.trim();

if (<i32> parseInt(input) < 2 || <i32> parseInt(lex) < 0) {
  process.stdout.write(`Expected n > 2, m >= 0, got ${input}, ${lex}`); // eval(input)
  process.exit(1);
}

array_nth_permutation(<i32> parseInt(input), <i32> parseInt(lex));
node_modules/.bin/asc --enable simd --exportStart  --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json  module.ts -o module.wasm
echo '4 5' | wasmtime module.wasm
5 of 23 (0-indexed, factorial 24) => [0,3,2,1]

or

wasmtime module.wasm 4 5
5 of 23 (0-indexed, factorial 24) => [0,3,2,1]

node_modules/.bin/wasm2js module.wasm --enable-bulk-memory --enable-nontrapping-float-to-int  -o module.js

At the bottom of the JavaScript output by wasm2js

import WASI from "https://raw.githubusercontent.com/guest271314/deno-wasi/refs/heads/runtime-agnostic-nodejs-api/wasi.js";import fs from "node:fs";
let wasi = new WASI({
  args:[, '4', '5']
});
var memasmFunc = new ArrayBuffer(0);
var retasmFunc = asmFunc({
  "wasi_snapshot_preview1": {
    memory: { buffer: memasmFunc },
    ...wasi.exports,
  }
});

export var array_nth_permutation = retasmFunc.array_nth_permutation;
export var memory = retasmFunc.memory;
export var _start = retasmFunc._start;

wasi.memory = memory;
_start();

This just hangs until ^C

echo '4 5' | deno -A module.js

@kripken
Copy link
Member

kripken commented Jan 28, 2025

To debug this, I would add some logging in the source, to see where the wasm2js build starts to behave differently.

If you can't figure it out that way, adding lower-level logging using binaryen is an option, like --log-execution.

If you want, attach the wasm file here for us to investigate.

@guest271314
Copy link
Author

Looks like the code hangs somewhere in $131.

deno -A module.js 4 5
asmFunc
array_nth_permutation 4 5
Do we get past label$1 while loop?
Do we get past label$3 while loop?
Before if $88_1
Inside if $88_1
 function $131($0_1, $1_1) {
  console.log("array_nth_permutation", $0_1, $1_1);
  $0_1 = $0_1 | 0;
  $1_1 = $1_1 | 0;
  // ...
  };
  console.log("Do we get past label$1 while loop?");
  // ...
  };
  console.log("Do we get past label$3 while loop?");
  $12_1 = $11_1;
  if (($1_1 | 0) >= (0 | 0)) {
   $88_1 = ($1_1 | 0) < ($11_1 | 0)
  } else {
   $88_1 = 0
  }
  console.log("Before if $88_1");
  if ($88_1) {
   console.log("Inside if $88_1");
   label$8 : while (1) {
    if (($0_1 | 0) > (0 | 0)) {
     $11_1 = ($11_1 | 0) / ($0_1 | 0) | 0;
     $10_1 = ($1_1 - (($1_1 | 0) % ($11_1 | 0) | 0) | 0 | 0) / ($11_1 | 0) | 0;
     $26_1 = $9_1;
     HEAP32[(global$31 + 4 | 0) >> 2] = $26_1;
     $26_1 = $5_1;
     HEAP32[(global$31 + 16 | 0) >> 2] = $26_1;
     $26_1 = $124($26_1 | 0, $10_1 | 0, 1 | 0) | 0;
     HEAP32[(global$31 + 12 | 0) >> 2] = $26_1;
     $126($9_1 | 0, +(+$125($26_1 | 0, 0 | 0))) | 0;
     $1_1 = ($1_1 | 0) % ($11_1 | 0) | 0;
     $0_1 = $0_1 - 1 | 0;
     continue label$8;
     console.log("Do we get past label$8 while loop?");
    }
    break label$8;
   };
  // ...
  }
  global$31 = global$31 + 60 | 0;
  console.log("End of $131");
 }

assemblyscript-wasm2js-hangs.tar.gz

@guest271314
Copy link
Author

I think I figured out the issue in the source AssemblyScript code

I included this part in the algorithm specifically for AssemblyScript because AssemblyScript is representing integers as decimals

    let result: string = "[";
    for (let x: i32 = 0; x < res.length; x++) {
      let m: string = res[x].toString();
      let i: i32 = 0;
      do {
        result += m[i];
        i++;
      } while (m[i] !== ".");
      if (x < res.length -1) {
        result += ",";
      }
    }
    result += "]";

That is, when I replace that part with

    let result: string = `[${res}]`;
    /*
    "[";
    for (let x: i32 = 0; x < res.length; x++) {
      let m: string = res[x].toString();
      let i: i32 = 0;
      do {
        result += m[i];
        i++;
      } while (m[i] !== ".");
      if (x < res.length -1) {
        result += ",";
      }
    }
    result += "]";
    */

and run with wasmtime this is the result, where I'm expecting integers reflecting indexes, not decimals

echo '4 5' | wasmtime module.wasm
5 of 23 (0-indexed, factorial 24) => [0.0,3.0,2.0,1.0]

However, if I use that input WASM to wasm2js I get zeros - with the decimal

import WASI from "./wasi.js";
import fs from "node:fs";
let wasi = new WASI({
  args:[, '4', '5']
});
var memasmFunc = new ArrayBuffer(0);
var retasmFunc = asmFunc({
  "wasi_snapshot_preview1": {
    memory: { buffer: memasmFunc },
    ...wasi.exports,
  }
});

export var array_nth_permutation = retasmFunc.array_nth_permutation;
export var memory = retasmFunc.memory;
export var _start = retasmFunc._start;

wasi.memory = memory;
_start();
node --no-warnings module.js
5 of 23 (0-indexed, factorial 24) => [0.0,.0,.0,.0]

@kripken
Copy link
Member

kripken commented Jan 29, 2025

I don't see the wasm file in the archive? With the wasm file and a way to run it I could compare wasm to wasm2js.

@guest271314
Copy link
Author

Thought I included the WASM...

I've updated the AssemblyScript code (see AssemblyScript/assemblyscript#2901 (comment)) to fix the part I initially filed this issue for, though the wasm2js still has a lingering issue.

I'm including the AssemblyScrip code, the WASM compiled using asc, and the wasm2js result (I fetched the lastest Binaryen yesterday, version 121).

node_modules/.bin/asc --enable simd --exportStart  --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json  module.ts -o module.wasm

The wasi-shim is from here https://github.com/AssemblyScript/wasi-shim.

../binaryen/bin/wasm2js module.wasm --enable-bulk-memory --enable-nontrapping-float-to-int -o module.js

With wasmtime I get the expected result

echo '12 2' | wasmtime module.wasm
2 of 479001599 (0-indexed, factorial 479001600) => [0,1,2,3,4,5,6,7,8,10,9,11]

With wasm2js JavaScript and WASI support using https://raw.githubusercontent.com/guest271314/deno-wasi/refs/heads/runtime-agnostic-nodejs-api/wasi.js, also included as wasi.js, in pertinent part

//import * as wasi_snapshot_preview1 from 'wasi_snapshot_preview1';
// ...
 return {
  "array_nth_permutation": $126, 
  "memory": Object.create(Object.prototype, {
   "grow": {
    "value": __wasm_memory_grow
   }, 
   "buffer": {
    "get": function () {
     return buffer;
    }
    
   }
  }), 
  "_start": $96
 };
}

import WASI from "./wasi.js";
import fs from "node:fs";
let wasi = new WASI();
var memasmFunc = new ArrayBuffer(0);
var retasmFunc = asmFunc({
  "wasi_snapshot_preview1": {
    memory: { buffer: memasmFunc },
    ...wasi.exports,
  }
});

export var array_nth_permutation = retasmFunc.array_nth_permutation;
export var memory = retasmFunc.memory;
export var _start = retasmFunc._start;

wasi.memory = memory;
_start();
echo '12 2' | node --no-warnings module.js
2 of 49001599 (0-indexed, factorial 49001600) => [0,1,2,3,4,5,6,7,8,10,911]

See that 911? Should be 9,11, like I get with wasmtime.

assemblyscript-wasm-wasm2js.tar.gz

@kripken
Copy link
Member

kripken commented Jan 30, 2025

I get this error with node 20:

$ echo '12 2' | node --no-warnings module.js
assemblyscript-wasm-wasm2js/module.js:4727
import WASI from "./wasi.js";
^^^^^^

SyntaxError: Cannot use import statement outside a module

@guest271314
Copy link
Author

That's Node.js clinging on to CommonJS. I'm running node nightly v24.0.0-nightly20250128532fff6b27. Even in version 20 you should be able to run standardized ECMAScript Modules with --experimental-default-type=module.

@guest271314
Copy link
Author

https://nodejs.org/en/blog/release/v20.10.0

2023-11-22, Version 20.10.0 'Iron' (LTS), @targos
Notable Changes
--experimental-default-type flag to flip module defaults
The new flag --experimental-default-type can be used to flip the default module system used by Node.js.

@guest271314
Copy link
Author

Interestingly that bug in the output by wasm2js is always at the 10th index (0-based)

echo '12 2' | node --no-warnings module.js
2 of 49001599 (0-indexed, factorial 49001600) => [0,1,2,3,4,5,6,7,8,10,911]
echo '13 2' | deno -A module.js
2 of 1932053503 (0-indexed, factorial 1932053504) => [0,1,2,3,4,5,6,7,8,11,910,12]

And here the 10th and 11th indexes are mangled together

echo '14 2' | bun module.js
2 of 1278945279 (0-indexed, factorial 1278945280) => [0,1,2,3,4,5,6,7,10,8,911,1213]

Bun can run WASM out of the box. Here's running the source WASM that wasm2js is passed and outputs the above, with 13 2 as input we get an indication of the bug source

echo '13 2' | bun module.wasm
RuntimeError: Division by zero (evaluating 'instance.exports')
      at start (node:wasi:1023:26)
      at /home/user/module.wasm:49:11

Bun v1.2.1-canary.26+3a4df79a6 (Linux x64 baseline)
echo '14 2' | wasmtime module.wasm
Error: failed to run main module `module.wasm`

Caused by:
    0: failed to invoke command default
    1: error while executing at wasm backtrace:
           0: 0x3683 - <unknown>!<wasm function 131>
           1: 0x3b77 - <unknown>!<wasm function 132>
           2: 0x200d - <unknown>!<wasm function 101>
    2: wasm trap: integer divide by zero

Here's Rust compiled to WASM version of the same algorithm

echo '12 2' | bun permutations-rust.wasm
2 of 479001599 (0-indexed, factorial 479001600) => [0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 9, 11]

However, push it to 13 2 we get an error

echo '13 2' | bun permutations-rust.wasm
thread 'main' panicked at permutations.rs:21:5:
attempt to multiply with overflow
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
RuntimeError: Unreachable code should not be executed (evaluating 'instance.exports')

Bun v1.2.1-canary.26+3a4df79a6 (Linux x64 baseline)
echo '13 2' | ../wasmer-linux-amd64/bin/wasmer permutations-rust.wasm
thread 'main' panicked at permutations.rs:21:5:
attempt to multiply with overflow
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
error: RuntimeError: unreachable
    at __rust_start_panic (permutations-rust.wasm[283]:0xe918)
    at rust_panic (permutations-rust.wasm[279]:0xe83f)
    at std::panicking::rust_panic_with_hook::h1ead75d7eace2784 (permutations-rust.wasm[278]:0xe812)
    at std::panicking::begin_panic_handler::{{closure}}::he44d57a6b952509a (permutations-rust.wasm[261]:0xdbd4)
    at std::sys::backtrace::__rust_end_short_backtrace::h0b4e9296dec8b10d (permutations-rust.wasm[260]:0xdb0e)
    at rust_begin_unwind (permutations-rust.wasm[270]:0xe1a6)
    at core::panicking::panic_fmt::h9cf85a86c30a3523 (permutations-rust.wasm[336]:0x132f5)
    at core::panicking::panic_const::panic_const_mul_overflow::hf20ebbd79badb656 (permutations-rust.wasm[400]:0x1732c)
    at permutations::array_nth_permutation::h93f1f81f912c4943 (permutations-rust.wasm[83]:0x5b4d)
    at permutations::main::h52e0aee3e982e29f (permutations-rust.wasm[84]:0x5fe2)
    at core::ops::function::FnOnce::call_once::hb243900555505583 (permutations-rust.wasm[97]:0x664e)
    at std::sys::backtrace::__rust_begin_short_backtrace::h87e777f30e6a49a0 (permutations-rust.wasm[96]:0x6625)
    at std::rt::lang_start::{{closure}}::h3dd0c64a3ec98083 (permutations-rust.wasm[15]:0xd1b)
    at std::rt::lang_start_internal::h1b3a8c98b33cbfb4 (permutations-rust.wasm[225]:0xb9de)
    at std::rt::lang_start::hce049f2007367618 (permutations-rust.wasm[14]:0xce1)
    at __main_void (permutations-rust.wasm[85]:0x6049)
    at _start (permutations-rust.wasm[6]:0x3e4)
╰─▶ 1: RuntimeError: unreachable
           at __rust_start_panic (permutations-rust.wasm[283]:0xe918)
           at rust_panic (permutations-rust.wasm[279]:0xe83f)
           at std::panicking::rust_panic_with_hook::h1ead75d7eace2784 (permutations-rust.wasm[278]:0xe812)
           at std::panicking::begin_panic_handler::{{closure}}::he44d57a6b952509a (permutations-rust.wasm[261]:0xdbd4)
           at std::sys::backtrace::__rust_end_short_backtrace::h0b4e9296dec8b10d (permutations-rust.wasm[260]:0xdb0e)
           at rust_begin_unwind (permutations-rust.wasm[270]:0xe1a6)
           at core::panicking::panic_fmt::h9cf85a86c30a3523 (permutations-rust.wasm[336]:0x132f5)
           at core::panicking::panic_const::panic_const_mul_overflow::hf20ebbd79badb656 (permutations-rust.wasm[400]:0x1732c)
           at permutations::array_nth_permutation::h93f1f81f912c4943 (permutations-rust.wasm[83]:0x5b4d)
           at permutations::main::h52e0aee3e982e29f (permutations-rust.wasm[84]:0x5fe2)
           at core::ops::function::FnOnce::call_once::hb243900555505583 (permutations-rust.wasm[97]:0x664e)
           at std::sys::backtrace::__rust_begin_short_backtrace::h87e777f30e6a49a0 (permutations-rust.wasm[96]:0x6625)
           at std::rt::lang_start::{{closure}}::h3dd0c64a3ec98083 (permutations-rust.wasm[15]:0xd1b)
           at std::rt::lang_start_internal::h1b3a8c98b33cbfb4 (permutations-rust.wasm[225]:0xb9de)
           at std::rt::lang_start::hce049f2007367618 (permutations-rust.wasm[14]:0xce1)
           at __main_void (permutations-rust.wasm[85]:0x6049)
           at _start (permutations-rust.wasm[6]:0x3e4)

@guest271314
Copy link
Author

I'm thinking there might be an issue with the algorithm I'm using, around here since the error message is printing division by zero

      f /= len;
      // a simple division gives the leading element index
      i = (n - n % f) / f; // Math.floor(n / f);

@guest271314
Copy link
Author

I think we've gotten past the hanging part. I'll figure out how to improve the algorithm in the source code. Thanks.

@guest271314
Copy link
Author

Just for comparison AssemblyScript source code compiled to JavaScript using TypeScript tsc, Deno, and Bun https://gist.github.com/guest271314/d50e4dd304cf7b3247128e124c619023

node node_modules/assemblyscript/std/module.js 14 2
2 of 87178291199 (0-indexed, factorial 87178291200) => [0,1,2,3,4,5,6,7,8,9,10,12,11,13]

@guest271314
Copy link
Author

I think the 13 and greater factorial then error could be AssemblyScript related.

Here's the same algorithm using Bytecode Alliance Javy

 echo '13 2' | wasmtime --preload javy_quickjs_provider_v3=../plugin.wasm ../nm_javy_permutations.wasm
2 of 6227020799 (0-indexed, factorial 6227020800) => [0,1,2,3,4,5,6,7,8,9,11,10,12]

Facebook's Static Hermes compiled to WASM with WASI-SDK

echo '13 2' | wasmtime out/fopen.wasm
2 of 6227020799 (0-indexed, factorial 6227020800) => [0,1,2,3,4,5,6,7,8,9,11,10,12]

@guest271314 guest271314 reopened this Feb 1, 2025
@guest271314
Copy link
Author

@kripken

This is not exclusive to AssemblyScript input.

Rust to WASM to JavaScript produces the same result


#![feature(str_split_whitespace_remainder)]
use std::io::{self, BufRead};

// https://stackoverflow.com/a/34238979
fn array_nth_permutation(t: usize, n: u128) -> usize {
    if t < 2 || n == u128::MAX {
        println!("Expected n > 2, m >= 0, got {}, {}", t, n);
        return 1;
    }

    let a: Vec<usize> = (0..t).collect();
    let lex = n;
    let mut b: Vec<usize> = a.clone(); // copy of the set
    let mut len = a.len() as u128; // length of the set
    let mut res: Vec<usize> = Vec::new(); // return value, undefined
    let mut f = (1..=len).product();     // compute f = factorial(len)
    let mut m = n;
    // compute f = factorial(len)
    let fac = f;
    // if the permutation number is within range
    if m < f {
        // start with the empty set, loop for len elements
        for _ in 0..len {
            // determine the next element:
            // there are f/len subsets for each possible element,
            f /= len;
            // a simple division gives the leading element index
            let i = m / f; // Math.floor(n / f);
            res.push(b.remove(i as usize));
            // reduce n for the remaining subset:
            // compute the remainder of the above division
            m %= f;
            len -= 1;
        }
        println!(
            "{} of {} (0-indexed, factorial {}) => {:?}",
            lex,
            fac - 1,
            fac,
            res
        );
    } else {
        println!("{} >= 0 && {} < {}: {}", n, n, f, n < f);
    }

    // return the permutated set or undefined if n is out of range
    0
}

fn main() {
    let stdin = io::stdin();
    let mut iterator = stdin.lock().lines();
    let line = iterator.next().unwrap().unwrap();
    let mut split = line.split_whitespace();
    let a: usize = split
        .next()
        .unwrap()
        .trim()
        .parse()
        .expect("Input not an integer");
    let n: u128 = split
        .next()
        .unwrap()
        .trim()
        .parse()
        .expect("Input not an integer");
    array_nth_permutation(a, n);
}
CARGO_HOME=/media/user/rust/.cargo RUSTUP_HOME=/media/user/rust/.rustup /media/user/rust/.cargo/bin/rustc permutations.rs -o permutations
echo '13 2' | ./permutations
2 of 6227020799 (0-indexed, factorial 6227020800) => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 10, 12]
CARGO_HOME=/media/user/rust/.cargo RUSTUP_HOME=/media/user/rust/.rustup /media/user/rust/.cargo/bin/rustc permutations.rs --target wasm32-wasip1 -o permutations-rust.wasm
echo '13 2' | wasmtime ./permutations-rust.wasm
2 of 6227020799 (0-indexed, factorial 6227020800) => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 10, 12]
../binaryen/bin/wasm2js module.wasm --enable-bulk-memory --enable-nontrapping-float-to-int --enable-sign-ext --enable-mutable-globals  -o module-rust.js
//import * as wasi_snapshot_preview1 from 'wasi_snapshot_preview1';
// ...
import WASI from "./wasi.js";

let wasi = new WASI();
var retasmFunc = asmFunc({
  "wasi_snapshot_preview1": wasi.exports,
});
export var memory = retasmFunc.memory;
export var _start = retasmFunc._start;
export var __main_void = retasmFunc.__main_void;

wasi.memory = memory;
_start();

The 10th index of stringified output array is still mangled at 1110. Should be 11,10 just like the wasmtime output and compiled Rust executable

echo '13 2' | node module-rust.js 
2 of 6227020799 (0-indexed, factorial 6227020800) => [0,1,2,3,4,5,6,7,8,9,1110,12]

@guest271314
Copy link
Author

@kripken I figured it out. I write each i64 integer by itself in AssemblyScript

    process.stdout.write(
      `${lex} of ${fac - 1} (0-indexed, factorial ${fac}) => [`,
    );

    for (let z:i64 = 0; z < res.length; z++) {
      process.stdout.write(`${res.at(<i32>z)}`);
      if (z < res.length -1) {
        process.stdout.write(",");
      }
    }
../binaryen/bin/wasm2js module.wasm --llvm-memory-copy-fill-lowering  --llvm-nontrapping-fptoint-lowering --signext-lowering --enable-mutable-globals --enable-bulk-memory  --signext-lowering  --enable-nontrapping-float-to-int --enable-memory64 -o module.js
// import * as wasi_snapshot_preview1 from 'wasi_snapshot_preview1';

  var bufferView;
  var base64ReverseLookup = new Uint8Array(123/*'z'+1*/);
  for (var i = 25; i >= 0; --i) {
    base64ReverseLookup[48+i] = 52+i; // '0-9'
    base64ReverseLookup[65+i] = i; // 'A-Z'
    base64ReverseLookup[97+i] = 26+i; // 'a-z'
  }
  base64ReverseLookup[43] = 62; // '+'
  base64ReverseLookup[47] = 63; // '/'

// ...

 return {
  "array_nth_permutation": legalstub$127, 
  "memory": Object.create(Object.prototype, {
   "grow": {
    "value": __wasm_memory_grow
   }, 
   "buffer": {
    "get": function () {
     return buffer;
    }
    
   }
  }), 
  "_start": $99
 };
}

import WASI from "./wasi.js";
import fs from "node:fs";
let wasi = new WASI();
var memasmFunc = new ArrayBuffer(0);
var retasmFunc = asmFunc({
  "wasi_snapshot_preview1": {
    memory: { buffer: memasmFunc },
    ...wasi.exports,
  }
});

export var array_nth_permutation = retasmFunc.array_nth_permutation;
export var memory = retasmFunc.memory;
export var _start = retasmFunc._start;

wasi.memory = memory;
_start();
echo '15 2' | node  module.js
2 of 107674367999 (0-indexed, factorial 107674368000) => [0,1,2,3,4,5,6,7,8,9,10,11,13,12,14]

Thanks, again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants