Fact-checked by Grok 2 weeks ago

asm.js

asm.js is a strict, low-level subset of JavaScript designed as a highly optimizable compilation target for languages such as C and C++, enabling near-native performance for web applications without plugins. Developed by Alon Zakai along with Luke Wagner and David Herman at Mozilla, asm.js emerged in early 2013 as an extension of prior work on compiling C/C++ to JavaScript using the Emscripten toolchain. The project formalized patterns that had evolved naturally in JavaScript optimization efforts, aiming to close the performance gap between browser-based code and native executables. The asm.js specification, published as a working draft on August 18, 2014, defines validation rules that allow engines to perform aggressive just-in-time () optimizations, such as and unboxed value representation. Core features include the "use asm" directive to signal the subset, explicit type annotations (e.g., |0 for signed 32-bit integers and + for doubles), a heap implemented via typed arrays, and restrictions excluding dynamic features like objects, strings, and closures to ensure predictable execution. These constraints create a sandboxed environment akin to a , facilitating static type checking at parse time and enabling engines like Firefox's to generate efficient . Mozilla's browser was the first to implement asm.js-specific optimizations in version 22, released in July 2013, with subsequent engines providing baseline support through general improvements. Tools like leveraged asm.js to port complex applications, including games and benchmarks like Poppler and , demonstrating throughput close to native speeds while maintaining web portability. However, limitations in text-based encoding and validation overhead prompted the evolution toward , a binary instruction format co-designed by , , Apple, and starting in 2015, which has largely superseded asm.js for new high-performance web development. Despite its deprecation, asm.js remains a foundational milestone in advancing compiled code execution on the web.

Overview and History

Definition and Goals

asm.js is a strict subset of JavaScript designed to serve as a low-level, efficient target language for compilers targeting high-performance execution in web browsers. It imposes restrictions on JavaScript features to enable aggressive optimizations, particularly for code compiled from languages like C and C++, while remaining fully compatible with standard JavaScript interpreters. Developed by Mozilla and first announced in 2013, asm.js aimed to bridge the performance gap between interpreted JavaScript and native code execution. The primary goals of asm.js were to deliver near-native speeds for ported C/C++ applications without relying on browser plugins or proprietary technologies, thereby expanding the web's capabilities for compute-intensive tasks such as game engines and physics simulations. It was created in collaboration with game industry partners to facilitate the reuse of existing C++ codebases, exemplified by the rapid porting of large projects like 3 to the web using tools like . By providing a standardized, portable target, asm.js sought to make the web a viable platform for . Key benefits of asm.js include predictable runtime performance due to its typed, low-level constructs that allow just-in-time (JIT) engines to generate efficient , as well as straightforward validation to confirm adherence to the subset's rules via a simple directive. This validation enables browsers to apply specialized optimizations, establishing asm.js as a for ahead-of-time (AOT) techniques that further enhance speed and portability across environments.

Development Timeline

asm.js was initially developed in late 2012 and early 2013 by Alon Zakai at , as an extension of the project, which Zakai had founded in 2010 to compile and code to for web execution. The technology aimed to create a highly optimizable subset of JavaScript to bridge the performance gap between native code and browser-based applications. Key contributors from the Mozilla team, including and Luke Wagner, collaborated on defining the subset's specifications and integration with the JavaScript engine. The first public mentions of asm.js emerged in February 2013, with presentations and discussions highlighting its potential for near-native performance in web environments. On , 2013, announced the integration of OdinMonkey, an asm.js optimization module, into Nightly builds, marking the initial browser implementation. This was followed by a major presentation by Alon Zakai at the conference in October 2013, where he demonstrated real-world applications and outlined the technology's design principles. Firefox 22, released on June 25, 2013, brought asm.js optimizations to stable users, enabling significant speedups for compiled codebases like games and simulations. The asm.js specification was published as a working draft on August 18, 2014. In 2013, expressed interest in supporting asm.js optimizations in its for , initiating cross-browser efforts to standardize performance enhancements. Collaborations between , , and accelerated adoption, with announcing plans for asm.js support in (then Spartan) in May 2015. By late 2015, major browsers including , , and provided validation and optimized execution for asm.js, achieving broad compatibility without plugins. Early development emphasized performance gains through and type predictions, with subsequent refinements focusing on improved developer tooling and integration with existing ecosystems. As of 2025, asm.js receives minimal updates, with development efforts shifting toward its successor, , which builds on similar principles for even greater efficiency and portability.

Language Design

Subset Restrictions

Asm.js imposes strict syntactic and semantic restrictions on to form a verifiable, low-level amenable to aggressive optimization. These constraints eliminate dynamic features that could hinder static or introduce non-determinism, ensuring that asm.js code behaves predictably like a . Core prohibitions include the use of , with statements, the keyword, and any form of dynamic , as these would prevent reliable ahead-of-time validation and optimization. Additionally, all functions must declare explicit type signatures through annotations, such as x|0 for signed 32-bit integers or +x for doubles, enforcing a discipline where every and parameter is statically typed at the boundaries of the . The of asm.js is deliberately limited to support efficient, machine-like operations without the overhead of JavaScript's dynamic typing. It mandates the use of typed arrays, such as Int32Array or Float64Array, for all memory access, providing a contiguous, fixed-size buffer that simulates a linear . operations are confined to bitwise shifts, (e.g., +, -, * via Math.imul for ), and comparisons, while floating-point math uses standard operators or fround for single-precision coercion, explicitly avoiding object creation, prototypes, or any higher-level abstractions that could invoke garbage collection. Value types are categorized into primitives like int (signed 32-bit), unsigned (unsigned 32-bit), double (64-bit float), and float (32-bit float), with coercions ensuring ; for instance, non-integer values are treated as doubles by default unless coerced. The memory model centers on a single, linear heap allocated via an ArrayBuffer passed as an to the , with no support for collection, dynamic allocation beyond the buffer's fixed bounds, or multiple heaps. Access to this heap occurs through typed array views like HEAP32 or HEAPF64, where pointers are represented as integers and indexing uses byte offsets adjusted by shifts (e.g., HEAP32[p >> 2] for 32-bit access at pointer p). This design mimics native memory layout, enabling direct manipulation without JavaScript's object overhead. Control flow in asm.js is restricted to deterministic, structured constructs to facilitate linear optimization passes. Permitted elements include straight-line code, conditional statements (if, switch), and loops (while, do-while, for), along with break and continue for loop control, but exclude exceptions (try, catch, throw), asynchronous operations, or any non-local jumps that could complicate analysis. These limitations ensure that execution paths are predictable and verifiable. A valid asm.js module begins with the "use asm" directive, which signals the JavaScript engine to validate the code against these subset rules. Imports are provided via three arguments to the module function: stdlib for host-provided globals like Math, foreign for external JavaScript functions, and heap as the ArrayBuffer. Exports occur through a returned object containing the module's functions. The following example illustrates a minimal compliant module that adds two integers:
javascript
function MyModule(stdlib, foreign, heap) {
  "use asm";
  function add(x, y) {
    x = x | 0;
    y = y | 0;
    return (x + y) | 0;
  }
  return { add: add };
}
This structure, when validated, allows the engine to treat the code as a typed, optimizable target.

