Stream: git-wasmtime

Topic: wasmtime / issue #10171 Incorrect `ref.test` result


view this post on Zulip Wasmtime GitHub notifications bot (Feb 03 2025 at 18:27):

fitzgen edited issue #10171:

(module
    (type $appNode
        (struct (field $left anyref)
                (field $right anyref)))

    (type $comb (struct (field $asciiTag i32)))

    (func $prob1 (export "prob1") (param $p (ref null $appNode)) (result i32)
        (local.get $p)
        (struct.get $appNode $left)
        (ref.cast (ref null $appNode))
        (struct.get $appNode $right)
        (ref.test (ref null $comb))
    )

    (func $prob2 (export "prob2") (param $p (ref null $appNode)) (result i32)
        (local.get $p)
        (struct.get $appNode $left)
        (ref.cast (ref null $appNode))
        (struct.get $appNode $left)
        (ref.test (ref null $comb))
    )

    (func $main (export "main") (result i32)
        (struct.new $appNode (struct.new $appNode (struct.new $comb (i32.const 67))
                                                  (struct.new $comb (i32.const 73)))
                             (ref.i31 (i32.const 2)))
        (call $prob2)
    )
)

Hey Wasmtime team! calling $prob1 returns 1 but $prob2 returns 0. Why is that? Shouldn't it be reading the (struct.new $comb (i32.const 67)) which indeed is a comb? I've tried reading the GC spec but haven't been able to figure out why the runtime behaves this way.

view this post on Zulip Wasmtime GitHub notifications bot (Feb 03 2025 at 18:39):

fitzgen commented on issue #10171:

Haven't managed to meaningfully reduce it past this:

(module
  (type $tree (struct (field $left anyref)
                      (field $right anyref)))
  (type $s (struct))
  (func (export "main") (result i32)
    (struct.new $tree
                (struct.new $tree
                            (struct.new $s)
                            (ref.i31 (i32.const 1)))
                (ref.i31 (i32.const 2)))
    struct.get $tree $left
    ref.cast (ref null $tree)
    struct.get $tree $left
    ref.test (ref null $s)
  )
)

Interestingly, changing $right to be an i31ref also makes the test pass.

view this post on Zulip Wasmtime GitHub notifications bot (Feb 03 2025 at 18:39):

fitzgen commented on issue #10171:

And removing one layer of tree nesting also makes the test pass.

view this post on Zulip Wasmtime GitHub notifications bot (Feb 03 2025 at 18:54):

fitzgen commented on issue #10171:

Using the null collector instead of the DRC collector also makes the test pass. I'm starting to suspect that this involves a Wasm-to-CLIF translation bug where we are accidentally generating CLIF that is more optimizable than it should be.

view this post on Zulip Wasmtime GitHub notifications bot (Feb 05 2025 at 17:28):

fitzgen commented on issue #10171:

FWIW, here is the flattened version of the test case, which makes the order of instructions a little easier to read when staring at clif and comparing it to the original wasm:

(module
  (type $tree (struct (field $left anyref)
                      (field $right anyref)))
  (type $s (struct))
  (func (export "main") (result i32)
    struct.new $s
    ref.null i31
    struct.new $tree
    i32.const 2
    ref.i31
    struct.new $tree
    struct.get $tree $left
    ref.cast (ref null $tree)
    struct.get $tree $left
    ref.test (ref null $s)
  )
)

view this post on Zulip Wasmtime GitHub notifications bot (Feb 08 2025 at 15:40):

apoorvaanand1998 commented on issue #10171:

Thank you for your quick response :bow:

Now that I know it's a bug with Wasmtime, I've been trying to run this on firefox. The first step I suppose is to use wat2wasm to compile this to a .wasm file so I can run it as shown here. But wat2wasm fails to parse my program

Error: parseWat failed:
test.wast:3:30: error: unexpected token "anyref", expected i32, i64, f32, f64, v128, externref or funcref.
        (struct (field $left anyref)
                             ^^^^^^
test.wast:4:31: error: unexpected token anyref.
                (field $right anyref)))
                              ^^^^^^
test.wast:8:50: error: unexpected token "null", expected a numeric index or a name (e.g. 12 or $foo).
    (func $prob1 (export "prob1") (param $p (ref null $appNode)) (result i32)
                                                 ^^^^

How did you get it to run on firefox?

I am sorry if this isn't the right place to be asking this. Let me know if it isn't and we can switch communication channels. Thank you for your help!

view this post on Zulip Wasmtime GitHub notifications bot (Feb 08 2025 at 18:19):

alexcrichton commented on issue #10171:

You can try using wasm-tools as wasm-tools parse foo.wat -o foo.wasm

view this post on Zulip Wasmtime GitHub notifications bot (Feb 12 2025 at 17:35):

fitzgen closed issue #10171:

(module
    (type $appNode
        (struct (field $left anyref)
                (field $right anyref)))

    (type $comb (struct (field $asciiTag i32)))

    (func $prob1 (export "prob1") (param $p (ref null $appNode)) (result i32)
        (local.get $p)
        (struct.get $appNode $left)
        (ref.cast (ref null $appNode))
        (struct.get $appNode $right)
        (ref.test (ref null $comb))
    )

    (func $prob2 (export "prob2") (param $p (ref null $appNode)) (result i32)
        (local.get $p)
        (struct.get $appNode $left)
        (ref.cast (ref null $appNode))
        (struct.get $appNode $left)
        (ref.test (ref null $comb))
    )

    (func $main (export "main") (result i32)
        (struct.new $appNode (struct.new $appNode (struct.new $comb (i32.const 67))
                                                  (struct.new $comb (i32.const 73)))
                             (ref.i31 (i32.const 2)))
        (call $prob2)
    )
)

Hey Wasmtime team! calling $prob1 returns 1 but $prob2 returns 0. Why is that? Shouldn't it be reading the (struct.new $comb (i32.const 67)) which indeed is a comb? I've tried reading the GC spec but haven't been able to figure out why the runtime behaves this way.


Last updated: Feb 28 2025 at 03:10 UTC