Closed2

Wasm(GC)でint to string実装

tanishikingtanishiking
(module
  (type $i16Array (array (mut i16)))

  (import "wasm:js-string" "fromCharCodeArray" (func $fromCharCodeArray (param (ref null $i16Array)) (param i32) (param i32) (result (ref extern))))

  (func (export "test") (param $i i32) (result (ref extern))
    (local $array (ref null $i16Array))
    local.get $i
    call $itoa
    local.tee $array ;; array
    i32.const 0 ;; array 0
    local.get $array
    array.len ;; array 0 length
    call $fromCharCodeArray
  )

  (func $itoa (param $n i32) (result (ref $i16Array))
    (local $temp_n i32)
    (local $array_len i32)
    (local $index i32)
    (local $negative i32)
    (local $result (ref $i16Array))

    local.get $n
    i32.const 0
    i32.eq
    if
      i32.const 48 ;; '0' character (ASCII/Unicode 48)
      array.new_fixed $i16Array 1
      return
    end

    local.get $n
    i32.const 0
    i32.lt_s
    if (result i32) ;; length
      local.get $n
      i32.const -1
      i32.mul
      local.set $n

      i32.const 1
      local.set $negative
      ;; Increment array length for '-' sign
      i32.const 1
    else
      i32.const 0
      local.set $negative
      i32.const 0
    end
    local.set $array_len

    ;; Now we calculate the number of digits
    local.get $n
    local.set $temp_n
    loop $l
      local.get $temp_n
      i32.eqz
      if ;; break if 0
      else
        ;; temp_n /= 10
        local.get $temp_n
        i32.const 10
        i32.div_s
        local.set $temp_n

        local.get $array_len
        i32.const 1
        i32.add
        local.set $array_len
        br $l
      end
    end

    local.get $array_len
    array.new_default $i16Array
    local.set $result

    ;; Now fill the array from the last index (right to left)
    local.get $n
    local.set $temp_n

    local.get $array_len
    i32.const 1
    i32.sub
    local.set $index

    loop $loop
      local.get $temp_n
      i32.eqz
      if
      else
        ;; Store it in the array at the current index
        local.get $result ;; array to store
        local.get $index  ;; Current index

        local.get $temp_n
        i32.const 10
        i32.rem_s
        i32.const 48 ;; '0'
        i32.add ;; character
        array.set $i16Array  ;; Set character in the array

        ;; decrement
        local.get $index
        i32.const 1
        i32.sub
        local.set $index

        ;; Update temp_n = temp_n / 10
        local.get $temp_n
        i32.const 10
        i32.div_s
        local.set $temp_n

        br $loop
      end
    end

    ;; If the number was negative, add the '-' sign
    local.get $negative
    if
      ;; Store the '-' character at the start of the array (index 0)
      local.get $result
      i32.const 0   ;; First index
      i32.const 45  ;; '-' character (ASCII/Unicode 45)
      array.set $i16Array
    end

    local.get $result
  )
)
tanishikingtanishiking
$ wasm-tools parse itoa.wat -o itoa.wasm

wasm-tools は stacky form の wat ファイルもコンパイルできて便利だね

import { readFileSync } from "node:fs";
const wasmBuffer = readFileSync("itoa.wasm");
const importObj = {}
const wasmModule = await WebAssembly.instantiate(wasmBuffer, importObj, { builtins: ['js-string'] });
const { test } = wasmModule.instance.exports;
console.log(test(0));
console.log(test(1));
console.log(test(-100));
console.log(test(-1395235));
console.log(test(999235));
$ node --experimental-wasm-imported-strings itoa.mjs
0
1
-100
-1395235
999235
このスクラップは8日前にクローズされました