Unsurprisingly, one of WebAssembly's primary purposes is to run on the Web, for example embedded in Web browsers (though this is not its only purpose).
This means integrating with the Web ecosystem, leveraging Web APIs, supporting the Web's security model, preserving the Web's portability, and designing in room for evolutionary development. Many of these goals are clearly reflected in WebAssembly's high-level goals. In particular, WebAssembly MVP will be no looser from a security point of view than if the module was JavaScript.
More concretely, the following is a list of points of contact between WebAssembly and the rest of the Web platform that have been considered:
A JavaScript API is provided which allows JavaScript to compile WebAssembly modules, perform limited reflection on compiled modules, store and retrieve compiled modules from offline storage, instantiate compiled modules with JavaScript imports, call the exported functions of instantiated modules, alias the exported memory of instantiated modules, etc.
The Web embedding includes additional methods useful in that context. In non-web embeddings, these APIs may not be present.
In Web embeddings, the following methods are added.
Note that it is expected that compileStreaming and instantiateStreaming be either both present or both absent.
🌀 Added for milestone 2, developers must feature detect.
Promise<WebAssembly.Module> compileStreaming(source)
This function accepts a Response object, or a
promise for one, and compiles the resulting bytes of the response. This compilation can be performed
in the background and in a streaming manner. If the Response is not
CORS-same-origin,
does not represent an ok status, or does not match the
`application/wasm` MIME type, the returned promise will be rejected with a TypeError; if
compilation fails, the returned promise will be rejected with a WebAssembly.CompileError.
- Return the result of processing a potential WebAssembly
response, given source, with the following steps:
- Processing steps, given bytes:
- Compile bytes, in the same fashion as specified for the
WebAssembly.Moduleconstructor. - If compilation completes successfully, return a success with the validated
Ast.modulecompilation result. - Otherwise, if compilation fails, return a failure with the failure reason.
- Compile bytes, in the same fashion as specified for the
- Success steps, given module
- Return a new
WebAssembly.Moduleinstance, with its [[Module]] set to module.
- Return a new
- Failure steps, given reason
- Return a new
WebAssembly.CompileErrorcontaining the compilation failure information stored in reason.
- Return a new
- Processing steps, given bytes:
🌀 Added for milestone 2, developers must feature detect.
dictionary WebAssemblyInstantiatedSource {
required WebAssembly.Module module;
required WebAssembly.Instance instance;
};
Promise<InstantiatedSource> instantiateStreaming(source [, importObject])
This function accepts a Response object, or a
promise for one, and compiles and instantiates the resulting bytes of the response. This compilation
can be performed in the background and in a streaming manner. If the Response is not
CORS-same-origin,
does not represent an ok status, or does not match the
`application/wasm` MIME type, the returned promise will be rejected with a TypeError; if
compilation or instantiation fails, the returned promise will be rejected with a
WebAssembly.CompileError, WebAssembly.LinkError, or WebAssembly.RuntimeError depending on the
cause of failure.
- Return the result of processing a potential WebAssembly
response, given source, with the following steps:
- Processing steps, given bytes:
- Compile bytes, in the same fashion as specified for the
WebAssembly.Moduleconstructor. - If compilation completes successfully:
- Let module be the
Ast.modulecompilation result. - Instantiate module in the in the same fashion as specified for the
WebAssembly.Instanceconstructor. - If instantiation completes successfully, return a success with a tuple containing module, the resulting instance, and the resulting exports.
- Otherwise, if instantiation fails, return a failure with the failure reason.
- Let module be the
- Otherwise, if compilation fails, return a failure with the failure reason.
- Compile bytes, in the same fashion as specified for the
- Success steps, given a tuple (module, instance, exports)
- Create exportsObject from exports, in the same fashion as specified for the
WebAssembly.Instanceconstructor. - Create instanceObject from exportsObject and instance, in the same fashion as specified for the
WebAssembly.Instanceconstructor. - Let moduleObject be a new
WebAssembly.Moduleinstance, with its [[Module]] set to module. - Let result be ObjectCreate(%ObjectPrototype%).
- Perform
CreateDataProperty(result,
"
module", moduleObject). - Perform
CreateDataProperty(result,
"
instance", instanceObject). - Return result.
- Create exportsObject from exports, in the same fashion as specified for the
- Failure steps, given reason
- Return a new
WebAssembly.CompileError,WebAssembly.LinkError, orWebAssembly.RuntimeErroras appropriate for the failure information stored in reason.
- Return a new
- Processing steps, given bytes:
The above two functions both reuse much of the same infrastructure for extracting bytes from an
appropriate Response object, differing only in
what they do with those bytes in the end. As such we define the following shared spec-level
procedure:
Process a potential WebAssembly response accepts an input argument and three sets of steps processingSteps, successSteps, and failureSteps:
- argument is an arbitrary author-supplied JavaScript value.
- processingSteps will occur in parallel (i.e. "off the main thread"), accepts a byte sequence, and must return a Realm-agnostic success or failure value.
- successSteps and failureSteps will occur in tasks posted back to the main event loop; they accept the Realm-agnostic values returned from processingSteps, and must transform them into JavaScript objects that can be used to appropriately fulfill or reject the returned promise.
Given these values, to process a potential WebAssembly response:
- Let returnValue be a new promise.
- Let sourceAsPromise be a promise resolved with argument.
- Upon fulfillment of
sourceAsPromise with value unwrappedSource:
- If unwrappedSource is not a
Responseobject, reject returnValue with aTypeErrorexception and abort these substeps. - Let response be unwrappedSource's response.
- Let mimeType be the result of extracting a MIME type from response's header list.
- If mimeType is not
`application/wasm`, reject returnValue with aTypeErrorand abort these substeps. (NOTE: extra parameters are not allowed, including the empty`application/wasm;`.) - If response is not
CORS-same-origin,
reject returnValue with a
TypeErrorand abort these substeps. - If response's status is not an
ok status, reject returnValue with a
TypeErrorand abort these substeps. - Consume response's body as an
ArrayBuffer, and let bodyPromise be the result. (NOTE: although it is specified here that the response is consumed entirely before processingSteps proceeds, that is purely for ease of specification; implementations are likely to instead perform processing in a streaming fashion. The different is unobservable, and thus the simpler model is specified.) - Upon fulfillment of
bodyPromise with value bodyArrayBuffer:
- Let bytes be the byte sequence underlying bodyArrayBuffer.
- In parallel, perform processingSteps, given bytes.
- If processingSteps succeeds with value processingSuccessValue, queue a task on the networking task source to run successSteps given processingSuccessValue, and let successResult be the result of those steps. Resolve returnValue with successResult.
- Otherwise, if processingSteps fails with reason processingFailureReason, queue a task on the networking task source to run failureSteps given processingFailureReason, and let failureResult be the result of those steps. Reject returnValue with failureResult.
- Upon rejection of
bodyPromise with reason reason:
- Reject returnValue with reason.
- If unwrappedSource is not a
- Upon rejection of
sourceAsPromise with reason reason:
- Reject returnValue with reason.
- Return returnValue.
Browsers, JavaScript engines, and offline tools have common ways of referring to JavaScript artifacts and language constructs. For example, locations in JavaScript source code are printed in stack traces or error messages, and are represented naturally as decimal-format lines and columns in text files. Names of functions and variables are taken directly from the sources. Therefore (for example) even though the exact format of Error.stack strings does not always match, the locations are easily understandable and the same across browsers.
To achive the same goal of a common representations for WebAssembly constructs, the following conventions are adopted.
A WebAssembly location is a reference to a particular instruction in the binary, and may be displayed by a browser or engine in similar contexts as JavaScript source locations. It has the following format:
${url}:wasm-function[${funcIndex}]:${pcOffset}
Where
${url}is the URL associated with the module, if applicable (see notes).${funcIndex}is an index in the function index space.${pcOffset}is the offset in the module binary of the first byte of the instruction, printed in hexadecimal with lower-case digits, with a leading0xprefix.
Notes:
- The URL field may be interpreted differently depending on the
context. When the response-based
instantiation API is used in a
browser, the associated URL should be used; or when the
ArrayBuffer-based instantiation
API is used, the browser should represent
the location of the API call. This kind of instantiation is analagous to
executing JavaScript using
eval; therefore if the browser has an existing method to represent the location of theevalcall it can use a similar one forWebAssembly.instantiate. For example if the browser usesfoo.js line 10 > evaloreval at bar (foo.js:10:3)foreval, it could usefoo.js line 10 > WebAssembly.instantiateorWebAssembly.instantiate at bar (foo.js:10:3), respectively. Offline tools may use a filename instead. - Using hexadecimal for module offsets matches common conventions in native tools such as objdump (where addresses are printed in hex) and makes them visually distinct from JavaScript line numbers. Other numbers are represented in decimal.
While the name property of exported WebAssembly functions
is specified by the JS API, synthesized function names are also
displayed in other contexts like devtool callstacks and Error.stack.
If a WebAssembly module contains a "name" section,
these names should be used to synthesize a function name as follows:
- If a function name subsection is present, the displayed name should
be
${module_name}.${function_name}or${function_name}, depending on whether the module name is present. - Otherwise, the output can be context-dependent:
- If the function name is shown alongside its location in a stack trace, then just the module name (if present) or an empty string can be used (because the function index is already in the location).
- Otherwise,
${module_name}.wasm-function[${funcIndex}]orwasm-function[${funcIndex}]should be used to convey the function index.
Note that this document does not specify the full format of strings such as stack frame representations; this allows engines to continue using their existing formats for JavaScript (which existing code may already be depending on) while still printing WebAssembly frames in a format consistent with JavaScript.
WebAssembly's modules allow for natural integration with the ES6 module system.
A WebAssembly module can have imports and exports, which are identified using
UTF-8 byte sequences. The most natural Web representation of a mapping of export
names to exports is a JS object in which each export is a property with a name
encoded in UTF-16. A WebAssembly module fails validation on the Web if it has
imports or exports whose names do not transcode cleanly to UTF-16 according to
the following conversion algorithm, assuming that the WebAssembly name is in a
Uint8Array called array:
function convertToJSString(array)
{
var string = "";
for (var i = 0; i < array.length; ++i)
string += String.fromCharCode(array[i]);
return decodeURIComponent(escape(string));
}
This performs the UTF8 decoding (decodeURIComponent(escape(string))) using
a common JS idiom.
Transcoding failure is detected by decodeURIComponent, which may throw
URIError. If it does, the WebAssembly module will not validate. This validation
rule is only mandatory for Web embedding.
Source maps are a debug-information format used on the web, generated by toolchains that target JavaScript, either from other languages (e.g. TypeScript, Emscripten) or from JavaScript itself (e.g. Closure, minifiers). A browser that supports source maps can display the original source in its developer tools instead of the compiled JavaScript that the VM actually executes. It can support setting breakpoints specified as source lines, single-stepping through source lines, and showing source lines in stack traces; however it cannot support getting or setting variables from the original source code because the format is not "full" debug info: it only maps locations from the compiled code back to locations in the source files (where a generated-code location consists of a line and column number, and a source location consists of file, line, and column). Generated files use a specially-formatted comment to specify a URL for a source map that describes the file.
Source maps can be made to serve the same purpose for WebAssembly binary files, allowing parity with asm.js. By re-using an existing standard, browsers can take advantage of their existing source map support without having to make significant changes to their developer tools.
An alternative method is to specify location mapping information in some way other than source maps. For example, it could be encoded directly into the WebAssembly binary the way function and local names are written in the "name" section. This is more convenient if the VM itself uses the information (for example to generate a stack trace). However existing developer tools implementations are designed around the source map model of passing a URL from the VM to the dev tools code, which fetches and interprets the information. Therefore it is expected that it will be much simpler to use "real" source maps than to design another format.
Source maps also have known limitations (e.g. source variables cannot be described). A complete debug info format will eventually be needed; however the intention of this specification is to allow for easy integration with existing developer tools implementations in browsers.
With few exceptions, most aspects of the source map spec may be applied directly to WebAssembly. Because WebAssembly is a binary format (and thus does not have lines and columns, or comments per se), some simple reinterpretation of concepts is needed.
Source maps specify how to map a (zero-based) line and column position in generated code to a file, line, and column location in the source. For WebAssembly binary locations, the line number is always 1, and the column number is interpreted as a byte offset into the WebAssembly binary content (this results in a more efficient encoding than using the line number instead). Source locations are interpreted as in the source map spec.
When the generated code is JavaScript, it includes a specially-formatted line
at the end, which is the URL of the associated source map. For WebAssembly, a custom
section named "sourceMappingURL" contains the URL.
The URL is represented and encoded as defined in the WHATWG
URL spec.
If the URL is not absolute, then:
- If the wasm module is associated with an HTTP response (e.g. the compileStreaming or instantiateStreaming APIs are used), then it is resolved relative to the URL of the response.
- Otherwise it is relative to the page's origin.
For wasm modules with an associated HTTP response (e.g. those using
the compileStreaming or instantiateStreaming
APIs) the source map URL may also be specified
using the SourceMap: HTTP header as with JavaScript source maps.
WebAssembly's security model should depend on the same-origin policy, with cross-origin resource sharing (CORS) and subresource integrity to enable distribution through content distribution networks and to implement dynamic linking.
Once SIMD is supported WebAssembly would:
- Be statically typed analogous to SIMD.js-in-asm.js;
- Reuse specification of operation semantics (with TC39);
- Reuse backend implementation (same IR nodes).
Once GC is supported, WebAssembly code would be able to reference and access JavaScript, DOM, and general WebIDL-defined objects.