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

Proof of concept WebAssembly JIT #214

Open
kripken opened this issue Sep 4, 2018 · 1 comment
Open

Proof of concept WebAssembly JIT #214

kripken opened this issue Sep 4, 2018 · 1 comment

Comments

@kripken
Copy link

kripken commented Sep 4, 2018

I was inspired by @ncoghlan's comment suggesting using asm2wasm for converting the current asm.js JIT to a wasm one. As a fun weekend hack I got that to work:

  • As suggested, this simply takes the asm.js from the current backend and runs it through asm2wasm (compiled to asm.js itself), which emits a wasm binary. We then compile that in the browser.
  • This hit a few asm2wasm parsing bugs, all fixed in a branch. Also asm2wasm was not in the JS port of binaryen yet, so I added that in the branch as well.
  • Code is in a wasmjit branch in a fork of pypyjs-release. To see it in action there, run a.js in node. Note you can pick wasm or asm.js at the top of lib/pypyjs.vm.js by setting the WASM var.

This is really just a quick hack. Instead of properly building pypyjs.vm.js to run using wasm (which I saw isn't trivial as it requires a 32-bit host), I manually modified the existing pypy.vm.js build where necessary. The key changes are in this diff, and they include:

  • Create a wasm Memory object, as we need to share memory with the JIT code, and wasm JIT code can only import a Memory.
  • As a result of that, we must set up memory early on, at the top of the file - I replaced the normal point where we create the main ArrayBuffer with just an assert to verify the size is right.
  • The interesting part is at the end of that diff, which is if we are in the wasm path, then:
  var module = Binaryen.asm2wasm(source);
  var binary = module.emitBinary();
  module.dispose();
  var info = {
   env: {
    memory: wasmMemory,
    table: wasmTable,
    memoryBase: 0,
    tableBase: 0
   },
   foreign: Module
  };
  var instance = new WebAssembly.Instance(new WebAssembly.Module(binary), info);
  func = instance.exports.singleton;

That basically just runs asm2wasm using binaryen.js, emits a wasm binary, compiles it, and gets the resulting wasm function.

Note that while this shows that it works, it isn't fast or anything like that! Limitations:

  • Because of how I hacked up the existing JS, pypyjs.vm.js no longer validates as asm.js, which may make the non-JIT code a lot slower. To get this done properly, we'd need to recompile it to wasm.
  • In the bigger picture, the proof of concept pipeline of pypy => asm.js => wasm adds a bunch of unnecessary overhead (we are emitting asm.js text, then parsing that text). It was quick to get working, but a proper approach would mean writing a wasm backend in pypy itself (perhaps using Binaryen's C API) so that we directly and efficiently emit wasm.
@Zireael07
Copy link

Any updates on this?

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

2 participants