This Mozilla technical blog post explains WebAssembly-JavaScript function call optimization in Firefox, demonstrating strong alignment with Article 19 (freedom of information), Article 26 (right to education), and Article 27 (participation in scientific culture). The content advocates for open web development and technical knowledge democratization through pedagogically sound, freely accessible explanation of complex engine internals. The article supports developer empowerment while maintaining institutional commitment to public-interest technology, though site-level analytics tracking introduces a privacy tension.
Kudos to the author of this post - it takes a lot of skill to explain complex concepts like this, let alone in plain enough english that someone not skilled in the art could follow along.
WebAssembly is one of those technologies where we haven't seen the true extent of its capabilities yet. This is an exciting time to be working in browsers.
Very exciting! And really amazing work. It appears that WASM, at least in Firefox, is now going to be on par with JS in terms of performance when calling other JS facilities. Those comparison times are quite impressive.
I think the thing I found most exciting is at the end: “WebAssembly is getting more flexible types very soon. Experimental support for the current proposal is already landed in Firefox Nightly.” Implication being that WASM will have native access to the DOM.
I think at that point WASM could be used to fully work with the DOM with no negative costs, right?
Lin is awesome, but reading this nice article I have one noob question.
> We took the code that C++ was running — the entry stub — and made it directly callable from JIT code. When the engine goes from JavaScript to WebAssembly, the entry stub un-boxes the values and places them in the right place. With this, we got rid of the C++ trampolining.
So they replaced unboxing C++ trampoline with entry stub. But isn't that stub technically written in C++ too?
Another interesting flag I found was javascript.options.wasm_cranelift, which enables a WASM code generator written in Rust: https://github.com/CraneStation/cranelift
While searching for more information on a configuration value mentioned in the article (javascript.options.wasm_gc) I came across another article on the topic, which I also found interesting because it's a bit more technical:
Firefox loads and runs Unity3D WebGL apps MUCH faster than Chrome.
The point of UnityJS is to tightly and efficiently integrate Unity3D and JavaScript, so it does a lot of JavaScript <=> C# calls, and I'm looking forward to it getting even faster!
You can pass delegates to C# functions that are directly callable into JavaScript using some magic PInvoke attributes and the Unity Runtime.dynCall function.
Declare a delegate that describes the signature of your C# function you want to call from JavaScript:
[MonoPInvokeCallback(typeof(AllocateTextureDelegate))]
public static int AllocateTexture(int width, int height) { ... }
Then pass those specially marked delegates to JavaScript and stash them in JS variables when you initialize (it doesn't work unless you use the magic MonoPInvokeCallback attribute):
In the awake function on the JavaScript side of your Unity WebGL extension (a .jslib file), wrap the C# delegate in a JavaScript thunk that calls into it via Runtime.dynCall:
params.cache.backgroundSharedTextureID = id =
window.bridge._UnityJS_AllocateTexture(params.width, params.height);
This is zillions of time faster and more flexible than using Unity's terrible SendMessage technique to send messages from JS=>C#, whose only parameter is a single string, and which inefficiently dispatches messages by looking up Unity objects by name, and is asynchronous and can't return a result.
I use this technique to efficiently copy binary textures and arrays of numbers between JavaScript and C#. MUCH better than serializing it as JSON, or base 64 encoded PNG files in a data: url (yuck!).
function DrawToCanvas(params, drawer, success, error)
{ [...]
var id = params.pie.backgroundSharedTextureID;
if (!id) {
params.pie.backgroundSharedTextureID = id =
window.bridge._UnityJS_AllocateTexture(params.width, params.height);
//console.log("game.js: DrawToCanvas: WebGL: AllocateTexture: width: " + params.width + " height: " + params.height + " id: " + id);
}
var imageData =
context.getImageData(0, 0, params.width, params.height);
window.bridge._UnityJS_UpdateTexture(id, imageData);
texture = {
type: 'sharedtexture',
id: id
};
success(texture, params);
canvasNode.parentNode.removeChild(canvasNode);
This lets me draw 2D user interface stuff, pie charts, diagrams, data visualizations, etc, in JavaScript with canvas, d3, or whatever library I like, and then efficiently use those images in Unity3D as user interface overlays, 3D textures, etc. It works great, and it's smooth and interactive, mixing up 2D canvas graphics with 3D Unity stuff!
Unity is sorely lacking a decent 2D drawing library like canvas, not to mention fancy stuff built on top of it like d3.
I'm currently working on the plumbing to send binary arrays of floats from JavaScript to Unity, so I can pass them right into shaders!
Here's some discussion about the magic MonoPInvokeCallback attribute:
Did anyone re-implement the basic React API surface, using Wasm as a backend for the Virtual DOM? To me, it sounds like this would be an interesting project.
Exposing Web APIs (e.g. DOM) to WASM and projecting them into native languages seems like it overlaps a lot with defining actual native API projections that would be shared between browser implementations.
It doesn't read like this is an explicit goal of the project, but are we going to get this by accident? Being able to use the same X code (where X is your favourite statically-compilable language) to generate both a WASM version that runs on the web and a statically-compiled version that links to the Y browser source (where Y can be whichever browser works for you because they all support the same native API) would be awesome.
> Function calls from WASM to JS don't seem to have improved so much.
Yeah, Wasm => JS calls used to be reasonably fast because we had optimized that before. The work described here made that path much nicer, though (a more unified stack layout for JIT/Wasm frames) and also a bit faster still.
JS => Wasm calls being slow was one of the big performance cliffs in SpiderMonkey and I'm really glad that's fixed now.
Almost, that will set the foundation for fully using the DOM APIs. The host bindings proposal mentioned at the end of the article should close the gap.
Don’t get me wrong this is a great article. But I found the analogy with the people and pieces of paper a bit hard to read. (The analogy with the people made me think the author was talking about some sort of prototype delegation chain, https://giamir.com/alternative-patterns-in-JS-OLOO-style, rather than nested function calls.) Who is clicking on this but doesn’t know what a stack frame is?
At the moment, wasm can only call functions that were passed as values of the import object which is passed to to one of the instantiation functions (e.g. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...), so which function gets called is up to the embedding JS code.
Timing for calls from WASM to JS went from 750ms to 450ms for 100 million calls, so from 7.5 nanoseconds per call to 4.5 nanoseconds per call.
A 3 GHz CPU would do 3 ticks per nanoseconds, doing such a bridging call in 23 or 15 CPU ticks is quite good IMHO (I just hope I didn't blunder the math, but function call overhead from WASM to JS isn't much of an issue, it was already fast after the previous round of optimizations).
At the moment I don't think there is a frontend language/framework which compiles to WASM and is actually worth using, at least from a perspective of frontend productivity. For performance or porting legacy code, WASM is already useful.
I mean, yes, there are things like Blazor or similar things for Rust or Nim, but these aren't yet compelling to me.
It's not clear to me why calling into C++ is expensive to begin with. My best guess is it has to do with switching to a native stack (switching "folders"). So making the stub directly callable from the JIT means not having to change activations. Also presumably it uses the parameter passing conventions and semantics of all other JIT functions (whereas with a C++ function it presumably has to marshal the parameters to the function).
Based on a quick look through https://bugzilla.mozilla.org/show_bug.cgi?id=1319203 it looks like the entry stub is generated by the JIT itself. So no, the entry stub is not written in C++. It gets output by the JIT as part of the generated jitcode.
There is still an out-of-line codepath that does call into a C++-implemented entry stub in some cases when the argument conversions involved are too complicated to do them directly in the JIT-generated code.
The article pretty much described what the big obstacle was: boxing. If WASM had boxing, then it wouldn't be any faster than JavaScript and there'd be no point. Since JavaScript requires boxing, there's no way to avoid the impedance mismatch at the boundary between them, and a JIT that wants to support both has to be aware of both boxed and unboxed numbers.
The WASM spec already tries to avoid pretty much every other big problem that would've confounded attempts to cross-language inline. For example, WASM requires structured control flow (IOW, WASM doesn't have `goto`), avoids type punning in favor of a reinterpret primitive, uses function addresses that are orthogonal to memory addresses, and allows non-deterministic floating point bit representations, all to match up closer with the way existing JavaScript JITs already work. But they can't do anything about boxing without either breaking the web or making WebAssembly essentially a binary encoding of the JavaScript language.
Not totally the same, but Blazor[1] is a similar framework powered by dotnet on wasm. As a React dev, looking at a Blazor component feels very familiar. I'd love to see something implemented in Go or another language without all the extra baggage dotnet comes with currently.
Good find! At the moment it is very very experimental and you might experience crashes and slowdowns if you're using it in place of the regular flags (that is why it is enabled only on Nightly builds and will not be enabled on Beta/Release for a while). We'll make sure to talk about it when the right time has come.
It's pretty hard to do well. If you look at Graal, a lot of the cutting edge research work they've done is about how to do cross-language inlining and subsequent optimisations better. It's more of a function of the JIT compiler design than language or bytecode specs though.
Editorial Channel
What the content says
+0.50
Article 19Freedom of Expression
High Advocacy Framing Practice Coverage
Editorial
+0.50
SETL
0.00
Article extensively documents technical knowledge without paywall, explaining WebAssembly optimization mechanisms in accessible detail. Clear information seeking/sharing framing throughout.
FW Ratio: 56%
Observable Facts
Article published without paywall or registration barrier; open access confirmed in domain context profile.
Clear author attribution: 'By Lin Clark' with date 'Posted on October 8, 2018'.
Public comments enable information exchange and dialogue, supporting collective knowledge building.
Attribution and dating support source traceability and accountability in information sharing.
+0.50
Article 26Education
High Advocacy Practice
Editorial
+0.50
SETL
0.00
Article explicitly educates readers through pedagogical explanation of technical concepts, with step-by-step reasoning, metaphors, and examples accessible to learners at different skill levels.
FW Ratio: 57%
Observable Facts
Content structured as progressive learning: begins with 'How do function calls work?' as foundational question, builds to advanced optimization techniques.
Content accessible to multiple skill levels: novices can understand call stacks; advanced readers can follow optimization details.
Free access with no registration barrier ensures equitable access to learning material.
Inferences
Pedagogical structure with progressive complexity supports diverse learners' right to education.
Accessible explanation of complex technical concepts democratizes knowledge that would otherwise be gatekept to experts.
Open access model removes economic barriers to technical education.
+0.40
Article 27Cultural Participation
Medium Advocacy Framing
Editorial
+0.40
SETL
+0.28
Article participates in technical and scientific culture by documenting engineering advancement, crediting contributors, and contributing to collective knowledge about how engines work.
Contributors credited: 'Thank you to Benjamin Bouvier, Luke Wagner, and Till Schneidereit for their input and feedback.'
Content compares approaches across different browsers/engines (V8, JavaScriptCore, Chakra, SpiderMonkey), contributing to scientific knowledge about system design.
Future work section discusses experimental features and ongoing scientific development ('Already landed in Firefox Nightly behind the pref').
Inferences
Detailed technical explanation contributes to scientific understanding of engine design and optimization.
Attribution of contributors recognizes collective scientific effort and enables peer verification.
Participation in browser standards and technical advancement supports right to participate in culture and science.
+0.20
PreamblePreamble
Medium Framing
Editorial
+0.20
SETL
+0.20
Mozilla mission statement frames technology optimization as enabling progress, implicitly supporting universal access to improved tools.
FW Ratio: 50%
Observable Facts
Article opens with Mozilla's stated goal: 'At Mozilla, we want WebAssembly to be as fast as it can be.'
Content is published through Mozilla's established technical communication channel without commercial restrictions.
Inferences
The framing of technical work as collective effort reflects institutional commitment to broad technology access.
Open publication without paywall suggests organizational values aligned with universal knowledge sharing.
+0.20
Article 18Freedom of Thought
Medium Advocacy
Editorial
+0.20
SETL
+0.14
Article presents technical ideas and knowledge transparently, supporting freedom of thought and intellectual exchange.
FW Ratio: 50%
Observable Facts
Article is authored by Lin Clark with clear byline and institutional affiliation to Mozilla.
Technical concepts are presented with explicit reasoning and multiple explanatory frameworks (metaphors of continents, folders, call stacks).
Inferences
Transparent presentation of ideas with attributed authorship supports freedom of thought.
Mozilla's institutional support for technical explanation reinforces freedom to express ideas.
+0.20
Article 23Work & Equal Pay
Low Advocacy
Editorial
+0.20
SETL
+0.14
Article indirectly supports right to work by documenting improvements to developer tools and performance, enabling better work output for tech workers.
FW Ratio: 50%
Observable Facts
Article explains optimization work that improves WebAssembly usability for developers.
Content educates developers on how to write performant code ('If you can write your code so that JavaScript is always passing the same types...').
Inferences
Better tools and understanding improve workers' capacity to perform tech work effectively.
Knowledge sharing about performance optimization enhances workers' professional capability.
0.00
Article 12Privacy
Medium Practice
Editorial
0.00
SETL
+0.20
Article content does not discuss privacy rights or protections.
FW Ratio: 50%
Observable Facts
Article does not contain privacy policy text or privacy-related discussion.
Domain context profile notes Google Analytics and GTM tracking deployed on hacks.mozilla.org.
Inferences
Absence of privacy discussion in technical blog is neutral for editorial channel.
Analytics tracking practice creates structural tension with privacy rights, despite Mozilla's privacy advocacy.
Site implements Google Analytics and GTM tracking with UTM parameter removal utility, indicating awareness of privacy concerns but continued analytics deployment.
Terms of Service
—
Terms of service not observable in provided content.
build 73de264+3rh4 · deployed 2026-02-28 13:33 UTC · evaluated 2026-02-28 13:38:19 UTC
Support HN HRCB
Each evaluation uses real API credits. HN HRCB runs on donations — no ads, no paywalls.
If you find it useful, please consider helping keep it running.