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

WASM u32 return type misinterpreted as i32 in JavaScript #26998

Open
swwind opened this issue Nov 22, 2024 · 0 comments
Open

WASM u32 return type misinterpreted as i32 in JavaScript #26998

swwind opened this issue Nov 22, 2024 · 0 comments

Comments

@swwind
Copy link

swwind commented Nov 22, 2024

Version: Deno 2.1.1

I'm exploring Deno's capability to import WebAssembly (WASM) directly into JavaScript. However, I encountered an issue where a function returning a u32 in Rust is always interpreted as i32 in JavaScript.

For example, consider the following Rust code:

#[no_mangle]
pub fn add(left: u32, right: u32) -> u32 {
    left.wrapping_add(right)
}

This compiles to the following WebAssembly (shown in WAT):

(module $wasm.wasm
  (type (;0;) (func (param i32 i32) (result i32)))
  (func $add (type 0) (param i32 i32) (result i32)
    local.get 1
    local.get 0
    i32.add)
  (table (;0;) 1 1 funcref)
  (memory (;0;) 16)
  (global $__stack_pointer (mut i32) (i32.const 1048576))
  (global (;1;) i32 (i32.const 1048576))
  (global (;2;) i32 (i32.const 1048576))
  (export "memory" (memory 0))
  (export "add" (func $add))
  (export "__data_end" (global 1))
  (export "__heap_base" (global 2)))

Although this function is meant to return a u32, it is represented as i32 in the WASM type system.

When I import and call this function in Deno, the result appears incorrect:

add(2147483647, 1); // Produces -2147483648

Some informations I found

  1. WebAssembly supports only a limited set of number types: i32, i64, f32, and f64. The distinction between signed and unsigned integers is made through specific instructions like i32.gt (signed) and i32.gt_u (unsigned). Consequently, a function returning i32 in WASM may correspond to either i32 or u32 in the original Rust source.

  2. Tools like wasm-bindgen handle unsigned integer transformations during post-processing. They wrap the result using number >>> 0 in JavaScript to correctly interpret u32 values. For example, a function returning u32 in Rust would be transformed into a JS-compatible form like this:

    function add(left, right) {
        return wasm_add(left, right) >>> 0;
    }

So, how can Deno handle this situation effectively? Since there’s nothing in the compiled WASM output explicitly indicating whether a return type is i32 or u32, how can deno ensure that the result is interpreted correctly as u32?

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

1 participant