Validation Mechanism

The validation of asm.js code occurs as a static analysis pass performed by the parser at parse time, ensuring adherence to the asm.js restrictions prior to execution and enabling ahead-of-time (AOT) for optimized . This process begins with the mandatory "use asm" directive in the module , which signals the engine to apply the asm.js and verify the code's compliance. The validation algorithm employs a single-pass that traverses the structure, types, and operations in a top-down manner, maintaining global (Δ) and local (Γ) environments to track type information. It proceeds through stages such as ValidateModule for overall structure (including parameters like stdlib, foreign, and [heap](/page/Heap), declarations, and exports), ValidateFunction for individual functions with their annotations, and ValidateExpression for ensuring operations like integer coercions (e.g., |0) and heap accesses conform to strict rules. Non-compliant code triggers immediate failure, preventing AOT optimization and reporting errors for correction. Built-in validators are integrated into JavaScript engines supporting asm.js, such as Firefox's parser, which implements an that performs this validation during . Standalone tools include reference validators like the Mozilla-hosted JavaScript-based checker, while toolchains such as incorporate validation during code generation to ensure output meets the spec, though explicit standalone validation in relies on engine integration or external checkers. Error handling focuses on precise diagnostics for violations, including type mismatches (e.g., using a where is required), invalid operations (e.g., unsupported bitwise shifts), or heap configuration issues (e.g., improper array buffer sizing). Upon failure, the engine reports these to developer consoles or tools, falling back to standard JavaScript interpretation or just-in-time () compilation on the "slow" path, while validated code executes on the optimized "fast" path. The validation process introduces negligible overhead, as it is confined to parse time, but critically unlocks AOT optimizations like specialized generation, resulting in near-native execution speeds without collection interruptions.

Code Generation

Compilation from C/C++

serves as the primary toolchain for compiling C/C++ code to compatible with asm.js, leveraging the infrastructure to bridge native code with web environments. Developed by Alon Zakai at , it enables porting existing C/C++ applications by translating them into a subset of that browsers can optimize as near-native . The compilation process begins with parsing C/C++ source code using Clang, the LLVM C/C++ frontend, which generates LLVM Intermediate Representation (IR) or bitcode. Emscripten then processes this IR through several phases: an intertyper converts it to an internal representation, an analyzer gathers data for optimizations, and a jsifier emits the final JavaScript code. Optimizations such as the relooper—which reconstructs high-level control structures like loops from low-level LLVM branches—and expression simplification are applied to improve performance and reduce code size. The output is a JavaScript module wrapped in a validating shell, including typed arrays for memory management and imports for host functions like Math or foreign APIs. Key C/C++ features are mapped to asm.js constructs for compatibility. Memory is handled via a single, flat represented by typed arrays (e.g., HEAP8 for bytes, HEAPF32 for floats), with pointers as offsets into this array to mimic C's contiguous addressing. Structs and data types are laid out sequentially in the , accessed via byte offsets calculated at , without direct object support to adhere to asm.js restrictions. Functions are compiled to named functions within the asm module, with dynamic calls routed through a FUNCTION_TABLE array for indirect invocation. Standard libraries like libc are partially emulated, but the Template Library (STL) requires polyfills or manual implementations due to asm.js's lack of dynamic allocation and generics support. Pointers demand explicit management by developers, as automatic garbage collection is absent. A simple example illustrates the process: compiling a C program that adds two integers, such as int add(int a, int b) { return a + b; } with a main function calling it. Using the Emscripten compiler frontend (emcc), the command emcc add.c -o add.js -sWASM=0 (disabling WebAssembly) produces a JavaScript file. In earlier versions of Emscripten (pre-2019), this output included the "use asm"; directive for asm.js optimization; as of 2025, it generates general JavaScript as a fallback for legacy environments. The module includes a runtime wrapper with imports, such as var asm = Module['asm']({}, ...);, allowing instantiation in a browser or Node.js. Limitations in this compilation approach stem from asm.js constraints and JavaScript's . Multithreading is unsupported due to the absence of in browsers at the time, requiring sequential execution or Web Workers for parallelism without direct heap access. SIMD instructions are not natively available, limiting vectorized computations to scalar emulations via ports. These gaps necessitate workarounds, such as custom bindings for complex libraries, to ensure portability.

Toolchain Integration

Asm.js integration extends beyond C/C++ compilation to support several other programming languages through compatible toolchains, primarily leveraging as the intermediary. For , developers can target asm.js using the asmjs-unknown-emscripten target in the compiler, which invokes to generate optimized output. Early interoperability for relied on manual foreign function interfaces (FFIs) or 's embedding mechanisms, serving as precursors to modern tools like wasm-bindgen. support is facilitated by projects such as PyPy.js, which compiles code to via , enabling execution of interpreters in the browser while adhering to asm.js restrictions. For , GHCJS adaptations compile source to that can be structured to fit the asm.js subset, allowing high-performance web deployment through 's pipeline. In game development frameworks, asm.js plays a key role in cross-platform exports. Unity's IL2CPP scripting backend integrates with to convert C# and managed code into for WebGL builds, enabling one-click web exports of complex 3D applications during the asm.js era. Similarly, supports targeting via , compiling over a million lines of C++ code into asm.js modules for browser-based rendering and interaction. The typical workflow involves pre-compiling source code to standalone JavaScript modules using , followed by embedding these modules into pages via a generated JavaScript shell that handles loading and instantiation. is enhanced through source maps, generated with flags like -g or --source-map, which map the optimized JavaScript output back to original source lines for browser developer tools. Emscripten provides the -sWASM=0 flag for legacy JavaScript output, which disables WebAssembly generation and produces general JavaScript using the upstream backend; as of 2025, this serves as a fallback for environments without WebAssembly support, though direct asm.js output is no longer guaranteed due to toolchain evolution. Handling FFIs and JavaScript interop is managed through tools like Embind, which automatically generates bindings for passing data types between C++ and JavaScript, ensuring seamless calls across the boundary while respecting asm.js type constraints. By 2025, most toolchains have migrated primary support to , positioning asm.js primarily as a fallback for legacy browsers through mechanisms like Emscripten's JS output or wasm2js polyfills.

Performance Features

Optimization Strategies

Browsers accelerate asm.js execution by validating modules at load time and applying specialized compilation paths that treat the code as a low-level, statically typed subset of , enabling optimizations not feasible for general . Upon encountering the "use asm" directive, the engine performs interprocedural validation to confirm adherence to asm.js restrictions, such as strict type coercions and heap access patterns; successful validation triggers ahead-of-time (AOT) or just-in-time () compilation directly to native , bypassing the interpreter and dynamic type checks. In Firefox's engine, the OdinMonkey subsystem integrates with the optimizing compiler to handle asm.js modules via AOT . Validation allows to assume typed operations—such as 32-bit integers and floats—enabling aggressive optimizations like inlining of small functions and in hot code paths, which reduce overhead from . This trap-based approach inserts minimal runtime checks only for exceptional cases (e.g., invalid accesses), while eliding most bounds and type validations based on the static guarantees provided by the asm.js structure. Parallel and asynchronous further mitigate startup latency, compiling code off the main thread using multiple cores. Google Chrome's employs similar validation-triggered optimizations for asm.js, routing validated modules through its compiler for enhanced code generation. This path leverages asm.js's predictable structure to apply type-specialized and optimizations akin to those for native-like code, including efficient handling of typed array operations. Microsoft's engine in follows a comparable strategy, generating type-specialized with native types (e.g., , , SIMD values) post-validation, which supports SIMD-like operations via typed arrays without boxing overhead. Asm.js's memory model relies on a single, growable ArrayBuffer for the , enabling direct, access that browsers optimize by eliding bounds checks after validation confirms safe access patterns. This allows memory loads and stores to compile to single machine instructions (e.g., on x64), avoiding the indirection typical in JavaScript's dynamic arrays. External interactions use numeric handles rather than garbage-collected objects, further reducing allocation overhead. These strategies introduce a "fast" path for validated asm.js code, achieving near-native performance by eliminating dynamic typing costs, but fallback to the slower general interpreter occurs if validation fails or the code deviates from asm.js invariants, ensuring compatibility without compromising security. The approach trades initial validation overhead for runtime efficiency, with no garbage collection involvement in the core .

Benchmark Results

Early benchmarks, such as those in the Octane 2.0 suite released by in 2013, demonstrated asm.js achieving approximately 2x speedups over vanilla implementations for compute-intensive tasks like zlib compression, with leading the optimizations. By 2014-2015, the JetStream benchmark suite, which incorporated multiple asm.js workloads, showed consistent performance gains across browsers, with asm.js scoring up to 2x faster than standard in numerical simulations and data processing tests. In comparisons to native C++ code compiled with , asm.js reached 50-80% of native speeds for compute tasks in 2013 benchmarks like the suite, improving to about 67% (1.5x slower) by late 2013 through float32 arithmetic optimizations in . For instance, the physics engine demo, compiled via , achieved 60 frames per second in browsers supporting asm.js optimizations as early as 2013, approaching native desktop performance for real-time simulations. Relative to Google's deprecated Native Client (NaCl), asm.js offered superior cross-browser compatibility and comparable or better execution speeds in shared benchmarks by 2014, avoiding NaCl's platform-specific binaries and overhead. Against plain , asm.js provided 10-50x speedups in tight numerical loops and operations, as seen in partial sums and spectral norm tests where standard JS lagged significantly due to dynamic typing. These gains were consistent across and by 2014, with both engines implementing ahead-of-time (AOT) compilation for asm.js modules. Asm.js excelled in numerical and CPU-bound workloads, such as floating-point heavy simulations in the Massive benchmark (2014), where and codebases ran with low variability and high throughput. However, benefits were lesser in I/O-bound tasks, where JavaScript's event-driven model dominated regardless of asm.js restrictions. A 2019 study found to be 1.3–1.5× faster than asm.js (23–50% faster) in benchmarks such as SPEC CPU2006 and CPU2017, due to its denser binary encoding and improved baseline optimizations, though asm.js remains viable for legacy numerical code.
Benchmark SuiteYearAsm.js vs. Vanilla JS SpeedupAsm.js vs. Native C Speed
2.02013~2x50-70%
JetStream2014-2015~2x (numerical tasks)60-80%
Emscripten ()201310-50x (loops)~60 FPS (near-native)

Implementations

Browser Support

Support for asm.js began with Mozilla Firefox, which introduced full optimizations in version 22, released on June 25, 2013. Google added performance optimizations enhancing execution speed by over twofold starting in version 28 in March 2014. Microsoft Edge implemented partial support in 2015, with an initial preview announced in May and default enabling in the stable release later that year. Apple Safari has no dedicated support for asm.js as of 2025, executing it as standard JavaScript without optimizations due to engine constraints. As of November 2025, major browsers universally execute code as standard , but dedicated optimizations have been deprecated across engines in favor of , rendering asm.js obsolete for new development. Compatibility extends to , where asm.js executes via regular interpretation or toolchains, though full optimizations require specific plugins or builds since native support is absent. Mobile browser support lags behind desktop, particularly for ; and on provide partial validation and execution from their respective versions, while on offers no support. To detect asm.js capability, applications often use JavaScript checks like parsing the navigator.appVersion for browser version details or employing try-catch blocks to attempt module validation on a minimal asm.js snippet. Notable gaps include the absence of official support in versions before 11 and Safari's lack of implementation stemming from JavaScriptCore engine differences.

Engine-Specific Details

Firefox's engine, powered by the IonMonkey optimizing compiler, pioneered full ahead-of-time (AOT) compilation for asm.js modules as part of the OdinMonkey project. This approach bypasses the dynamic-language just-in-time () infrastructure by generating mid-level (MIR) directly from the asm.js , enabling predictable near-native performance. If asm.js type checks fail during validation, the engine transparently falls back to standard baseline compilation for the module. Additionally, supports large asm.js heaps up to 4 GB on 64-bit systems, consistent with JavaScript's typed array limits. In Google's , used in , asm.js validation is followed by aggressive optimizations in the TurboFan compiler, which was explicitly designed to handle asm.js-like low-level code efficiently by producing high-quality from a sea-of-nodes . Prior to its in 2017, V8 supported hybrid workflows integrating asm.js with Portable Native Client (PNaCl), allowing developers to mix portable native code with subsets for enhanced performance in applications. Microsoft Edge's legacy Chakra engine implemented asm.js support through a dedicated and type-specialized generation, incorporating handlers for errors like out-of-bounds accesses to ensure safe execution. This implementation emphasized integration with Windows ecosystem features, such as deployment in HTML-based (UWP) apps via EdgeHTML rendering. Apple's JavaScriptCore engine in lacks dedicated asm.js support, executing it via standard interpretation without optimizations or special validation, resulting in performance equivalent to vanilla JavaScript. Despite this, asm.js has been employed in WebKit environments for resource-constrained scenarios, including Web-based games compiled via tools like , where it provides no incremental benefits over unoptimized code. As of 2025, all major browser engines—, V8, (pre-Chromium ), and JavaScriptCore—prioritize for high-performance compilation targets, relegating asm.js to a compatibility polyfill in legacy toolchains such as 1.x versions.

Adoption

Language Bindings

Asm.js primarily facilitated bindings for low-level languages like and C++, where served as the dominant toolchain for compiling source code to the asm.js subset of . leveraged to generate asm.js modules from C/C++ code, enabling seamless integration with through mechanisms like Embind and WebIDL Binder, which automatically generate bindings for C++ classes, functions, and structures. Notable ports included , a lightweight SQL database engine, and Bullet Physics, a real-time library, demonstrating asm.js's capability to run complex C/C++ libraries in browsers with near-native performance. For , early support came via the asmjs-unknown-emscripten target in the Rust compiler, which used to output asm.js code suitable for web deployment. This allowed Rust code to be compiled into asm.js modules, with initial versions of wasm-bindgen providing bindings to interact with by generating glue code for function calls and data passing. However, as matured, support for the asm.js target was deprioritized and ultimately removed in 2025, with wasm-bindgen dropping explicit asm.js compatibility in favor of wasm32-unknown-emscripten. Other languages saw experimental adaptations for asm.js output. For , tools like Transcrypt compiled Python 3 code to efficient that could leverage asm.js optimizations in supporting engines, while Brython provided a implementation allowing Python scripts to execute in browsers with potential for asm.js acceleration through its backend. For Go, GopherJS transpiled Go code to readable , with discussions around enhancing its output for asm.js compatibility to improve performance in computation-heavy scenarios. Assembly-like programming was enabled via LLJS (Low-Level ), a structured language that compiled directly to asm.js, offering a higher-level syntax for writing optimized modules while adhering to asm.js's strict typing and validation rules. The bindings process in asm.js relied on exposing functions through imports and exports at the module boundary. Imported functions from (via a foreign object) or the (via stdlib) were declared with fixed signatures, such as (int, double) → void, allowing type validation at load time. Exports returned an object containing callable functions, enabling to invoke asm.js code directly, as in var module = asm(stdlib, foreign, [heap](/page/Heap)); var result = module.myFunction(arg1, arg2);. Data marshaling between and asm.js modules used typed arrays to represent the , typically a single ArrayBuffer viewed as Uint8Array or similar, with offsets used for pointer passing (e.g., HEAP32[ptr >> 2] = value;). This approach ensured efficient, data transfer but required manual alignment and bounds checking to avoid runtime errors. Challenges arose particularly with languages featuring garbage collection, such as ports, where asm.js's manual memory model clashed with automatic semantics. Ports required workarounds like implementing conservative mark-and-sweep collectors in JavaScript or restricting features to avoid pauses, leading to increased complexity and potential performance overhead compared to native environments. These limitations highlighted asm.js's suitability for systems languages over managed ones, paving the way for later extensions in .

Application Frameworks

Unity integrated asm.js into its WebGL build pipeline starting in 2014 through a partnership with , leveraging to compile C/C++ code for browser-based execution. This enabled developers to export Unity projects, including those using the IL2CPP scripting backend from around 2017 to 2018, directly to asm.js modules, facilitating the deployment of interactive 2D and 3D games without plugins. However, Unity removed asm.js support in 2019. Unreal Engine provided HTML5 export support via Emscripten, targeting asm.js for WebGL rendering from 3 in 2013 and extending to UE4 by 2015, allowing C++-based projects to run in browsers for demonstrations and prototypes. Support for asm.js was deprecated in UE4 around 2017. Frameworks like and NW.js supported the integration of asm.js modules compiled from , enabling hybrid desktop applications to offload compute-intensive operations to near-native performance in JavaScript environments. PlayCanvas, a WebGL-focused , incorporated asm.js for its physics simulations, utilizing ports like ammo.js—a Bullet physics library compiled via —to enhance real-time interactions in browser-based 3D applications. Certain plugins for mobile apps employed asm.js to bridge native device features with web views, allowing performance-critical computations in while accessing hardware capabilities. By 2025, most application frameworks had transitioned from asm.js to for superior efficiency and broader compatibility, with deprecating asm.js output in 2022. Legacy support persists only in very old versions of tools like (pre-2019) and (pre-2017).

