Skip to content

JS interop and glue code #119

Closed
Closed
@kg

Description

@kg

There's a gap in our current plans regarding JS interop and JS glue code.

At present, an emscripten-compiled module includes a bunch of JS interop and glue code that wraps the asm.js module. When you load an emscripten-compiled module, the glue code is what runs and does the work of turning that asm.js module into something that is exposed to javascript.

So far it seems that we are assuming that wasm will eliminate the need for most of this glue javascript. I agree with this. However, some of it is going to have to stick around no matter what, because it abstracts away the emscripten ABI and provides a surface the emscripten-compiled C++ can use to talk to the dom. Eliminating that glue will not be feasible until we've specified an ABI and webassembly can interact with GC objects.

At present the solution to these issues would probably be something like this:
Compilers like emscripten generate a wrapper javascript file (foo.wrap.js) next to every wasm module they generate (foo.wasm). Consumers have to import foo.wrap.js, not foo.wasm. The ABI is abstracted by each generated .wrap.js file.
The .wrap.js file exposes its interop code to the webasm... somehow? Right now it'd be passed in to the asm.js module via that globals/imports object, but we're doing away with that and having webassembly pull things in via ES6 imports. So does the webasm module import from the glue JS while the glue JS imports the webasm module?
The glue JS is required for an asm.js/webasm module to be able to interop with some DOM APIs, for example ones that take strings or arrays. Presently this is simple since emscripten just bundles the necessary wrapper code in - when we take that away the glue code will be mandatory for those modules to work.

Aside from the complexity here, there are some real threats:

  • Once dynamic linking is introduced, webasm modules will need a way to import the unwrapped webasm module so they have direct access to the native entry points, instead of the wrapped JS ones being exposed by the wrapper JS module.
  • Developers may tire of the wrapper JS mess and decide to instead use a single common glue/wrapper library that imports all their modules directly. In this scenario, the emscripten ABI becomes a de-facto standard. (I consider this an extremely realistic threat, since that's the approach I went with for my compiler's emscripten interop.)

It's my opinion that we need to spec - even in the MVP - a basic mechanism for bundling a glue/wrapper JS file into a webasm module/executable. The glue/wrapper file will serve as an analogue to how COM type libraries (IDL descriptions) can be embedded into native win32 .dll and .exe files to allow a consumer to import directly from those executables without any supporting files. In native runtime environments (non-JS) and dynamic linking scenarios, the glue JS would be ignored since it serves no purpose.

My rough proposal for this would be:
Every webasm file has an optional 'glue' section that contains an ecmascript module. If provided, this module can be imported by the webasm code via a special name as if it were a regular ES6 module (i.e. import { supportFunction } from 'glue').

The glue module can expose a special function that is invoked after the webasm module has finished loading:
function doExport (nativeModule)
If provided, doExport is invoked and the native webasm module object is passed as a parameter. The return value of doExport is the actual object exported when JS imports the module. This allows you to add glue code as properties onto the asm module object, or return a special wrapper object instead (that hides methods, etc.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions