WebAssembly: Status & Web IDL Bindings W3C Games Workshop - June, 2019 Luke Wagner Based on joint Mozilla/Google presentation to WebAssembly CG last week (link)
WebAssembly Status ● 2017: "MVP" ships in 4 browsers \o/ ● Immediately continued work on a pipeline of proposed additions ● Based on TC39 stages process ● Post-MVP Roadmap ● https://github.com/webassembly/proposals
* Bindings Proposal History ● 2017 - Ship the WebAssembly "MVP" ○ Only 4 value types: i32, i64, f32, f64 ○ How can WebAssembly call Web APIs? ● 2017 - Take 1: "Host Bindings" (CG pres, TPAC pres) ○ All host values go in wasm tables (wasm linear memory requires exposing raw bits) ○ Automatically convert between table indices and host values at the interface ○ Increasingly awkward as we worked through use cases; also not efficient ● 2018 - Reference Types (CG pres, explainer) ○ Subtype hierarchy: anyref, funcref, ref T (where T = func(X→Y), struct{x:A,y:B}, array(T), ...) ○ Gives wasm first-class host values ● 2019 - Take 2: "Web IDL Bindings" (CG pres, explainer) ○ Let's focus just on efficiently binding to Web IDL , building on reference types ○ "Efficiently" means eliminating copies, garbage, auxiliary calls ("Host Bindings" didn't) ○ "Web IDL" allows us to focus on Web IDL's types, avoid Hard(TM) problems
... when calling wasm In the MVP, ... ... when calling a Web API Web API function Web IDL values Web IDL spec: ECMAScript Binding JS glue code wasm module function export JS values results results wasm JS API spec params params function import function import wasm module function export function export results results params params wasm JS API spec JS glue code function import JS values wasm module Web IDL spec: ECMAScript Binding Web IDL values Web API callback
... when calling wasm With the proposal... ... when calling a Web API Web IDL Bindings "wrap" the core module ● Defines new custom section ● Can 100% polyfill by generating JS glue from wasm module custom section Web API function function export Web IDL values results results params params Incoming binding exprs ● can place values into function import function import linear memory wasm module function export function export Outgoing binding exprs ● can extract values from results results params params linear memory Web IDL Bindings function import Web IDL values Web API callback wasm module
Binding Types/Values sketch reftype ::= ... all the core wasm reference types numtype ::= s8 | u8 | s16 | u16 | s32 | u32 | s64 | u64 | f32 | f64 / / signedness matters bindingtype ::= / / Web IDL type reftype | / / ↔ any, Interface, Promise, ... numtype | / / ↔ byte, octet, short, ... string | / / ↔ DOMString bytes | / / ↔ ArrayBuffer numtype view | / / ↔ Int8Array, Uint8Array, ... bindingtype list | / / ↔ Sequence record{ (lbl: bindingtype)* } | / / ↔ Dictionary variant{ (lbl: bindingtype)* } | / / ↔ Union, Enumeration func(bindingtype* → bindingtype*) / / ↔ Callback function
Binding Expressions sampler wasm type outgoing expression incoming expression wasm type binding type as as ref T ref T ref T i32 i32 e e f r $ c utf8-mem-str o l l a $ t r s m - e m - f 8 t u c - o i32 l l a i32 a l l o c - u t f 8 - g t r c - s t - s string r g c 8 - u t f ref array u8 as ref array u8 s a ref T T=string T=string ref T as ref struct ... ref struct ... a s record { " x " fi e l d x:string, record string string ... ... field "y" y:string } string string ... ...
Two facets of "direct" Web IDL access from wasm Importing Calling // JS loader glue code: // JS runtime glue code const importObj = { var memory = ... Document: { var td = new TextDecoder(); createElement: Document.prototype.createElement function createElement_glue(doc,tagOff,tagLen) { } var buf = memory.buffer; }; var bytes = new Uint8Array(buf,tagOff,tagLen); return doc.createElement(td.decode(bytes)); WebAssembly.instantiate(module, importObj) } .then(...) // wasm caller (import "Document" "createElement" (func (param anyref i32 i32) (result anyref))) This JS glue will be removed by a combination of: ● WebAssembly ESM-integration Removing this type of JS glue is the focus of Web IDL ● Built-in modules + import-maps Bindings ● get-originals
C++ Prototype https://github.com/jgravelle-google/wasm-webidl-polyfill Building a webIDL.js module, reads a custom section and fixes up import + export dicts at runtime Goals: ● Prototype the design, prove feasibility of polyfilling ● Polyfillability in general is a useful property because developers can ship the real bytes early, and the browser can support that natively at a later time ● Having a prepackaged chunk of JS makes this easier to include in arbitrary toolchains
Rust: wasm-bindgen wasm-bindgen as optional AOT polyfill ✗ No anyref wasm-bindgen ✗ No webidl bindings rustc/llvm ✓ Uses anyref wasm-bindgen ✓ Has webidl bindings section Sources #[wasm_bindgen(js_namespace = console)] fn log(s: &str); ●“Anyref” table in JS ●obj/slice/string glue
WebGL Prototype ● Animometer Benchmark uses ~20 OpenGL functions. ● 7 function calls in a hot loop. // repeated for 20,000 primitives glUniform1f(uScale, uniformData[i].scale); glUniform1f(uTime, uniformData[i].time); glUniform1f(uOffsetX, uniformData[i].offsetX); glUniform1f(uOffsetY, uniformData[i].offsetY); glUniform1f(uScalar, uniformData[i].scalar); glUniform1f(uScalarOffset, uniformData[i].scalarOffset); glDrawArrays(GL_TRIANGLES, 0, 3);
WebGL Prototype Experimental Results
Debugging ● Discussion at CG meeting last week (minutes) ● Converging on new debugging interfaces allowing portable debuggers ○ Goal: don't require building DWARF into all browsers ● Expect renewed activity in WebAssembly debugging subgroup (link) ○ Join!
Discussion
Recommend
More recommend