Notable Software Examples

One prominent example of asm.js in gaming is the 2011 port of the classic Doom, developed by Alon Zakai using to compile the C++ codebase into highly optimized , achieving near-native performance in web browsers without plugins. Similarly, was ported via the QuakeJS project, which used to translate the ioquake3 engine—a derivative of the original III codebase—into asm.js, enabling full gameplay directly in browsers at playable frame rates. , a popular , integrated asm.js support through starting with Unity 5 in 2015, allowing developers to export complex titles to the web; this facilitated browser-based versions of games like , where intricate illusions and physics were rendered efficiently without native installations. In emulation, asm.js enabled faithful recreations of legacy hardware. EM-DOSBox, an Emscripten-compiled port of the DOSBox x86 emulator, brought MS-DOS applications and games to modern browsers by executing 8086 assembly code at speeds approaching the original hardware, supporting titles like early PC adventures. The physics library Box2D saw an asm.js port via Emscripten, providing 2D rigid body simulations for browser games with performance rivaling native C++ implementations, as demonstrated in benchmarks showing up to 5x speedup over standard JavaScript ports. For console emulation, projects like em-fceux—a port of the FCEUX NES/Famicom emulator—used Emscripten to compile C++ emulation logic to asm.js, allowing cycle-accurate rendering of 8-bit games such as Super Mario Bros. in real-time within HTML5 canvases. Key libraries leveraged asm.js for compute-intensive tasks. FFmpeg.js, an Emscripten port of the FFmpeg multimedia framework, processed video encoding, decoding, and streaming in browsers, enabling client-side format conversions like MP4 to without server dependencies, with asm.js optimizations reducing memory usage for in-browser playback. For professional software, developed web viewer prototypes for using to compile core rendering and modeling code to asm.js, allowing lightweight DWG file viewing and basic editing in browsers as an early step toward full web deployment. In and scientific computing, ports of and BLAS to asm.js via provided browser-accessible linear algebra routines. The emlapack library compiled these Fortran-derived solvers to asm.js, supporting operations like matrix decompositions and eigenvalue computations for web-based , with outputs including dedicated asmjs.js modules for optimized execution. These examples illustrate asm.js's role in enabling plugin-free, high-performance web applications, particularly before 's standardization; by 2025, many such projects, including Figma's design tool—which initially relied on asm.js for compiling its C++ rendering engine—had migrated to , as seen in Figma's 2017 transition that reduced load times by 3x while maintaining compatibility.

Transition and Deprecation

Relation to WebAssembly

asm.js served as a key precursor to , informing its design principles for a binary format, validation mechanisms, and ahead-of-time (AOT) compilation support. The experiences gained from implementing and optimizing asm.js in browsers demonstrated the viability of a portable, safe for high-performance code, which directly influenced 's development as a more efficient evolution. In June 2015, , along with , , and Apple, proposed as a binary instruction format initially co-expressive with asm.js, aiming to standardize a common target for compiling languages like and to the web. This proposal built on asm.js's proof-of-concept status, addressing its limitations such as text-based parsing overhead, particularly on resource-constrained devices. A clear migration path exists from asm.js to , facilitated by tools like , which by default compiles to but supports asm.js output for compatibility. initially converted its asm.js output to using the Binaryen toolkit's asm2wasm tool, enabling a seamless transition within the shared compilation pipeline. This shared toolchain, including Binaryen for optimization and transformation, allowed developers to leverage existing asm.js workflows while adopting 's binary format. WebAssembly differs from asm.js in several fundamental ways: it uses a compact format rather than a text-based subset of , enabling faster loading and decoding—often over 20 times quicker than asm.js. Unlike asm.js, which remains constrained by semantics and lacks native support for features like threads and SIMD, is designed as an independent instruction set, natively incorporating multithreading (via Web Workers) and SIMD instructions for better parallelism and vectorized computations. Additionally, 's formal validation and AOT compilation provide more predictable performance across browsers, free from asm.js's reliance on just-in-time () optimization of subsets. The adoption of marked a shift from asm.js, with the (MVP) reaching consensus in March 2017 and shipping in major browsers later that year, establishing it as the preferred format for high-performance web code. Standardized by the W3C as a Recommendation in December 2019, became the official successor, while asm.js continued as a fallback mechanism through polyfills that convert modules to asm.js for unsupported environments. Post-2017, browser engines prioritized optimizations, reducing reliance on asm.js except in legacy scenarios.

Current Status

As of 2025, asm.js is widely regarded as a deprecated technology, with major browser documentation and support tables labeling it obsolete in favor of . The Mozilla Developer Network (MDN) explicitly states that the asm.js specification is deprecated, advising developers to adopt for running high-performance code in browsers. Similarly, CanIUse marks asm.js as obsolete, noting its partial support across browsers but emphasizing its supersession by more efficient alternatives. This deprecation aligns with browser vendor decisions between 2017 and 2020 to phase out specialized optimizations, as asm.js received no substantive updates or new features after its core specification in 2013. Despite its deprecation, asm.js lingers in legacy contexts, particularly within older builds and archived projects where it was used to compile C/C++ code to . It occasionally serves as a fallback mechanism for environments lacking support, though such scenarios are exceedingly rare in 2025 due to near-universal Wasm compatibility across modern browsers. , the primary toolchain for asm.js, discontinued active asm.js support with the removal of the fastcomp backend in version 2.0.0 (August 2020), redirecting focus to while preserving legacy compatibility for historical compilations. Community engagement with asm.js has dwindled to minimal levels, with maintenance efforts largely abandoned in favor of WebAssembly advancements and education. Developer discussions and repositories, such as those on , now treat asm.js primarily as a teaching tool for understanding WebAssembly's origins, with occasional references in academic or demonstrative contexts. For instance, historical research ports like the jor1k project, which compiled the OR1K to asm.js for browser execution in 2013, persist as archived demos highlighting early web-based system emulation. A revival of asm.js appears improbable, cementing its role as a pivotal but outdated milestone in the progression of technologies from subsets to binary formats like .

