julia
2d2cffe8 - Very WIP: [wasm] Bidirectional Julia/JS object access

Commit
6 years ago
Very WIP: [wasm] Bidirectional Julia/JS object access This is a start at what I think is the last major feature on the wasm porting punch list: sharing/accessing objects between Julia and the native javascript environment. This PR currently contains a rough sketch of the interpreter version of this integration, though we should of course try to get the compiled version going as soon as possible, since we now ship a compiled system image for the wasm target. For the compiled version of this we'd like to use the reference-types (https://github.com/WebAssembly/reference-types) wasm extension, which is currently in development, so even the interpreter parts are written with that extension in mind. In particular, we have a wasm table of javascript objects that represents our (indexed) managed heap of javascript objects. A boxed reference to javascript is then the julia type tag, plus an index into this table (in compiled mode an unboxed reference would just be a raw `anyref` without going through the table). The GC is responsible for managing this table of javascript objects, marking any JS objects that are reachable and sweeping the unreachable ones by nulling out the references (this part isn't implemented yet). On the julia side, we provide one julia type for every javascript builtin type ('number' corresponds to Float64 and 'boolean' to Bool, but otherwise the types are dedicated), with the non-singleton types being primitive types of pointer size to store the index into the table of javascript objects (at least semantically, as mentioned codegen will not use the table if possible). There is a bit of logic in javascript to convert these boxed representations on the julia heap into proper javascript objects, but otherwise the julia code is responsible for conversions from Julia objects to javascript objects (e.g. `String` to `JSString`, or `Ptr` to `JSNumber` - i.e. Float64). A `@jscall` macro is provided to call javascript functions from within julia. Under the hood this lowers to an `Expr(:foreigncall, ...)` with `jscall` calling convention for which we implement support in the interpreter. I don't forsee any problems with codegen for this representation, but that part is not implemented yet. For the reverse (referencing julia objects from javascript), I mostly followed what pyodide does and used a javascript `Proxy` object that wraps a boxed julia pointer (set/getproperty aren't implemented yet, but that should be straightforward). For GC integration, we make use of the (experimental) [JavaScript WeakRef](https://github.com/tc39/proposal-weakrefs) support, which essentially implements finalizers. On the julia side, I stole one of the remaining GC bits (at least one of the bits documented to be remaining - it looks like we don't overalign types sufficiently for this to actually work at the moment) to mark an object as being borrowed by the external VM and thus being protected from collection even if there is no remaining julia references. The JS side finalizer clears this bit on an object when there are no remaining references on the JS side. As always with these kinds of systems, reference cycles are not collected. I don't think there's much to be done about that, until WebAssembly gets more native integration with the JavaScript JC and we can re-use that for Julia objects. It should be noted that the WeakRef proposal is curently behind a flag in both Firefox and Chrome, but my understanding is that the timeline for this fetaure is comparable to that of the reference types proposal this builds on, so it should be ok to use (and I don't know of any other mechanism to learn whether the JS side has been collected). Remaining TODOs: - [ ] Hook up get/setproperty on the JS side - [ ] Julia GC marking/sweeping slots in the JS object table - [ ] Codegen For codegen, the major obstacle is lack of support in the toolchains (llvm, emscripten). I'm thinking it should be possible to just represent anyref as a non-integral pointer type in LLVM and get somewhere, but plumbing everything through is still a decent amount of work, that I'm unlikely to have the time for - I'm hoping somebody else will take that on.
Author
Committer
Parents
Loading