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

Execution error with array.new_fixed and node v21.3.0 and V8 version 11.7.439.16 #6176

Closed
ericvergnaud opened this issue Dec 13, 2023 · 20 comments

Comments

@ericvergnaud
Copy link
Contributor

ericvergnaud commented Dec 13, 2023

Hi,

Using binaryen with GC instructions.

I have the following pseudo-code:

export function stuff(): i32[] { const a:i32[] = [ 3, 5 ]; return a; }

From it, I'm able to generate the following wat (using module.emitText():

(module
 (type $0 (array i32))
 (type $1 (func (result (ref null $0))))
 (type $2 (array (mut i32)))
 (export "stuff" (func $stuff))
 (func $stuff (type $1) (result (ref null $0))
  (local $a (ref null $0))
  (local.set $a
   (array.new_fixed $2 2
    (i32.const 3)
    (i32.const 5)
   )
  )
  (return
   (local.get $a)
  )
 )
)

and the corresponding wasm.

Interestingly, when I run the wasm with just the --experimental-wasm-gc node shouts as follows:

CompileError: WebAssembly.Module(): invalid value type 'stringview_wtf8ref', enable with --experimental-wasm-stringref @+17

This seems a bit weird since the above wat does not use sotringview at all...

If I enable --experimental-wasm-stringref the above error goes away, but then I get:

CompileError: WebAssembly.Module(): unknown type form: 0 @+18

Digging around, I see that WASM GS support in v8 is pretty mature. Could this be caused by a bug in Binaryen itself ?
Or is there something wrong in the above wat ?

@kripken
Copy link
Member

kripken commented Dec 13, 2023

The wat doesn't look valid,

$ bin/wasm-opt a.wat -all
[wasm-validator error in function stuff] local.set's value type must be correct, on 
(local.set $0
 (array.new_fixed $2 2
  (i32.const 3)
  (i32.const 5)
 )
)
Fatal: error validating input

That error looks correct. The local.set writes a ref of type $2 to a local of type $0, but those types are unconnected,

