29

Is there any way to get read/write access to DOM and/or the WebAPIs(i.e. fullscreen API) without JavaScript?

I'm trying to build a basic application in C(C source being actually the result of transpilation from a GC language). The app I'm building will run as Desktop app(it's not meant to run in "real" browsers yet) so I can tweak the environment(i.e. the layout engine) if necessary.

starball
  • 20,030
  • 7
  • 43
  • 238
themihai
  • 7,903
  • 11
  • 39
  • 61

4 Answers4

17

In the WebAssembly Minimal Viable Product the only way to call into and out of WebAssembly is through imports and exports. In the future, WebAssembly may gain capabilities which allow the embedder expose APIs directly, in a browser embedding this could include the DOM.

Imports and exports aren't very complicated though: from your C code's point of view they just look like an extern call, similar to a DLL on the Windows platform. You'd likely compile the C code using Emscripten, see its documentation "Call JavaScript functions from C/C++" for details on how this works (since this isn't the question you're asking, but I'm guessing it's the next question).


It's not clear from your question if you:

  1. Want to compile C code and run it within WebAssembly inside a browser.
  2. Want to compile C code and run it within WebAssembly outside a browser.

Or both.

JF Bastien
  • 6,673
  • 2
  • 26
  • 34
  • 1
    I'm looking to run the compiled C -> wasm code within Chromium Embedded Framework so it will run inside a embedded browser. The JS bridge is not really what I'm looking for so I will skip it for now and reconsider it once it gets real/native DOM access. – themihai Mar 06 '17 at 18:18
  • 1
    What are you looking for? If your needs aren't met I suggest filing an issue here: https://github.com/WebAssembly/design/issues – JF Bastien Mar 06 '17 at 19:17
  • It's just that the JS part creates additional friction. Maybe it's worth it if you actually need JS interlop or if web/browser support is mandatory but it's not my case thus the reason why I skip it for now. I see that DOM access is on the roadmap. Should I still fill an issue on github? – themihai Mar 06 '17 at 20:26
  • Not if your usecase is just to remove friction, that's why it's on the roadmap already :-) – JF Bastien Mar 06 '17 at 21:28
8

It all depends on compiler capabilities.

Currently there is no way to access the DOM or any other browser API directly. It is also not possible to store JavaScript references inside of Wasm linear memory or Wasm tables. It is also not possible to use JavaScript references as function arguments or return values. They just do not exists in the MVP type system. However, there is the Reference Type Proposal, which might someday become part of the Wasm runtime, but there is no official release date available.

So, how can Wasm to Host Environment interaction be done? Well, it turns out that the Wasm module system with imports and exports can be used to create an emulation layer. Creating this layer by hand is painful, so it is a good task for a compiler to create it. But how?

For instance, we want to set the document title in the current browser window. The Wasm needs to access the current window instance, select the document, and set the title property of it. As the Wasm runtime cannot access the references, we need to create a mapping table on JS side and some JS functions with mapping logic and import them into the Wasm module.

So, we create a function called getWindow. This function takes the global window reference, puts it into a mapping table and returns the index in the table. This index will be accessible as an I32 on Wasm side. This function is imported into the Wasm module.

Now, we create a function called getDocumentFromWindow. This function takes an index into the mapping table, and returns another index. The implementation looks up the window reference from the mapping table and resolves its document property, and puts this document into the mapping table and returns that index to Wasm. This function is also imported into the Wasm module.

On the Wasm side, we can now indirectly manipulate Wasm host references by our imported functions. Our mapping table emulates JS references by integer indices. This is a slower version of what might come with the Wasm Reference Type proposal.

So this whole mapping logic can be created by the compiler. Once reference types are available, the compiler can be changed and use the new type system for more efficient code.

It you want to see such kind if compiler in action, take a look at https://github.com/mirkosertic/Bytecoder. It can compile JVM bytecode to JavaScript and WebAssembly and provides a transparent way for DOM and Browser API interaction in both ways. It is possible to call DOM from Wasm, and it is also possible to call Wasm from DOM, for instance to implement click-listeners and other cool stuff like interaction with high level frameworks like vue.js.

Disclaimer: I am the inventor of Bytecoder, but the described logic can be adapted to any other compiler.

Andreas Rossberg
  • 34,518
  • 3
  • 61
  • 72
Mirko Sertic
  • 368
  • 3
  • 7
  • 1
    The fundamental problem with this approach is that it will leak memory if you don't take extra steps to free unused entries in the mapping table. In general, that'll require a form of garbage collection that spans both the JS heap and the heap inside the Wasm app, which is very hard to do correctly and efficiently. The reference type proposal is meant to solve this problem. – Andreas Rossberg Dec 29 '18 at 08:36
  • 1
    The Wasm reference type proposal states references can be stored in tables. So in fact there is still a mapping table, but it is part of the Wasm module instance. IMHO house keeping must sill be done to prevent memory leaks, but the whole GC logic can be implemented in the Was, module. – Mirko Sertic Jan 02 '19 at 21:43
  • @MirkoSerlic, true, but the Wasm app only needs to put references there that it needs to point to from linear memory (and it can then manage memory and table together). References merely passed as parameters/results (or stored in globals) don't require any explicit management. – Andreas Rossberg Jan 03 '19 at 08:49
  • Can you provide the most minimal example (or basically the example you mentioned about changing the document title) in a working codepen.io example? – trusktr Feb 16 '19 at 20:09
  • @AndreasRossberg thanks for all your collaborations to make wasm possible, can you please expand this, answering https://stackoverflow.com/questions/62587845/wasm-reference-types-and-dom-access? – Exec21 Jun 26 '20 at 04:07
4

WebAssembly folks haven't any strong idea yet for what JS objects in WebAssembly are going to look like, it seems.

I'd look through PR #1080, which is about the Garbage Collection spec being spun off into it's own repo for now. But while that's happening they're removing the only mentions of the web platform & interop with JS objects that exist in the spec, which is described as:

It's more aspirational that concrete,

edgerunner
  • 14,873
  • 2
  • 57
  • 69
rektide
  • 1,492
  • 13
  • 21
3

I just came across js_ffi
https://github.com/richardanaya/js_ffi
Not sure if it works for C as well, but it is advertised as such.

GRASBOCK
  • 631
  • 6
  • 16
  • That looks great actually - looking to write a fast (table, list) filtering in rust/wasm as a side project to learn some rust - this could be the perfect tool to get the data in and out – Max Aug 24 '20 at 16:26