After the MVP, to realize the high-level goals of (1) integrating well with the existing Web platform and (2) supporting languages other than C++, WebAssembly needs to be able to:
The following document is a high-level sketch of one approach for implementing the above goals. Consider the contents incomplete and expect change over time.
An important constraint is that, while WebAssembly should allow tight integration with the Web, it should not bake in details or Web standards dependencies that prevent execution in a non-Web embedding. This suggests a design (called opaque reference types below) that hides the details of JavaScript and WebIDL behind Web-embedding-specific builtin modules. On the other hand, WebAssembly can define a set of native GC primitives that allowed portable GC code to be written regardless of the host environment.
The first feature is to extend module imports to allow modules to import opaque reference types. “Opaque” means that the reference type itself has no structural content and does not, e.g., define any methods or fields. Once imported, an opaque reference type can be used in the signature of other imported functions. Thus, the point of an opaque reference type is to be passed to and returned from exported functions.
Reference types are allowed to be used as the types of locals, parameters
and return types. Additionally, references would be allowed as operands to
operators that treat their values as black boxes (br
, block
, etc.).
A new dynamic_cast
operator would be added to allow checked
casting from any opaque reference type to any other opaque reference type.
Whether the cast succeeds is up to the host environment; WebAssembly itself
will define no a priori subtyping relationship.
For reasons of safety and limiting nondeterminism, imported opaque reference types would not be able to be loaded from or stored to linear memory where they could otherwise be arbitrarily aliased as integers. Instead, a new set of operators would be added for allocating, deallocating, loading and storing from integer-indexed cells that could hold references and were not aliasable by linear memory.
With opaque reference types expressed as imports, host environments can provide access to various kinds of reference-counted or garbage-collected host-defined objects via builtin modules. While this design does not mandate a JavaScript VM or browser, it does allow natural integration with both JavaScript and WebIDL in a Web environment.
Using opaque reference types,
JavaScript values could be made accessible to WebAssembly code through a builtin
js
module providing:
string
opaque reference type and exported functions
to allocate, query length, and index string
values;object
opaque reference type and exported functions
that correspond with the ES5 meta-object protocol including the
ability to [[Call]]
function objects;value
opaque reference type with exported functions for
constructing value
s from integers, floats, object
s, string
s, etc and
with exported functions for querying the type of a value
and extracting the
abovementioned payload types.Since a browser’s WebAssembly engine would have full knowledge of the js
builtin module, it should be able to optimize string/object accesses as well as
a normal JavaScript JIT compiler (perhaps even using the same JIT compiler).
Using opaque reference types, it would be possible to allow direct access to DOM and Web APIs by mapping their WebIDL interfaces to WebAssembly builtin module signatures. In particular:
void (WebGLRenderingContextBase, int32, WebGLTexture?)
).This high-level description glosses over many important details about WebIDL:
First, the WebIDL spec contains many JavaScript-specific details that are unnecessary in a WebAssembly context. In particular, there are basically three components specified by a WebIDL interface:
(1) and (2) of the WebIDL spec are meaningful to WebAssembly, but (3) would effectively be skipped.
Another important issue is mapping WebIDL values types that aren’t simple primitive types:
(function pointer, environment pointer)
closure pair.Overall, the goal of mapping WebIDL to WebAssembly builtin modules is to avoid the need to define a duplicate WebAssembly interface for all Web APIs. In practice, some WebIDL patterns may have an unnatural or inefficient mapping into WebAssembly such that new overloads and best practices would need to be adopted. Over time, though, these rough edges would be ironed out leaving the long term benefit of defining Web APIs with a single interface and ensuring that JavaScript and WebAssembly always had access to the same raw functionality.
In contrast to opaque reference types, a second feature would be to allow direct GC allocation and field access from WebAssembly code through non-opaque reference types.
There is a lot of the design left to consider for this feature, but a few points of tentative agreement are: