Gc: FYI: prototyping work in wabt and V8

Created on 18 Mar 2020  路  40Comments  路  Source: WebAssembly/gc

Just FYI to anyone who's interested: we have started prototyping this proposal in both wabt and V8.
We've consolidated the plan for the prototypes in this document to ensure that both implementations are compatible.

I'd like to emphasize that we're not trying to shortcut or sidestep the ongoing discussion about the specifics of the proposal. The prototypes will not ship (they will remain behind off-by-default flags). We will ship whatever the outcome of the proposal/spec process will be. The prototypes do not constitute an expression of preference/opinion on any of the open questions.

Instead, the idea is to (1) start making progress with the core implementation work we will (most likely) have to do at some point anyway, and (2) hopefully be able to provide feedback to the ongoing discussion, e.g. around practical feasibility of structural type checking, although to be really meaningful this might require some Wasm producers (i.e., source languages) to volunteer to invest the effort to produce modules targeting the prototypes.

Most helpful comment

Status update: we have updated our "prototype specification" document to reflect the latest changes to the relevant proposals, as well as our plans for a "milestone 2". Aside from that, we have kept the specification as backwards-compatible as possible.

We have also introduced columns to indicate the implementation status (currently for SpiderMonkey/V8/WABT, happy to add others if there are any) and are inviting representatives of those prototypes to indicate their status there if they wish. The idea is that interested users/consumers can easily see how far along the various prototypes are, and which implementation might fit their current needs.

The link to the doc is still https://bit.ly/3cWcm6Q.

All 40 comments

That's great news. Firefox has also had a prototype for about a year or so, documented here.

Excellent news! I'll push forward with the reference interpreter, probably focussing on the function refs and type imports proposals first.

@lars-t-hansen Do you plan to adapt the binary coding of Firefox GC as soon as the implementation in WABT progresses?

I ask because I use your code for my tests.

Kotlin/Wasm prototype also currently targets Firefox GC instruction set. In order to fully port it to WABT and V8 we would need optref, ref.cast and ref.test on top of the MVA.

Cool! Regarding (2), it will be helpful if you make it easy to turn on and off optimizations, since some optimizations we can rely on now we might not be able to rely on in the future, so it'd be nice to know how critical that reliance is.

And yes, we need to get some languages to work on targeting this extension. Great to hear that Kotlin is already working on it! I think OCaml is working on it too. I'll see if I can rally some more, ideally from the dynamic languages.

@skuzmich thanks for the info! I'll make sure to work on those next.

@lars-t-hansen Do you plan to adapt the binary coding of Firefox GC as soon as the implementation in WABT progresses?

In general, the Firefox implementation can be changed to be compatible with whatever, as few people are using it. I've not looked at what @binji's done yet, but if it's incompatible with what I have then I guess we have to make the designs converge.

I took a quick look, it seems like the main differences are these:

| name | v8/wabt | FF |
| -- | -- | -- |
| structtype form | 0x5f | 0x50 |
| ref.eq | 0xd3 | 0xf0 |
| struct.new | 0xfb00 | 0xfc50 |
| struct.get | 0xfb03 | 0xfc51 |
| struct.set | 0xfb06 | 0xfc52 |
| struct.narrow | X | 0xfc53 |

Another major difference is that FF (ref T) is v8 (optref T)

FF also requires the presence of a special section in the module to enable the feature at all, https://github.com/lars-t-hansen/moz-gc-experiments/blob/master/version2.md#special-section-required. This was just paranoia on my part. If we're converging on some basic aspects of the design and some shared opcodes I could remove that requirement.

Another major difference is that FF (ref T) is v8 (optref T)

That's just syntax, right? Easy enough to fix...

I think optref is nullable and ref is non-nullable.
edit: ah, sorry I see what you mean. :-)

@jakobkummerow It there any build of V8 that include this prototype for testing?

@Horcrux7 Not yet. The V8-side work is far from complete (even the "MVA" subset). I'll post an update here when there's something to play with.

@jakobkummerow I think the MVA subset should be enough for first test.