References

  1. [1]
    asm.js
    asm.js. an extraordinarily optimizable, low-level subset of JavaScript. specification (work in progress) frequently asked questions · big web app? compile it ...
  2. [2]
    asm.js - Game development | MDN
    ### Summary of asm.js from MDN
  3. [3]
    asm.js: closing the gap between JavaScript and native - 2ality
    Feb 16, 2013 · asm.js defines a subset of JavaScript that can be compiled to fast executables. It has been created at Mozilla by David Herman, Luke Wagner and Alon Zakai.
  4. [4]
    Asm.js: The JavaScript Compile Target - John Resig
    Apr 3, 2013 · Asm.js is a subset of JavaScript that is heavily restricted in what it can do and how it can operate. This is done so that the compiled Asm.js code can run as ...<|control11|><|separator|>
  5. [5]
    What asm.js is and what asm.js isn't - azakai's blog
    Jun 20, 2013 · This is going to be a bit long, so tl;dr asm.js is a formalization of a pattern of JavaScript that has been developing in a natural way over ...
  6. [6]
    asm.js
    Aug 18, 2014 · This specification defines asm.js, a strict subset of JavaScript that can be used as a low-level, efficient target language for compilers.
  7. [7]
    Why WebAssembly is Faster Than asm.js - the Web developer blog
    Mar 15, 2017 · About Alon Zakai ... Alon is on the research team at Mozilla, where he works primarily on Emscripten, a compiler from C and C++ to JavaScript.
  8. [8]
    MASSIVE - the asm.js benchmark
    The Massive benchmark includes several very large codebases (Poppler, SQLite, etc.), and measures throughput as well as responsiveness, variability and startup ...
  9. [9]
    From ASM.JS to WebAssembly - Brendan Eich
    Jun 17, 2015 · ... Alon Zakai of asm.js & Emscripten fame; Filip Pizlo for JavaScriptCore/WebKit; and especially asm.js/OdinMonkey mastermind Luke Wagner. The ...
  10. [10]
    asm.js: it's really fast, backwards compatible, and now in the release ...
    Jun 25, 2013 · One of its key features is a new set of optimizations for asm.js, a highly optimizable subset of JavaScript. asm.js was developed by Mozilla ...
  11. [11]
    asm.js in Firefox Nightly | Luke Wagner's Blog
    Mar 21, 2013 · OdinMonkey, an asm.js optimization module for Firefox's JavaScript engine, is now in Nightly builds and will ship with Firefox 22 in June.
  12. [12]
    Asm.js: a strict subset of js for compilers – working draft | Hacker News
    Feb 15, 2013 · Alon Zakai is presenting some of the ideas at http://mloc-js.com tomorrow, including an overview of the ideas and some preliminary ...
  13. [13]
    "Native Speed on the Web: JavaScript and asm.js" by Alon Zakai ...
    Feb 26, 2021 · ... Alon founded the Emscripten open source project which utilizes LLVM to compile C and C++ to JavaScript, with the goal of allowing existing ...Missing: Bringing ++:
  14. [14]
    Google shows interest in ASM.js, Mozilla's plan for fast Web apps
    Mar 28, 2013 · Yesterday, Mozilla held a coming-out party for ASM.js, announcing a cooperation with Epic to bring its Unreal game engine to ASM.js. The same ...
  15. [15]
    Bringing Asm.js to Chakra and Microsoft Edge - Windows Blog
    May 7, 2015 · We are now previewing the early work that we've been doing to enable Asm.js support in Chakra and Microsoft Edge.
  16. [16]
    asm.js Speedups Everywhere - the Web developer blog
    Mar 3, 2015 · asm. js is an easy-to-optimize subset of JavaScript. It runs in all browsers without plugins, and is a good target for porting C/C++ codebases ...Missing: goals | Show results with:goals
  17. [17]
    A reference validator for asm.js. - GitHub
    This repo hosts JS source code which performs asm.js validation, however as of this update, this code is not up to date with the latest working draft and is not ...Missing: mechanism | Show results with:mechanism
  18. [18]
    frequently asked questions - asm.js
    The directive prologue identifies the developer's intention that code should be considered valid asm.js. If the code fails to validate, the engine can report ...
  19. [19]
    Emscripten: an LLVM-to-JavaScript compiler - ACM Digital Library
    We present Emscripten, a compiler from LLVM (Low Level Virtual Machine) assembly to JavaScript. This opens up two avenues for running code written in languages ...
  20. [20]
    [PDF] EMSCRIPTEN - COMPILING LLVM BITCODE TO JAVASCRIPT (?!)
    Loads in LLVM IR become reads from typed array in JS, which become reads in machine code. Emscripten's memory model is identical to LLVM's. (flat Clike ...
  21. [21]
    [PDF] Emscripten: An LLVM-to-JavaScript Compiler - GitHub
    Apr 6, 2011 · We present Emscripten, an LLVM-to-JavaScript compiler. Emscripten compiles LLVM assembly code into standard. JavaScript, which opens up two ...
  22. [22]
    Emscripten Tutorial — Emscripten 4.0.19-git (dev) documentation
    Emscripten is accessed via emcc, which compiles C/C++ to JavaScript. This tutorial shows how to compile examples from the command line.
  23. [23]
    Compiling to the web with Rust and emscripten
    Oct 12, 2016 · Rust can now target asm.js and WebAssembly (wasm) via emscripten. That means you can run Rust code on the web, and this capability is available on Rust ...
  24. [24]
    Upgrading Rust's Emscripten Support - compiler
    Aug 9, 2019 · To get the JS output, you can instead use the emscripten target normally and add -s WASM=0 to the link-time flags. Alternatively, if the ...
  25. [25]
    PyPy.js: First Steps
    Jul 23, 2013 · It is fully supported and fully expected, given the dynamic nature of JavaScript. However, code running in asm.js mode is forbidden from ...
  26. [26]
    ghcjs/ghcjs: Haskell to JavaScript compiler, based on GHC - GitHub
    GHCJS contains a library, ghcjs, which contains the JavaScript code generator and a slightly customized variant of the ghc library, and several executable ...Missing: asm. | Show results with:asm.
  27. [27]
    Unity 5 Ships and Brings One Click WebGL Export to Legions of ...
    Mar 3, 2015 · Unity's new approach to Web delivery is made possible by using a combination of IL2CPP and a cross-compiler named Emscripten to port its content ...
  28. [28]
    Unreal in Javascript - over a million C++ lines compiled with asm.js
    May 8, 2013 · With Emscripten, the web is just another platform to target. It can be targetted alongside other platforms, with the additional development ...Microsoft announces asm.js optimizations : r/programming - RedditELI5 asm.js, WebAssembly and why it matters (or not) - RedditMore results from www.reddit.com
  29. [29]
    Deploying Emscripten Compiled Pages
    Emscripten compiled output can either be run directly in a JS shell from command line, or hosted on a web page. When hosting asm.js and WebAssembly compiled ...
  30. [30]
    Building to WebAssembly — Emscripten 4.0.19-git (dev) documentation
    ### Summary of asm.js Validation or Tools in Emscripten
  31. [31]
    Connecting C++ and JavaScript — Emscripten 4.0.19-git (dev) documentation
    ### Summary of Emscripten C++ and JavaScript Interop
  32. [32]
    Compile to ASM.js · Issue #18013 · emscripten-core ... - GitHub
    Oct 7, 2022 · Is it still possible to compile to ASM.js and if so what options do i need to use? I have tried to use WASM=0 but asm.js isnt outputted.
  33. [33]
    asm.js AOT compilation and startup performance | Luke Wagner's Blog
    Jan 14, 2014 · In this blog post I'll explain the compilation strategy we use for asm.js, why we decided to try this strategy, how it's been working, and 3 optimizations.
  34. [34]
  35. [35]
    Asm.js: A Low Level, Highly Optimizable Subset of JavaScript for ...
    Asm.js: A Low Level, Highly Optimizable Subset of JavaScript for Compilers (badassjs.com) ... Mozilla is perfectly free to implement the ...
  36. [36]
    Staring at the Sun: Dalvik vs. ASM.js vs. Native - The Mozilla Blog
    Aug 1, 2013 · Don't forget that we are talking about ASM.js and the purpose of ASM is to create heavily optimized JS code on its output. You as a ...
  37. [37]
    asm.js performance improvements in the latest version of Firefox ...
    May 5, 2014 · The latest version of Firefox which launched last week includes a major update to the user interface as well as to features like Sync.
  38. [38]
    When asm.js is faster than normal JS code, why should I write new ...
    May 13, 2013 · asm.js is not a faster way to execute Javascript-esque code. It is a faster way to run code which is already reduced to the level of ...Huge performance lack in emscripten code - Stack OverflowEmscripten seems to not use asm.js - Stack OverflowMore results from stackoverflow.com
  39. [39]
    [PDF] Analyzing the Performance of WebAssembly vs. Native Code
    Jul 10, 2019 · Since asm.js is a subset of JavaScript, adding all native features to asm.js such as 64-bit integers will first require extending JavaScript.Missing: October | Show results with:October
  40. [40]
    Firefox 22 release notes for developers - Mozilla - MDN Web Docs
    Jun 25, 2013 · JavaScript. Asm.js optimizations are enabled, making it possible to compile C/C++ applications to a subset of JavaScript for better performance.Missing: integration | Show results with:integration
  41. [41]
    asm.js | Can I use... Support tables for HTML5, CSS3, etc - CanIUse
    An extraordinarily optimizable, low-level subset of JavaScript, intended to be a compile target from languages like C++.
  42. [42]
    How to test the availability of asm.js in a web browser?
    Jul 19, 2017 · I'd like to test and see if the browser supports asm.js or not. If it is false , display a message indicating that the browser is old or something like that.What is the difference between asm.js and WebAssembly?Why does asm.js deteriorate performance? - Stack OverflowMore results from stackoverflow.comMissing: timeline | Show results with:timeline
  43. [43]
    Embind — Emscripten 4.0.19-git (dev) documentation
    Embind is used to bind C++ functions and classes to JavaScript, so that the compiled code can be used in a natural way by “normal” JavaScript.Missing: asm. | Show results with:asm.
  44. [44]
    Fast C++ on the Web using Emscripten and asm.js
    Despite JavaScript's dynamic nature, modern JavaScript VMs are quite speedy, and even more so with asm.js as we saw in the demos before!
  45. [45]
    Compiling LLJS to asm.js - James Long
    Mar 25, 2013 · I'd like to announce that I have LLJS successfully compiling to asm.js, so we can tap into the amazing optimizations provided from it.
  46. [46]
    Compile Java to asm.js - Stack Overflow
    Aug 1, 2013 · It cannot currently handle languages with garbage collection semantics, silly as that may seem given that it is JavaScript which is a garbage ...Strange garbage collection behaviour leads to server performance ...Why doesn't JavaScript's garbage collector clean up global variables?More results from stackoverflow.com
  47. [47]
    Unity Partners With Mozilla To Port Its Popular Game Engine To The ...
    Mar 18, 2014 · Unity and Mozilla today announced that they are bringing the Unity game engine to the web using the WebGL standard and Mozilla's asm.js.Missing: history | Show results with:history
  48. [48]
    Mozilla-pioneered asm.js and WebGL achieve milestone as the ...
    Dec 7, 2015 · Our long-standing partner, Unity announced today that it is removing the preview label from its WebGL export functionality as of Unity 5.3.Missing: history | Show results with:history
  49. [49]
    Why was asm.js removed? - Unity Discussions
    May 21, 2019 · I am having a problem with webassembly and wanted to compile in asm.js. Where exactly do I add the code? PlayerSettings.WebGL.linkerTarget= ...Missing: deprecation | Show results with:deprecation
  50. [50]
    First 3D Commercial Web Game Powered By asm.js Unveiled
    Dec 12, 2013 · Earlier this year, Mozilla and Epic Games showcased Unreal Engine 3 running in Firefox and other Web browsers using asm.js, Emscripten, and ...
  51. [51]
    Unreal Engine 3 compiled to asm.js - PC Perspective
    May 7, 2013 · For Unreal Engine 3 compiled into Javascript we notice an almost 3-fold improvement in average framerate with asm.js and the few other tweaks.
  52. [52]
    Asm.js, WebGL, and game engine (UE4) - Platform & Builds
    Jul 8, 2015 · Emscripten is an LLVM based project that compiles C and C++ into highly performant JavaScript in the asm.js format. In short: near native ...Missing: target | Show results with:target
  53. [53]
    My experience with asm.js
    Jul 18, 2016 · Asm.js is annotated JavaScript. It's perfectly valid JavaScript code that runs in every browser without any special hacks. However, it annotates ...
  54. [54]
    Physics Basics - PlayCanvas Developer Site
    PlayCanvas incorporates a very powerful physics engine called ammo.js. This is a browser port of the open source C++ Bullet physics engine.
  55. [55]
    Plugin Development Guide - Apache Cordova
    A plugin is a package of injected code that allows the Cordova webview within which the app renders to communicate with the native platform on which it runs.
  56. [56]
    Web runtime updates are here: Take your browser to the next level
    Nov 30, 2023 · The Emscripten compiler brings your Unity il2cpp build to WebAssembly. With each new Long Term Support (LTS) release, we include the latest ...Missing: 2014-2018 | Show results with:2014-2018
  57. [57]
    Problems with Packaging in Unreal4 for HTML5 - Stack Overflow
    Sep 10, 2017 · Packaging UE4 for HTML5 will now use WebAssembly by default. ASM.js is being deprecated and support is being removed from UE4 as major ...
  58. [58]
    WAD Commander and wasm-doom - Source Ports - Doomworld
    Feb 21, 2019 · There was an original port of Doom to HTML5 using asm.js in 2011 by Alon Zakai, but that version was taken down and as I remember it was also ...
  59. [59]
    quakejs.com
    QuakeJS is a port of ioquake3 to JavaScript with the help of Emscripten. This project started to demonstrate the feasibility of browser-based gaming.
  60. [60]
    Emscripten port, for running in web browsers - DOSBox - VOGONS
    Jan 24, 2014 · I've been working on an Emscripten port of DOSBox. I started a branch from the SVN revision closest to 0.74.Missing: Quake FFmpeg
  61. [61]
    kripken/box2d.js: Port of Box2D to JavaScript using Emscripten
    box2d.js is a direct port of the Box2D 2D physics engine to JavaScript, using Emscripten. The source code is translated directly to JavaScript, without human ...Missing: asm. 60fps 2013
  62. [62]
    fcambus/jsemu: A list of emulators written in the JavaScript ... - GitHub
    Emulators written in JavaScript · Acorn · Altair · Amstrad · Apple · Atari · Commodore · Data General · DEC.
  63. [63]
    Kagami/ffmpeg.js: Port of FFmpeg with Emscripten - GitHub
    This library provides FFmpeg builds ported to JavaScript using Emscripten project. Builds are optimized for in-browser use: minimal size for faster loading, asm ...
  64. [64]
    AutoCAD & WebAssembly: Moving a 30 Year Code Base to the Web
    Sep 26, 2018 · Kevin Cheung presents a practical guide to getting legacy code to work on the web using AutoCAD as the example with the Emscripten compiler and WebAssembly.Missing: asm. | Show results with:asm.
  65. [65]
    likr/emlapack: BLAS / LAPACK for JavaScript - GitHub
    After the script completes, you will see asmjs.js , emlapack.wasm , and wasm.js outputted to the root of the project directory. References. For more detail ...
  66. [66]
    Figma is powered by WebAssembly | Figma Blog
    Jun 8, 2017 · The asm.js subset is basically JavaScript where you can only use numbers (no strings, objects, etc.). This is all you need to run C++ code ...Missing: AutoCAD Photoshop LAPACK
  67. [67]
    FAQ - WebAssembly
    In fact, by dropping all the coercions required by asm.js validation, the WebAssembly text format should be much more natural to read and write than asm.js.
  68. [68]
    Feature Status - WebAssembly
    In November 2017, WebAssembly CG members representing four browsers, Chrome, Edge, Firefox, and WebKit, reached consensus that the design of the initial (MVP) ...
  69. [69]
    World Wide Web Consortium (W3C) brings a new language to the ...
    Dec 5, 2019 · WebAssembly joins the many W3C standards that define an Open Web Platform for application development with unprecedented potential to enable ...
  70. [70]
    Linux Kernel Running In JavaScript Emulator With Graphics and ...
    Nov 12, 2013 · Linux Kernel Running In JavaScript Emulator With Graphics and Network Support ... Sebastian Macke's jor1k project uses asm.js to produce a very ...
  71. [71]
    The State of WebAssembly – 2024 and 2025 - Uno Platform
    Jan 27, 2025 · In this article, I'll start off with a review of what happened around WebAssembly in 2024 and then look at what I think might happen in 2025.Missing: asm. | Show results with:asm.
  72. [72]
    WebAssembly (WASM), WebAssembly Adoption Surges in 2025
    Jun 9, 2025 · In 2025, the adoption of WASM has surged, with major companies like Adobe, Figma, and Autodesk integrating it into their platforms to accelerate ...