-
Notifications
You must be signed in to change notification settings - Fork 695
Improve code loading and modules section #71
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,50 @@ precise descriptions of: | |
* the [AST semantics](AstSemantics.md) | ||
* the [binary encoding](BinaryEncoding.md) | ||
|
||
## Modules | ||
* The primary unit of loadable, executable code is a *module*. | ||
* In a host environment with ES6 modules (browser, node.js), a WebAssembly | ||
module is loaded in the same way as an ES6 module (`import` statements, | ||
`Reflect` API, `Worker` constructor, etc) and the result is reflected to | ||
JS as an ES6 module object. | ||
* A module can declare a subset of its functions and global variables to be | ||
*exports*. The meaning of exports (how and when they are called) is defined by | ||
the host environment. | ||
* In an environment with ES6 modules, the WebAssembly exports would be the | ||
ES6 module object exports. | ||
* A minimal shell environment might define `main` to be the only | ||
meaningful export. | ||
* We may want to define an `init` method in the spec that is always called | ||
after loading a module and before any other exports are called. | ||
* A module can declare a set of *imports*. An import is a tuple containing a | ||
module name, export name, and the type to use for the import within the | ||
module. The host environment controls the mapping from module name to which module | ||
is loaded. | ||
* In an environment with ES6 modules, an import first passes the | ||
module name to the [module loader pipeline](http://whatwg.github.io/loader) | ||
and resulting ES6 module (which could be implemented in JS or WebAssembly) | ||
is queried for the export name. | ||
* The spec defines the semantics of loading and calling exports of a | ||
*single* module. The meaning of a call to an import is defined by | ||
the host environment. | ||
* In an environment with ES6 modules, there is no special case for when one | ||
WebAssembly module imports another: they have separate [heaps](V1.md#heap) | ||
and pointers cannot be passed between the two. Module imports encapsulate | ||
the importer and importee. | ||
* In a minimal shell environment, imports could be limited to | ||
builtin modules (implemented by the shell) and/or shell scripts. | ||
* The [dynamic linking](FutureFeatures.md#dynamic-linking) post-v.1 feature | ||
would extend the semantics to include multiple modules and thus allow heap | ||
and pointer sharing. Dynamic linking would be semantically distinct from | ||
importing, though. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I greatly appreciate the rephrasing here, it makes it pretty clear what you're suggesting. It is highly contended though! Myself and many coworkers think that the API surface layer is something that we'll need to define more strictly than what you've outlined, though I do think your description is a good first step in that direction. I think it would be useful to leave this text pretty much as is with a TODO explaining that we haven't quite agreed on this yet. I think we'll want to do so in a separate PR though, and it may be better to talk through where we're coming from in a higher throughput medium first. /cc @titzer @davidsehr @ncbray to comment. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great, happy to iterate on this more in the future. |
||
* When compiling from C++, imports would be generated for unresolved | ||
`extern` functions and calls to those `extern` functions would call the import. | ||
* Thus, in an environment with ES6 modules, to synchronously call into JS from | ||
C++, the C++ code would declare and call an unndefined `extern` function and | ||
the target JS function would be given the (mangled) name of the `extern` and | ||
put inside the imported ES6 module. | ||
* TODO: there is more to discuss here concerning APIs. | ||
|
||
## Module structure | ||
* At the top level, a module is ELF-like: a sequence of sections which declare their type and byte-length. | ||
* Sections with unknown types would be skipped without error. | ||
|
@@ -81,20 +125,6 @@ precise descriptions of: | |
directly into JS. | ||
* TODO: there is no real proposal yet | ||
|
||
## Code loading and imports | ||
* The loadable unit of WebAssembly code is a *module*. | ||
* WebAssembly modules can be loaded declaratively (via import on page load) or imperatively (via API call) | ||
and can be compiled dynamically (from bytes, as defined by the binary format). | ||
* A natural integration point with JS would be to have WebAssembly modules be reflected to JS | ||
as ES6 Modules. | ||
* The module interface would mostly hide whether the module was JS or WebAssembly (except for things | ||
like `fun.toSource()`) and allow webapps to be naturally composed of both JS and WebAssembly modules. | ||
* ES6 Modules can be loaded declaratively (via imports) or imperatively (via API calls at runtime). | ||
* The ES6 Module API also allows dynamically generated modules (a JS module can be compiled from a string); | ||
building on this, WebAssembly modules could be dynamically compiled from an ArrayBuffer. | ||
* Just like ES6 modules, WebAssembly modules could import other modules (JS or WebAssembly); this would | ||
replace asm.js [FFIs](http://asmjs.org/spec/latest/index.html#external-code-and-data). | ||
|
||
## Heap | ||
* In v.1, when a WebAssembly module is loaded, it creates a new heap. | ||
* The [dynamic linking](FutureFeatures.md#dynamic-linking) feature will be necessary for two | ||
|
@@ -123,8 +153,8 @@ precise descriptions of: | |
for portable C/C++ code. | ||
|
||
## Non-browser embedding | ||
* Host environments can define builtin modules that are implemented natively and thus be imported | ||
directly by WebAssembly modules. | ||
* Host environments can define builtin modules that are implemented natively but can otherwise | ||
be imported like [other modules](V1.md#code-loading-and-imports). | ||
* For example, a WebAssembly shell might define a builtin `stdio` library with an export `puts`. | ||
* Another example, in the browser, would be the WebIDL support mentioned in [future features](FutureFeatures.md). | ||
* Where there is overlap between the browser and popular non-browser environments, a shared spec could be | ||
|
@@ -135,8 +165,8 @@ precise descriptions of: | |
on core APIs like network and file I/O. | ||
* To allow writing portable POSIX-like code (that ran in both browser and other environments), the | ||
WebAssembly community would develop a shared repository of WebAssembly code that mapped between a | ||
POSIX-like interface and the host's builtin modules at either compile-time (#ifdefs) or run-time | ||
(feature-testing and conditional loading; both v.1 features). | ||
POSIX-like interface and the host's builtin modules using compile-time #ifdefs or, after | ||
[dynamic linking](FutureFeatures.md#dynamic-linking) was added, client-side dynamic feature testing. | ||
* A symmetric example in JS would be the [ES6 Module Loader polyfill](https://github.com/ModuleLoader/es6-module-loader) library. | ||
* The WebAssembly spec would thus not try to define any large portable libc-like library. | ||
* However, certain features that are core to WebAssembly semantics that are found in native libc | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like PNaCl's approach of only defining
_start
as an export: it's up to the developer's code (usually provided by the toolchain) to go through the.init_array
(which PNaCl merges with the C++ global static ctors). The approach is very extensible-web-y in that it's the minimum feature set and lets developers to everything.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you specifically talking about initialization or saying that there only be a single export. If the former, I'm missing how that's different than what the bullet says (s/init/_start/). If the latter, then we hurt the use case where a wasm module is written to be used as an ES6 module from JS.