Firefox update landing before long: https://bugzilla.mozilla.org/show_bug.cgi?id=1624363 though this will only have optref for now, buyer beware.

Is there already something I can use to run .wat files that contain white and green instructions from the Google document linked above?

The reason I ask is that it would be really nice to run the code emitted by an experimental compiler backend in someone else's GC prototype.

@sabine you may be able to use the wabt interpreter, if your cases are simple enough. See the GC branch: https://github.com/WebAssembly/wabt/tree/gc

We're looking at updating SpiderMonkey for the changes introduced by removing funcref/anyref subtyping in webassembly/reference-types#69. One question that arose is what to do for our GC prototype, and I think it'd be good to align with other prototypes.

One approach that we're considering is to keep all subtyping logic, but conditionally enable it for when the GC prototype is enabled. So when GC is not-enabled, there would be no subtypes. But when GC is enabled, the old subtyping model of funcref :> anyref/externref and ref T :> anyref/externref would be re-enabled. The advantage of this is that it's likely the easiest change and would be maximally compatible with existing users.

Another option would be to create a new subtyping hierarchy for the GC types such as a gcref that is the super type of all ref T. This would need a more detailed proposal and would also break existing prototypes.

In V8's upcoming GC prototype, our situation is that we're approaching this from the other direction (as we don't have an existing prototype to modify), and our preliminary plan is to build only the subtyping that we absolutely need, considering that the larger questions around how subtyping should work are still in flux (as evidenced e.g. by the recent funcref change, as well as the larger nominal-vs-structural discussion). At a minimum, we think we'll need ref T :> optref T :> eqref, for T being any struct or array type (essentially making eqref the supertype of all managed types, what you call gcref in your last paragraph).

I'm open to thoughts about implementing more. Since we'll use a unified representation internally anyway, adding eqref :> anyref would be easy. Keeping funcref :> anyref when the experimental-gc flag is present would also be feasible, if you think that'd be desirable.

Is there a newer version of the prototype which reflect the latest changes for removing subtyping?

@Horcrux7, subtyping was only removed from the reference types proposal. It's still included in the GC proposal.

@rossberg With the "removing subtyping" there are some incompatible changes like the extra parameter for ref.null and ref.is_null. Also the type 0x11 is named externalref now. If there is a type anyref in the GC spec it required a new code. Or it must be renamed. Then I think the type nullref is obsolete. Or come it again with the GC spec?

Status update: we have updated our "prototype specification" document to reflect the latest changes to the relevant proposals, as well as our plans for a "milestone 2". Aside from that, we have kept the specification as backwards-compatible as possible.

We have also introduced columns to indicate the implementation status (currently for SpiderMonkey/V8/WABT, happy to add others if there are any) and are inviting representatives of those prototypes to indicate their status there if they wish. The idea is that interested users/consumers can easily see how far along the various prototypes are, and which implementation might fit their current needs.

The link to the doc is still https://bit.ly/3cWcm6Q.

Are there currently plans to implement i31ref? With the recent change to anyref not being a supertype of things, I'm a little confused whether there will be an i31ref in the future.

@sabine, to clarify, anyref was merely removed (deferred) from the initial reftypes proposal. It has moved to the type imports proposal, which is a prerequisite of this one. Both type imports and the GC proposal as it stands would be of rather limited use without some version of anyref.

Regarding implementation plans: as our document https://bit.ly/3cWcm6Q describes, we haven't committed to implementing i31ref yet. That doesn't rule out that we might implement it in Q3; it only means that so far it hasn't had priority. Do you have a particular need or use case for it (that's not adequately served by (struct $fake_i31 (field mut i32)) for the time being)?

@jakobkummerow Using the workaround of boxing all the i31s is alright, for now, but clearly not good for performance (the integer unboxing strategy of OCaml already comes at the cost of having to do 31-bit arithmetic; the gain that traditionally offsets this cost is that there is no indirection through the heap when accessing the unboxed integer).

I'm only worried that, if i31ref was, in general, at risk of getting scrapped (without a replacement feature) or at risk of getting delayed for a long time (more than 2 years), then relying on this workaround and planning to use i31ref in the future (which would require the least amount of changes to the existing compiler and probably result in the least amount of additional complexity introduced to the compiler) would be a bad direction to head in. In that case, it would make sense for me to explore other options that can enable parametric polymorphism with unboxed (31-bit-)integers (e.g. run-time code specialization or having a linker that does full-program analysis) and to learn how to change the existing compiler to be able to make use of them.

Edit: to elaborate: When I translate the compiler primitives that operate on unboxed 31-bit integers (i31ref) to the workaround in the naive way, every single one of these operations first unboxes (i.e. reads the i31 value stored in the field of struct $fake_i31), then does i31 arithmetic, and then boxes (writes the result to the field of the $fake_i31 struct) the value again. (Which is perfectly fine for a proof-of-concept.)

@sabine, it's hard to say what the future of i31ref is. In particular, WebAssembly is supposed to be fairly flexible with regards to implementation strategies, and the precise choice of 31 bits means that i31ref is designed around a specific GC-implementation strategy. That doesn't mean it's going away, and even if it does go away that doesn't mean that an alternative won't be made available, and even if such an alternative isn't available in the MVP (which is supposed to minimal) that doesn't mean it won't be made available later. So there's enough uncertainty that it's worth investigating other options, though you probably want to defer picking a particular option until more has been pinned down.

One thing I'll note specific to OCaml is that its semantics for int is already platform specific: 31 bits on 32-bit machines and 63 bits on 64-bit machines. Given that a number of programs already deal with this variation, they might be amenable to simply using 32 bits for int. But you know OCaml's ecosystem better than me, so your better positioned to make that call; I just wanted to put the suggestion out there.

@RossTate let's continue this in https://github.com/WebAssembly/gc/issues/100, to not derail this thread further.

Just to be clear, there currently is no plan for dropping i31ref. The GC proposal clearly needs a way to express unboxed scalars, and in a way that is predictable and works across platforms.

One could argue that this is just a performance improvement, and technically that's true. However, it also is such a fundamental feature that it should be part of the basic design evaluation that we want to do with the MVP. Without a proven way to incorporate unboxed scalars, practical usability of the GC extension will remain completely unclear for a whole range of languages.

We will add i31ref to the V8 prototype soon.

@jakobkummerow would love to hear along what paths adding i31ref causes conditionals.

@rossberg that still appears to be a matter of opinion.

Side question: to use the V8 prototype, we use the instructions at https://v8.dev/docs/build to build V8 from source, or is there a simpler/quicker method to get a build of the bleeding-edge V8?

https://github.com/GoogleChromeLabs/jsvu is a handy tool that downloads and updates canary builds of V8 and other engines.

@sabine I use https://github.com/nodejs/node-v8
It is a node build with v8-canary. You can download directly the binaries. But currently it is broken for Windows. Only the other platforms are available.

@jakobkummerow Are you interested in bug reports or is it too early for that? Currently I have a crash with 0xC0000005.

FYI: I haven't made much progress on wabt, but I have implemented milestone2 support in wasp: https://github.com/binji/wasp

The plan is to merge the wasp library into wabt, but for now wasp has its own tool to do the text -> binary conversion.

@Horcrux7 yes, I'm interested in bug reports. Probably makes sense not to derail this thread; you can email me (address in the doc linked in the OP) or file a bug at crbug.com/v8/new and assign it to me. Please include repro instructions :-)

Heads up: we're planning to adopt the lastest changes to the proposal, which will break backwards compatibility. Please comment on this draft doc: https://docs.google.com/document/d/1yAWU3dbs8kUa_wcnnirDxUu9nEBsNfq0Xo90OWx6yuo/edit# if you have questions/comments/concerns.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

tlively picture tlively  路  4Comments

dcodeIO picture dcodeIO  路  7Comments

vargaz picture vargaz  路  8Comments

TomMarius picture TomMarius  路  3Comments

dcodeIO picture dcodeIO  路  4Comments