(module
 (type $0 (array i32))
 (type $2 (array (mut i32)))

(there is no subtyping between them, and there also cannot be subtyping between them because of the difference in mutability).

How was the wat generated?

@ericvergnaud
Copy link
Contributor Author

Thanks for the quick response. The wat was generated using binaryen emitText.

@kripken
Copy link
Member

kripken commented Dec 13, 2023

Does that wasm pass validation before emitting the text?

(If it does, then it's definitely a bug.)

@ericvergnaud
Copy link
Contributor Author

Fixed the 'mut' issue, now I have:

(module
 (type $0 (array (mut i32)))
 (type $1 (func (result (ref null $0))))
 (export "stuff" (func $stuff))
 (func $stuff (type $1) (result (ref null $0))
  (local $a (ref null $0))
  (local.set $a
   (array.new_fixed $0 2
    (i32.const 3)
    (i32.const 5)
   )
  )
  (return
   (local.get $a)
  )
 )
)

Now I get:
CompileError: WebAssembly.Module(): section was shorter than expected size (9 bytes expected, 8 decoded) @+18

@ericvergnaud
Copy link
Contributor Author

I now run module.validate() before emitText() and it doesn't shout

ericvergnaud added a commit to compose-lang/compiler that referenced this issue Dec 13, 2023
@kripken
Copy link
Member

kripken commented Dec 13, 2023

That wat in binary form loads ok in latest V8 for me. Perhaps node has a newer version with latest V8? If not you may need to try with either the (latest) V8 shell (d8 which is how I tested), or with chrome.

I am guessing your node has an old-enough V8 that it has an older version of the binary format for WasmGC, which was updated just two months ago or so.

@ericvergnaud
Copy link
Contributor Author

Thanks for your help. Just upgraded to latest i.e. v21.4.0 and it doesn't fix the issue.

@ericvergnaud
Copy link
Contributor Author

ericvergnaud commented Dec 14, 2023

Using latest d8 (V8 version 11.7.439.16), I'm able to reproduce the issue.
The attached file contains the wasm generated by binaryen from the same IR that produces the above wat.

I run d8 as follows:

d8 --experimental-wasm-gc --experimental-wasm-stringref

In d8, I run the following:

 const wasm = readbuffer("returns_an_i32_array.wasm");
 const module = new WebAssembly.Module(wasm);

This triggers the following error:

CompileError: WebAssembly.Module(): section was shorter than expected size (9 bytes expected, 8 decoded) @+18

What am I doing wrong ?

returns_an_i32_array.wasm.zip

n.b. this is using my typescript branch, forked from commit 66277f9

@ericvergnaud
Copy link
Contributor Author

ericvergnaud commented Dec 14, 2023

FWIW I tried converting the wat to wasm using wat2wasm but the latest release 1.0.34 does not yet support GC:
/Users/ericvergnaud/Development/compose/compiler/returns_an_i32_array.wat:2:12: error: array type not allowed
(type $0 (array (mut i32)))

@ericvergnaud
Copy link
Contributor Author

Similarly, using binaryen.js 116.0.0, which relies on binaryen commit https://github.com/WebAssembly/binaryen/tree/11dba9b1c2ad988500b329727f39f4d8786918c5, the generated wasm is identical to the one attached above:

import * as fs from "fs";
import binaryen from "binaryen";

const wat = fs.readFileSync("../dumps/returns_an_i32_array.wat", "utf8");
const module = binaryen.parseText(wat);
module.setFeatures(binaryen.Features.GC | binaryen.Features.ReferenceTypes)
const wasm = module.emitBinary();
fs.writeFileSync("../dumps/returns_an_i32_array.wasm", wasm);

@ericvergnaud
Copy link
Contributor Author

Here is my (manual!) disassembly of the generated wasm.
Tbh I don't see anything wrong in there according to the latest spec
https://webassembly.github.io/spec/core/binary/index.html

Given the error:
CompileError: WebAssembly.Module(): section was shorter than expected size (9 bytes expected, 8 decoded) @+18,
I guess the issue is with the types section, with the loader not properly reading the ref null type 00 following the type itself 63 at index 18 of the wasm (or maybe it doesn't understand 63 ?)

00 61 73 6D magic
01 00 00 00 version

01 types section
09 length
02 types count
// type 0
5E array
7F i32
01 mutable
// type 1
60 func
00 params count
01 results count
63 ref null
00 heap type 0

03 functions section
02 length
01 functions count
// function 0
01 function type index

07 exports section
09 length
01 exports count
// export 0
05 name length
73 74 75 66 66 "stuff"
00 export type = function
00 function index

0A code section
14 length (20)
01 codes count
// code 0
12 code length (18)
01 locals count
// local 0 (variable a)
01 ??? not sure why this is 1 rather than 0 ?
63 local type = ref null
00 local type index
// start of code
41 03 i32.const 3
41 05 i32.const 5
FB 08 00 02 array.new_fixed, array type index (0), array size (2)
21 00 local.set 0
20 00 local.get 0
0F return
0B end

@ericvergnaud ericvergnaud changed the title Execution error with array.new_fixed and node v21.3.0 Execution error with array.new_fixed and node v21.3.0 and V8 version 11.7.439.16 Dec 14, 2023
@ericvergnaud
Copy link
Contributor Author

News from the battlefront:

  • I'm able to load the generated wasm in Chrome version 120.0.6099.109
  • I'm able to locate and call the 'stuff" function
  • but the result is an empty object, not an Int32Array as I was expecting
    So not sure what to think...

@ericvergnaud
Copy link
Contributor Author

ericvergnaud commented Dec 14, 2023

Also doesn't work (loads but doesn't return usable data) in latest Chromium...

So to sum up, as of writing:

  • Latest v8 version is 12.2 (from the v8 web site)
  • Latest v8 version in brew is 11.7
  • Chrome 120 uses V8 12.0
  • Chromium 122 use V8 12.2
  • Node v21.3 use V8 11.8

I'm beginning to think that:

  • proper support for Wasm GC requires v8 12+ (hence why it loads ok in Chrome and Chromium)
  • but mapping of returned heap type values to JS object is not working yet in V8 ?

qq: would you know where I can download v8 12.2 for Mac (I'd rather avoid building it locally)

@kripken
Copy link
Member

kripken commented Dec 14, 2023

I don't think there is a mapping of wasm Array types to JS TypedArrays. There has been discussion about it, but no concrete spec yet. Typically what people do for now is call into the wasm to do each array.get, which can be fast if the VM inlines those wasm functions into JS.

To download recent VM builds, try jsvu.

@ericvergnaud
Copy link
Contributor Author

Thanks for the link to jsvu!
I'll keep an eye on the "wasm Array types to JS TypedArrays" topic, if you can provide a link to that discussion ?

@kripken
Copy link
Member

kripken commented Dec 14, 2023

I'm not sure if there are active discussions, but this is the last update I am aware of, which links to relevant places,

WebAssembly/gc#235 (comment)

@tlively might know more.

@tlively
Copy link
Member

tlively commented Dec 14, 2023

Correct, all GC objects including arrays are completely opaque to JS and have to be accessed via exported Wasm functions. There is broad interest in improving this somehow, but all the obvious design would be technically challenging for engines to implement, so I wouldn't expect the situation to change any time soon.

@ericvergnaud
Copy link
Contributor Author

Thank you both !

@ericvergnaud
Copy link
Contributor Author

ericvergnaud commented Dec 15, 2023

@kripken FYI there are no pre-built V8 binaries for maces, so jsvu. It's gonna be the hard way...

@ericvergnaud
Copy link
Contributor Author

FYI I have migrated to Deno, which has a much fresher version of v8

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

3 participants