<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:base="en">
	<title>Igalia Compilers Team</title>
	<subtitle>Blog of the Igalia Compilers Team.</subtitle>
	<link href="https://blogs.igalia.com/compilers/feed/feed.xml" rel="self"/>
	<link href="https://blogs.igalia.com/compilers/"/>
	<updated>2026-02-06T00:00:00Z</updated>
	<id>https://blogs.igalia.com/</id>
	<author>
		<name>compilers</name>
		<email></email>
	</author>
	
	<entry>
		<title>Igalia’s Compilers Team - A 2025 Retrospective</title>
		<link href="https://blogs.igalia.com/compilers/2026/02/06/igalia-s-compilers-team-a-2025-retrospective/"/>
		<updated>2026-02-06T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2026/02/06/igalia-s-compilers-team-a-2025-retrospective/</id>
		<content type="html">&lt;p&gt;Hey, hey, it’s the beginning of a new year and before we sprint too far into 2026, let’s take a quick breather, zoom out, and celebrate what Igalia’s awesome compilers team got up to in 2025.
Over the past year we’ve been deeply involved in shaping &lt;em&gt;and&lt;/em&gt; shipping key Web and JavaScript standards, which includes not just participating in committees but also chairing and actively moving the proposals forward.
We worked on major JavaScript runtimes and foundational ahead-of-time compilers including LLVM and Mesa, as well as JIT CPU emulation, and smaller language VMs.&lt;/p&gt;
&lt;p&gt;Some big highlights of this year included our work on FEX and Mesa that helped Valve with their upcomimg gaming devices - the Steam Frame and the Steam Machine (we talk more about this in a dedicated &lt;a href=&quot;https://www.igalia.com/2025/11/helpingvalve.html&quot;&gt;blog post&lt;/a&gt;), our continued involvement in supporting RISC-V in contemporary compilers, and our key role in multiple WebAssembly implementations.&lt;/p&gt;
&lt;h2 id=&quot;standards&quot; tabindex=&quot;-1&quot;&gt;Standards &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/06/igalia-s-compilers-team-a-2025-retrospective/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In 2025, our standards work focused on parts of JavaScript developers touch every day like time, numbers, modules and more. Across TC39, WHATWG, WinterTC and internationalization ecosystems, we helped move proposals forward while turning specifications into running, interoperable code. So yep, let’s talk about our most significant standards contributions from the year!&lt;/p&gt;
&lt;h3 id=&quot;temporal&quot; tabindex=&quot;-1&quot;&gt;Temporal &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/06/igalia-s-compilers-team-a-2025-retrospective/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It’s been an exciting year for the &lt;a href=&quot;https://github.com/tc39/proposal-temporal/&quot;&gt;Temporal proposal&lt;/a&gt;, which adds a modern date-and-time API to JavaScript. For starters, MDN published their &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal&quot;&gt;API documentation for it&lt;/a&gt;, which created a huge surge of interest.&lt;/p&gt;
&lt;p&gt;On the shipping front: Firefox shipped their implementation of the proposal and it’s now available in Firefox 139. Chrome moved their implementation to beta in late 2025, and released it in early 2026. Meanwhile, we’ve been steadily working on getting Temporal into Safari, with support for correct duration math and the &lt;code&gt;PlainMonthDay&lt;/code&gt; and &lt;code&gt;PlainYearMonth&lt;/code&gt; types added during 2025/early 2026. You can read more about this in our recent &lt;a href=&quot;https://blogs.igalia.com/compilers/2026/02/02/implementing-the-temporal-proposal-in-javascriptcore/&quot;&gt;post on implementing Temporal&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Alongside that, we’ve been working on the &lt;a href=&quot;https://github.com/tc39/proposal-intl-era-monthcode/&quot;&gt;Intl Era and Month Code proposal&lt;/a&gt;, which has expanded in scope beyond era codes and month codes to cover other calendar-specific things that a JS engine with &lt;code&gt;Intl&lt;/code&gt; must implement. This allows developers to make use of a number of commonly-used non-Gregorian calendars, including but not limited to the calendar used in Thailand, the Japanese Imperial calendar, and Islamic calendars.&lt;/p&gt;
&lt;h3 id=&quot;decimal&quot; tabindex=&quot;-1&quot;&gt;Decimal &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/06/igalia-s-compilers-team-a-2025-retrospective/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A lot of our recent work around the &lt;a href=&quot;https://github.com/tc39/proposal-decimal&quot;&gt;Decimal&lt;/a&gt; proposal has now migrated to a newer similarly number-focused effort called &lt;a href=&quot;https://github.com/tc39/proposal-amount&quot;&gt;Amount&lt;/a&gt; (formerly known as &amp;quot;Measure&amp;quot; and officially renamed in 2025). The proposal reached Stage 1 at the November 2024 TC39 plenary. We also launched a &lt;a href=&quot;https://www.npmjs.com/package/proposal-amount&quot;&gt;polyfill&lt;/a&gt;.
Since then, we have iterated on the Amount API and data model a number of times in plenary. So while it started 2025 at &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;stage 1&lt;/a&gt; and remains at stage 1 heading into 2026, the design is noticeably sharper, thanks to a lot of TC39 discussions. We’re lined up to keep it pushing forward next year.&lt;/p&gt;
&lt;p&gt;And because numerics work benefits a ton from regular iteration, in late 2024, we also kicked off a biweekly community call (&amp;quot;JS Numerics&amp;quot;) for those in TC39 interested in proposals related to numbers, such as Decimal, Amount, &lt;a href=&quot;https://github.com/tc39/proposal-intl-keep-trailing-zeros&quot;&gt;intl-keep-trailing-zeros&lt;/a&gt;, etc. We still host it, and it’s turned out to be a genuinely productive place to hash things out without waiting for plenary.&lt;/p&gt;
&lt;h3 id=&quot;source-maps&quot; tabindex=&quot;-1&quot;&gt;Source Maps &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/06/igalia-s-compilers-team-a-2025-retrospective/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We implemented draft range mappings implementations on a number of systems: WebKit, &lt;a href=&quot;https://github.com/jridgewell/sourcemaps/tree/main/packages/sourcemap-codec&quot;&gt;Justin Ridgewell’s source map decoder&lt;/a&gt;, a source map validator, and more.&lt;/p&gt;
&lt;p&gt;We also facilitated source map TG4 meetings and assisted with advancing proposals such as the scopes proposal.
Throughout the year, we continued serving as editors for the ECMA-426 specification, landing a steady stream of improvements and clarifications.&lt;/p&gt;
&lt;h3 id=&quot;modules&quot; tabindex=&quot;-1&quot;&gt;Modules &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/06/igalia-s-compilers-team-a-2025-retrospective/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We pushed JavaScript’s module system forward on multiple fronts, especially around reducing the impact of modules on application startup:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;we advanced the &lt;a href=&quot;https://github.com/tc39/proposal-defer-import-eval&quot;&gt;&lt;code&gt;import defer&lt;/code&gt;&lt;/a&gt; proposal, which allows modules to be be synchronously lazily evaluated, to Stage 3 in TC39. We are working on its implementations in V8 and WebKit, and we implemented it in Babel, webpack (together with other community members) and TypeScript.&lt;/li&gt;
&lt;li&gt;we presented &lt;a href=&quot;https://github.com/tc39/proposal-deferred-reexports&quot;&gt;&lt;code&gt;export defer&lt;/code&gt;&lt;/a&gt; and pushed it to Stage 2 in TC39: it allows more granular lazy evaluation, as well as built-in browser support for tree-shaking of re-exports.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We are among the most active members of the &amp;quot;Modules Harmony&amp;quot; group, an unofficial group within TC39 that aims at improving the capabilities of ESM to improve native adoption, while making sure that all modules proposals are well-coordinated with each other.&lt;/p&gt;
&lt;h3 id=&quot;asynccontext&quot; tabindex=&quot;-1&quot;&gt;AsyncContext &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/06/igalia-s-compilers-team-a-2025-retrospective/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;And over in the &lt;a href=&quot;https://github.com/tc39/proposal-async-context&quot;&gt;AsyncContext proposal&lt;/a&gt; world, we spent 2025 focusing on how the proposal should integrate with various &lt;a href=&quot;https://github.com/tc39/proposal-async-context/blob/master/WEB-INTEGRATION.md&quot;&gt;web APIs&lt;/a&gt;. The way AsyncContext interacts with the web platform is unusually pervasive, and more challenging to figure out than the core TC39 proposal itself.&lt;/p&gt;
&lt;p&gt;In a first for a TC39 proposal, it is not also going through the &lt;a href=&quot;https://whatwg.org/stages&quot;&gt;WHATWG stages process&lt;/a&gt;, where it has reached Stage 1. This gives us a clearer path to iterate with direct feedback from browser engines.&lt;/p&gt;
&lt;h3 id=&quot;unicode-standards&quot; tabindex=&quot;-1&quot;&gt;Unicode standards &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/06/igalia-s-compilers-team-a-2025-retrospective/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We have been working on &lt;a href=&quot;https://messageformat.unicode.org/&quot;&gt;Unicode MessageFormat&lt;/a&gt;, which is a Unicode standard for localizable dynamic message strings, designed to make it simple to create natural sounding localized messages.&lt;/p&gt;
&lt;p&gt;In 2025, we helped the &lt;a href=&quot;https://icu.unicode.org/&quot;&gt;ICU4C&lt;/a&gt; implementation of Unicode MessageFormat align with ongoing specification changes. We also carried out &lt;a href=&quot;https://github.com/unicode-org/icu/pull/3536&quot;&gt;experimental work&lt;/a&gt; on the custom function interface to support more extensible formatting formatting capabilities, which is currently under review.&lt;/p&gt;
&lt;h3 id=&quot;wintertc&quot; tabindex=&quot;-1&quot;&gt;WinterTC &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/06/igalia-s-compilers-team-a-2025-retrospective/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In December 2024, &lt;a href=&quot;https://wintertc.org/&quot;&gt;WinterTC&lt;/a&gt; was formed to replace WinterCG as an official ECMA &lt;a href=&quot;https://ecma-international.org/technical-committees/&quot;&gt;Techincal committee&lt;/a&gt; to achieve some level of API interoperability across server-side JavaScript runtimes, especially for APIs that are common with the web.&lt;/p&gt;
&lt;p&gt;We started chairing (together folks from Deno), and became involved in admin tasks.
Over the course of the year, we:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Identified a core set of Web APIs that should be shared across runtimes and standardized it as the &lt;a href=&quot;https://min-common-api.proposal.wintertc.org/&quot;&gt;Minimum Common Web API specification&lt;/a&gt;, which was officially published at the ECMA General Assembly in December.&lt;/li&gt;
&lt;li&gt;Started identifying a subset of the WPT test suite that covers the Minimum Common Web API, and made some headway towards clarifying which parts of the Fetch specification server-side runtimes should support, and which they shouldn’t.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, if you’re curious, we gave two talks about WinterTC: &lt;a href=&quot;https://youtu.be/elGNcCv57ZE&quot;&gt;one at the Web Engines Hackfest together with Deno folks, the other chair of WinterTC&lt;/a&gt;; and &lt;a href=&quot;https://youtu.be/T9g3DtdTsGU&quot;&gt;one at JSConf.JP&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;node-js&quot; tabindex=&quot;-1&quot;&gt;Node.js &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/06/igalia-s-compilers-team-a-2025-retrospective/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In Node.js, our work in 2025 spanned interoperability, proxy integration, and adding support for HTTP/HTTPS proxy and shipping integration of System CA certificates across platforms.&lt;/p&gt;
&lt;p&gt;On the module side, we delivered interoperability features and bug fixes for &lt;code&gt;require(esm)&lt;/code&gt; and helped stabilize it (read more about it in our colleague &lt;a href=&quot;https://joyeecheung.github.io/blog/2025/12/30/require-esm-in-node-js-from-experiment-to-stability/&quot;&gt;Joyee’s blog&lt;/a&gt;), &lt;a href=&quot;https://github.com/nodejs/node/pull/55698&quot;&gt;shipped synchronous and universal loader hooks&lt;/a&gt; (now promoted to release candidate), integrated TypeScript into the &lt;a href=&quot;https://github.com/nodejs/node/issues/52696&quot;&gt;compile cache&lt;/a&gt;, and improved the portability of the cache. Check out &lt;a href=&quot;https://www.youtube.com/watch?v=MYVn6TuZCEQ&quot;&gt;Joyee’s talk at JSConf JP&lt;/a&gt; if you are interested in learning more about these new module loader features.&lt;/p&gt;
&lt;p&gt;We also strengthened &lt;a href=&quot;https://github.com/nodejs/node/issues/58990&quot;&gt;System CA certificate integration&lt;/a&gt; along with JavaScript APIs for reading and configuring trusted CAs globally, &lt;a href=&quot;https://github.com/nodejs/node/issues/57872&quot;&gt;adding built-in HTTP/HTTPS proxy support&lt;/a&gt;, and expanding &lt;a href=&quot;https://nodejs.org/en/learn/http/enterprise-network-configuration&quot;&gt;documentation for using Node.js in enterprise environments&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Additionally, we started migration to the new V8 CppHeap model in Node.js and improved its V8 Platform integration.&lt;/p&gt;
&lt;h2 id=&quot;v8&quot; tabindex=&quot;-1&quot;&gt;V8 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/06/igalia-s-compilers-team-a-2025-retrospective/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On the V8 side of things, we worked on &lt;code&gt;HeapProfiler::QueryHolders&lt;/code&gt;, a companion API to the &lt;a href=&quot;https://chromium-review.googlesource.com/c/v8/v8/+/5006373&quot;&gt;QueryObjects API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We worked on extending the &lt;a href=&quot;https://v8.github.io/api/head/classv8_1_1HeapStatistics.html&quot;&gt;HeapStatistics API&lt;/a&gt; to include a new field that tracks the total of bytes allocated in an Isolate since its creation. This counter excludes allocations that happen due to GC operations and it’s intended to be used to create memory regression tests. Here’s the &lt;a href=&quot;https://chromium-review.googlesource.com/c/v8/v8/+/6996467&quot;&gt;CL&lt;/a&gt; highlighting these changes.&lt;/p&gt;
&lt;p&gt;We also started working on implementation of the &lt;a href=&quot;https://github.com/tc39/proposal-defer-import-eval&quot;&gt;import defer proposal&lt;/a&gt; on V8. This proposal extends the syntax of ESM imports to allow a mode where the evaluation of an imported module is deferred until its first access.
From our work in Node.js, we upstreamed a few improvements and bug fixes in V8’s embedder API and startup snapshot implementation. We also contributed to Node.js’s V8 upgrade and upstreamed patches to address issues discovered in the upgrade.&lt;/p&gt;
&lt;p&gt;As part of our collaboration with Cloudflare we added &lt;code&gt;v8::IsolateGroup&lt;/code&gt;: a new unit that owns an independent pointer-compression cage. We then also enabled multiple cages per process (“multi-cage”), so thousands of isolates aren’t forced into one &amp;lt; 4 GiB region. Finally, we extended this to multiple sandboxes: one sandbox per isolate group instead of a single process-wide sandbox. In the end this work helped Cloudflare to enable the sandbox in Cloudflare workers.&lt;/p&gt;
&lt;h2 id=&quot;babel&quot; tabindex=&quot;-1&quot;&gt;Babel &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/06/igalia-s-compilers-team-a-2025-retrospective/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Our team also helps co-maintianing &lt;a href=&quot;https://babeljs.io&quot;&gt;Babel&lt;/a&gt;. The build tools area is very active nowdays, and we strongly believe that alongside the innovation happening in the ecosystem companies need to invest on ensuring that the older and widely used tools keep being actively maintained and improving over time.&lt;/p&gt;
&lt;h2 id=&quot;llvm&quot; tabindex=&quot;-1&quot;&gt;LLVM &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/06/igalia-s-compilers-team-a-2025-retrospective/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In LLVM, we helped extend auto-vectorization to take full advantage of the RISC-V vector extension’s many innovative features.&lt;/p&gt;
&lt;p&gt;After four years of development by contributors from multiple organizations including Igalia, we finally enabled &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/151681&quot;&gt;EVL tail folding for RISC-V&lt;/a&gt; as an LLVM default.&lt;/p&gt;
&lt;p&gt;This work took advantage of the new VPlan infrastructure, extending it and developing it iteratively in-tree when needed to give us the ability to model a relatively complex vectorization scheme.&lt;/p&gt;
&lt;p&gt;We also added &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/141865&quot;&gt;full scalable segmented access support&lt;/a&gt; and &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/158690&quot;&gt;taught the loop vectorizer to make smarter cost model decisions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Building on top of this, we achieved &lt;a href=&quot;https://blogs.igalia.com/compilers/2025/05/28/improvements-to-risc-v-vector-code-generation-in-llvm/&quot;&gt;improvements in RISC-V vectorization&lt;/a&gt;. In parallel, we also worked on LLVM scheduling models for the SpacemiT-x60 RISC-V processor, scoring a whopping &lt;a href=&quot;https://blogs.igalia.com/compilers/2025/11/22/unlocking-15-more-performance-a-case-study-in-llvm-optimization-for-risc-v/&quot;&gt;16% performance improvement&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Regarding WebAssembly in LLVM we landed a number of commits that improve size and performance of generated code, and added support for a few ISD nodes that enable vectorization for otherwise sequential codegen.&lt;/p&gt;
&lt;h2 id=&quot;mesa-ir3&quot; tabindex=&quot;-1&quot;&gt;Mesa/IR3 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/06/igalia-s-compilers-team-a-2025-retrospective/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We continued work on improving IR3, the Mesa compiler backend for Qualcomm Adreno GPUs. We &lt;a href=&quot;https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/31222&quot;&gt;implemented support for alias instructions&lt;/a&gt; novel to the &lt;em&gt;a7xx&lt;/em&gt; generation of GPUs, significantly improving register pressure for texture instructions. We also &lt;a href=&quot;https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/34108&quot;&gt;refactored the post-RA scheduler&lt;/a&gt; to be able to reuse the legalization logic, significantly improving its accuracy when calculating instruction delays and, consequently, reducing latency.&lt;/p&gt;
&lt;p&gt;We also &lt;a href=&quot;https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/33602&quot;&gt;added debug tooling&lt;/a&gt; to easily identify the shader that causes problems, among many other &lt;a href=&quot;https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/?sort=merged_at_desc&amp;amp;state=merged&amp;amp;author_username=jnoorman&amp;amp;first_page_size=20&quot;&gt;optimizations, implementations of new instructions, and bug fixes&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;guile-and-whippet&quot; tabindex=&quot;-1&quot;&gt;Guile and Whippet &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/06/igalia-s-compilers-team-a-2025-retrospective/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This year we also made some interesting progress on &lt;a href=&quot;https://github.com/wingo/whippet&quot;&gt;Whippet&lt;/a&gt;, a no-dependencies embeddable garbage collector.  We were able to integrate Whippet into the &lt;a href=&quot;https://gnu.org/s/guile&quot;&gt;Guile&lt;/a&gt; Scheme implementation, replacing Guile’s use of the venerable Boehm-Demers-Weiser library.  We hope to merge the &lt;a href=&quot;https://codeberg.org/guile/guile/src/branch/wip-whippet&quot;&gt;integration branch&lt;/a&gt; upstream over the next months.  We also wrote up a &lt;a href=&quot;https://arxiv.org/abs/2503.16971&quot;&gt;paper describing the innards of some of Whippet’s algorithms&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We think Whippet is interesting whereever a programming language needs a garbage collector: it’s customizable and easy to manage, as it is designed to be &amp;quot;vendored&amp;quot; directly into a user’s source code repository. We are now in the phase of building out examples to allow for proper performance evaluation; after a &lt;a href=&quot;https://github.com/wingo/whiffle&quot;&gt;bespoke Scheme implementation&lt;/a&gt; and Guile itself, we also wrote a &lt;a href=&quot;https://codeberg.org/wingo/wastrel&quot;&gt;fresh ahead-of-time compiler for WebAssembly&lt;/a&gt;, which in the near future will gain support for the garbage collection WebAssembly extensions, thanks to Whippet.  For more info on our progress, check out &lt;a href=&quot;https://wingolog.org/tags/whippet&quot;&gt;Andy Wingo’s blog series&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;fex&quot; tabindex=&quot;-1&quot;&gt;FEX &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/06/igalia-s-compilers-team-a-2025-retrospective/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For the FEX x86 JIT emulator for ARM64, we worked on X87 Floating-Point Emulation, &lt;a href=&quot;https://github.com/FEX-Emu/FEX/pull/4642&quot;&gt;implemented x87 invalid operation bit handling in F80 mode&lt;/a&gt;, &lt;a href=&quot;https://github.com/FEX-Emu/FEX/pull/4811&quot;&gt;fixed IEEE 754 unordered comparison detection&lt;/a&gt;, and &lt;a href=&quot;https://github.com/FEX-Emu/FEX/pull/5009&quot;&gt;added f80 stack xchg optimization for fast path&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Besides &lt;a href=&quot;https://github.com/FEX-Emu/FEX/pull/4846&quot;&gt;further&lt;/a&gt; &lt;a href=&quot;https://github.com/FEX-Emu/FEX/pull/5062&quot;&gt;fixes&lt;/a&gt; for instruction implementations, we also worked on memory and stability improvements, &lt;a href=&quot;https://github.com/FEX-Emu/FEX/pull/4540&quot;&gt;protecting the last page of CodeBuffer&lt;/a&gt;, and &lt;a href=&quot;https://github.com/FEX-Emu/FEX/pull/5035&quot;&gt;implementing gradual memory growth&lt;/a&gt;. Finally, we also did some infrastructure work by &lt;a href=&quot;https://github.com/FEX-Emu/FEX/pull/4661&quot;&gt;upgrading the codebase to clang-format-19&lt;/a&gt; and &lt;a href=&quot;https://github.com/FEX-Emu/FEX/pull/4488&quot;&gt;adding UBSAN support&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This year’s FEX work focused on x87 floating-point correctness and 32-bit compatibility—both critical for Valve’s Steam Frame, the ARM-powered VR headset they announced in November that uses FEX to run x86 games.&lt;/p&gt;
&lt;p&gt;The x87 improvements matter because many games and middleware still use legacy floating-point code. Subtle deviations from Intel’s behavior—wrong exception flags, incorrect comparison semantics—cause crashes or weird behavior. Fixing invalid operation exceptions, IEEE 754 comparisons, and optimizing the x87 stack pass eliminated entire classes of compatibility bugs.&lt;/p&gt;
&lt;p&gt;The 32-bit fixes are just as important. A huge chunk of Steam’s catalog is still 32-bit, and even 64-bit games often ship 32-bit launchers. Getting &lt;code&gt;fcntl&lt;/code&gt; and addressing modes right means these games just work without users needing to do anything.&lt;/p&gt;
&lt;p&gt;In total, this work gave Valve confidence that the Steam Frame could ship with solid library coverage, letting them announce the device on schedule.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Alright, that’s a wrap on our 2025 retrospective! We hope you had as much fun reading it as we had writing it, and building all the things we talked about along the way. We’ll see you next year with another roundup; until then, you can keep up with our latest work on the &lt;a href=&quot;https://blogs.igalia.com/compilers/&quot;&gt;team blog&lt;/a&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Implementing the Temporal proposal in JavaScriptCore</title>
		<link href="https://blogs.igalia.com/compilers/2026/02/02/implementing-the-temporal-proposal-in-javascriptcore/"/>
		<updated>2026-02-02T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2026/02/02/implementing-the-temporal-proposal-in-javascriptcore/</id>
		<content type="html">&lt;p&gt;&lt;em&gt;&lt;a href=&quot;https://www.publicdomainpictures.net/en/view-image.php?image=10690&amp;amp;picture=prague-astronomical-clock-detail&quot;&gt;Image source&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;For the past year, I&#39;ve been working on implementing the &lt;a href=&quot;https://tc39.es/proposal-temporal/docs/&quot;&gt;Temporal&lt;/a&gt; proposal for date and time handling in JavaScript, in JavaScriptCore (JSC). JavaScriptCore is the JavaScript engine that&#39;s part of the WebKit browser engine. When I started, Temporal was partially implemented, with support for the &lt;code&gt;Duration&lt;/code&gt;, &lt;code&gt;PlainDate&lt;/code&gt;, &lt;code&gt;PlainDateTime&lt;/code&gt;, and &lt;code&gt;Instant&lt;/code&gt; types. However, many &lt;a href=&quot;https://github.com/tc39/test262&quot;&gt;test262&lt;/a&gt; tests related to Temporal didn&#39;t pass, and there was no support for &lt;code&gt;PlainMonthDay&lt;/code&gt;, &lt;code&gt;PlainYearMonth&lt;/code&gt;, or &lt;code&gt;ZonedDateTime&lt;/code&gt; objects. Further, there was no support for the &lt;code&gt;relativeTo&lt;/code&gt; parameter, and only the &amp;quot;iso8601&amp;quot; calendar was supported.&lt;/p&gt;
&lt;h2 id=&quot;duration-precision-landed&quot; tabindex=&quot;-1&quot;&gt;Duration precision (landed) &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/02/implementing-the-temporal-proposal-in-javascriptcore/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Conceptually, a duration is a 10-tuple of time components, or a record with the fields &amp;quot;years&amp;quot;, &amp;quot;months&amp;quot;, &amp;quot;weeks&amp;quot;, &amp;quot;days&amp;quot;, &amp;quot;hours&amp;quot;, &amp;quot;seconds&amp;quot;, &amp;quot;milliseconds&amp;quot;, &amp;quot;microseconds&amp;quot;, and &amp;quot;nanoseconds&amp;quot;.&lt;/p&gt;
&lt;p&gt;One way durations are used is to represent the difference between two dates. For example, to find the length of time from a given date until the end of 2027, I could write the following JS code:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; duration &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Temporal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PlainDate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2026&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;until&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Temporal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PlainDate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2027&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;largestUnit&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;years&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; duration&lt;br&gt;Temporal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Duration &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;P1Y11M5D&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;years&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;months&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;days&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;until&lt;/code&gt; method in this case returns a duration comprising one year, eleven months, and five days. Because durations can represent differences between dates, they can also be negative:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; duration &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Temporal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PlainDate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2027&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;until&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Temporal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PlainDate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2026&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;largestUnit&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;years&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; duration&lt;br&gt;Temporal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Duration &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;P1Y11M5D&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;years&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;months&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;days&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When converted to nanoseconds, the total of days, hours, minutes, seconds, milliseconds, microseconds, and nanoseconds for a duration may be a number whose absolute value is as large as 10&lt;sup&gt;9&lt;/sup&gt; × 2&lt;sup&gt;53&lt;/sup&gt;. This number is too large to represent either as a 32-bit integer or as a 64-bit double-precision value. (If you&#39;re wondering about the significance of the number 2&lt;sup&gt;53&lt;/sup&gt;, see the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER&quot;&gt;MDN documentation on JavaScript&#39;s &lt;code&gt;MAX_SAFE_INTEGER&lt;/code&gt;&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;To understand why we need to be able to work with such large numbers, consider totaling the number of nanoseconds in a duration.  Following on the previous example’s definition of the variable &lt;code&gt;duration&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; duration&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;unit&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;nanoseconds&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;relativeTo&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Temporal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PlainDate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2025&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;15&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;60912000000000000&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are 60912000000000000 nanoseconds, or about 6.1e16, in a period of one year, eleven months, and five days. Since we want to allow this computation to be done with any valid start and end date, and valid years in Temporal range from -271821 to 275760, the result can get quite large. (By default, Temporal follows the &lt;a href=&quot;https://en.wikipedia.org/wiki/ISO_8601&quot;&gt;ISO 8601 standard&lt;/a&gt; for calendars, which entails using a &lt;a href=&quot;https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar&quot;&gt;proleptic Gregorian calendar&lt;/a&gt;. Also note that this example uses a &lt;code&gt;PlainDate&lt;/code&gt;, which has no time zone, so computations are not affected by daylight savings time; when computing with the Temporal &lt;code&gt;ZonedDateTime&lt;/code&gt; type, the specification ensures that time zone math is done properly.)&lt;/p&gt;
&lt;p&gt;To make it easier for implementations to fulfill these requirements, the specification represents durations internally as &lt;a href=&quot;https://tc39.es/proposal-temporal/#sec-temporal-internal-duration-records&quot;&gt;Internal Duration Records&lt;/a&gt; and converts between JavaScript-level duration objects and Internal Duration Records (which I&#39;ll call &amp;quot;internal durations&amp;quot;) as needed. An internal duration pairs the date component of the duration (the years, months, weeks, and days fields) with a &amp;quot;time duration&amp;quot;, which is a single integer that falls within an accepted range, and can be as large as 2&lt;sup&gt;53&lt;/sup&gt; × 10&lt;sup&gt;9&lt;/sup&gt; - 1.&lt;/p&gt;
&lt;p&gt;Implementations don&#39;t &lt;em&gt;have&lt;/em&gt; to use this representation, as long as the results are observably the same as what the specification dictates. However, the pre-existing implementation didn&#39;t suffice, so I re-implemented durations in a way that closely follows the approach in the specification.&lt;/p&gt;
&lt;p&gt;This work has been landed in JSC.&lt;/p&gt;
&lt;h2 id=&quot;new-date-types&quot; tabindex=&quot;-1&quot;&gt;New date types &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/02/implementing-the-temporal-proposal-in-javascriptcore/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Temporal&#39;s date types include &lt;code&gt;PlainDate&lt;/code&gt;, &lt;code&gt;PlainDateTime&lt;/code&gt;, &lt;code&gt;Instant&lt;/code&gt;, &lt;code&gt;ZonedDateTime&lt;/code&gt;, &lt;code&gt;PlainMonthDay&lt;/code&gt;, and &lt;code&gt;PlainYearMonth&lt;/code&gt;. The latter two represent partial dates: either a pair of a month and a day within that month, or a pair of a year and month within that year. Partial dates are a better solution for representing dates where not all of the fields are known (or not all of the fields matter) than full dates with default values for the missing bits.&lt;/p&gt;
&lt;p&gt;Temporal&#39;s &lt;code&gt;ZonedDateTime&lt;/code&gt; type represents a date along with a time zone, which can either be a numeric offset from UTC, or a named time zone.&lt;/p&gt;
&lt;p&gt;I implemented &lt;code&gt;PlainMonthDay&lt;/code&gt; and &lt;code&gt;PlainYearMonth&lt;/code&gt; with all their operations. &lt;code&gt;ZonedDateTime&lt;/code&gt; is fully implemented and the first pull request in a series of PRs for it has been submitted.&lt;/p&gt;
&lt;h2 id=&quot;the-relativeto-parameter&quot; tabindex=&quot;-1&quot;&gt;The relativeTo parameter &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/02/implementing-the-temporal-proposal-in-javascriptcore/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;What if you want to convert a number of years to a number of days? Temporal can do that, but there&#39;s a catch. Converting years to days depends on what year it is, when using the ISO 8601 calendar (similar to the Gregorian calendar), because the calendar has leap years. Some calendars have leap months as well, so converting years to months would depend on what year it is as well. Likewise, converting months to days doesn&#39;t have a consistent answer, because months vary in length.&lt;/p&gt;
&lt;p&gt;For that reason, the following code will throw an exception, because there&#39;s not enough information to compute the result:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; duration &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Temporal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Duration&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;years&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; duration&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;unit&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;days&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;Uncaught RangeError&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; a starting point is required &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; years total&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above definition of &lt;code&gt;duration&lt;/code&gt; can still be made to work if we pass in a starting point, which we can do using the &lt;code&gt;relativeTo&lt;/code&gt; parameter:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; duration&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;unit&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;days&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;relativeTo&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2025-01-01&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;365&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; duration&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;unit&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;days&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;relativeTo&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2024-01-01&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;366&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The string passed in for the &lt;code&gt;relativeTo&lt;/code&gt; parameter is automatically converted to either a &lt;code&gt;PlainDate&lt;/code&gt; or a &lt;code&gt;ZonedDateTime&lt;/code&gt;, depending on which format it conforms to.&lt;/p&gt;
&lt;p&gt;I implemented support for the &lt;code&gt;relativeTo&lt;/code&gt; parameter on all the operations that have it; once the implementations for all the date types land, I&#39;ll be submitting this work as a series of pull requests.&lt;/p&gt;
&lt;h2 id=&quot;calendars&quot; tabindex=&quot;-1&quot;&gt;Calendars &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/02/implementing-the-temporal-proposal-in-javascriptcore/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Representing dates with non-ISO8601 calendars is still very much a work in progress. The &lt;a href=&quot;https://icu.unicode.org/&quot;&gt;ICU library&lt;/a&gt; can already do the basic date computations, but much glue code is necessary to internally represent dates with non-ISO8601 calendars and call the correct ICU functions to do the computations. This work is still underway. The Temporal specification does not require support for non-ISO8601 calendars, but a separate proposal, &lt;a href=&quot;https://tc39.es/proposal-intl-era-monthcode/&quot;&gt;Intl Era Month Code&lt;/a&gt;, proposes a set of calendars to be supported by conformant implementations.&lt;/p&gt;
&lt;h2 id=&quot;testing-temporal&quot; tabindex=&quot;-1&quot;&gt;Testing Temporal &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/02/implementing-the-temporal-proposal-in-javascriptcore/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The JavaScript test suite is called &lt;a href=&quot;https://github.com/tc39/test262&quot;&gt;test262&lt;/a&gt; and every new proposal in JavaScript must be accompanied by test262 tests. Not all JS implementations are required to support internationalization, so Temporal tests that involve non-ISO calendars or named time zones (other than the UTC time zone) are organized in a separate &lt;code&gt;intl402&lt;/code&gt; subdirectory in test262.&lt;/p&gt;
&lt;p&gt;The test262 suite includes 6,764 tests for Temporal, with 1,791 of these tests added in 2025. Igalia invested hundreds of hours on increasing test coverage over the past year.&lt;/p&gt;
&lt;h2 id=&quot;status-of-work&quot; tabindex=&quot;-1&quot;&gt;Status of work &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/02/02/implementing-the-temporal-proposal-in-javascriptcore/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All of this work is behind a flag in JSC in Technology Preview, so to try it out, you&#39;ll have to pass the &lt;code&gt;--useTemporal=1&lt;/code&gt; flag.&lt;/p&gt;
&lt;p&gt;All of the implementation work discussed above (except for non-ISO calendars) is complete, but I&#39;ve been following an incremental approach to submitting the code for review by the JSC code owners. I&#39;ve already landed about 40 pull requests over the course of 2025, and expect to be submitting at least 25 more to complete the work on &lt;code&gt;PlainYearMonth&lt;/code&gt;, &lt;code&gt;ZonedDateTime&lt;/code&gt;, and &lt;code&gt;relativeTo&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Based on all the code that I&#39;ve implemented, 100% of the non-intl402 test262 tests for Temporal pass, while the current HEAD version of JSC passes less than half the tests.&lt;/p&gt;
&lt;p&gt;My colleagues at Igalia and I look forward to a future JavaScript standard that fully integrates Temporal, enabling JavaScript programs to handle dates more robustly and efficiently. Consistent implementation of the proposal across browsers is a key step towards this future. Step by step, we&#39;re getting closer to this goal.&lt;/p&gt;
&lt;p&gt;We thank &lt;a href=&quot;https://www.bloomberg.com/&quot;&gt;Bloomberg&lt;/a&gt; for sponsoring this work.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Legacy RegExp features in JavaScript</title>
		<link href="https://blogs.igalia.com/compilers/2026/01/20/legacy-regexp-features-in-javascript/"/>
		<updated>2026-01-20T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2026/01/20/legacy-regexp-features-in-javascript/</id>
		<content type="html">&lt;p&gt;In June 2025, I joined the &lt;a href=&quot;https://www.igalia.com/coding-experience/&quot;&gt;Igalia Coding Experience&lt;/a&gt; program. My role was to implement the TC39 proposal &lt;a href=&quot;https://github.com/tc39/proposal-regexp-legacy-features&quot;&gt;Legacy RegExp Features&lt;/a&gt; in SpiderMonkey, the JavaScript engine in Mozilla Firefox. This wasn&#39;t my first proposal implementation. I&#39;d already implemented the &lt;a href=&quot;https://tc39.es/proposal-is-error/#sec-fundamental-objects&quot;&gt;Error.isError&lt;/a&gt; and &lt;a href=&quot;https://spidermonkey.dev/blog/2025/03/05/iterator-range.html&quot;&gt;Iterator.range&lt;/a&gt; TC39 proposals in SpiderMonkey, but implementing the Legacy RegExp Features proposal involved delving deeper into the Mozilla codebase, and new challenges for me.&lt;/p&gt;
&lt;p&gt;To begin with, I created an implementation plan with a timeline of how I was going to approach the proposal. Additionally, I added links to the codebase where I thought I was going to make changes as per the specification, which helped me have a clear starting point and path for integrating the feature. It also meant I could get feedback from SpiderMonkey developers before actually beginning the implementation.&lt;/p&gt;
&lt;p&gt;The Legacy RegExp features proposal disables legacy static properties and RegExp.prototype.compile for instances of proper subclasses of RegExp as well as for cross-realm regexps.&lt;/p&gt;
&lt;p&gt;The following operations are modified in SpiderMonkey:&lt;/p&gt;
&lt;h3 id=&quot;regexp-prototype-compile-pattern-flags&quot; tabindex=&quot;-1&quot;&gt;RegExp.prototype.compile(pattern, flags) &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/01/20/legacy-regexp-features-in-javascript/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This method reinitializes an existing RegExp object with a new pattern and/or flags. It modifies the RegExp object in place rather than creating a new one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Modification:&lt;/strong&gt; The proposal modifies &lt;code&gt;RegExp.prototype.compile&lt;/code&gt; to throw errors for objects that are not direct instances of the RegExp as well as for cross-realm mismatches. The &lt;code&gt;compile()&lt;/code&gt; method initializes a RegExp object similar to the way a RegExp literal is created, bypassing any preprocessing of the pattern that might be done by a RegExp subclass&#39;s constructor, and potentially breaking a subclass&#39;s custom &amp;quot;exec&amp;quot; method. Thus, compile is disallowed for subclasses. It is now forbidden for a RegExp compile method to be applied to a RegExp object belonging to a different realm, as this would typically result in static properties of the incorrect realm being updated.&lt;/p&gt;
&lt;p&gt;Example of newly restricted behaviour:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;base&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; $ ./mach run&lt;br&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;:00.29 /Users/default/firefox/obj-aarch64-apple-darwin25.2.0/dist/bin/js&lt;br&gt;js&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;let&lt;/span&gt; g &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; newGlobal&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;js&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;let&lt;/span&gt; re &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; g.RegExp&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;js&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; RegExp.prototype.compile.call&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;re&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;typein:3:26 TypeError: RegExp operation not permitted on object from different realm&lt;br&gt;Stack:&lt;br&gt;  @typein:3:26&lt;br&gt;js&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To explain each line of the JavaScript code in detail:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;let g&lt;/code&gt; = &lt;a href=&quot;https://searchfox.org/firefox-main/rev/6ece603789f6751c37c48b23f39dbbb16b290592/js/src/shell/js.cpp#7449&quot;&gt;&lt;code&gt;newGlobal()&lt;/code&gt;&lt;/a&gt; creates a new JavaScript global object in SpiderMonkey, similar to opening a new window in a browser. Each global object has its own realm.
A realm is a JavaScript execution context that contains its own set of global objects and built-in functions. Every object in SpiderMonkey has a realm pointer which identifies which realm it belongs to.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;let re = g.RegExp(“x”)&lt;/code&gt; creates a new RegExp object from &lt;code&gt;g&lt;/code&gt;&#39;s realm, with a distinct instance of the RegExp constructor. Although the object behaves like one created from &lt;code&gt;RegExp(&amp;quot;x&amp;quot;)&lt;/code&gt;, the two are not wholly compatible with one another.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;RegExp.prototype.compile.call(re)&lt;/code&gt; invokes the &lt;a href=&quot;https://searchfox.org/firefox-main/rev/e1eada69e2ddd86a398ccb141dcbf772254162eb/js/src/builtin/RegExp.cpp&quot;&gt;&lt;code&gt;compile()&lt;/code&gt;&lt;/a&gt; method with the regexp initialized above for a realm returned from newGlobal(). Per &lt;a href=&quot;https://github.com/tc39/proposal-regexp-legacy-features?tab=readme-ov-file#regexpprototypecompile--pattern-flags-&quot;&gt;step 5&lt;/a&gt; of the modified &lt;code&gt;RegExp.prototype.compile()&lt;/code&gt; algorithm in the proposal, this results in a &lt;code&gt;TypeError&lt;/code&gt; exception being thrown.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Initially, I added my changes in &lt;a href=&quot;https://searchfox.org/firefox-main/rev/6ece603789f6751c37c48b23f39dbbb16b290592/js/src/builtin/RegExp.cpp#582&quot;&gt;&lt;code&gt;regexp_compile_impl()&lt;/code&gt;&lt;/a&gt;, but when testing with &lt;code&gt;./mach try auto&lt;/code&gt;, the feature failed test262 cross-realm tests when run with the &lt;code&gt;ion eager&lt;/code&gt; and &lt;code&gt;--more-compartments&lt;/code&gt; flag. Debug output showed that when invoking the RegExp.prototype.compile(re)&lt;code&gt; both the receiver or (&lt;/code&gt;this`)  of the RegExp.prototype.compile() method, and the RegExp object were in the same realm while they weren’t. In other words, the cross-realm check was passing, when it should have been failing, according to the test expectations.&lt;/p&gt;
&lt;p&gt;By the time execution reached &lt;code&gt;regexp_compile()&lt;/code&gt;, the &lt;code&gt;CallNonGenericMethod&amp;lt;IsRegExpObject, regexp_compile_impl&amp;gt;&lt;/code&gt; wrapper had already processed the &amp;quot;receiver&amp;quot; or &amp;quot;this&amp;quot; of the compile method. According to the &lt;a href=&quot;https://searchfox.org/firefox-main/rev/6ece603789f6751c37c48b23f39dbbb16b290592/js/public/CallNonGenericMethod.h#88-100&quot;&gt;CallNonGenericMethod documentation&lt;/a&gt;, if &lt;code&gt;args.thisv()&lt;/code&gt; is not of the correct type, it will attempt to unwrap &lt;code&gt;this&lt;/code&gt; and if successful, call the implementation function on the unwrapped &lt;code&gt;this&lt;/code&gt;. For a bit of context on this, SpiderMonkey has a concept of &lt;a href=&quot;https://searchfox.org/firefox-main/rev/6ece603789f6751c37c48b23f39dbbb16b290592/js/public/Wrapper.h#120-133&quot;&gt;Wrapper&lt;/a&gt; objects, which decorate an object in a sort of proxy membrane to provide security boundary enforcement. For instance, ensuring that a method can be invoked or a field can be written to from the presently entered compartment. Unwrapping an object means removing that proxy membrane, to access the actual object, similar to how you’d unwrap a gift. This can be done using &lt;a href=&quot;https://searchfox.org/firefox-main/rev/6ece603789f6751c37c48b23f39dbbb16b290592/js/src/proxy/Wrapper.cpp#353&quot;&gt;&lt;code&gt;js::CheckedUnwrapStatic()&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;--more-compartments&lt;/code&gt;, &lt;code&gt;CallNonGenericMethod&lt;/code&gt; in &lt;code&gt;regexp_compile()&lt;/code&gt; was automatically unwrapping cross-compartment proxies through &lt;code&gt;CallMethodIfWrapped &lt;/code&gt;before calling &lt;code&gt;regexp_compile_impl()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This unwrapping process also switched the JSContext to the target object&#39;s realm. This meant that by the time my realm checks executed in &lt;code&gt;regexp_compile_impl()&lt;/code&gt;, both &lt;code&gt;cx-&amp;gt;realm()&lt;/code&gt; and the RegExp object&#39;s realm pointed to the same realm (the object&#39;s home realm), making them appear equal even in genuine cross-realm call scenarios where the original call came from a different realm.&lt;/p&gt;
&lt;p&gt;So I moved the same-realm testing and [[LegacyFeaturesEnabled]] bit testing to &lt;a href=&quot;https://searchfox.org/firefox-main/rev/6ece603789f6751c37c48b23f39dbbb16b290592/js/src/builtin/RegExp.cpp#647&quot;&gt;&lt;code&gt;regexp_compile()&lt;/code&gt;&lt;/a&gt;, just before &lt;code&gt;CallNonGenericMethod&lt;/code&gt; is called and added &lt;code&gt;js::CheckedUnwrapStatic()&lt;/code&gt; to unwrap any proxy wrappers before checking the realm. This ensures we’re checking the realm of the actual RegExp object and not the compartment wrappers around it.&lt;/p&gt;
&lt;h3 id=&quot;subclass-instances&quot; tabindex=&quot;-1&quot;&gt;Subclass Instances &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/01/20/legacy-regexp-features-in-javascript/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As mentioned above, the RegExp method &lt;code&gt;RegExp.prototype.compile()&lt;/code&gt; re-initializes a RegExp using a newly created matcher for the specified pattern and flags. The proposal adds some restrictions to this which prevent oddities such as subclasses not functioning as expected (for instance, by not preprocessing the pattern and adding context used by their &lt;code&gt;exec()&lt;/code&gt; implementation). More importantly, when applied to a cross-realm object, this would result in execution modifying the static RegExp members for the incorrect realm.&lt;/p&gt;
&lt;p&gt;The proposal modifies the behavior so that legacy static properties are only updated when direct instances of the built-in RegExp constructor are used, not subclass instances or cross-realm objects, using similar logic to &lt;code&gt;RegExp.prototype.compile()&lt;/code&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol start=&quot;7&quot;&gt;
&lt;li&gt;If SameValue(thisRealm, rRealm) is true, then
&lt;ul&gt;
&lt;li&gt;i. If the value of R’s [[LegacyFeaturesEnabled]] internal slot is true, then
&lt;ul&gt;
&lt;li&gt;a. Perform UpdateLegacyRegExpStaticProperties(%RegExp%, S, lastIndex, e, capturedValues).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ii. Else,
&lt;ul&gt;
&lt;li&gt;a. Perform InvalidateLegacyRegExpStaticProperties(%RegExp%).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;The properties are specced and implemented as accessors with a getter and no setter, except for &lt;code&gt;RegExp.input&lt;/code&gt; (and its alias &lt;code&gt;RegExp.$_&lt;/code&gt;), which remains writable. Inside each of the accessors, if the receiver &lt;code&gt;this&lt;/code&gt; and the %RegExp% realm intrinsic (the standard RegExp constructor) are not the same, we throw a &lt;code&gt;TypeError&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;base&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; $ ./mach run&lt;br&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;:00.28 /Users/default/firefox/obj-aarch64-apple-darwin25.2.0/dist/bin/js&lt;br&gt;js&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; /a&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;c/.exec&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;abc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;abc&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br&gt;js&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; RegExp.&lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt; &lt;br&gt;&lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;br&gt;js&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; new RegExp&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a(b)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;.exec&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ab&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ab&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br&gt;js&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; RegExp.&lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt;                       &lt;br&gt;&lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;br&gt;js&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; new &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;class extends RegExp &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a(b)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;.exec&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ab&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ab&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br&gt;js&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; RegExp.&lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt;                                          &lt;br&gt;typein:6:1 TypeError: RegExp static property &lt;span class=&quot;token string&quot;&gt;&#39;static_paren1_getter&#39;&lt;/span&gt; is invalid&lt;br&gt;Stack:&lt;br&gt;  @typein:6:1&lt;br&gt;js&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-bash&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;/a&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;c/.exec&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;abc&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; RegExp.&lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt;  // should &lt;span class=&quot;token builtin class-name&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;br&gt;new RegExp&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a(b)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;.exec&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ab&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; RegExp.&lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt;  // &lt;span class=&quot;token string&quot;&gt;&quot;b&quot;&lt;/span&gt;&lt;br&gt;new &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;class extends RegExp &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;a(b)&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;.exec&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ab&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; RegExp.&lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt; //  throws&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;normalisation-of-regexp-static-properties&quot; tabindex=&quot;-1&quot;&gt;Normalisation of RegExp Static Properties &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/01/20/legacy-regexp-features-in-javascript/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;RegExp static properties are now defined as configurable and non-enumerable. This is so that the associated features may be easily removed by using the JavaScript &lt;code&gt;delete&lt;/code&gt; operator. This is important for consistency with modern ECMA262 and for allows for applications to further reduce the number of side-affect producing globals, including VM native methods.&lt;/p&gt;
&lt;p&gt;In SpiderMonkey, the legacy static properties are defined &lt;a href=&quot;https://searchfox.org/firefox-main/rev/6ece603789f6751c37c48b23f39dbbb16b290592/js/src/builtin/RegExp.cpp#1499-1552&quot;&gt;in RegExp.cpp&lt;/a&gt;. To implement the proposal, I enclosed the properties with a NIGHTLY_BUILD directive, removing the &lt;code&gt;JS_PROP_PERMANEN&lt;/code&gt; and &lt;code&gt;JS_PROP_ENUMERATE&lt;/code&gt; flags to make them configurable and non-enumerable for the Nightly environment, where they can be tested by the community. Outside of Nightly, we continue supporting the old implementation for beta/release environments.&lt;/p&gt;
&lt;p&gt;Then, I updated the test262 AnnexB RegExp tests to support the change and to limit the tests to Nightly.&lt;/p&gt;
&lt;h2 id=&quot;understanding-the-implementation-challenges-and-solutions&quot; tabindex=&quot;-1&quot;&gt;Understanding the Implementation: Challenges and Solutions &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/01/20/legacy-regexp-features-in-javascript/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;1-creative-bit-packing&quot; tabindex=&quot;-1&quot;&gt;1. Creative Bit Packing &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/01/20/legacy-regexp-features-in-javascript/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Once the legacy RegExp statics were normalised, the next step was adding a &lt;code&gt;LegacyFeaturesEnabled&lt;/code&gt; internal slot. This slot keeps a reference to its constructor and is checked whenever legacy features are accessed. If the &lt;code&gt;RegExp&lt;/code&gt; is a subclass instance or is is associated with a different realm, the slot indicates that legacy features should throw an error.&lt;/p&gt;
&lt;p&gt;Initially, I added the slot to the &lt;a href=&quot;https://searchfox.org/firefox-main/rev/6ece603789f6751c37c48b23f39dbbb16b290592/js/src/vm/RegExpObject.h#43&quot;&gt;RegExpObject &lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; LEGACY_FEATURES_ENABLED_SLOT &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This presented a couple of problems for me:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The number of reserved slots must match the allocation kind defined in &lt;a href=&quot;https://searchfox.org/firefox-main/rev/6ece603789f6751c37c48b23f39dbbb16b290592/js/src/gc/AllocKind.h#60&quot;&gt;FOR_EACH_OBJECT_ALLOCKIND(D)&lt;/a&gt;. The number of reserved slots increased to 5, which meant that I had to choose between OBJECT6 or OBJECT8. During implementation, I somehow missed OBJECT6 and went with OBJECT8.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I knew that I’d get some pushback in code review, as my changes increased the size of the RegExp Object by 32 bytes (four 8-byte slots). I could see that there was a way for &lt;a href=&quot;https://searchfox.org/firefox-main/rev/6ece603789f6751c37c48b23f39dbbb16b290592/js/public/RegExpFlags.h&quot;&gt;Boolean flags to share a slot&lt;/a&gt; but I didn&#39;t know how to implement my changes without breaking the JIT.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I decided to leave the implementation as is and wait for SpiderMonkey engineers / reviewers to give me feedback and their preference on how to add the Boolean.&lt;/p&gt;
&lt;p&gt;During code review, my reviewer Iain pointed out that since we’re only storing a single bit of information (whether legacy features are enabled or not), and the existing &lt;code&gt;FLAGS_SLOT&lt;/code&gt; only uses 8 bits, I could store the legacy features in the unused higher bits.&lt;/p&gt;
&lt;p&gt;The slot implementation includes a getter, &lt;code&gt;bool legacyFeaturesEnabled()&lt;/code&gt;, that reads the bit from the &lt;code&gt;FLAGS_SLOT&lt;/code&gt;; and a setter, &lt;code&gt;setLegacyFeaturesEnabled(bool)&lt;/code&gt;, that writes the bit to the &lt;code&gt;FLAGS_SLOT&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The new approach involved defining some constants based on the size of RegExp Flags so that the code keeps working if RegExpFlags gets bigger in future:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; size_t RegExpFlagsMask &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;RegExpFlag&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;AllFlags&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; size_t LegacyFeaturesEnabledBit &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Bit&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token function&quot;&gt;static_assert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;RegExpFlagsMask &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; LegacyFeaturesEnabledBit&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;              &lt;span class=&quot;token string&quot;&gt;&quot;LegacyFeaturesEnabledBit must not overlap&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://searchfox.org/firefox-main/rev/6ece603789f6751c37c48b23f39dbbb16b290592/js/src/vm/RegExpObject.h#65&quot;&gt;RegExpFlagsMask&lt;/a&gt; has a bit set to 1 if that bit is part of the RegExpFlags, and 0 otherwise. The lowest 8 bits are currently set to other RegExp flags, which leaves us with the highest bits to pack our slot in.&lt;/p&gt;
&lt;p&gt;We perform two operations: &lt;code&gt;raw &amp;amp; RegExpFlagsMask&lt;/code&gt;, which gets only the traditional RegExp flags; and &lt;code&gt;raw &amp;amp; ~RegExpFlagsMask&lt;/code&gt;, which gets everything apart from the RegExp flags.Those are bits 0-7. We use bit 8 to store &lt;code&gt;LegacyFeaturesEnabled&lt;/code&gt;.
When we read the flags, we mask off any bits that are not part of the RegExpFlags.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;RegExpFlags&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;raw &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; RegExpFlagsMask&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we write to the flags, we combine the new value of the RegExpFlags bits &lt;code&gt;(flags.value())&lt;/code&gt; with the old value of the other bits in &lt;code&gt;(raw &amp;amp; RegExpFlagsMask)&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;uint32_t newValue &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; flags&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;raw &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;~&lt;/span&gt;RegExpFlagsMask&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token function&quot;&gt;setFixedSlot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;FLAGS_SLOT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;Int32Value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;newValue&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we read the &lt;code&gt;LegacyFeaturesEnabledBit&lt;/code&gt;, we check if it’s set. When we write it, we take the existing raw value and either set or clear the &lt;code&gt;LegacyFeaturesEnabledBit&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;2-lazy-evaluation&quot; tabindex=&quot;-1&quot;&gt;2. Lazy Evaluation &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/01/20/legacy-regexp-features-in-javascript/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The proposal specifies RegExp properties as internal slots of the RegExp Object, and the abstract operations &lt;code&gt;UpdateLegacyRegExpStaticProperties (C, S, startIndex, endIndex, capturedValues)&lt;/code&gt; and &lt;code&gt;InvalidateLegacyRegExpStaticProperties(C)&lt;/code&gt; were initially confusing. The confusion came from a specification detail: we need to eagerly update the properties at a specific point in time, as opposed to SpiderMonkey’s lazily evaluated implementation.&lt;/p&gt;
&lt;p&gt;It was the first time I had come across lazy evaluation and thought, naively, that it would be possible to change the implementation to eagerly update static properties after a successful match. This didn&#39;t work for a few reasons.&lt;/p&gt;
&lt;p&gt;First, lazy evaluation is heavily embedded in the JIT, so the idea of just changing that was… ambitious. Second, lazy evaluation is a way to defer regexp evaluation until RegExp properties are accessed. Third, there’s no observable difference to the end user whether the RegExp properties were lazily or eagerly evaluated. Lastly, internal slots are a way for ECMA262 to describe the internal state of the object.&lt;/p&gt;
&lt;p&gt;So, &lt;code&gt;UpdateLegacyRegExpStaticProperties (C, S, startIndex, endIndex, capturedValues)&lt;/code&gt; wasn’t needed, as it codifies already existing behaviour in SpiderMonkey. For &lt;code&gt;InvalidateLegacyRegExpStaticProperties(C)&lt;/code&gt;, my mentor suggested implementing it as a &lt;a href=&quot;https://searchfox.org/firefox-main/rev/6ece603789f6751c37c48b23f39dbbb16b290592/js/src/vm/RegExpStatics.h#17&quot;&gt;boolean flag in RegExpStatics&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When a subclass or cross-realm regexp executes, this flag is set to true, preventing legacy static properties from being accessed. The flag is cleared after normal RegExp executions, allowing legacy features to work for standard RegExp instances.&lt;/p&gt;
&lt;p&gt;Because &lt;code&gt;InvalidateLegacyRegExpStaticProperties(C)&lt;/code&gt; marks the values of the static properties as unavailable by setting the internal slots to empty, in step 4 of the accessors &lt;code&gt;GetLegacyRegExpStaticProperty(C, thisValue, internalSlotName)&lt;/code&gt;, we throw a TypeError if the static properties are invalidated.&lt;/p&gt;
&lt;p&gt;Then, we add the equivalent code in the &lt;a href=&quot;https://searchfox.org/firefox-main/rev/6ece603789f6751c37c48b23f39dbbb16b290592/js/src/jit/CodeGenerator.cpp#2229-2243&quot;&gt;JIT path&lt;/a&gt; and so that when a regexp is executed, we lazily store enough information to be able to rerun the regexp later if the RegExpStatics are accessed.&lt;/p&gt;
&lt;h3 id=&quot;3-gating-the-implementation-behind-a-preference&quot; tabindex=&quot;-1&quot;&gt;3. Gating the implementation behind a preference &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/01/20/legacy-regexp-features-in-javascript/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first step to implementing a TC39 proposal in SpiderMonkey is adding a preference for it. This allows the feature to be enabled or disabled at runtime, which is important in gating the feature until it has been tested enough for release.&lt;/p&gt;
&lt;p&gt;With this proposal, it was awkward, because this was not a new syntax or library method, but behavioral modifications to the existing RegExp static properties and the &lt;code&gt;compile()&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;At first, I enclosed my changes in an &lt;code&gt;#ifdef NIGHTLY_BUILD&lt;/code&gt; directive so that they are only available in the nightly environment. But given the potential for web compatibility risks, we needed to put the changes behind a preference. That way, we can flip the feature back in case we break something.&lt;/p&gt;
&lt;p&gt;This created an awkward situation: the static RegExp properties themselves (like &lt;code&gt;RegExp.$1, RegExp.input&lt;/code&gt;) are defined in &lt;code&gt;regexp_static_props&lt;/code&gt;, which is baked into the static RegExp JSClass and embedded in the binary at compile time. I ended up wrapping these property definitions in an &lt;code&gt;#ifdef NIGHTLY_BUILD&lt;/code&gt;, meaning they only exist in Nightly builds.&lt;/p&gt;
&lt;p&gt;But the behavior of these properties — that is, whether accessing them should throw errors for subclasses and cross-realm regexps — is gated behind a runtime preference. This is even more awkward, because it will change behaviour in Nightly even without the preference enabled.&lt;/p&gt;
&lt;p&gt;Thus, the preference only controls whether the new throwing behavior is active. As Iain noted, there wasn&#39;t a particularly clean way to avoid this. We&#39;d need two parallel RegExp classes and then have to switch between them at runtime based on the pref, which seemed like overkill.&lt;/p&gt;
&lt;p&gt;The compromise was to ship the properties in Nightly, use the preference to control the new behavior, and rely on extra-careful testing.&lt;/p&gt;
&lt;h3 id=&quot;4-wild-goose-chase&quot; tabindex=&quot;-1&quot;&gt;4. Wild Goose Chase &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/01/20/legacy-regexp-features-in-javascript/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Around August, when I had the initial implementation working without memory optimization or centralized legacy and realm checks, I was updating legacy regexp statics in &lt;code&gt;RegExpBuiltinExec()&lt;/code&gt; only when matches succeeded.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RegExpBuiltinExec()&lt;/code&gt; has two execution paths: a &lt;code&gt;forTest&lt;/code&gt; path for &lt;code&gt;RegExp.prototype.test&lt;/code&gt; (where we can skip allocating a result object) and a normal path for full execution. I had legacy feature validation in both paths, but only for successful matches.&lt;/p&gt;
&lt;p&gt;My mentor suggested we needed to update the legacy regexp statics not just on success, but also on failure. That made sense from a spec perspective, so I spent the next week and a half trying to figure out how to implement this. I was looking into the execution paths, trying to understand where and how to trigger updates on failed matches.&lt;/p&gt;
&lt;p&gt;After about a week, we realized that they had misread the proposal! Oops. Turns out, SpiderMonkey doesn&#39;t update legacy regexp properties on failure at all: it just returns the last successful result. I&#39;d been chasing a solution to a problem that didn&#39;t actually exist in the implementation.&lt;/p&gt;
&lt;h3 id=&quot;next-steps-and-final-thoughts&quot; tabindex=&quot;-1&quot;&gt;Next Steps and Final Thoughts &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/01/20/legacy-regexp-features-in-javascript/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &amp;quot;Legacy RegExp features in JavaScript&amp;quot; proposal is, at the time of this writing, in &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;stage 3&lt;/a&gt; of the TC39 process, meaning the proposal is stable and no further changes can be made to it. There are potential backward compatibility risks and any attempt to use a disabled feature will throw a Type Error. More on that can be found in &lt;a href=&quot;https://github.com/tc39/proposal-regexp-legacy-features/blob/918a4b09723b34e4f857f10b4576028a8a02e97d/web-breaking-hazards.md&quot;&gt;the Breaking Hazards portion of the proposal&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before implementing this proposal I had briefly interacted with C++ on a production level codebase when working on the Error.isError proposal, but working on legacy RegExp properties was a deeper dive into C++ and browser internals, which was difficult but also very much appreciated!&lt;/p&gt;
&lt;p&gt;Working on this proposal exposed gaps in my knowledge but also gave me confidence in navigating large C++ codebases. I’m particularly grateful to my mentor, and Daniel Minor and Iain Ireland (from the SpiderMonkey team) for pointing me in the right direction and brainstorming solutions with me.&lt;/p&gt;
&lt;h3 id=&quot;you-may-also-like&quot; tabindex=&quot;-1&quot;&gt;You may also like: &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2026/01/20/legacy-regexp-features-in-javascript/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://hacks.mozilla.org/2020/06/a-new-regexp-engine-in-spidermonkey/&quot;&gt;A New RegExp Engine in SpiderMonkey&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://spidermonkey.dev/blog/2025/03/05/iterator-range.html&quot;&gt;Implementing Iterator.range in SpiderMonkey&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
</content>
	</entry>
	
	<entry>
		<title>Unlocking 15% More Performance: A Case Study in LLVM Optimization for RISC-V</title>
		<link href="https://blogs.igalia.com/compilers/2025/11/22/unlocking-15-more-performance-a-case-study-in-llvm-optimization-for-risc-v/"/>
		<updated>2025-11-22T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2025/11/22/unlocking-15-more-performance-a-case-study-in-llvm-optimization-for-risc-v/</id>
		<content type="html">&lt;p&gt;This blog post summarizes a talk given by Mikhail R. Gadelha at the RISC-V Summit North America 2025.&lt;/p&gt;
&lt;p&gt;You can also watch the presentation &lt;a href=&quot;https://www.youtube.com/watch?v=cWzuFmh14X0&quot;&gt;here&lt;/a&gt;. And download &lt;a href=&quot;https://igalia.com/downloads/slides/MikhailRGadelha-Unlocking15percentMorePerformance.pdf&quot;&gt;the full presentation here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/-ZNCpj3YpF-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/-ZNCpj3YpF-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;Title slide&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/-ZNCpj3YpF-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/11/22/unlocking-15-more-performance-a-case-study-in-llvm-optimization-for-risc-v/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In this post, I will walk through the results of a 10-month &lt;a href=&quot;https://riseproject.dev/&quot;&gt;RISE&lt;/a&gt; project we completed in September, focused on improving the performance of the LLVM toolchain for RISC-V.&lt;/p&gt;
&lt;p&gt;Since the moment I originally submitted this talk, we have actually squeezed out a bit more performance: what used to be a 15% speed-up is now up to 16% on &lt;a href=&quot;https://www.spec.org/cpu2017/&quot;&gt;SPEC CPU® 2017&lt;/a&gt;. Small change, but still measurable.&lt;/p&gt;
&lt;p&gt;The project targeted the &lt;a href=&quot;https://docs.banana-pi.org/en/BPI-F3/BananaPi_BPI-F3&quot;&gt;Banana Pi BPI-F3&lt;/a&gt; board, which uses the SpacemiT X60: an in-order, 8-core RISC-V processor supporting the RVA22U64 profile and RVV 1.0, 256-bit vectors.&lt;/p&gt;
&lt;p&gt;Our high-level goal was straightforward: to reduce the performance gap between LLVM and GCC for RISC-V. However, there wasn&#39;t (and still isn&#39;t) one single fix; LLVM is an extremely active codebase where improvements and regressions happen constantly. Instead, we focused on three major contributions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;A full scheduling model for the SpacemiT X60.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Improvements to vectorization across calls.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;IPRA support for the RISC-V backend.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let&#39;s walk through each contribution.&lt;/p&gt;
&lt;h2 id=&quot;1-spacemit-x60-scheduling-model&quot; tabindex=&quot;-1&quot;&gt;1. SpacemiT-X60 Scheduling Model &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/11/22/unlocking-15-more-performance-a-case-study-in-llvm-optimization-for-risc-v/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By far, our main contribution to the LLVM project was the scheduling model for the Spacemit-X60, but before we delve deeper into the changes, let&#39;s understand what a scheduling model is.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/Fzn2FiG-g4-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/Fzn2FiG-g4-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;Explaining a scheduling model with an example&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/Fzn2FiG-g4-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Instruction scheduling directly impacts performance, especially on in-order processors. Without accurate
instruction latencies, and instruction resource usage, the compiler can make poor scheduling decisions.&lt;/p&gt;
&lt;p&gt;In our slides, there is an example where:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;load -&amp;gt; uses ft0
fadd -&amp;gt; depends on ft0
fmul -&amp;gt; independent
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above is a possible naive code generated by the compiler, which has &lt;code&gt;latency(load + fadd + fmul)&lt;/code&gt;. Thanks to an accurate scheduling model the compiler can reason that it is better to emit the following code with &lt;code&gt;latency(max(load, fmul) + fadd)&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;load -&amp;gt; uses ft0
fmul -&amp;gt; independent of preceding load
fadd -&amp;gt; depends on load
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This was just an illustrative example, not something LLVM typically emits, but it demonstrates how missing scheduling information leads to unnecessary stalls.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/yr3OFWX3j_-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/yr3OFWX3j_-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;How we got the latencies and throughput of all instructions&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/yr3OFWX3j_-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The biggest piece of the work was to actually collect the data on every single instruction supported by the board. To build a correct model, we:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;wrote custom microbenchmarks to measure latency for every instruction.&lt;/li&gt;
&lt;li&gt;used throughput data from camel-cdr&#39;s RVV benchmark results.&lt;/li&gt;
&lt;li&gt;tracked all combinations of LMUL × SEW, which leads to:
&lt;ul&gt;
&lt;li&gt;201 scalar instructions.&lt;/li&gt;
&lt;li&gt;82 FP instructions.&lt;/li&gt;
&lt;li&gt;9185 RVV &amp;quot;instructions&amp;quot; (combinations).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This resulted in a very, very large spreadsheet, and it took some time to analyse and then produce a series of upstream patches to reflect that data in LLVM.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/JXVn5KDyU0-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/JXVn5KDyU0-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;RVA22U64 SPEC execution time results&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/JXVn5KDyU0-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;With scheduling enabled on RVA22U64 (scalar-only), we got up to &lt;strong&gt;16.8%&lt;/strong&gt; execution time improvements (538.imagick_r) and no regressions. The combined results show a -4.75% geometric mean improvement on execution time.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/pqkQj2ezyf-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/pqkQj2ezyf-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;RVA22U64_V SPEC execution time results&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/pqkQj2ezyf-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;When we enable vectors (RVA22U64_V), we got up to &lt;strong&gt;16%&lt;/strong&gt; improvement (508.namd_r) and no regressions. The combined results show a -3.28% geometric mean improvement on execution time.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/-SgI5Bu3LL-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/-SgI5Bu3LL-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;Comparison between RVA22U64 and RVA22U64_V execution time&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/-SgI5Bu3LL-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;One interesting result: scheduling nearly eliminated the gap between scalar and vector configurations on the x60; only one SPEC benchmark (x264) still favored the vectorized build.&lt;/p&gt;
&lt;p&gt;This shows there may be more work in improving our ability to find profitable vectorization.&lt;/p&gt;
&lt;h2 id=&quot;2-improving-vectorization-across-calls&quot; tabindex=&quot;-1&quot;&gt;2. Improving Vectorization Across Calls &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/11/22/unlocking-15-more-performance-a-case-study-in-llvm-optimization-for-risc-v/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;During benchmarking, we found strange cases where scalar code was faster than vectorized code. The root cause: register spills, especially around function call boundaries.&lt;/p&gt;
&lt;h3 id=&quot;example-544-nab-r&quot; tabindex=&quot;-1&quot;&gt;Example: 544.nab_r &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/11/22/unlocking-15-more-performance-a-case-study-in-llvm-optimization-for-risc-v/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/lFmaDePaBR-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/lFmaDePaBR-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;Reduced test from 544.nab_r that triggered the issue&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/lFmaDePaBR-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In this function, the SLP vectorizer would look only at the basic blocks performing loads/stores, and ignore the blocks containing function calls in-between blocks.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/-Bcf4CFudF-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/-Bcf4CFudF-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;Previous image but showing which blocks were not being analysed&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/-Bcf4CFudF-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Because those call blocks weren&#39;t considered when computing profitability, the vectorizer assumed vectorization was cheap, but in reality, it caused expensive vector register spills.&lt;/p&gt;
&lt;p&gt;We modified SLP to walk all blocks in the region and estimate the cost properly. This helped: &lt;strong&gt;+9.9%&lt;/strong&gt; faster on 544.nab_r, but hurt compilation time: &lt;strong&gt;+6.9%&lt;/strong&gt; slower on 502.gcc_r. After discussion, Alexey Bataev (SLP vectorizer maintainer) created a refined version that fixed the issue and avoided compilation slowdowns. This shows how the open-source community is important and that collaboration can take us further.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/3TSR6r3CoM-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/3TSR6r3CoM-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;RVA22U64_V SPEC execution time results&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/3TSR6r3CoM-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;With the refined patch, we got up to &lt;strong&gt;11.9%&lt;/strong&gt; improvement (544.nab_r), no regressions, with negligible compile-time regressions. The combined results show a -3.28% geometric mean improvement on execution time.&lt;/p&gt;
&lt;p&gt;Note that we only show results for RVA22U64_V, because the regression only happened when vectors were enabled. Now, the execution time is on par or better than the scalar-only execution time.&lt;/p&gt;
&lt;h2 id=&quot;3-ipra-support-inter-procedural-register-allocation&quot; tabindex=&quot;-1&quot;&gt;3. IPRA Support (Inter-Procedural Register Allocation) &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/11/22/unlocking-15-more-performance-a-case-study-in-llvm-optimization-for-risc-v/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;IPRA tracks which registers are actually used across call boundaries. Without it, LLVM spills registers conservatively, including registers that aren’t truly live.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/t6ixxXGinL-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/t6ixxXGinL-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;IPRA illustrative example&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/t6ixxXGinL-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Let&#39;s consider the illustrative example above, and assume &lt;code&gt;s0&lt;/code&gt; and &lt;code&gt;s1&lt;/code&gt; are not live in this function. LLVM will still save and restore these registers when IPRA is disabled. By enabling IPRA, we reduce register pressure and create shorter function prologues and epilogues.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/hSKqXJqAwn-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/hSKqXJqAwn-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;RVA22U64 SPEC execution time results&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/hSKqXJqAwn-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;With IPRA enabled on RVA22U64, we got up to &lt;strong&gt;3.2%&lt;/strong&gt; execution time improvements (538.lbm_r) and no regressions. The combined results show a -0.50% geometric mean improvement on execution time.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/ZnP_0LaNLE-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/ZnP_0LaNLE-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;RVA22U64_V SPEC execution time results&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/ZnP_0LaNLE-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;When we enable vectors (RVA22U64_V), we got up to &lt;strong&gt;3.4%&lt;/strong&gt; improvement (508.deepsjeng_r) and no regressions. The combined results show a -0.39% geometric mean improvement on execution time.&lt;/p&gt;
&lt;p&gt;Small but consistent wins; however, IPRA can’t be enabled by default due to an &lt;a href=&quot;https://github.com/llvm/llvm-project/issues/119556&quot;&gt;open bug&lt;/a&gt;, though it does not affect SPEC.&lt;/p&gt;
&lt;h2 id=&quot;llvm-vs-gcc&quot; tabindex=&quot;-1&quot;&gt;LLVM vs GCC &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/11/22/unlocking-15-more-performance-a-case-study-in-llvm-optimization-for-risc-v/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This comparison isn’t perfectly apples-to-apples because LLVM has X60-specific scheduling and GCC does not. Still, it&#39;s useful to see progress.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/ypmGz9umkZ-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/ypmGz9umkZ-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;LLVM vs GCC on RVA22U64&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/ypmGz9umkZ-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;On RVA22U64, LLVM can be &lt;strong&gt;27%&lt;/strong&gt; faster on some benchmarks but also &lt;strong&gt;27%&lt;/strong&gt; slower on others (notably x264).&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/SGNoJnMDeO-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/SGNoJnMDeO-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;RVA22U64_V SPEC execution time results&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/SGNoJnMDeO-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The results when we enable vectors (RVA22U64_V) are similar: LLVM can be &lt;strong&gt;8%&lt;/strong&gt; faster in some benchmarks but also &lt;strong&gt;9.2%&lt;/strong&gt; slower in others.&lt;/p&gt;
&lt;p&gt;My colleague Luke Lau is currently investigating these results to try to address the cases where we are slower.&lt;/p&gt;
&lt;h2 id=&quot;what-we-learned&quot; tabindex=&quot;-1&quot;&gt;What we learned &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/11/22/unlocking-15-more-performance-a-case-study-in-llvm-optimization-for-risc-v/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Adding a scheduling model can give meaningful performance improvements, especially for in-order cores.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A default in-order scheduling model may be needed. Other backends do this already, and we have a PR open for that at &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/167008&quot;&gt;PR#167008&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Many contributions don’t show results until the entire system comes together. When the project started, I spent some time modeling individual instruction, but only when the full model was integrated did we see actual improvements.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Vectorization must be tuned carefully; incorrect cost modeling leads to regressions.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;thank-you&quot; tabindex=&quot;-1&quot;&gt;Thank you &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/11/22/unlocking-15-more-performance-a-case-study-in-llvm-optimization-for-risc-v/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/flq28YfP46-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/flq28YfP46-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;Thank you slide&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/flq28YfP46-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Thank you for reading!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Summary of the May 2025 TC39 plenary</title>
		<link href="https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/"/>
		<updated>2025-07-03T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/</id>
		<content type="html">&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hello everyone! As we have with the last bunch of meetings, we&#39;re excited to tell you about all the new discussions taking place in TC39 meetings and how we try to contribute to them. However, this specific meeting has an even more special place in our hearts since Igalia had the privilege of organising it in our headquarters in A Coruña, Galicia. It was an absolute honor to host all the amazing delegates in our home city. We would like to thank everyone involved and look forward to hosting it again!&lt;/p&gt;
&lt;p&gt;Let&#39;s delve together into some of the most exciting updates.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;You can also read the &lt;a href=&quot;https://github.com/tc39/agendas/blob/main/2025/05.md&quot;&gt;full agenda&lt;/a&gt; and the &lt;a href=&quot;https://github.com/tc39/notes/pull/373&quot;&gt;meeting minutes&lt;/a&gt; on GitHub.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;progress-report-stage-4-proposals&quot; tabindex=&quot;-1&quot;&gt;Progress Report: &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;Stage 4&lt;/a&gt; Proposals &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;array-fromasync-for-stage-4&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-array-from-async&quot;&gt;&lt;code&gt;Array.fromAsync&lt;/code&gt;&lt;/a&gt; for stage 4 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Array.from&lt;/code&gt;, which takes a synchronous iterable and dumps it into a new array, is one of &lt;code&gt;Array&lt;/code&gt;&#39;s most frequently used built-in methods, especially for unit tests or CLI interfaces. However, there was no way to do the equivalent with an asynchronous iterator. &lt;code&gt;Array.fromAsync&lt;/code&gt; solves this problem, being to &lt;code&gt;Array.from&lt;/code&gt; as &lt;code&gt;for await&lt;/code&gt; is to &lt;code&gt;for&lt;/code&gt;. This proposal has now been shipping in all JS engines for at least a year (which means it&#39;s &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/Baseline/Compatibility&quot;&gt;Baseline 2024&lt;/a&gt;), and it has been highly requested by developers.&lt;/p&gt;
&lt;p&gt;From a bureaucratic point of view however, the proposal was never really stage 3. In September 2022 it advanced to stage 3 with the condition that all three of the ECMAScript spec editors signed off on the spec text; and the editors requested that a pull request was opened against the spec with the actual changes. However, this PR was not opened until recently. So in this TC39 meeting, the proposal advanced to stage 4, conditional on this editors actually reviewing it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter(s): J. S. Choi&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;explicit-resource-management-for-stage-4&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-explicit-resource-management&quot;&gt;Explicit Resource Management&lt;/a&gt; for Stage 4 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Explicit Resource Management proposal introduces implicit cleanup callbacks for objects based on lexical scope. This is enabled through the new &lt;code&gt;using x = &lt;/code&gt; declaration:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  using myFile &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fileURL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; someBytes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; myFile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;  &lt;span class=&quot;token comment&quot;&gt;// myFile will be automatically closed, and the&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token comment&quot;&gt;// associated resources released, here at the&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token comment&quot;&gt;// end of the block.&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The proposal is now shipped in Chrome, Node.js and Deno, and it&#39;s behind a flag in Firefox. As such, Ron Buckton asked for (and obtained!) consensus to approve it for Stage 4 during the meeting.&lt;/p&gt;
&lt;p&gt;Similarly to &lt;code&gt;Array.fromAsync&lt;/code&gt;, it&#39;s &lt;em&gt;not quite Stage 4 yet&lt;/em&gt;, as there is still something missing before including it in the ECMAScript standard: &lt;a href=&quot;https://github.com/tc39/test262&quot;&gt;test262&lt;/a&gt; tests need to be merged, and the ECMAScript spec editors need to approve the proposed specification text.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter(s): Ron Buckton&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;error-iserror-for-stage-4&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-is-error&quot;&gt;Error.isError&lt;/a&gt; for stage 4 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;Error.isError(objectToCheck)&lt;/code&gt; method provides a reliable way to check whether a given value is a real instance of &lt;code&gt;Error&lt;/code&gt;. This proposal was originally presented by Jordan Harband in 2015, to address concerns about it being impossible to detect whether a given JavaScript value is actually an error object or not (did you know that you can &lt;code&gt;throw&lt;/code&gt; anything, including numbers and booleans!?). It finally became part of the ECMAScript standard during this meeting.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter(s): Jordan Harband&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;adding-intl-locale-variants&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/ecma402/pull/960&quot;&gt;Adding &lt;code&gt;Intl.Locale#variants&lt;/code&gt;&lt;/a&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Intl.Locale&lt;/code&gt; objects represent &lt;a href=&quot;https://unicode.org/reports/tr35/&quot;&gt;Unicode Locale identifiers&lt;/a&gt;; i.e., a combination of language, script, region, and preferences for things like collation or calendar type.&lt;/p&gt;
&lt;p&gt;For example, &lt;code&gt;de-DE-1901-u-co-phonebk&lt;/code&gt; means &amp;quot;the German language as spoken in Germany with the traditional German orthography from 1901, using the phonebook collation&amp;quot;. They are composed of a &lt;code&gt;language&lt;/code&gt; optionally followed by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;script&lt;/code&gt; (i.e. an alphabet)&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;region&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;one or more &lt;code&gt;variants&lt;/code&gt; (such as &amp;quot;the traditional German orthography from 1901&amp;quot;)&lt;/li&gt;
&lt;li&gt;a list of additional modifiers (such as collation)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;Intl.Locale&lt;/code&gt; objects already had accessors for querying multiple properties about the underlying locale but was missing one for the variants due to an oversight, and the committee reached consensus on also exposing them in the same way.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter(s): Richard Gibson&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;progress-report-stage-3-proposals&quot; tabindex=&quot;-1&quot;&gt;Progress Report: &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;Stage 3&lt;/a&gt; Proposals &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;intl-locale-info-stage-3-update&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-intl-locale-info/&quot;&gt;Intl.Locale Info&lt;/a&gt; Stage 3 update &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/tc39/proposal-intl-locale-info&quot;&gt;&lt;code&gt;Intl.Locale&lt;/code&gt; Info&lt;/a&gt; Stage 3 proposal allows JavaScript applications to query some metadata specific to individual locales. For example, it&#39;s useful to answer the question: &amp;quot;what days are considered weekend in the &lt;code&gt;ms-BN&lt;/code&gt; locale?&amp;quot;.&lt;/p&gt;
&lt;p&gt;The committee reached consensus on a change regarding information about text direction: in some locales text is written left-to-right, in others it&#39;s right-to-left, and for some of them it&#39;s unknown. The proposal now returns &lt;code&gt;undefined&lt;/code&gt; for unknown directions, rather than falling back to left-to-right.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter(s): Shane F. Carr&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;temporal-status-update&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-temporal&quot;&gt;Temporal&lt;/a&gt; status update &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our colleague &lt;a href=&quot;https://www.igalia.com/team/pchimento&quot;&gt;Philip Chimento&lt;/a&gt; presented a regular status update on Temporal, the upcoming proposal for better date and time support in JS. The biggest news is that Temporal is now available in the latest Firefox release! The Ladybird, Graal, and Boa JS engines all have mostly-complete implementations. The committee agreed to make a minor change to the proposal, to the interpretation of the seconds (:00) component of UTC offsets in strings. (Did you know that there has been a time zone that shifted its UTC offset by just 20 seconds?)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter(s): Philip Chimento&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;immutable-arraybuffer-update&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-immutable-arraybuffer&quot;&gt;Immutable ArrayBuffer&lt;/a&gt; update &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Immutable ArrayBuffer proposal allows creating ArrayBuffers in JS from read-only data, and in some cases allows zero-copy optimizations. After last time, the champions hoped they could get the tests ready for this plenary and ask for stage 3, but they did not manage to finish that on time. However, they did make a very robust &lt;a href=&quot;https://github.com/tc39/test262/blob/main/docs/testing-plan-guide.md&quot;&gt;testing plan&lt;/a&gt;, which should make this proposal &amp;quot;the most well-tested part of the standard library that we&#39;ve seen thus far&amp;quot;. The champions will ask to advance to stage 3 once all of the tests outlined in the plan have been written.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter(s): Peter Hoddie, Richard Gibson&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;progress-report-stage-2-7-proposals&quot; tabindex=&quot;-1&quot;&gt;Progress Report: &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;Stage 2.7&lt;/a&gt; Proposals &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;iterator-sequencing-update&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-iterator-sequencing&quot;&gt;Iterator Sequencing&lt;/a&gt; update &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The iterator sequencing Stage 2.7 proposal introduces a new &lt;code&gt;Iterator.concat&lt;/code&gt; method that takes a list of iterators and returns an iterator yielding all of their elements. It&#39;s the iterator equivalent of &lt;code&gt;Array.prototype.concat&lt;/code&gt;, except that it&#39;s a static method.&lt;/p&gt;
&lt;p&gt;Michael Ficarra, the proposal&#39;s champion, was originally planning to ask for consensus on advancing the proposal to Stage 3: &lt;a href=&quot;https://github.com/tc39/test262&quot;&gt;test262&lt;/a&gt; tests had been written, and on paper the proposal was ready. However, that was not possible because the committe discussed some changes about re-using &amp;quot;iterator result&amp;quot; objects that require some changes to the proposal itself (i.e. should &lt;code&gt;Iterator.concat(x).next()&lt;/code&gt; return the same object as &lt;code&gt;x.next()&lt;/code&gt;, or should it re-create it?).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter(s): Michael Ficarra&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;progress-report-stage-2-proposals&quot; tabindex=&quot;-1&quot;&gt;Progress Report: &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;Stage 2&lt;/a&gt; Proposals &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;iterator-chunking-update&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-iterator-chunking&quot;&gt;Iterator Chunking&lt;/a&gt; update &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The iterator chunking Stage 2 proposal introduces two new &lt;code&gt;Iterator.prototype.*&lt;/code&gt; methods: &lt;code&gt;chunks(size)&lt;/code&gt;, which splits the iterator into non-overlapping chunks, and &lt;code&gt;windows(size)&lt;/code&gt;, which generates overlapping chunks offset by 1 element:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;chunks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// [1,2] and [3,4]&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;windows&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// [1,2], [2,3] and [3,4]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The proposal champion was planning to ask for Stage 2.7, but that was not possible due to some changes about the &lt;code&gt;.windows&lt;/code&gt; behaviour requested by the committee: what should happen when requesting windows of size &lt;code&gt;n&lt;/code&gt; out of an iterator that has less than &lt;code&gt;n&lt;/code&gt; elements? We considered multiple options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Do not yield any array, as it&#39;s impossible to create a window of size &lt;code&gt;n&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Yield an array with some padding (&lt;code&gt;undefined&lt;/code&gt;?) at the end to get it to the expected length&lt;/li&gt;
&lt;li&gt;Yield an array with fewer than &lt;code&gt;n&lt;/code&gt; elements&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The committee concluded that there are valid use cases both for (1) and for (3). As such, the proposal will be updated to split &lt;code&gt;.windows()&lt;/code&gt; into two separate methods.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter(s): Michael Ficarra&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;asynccontext-web-integration-brainstorming&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-async-context/&quot;&gt;AsyncContext&lt;/a&gt; web integration brainstorming &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;AsyncContext is a proposal that allows having state persisted across async flows of control -- like thread-local storage, but for asynchronicity in JS. The champions of the proposal believe async flows of control should not only flow through &lt;code&gt;await&lt;/code&gt;, but also through &lt;code&gt;setTimeout&lt;/code&gt; and other web features, such as APIs (like &lt;code&gt;xhr.send()&lt;/code&gt;) that asynchronously fire events. However, the proposal was stalled due to concerns from browser engineers about the implementation complexity of it.&lt;/p&gt;
&lt;p&gt;In this TC39 session, we brainstormed about removing some of the integration points with web APIs: in particular, context propagation through events caused asynchronously. This would work fine for web frameworks, but not for tracing tools, which is the other main use case for AsyncContext in the web. It was pointed out that if the context isn&#39;t propagated implicitly through events, developers using tracing libraries might be forced to snapshot contexts even when they&#39;re not needed, which would lead to userland memory leaks. In general, the room seemed to agree that the context should be propagated through events, at the very least in the cases in which this is feasible to implement.&lt;/p&gt;
&lt;p&gt;This TC39 discussion didn&#39;t do much move the proposal along, and we weren&#39;t expecting it to do so -- browser representatives in TC39 are mostly engineers working on the core JS engines (such as SpiderMonkey, or V8), while the concerns were coming from engineers working on web APIs. However, the week after this TC39 plenary, Igalia organized the &lt;a href=&quot;https://webengineshackfest.org/&quot;&gt;Web Engines Hackfest&lt;/a&gt;, also in A Coruña, where we could &lt;a href=&quot;https://github.com/Igalia/webengineshackfest/issues/64&quot;&gt;resume this conversation&lt;/a&gt; with the relevant people in the room. As a result, we&#39;ve had positive discussions with Mozilla engineers about a possible path forward for the proposal that did propagate the context through events, analyzing more in detail the complexity of some specific APIs where we expect the propagation to be more complex.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter(s): &lt;a href=&quot;https://igalia.com/team/abotella&quot;&gt;Andreu Botella&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;math-clamp-for-stage-2&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-math-clamp&quot;&gt;&lt;code&gt;Math.clamp&lt;/code&gt;&lt;/a&gt; for Stage 2 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;Math.clamp&lt;/code&gt; proposal adds a method to clamp a numeric value between two endpoints of a range. This proposal reached stage 1 last February, and in this plenary we discussed and resolved some of the open issues it had:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One of them was whether the method should be a static method &lt;code&gt;Math.clamp(min, value, max)&lt;/code&gt;, or whether it should be a method on &lt;code&gt;Number.prototype&lt;/code&gt; so you could do &lt;code&gt;value.clamp(min, max)&lt;/code&gt;. We opted for the latter, since in the former the order of the arguments might not be clear.&lt;/li&gt;
&lt;li&gt;Another was whether the proposal should support BigInt as well. Since we&#39;re making &lt;code&gt;clamp&lt;/code&gt; a method of &lt;code&gt;Number&lt;/code&gt;, we opted to only support the JS number type. A follow-up proposal might add this on &lt;code&gt;BigInt.prototype&lt;/code&gt; as well.&lt;/li&gt;
&lt;li&gt;Finally, there was some discussion about whether &lt;code&gt;clamp&lt;/code&gt; should throw an exception if &lt;code&gt;min&lt;/code&gt; is not lower or equal to &lt;code&gt;max&lt;/code&gt;; and in particular, how this should work with positive and negative zeros. The committee agreed that this can be decided during Stage 2.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With this, the &lt;code&gt;Math.clamp&lt;/code&gt; (or rather, &lt;code&gt;Number.prototype.clamp&lt;/code&gt;) proposal advanced to stage 2. The champion was originally hoping to get to Stage 2.7, but they ended up not proposing it due to the pending planned changes to the proposed specification text.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter(s): Oliver Medhurst&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;seeded-prng-for-stage-2&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-seeded-random&quot;&gt;Seeded PRNG&lt;/a&gt; for Stage 2 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As it stands, JavaScript&#39;s built-in functionality for generating (pseudo-)random numbers does not accept a &lt;em&gt;seed&lt;/em&gt;, a piece of data that anchors the generation of random numbers at a fixed place, ensuring that repeated calls to &lt;code&gt;Math.random&lt;/code&gt;, for example, produce a fixed sequence of values. There are various use cases for such numbers, such as testing (how can I lock down the behavior of a function that calls &lt;code&gt;Math.random&lt;/code&gt; for testing purposes if I don&#39;t know what it will produce?). This proposal seeks to add a new top-level Object, &lt;code&gt;Random&lt;/code&gt;, that will permit seeding of random number generation. It was generally well received and advanced to stage 2.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter(s): Tab Atkins-Bittner&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;progress-report-stage-1-proposals&quot; tabindex=&quot;-1&quot;&gt;Progress Report: &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;Stage 1&lt;/a&gt; Proposals &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;more-random-functions-for-stage-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-random-functions&quot;&gt;More random functions&lt;/a&gt; for stage 1 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Tab Atkins-Bittner, who presented the Seeded PRNG proposal, continued in a similar vein with &amp;quot;More random functions&amp;quot;. The idea is to settle on a set of functions that frequently arise in all sorts of settings, such as shuffling an array, generating a random number in an interval, generating a random boolean, and so on. There are a lot of fun ideas that can be imagined here, and the committee was happy to advance this proposal to stage 1 for further exploration.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter(s): Tab Atkins-Bittner&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;keep-trailing-zeros-in-intl-numberformat-and-intl-pluralrules-for-stage-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-intl-keep-trailing-zeros&quot;&gt;Keep trailing zeros in Intl.NumberFormat and Intl.PluralRules&lt;/a&gt; for Stage 1 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Eemeli Aro of Mozilla proposed a neat bugfix for two parts of JavaScript&#39;s internationalization API that handle numbers. At the moment, when a digit string, such as &lt;code&gt;&amp;quot;123.456&amp;quot;&lt;/code&gt; is given to the Intl.PluralRules and Intl.NumberFormat APIs, the string is converted to a Number. This is generally fine, but what about digit strings that contain trailing zeroes, such as &lt;code&gt;&amp;quot;123.4560&amp;quot;&lt;/code&gt;? At the moment, that trailing zero gets removed and cannot be recovered. Eemeli suggest that we keep such digits. They make a difference when formatting numbers and in using them for pluralizing words, such as &amp;quot;1.0 stars&amp;quot;. This proposal advanced to stage 1, with the understanding that some work needs to be done to clarify how some some already-existing options in the NumberFormat and PluralRules APIs are to be understood when handling such strings. Eemeli&#39;s proposal is now at stage 1!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter(s): Eemeli Aro&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;decimal-stage-1-update&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-decimal&quot;&gt;Decimal&lt;/a&gt; Stage 1 update &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We shared the latest developments on the Decimal proposal and its potential integration with &lt;code&gt;Intl&lt;/code&gt;, focusing on the concept of &lt;em&gt;amounts&lt;/em&gt;. These are lightweight wrapper classes designed to pair a decimal number with an integer &amp;quot;precision&amp;quot;, representing either the number of significant digits or the number of fractional digits, depending on context. The discussion was a natural follow-on to the earlier discussion of keeping trailing zeroes in Intl.NumberFormat and Intl.PluralRules. In discussions about decimal, we floated the idea of a string-based version of amounts, as opposed to one backed by a decimal, but this was a new, work-in-progress idea. It seems that the committee is generally happy with the underlying decimal proposal but not yet convinced about the need for a notion of an amount, at least as it was presented. Decimal stays at stage 1.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter(s): Jesse Alama&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;comparisons-to-stage-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/JakobJingleheimer/proposal-comparisons&quot;&gt;Comparisons&lt;/a&gt; to Stage 1 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Many JS environments today provide some sort of assertion functions. (For example, &lt;code&gt;console.assert&lt;/code&gt;, Node.js&#39;s &lt;code&gt;node:assert&lt;/code&gt; module, the &lt;code&gt;chai&lt;/code&gt; package on NPM.) The committee discussed a new proposal presented by Jacob Smith, &lt;a href=&quot;https://github.com/JakobJingleheimer/proposal-comparisons&quot;&gt;Comparisons&lt;/a&gt;, which explores whether this kind of functionality should be part of the ECMAScript standard.  The proposal reached stage 1, so the investigation and scoping will continue: should it cover rich equality comparisons, should there be some sort of test suite integration, should there be separate debug and production modes? These questions will be explored in future meetings.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter(s): Jacob Smith&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;idl-for-ecmascript&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-idl&quot;&gt;IDL for ECMAScript&lt;/a&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you look at the specifications for HTML, the DOM, and other web platform features, you can&#39;t miss the &lt;a href=&quot;https://en.wikipedia.org/wiki/Web_IDL&quot;&gt;Web IDL&lt;/a&gt; snippets in there. This IDL is used to describe all of the interfaces available in web browser JS environments, and how each function argument is processed and validated.&lt;/p&gt;
&lt;p&gt;IDL does not only apply to the specifications! The IDL code is also copied directly into web browsers&#39; code bases, sometimes with slight modifications, and used to generate C++ code.&lt;/p&gt;
&lt;p&gt;Tooru Fujisawa (Arai) from Mozilla brought this proposal back to the committee after a long hiatus, and presented a vision of how the same thing might be done in the ECMAScript specification, gradually. This would lower maintenance costs for any JS engine, not just web browsers. However, the way that function arguments are generally handled differs sufficiently between web platform APIs and the ECMAScript specification that it wouldn&#39;t be possible to just use the same Web IDL directly.&lt;/p&gt;
&lt;p&gt;Tooru &lt;a href=&quot;https://docs.google.com/presentation/d/10MXBbI994Go9XNNVvWHGeGHlck0TfZLjKNisE5xF5aE&quot;&gt;presented&lt;/a&gt; some possible paths to squaring this circle: adding new annotations to the existing Web IDL or defining new syntax to support the ECMAScript style of operations.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Presenter(s): Tooru Fujisawa&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;community-event&quot; tabindex=&quot;-1&quot;&gt;Community Event &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After the meeting on Thursday, we co-organized &lt;a href=&quot;https://www.meetup.com/gpul-labs/events/307842803/&quot;&gt;a community event&lt;/a&gt; with the help of &lt;a href=&quot;https://gpul.org/&quot;&gt;our local&lt;/a&gt; &lt;a href=&quot;https://corunawtf.github.io/page/&quot;&gt;tech communities&lt;/a&gt;. With an &lt;a href=&quot;https://youtu.be/2zmIVBgbNag?si=WM-ZEAAB9xhZhSPI&quot;&gt;exciting agenda full of insightful and unique presentations&lt;/a&gt; and a lively networking session afterwards over some snacks, we hope to have started some interesting conversations in the communities and piqued the interest of JavaScript developers around them over these topics.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot; tabindex=&quot;-1&quot;&gt;Conclusion &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/07/03/summary-of-the-may-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The May 2025 plenary was packed with exciting progress across the JavaScript language and internationalization features. It was also a special moment for us at Igalia as proud hosts of the meeting in our hometown of A Coruña.
We saw long-awaited proposals like Array.fromAsync, Error.isError, and Explicit Resource Management reach Stage 4, while others continued to evolve through thoughtful discussion and iteration.&lt;/p&gt;
&lt;p&gt;We’ll continue sharing updates as the work evolves, until then, thanks for reading, and see you at the next meeting!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Improvements to RISC-V vector code generation in LLVM</title>
		<link href="https://blogs.igalia.com/compilers/2025/05/28/improvements-to-risc-v-vector-code-generation-in-llvm/"/>
		<updated>2025-05-28T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2025/05/28/improvements-to-risc-v-vector-code-generation-in-llvm/</id>
		<content type="html">&lt;style&gt;
main img{
  width:75%;
  border: 1px solid #333;
}
&lt;/style&gt;
&lt;p&gt;Earlier this month, Alex presented &amp;quot;Improvements to RISC-V vector code
generation in LLVM&amp;quot; at the RISC-V Summit Europe in Paris. This blog post
summarises that talk.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/PACmNiBBmm-3304.avif 3304w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/PACmNiBBmm-3304.webp 3304w&quot;&gt;&lt;img alt=&quot;Title slide&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/PACmNiBBmm-3304.png&quot; width=&quot;3304&quot; height=&quot;1858&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot; tabindex=&quot;-1&quot;&gt;Introduction &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/28/improvements-to-risc-v-vector-code-generation-in-llvm/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So RISC-V, vectorisation, the complexities of the LLVM toolchain and just 15
minutes to cover it in front of an audience with varying specialisations.  I
was a little worried when first scoping this talk but the thing with compiler
optimisations is that the objective is often pretty clear and easy to
understand, even if the implementation can be challenging. I&#39;m going to be
exploiting that heavily in this talk by trying to focus on the high level
objective and problems encountered.&lt;/p&gt;
&lt;h2 id=&quot;rvv-codegen-development&quot; tabindex=&quot;-1&quot;&gt;RVV codegen development &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/28/improvements-to-risc-v-vector-code-generation-in-llvm/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/iWH4XF1s7U-3304.avif 3304w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/iWH4XF1s7U-3304.webp 3304w&quot;&gt;&lt;img alt=&quot;RVV codegen development&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/iWH4XF1s7U-3304.png&quot; width=&quot;3304&quot; height=&quot;1858&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Where are we today in terms of the implementation of optimisation of RISC-V
vector codegen? I&#39;m oversimplifying the state of affairs here, but the list in
the slide above isn&#39;t a bad mental model. Basic enablement is done, it&#39;s been
validated to the point it&#39;s enabled by default, we&#39;ve had a round of
additional extension implementation, and a large portion of ongoing work is on
performance analysis and tuning. I don&#39;t think I&#39;ll be surprising any of you
if I say this is a huge task. We&#39;re never going to be &amp;quot;finished&amp;quot; in the sense
that there&#39;s always more compiler performance tuning to be done, but there&#39;s
certainly phases of catching the more obvious cases and then more of a long
tail.&lt;/p&gt;
&lt;h2 id=&quot;improving-rvv-code-generation&quot; tabindex=&quot;-1&quot;&gt;Improving RVV code generation &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/28/improvements-to-risc-v-vector-code-generation-in-llvm/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/3KJOK43U9d-3304.avif 3304w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/3KJOK43U9d-3304.webp 3304w&quot;&gt;&lt;img alt=&quot;Improving RVV code generation&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/3KJOK43U9d-3304.png&quot; width=&quot;3304&quot; height=&quot;1858&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;What is the compiler trying to do here? There are multiple metrics, but
typically we&#39;re focused primarily on performance of generated code. This isn&#39;t
something we do at all costs -- in a general purpose compiler you can&#39;t for
instance spend 10hrs optimising a particular input. So we need a lot of
heuristics that help us arrive at a reasonable answer without exhaustively
testing all possibilities.&lt;/p&gt;
&lt;p&gt;The kind of considerations for the compiler during compilation includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Profitability. If you&#39;re transforming your code then for sure you want the
new version to perform better than the old one! Given the complexity of the
transformations from scalar to vector code and costs incurred by moving
values between scalar and vector registers, it can be harder than you might
think to figure out at the right time whether the vector route vs the scalar
route might be better. You&#39;re typically estimating the cost of either choice
before you&#39;ve gone and actually applied a bunch of additional optimisations
and transformations that might further alter the trade-off.&lt;/li&gt;
&lt;li&gt;More specific to RISC-V vectors, it&#39;s been described before as effectively
being a wider than 32-bit instruction width but with the excess encoded in
control status registers. If you&#39;re too naive about it, you risk switching
the &lt;code&gt;vtype&lt;/code&gt; CSR more than necessary, adding unwanted overhead.&lt;/li&gt;
&lt;li&gt;Spilling is when we load and store values to the stack. Minimising this is a
standard objective for any target, but the lack of callee saved vector
registers in the standard ABI poses a challenge, and this is more subtle but
the fact we don&#39;t have immediate offsets for some vector instructions can
put more pressure on scalar register allocation.&lt;/li&gt;
&lt;li&gt;Or otherwise just ensuring that we&#39;re using the instructions available
whenever we can. One of the questions I had was whether I&#39;m going to be
talking just about autovectorisation, or vector codegen where it&#39;s explicit
in the input (e.g. vector datatypes, intrinsics). I&#39;d make the point they&#39;re
not fully independent, in fact all these kind of considerations are
inter-related. If the compiler is doing cost modelling that&#39;s telling it
vectorisation isn&#39;t profitable. Sometimes that&#39;s true, sometimes the model
isn&#39;t detailed enough, or sometimes it&#39;s true for the compiler &lt;em&gt;right now&lt;/em&gt;
because it could be doing a better job of choosing instructions. If I solve
the issue of suboptimal instruction selection then it benefits both
autovectorisation (as it&#39;s more likely to be profitable, or will be more
profitable) and potentially the more explicit path (as explicit uses of
vectors benefit from the improved lowering).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Just one final point of order I&#39;ll say once to avoid repeating myself again
and again. I&#39;m giving a summary of improvements made by all LLVM contributors
across many companies, rather than just those by my colleagues at Igalia.&lt;/p&gt;
&lt;h2 id=&quot;non-power-of-two-vectorization&quot; tabindex=&quot;-1&quot;&gt;Non-power-of-two vectorization &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/28/improvements-to-risc-v-vector-code-generation-in-llvm/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/opTfS4hjPw-3304.avif 3304w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/opTfS4hjPw-3304.webp 3304w&quot;&gt;&lt;img alt=&quot;Non-power-of-two vectorization&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/opTfS4hjPw-3304.png&quot; width=&quot;3304&quot; height=&quot;1858&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The intuition behind both this improvement and the one on the next slide is
actually exactly the same. Cast your minds back to 2015 or so when Krste was
presenting the vector extension. Some details have changed, but if you look at
the slides (or any RVV summary since then) you see code examples with simple
minimal loops even for irregularly sized vectors or where the length of a
vector isn&#39;t fixed at compile time. The headline is that the compiler now
generates output that looks a lot more like that handwritten code that better
exploits the features of RISC-V vector.&lt;/p&gt;
&lt;p&gt;For non-power-of-two vectorisation, I&#39;m talking about the case here where you
have a fixed known-at-compile time length. In LLVM this is handled usually by
what we call the &lt;a href=&quot;https://llvm.org/docs/Vectorizers.html#slp-vectorizer&quot;&gt;SLP or Superword Level Parallelism
vectorizer&lt;/a&gt;. It needed
to be taught to handle non-power-of-two sizes like we support in RVV. Other
SIMD ISAs don&#39;t have the notion of &lt;code&gt;vl&lt;/code&gt; and so generating non-power-of-two
vector types isn&#39;t as easy.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/3d3Aop8eUv-3304.avif 3304w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/3d3Aop8eUv-3304.webp 3304w&quot;&gt;&lt;img alt=&quot;Non-power-of-two vectorization example&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/3d3Aop8eUv-3304.png&quot; width=&quot;3304&quot; height=&quot;1858&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The example I show here has pixels with rgb values. Before it would do a very
narrow two-wide vector operation then handle the one remaining item with
scalar code. Now we directly operate on a 3-element vector.&lt;/p&gt;
&lt;p&gt;We are of course using simple code examples for illustration here. If you want
to brighten an image as efficiently as possible sticking the per-pixel
operation in a separate function like this perhaps isn&#39;t how you&#39;d do it!&lt;/p&gt;
&lt;h2 id=&quot;vl-tail-folding&quot; tabindex=&quot;-1&quot;&gt;vl tail folding &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/28/improvements-to-risc-v-vector-code-generation-in-llvm/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/sce17EWKZC-3304.avif 3304w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/sce17EWKZC-3304.webp 3304w&quot;&gt;&lt;img alt=&quot;vl tail folding&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/sce17EWKZC-3304.png&quot; width=&quot;3304&quot; height=&quot;1858&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Often when operating on a loop, you have an input of a certain length and you
process it in chunks of some reasonable size. RISC-V vector gives us a lot
more flexibility about doing this. If our input vector isn&#39;t an exact multiple
of our vectorization factor (&amp;quot;chunk size&amp;quot;) - which is the calculated vector
length used per iteration - we can still process that in RVV using the same
vector code path. While for other architectures, as you see with the old code
has a vector loop, then may branch to a scalar version for the tail for any
remainder elements. Now that&#39;s not necessary, LLVM&#39;s &lt;a href=&quot;https://llvm.org/docs/Vectorizers.html#the-loop-vectorizer&quot;&gt;loop
vectorizer&lt;/a&gt; can
handle these cases properly and we get a single vectorised loop body. This
results in performance improvements on benchmarks like x264 where the scalar
tail is executed frequently, and improves code size even in cases where there
is no direct performance impact.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/H70Ssl-o09-3304.avif 3304w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/H70Ssl-o09-3304.webp 3304w&quot;&gt;&lt;img alt=&quot;vl tail folding example&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/H70Ssl-o09-3304.png&quot; width=&quot;3304&quot; height=&quot;1858&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;libcall-expansion&quot; tabindex=&quot;-1&quot;&gt;libcall expansion &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/28/improvements-to-risc-v-vector-code-generation-in-llvm/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/Pld-DE3UKJ-3304.avif 3304w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/Pld-DE3UKJ-3304.webp 3304w&quot;&gt;&lt;img alt=&quot;libcall expansion&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/Pld-DE3UKJ-3304.png&quot; width=&quot;3304&quot; height=&quot;1858&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;This one is a little bit simpler. It&#39;s common for the compiler to synthesise
its own version of &lt;code&gt;memcpy&lt;/code&gt;/&lt;code&gt;memset&lt;/code&gt; when it sees it can generate a more
specialised version based on information about alignment or size of the
operands. Of course when the vector extension is available the compiler
should be able to use it to implement these operations, and now it can.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/TdJRDPojGO-3304.avif 3304w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/TdJRDPojGO-3304.webp 3304w&quot;&gt;&lt;img alt=&quot;libcall expansion example&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/TdJRDPojGO-3304.png&quot; width=&quot;3304&quot; height=&quot;1858&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;This example shows how a small number of instructions expanded inline might be
used to implement memcpy and memcmp. I also note there is a RISC-V vector
specific consideration in favour of inlining operations in this case - as the
standard calling convention doesn&#39;t have any callee-saved vector registers,
avoiding the function call may avoid spilling vector registers.&lt;/p&gt;
&lt;h2 id=&quot;newer-rvv-extensions&quot; tabindex=&quot;-1&quot;&gt;Newer RVV extensions &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/28/improvements-to-risc-v-vector-code-generation-in-llvm/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/3BzOkHwSmk-3304.avif 3304w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/3BzOkHwSmk-3304.webp 3304w&quot;&gt;&lt;img alt=&quot;Improving codegen for newer RVV extensions&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/3BzOkHwSmk-3304.png&quot; width=&quot;3304&quot; height=&quot;1858&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Sometimes of course it&#39;s a matter of a new extension letting us do something
we couldn&#39;t before. We need to teach the compiler how to select instructions
in that case, and to estimate the cost. Half precision and bf16 floating point
is an interesting example where you introduce a small number of instructions
for the values of that type, but otherwise rely on widening to 32-bit. This is
of course better than falling back to a libcall or scalarising to use Zfh
instruction, but someone needs to be put in the work to convince the compiler
of that!&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/V3L1qQC-SY-3304.avif 3304w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/V3L1qQC-SY-3304.webp 3304w&quot;&gt;&lt;img alt=&quot;Loop vectorizer f32 widening&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/V3L1qQC-SY-3304.png&quot; width=&quot;3304&quot; height=&quot;1858&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;h2 id=&quot;other-improvements&quot; tabindex=&quot;-1&quot;&gt;Other improvements &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/28/improvements-to-risc-v-vector-code-generation-in-llvm/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/HwUdpRQywp-3304.avif 3304w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/HwUdpRQywp-3304.webp 3304w&quot;&gt;&lt;img alt=&quot;Other improvements&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/HwUdpRQywp-3304.png&quot; width=&quot;3304&quot; height=&quot;1858&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The slide above has a sampling of other improvements. If you&#39;d like to know
more about the VL optimizer, my colleague&#39;s presentation at EuroLLVM earlier
this year is &lt;a href=&quot;https://www.youtube.com/watch?v=Mfb5fRSdJAc&quot;&gt;now up on YouTube&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Another fun highlight is
&lt;a href=&quot;https://llvm.org/docs/CommandGuide/llvm-exegesis.html&quot;&gt;llvm-exegesis&lt;/a&gt;, this
is a tool for detecting microarchitectural implementation details via probing,
e.g. latency and throughput of different operations that will help you write a
scheduling model. It now supports RVV which is a bit helpful for the one piece
of RVV 1.0 hardware we have readily available, but should be a lot more
helpful once more hardware reaches the market.&lt;/p&gt;
&lt;h2 id=&quot;results&quot; tabindex=&quot;-1&quot;&gt;Results &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/28/improvements-to-risc-v-vector-code-generation-in-llvm/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/HCA3JnO-qA-3304.avif 3304w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/HCA3JnO-qA-3304.webp 3304w&quot;&gt;&lt;img alt=&quot;Results&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/HCA3JnO-qA-3304.png&quot; width=&quot;3304&quot; height=&quot;1858&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;So, it&#39;s time to show the numbers. Here I&#39;m looking at execution time for SPEC
CPU 2017 benchmarks (run using LLVM&#39;s harness) on at SpacemiT X60 and compiled
with the options mentioned above. As you can see, 12 out of 16 benchmarks
improved by 5% or more, 7 out of 16 by 10% or more. These are meaningful
improvements a bit under 9% geomean when compared to Clang as of March this
year to Clang from 18 months prior.&lt;/p&gt;
&lt;p&gt;There&#39;s more work going in as we speak, such as the optimisation work done by
my colleague Mikhail and &lt;a href=&quot;https://riseproject.dev/2025/05/08/project-rp009-llvm-spec-optimization/&quot;&gt;written up on the RISE
blog&lt;/a&gt;.
Benchmarking done for that work comparing Clang vs GCC showed today&#39;s LLVM is
faster than GCC in 11 of the 16 tested SPEC benchmarks, slower in 3, and about
equal for the other two.&lt;/p&gt;
&lt;p&gt;Are we done? Goodness no! But we&#39;re making great progress. As I say for all of
these presentations, even if you&#39;re not directly contributing compiler
engineering resources I really appreciate anyone able to contribute by
reporting any cases when they compiler their code of interest and don&#39;t get
the optimisation expected. The more you can break it down and produce minimised
examples the better, and it means us compiler engineers can spend more time
writing compiler patches rather than doing workload analysis to figure out the
next priority.&lt;/p&gt;
&lt;h2 id=&quot;testing&quot; tabindex=&quot;-1&quot;&gt;Testing &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/28/improvements-to-risc-v-vector-code-generation-in-llvm/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/1XJ360BpSN-3304.avif 3304w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/1XJ360BpSN-3304.webp 3304w&quot;&gt;&lt;img alt=&quot;Testing&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/1XJ360BpSN-3304.png&quot; width=&quot;3304&quot; height=&quot;1858&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Adding all these new optimisations is great, but we want to make sure the
generated code works and continues to work as these new code generation
features are iterated on. It&#39;s been really important to have CI coverage for
some of these new features including when they&#39;re behind flags and not enabled
by default. Thank you to RISE for supporting my work here, we have a nice
&lt;a href=&quot;https://igalia.github.io/riscv-llvm-ci/&quot;&gt;dashboard providing an easy view of just the RISC-V
builders&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;future-work&quot; tabindex=&quot;-1&quot;&gt;Future work &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/28/improvements-to-risc-v-vector-code-generation-in-llvm/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/GYdW5uSHwh-3304.avif 3304w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/GYdW5uSHwh-3304.webp 3304w&quot;&gt;&lt;img alt=&quot;Future work&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/GYdW5uSHwh-3304.png&quot; width=&quot;3304&quot; height=&quot;1858&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Here&#39;s some directions of potential future work or areas we&#39;re already
looking. Regarding the default scheduling model, Mikhail&#39;s recent work on the
Spacemit X60 scheduling model shows how having at least a basic scheduling
model can have a big impact (partly as various code paths are pessimised in
LLVM if you don&#39;t at least have something). Other backends like AArch64 pick a
reasonable in-order core design on the basis that scheduling helps a lot for
such designs, and it&#39;s not harmful for more aggressive OoO designs.&lt;/p&gt;
&lt;h2 id=&quot;thank-you&quot; tabindex=&quot;-1&quot;&gt;Thank you &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/28/improvements-to-risc-v-vector-code-generation-in-llvm/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/eR4vgX_IX1-3304.avif 3304w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/eR4vgX_IX1-3304.webp 3304w&quot;&gt;&lt;img alt=&quot;Thank you&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/eR4vgX_IX1-3304.png&quot; width=&quot;3304&quot; height=&quot;1858&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;To underline again, I&#39;ve walked through progress made by a whole community of
contributors not just Igalia. That includes at least the companies mentioned
above, but more as well. I really see upstream LLVM as a success story for
cross-company collaboration within the RISC-V ecosystem. For sure it could be
better, there are companies doing a lot with RISC-V who aren&#39;t doing much with
the compiler they rely on, but a huge amount has been achieved by a
contributor community that spans many RISC-V vendors. If you&#39;re working on the
RISC-V backend downstream and looking to participate in the upstream
community, we run biweekly contributor calls (details on the &lt;a href=&quot;https://discourse.llvm.org/c/code-generation/riscv/57&quot;&gt;RISC-V category
on LLVM&#39;s Discourse&lt;/a&gt;
that may be a helpful way to get started.&lt;/p&gt;
&lt;p&gt;Thank you for reading!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Summary of the April 2025 TC39 plenary</title>
		<link href="https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/"/>
		<updated>2025-05-20T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/</id>
		<content type="html">&lt;p&gt;In April, many colleagues from Igalia participated in a TC39 meeting organized remotely to discuss proposed features for the JavaScript standard alongside delegates from various other organizations.&lt;/p&gt;
&lt;p&gt;Let&#39;s delve together into some of the most exciting updates!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;You can also read the &lt;a href=&quot;https://github.com/tc39/agendas/blob/main/2025/04.md&quot;&gt;full agenda&lt;/a&gt; and the &lt;a href=&quot;https://github.com/tc39/notes/pull/369&quot;&gt;meeting minutes&lt;/a&gt; on GitHub.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;progress-report-stage-4-proposals&quot; tabindex=&quot;-1&quot;&gt;Progress Report: &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;Stage 4&lt;/a&gt; Proposals &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;add-notation-to-intl-pluralrules&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/ecma402/pull/989&quot;&gt;Add &lt;code&gt;notation&lt;/code&gt; to &lt;code&gt;Intl.PluralRules&lt;/code&gt;&lt;/a&gt; &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In 2020, the &lt;code&gt;Intl.NumberFormat&lt;/code&gt; Unified API proposal added a plethora of new features to &lt;code&gt;Intl.NumberFormat&lt;/code&gt;, including compact and other non-standard notations. It was planned that &lt;code&gt;Intl.PluralRules&lt;/code&gt; would be updated to work with the notation option to make the two complement each other. This normative change achieved this by adding a &lt;code&gt;notation&lt;/code&gt; option to the &lt;code&gt;PluralRules&lt;/code&gt; constructor.&lt;/p&gt;
&lt;p&gt;Given the very small size of this &lt;code&gt;Intl&lt;/code&gt; change, it didn&#39;t go through the staging process for proposals and was instead directly approved to be merged into the ECMA-402 specification.&lt;/p&gt;
&lt;h2 id=&quot;progress-report-stage-3-proposals&quot; tabindex=&quot;-1&quot;&gt;Progress Report: &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;Stage 3&lt;/a&gt; Proposals &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;temporal-stage-3-status-update&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-temporal&quot;&gt;Temporal&lt;/a&gt; Stage 3 status update &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our colleague Philip Chimento presented a regular status update on Temporal, the upcoming proposal for better date and time support in JS.&lt;/p&gt;
&lt;p&gt;Firefox is at ~100% conformance with just a handful of open questions. The next most conformant implementation, in the Ladybird browser, dropped from 97% to 96% since February — not because they broke anything, but just because we added more tests for tricky cases in the meantime. GraalJS at 91% and Boa at 85% have been catching up.&lt;/p&gt;
&lt;p&gt;Completing the Firefox implementation has raised a few interoperability questions which we plan to solve with the &lt;a href=&quot;https://github.com/tc39/proposal-intl-era-monthcode&quot;&gt;Intl Era and Month Code&lt;/a&gt; proposal soon.&lt;/p&gt;
&lt;h3 id=&quot;explicit-resource-management-stage-3-implementer-feedback&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-explicit-resource-management&quot;&gt;Explicit Resource Management&lt;/a&gt; Stage 3 implementer feedback &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Dan Minor of Mozilla reported on a tricky case with the proposed &lt;code&gt;using&lt;/code&gt; keyword for certain resources. The feature is essentially completely implemented in SpiderMonkey, but Dan highlighted an ambiguity about &lt;a href=&quot;https://github.com/rbuckton/ecma262/pull/14&quot;&gt;using the new keyword in &lt;code&gt;switch&lt;/code&gt; statements&lt;/a&gt;. The committee agreed on a resolution of the issue suggested by Dan, including those implementers who have already shipped this stage 3 feature.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champion: Ron Buckton&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;changed-behavior-of-array-fromasync-stage-3-after-spec-pr-2600&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-array-from-async/issues/39#issuecomment-1526744932&quot;&gt;Changed behavior of &lt;code&gt;Array.fromAsync&lt;/code&gt;&lt;/a&gt; (Stage 3) after spec PR &lt;a href=&quot;https://github.com/tc39/ecma262/pull/2600&quot;&gt;#2600&lt;/a&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The JavaScript &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol&quot;&gt;iterator&lt;/a&gt; and async iterator protocols power all modern iteration methods in the language, from &lt;code&gt;for of&lt;/code&gt; and &lt;code&gt;for await of&lt;/code&gt; to the rest and spread operators, to the modern iterator helpers proposals...&lt;/p&gt;
&lt;p&gt;One less-well-known part of these protocols, however, is the optional &lt;code&gt;.throw()&lt;/code&gt; and &lt;code&gt;.return()&lt;/code&gt; methods, which can be used to influence the iteration itself. In particular, &lt;code&gt;.return()&lt;/code&gt; indicates to the iterator that the iteration is finished, so it can perform any cleanup actions. For example, this is called in &lt;code&gt;for of&lt;/code&gt;/&lt;code&gt;for await of&lt;/code&gt; when the iteration stops early (due to a &lt;code&gt;break&lt;/code&gt;, for example).&lt;/p&gt;
&lt;p&gt;When using &lt;code&gt;for await of&lt;/code&gt; with a sync iterator/iterable, such as an array of promises, each value coming from the sync iterator is awaited. However, a bug was found recently where if one of those promises coming from the sync iterator rejects, the iteration would stop, but the original sync iterator&#39;s &lt;code&gt;.return()&lt;/code&gt; method would never be called. (Note that in &lt;code&gt;for of&lt;/code&gt; with sync iterators, &lt;code&gt;.return()&lt;/code&gt; is always called after &lt;code&gt;.next()&lt;/code&gt; throws).&lt;/p&gt;
&lt;p&gt;In the January TC39 plenary we decided to make it so that such a rejection would close the original sync iterator. In this plenary, we decided that since &lt;a href=&quot;https://github.com/tc39/proposal-array-from-async/&quot;&gt;&lt;code&gt;Array.fromAsync&lt;/code&gt;&lt;/a&gt; (which is currently stage 3) uses the same underlying spec machinery for this, it also would affect that API.&lt;/p&gt;
&lt;h2 id=&quot;progress-report-stage-2-7-proposals&quot; tabindex=&quot;-1&quot;&gt;Progress Report: &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;Stage 2.7&lt;/a&gt; Proposals &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;immutable-arraybuffers-missed-stage-3&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-immutable-arraybuffer&quot;&gt;Immutable ArrayBuffers&lt;/a&gt; missed Stage 3 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The Immutable ArrayBuffer proposal allows creating ArrayBuffers in JS from read-only data, and in some cases allows zero-copy optimizations. After advancing to stage 2.7 last time, there is work underway to write conformance tests. The committee considered advancing the proposal to stage 3 conditionally on the tests being reviewed, but decided to defer that to the next meeting.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champions: Mark S. Miller, Peter Hoddie, Richard Gibson, Jack-Works&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;upsert-to-stage-2-7&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-upsert&quot;&gt;Upsert&lt;/a&gt; to Stage 2.7 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The notion of &amp;quot;upserting&amp;quot; a value into an object for a key is a great match for a common use case: is it possible to set a value for a property on an object, but, if the object already has that property, &lt;em&gt;update&lt;/em&gt; the value in some way? To use CRUD terminology, it&#39;s a fusion of inserting and updating. This proposal is proceeding nicely; it just recently achieved stage 2, and achieved stage 2.7 at this plenary, since it has landed a number of test262 tests. This proposal is being worked on by Dan Minor with assistance from a number of students at the University of Bergen, illustrating a nice industry-academia collaboration.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champion: Daniel Minor&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;applying-non-extensibility-to-private-fields-to-stage-2-7&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/syg/proposal-nonextensible-applies-to-private&quot;&gt;Applying non-extensibility to private fields&lt;/a&gt; to Stage 2.7 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;JavaScript objects can be made non-extensible using &lt;code&gt;Object.preventExtensions&lt;/code&gt;: the value of the properties of a non-extensible object can be changed, but you cannot add new properties to it.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token string&quot;&gt;&quot;use strict&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; myObj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventExtensions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myObj&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;myObj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ok&lt;/span&gt;&lt;br&gt;myObj&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;z &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// error!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, this only applies to &lt;em&gt;public&lt;/em&gt; properties: you can still install new private fields on the object thanks to the &amp;quot;return it from &lt;code&gt;super()&lt;/code&gt; trick&amp;quot;.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AddPrivateField&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; x &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    #foo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;hasFoo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; #foo &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; obj&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; myObj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventExtension&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myObj&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;AddPrivateField&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasFoo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// false&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AddPrivateField&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;AddPrivateField&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasFoo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;obj&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This new proposal, which went all the way to Stage 2.7 in a single meeting, attempts to make the &lt;code&gt;new AddPrivateField(obj)&lt;/code&gt; throw when &lt;code&gt;myObj&lt;/code&gt; is non-extensible.&lt;/p&gt;
&lt;p&gt;The V8 team is currently investigating the web compatibility of this change.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champions: Mark Miller, Shu-yu Guo, Chip Morningstar, Erik Marks&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;progress-report-stage-2-proposals&quot; tabindex=&quot;-1&quot;&gt;Progress Report: &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;Stage 2&lt;/a&gt; Proposals &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;withdrawing-records-and-tuples-replaced-by-stage-1-composite-keys&quot; tabindex=&quot;-1&quot;&gt;Withdrawing &lt;a href=&quot;https://github.com/tc39/proposal-record-tuple&quot;&gt;Records and Tuples&lt;/a&gt;, replaced by Stage 1 &lt;a href=&quot;https://github.com/tc39/proposal-composites&quot;&gt;composite keys&lt;/a&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Records and Tuples was a proposal to support composite primitive types, similar to object and arrays, but that would be deeply immutable and with recursive equality. They also had similar syntax as objects and arrays, but prefixed by &lt;code&gt;#&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; myRecord &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; #&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Nic&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;company&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Igalia&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; myRecord&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;record&quot;&lt;/span&gt;&lt;br&gt;myRecord&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// error&lt;/span&gt;&lt;br&gt;myRecord &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; #&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Nic&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;company&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Igalia&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The proposal reached stage 2 years ago, but then got stuck due to significant performance concerns from browsers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;changing the way &lt;code&gt;===&lt;/code&gt; works would risk making every existing &lt;code&gt;===&lt;/code&gt; usage a little bit slower&lt;/li&gt;
&lt;li&gt;JavaScript developers were expecting &lt;code&gt;===&lt;/code&gt; on these values to be fast, but in reality it would have required either a full traversal of the two records/tuples or complex interning mechanisms&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Ashley Claymore, working at Bloomberg, presented a new simpler proposal that would solve &lt;em&gt;one&lt;/em&gt; of the use cases of Records and Tuples: having &lt;code&gt;Map&lt;/code&gt;s and &lt;code&gt;Set&lt;/code&gt;s whose keys are composed of multiple values. The proposal introduces &lt;a href=&quot;https://github.com/tc39/proposal-composites&quot;&gt;composites&lt;/a&gt;: some objects that &lt;code&gt;Map&lt;/code&gt; and &lt;code&gt;Set&lt;/code&gt; would handle specially for that purpose.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; myMap &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;myMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;myMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// false, it&#39;s a different array with just the same contents&lt;/span&gt;&lt;br&gt;&lt;br&gt;myMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Composite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;world&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;myMap&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;has&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Composite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hello&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;world&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// true!&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Champion: Ashley Claymore&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;asynccontext-stage-2-updates&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-async-context/&quot;&gt;AsyncContext&lt;/a&gt; Stage 2 updates &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;AsyncContext is a proposal that allows storing state which is local to an async flow of control (roughly the async equivalent of thread-local storage in other languages), which was impossible in browsers until now. We had previously opened a Mozilla standards position issue about AsyncContext, and it came back negative. One of the main issues they had is that AsyncContext has a niche use case: this feature would be mostly used by third-party libraries, especially for telemetry and instrumentation, rather than by most developers. And Mozilla reasoned that making those authors&#39; lives slightly easier was not worth the additional complexity to the web platform.&lt;/p&gt;
&lt;p&gt;However, we should have put more focus on the facts that AsyncContext would enable libraries to improve the UX for their users, and that AsyncContext is also incredibly useful in many front-end frameworks. Not having access to AsyncContext leads to &lt;a href=&quot;https://react.dev/reference/react/useTransition#react-doesnt-treat-my-state-update-after-await-as-a-transition&quot;&gt;confusing and hard-to-debug behavior&lt;/a&gt; in some frameworks, and &lt;a href=&quot;https://github.com/vuejs/core/blob/d48937fb9550ad04b1b28c805ecf68c665112412/packages/runtime-core/src/apiSetupHelpers.ts#L480-L498&quot;&gt;forces other frameworks to transpile all user code&lt;/a&gt;. We interviewed the maintainers for a number of frameworks to see their use cases, which you can read &lt;a href=&quot;https://github.com/tc39/proposal-async-context/blob/master/FRAMEWORKS.md&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Mozilla was also worried about the potential for memory leaks, since in a previous version of this proposal, calling &lt;code&gt;.addEventListener&lt;/code&gt; would store the current context (that is, a copy of the value for every single &lt;code&gt;AsyncContext.Variable&lt;/code&gt;), which would only be released in the corresponding &lt;code&gt;.removeEventListener&lt;/code&gt; call -- which almost never happens. As a response we changed our model so that &lt;code&gt;.addEventListener&lt;/code&gt; would not store the context. (You can read more about the memory aspects of the proposal &lt;a href=&quot;https://github.com/tc39/proposal-async-context/blob/master/MEMORY-MANAGEMENT.md&quot;&gt;here&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;A related concern is developer complexity, because in a previous model some APIs and events used the &amp;quot;registration context&amp;quot; (for events, the context in which &lt;code&gt;.addEventListener&lt;/code&gt; is called) while others used the &amp;quot;dispatch context&amp;quot; (for events, the context that directly caused the event). We explained that in our newer model, we always use the dispatch context, and that this model would match the context you&#39;d get if the API was internally implemented in JS using promises -- but that for most APIs other than events, those two contexts are the same. (You can read more about the web integration of AsyncContext &lt;a href=&quot;https://github.com/tc39/proposal-async-context/blob/master/WEB-INTEGRATION.md&quot;&gt;here&lt;/a&gt;.)&lt;/p&gt;
&lt;p&gt;After the presentation, Mozilla still had concerns about how the web integration might end up being a large amount of work to implement, and it might still not be worth it, even when the use cases were clarified. They pointed out that the frameworks do have use cases for the core of the proposal, but that they don&#39;t seem to need the web integration.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champions: Andreu Botella, Chengzhong Wu, Justin Ridgewell&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;intl-era-month-code-stage-2-update&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-intl-era-monthcode&quot;&gt;Intl Era Month Code&lt;/a&gt; Stage 2 Update &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In a post Temporal JavaScript, non-Gregorian calendars can be utilized beyond just Internationalization with a much higher level of detail. Some of this work is relatively uncharted and therefore needs standardization. One of these small but highly significant details is the string IDs for era and months for various calendars. This stage 2 update brought the committee up to speed on some of the design directions of the effort and justified the rationale behind certain tradeoffs including favoring human-readable era codes and removing the requirement of them to be globally unique as well as some of the challenges we have faced with standardizing and programmatically implementing Hijri calendars.&lt;/p&gt;
&lt;h3 id=&quot;deferred-re-exports-to-stage-2&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-deferred-reexports/&quot;&gt;Deferred re-exports&lt;/a&gt; to Stage 2 &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Originally created as part of the &lt;a href=&quot;https://github.com/tc39/proposal-defer-import-eval&quot;&gt;&lt;code&gt;import defer&lt;/code&gt;&lt;/a&gt; proposal, deferred re-exports allow, well... deferring re-export declarations.&lt;/p&gt;
&lt;p&gt;The goal of the proposal is to reduce the cost of unused &lt;code&gt;export ... from&lt;/code&gt; statements, as well as providing a minimum basis for tree-shaking behavior that everybody must implement and can be relied upon.&lt;/p&gt;
&lt;p&gt;Consider this example:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// my-library/index.js&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; add&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; multiply &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./arithmetic.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; union&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; intersection &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./sets.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If a consumer of &lt;code&gt;my-library&lt;/code&gt; only needs the &lt;code&gt;add&lt;/code&gt; function, they have two choices:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;either import &lt;code&gt;my-library&lt;/code&gt;&#39;s internal files, to only load &lt;code&gt;my-library/arithmetic.js&lt;/code&gt;, or&lt;/li&gt;
&lt;li&gt;&lt;code&gt;import { add } from &amp;quot;./my-library&amp;quot;&lt;/code&gt;, however causing unnecessary work to load and execute &lt;code&gt;my-library/sets.js&lt;/code&gt; (which is not used!).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With deferred re-exports, &lt;code&gt;my-library&lt;/code&gt; could mark its own &lt;code&gt;export ... from&lt;/code&gt; statements as &amp;quot;free to ignore if unused&amp;quot;:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// my-library/index.js&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; defer &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; add&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; multiply &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./arithmetic.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; defer &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; union&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; intersection &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./sets.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, when users do &lt;code&gt;import { add } from &amp;quot;./my-library.js&amp;quot;&lt;/code&gt;, &lt;code&gt;my-library/sets.js&lt;/code&gt; will not be loaded and executed: the decision whether it should actually be imported or not has been &lt;em&gt;deferred&lt;/em&gt; to &lt;code&gt;my-library&lt;/code&gt;&#39;s user, who decided to only import what was necessary for the &lt;code&gt;add&lt;/code&gt; function.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champion: Nicolò Ribaudo&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;progress-report-stage-1-proposals&quot; tabindex=&quot;-1&quot;&gt;Progress Report: &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;Stage 1&lt;/a&gt; Proposals &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;disposable-asynccontext-variable-to-stage-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-async-context-disposable&quot;&gt;Disposable &lt;code&gt;AsyncContext.Variable&lt;/code&gt;&lt;/a&gt; to Stage 1 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the AsyncContext proposal, you can&#39;t set the value of an &lt;code&gt;AsyncContext.Variable&lt;/code&gt;. Instead, you have the &lt;code&gt;.run&lt;/code&gt; method, which takes a callback, runs it with the updated state, and restores the previous value before returning. This offers strong encapsulation, making sure that no mutations can be leaked out of the scope. However, this also adds inflexibility in some cases, such as when refactoring a scope inside a function.&lt;/p&gt;
&lt;p&gt;The disposable &lt;code&gt;AsyncContext.Variable&lt;/code&gt; proposal extends the AsyncContext proposal by adding a way to set a variable without entering a new function scope, which builds on top of the &lt;a href=&quot;https://github.com/tc39/proposal-explicit-resource-management&quot;&gt;explicit resource management&lt;/a&gt; proposal and its &lt;code&gt;using&lt;/code&gt; keyword:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; asyncVar &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AsyncContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Variable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;gen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token comment&quot;&gt;// This code with `.run` would need heavy refactoring,&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token comment&quot;&gt;// since you can&#39;t yield from an inner function scope.&lt;/span&gt;&lt;br&gt;  using _ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; asyncVar&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;withValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createSpan&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;computeResult&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;computeResult2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token comment&quot;&gt;// The scope of `_` ends here, so `asyncVar` is restored&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token comment&quot;&gt;// to its previous value.&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One issue with this is that if the return value of &lt;code&gt;.withValue&lt;/code&gt; is not used with a &lt;code&gt;using&lt;/code&gt; declaration, the context will never be reset at the end of the scope; so when the current function returns, its caller will see an unexpected context (the context inside the function would leak to the outside). The &lt;a href=&quot;https://github.com/tc39/proposal-using-enforcement&quot;&gt;strict enforcement of &lt;code&gt;using&lt;/code&gt; proposal&lt;/a&gt; (currently stage 1) would prevent this from happening accidentally, but deliberately leaking the context would still be possible by calling &lt;code&gt;Symbol.enter&lt;/code&gt; but not &lt;code&gt;Symbol.dispose&lt;/code&gt;. (Note that context leaks are &lt;em&gt;not&lt;/em&gt; memory leaks.)&lt;/p&gt;
&lt;p&gt;The champions of this proposal explored how to deal with context leaks, and whether it&#39;s worth it, since preventing them would require changing the internal &lt;code&gt;using&lt;/code&gt; machinery and would make composition of disposables non-intuitive. These leaks are not &amp;quot;unsafe&amp;quot; since you can only observe them with access to the same &lt;code&gt;AsyncContext.Variable&lt;/code&gt;, but they are unexpected and hard to debug, and the champions do not know of any genuine use case for them.&lt;/p&gt;
&lt;p&gt;The committee resolved on advancing this proposal to stage 1, indicating that it is worth spending time on, but the exact semantics and behaviors still need to be decided.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champions: Chengzhong Wu, Luca Casonato, snek&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;stage-1-update-for-decimal-and-measure-amounts&quot; tabindex=&quot;-1&quot;&gt;Stage 1 update for &lt;a href=&quot;https://github.com/tc39/proposal-decimal&quot;&gt;decimal&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://github.com/tc39/proposal-measure&quot;&gt;measure&lt;/a&gt;: Amounts &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We presented the results of recent discussions in the overlap between the measure and decimal proposals having to do with what we call an Amount: a container for a number (a Decimal, a Number, a BigInt, a digit string) together with precision. The goal is to be able to represent a number that knows how precise it is. The presentation focused on how the notion of an Amount can solve the internationalization needs of the decimal proposal while, at the same time, serving as a building block on which the measure proposal can build by slotting in a unit (or currency). The committee was not quite convinced by this suggestion, but neither did they reject the idea. We have an active biweekly champions call dedicated to the topic of JS numerics, where we will iterate on these ideas and, in all likelihood, present them again to committee at the next TC39 plenary in May at Igalia headquarters in A Coruña. Stay tuned!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champions: Jesse Alama, Jirka Maršík, Andrew Paprocki&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;compare-strings-by-code-point&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-compare-strings-by-codepoint&quot;&gt;Compare strings by code point&lt;/a&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;String encoding in programming languages has come a long way since the Olden Times, when anything not 7-bit ASCII was implementation-defined. Now we have Unicode. 32 bits per character is a lot though, so there are various ways to encode Unicode strings that use less space. Common ones include UTF-8 and UTF-16.&lt;/p&gt;
&lt;p&gt;You can tell that JavaScript encodes strings as UTF-16 by the fact that string indexing &lt;code&gt;s[0]&lt;/code&gt; returns the first 2-byte code unit. Iterators, on the other hand, iterate through Unicode characters (&amp;quot;code points&amp;quot;). Explained in terms of pizza:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;🍕&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// code unit indexing&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token string&quot;&gt;&#39;&#92;ud83c&#39;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;🍕&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length  &lt;span class=&quot;token comment&quot;&gt;// length in 2-byte code units&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;🍕&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// code point indexing (by using iteration)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token string&quot;&gt;&#39;🍕&#39;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;🍕&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length  &lt;span class=&quot;token comment&quot;&gt;// length in code points&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&#39;s currently possible to compare JavaScript strings by code &lt;em&gt;units&lt;/em&gt; (the &lt;code&gt;&amp;lt;&lt;/code&gt; and &lt;code&gt;&amp;gt;&lt;/code&gt; operators and the array &lt;code&gt;sort()&lt;/code&gt; method) but there&#39;s no facility to compare strings by code &lt;em&gt;points&lt;/em&gt;. It requires writing complicated code yourself. This is unfortunate for interoperability with non-JS software such as databases, where comparisons are almost always by code point. Additionally, the problem is unique to UTF-16 encoding: with UTF-8 it doesn&#39;t matter if you compare by unit or point, because the results are the same.&lt;/p&gt;
&lt;p&gt;This is a completely new proposal and the committee decided to move it to stage 1. There&#39;s no proposed API yet, just a consensus to explore the problem space.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champions: Mathieu Hofman, Mark S. Miller, Christopher Hiller&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;don-t-remember-panicking-stage-1-update&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-oom-fails-fast&quot;&gt;Don&#39;t Remember Panicking&lt;/a&gt; Stage 1 Update &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This proposal discusses a taxonomy of possible errors that can occur when a JavaScript host runs out of memory (OOM) or space (OOS). It generated much discussion about how much can be reasonably expected of a JS host, especially when under such pressure. This question is particularly important for JS engines that are, by design, working with rather limited memory and space, such as embedded devices. There was no request for stage advancement, so the proposal stays at stage 1. A wide variety of options and ways in which to specify JS engine behavior under these extreme conditions were presented, so we can expect the proposal champions to iterate on the feedback they received and come back to plenary with a more refined proposal.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champions: Mark S. Miller, Peter Hoddie, Zbyszek Tenerowicz, Christopher Hiller&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;enums-for-stage-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-enum&quot;&gt;Enums&lt;/a&gt; for Stage 1 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/20/summary-of-the-april-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.typescriptlang.org/docs/handbook/enums.html&quot;&gt;Enums&lt;/a&gt; have been a staple of TypeScript for a long time, providing a type that represents a finite domain of named constant values. The reason to propose enums in JavaScript after all this time is that some modes of compilation, such as the &lt;a href=&quot;https://nodejs.org/docs/latest/api/typescript.html#type-stripping&quot;&gt;&amp;quot;type stripping&amp;quot;&lt;/a&gt; mode used by default in Node.js, can&#39;t support enums unless they&#39;re also part of JS.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;enum&lt;/span&gt; Numbers &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  zero &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  one &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  two &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;  alsoTwo &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; two&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// self-reference&lt;/span&gt;&lt;br&gt;  twoAgain &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Numbers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;two&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// also self-reference&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Numbers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;zero&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// 0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One notable difference with TS is that all members of the enum must have a provided initializer, since automatic numbering can easily cause accidental breaking changes. Having auto-initializers seems to be highly desirable, though, so some ways to extend the syntax to allow them are being considered.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champion: Ron Buckton&lt;/li&gt;
&lt;/ul&gt;
</content>
	</entry>
	
	<entry>
		<title>Boosting RISC-V Application Performance: An 8-Month LLVM Journey</title>
		<link href="https://blogs.igalia.com/compilers/2025/05/05/boosting-risc-v-application-performance-an-8-month-llvm-journey/"/>
		<updated>2025-05-05T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2025/05/05/boosting-risc-v-application-performance-an-8-month-llvm-journey/</id>
		<content type="html">&lt;p&gt;Over the past eight months, Igalia has been working through &lt;a href=&quot;https://riseproject.dev/&quot;&gt;RISE&lt;/a&gt; on the LLVM compiler, focusing on its RISC-V target. The goal is to improve the performance of generated code for application-class RISC-V processors, especially where there are gaps between LLVM and GCC RISC-V.
The result? A set of improvements that reduces execution time by &lt;strong&gt;up to 15%&lt;/strong&gt; on our &lt;a href=&quot;https://www.spec.org/cpu2017/&quot;&gt;SPEC CPU® 2017-based benchmark&lt;/a&gt; harness.&lt;/p&gt;
&lt;p&gt;In this blog post, I’ll walk through the challenges, the work we did across different areas of LLVM (including instruction scheduling, vectorization, and late-stage optimizations), and the resulting performance gains that demonstrate the power of targeted compiler optimization for the RISC-V architecture on current RVA22U64+V and future RVA23 hardware.&lt;/p&gt;
&lt;h1 id=&quot;understanding-the-landscape&quot; tabindex=&quot;-1&quot;&gt;&lt;strong&gt;Understanding the Landscape&lt;/strong&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/05/boosting-risc-v-application-performance-an-8-month-llvm-journey/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;First, to understand the work involved in optimizing the RISC-V performance, let’s briefly discuss the key components of this project: the RISC-V architecture itself, the LLVM compiler infrastructure, and the Banana Pi BPI-F3 board as our target platform.&lt;/p&gt;
&lt;h2 id=&quot;the-risc-v-architecture&quot; tabindex=&quot;-1&quot;&gt;&lt;strong&gt;The RISC-V Architecture&lt;/strong&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/05/boosting-risc-v-application-performance-an-8-month-llvm-journey/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;RISC-V is a modern, open-standard instruction set architecture (ISA) built around simplicity and extensibility. Unlike proprietary ISAs, RISC-V’s modular design allows implementers to choose from base instruction sets (e.g., RV32I, RV64I) and optional extensions (e.g., vector ops, compressed instructions). This flexibility makes it ideal for everything from microcontrollers to high-performance cores, while avoiding the licensing hurdles of closed ISAs. However, this flexibility also creates complexity: without guidance, developers might struggle to choose the right combination of extensions for their hardware.&lt;/p&gt;
&lt;p&gt;Enter RISC-V Profiles: standardized bundles of extensions that ensure software compatibility across implementations. For the BPI-F3’s CPU, the relevant profile is &lt;a href=&quot;https://github.com/riscv/riscv-profiles/blob/main/src/profiles.adoc#rva22u64-profile&quot;&gt;RVA22U64&lt;/a&gt;, which includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mandatory&lt;/strong&gt;: RV64GC (64-bit with general-purpose + compressed instructions), Zicsr (control registers), Zifencei (instruction-fetch sync), and more.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optional&lt;/strong&gt;: The Vector extension (V) v1.0 (for SIMD operations) and other accelerators.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We chose to focus our testing on two configurations: RVA22U64 (scalar) and RVA22U64+V (vector), since they cover a wide variety of hardware. It&#39;s also important to note that code generation for vector-capable systems (RVA22U64+V) differs significantly from scalar-only targets, making it crucial to optimize both paths carefully.&lt;/p&gt;
&lt;p&gt;RVA23U64, which mandates the vector extension, was not chosen because the BPI-F3 doesn’t support it.&lt;/p&gt;
&lt;h2 id=&quot;the-llvm-compiler&quot; tabindex=&quot;-1&quot;&gt;&lt;strong&gt;The LLVM compiler&lt;/strong&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/05/boosting-risc-v-application-performance-an-8-month-llvm-journey/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;LLVM is a powerful and widely used open-source compiler infrastructure. It&#39;s not a single compiler but rather a collection of modular and reusable compiler and toolchain technologies. LLVM&#39;s strength lies in its flexible and well-defined architecture, which allows it to efficiently compile code written in various source languages (like C, C++, Rust, etc.) for a multitude of target architectures, including RISC-V. A key aspect of LLVM is its optimization pipeline. This series of analysis and transformation passes works to improve the generated machine code in various ways, such as reducing the number of instructions, improving data locality, and exploiting target-specific hardware features.&lt;/p&gt;
&lt;h2 id=&quot;the-banana-pi-bpi-f3&quot; tabindex=&quot;-1&quot;&gt;&lt;strong&gt;The Banana Pi BPI-F3&lt;/strong&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/05/boosting-risc-v-application-performance-an-8-month-llvm-journey/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/syFe9bWWc3-1984.avif 1984w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/syFe9bWWc3-1984.webp 1984w&quot;&gt;&lt;img alt=&quot;Banana PI BPI-F3 board&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/syFe9bWWc3-1984.jpeg&quot; width=&quot;1984&quot; height=&quot;1197&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The Banana Pi BPI-F3 is a board featuring a SpacemiT K1 8-core RISC-V chip: PU integrates 2.0 TOPs AI computing power. 2/4/8/16G DDR and 8/16/32/128G eMMC onboard.2x GbE Ethernet port, 4x USB 3.0 and PCIe for M.2 interface, support HDMI and Dual MIPI-CSI Camera.&lt;/p&gt;
&lt;p&gt;Most notably, the RISC-V CPU supports the RVA22U64 Profile and 256-bit RVV 1.0 standard.&lt;/p&gt;
&lt;h1 id=&quot;8-months-of-optimizations&quot; tabindex=&quot;-1&quot;&gt;&lt;strong&gt;8 Months of Optimizations&lt;/strong&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/05/boosting-risc-v-application-performance-an-8-month-llvm-journey/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Let&#39;s define the testing environment. We use the training dataset on SPEC CPU® 2017-based benchmark to measure the impact of changes to the LLVM codebase. We do not use the reference dataset for practical reasons, i.e., the training dataset finishes in hours instead of days.&lt;/p&gt;
&lt;p&gt;The benchmarks were executed on the BPI-F3, running Arch Linux and Kernel 6.1.15. The configuration of each compiler invocation is as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LLVM at the start of the project (commit cd0373e0)&lt;/strong&gt;: SPEC benchmarks built with optimization level 3 (-O3), and LTO enabled (-flto). We’ll show the results using both RVA22U64 (-march=rva22u64) and the RVA22U64+V profiles (-march=rva22u64_v).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LLVM today (commit b48c476f)&lt;/strong&gt;: SPEC benchmarks built with optimization level 3 (-O3), LTO enabled (-flto), tuned for the SpacemiT-X60 (-mcpu=spacemit-x60), and IPRA enabled (-mllvm -enable-ipra -Wl,-mllvm,-enable-ipra). We’ll also show the results using both RVA22U64 (-march=rva22u64) and the RVA22U64+V profile (-march=rva22u64_v).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GCC 14.2&lt;/strong&gt;: SPEC benchmarks built with optimization level 3 (-O3), and LTO enabled (-flto). GCC 14.2 doesn&#39;t support profile names in -march, so a functionally equivalent ISA naming string was used (skipping the assortment of extensions that don&#39;t affect codegen and aren&#39;t recognised by GCC 14.2) for both RVA22U64 and RVA22U64+V.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The following graph shows the improvements in execution time of the SPEC benchmarks from the start of the project (light blue bar) to today (dark blue bar) using the &lt;strong&gt;RVA22U64&lt;/strong&gt; profile, on the BPI-F3. Note that these include not only my contributions but also the improvements of all other individuals working on the RISC-V backend. We also include the results of GCC 14.2 for comparison (orange bar). Our contributions will be discussed later.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/5PBZLDstSq-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/5PBZLDstSq-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;Overall RVA22U64 improvements&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/5PBZLDstSq-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Full data available at &lt;a href=&quot;https://lnt.lukelau.me/db_default/v4/nts/507?compare_to=494&quot;&gt;https://lnt.lukelau.me/db_default/v4/nts/507?compare_to=494&lt;/a&gt;, including code size gains.&lt;/p&gt;
&lt;p&gt;The graph is sorted by the execution time improvements brought by the new scheduling model. We see improvements across almost all benchmarks, from small gains in 531.deepsjeng_r (3.63%) to considerable ones in 538.imagick_r (19.67%) and 508.namd_r (25.73%). There were small regressions in the execution time of 510.parest_r (-3.25%); however, 510.parest_r results &lt;a href=&quot;https://lnt.lukelau.me/db_default/v4/nts/graph?highlight_run=488&amp;amp;plot.2=25.2.3&quot;&gt;vary greatly in daily tests&lt;/a&gt;, so it might be just noise. Five benchmarks are within 1% of previous results, so we assume there was no impact on their execution time.&lt;/p&gt;
&lt;p&gt;When compared to GCC, LLVM today is faster in 11 out of the 16 tested benchmarks (up to 23.58% faster than GCC in 541.leela_r), while being slower in three benchmarks (up to 6.51% slower than GCC in 510.parest_r). Current LLVM and GCC are within 1% of each other in the other two benchmarks. Compared to the baseline of the project, GCC was faster in ten benchmarks (up to 26.83% in 508.namd_r) while being slower in only five.&lt;/p&gt;
&lt;p&gt;Similarly, the following graph shows the improvements in the execution time of SPEC benchmarks from the start of the project (light blue bar) to today (dark blue bar) on the BPI-F3, but this time with the &lt;strong&gt;RVA22U64+V&lt;/strong&gt; profile, i.e., the &lt;strong&gt;RVA22U64&lt;/strong&gt; plus the vector extension (&lt;strong&gt;V&lt;/strong&gt;) enabled. Again, GCC results are included (orange bar), and the graph shows all improvements gained during the project.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/TraC_OKyBH-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/TraC_OKyBH-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;Overall RVA22U64+V improvements&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/TraC_OKyBH-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Full data available at &lt;a href=&quot;https://lnt.lukelau.me/db_default/v4/nts/527?compare_to=500&quot;&gt;https://lnt.lukelau.me/db_default/v4/nts/527?compare_to=500&lt;/a&gt;, including code size gains.&lt;/p&gt;
&lt;p&gt;The graph is sorted by the execution time improvements brought by the new scheduling model. The results for RVA22U64+V follow a similar trend, and we see improvements in almost all benchmarks. From 4.91% in 500.perlbench_r to (again) a considerable 25.26% improvement in 508.namd_r. Similar to the RVA22U64 results, we see a couple of regressions: 510.parest_r with (-3.74%) and 523.xalancbmk_r (-6.01%). Similar to the results on RVA22U64, &lt;a href=&quot;https://lnt.lukelau.me/db_default/v4/nts/graph?highlight_run=502&amp;amp;plot.0=25.12.3&quot;&gt;523.xalancbmk_r&lt;/a&gt;, and &lt;a href=&quot;https://lnt.lukelau.me/db_default/v4/nts/graph?highlight_run=488&amp;amp;plot.2=25.2.3&quot;&gt;510.parest_r&lt;/a&gt; vary greatly in daily tests on RVA22u64+V, so these regressions are likely noise. Four benchmarks are within 1% of previous results, so we assume there was no impact on their execution time.&lt;/p&gt;
&lt;p&gt;When compared to GCC, LLVM today is faster in 10 out of the 16 tested benchmarks (up to 23.76% faster than GCC in 557.xz_r), while being slower in three benchmark (up to 5.58% slower in 538.imagick_r). LLVM today and GCC are within 1-2% of each other in the other three benchmarks. Compared to the baseline of the project, GCC was faster in eight benchmarks (up to 25.73% in 508.namd_r) while being slower in five.&lt;/p&gt;
&lt;h1 id=&quot;our-contributions&quot; tabindex=&quot;-1&quot;&gt;Our Contributions &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/05/boosting-risc-v-application-performance-an-8-month-llvm-journey/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Over the past eight months, our efforts have concentrated on several key areas within the LLVM compiler infrastructure to specifically target and improve the efficiency of RISC-V code generation. These contributions have involved delving into various stages of the compilation process, from instruction selection to instruction scheduling. Here, we&#39;ll focus on three major areas where substantial progress has been made:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Introducing a scheduling model for the hardware used for benchmarking (SpacemiT-X60)&lt;/strong&gt;: LLVM had no scheduling model for the SpacemiT-X60, leading to pessimistic and inefficient code generation. We added a model tailored to the X60’s pipeline, allowing LLVM to better schedule instructions and improve performance. Longer term, a more generic in-order model could be introduced in LLVM to help other RISC-V targets that currently lack scheduling information, similar to how it’s already done for other targets, e.g., &lt;a href=&quot;https://github.com/llvm/llvm-project/commit/adec9223616477df023026b0269ccd008701cc94#diff-eeb994156ce5a953d60e317feb429413892822c4d8603fd5281d1cd8bc9d2e6a&quot;&gt;Aarch64&lt;/a&gt;. This contribution alone brings up to 15.76% improvement on the execution time of SPEC benchmarks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Improved Vectorization Efficiency&lt;/strong&gt;: LLVM’s SLP vectorizer used to skip over entire basic blocks when calculating spill costs, leading to inaccurate estimations and suboptimal vectorization when functions were present in the skipped blocks. We addressed this by improving the backward traversal to consider all relevant blocks, ensuring spill costs were properly accounted for. The final solution, contributed by the SLP Vectorizer maintainer, was to fix the issue without impacting compile times, unlocking better vectorization decisions and performance. This contribution brings up to 11.87% improvement on the execution time of SPEC benchmarks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Register Allocation with IPRA Support&lt;/strong&gt;: enabling Inter-Procedural Register Allocation (IPRA) to the RISC-V backend. IPRA reduces save/restore overhead across function calls by tracking which registers are used. In the RISC-V backend, supporting IPRA required implementing a hook to report callee-saved registers and prevent miscompilation. This contribution brings up to 3.42% improvement on the execution time of SPEC benchmarks.&lt;/p&gt;
&lt;h2 id=&quot;spacemit-x60-scheduler-model&quot; tabindex=&quot;-1&quot;&gt;SpacemiT-X60 Scheduler Model &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/05/boosting-risc-v-application-performance-an-8-month-llvm-journey/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;PR: &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/137343&quot;&gt;https://github.com/llvm/llvm-project/pull/137343&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The biggest contribution so far is the scheduler modeling tailored for the SpacemiT-X60. This scheduler is integrated into LLVM&#39;s backend and is designed to optimize instruction ordering based on the specific characteristics of the &lt;a href=&quot;https://developer.spacemit.com/documentation?token=Alhewa0fai7lvbk9sajcumNqn4f&quot;&gt;X60 CPU&lt;/a&gt;.​&lt;/p&gt;
&lt;p&gt;The scheduler was introduced in PR &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/137343&quot;&gt;137343&lt;/a&gt;. It includes detailed scheduling models that account for the X60&#39;s pipeline structure, instruction latencies for all scalar instructions, and resource constraints. The current scheduler model does not include latencies for vector instructions, but it is a planned future work.  By providing LLVM with accurate information about the target architecture, the scheduler enables more efficient instruction scheduling, reducing pipeline stalls and improving overall execution performance.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/ZA53snFLZv-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/ZA53snFLZv-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;Execution time improvements on RVA22U64 from the Scheduler model&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/ZA53snFLZv-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Full data available at &lt;a href=&quot;https://lnt.lukelau.me/db_default/v4/nts/471?compare_to=405&quot;&gt;https://lnt.lukelau.me/db_default/v4/nts/471?compare_to=405&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The graph is sorted by the execution time improvements brought by the new scheduling model.  The introduction of a dedicated scheduler yielded substantial performance gains. Execution time improvements were observed across several benchmarks, ranging from 1.04% in 541.leela_r to 15.76% in 525.x264_r.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/rBjEhHy97o-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/rBjEhHy97o-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;Execution time improvements on RVA22U64+V from the Scheduler model&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/rBjEhHy97o-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Full data available at &lt;a href=&quot;https://lnt.lukelau.me/db_default/v4/nts/474?compare_to=404&quot;&gt;https://lnt.lukelau.me/db_default/v4/nts/474?compare_to=404&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Additionally, the scheduler brings significant benefits even when vector extensions are enabled, as shown above. The graph is sorted by the execution time improvements brought by the new scheduling model. Execution time improvements range from 3.66% in 544.nab_r to 15.58% in 508.namd_r, with notable code size reductions as well, e.g., a 6.47% improvement in 519.lbm_r (due to decreased register spilling).&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/ylr58_nBQb-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/ylr58_nBQb-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;RVA22U64 vs RVA22U64+V&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/ylr58_nBQb-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Full data available at: &lt;a href=&quot;https://lnt.lukelau.me/db_default/v4/nts/474?compare_to=471&quot;&gt;https://lnt.lukelau.me/db_default/v4/nts/474?compare_to=471&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Finally, the previous graph shows the comparison between RVA22U64 vs RVA22U64+V, both with the X60 scheduling model enabled. The only difference is 525.x264_r: it is 17.48% faster on RVA22U64+V.&lt;/p&gt;
&lt;p&gt;A key takeaway from these results is the critical importance of scheduling for in-order processors like the SpacemiT-X60. The new scheduler effectively closed the performance gap between the scalar (RVA22U64) and vector (RVA22U64+V) configurations, with the vector configuration now outperforming only in a single benchmark (525.x264_r). On out-of-order processors, the impact of scheduling would likely be smaller, and vectorization would be expected to deliver more noticeable gains.&lt;/p&gt;
&lt;h2 id=&quot;slp-vectorizer-spill-cost-fix-dag-combiner-tuning&quot; tabindex=&quot;-1&quot;&gt;SLP Vectorizer Spill Cost Fix + DAG Combiner Tuning &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/05/boosting-risc-v-application-performance-an-8-month-llvm-journey/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;PR 1 (not landed): &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/128620&quot;&gt;https://github.com/llvm/llvm-project/pull/128620&lt;/a&gt;
PR 2 (landed): &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/129258&quot;&gt;https://github.com/llvm/llvm-project/pull/129258&lt;/a&gt;
PR 3 (landed): &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/130430&quot;&gt;https://github.com/llvm/llvm-project/pull/130430&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;One surprising outcome in early benchmarking was that scalar code sometimes outperformed vectorized code, despite RISC-V vector support being available. This result prompted a detailed investigation.&lt;/p&gt;
&lt;p&gt;Using profiling data, we noticed increased cycle counts around loads and stores in vectorized functions; the extra cycles were due to register spilling, particularly around function call boundaries. Digging further, we found that the SLP Vectorizer was aggressively vectorizing regions without properly accounting for the cost of spilling vector registers across calls.&lt;/p&gt;
&lt;p&gt;To understand how spill cost miscalculations led to poor vectorization decisions, consider this simplified function, and its graph representation:&lt;/p&gt;
&lt;center&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;text-align:left&quot;&gt;&lt;code&gt;declare void @g()&lt;/code&gt;&lt;br&gt;&lt;br&gt;&lt;code&gt;define void @f(i1 %c, ptr %p, ptr %q) {&lt;/code&gt;&lt;br&gt;&lt;code&gt;entry:&lt;/code&gt;&lt;br&gt;    &lt;code&gt;%x0 = load i64, ptr %p&lt;/code&gt;  &lt;br&gt;  &lt;code&gt;  %p1 =  getelementptr i64, ptr %p, i64 1&lt;/code&gt;&lt;br&gt;  &lt;code&gt;  %x1 = load i64, ptr %p1&lt;/code&gt;&lt;br&gt;  &lt;code&gt;  br i1 %c, label %foo, label %bar&lt;/code&gt;&lt;br&gt;&lt;code&gt;foo:&lt;/code&gt;&lt;br&gt;  &lt;code&gt;  call void @g()&lt;/code&gt;&lt;br&gt;  &lt;code&gt;  br label %baz&lt;/code&gt;&lt;br&gt;&lt;code&gt;bar:&lt;/code&gt;&lt;br&gt;  &lt;code&gt;  call void @g()&lt;/code&gt;&lt;br&gt;  &lt;code&gt;  br label %baz&lt;/code&gt;&lt;br&gt;&lt;code&gt;baz:&lt;/code&gt;&lt;br&gt;  &lt;code&gt;  store i64 %x0, ptr %q&lt;/code&gt;&lt;br&gt;  &lt;code&gt;  %q1 =  getelementptr i64, ptr %q, i64 1&lt;/code&gt;&lt;br&gt;  &lt;code&gt;  store i64 %x1, ptr %q1&lt;/code&gt;&lt;br&gt;  &lt;code&gt;  ret void&lt;/code&gt;&lt;br&gt;&lt;code&gt;}&lt;/code&gt;&lt;br&gt;&lt;/th&gt;
&lt;th&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/B7gzCRYlU4-307.avif 307w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/B7gzCRYlU4-307.webp 307w&quot;&gt;&lt;img alt=&quot;Graph representation of the program above&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/B7gzCRYlU4-307.png&quot; width=&quot;307&quot; height=&quot;306&quot;&gt;&lt;/picture&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;/table&gt;
&lt;/center&gt;
&lt;p&gt;This function loads two values from &lt;code&gt;%p&lt;/code&gt;, conditionally calls &lt;code&gt;@g()&lt;/code&gt; (in both foo and bar), and finally stores the values to &lt;code&gt;%q&lt;/code&gt;. Previously, the SLP vectorizer only analyzed the &lt;code&gt;entry&lt;/code&gt; and &lt;code&gt;baz&lt;/code&gt; blocks, ignoring &lt;code&gt;foo&lt;/code&gt; and &lt;code&gt;bar&lt;/code&gt; entirely. As a result, it missed the fact that both branches contain a call, which increases the cost of spilling vector registers. This led LLVM to vectorize loads and stores here, introducing unprofitable spills across the calls to &lt;code&gt;@g()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To address the issue, we first proposed PR &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/128620&quot;&gt;128620&lt;/a&gt;, which modified the SLP vectorizer to properly walk through all basic blocks when analyzing cost. This allowed the SLP vectorizer to correctly factor in function calls and estimate the spill overhead more accurately.&lt;/p&gt;
&lt;p&gt;The results were promising: execution time dropped by 9.92% in 544.nab_r, and code size improved by 1.73% in 508.namd_r. However, the patch also increased compile time in some cases (e.g., +6.9% in 502.gcc_r), making it unsuitable for upstream merging.&lt;/p&gt;
&lt;p&gt;Following discussions with the community, Alexey Bataev (SLP Vectorizer code owner) proposed a refined solution in PR &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/129258&quot;&gt;129258&lt;/a&gt;. His patch achieved the same performance improvements without any measurable compile-time overhead and was subsequently merged.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/aESVuEJSZ0-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/aESVuEJSZ0-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;RVA22U64+V execution time improvements from the SLP fix&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/aESVuEJSZ0-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Full data available at &lt;a href=&quot;https://lnt.lukelau.me/db_default/v4/nts/288?compare_to=281&quot;&gt;https://lnt.lukelau.me/db_default/v4/nts/288?compare_to=281&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The graph shows execution time improvements from Alexey’s patch, ranging from 1.49% in 500.perlbench_r to 11.87% in 544.nab_r. Code size also improved modestly, with a 2.20% reduction in 508.namd_r.&lt;/p&gt;
&lt;p&gt;RVA22U64 results are not shown since this is an optimization tailored to prevent the spill of vectors. Scalar code was not affected by this change.&lt;/p&gt;
&lt;p&gt;Finally, PR &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/130430&quot;&gt;130430&lt;/a&gt; addressed the same issue in the DAG Combiner by preventing stores from being merged across call boundaries. While this change had minimal impact on performance in the current benchmarks, it improves code correctness and consistency and may benefit other workloads in the future.&lt;/p&gt;
&lt;h2 id=&quot;ipra-inter-procedural-register-allocation-support&quot; tabindex=&quot;-1&quot;&gt;IPRA (Inter-Procedural Register Allocation) Support &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/05/boosting-risc-v-application-performance-an-8-month-llvm-journey/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;GitHub PR: &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/125586&quot;&gt;https://github.com/llvm/llvm-project/pull/125586&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Inter-Procedural Register Allocation (IPRA) is a compiler optimization technique that aims to reduce the overhead of saving and restoring registers across function calls. By analyzing the entire program, IPRA determines which registers are used across function boundaries, allowing the compiler to avoid unnecessary save/restore operations.​&lt;/p&gt;
&lt;p&gt;In the context of the RISC-V backend in LLVM, enabling IPRA required implementing a hook in LLVM. This hook informs the compiler that callee-saved registers should always be saved in a function, ensuring that critical registers like the return address register (ra) are correctly preserved. Without this hook, enabling IPRA would lead to miscompilation issues, e.g., 508.namd_r would never finish running (probably stuck in an infinite loop).&lt;/p&gt;
&lt;p&gt;To understand how IPRA works, consider the following program before IPRA. Let’s assume function &lt;code&gt;foo&lt;/code&gt; uses &lt;code&gt;s0&lt;/code&gt; but doesn&#39;t touch &lt;code&gt;s1&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# Function bar calls foo and conservatively saves all callee-saved registers.
bar:
    addi  sp, sp, -32
    sd    ra, 16(sp)     # Save return address (missing before our PR)
    sd    s0, 8(sp)
    sd    s1, 0(sp)      # Unnecessary spill (foo won&#39;t clobber s1)
    call  foo
    ld    s1, 0(sp)      # Wasted reload
    ld    s0, 8(sp)
    ld    ra, 16(sp)
    addi  sp, sp, 32
    ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After IPRA (optimized spills):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# bar now knows foo preserves s1: no s1 spill/reload.
bar:
    addi  sp, sp, -16
    sd    ra, 8(sp)     # Save return address (missing before our PR)
    sd    s0, 0(sp)
    call  foo
    ld    s0, 0(sp)
    ld    ra, 8(sp)
    addi  sp, sp, 16
    ret
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By enabling IPRA for RISC-V, we eliminated redundant spills and reloads of callee-saved registers across function boundaries. In our example, IPRA reduced stack usage and cut unnecessary memory accesses. Crucially, the optimization maintains correctness: preserving the return address (ra) while pruning spills for registers like s1 when provably unused. Other architectures like x86 already support IPRA in LLVM, and we enable IPRA for RISC-V PR &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/125586&quot;&gt;125586&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;IPRA is not enabled by default due to a bug, described in issue &lt;a href=&quot;https://github.com/llvm/llvm-project/issues/119556&quot;&gt;119556&lt;/a&gt;; however, it does not affect the SPEC benchmarks.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/43C1GpCU3y-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/43C1GpCU3y-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;Execution time improvements on RVA22U64 from the IPRA fix&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/43C1GpCU3y-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Full data available at &lt;a href=&quot;https://lnt.lukelau.me/db_default/v4/nts/507?compare_to=526&quot;&gt;https://lnt.lukelau.me/db_default/v4/nts/507?compare_to=526&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The graph shows the improvements achieved by this transformation alone, using the RVA22U64 profile. There were execution time improvements ranging from 1.57% in 505.mcf_r to 3.16% in 519.lbm_r.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bcq3qs-tXD-1280.avif 1280w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bcq3qs-tXD-1280.webp 1280w&quot;&gt;&lt;img alt=&quot;Execution time improvements on RVA22U64+V from the IPRA fix&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bcq3qs-tXD-1280.png&quot; width=&quot;1280&quot; height=&quot;720&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Full data available at &lt;a href=&quot;https://lnt.lukelau.me/db_default/v4/nts/527?compare_to=525&quot;&gt;https://lnt.lukelau.me/db_default/v4/nts/527?compare_to=525&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The graph shows the improvements achieved by this transformation alone, using the RVA22U64+V profile. We see similar gains, with execution time improvements of 1.14% in 505.mcf_r and 3.42% in 531.deepsjeng_r.&lt;/p&gt;
&lt;p&gt;While we initially looked at code size impact, the improvements were marginal. Given that save/restore sequences tend to be a small fraction of total size, this isn&#39;t surprising and not the main goal of this optimization.&lt;/p&gt;
&lt;h1 id=&quot;challenges-and-lessons-learned&quot; tabindex=&quot;-1&quot;&gt;Challenges and Lessons Learned &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/05/boosting-risc-v-application-performance-an-8-month-llvm-journey/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Setting Up Reliable Performance Testing.&lt;/strong&gt; A key part of this project was being able to measure the impact of our changes consistently and meaningfully. For that, we used &lt;a href=&quot;https://llvm.org/docs/lnt/intro.html&quot;&gt;LNT&lt;/a&gt;, LLVM’s performance testing tool, to automate test builds, runs, and result comparisons. Once set up, LNT allowed us to identify regressions early, track improvements over time, and visualize the impact of each patch through clear graphs.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reducing Noise on the BPI-F3.&lt;/strong&gt; Benchmarking is noisy by default, and it took considerable effort to reduce variability between runs. These steps helped:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Disabling ASLR: To ensure a more deterministic memory layout.&lt;/li&gt;
&lt;li&gt;Running one benchmark at a time on the same core: This helped eliminate cross-run contention and improved result consistency.&lt;/li&gt;
&lt;li&gt;Multiple samples per benchmark: We collected 3 samples to compute statistical confidence and reduce the impact of outliers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These measures significantly reduced noise, allowing us to detect even small performance changes with confidence.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interpreting Results and Debugging Regressions.&lt;/strong&gt; Another challenge was interpreting performance regressions or unexpected results. Often, regressions weren&#39;t caused by the patch under test, but by unrelated interactions with the backend. This required:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cross-checking disassembly between runs.&lt;/li&gt;
&lt;li&gt;Profiling with hardware counters (e.g., using &lt;a href=&quot;https://github.com/preames/public-notes/blob/5d2c79f3a05457cfdba2ec88a26028cf309ffc35/riscv/bp3-setup.rst#id5&quot;&gt;perf&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Identifying missed optimization opportunities due to incorrect cost models or spill decisions.&lt;/li&gt;
&lt;li&gt;Comparing scalar vs vector codegen and spotting unnecessary spills or register pressure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;My colleague Luke Lau also set up a &lt;a href=&quot;https://lnt.lukelau.me/db_default/v4/nts/recent_activity&quot;&gt;centralized LNT instance&lt;/a&gt; that runs nightly tests. This made it easy to detect and track performance regressions (or gains) shortly after new commits landed. When regressions did appear, we could use the profiles and disassembly generated by LNT to narrow down which functions were affected, and why.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Using llvm-exegesis (sort of).&lt;/strong&gt; At the start of the project, &lt;a href=&quot;https://llvm.org/docs/CommandGuide/llvm-exegesis.html&quot;&gt;llvm-exegesis&lt;/a&gt;, the tool LLVM provides to measure instruction latencies and throughput, didn’t support RISC-V at all. Over time, support was added incrementally across three patches: first for basic arithmetic instructions, then load instructions, and eventually vector instructions. This made it a lot more viable as a tool for microarchitectural analysis on RISC-V. However, despite this progress, we ultimately didn’t use llvm-exegesis to collect the latency data for our scheduling model. The results were too noisy, and we needed more control over how measurements were gathered. Instead, we developed an internal tool to generate the latency data, something we plan to share in the future.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Notable Contributions Without Immediate Benchmark Impact.&lt;/strong&gt; While some patches may not have led to significant performance improvements in benchmarks, they were crucial for enhancing the RISC-V backend&#39;s robustness and maintainability:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Improved Vector Handling in matchSplatAsGather (PR &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/117878&quot;&gt;#117878&lt;/a&gt;): This patch updated the matchSplatAsGather function to handle vectors of different sizes, enhancing code generation for @llvm.experimental.vector.match on RISC-V.&lt;/li&gt;
&lt;li&gt;Addition of FMA Cost Model (PRs &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/125683&quot;&gt;#125683&lt;/a&gt; and &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/126076&quot;&gt;#126076&lt;/a&gt;): These patches extended the cost model to cover the FMA instruction, ensuring accurate cost estimations for fused multiply-add operations.&lt;/li&gt;
&lt;li&gt;Generalization of vp_fneg Cost Model (PR &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/126915&quot;&gt;#126915&lt;/a&gt;): This change moved the cost model for vp_fneg from the RISC-V-specific implementation to the generic Target Transform Info (TTI) layer, promoting consistent handling across different targets.&lt;/li&gt;
&lt;li&gt;Late Conditional Branch Optimization for RISC-V (PR &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/133256&quot;&gt;#133256&lt;/a&gt;): Introduced a late RISC-V-specific optimization pass that replaces conditional branches with unconditional ones when the condition can be statically evaluated. This creates opportunities for further branch folding and cleanup later in the pipeline. While performance impact was limited in current benchmarks, it lays the foundation for smarter late-stage CFG optimizations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These contributions, while not directly impacting benchmark results, laid the groundwork for future improvements.&lt;/p&gt;
&lt;h1 id=&quot;the-future-of-risc-v-in-llvm&quot; tabindex=&quot;-1&quot;&gt;The Future of RISC-V in LLVM &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/05/boosting-risc-v-application-performance-an-8-month-llvm-journey/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This project significantly improved the performance of the RISC-V backend in LLVM through a combination of targeted optimizations, infrastructure improvements, and upstream contributions. We tackled key issues in vectorization, register allocation, and scheduling, demonstrating that careful backend tuning can yield substantial real-world benefits, especially on in-order cores like the SpacemiT-X60.&lt;/p&gt;
&lt;p&gt;Future Work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Vector latency modeling&lt;/strong&gt;: The current scheduling model lacks accurate latencies for vector instructions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Further scheduling model fine-tuning&lt;/strong&gt;: This would impact the largest number of users and would align RISC-V with other targets in LLVM.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improve vectorization&lt;/strong&gt;: The similar performance between scalar and vectorized code suggests we are not fully exploiting vectorization opportunities. Deeper analysis might uncover missed cases or necessary model tuning.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improvements to DAGCombine&lt;/strong&gt;: after PR &lt;a href=&quot;https://github.com/llvm/llvm-project/pull/130430&quot;&gt;130430&lt;/a&gt;, Philip Reames created issue &lt;a href=&quot;https://github.com/llvm/llvm-project/issues/132787&quot;&gt;132787&lt;/a&gt; with ideas to improve the store merging code.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;acknowledgments&quot; tabindex=&quot;-1&quot;&gt;Acknowledgments &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/05/05/boosting-risc-v-application-performance-an-8-month-llvm-journey/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This work was made possible thanks to support from RISE, under Research Project RP009. I would like to thank my colleagues &lt;a href=&quot;https://igalia.com/team/luke&quot;&gt;Luke Lau&lt;/a&gt; and &lt;a href=&quot;https://igalia.com/team/asb&quot;&gt;Alex Bradbury&lt;/a&gt; for their ongoing technical collaboration and insight throughout the project. I’m also grateful to Philip Reames from Rivos for his guidance and feedback. Finally, a sincere thank you to all the reviewers in the LLVM community who took the time to review, discuss, and help shape the patches that made these improvements possible.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Summary of the February 2025 TC39 plenary</title>
		<link href="https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/"/>
		<updated>2025-03-27T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/</id>
		<content type="html">&lt;p&gt;The February TC39 meeting in Seattle wrapped up with significant updates and advancements in ECMAScript, setting an exciting trajectory for the language&#39;s evolution. Here are the key highlights, proposal advancements, and lively discussions from the latest plenary.&lt;/p&gt;
&lt;h2 id=&quot;proposals-advancing-to-stage-4&quot; tabindex=&quot;-1&quot;&gt;Proposals advancing to Stage 4 🎉 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The following proposals advanced to stage 4 early in the meeting, officially becoming a part of ECMAScript 2025. Congratulations to the people who shepherded them through the standardization process!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float16Array&quot;&gt;&lt;strong&gt;Float16Array&lt;/strong&gt;&lt;/a&gt;: a typed array that uses 16-bit floating point values, mostly for interfacing with other systems that need 16-bit float arrays.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champions: Leo Balter, Kevin Gibbons&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/escape&quot;&gt;&lt;strong&gt;RegExp.escape()&lt;/strong&gt;&lt;/a&gt;: Sanitizes a string so that it can be used as a string literal pattern for the RegExp constructor.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champions: Kevin Gibbons, Jordan Harband&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tc39/proposal-redeclarable-global-eval-vars&quot;&gt;&lt;strong&gt;Redeclarable global eval vars&lt;/strong&gt;&lt;/a&gt; simplifies the mental model of global properties. It&#39;s no longer an error to redeclare a &lt;code&gt;var&lt;/code&gt; or &lt;code&gt;function&lt;/code&gt; global property with a &lt;code&gt;let&lt;/code&gt; or &lt;code&gt;const&lt;/code&gt; of the same name.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champion: Shu-yu Guo&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;stage-changes&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;Stage changes&lt;/a&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;import-defer-reaches-stage-3&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-defer-import-eval/&quot;&gt;&lt;code&gt;import defer&lt;/code&gt;&lt;/a&gt; reaches Stage 3 &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now with full test262 coverage, the &lt;code&gt;import defer&lt;/code&gt; proposal advanced to stage 3, without changes since its previous presentation. This is the signal for implementors to go ahead and implement it. This means that the proposal is likely to appear soon in browsers!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champion: Nicolò Ribaudo &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/pkjMZ4BUKM-16.avif 16w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/pkjMZ4BUKM-16.webp 16w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/pkjMZ4BUKM-16.png&quot; width=&quot;16&quot; height=&quot;16&quot;&gt;&lt;/picture&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;math-clamp-reaches-stage-1&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-math-clamp&quot;&gt;&lt;code&gt;Math.clamp&lt;/code&gt;&lt;/a&gt; reaches Stage 1 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To clamp a number &lt;em&gt;x&lt;/em&gt; to an interval [&lt;em&gt;a&lt;/em&gt;, &lt;em&gt;b&lt;/em&gt;] means to produce a value no smaller than &lt;em&gt;a&lt;/em&gt; and no greater than &lt;em&gt;b&lt;/em&gt; (returning &lt;em&gt;x&lt;/em&gt; if &lt;em&gt;x&lt;/em&gt; is in the interval). Oliver Medhurst presented a neat little proposal to add this feature to JS&#39;s &lt;code&gt;Math&lt;/code&gt; standard library object. And Oliver was able to convince the committee to advance the discussion to stage 1.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champion: Oliver Medhurst&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;error-stack-accessor-reaches-stage-2&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/ljharb/proposal-error-stack-accessor&quot;&gt;Error stack accessor&lt;/a&gt; reaches stage 2 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Instances of &lt;code&gt;Error&lt;/code&gt; and its subclasses have a &lt;code&gt;stack&lt;/code&gt; property that returns a string representing the stack trace. However, this property is not specified, and &lt;a href=&quot;https://github.com/tc39/proposal-error-stacks&quot;&gt;previous attempts to define it in the spec&lt;/a&gt; did not get far because different JS engines have different string representations for the stack trace, and implementations can&#39;t converge on one behavior because there&#39;s code in the wild that does browser detection to know how to parse the format.&lt;/p&gt;
&lt;p&gt;In December it was decided that specifying the presence of a &lt;code&gt;stack&lt;/code&gt; property should be split off of the error stack proposal. This new error stack accessor proposal was first presented in this plenary, where it reached stage 2. The proposal achieves some amount of browser alignment on some details (e.g. is &lt;code&gt;stack&lt;/code&gt; an own property? is it a getter/setter pair?), while also providing a specified base on which other proposals and web specs can build, but it leaves the stack trace string implementation-defined.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champions: Jordan Harband, Mark S. Miller&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;proposal-number-issafenumeric&quot; tabindex=&quot;-1&quot;&gt;Proposal &lt;a href=&quot;https://github.com/Lxxyx/proposal-number-is-safe-numeric&quot;&gt;&lt;code&gt;Number.isSafeNumeric&lt;/code&gt;&lt;/a&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;New TC39 contributor ZiJian Liu offered a suggestion for tackling a problem routinely faced by JS programmers who work closely with numbers:
&amp;quot;&lt;em&gt;Am I sure that this numeric string S, if interpreted as a JS number, is going to be exactly preserved?&lt;/em&gt;&amp;quot;&lt;/p&gt;
&lt;p&gt;The proposal is a new method on Numbers, &lt;code&gt;isSafeNumeric&lt;/code&gt;, that would allow us to check this in advance. Essentially, ZiJian is trying to delimit a safe space for JS numbers. The discussion was heated, with many in the committee not sure what it &lt;em&gt;actually&lt;/em&gt; means for a numeric string to be &amp;quot;preserved&amp;quot;, and whether it can even be solved at all. Others thought that, although there may be no solution, it&#39;s worth advancing the proposal to stage 1 to begin to explore the space. Ultimately, the proposal did not advance to stage 1, but that doesn&#39;t mean it&#39;s the end—this topic may well come back in a sharper, more clearly defined form later on.&lt;/p&gt;
&lt;h2 id=&quot;temporal&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-temporal&quot;&gt;Temporal&lt;/a&gt; &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Temporal, the upcoming proposal for better date and time support in JS, has been seeing a surge of interest in the last few weeks because of a complete implementation being available in Firefox Nightly. Folks seem to be looking forward to using it in their codebases!&lt;/p&gt;
&lt;p&gt;Our colleague Philip Chimento presented a status update. Firefox is at ~100% conformance with just a handful of open questions, and the Ladybird browser is the next closest to shipping a full implementation, at 97% conformance with the test suite.&lt;/p&gt;
&lt;p&gt;The committee also reached consensus on making a minor change to the proposal which relaxed the requirements on JS engines when calculating lunar years far in the future or past.&lt;/p&gt;
&lt;h2 id=&quot;shadowrealm&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-shadowrealm&quot;&gt;ShadowRealm&lt;/a&gt; &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Philip also presented a status update on the ShadowRealm proposal. ShadowRealm is a mechanism that lets you execute JavaScript code synchronously, in a fresh, isolated environment. This has a bunch of useful applications such as running user-supplied plugins without letting them destabilize your app, or prevention of supply chain attacks in your dependencies.&lt;/p&gt;
&lt;p&gt;We think we have resolved all of the open questions on the TC39 side, but what remains is to gauge the interest in implementing the web integration parts. We had a lively discussion on what kinds of use cases we&#39;d like to see in TC39 versus what kinds of use cases the web platform world would like to see.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champions: Dave Herman, Caridy Patiño, Mark S. Miller, Leo Balter, Rick Waldron, Chengzhong Wu&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;decorators-update&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-decorators&quot;&gt;Decorators update&lt;/a&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Implementations of the &lt;a href=&quot;https://github.com/tc39/proposal-decorators&quot;&gt;decorators&lt;/a&gt; proposal are in progress: the Microsoft Edge team has an almost complete implementation on top of Chromium&#39;s V8 engine, and Firefox&#39;s implementation is in progress.&lt;/p&gt;
&lt;p&gt;Although there are two implementations in progress, it has been stated that none of the three major browsers want to be the first one to ship among them, leaving the future of the proposal uncertain.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champions: Kristen Hewell Garett&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;arraybuffers&quot; tabindex=&quot;-1&quot;&gt;ArrayBuffers &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There was some progress on proposals related to ArrayBuffers. One topic was about the &lt;a href=&quot;https://github.com/tc39/proposal-immutable-arraybuffer&quot;&gt;Immutable ArrayBuffer&lt;/a&gt; proposal, which allows creating ArrayBuffers in JS from read-only data, and in some cases allows zero-copy optimizations. &lt;strong&gt;The proposal advanced to stage 2.7&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champions: Mark S. Miller, Peter Hoddie, Richard Gibson, Jack Works&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In light of that, the committee considered whether or not it made sense to withdraw the &lt;a href=&quot;https://github.com/tc39/proposal-limited-arraybuffer&quot;&gt;Limited ArrayBuffer&lt;/a&gt; proposal (read-only views of mutable buffers). It was not withdrawn and remains at stage 1.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champion: Jack Works&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;don-t-call-well-known-symbol-methods-for-regexp-on-primitive-values&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/ecma262/pull/3009&quot;&gt;Don’t call well-known Symbol methods for &lt;code&gt;RegExp&lt;/code&gt; on primitive values&lt;/a&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The well-known symbols &lt;code&gt;Symbol.match&lt;/code&gt;, &lt;code&gt;Symbol.matchAll&lt;/code&gt;, &lt;code&gt;Symbol.replace&lt;/code&gt;, &lt;code&gt;Symbol.search&lt;/code&gt; and &lt;code&gt;Symbol.split&lt;/code&gt; allow an arbitrary object to be passed as the argument to the corresponding string methods and behave like a custom &lt;code&gt;RegExp&lt;/code&gt;. However, these methods don&#39;t check that the argument is an object, so you could make &lt;code&gt;&amp;quot;foo bar&amp;quot;.split(&amp;quot; &amp;quot;)&lt;/code&gt; have arbitrary behavior by setting &lt;code&gt;String.prototype[Symbol.split]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is an issue especially for Node.js and Deno, since a lot of their internal code is written in JavaScript. They use &lt;a href=&quot;https://h3manth.com/posts/primordials-in-node/&quot;&gt;primordials&lt;/a&gt; to guard their internal code from userland monkeypatching, but guarding against overriding the matching behavior of strings could lead to performance issues.&lt;/p&gt;
&lt;p&gt;The proposed solution was to have the relevant string methods only look for these well-known symbols if the argument is an object, rather than doing so for all primitives other than &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;. This is technically a breaking change, but it&#39;s not expected to lead to web compatibility issues in the wild because of how niche these symbols are. Given that, the committee reached consensus on making this change.&lt;/p&gt;
&lt;h2 id=&quot;future-direction-for-records-and-tuples&quot; tabindex=&quot;-1&quot;&gt;Future direction for &lt;a href=&quot;https://github.com/tc39/proposal-record-tuple&quot;&gt;Records and Tuples&lt;/a&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Records and Tuples proposal has been stuck at stage 2 for long time, due to significant concerns around unrealistic performance expectations. The committee again discussed the proposal, and how to rewrite it to introduce &lt;em&gt;some&lt;/em&gt; of its capabilities to the language without falling into the same performance risks.&lt;/p&gt;
&lt;p&gt;You can read more details &lt;a href=&quot;https://github.com/tc39/proposal-record-tuple/issues/393&quot;&gt;on GitHub&lt;/a&gt;, but the summary is that Records and Tuples might become:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;objects, rather than primitives&lt;/li&gt;
&lt;li&gt;shallowly immutable, rather than enforcing deep immutability&lt;/li&gt;
&lt;li&gt;using an &lt;code&gt;equals()&lt;/code&gt; method rather than relying on &lt;code&gt;===&lt;/code&gt; for recursive comparison&lt;/li&gt;
&lt;li&gt;have special handling in &lt;code&gt;Map&lt;/code&gt;/&lt;code&gt;Set&lt;/code&gt;, easily allowing multi-value keys.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Champions: Ashley Claymore&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;a-unified-vision-for-measure-and-decimal&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://notes.igalia.com/p/tc39-2025-02-plenary-decimal-measure-unity&quot;&gt;A unified vision for measure and decimal&lt;/a&gt; &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In discussions surrounding the topic of &lt;a href=&quot;https://github.com/tc39/proposal-decimal&quot;&gt;decimal&lt;/a&gt;, it has become increasingly clear that it overlaps with the &lt;a href=&quot;https://github.com/tc39/proposal-measure&quot;&gt;measure&lt;/a&gt; proposal (possibly to be rechristened as &lt;code&gt;amount&lt;/code&gt; -- watch this space) to such an extent that it might make sense to consider both proposals in a unified way. That may or may not mean that the proposals get literally merged together (although that could be &lt;em&gt;a&lt;/em&gt; path forward). Ultimately, the committee wasn&#39;t in favor of merging the proposals, though there were concerns that, if they were kept separate, one proposal might advance without the other advancing. As usual with all discussions of decimal, the discussion overflowed into the next day, with Shane Carr of Google presenting his own &lt;a href=&quot;https://docs.google.com/presentation/d/1050DHlNOzcN-8LqJQ_6z8j-LryXgEqOcLfcVzkhJyEk/&quot;&gt;sketch&lt;/a&gt; of how the unity of decimal and measure might happen.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champions (Decimal): Jesse Alama &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/pkjMZ4BUKM-16.avif 16w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/pkjMZ4BUKM-16.webp 16w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/pkjMZ4BUKM-16.png&quot; width=&quot;16&quot; height=&quot;16&quot;&gt;&lt;/picture&gt; , Jirka Maršík, Andrew Paprocki&lt;/li&gt;
&lt;li&gt;Champion (Measure): Ben Allen &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/pkjMZ4BUKM-16.avif 16w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/pkjMZ4BUKM-16.webp 16w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/pkjMZ4BUKM-16.png&quot; width=&quot;16&quot; height=&quot;16&quot;&gt;&lt;/picture&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;error-capturestacktrace&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/mgaudet/proposal-error-capturestacktrace&quot;&gt;&lt;code&gt;Error.captureStackTrace&lt;/code&gt;&lt;/a&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Since at least 2015, V8 has exposed a non-standard API called &lt;a href=&quot;https://v8.dev/docs/stack-trace-api#stack-trace-collection-for-custom-exceptions&quot;&gt;&lt;code&gt;Error.captureStackTrace()&lt;/code&gt;&lt;/a&gt; to expose an Error-like &lt;code&gt;stack&lt;/code&gt; property on any arbitrary object. It also allows passing a function or constructor as its second argument, to skip any stack frames after the last call to that function, which can be used to hide implementation details that won&#39;t be useful to the user.&lt;/p&gt;
&lt;p&gt;Although this API was V8-internal for so long, in 2023 JSC shipped an implementation of this API, and now SpiderMonkey is working on one. And since the V8 and JSC implementations have some differences, this is now being brought up as a TC39 proposal to settle on some exact behavior, which is now stage 1.&lt;/p&gt;
&lt;p&gt;This proposal is only about &lt;code&gt;Error.captureStackTrace()&lt;/code&gt;, and it does &lt;em&gt;not&lt;/em&gt; attempt to specify V8&#39;s &lt;a href=&quot;https://v8.dev/docs/stack-trace-api#customizing-stack-traces&quot;&gt;&lt;code&gt;Error.prepareStackTrace()&lt;/code&gt;&lt;/a&gt; API, which allows customizing the stack trace string representation. This API is still V8-only, and there don&#39;t seem to be any plans to implement it elsewhere.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champion: Matthew Gaudet&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;the-fixed-and-stable-object-integrity-traits&quot; tabindex=&quot;-1&quot;&gt;The &amp;quot;fixed&amp;quot; and &amp;quot;stable&amp;quot; object integrity traits &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/tc39/proposal-stabilize&quot;&gt;Stabilize&lt;/a&gt; proposal is exploring adding a new &lt;em&gt;integrity trait&lt;/em&gt; for objects, similar to &lt;code&gt;Object.preventExtension&lt;/code&gt;, &lt;code&gt;Object.seal&lt;/code&gt; and &lt;code&gt;Object.freeze&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A &lt;em&gt;fixed&lt;/em&gt; object is an object whose properties can be safely introspected without triggering side effects, except for when triggering a getter through property access. In addition to that, it&#39;s also free from what we call the &amp;quot;override mistake&amp;quot;: a non-writeable property doesn&#39;t prevent the same property from being set on objects that inherit from it.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; plainObject &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;defineProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token literal-property property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token literal-property property&quot;&gt;writable&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fixedObject &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;defineProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;x&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token literal-property property&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token literal-property property&quot;&gt;writable&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;Object&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fixedObject&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; inheritPlain &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;__proto__&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; plainObject &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;inheritPlain&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// doesn&#39;t work!&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; inheritFixed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;__proto__&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; fixedObject &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;inheritFixed&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// sets `inheritFixed.x` to `3`, while leaving `fixedObject.x` as `1`&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An object that is both &lt;em&gt;fixed&lt;/em&gt; and &lt;em&gt;frozen&lt;/em&gt; is called &lt;em&gt;stable&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The proposal was originally also exploring one more integrity trait, to prevent code from defining new private fields on an existing object through the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_properties#returning_overriding_object&quot;&gt;return override trick&lt;/a&gt;. This has been removed from this proposal, and instead we are exploring changing the behavior of &lt;code&gt;Object.preventExtensions&lt;/code&gt; to also cover this case.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champions: Mark S. Miller, Chip Morningstar, Richard Gibson, Mathieu Hofman&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;curtailing-the-power-of-thenables&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/mgaudet/proposal-thennable-curtailment&quot;&gt;Curtailing the power of &amp;quot;thenables&amp;quot;&lt;/a&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Once upon a time, async functions did not exist, and neither did promises. For a long time, the only way to do asynchronous work in JS was with callbacks, resulting in &lt;a href=&quot;http://callbackhell.com/&quot;&gt;&amp;quot;callback hell&amp;quot;&lt;/a&gt;. Promises first appeared in userland libraries, which eventually converged into one single interoperable API shape called &lt;a href=&quot;https://promisesaplus.com/&quot;&gt;Promises/A+&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When JS added the &lt;code&gt;Promise&lt;/code&gt; built-in in ES6, it followed Promises/A+, which included a way to interoperate with other promise libraries. You might know that resolving a promise &lt;code&gt;p1&lt;/code&gt; with a value which is a different promise &lt;code&gt;p2&lt;/code&gt; will not immediately fulfill &lt;code&gt;p1&lt;/code&gt;, but it will wait until &lt;code&gt;p2&lt;/code&gt; is resolved and have the same fulfilled value or rejection reason as &lt;code&gt;p2&lt;/code&gt;. For compatibility with promise libraries, this doesn&#39;t only work for built-in promises, but for any object that has a &lt;code&gt;.then&lt;/code&gt; method (called &amp;quot;thenables&amp;quot;).&lt;/p&gt;
&lt;p&gt;In the time since &lt;code&gt;Promise&lt;/code&gt; was added as a built-in, however, it has become clear that thenables are a problem, because it&#39;s easy for folks working on the JS engines to forget they exist, resulting in JS code execution happening in unexpected places inside the engine. In fact, even objects fully created within the engine can end up being thenables, since you can set &lt;code&gt;Object.prototype.then&lt;/code&gt; to a function. This has led to a number of security vulnerabilities in JS engines, including one last year involving async generators &lt;a href=&quot;https://github.com/tc39/ecma262/security/advisories/GHSA-g38c-wh3c-5h9r&quot;&gt;that needed fixes in the JS specification&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It is not feasible to completely get rid of thenables because pre-ES6 promise libraries are still being used to some extent. However, this proposal is about looking for ways to change their behavior so that these bugs can be avoided. It just became stage 1, meaning the possible solutions are still in the process of being explored, but some proposed ideas were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Make it impossible to set &lt;code&gt;Object.prototype.then&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Ignore thenables for some internal operations.&lt;/li&gt;
&lt;li&gt;Change the definition of thenable so that having a &lt;code&gt;then&lt;/code&gt; method on &lt;code&gt;Object.prototype&lt;/code&gt; and other fundamental built-in objects and prototypes doesn&#39;t count, while it would count for regular user-created objects.&lt;/li&gt;
&lt;li&gt;During the discussion in plenary, it was mentioned that userland JS also runs into issues with thenables when the call to &lt;code&gt;.then&lt;/code&gt; leads to reentrancy (that is, if it calls back into the code that called it). If all engine vulnerabilities caused by thenables are related to reentrancy, then both issues could be solved at once. But it does not seem like that is the case, and solving the reentrancy issue might be harder.&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Champion: Matthew Gaudet&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;stable-formatting-update&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-stable-formatting&quot;&gt;Stable Formatting update&lt;/a&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Eemeli Aro from Mozilla presented an update on stable formatting. This proposal aims to add a &amp;quot;stable&amp;quot; locale for addressing some of the weaknesses of our current model of localization. Most importantly, people need an entirely separate code path for either unlocalized or machine-readable use cases which hurts in that it adds complexity to the interface, and it distracts users away from the patterns they ought to be using for their interfaces. This is relevant for use-cases such as testing (especially snapshot testing).&lt;/p&gt;
&lt;p&gt;Temporal already made some strides in this direction by keeping the API surface consistent while allowing users to specify the ISO8601 calendar or the UTC timezone instead of relying on localizable alternatives. This proposal would add a &amp;quot;null&amp;quot; locale either in the form of the literal &lt;code&gt;null&lt;/code&gt; value in JavaScript or using the &amp;quot;zxx&amp;quot; pattern commonly used in the Internationalization world, in order to provide a stable formatting output so users could write their interface once and just use this specific locale to achieve their desired result.&lt;/p&gt;
&lt;p&gt;In the meeting, Eemeli presented their proposal for various formats that should be a part of this stable locale and the committee expressed a preference for the &amp;quot;zxx&amp;quot; locale instead of null with some concerns regarding null being too similar to undefined.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champion: Eemeli Aro&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;intl-locale-info-api&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-intl-locale-info&quot;&gt;Intl Locale Info API&lt;/a&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Intl Locale Info API proposal, which is very close to done, was brought back to the committee perhaps for the last time before Stage 4. The notable change was to remove minimal days from the API due to the lack of strong use cases for it. Finally, there were discussions about the final remaining open questions, especially those that would block implementations. These are planned to be fixed shortly before the proposal goes to Stage 4.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Champion: Frank Tang&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;community-event&quot; tabindex=&quot;-1&quot;&gt;Community event &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;On Thursday evening after the meeting adjourned, the committee members traveled 2 blocks down the road to a SeattleJS meetup kindly hosted by DocuSign at their HQ. A number of committee members gave presentations on TC39-related topics. Two of these were by our colleagues Nicolò Ribaudo, who gave an introduction to the deferred imports proposal, and Philip Chimento, who gave a tour of the Temporal API.&lt;/p&gt;
&lt;h2 id=&quot;tg5-workshop&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/tg5/blob/main/workshops/2025/106.md&quot;&gt;TG5 Workshop&lt;/a&gt; &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/03/27/summary-of-the-february-2025-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After the  plenary ended on Thursday, the discussion continued on Friday with a session of the TG5 part of TC39, which is dedicated to research aspects of JavaScript.
Our colleague Jesse Alama presented on Formalizing JS decimal numbers with the Lean proof assistant. There were a number of other presentations - a report on user studies of the &lt;a href=&quot;https://github.com/tc39/tg5/issues/3&quot;&gt;MessageFormat 2.0&lt;/a&gt;, studies on TC39 proposals, &lt;a href=&quot;https://github.com/erights/quasiParserGenerator&quot;&gt;A parser generator template literal tag generating template literal tags&lt;/a&gt; and &amp;quot;uncanny valleys&amp;quot; in &lt;a href=&quot;https://drops.dagstuhl.de/entities/document/10.4230/LIPIcs.SNAPL.2017.9&quot;&gt;language design&lt;/a&gt;.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Sharing SpiderMonkey tests with the world</title>
		<link href="https://blogs.igalia.com/compilers/2025/02/18/sharing-spidermonkey-tests-with-the-world/"/>
		<updated>2025-02-18T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2025/02/18/sharing-spidermonkey-tests-with-the-world/</id>
		<content type="html">&lt;p&gt;At Igalia, we believe in building open and interoperable platforms, and we’ve found that for such platforms to succeed, it is essential to combine a clear standard with an extensive test suite. We’ve worked on a number of such test suites, ranging from the official JavaScript conformance test suite &lt;a href=&quot;https://github.com/tc39/test262/&quot;&gt;&lt;code&gt;test262&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://web-platform-tests.org/&quot;&gt;web-platform-tests&lt;/a&gt;, which covers the rest of the web platform, to the &lt;a href=&quot;https://github.com/KhronosGroup/VK-GL-CTS&quot;&gt;Khronos Vulkan and OpenGL CTS&lt;/a&gt;. Our experience has consistently shown that the existence of a thorough test suite that is easy for implementers to run, helps significantly to get different products to interoperate in the real world.&lt;/p&gt;
&lt;p&gt;An important way to maximize the coverage of such a test suite is to encourage implementers to share the tests they are writing as part of their implementation work. In the first place, it is helpful to share new tests – a great success story here is the web-platform-tests project, which has two-way synchronization tooling for the major browsers. This allows developers to write tests directly within their own project, which are then shared more or less automatically. However, for mature platforms, especially when the platform and implementations are older than the centralised test suite, there is often a large backlog of existing tests. We would love to see more of these tests made available.&lt;/p&gt;
&lt;p&gt;During 2024, we looked in particular at contributing such backlog tests to &lt;code&gt;test262&lt;/code&gt;. We identified SpiderMonkey’s &lt;code&gt;non262&lt;/code&gt; suite as a potential source of interesting tests for this purpose. This test suite is interesting for several reasons.&lt;/p&gt;
&lt;p&gt;In the first place, it is part of the larger &lt;code&gt;jstests&lt;/code&gt; suite, which also contains the upstream &lt;code&gt;test262&lt;/code&gt; tests (hence the name). This meant we did not expect architectural issues to crop up when upstreaming those tests. Second, as a test suite built by JavaScript engine implementers, it seemed likely to contain tests for edge cases and requirements that changed over time. It is not uncommon for several implementers to be caught out by the same issue, so such tests are more likely to find bugs in other engines as well.&lt;/p&gt;
&lt;p&gt;During our investigation, we discovered that our friends at Bocoup had a similar idea back in 2017, and they had created a python script to transform parts of the &lt;code&gt;jstests&lt;/code&gt; suite to work within the &lt;code&gt;test262&lt;/code&gt; test suite, which we gratefully reused. However, some issues quickly came to light: it had been written for Python 2, and its unit test had not been enabled in continuous integration, so it needed some work to be of use in 2024. Once that was done, we discovered that the script had been used as part of a mostly manual process to submit specifically curated tests, and it could not cope with the diversity and complexity of the whole test suite without significant up-front work to put the tests into a shape that it could deal with. We suspect that this is part of the reason that their project did not bear all that much fruit in the end, and decided that our approach needed to maximize the number of shared tests for the effort expended.&lt;/p&gt;
&lt;p&gt;After getting the script into shape, we set to work on a batch export of the &lt;code&gt;non262&lt;/code&gt; test suite. In order to verify the quality of the exported tests, we ran the tests against both SpiderMonkey and V8 using the upstream tooling. This process revealed several issues—some anticipated, others more unexpected. For example, a large number of tests used helper functions that were only available in SpiderMonkey, which we either needed to provide in &lt;code&gt;test262&lt;/code&gt; or automatically translate to an existing helper function. Other APIs, for example those testing specific details of the garbage collection implementation, could not be reproduced at all.&lt;/p&gt;
&lt;p&gt;Besides that, a fair number of tests relied on specifics of the SpiderMonkey implementation that were not guaranteed by the standard – such as testing exact values of the &lt;code&gt;error.message&lt;/code&gt; property or the handling of particular bit patterns in typed arrays. Some tests also turned out not to be testing what they were meant to test or covered a previous version of the specification or a not-yet-finalized proposal. Depending on the situation, we improved the tests and added APIs to make it possible to share them, or we skipped exporting the offending tests.&lt;/p&gt;
&lt;p&gt;We also discovered some issues in the test262-harness tool that we used to run the tests upstream, notably around tests using &lt;a href=&quot;https://github.com/tc39/eshost/pull/141&quot;&gt;JavaScript modules&lt;/a&gt; and the &lt;a href=&quot;https://github.com/tc39/eshost/pull/140&quot;&gt;[[IsHTMLDDA]] internal slot&lt;/a&gt; (used to specify the web compatibility requirements around &lt;code&gt;document.all&lt;/code&gt;). Also, it turned out that the mechanism to include helper libraries into tests was not fully specified, which led to some combinations of helpers to work in some test runners but not others. We have started the process to &lt;a href=&quot;https://github.com/tc39/test262/pull/4398&quot;&gt;clarify the documentation&lt;/a&gt; on this point.&lt;/p&gt;
&lt;p&gt;As part of this project so far, we landed about &lt;a href=&quot;https://github.com/tc39/test262/pull/4106&quot;&gt;1600 new tests&lt;/a&gt; into &lt;code&gt;test262&lt;/code&gt; and filed 10 bugs (some covering failures in multiple tests), of which half have been fixed by the engine maintainers. Several failures also were the result of bugs that had been filed earlier but hadn’t been fixed yet. Also, Mozilla has decided to remove the exported tests from their own repository, and to use the centralised copies instead.&lt;/p&gt;
&lt;p&gt;In terms of future work for this particular project, we’re expecting to investigate if we can share some more of the tests that are currently skipped. Separately we’re interested in looking into a fully automated two-way synchronization system; this would significantly ease the cooperation of engine developers and project maintainers on a unified test suite, though the engineering effort would be commensurate. We’ll also continue investigating if we can identify other test suites that can benefit from a similar treatment.&lt;/p&gt;
&lt;p&gt;We would like to thank &lt;a href=&quot;https://www.bloomberg.com/&quot;&gt;Bloomberg&lt;/a&gt; for sponsoring this work and the Mozilla community, in particular Dan Minor, for their indispensable help and code reviews.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Igalia&#39;s Compilers Team in 2024</title>
		<link href="https://blogs.igalia.com/compilers/2025/01/13/igalia-s-compilers-team-in-2024/"/>
		<updated>2025-01-13T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2025/01/13/igalia-s-compilers-team-in-2024/</id>
		<content type="html">&lt;p&gt;2024 marked another year of exciting developments and accomplishments for Igalia&#39;s Compilers team packed with milestones, breakthroughs, and a fair share of long debugging sessions. From advancing JavaScript standards, improving LLVM RISC-V performance, to diving deep into Vulkan and FEX emulation, we did it all.&lt;/p&gt;
&lt;p&gt;From shipping &lt;code&gt;require(esm)&lt;/code&gt; in &lt;a href=&quot;https://nodejs.org/en&quot;&gt;Node.js&lt;/a&gt; to porting LLVM’s &lt;code&gt;libc&lt;/code&gt; to RISC-V, and enabling WebAssembly’s highest optimization tier in JavaScriptCore, last year was been nothing short of transformative. So, grab a coffee (or your preferred debugging beverage), and let’s take a look back at the milestones, challenges, and just plain cool stuff we&#39;ve been up to last year.&lt;/p&gt;
&lt;h2 id=&quot;javascript-standards&quot; tabindex=&quot;-1&quot;&gt;JavaScript Standards &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/01/13/igalia-s-compilers-team-in-2024/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We secured a few significant wins last year when it comes to JavaScript standards.
First up, we got &lt;a href=&quot;https://github.com/tc39/proposal-import-attributes&quot;&gt;Import attributes&lt;/a&gt; (alongside &lt;a href=&quot;https://github.com/tc39/proposal-json-modules&quot;&gt;JSON modules&lt;/a&gt;) to Stage 4.
Import attributes allow customizing how modules are imported. For example, in all JavaScript environments you&#39;ll be able to natively import JSON files using&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; myData &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./data&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not far behind, the &lt;a href=&quot;https://github.com/tc39/proposal-intl-duration-format&quot;&gt;&lt;code&gt;Intl.DurationFormat&lt;/code&gt;&lt;/a&gt; proposal also reached Stage 4. &lt;code&gt;Intl.DurationFormat&lt;/code&gt; provides a built-in way to format durations (e.g., days, hours, minutes) in a locale-sensitive manner, enhancing internationalization support.&lt;/p&gt;
&lt;p&gt;We also advanced &lt;a href=&quot;https://github.com/tc39/proposal-shadowrealm&quot;&gt;ShadowRealm&lt;/a&gt;, the JavaScript API that allows you to execute code in a fresh and isolated environment, to Stage 2.7, making significant progress in resolving the questions about which web APIs should be included. We addressed open issues related to HTML integration and ensured comprehensive WPT coverage.&lt;/p&gt;
&lt;p&gt;We didn&#39;t stop there though. We implemented &lt;a href=&quot;https://github.com/unicode-org/message-format-wg/&quot;&gt;MessageFormat 2.0&lt;/a&gt; in ICU4C; you can read more about it in this &lt;a href=&quot;https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/&quot;&gt;blog post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We also continued working on &lt;a href=&quot;https://github.com/tc39/proposal-async-context&quot;&gt;AsyncContext&lt;/a&gt;, an API that would let you persist state across &lt;code&gt;await&lt;/code&gt;s and other ways of running code asynchronously. The main blocker for Stage 2.7 is figuring out how it should interact with web APIs, and events in particular, and we have made a lot of progress in that area.&lt;/p&gt;
&lt;p&gt;Meanwhile, the source map specification got a major update, with the publication of &lt;a href=&quot;https://tc39.es/ecma426/&quot;&gt;ECMA-426&lt;/a&gt;. This revamped spec, developed alongside &lt;a href=&quot;https://bloomberg.com&quot;&gt;Bloomberg&lt;/a&gt;, brings much-needed precision and new features like &lt;code&gt;ignoreList&lt;/code&gt;, all aimed at improving interoperability.&lt;/p&gt;
&lt;p&gt;We also spent time finishing &lt;a href=&quot;https://tc39.es/proposal-temporal/&quot;&gt;Temporal&lt;/a&gt;, the modern date and time API for JavaScript—responding to feedback, refining the API, and reducing binary size. After clearing those hurdles, we moved forward with Test262 coverage and WebKit implementation.&lt;/p&gt;
&lt;p&gt;Speaking of &lt;a href=&quot;https://github.com/tc39/test262&quot;&gt;Test262&lt;/a&gt;, our team continued our co-stewardship of this project that ensures compatibility between JavaScript implementations across browsers and runtimes, thanks to support from the &lt;a href=&quot;https://www.sovereign.tech/&quot;&gt;Sovereign Tech Fund&lt;/a&gt;. We worked on tests for everything from resizable ArrayBuffers to deferred imports, keeping JavaScript tests both thorough and up to date.
To boost Test262 coverage, we successfully ported the first batch of SpiderMonkey&#39;s &lt;a href=&quot;https://github.com/mozilla/gecko-dev/tree/master/js/src/tests/non262&quot;&gt;non-262 test suite&lt;/a&gt; to Test262. This initiative resulted in the addition of approximately &lt;a href=&quot;https://github.com/tc39/test262/pull/4106&quot;&gt;1,600 new tests&lt;/a&gt;, helping to expand and strengthen the testing framework. We would like to thank Bloomberg for supporting this work.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/tc39/proposal-decimal&quot;&gt;decimal proposal&lt;/a&gt; started the year in Stage 1 and remains so, but it has gone through a number of iterative refinements after being presented at the TC39 plenary.&lt;/p&gt;
&lt;p&gt;It’s was a productive year, and we’re excited to keep pushing these and more proposals forward.&lt;/p&gt;
&lt;h2 id=&quot;node-js&quot; tabindex=&quot;-1&quot;&gt;Node.js &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/01/13/igalia-s-compilers-team-in-2024/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In 2024, we introduced several key enhancements in Node.js.&lt;/p&gt;
&lt;p&gt;We kicked things off by adding &lt;a href=&quot;https://docs.google.com/document/d/1ny2Qz_EsUnXGKJRGxoA-FXIE2xpLgaMAN6jD7eAkqFQ/edit&quot;&gt;initial support for CPPGC-based wrapper management&lt;/a&gt;, which helps making the C++/JS corss-heap references visible to the garbage collector, reduces risks of memory leaks/use-after-frees, and improves garbage collection performance.&lt;/p&gt;
&lt;p&gt;Node.js contains a significant amount of JavaScript internals, which are precompiled and preloaded into a custom V8 startup snapshot for faster startup. However, embedding these snapshots and code caches introduced reproducibility issues in Node.js executables. In 2024, We made the &lt;a href=&quot;https://joyeecheung.github.io/blog/2024/09/28/reproducible-nodejs-builtin-snapshots-1/&quot;&gt;built-in snapshot and code cache reproducible&lt;/a&gt;, which is a major milestone in making the Node.js executables &lt;a href=&quot;https://reproducible-builds.org/&quot;&gt;reproducible&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To help user applications start up faster, we also shipped support for &lt;a href=&quot;https://github.com/nodejs/node/pull/52535&quot;&gt;on-disk compilation cache for user modules&lt;/a&gt;. Using this feature, TypeScript made their CLI start up &lt;a href=&quot;https://github.com/nodejs/node/issues/52696&quot;&gt;~2.5x faster&lt;/a&gt;, for example.&lt;/p&gt;
&lt;p&gt;One of the impactful work we&#39;ve done in 2024 was implementing and shipping &lt;a href=&quot;https://github.com/nodejs/node/issues/52697&quot;&gt;&lt;code&gt;require(esm)&lt;/code&gt;&lt;/a&gt;, which is set to accelerate EcmaScript Modules (ESM) adoption in the Node.js ecosystem, as now package maintainers can ship ESM directly without having to choose between setting up dual shipping or losing reach, and it allows many frameworks/tools to load user code in ESM directly instead of doing hacky ESM -&amp;gt; CJS conversion , which tend to be bug-prone, or outright rejecting ESM code. Additionally, we landed &lt;a href=&quot;https://github.com/nodejs/node/issues/56241&quot;&gt;&lt;code&gt;module.registerHooks()&lt;/code&gt;&lt;/a&gt; to help the ecosystem migrate away from dependency of CJS loader internals and improve the state of ESM customization.&lt;/p&gt;
&lt;p&gt;We also shipped a bunch of other smaller &lt;a href=&quot;https://github.com/nodejs/node/pulls?q=is%3Apr+author%3Ajoyeecheung+label%3Asemver-minor+is%3Aclosed+closed%3A%3E2024-01-01+&quot;&gt;semver-minor features&lt;/a&gt; throughout 2024, such as &lt;a href=&quot;https://nodejs.org/en/blog/release/v21.7.0#sea-support-embedding-assets&quot;&gt;support for embedded assets&lt;/a&gt; in single executable applications, &lt;a href=&quot;https://github.com/nodejs/node/pull/51044&quot;&gt;&lt;code&gt;crypto.hash()&lt;/code&gt;&lt;/a&gt; for more efficient one-off hashing, and &lt;a href=&quot;https://github.com/nodejs/node/pull/51927&quot;&gt;&lt;code&gt;v8.queryObjects()&lt;/code&gt;&lt;/a&gt; for memory leak investigation, to name a few.&lt;/p&gt;
&lt;p&gt;Apart from project work, we also co-organized the &lt;a href=&quot;https://nodejs.org/en/blog/events/collab-summit-2024-london&quot;&gt;Node.js collaboration summit in Bloomberg&#39;s London office&lt;/a&gt;, and worked on &lt;a href=&quot;https://github.com/nodejs/bluesky&quot;&gt;Node.js&#39;s Bluesky content automation&lt;/a&gt; for a more transparent and collaborative social media presence of the project.&lt;/p&gt;
&lt;p&gt;You can learn more about the new module loading features from &lt;a href=&quot;https://github.com/joyeecheung/talks/blob/master/viteconf_2024/new-and-upcomng-features-in-the-nodejs-module-loaders.pdf&quot;&gt;our talk at ViteConf Remote&lt;/a&gt;, and about &lt;code&gt;require(esm)&lt;/code&gt; from &lt;a href=&quot;https://github.com/joyeecheung/talks/blob/master/nodeconfeu_2024/require-esm-in-node.pdf&quot;&gt;our NodeConf EU talk&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;javascriptcore&quot; tabindex=&quot;-1&quot;&gt;JavaScriptCore &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/01/13/igalia-s-compilers-team-in-2024/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In JavaScriptCore, we&#39;ve ported BBQJIT, the first WebAssembly optimizing tier to 32-bits. It should be a solid improvement over the previous fast-and-reasonably-performant tier (BBQ) for most workloads. The previous incarnation of this tier generated the Air IR (the low-level); BBQJIT generates machine code more directly, which means JSC can tier-up to it faster.&lt;/p&gt;
&lt;p&gt;We&#39;re also very close to enabling (likely this month) the highest optimizing tier (called &amp;quot;OMG&amp;quot;) for WebAssembly on 32-bits. OMG generates code in the B3 IR, for which JSC implements many more optimizations. B3 then gets lowered to Air and finally to machine code. OMG can increase peak performance for many workloads, at the cost of more time spent on compilation. This has been a year-long effort by multiple people.&lt;/p&gt;
&lt;h2 id=&quot;v8&quot; tabindex=&quot;-1&quot;&gt;V8 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/01/13/igalia-s-compilers-team-in-2024/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In V8, we introduced a new entity called Isolate Groups to break the limit of 4Gb for pointer compression usage.
It should help V8 embedders like node, deno, and others to allocate more isolate per process.
We also supported multi-cage mode for the newly added sandbox feature of V8.
You can read more about this in the &lt;a href=&quot;https://dbezhetskov.dev/multi-sandboxes/&quot;&gt;blog post&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;llvm&quot; tabindex=&quot;-1&quot;&gt;LLVM &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/01/13/igalia-s-compilers-team-in-2024/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In LLVM&#39;s RISC-V backend, we added full scalable vectorization support for the BF16 vector extensions &lt;code&gt;zvfbfmin&lt;/code&gt; and &lt;code&gt;zvfbfwma&lt;/code&gt;. This means that code like the following C snippet:&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; restrict dst&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; __bf16 &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; restrict a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; __bf16 &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; restrict b&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;    dst&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now gets efficiently vectorized into assembly like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;	vsetvli	t4, zero, e16, m1, ta, ma
.LBB0_4:
	vl1re16.v	v8, (t3)
	vl1re16.v	v9, (t2)
	vl2re32.v	v10, (t1)
	vfwmaccbf16.vv	v10, v8, v9
	vs2r.v	v10, (t1)
	add	t3, t3, a4
	add	t2, t2, a4
	sub	t0, t0, a6
	add	t1, t1, a7
	bnez	t0, .LBB0_4
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On top of that, we’ve made significant strides in overall performance last year. Here&#39;s a bar plot showing the improvements in performance from LLVM 17 last November to now.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: This accomplishment is the result of the combined efforts of many developers, including those at Igalia!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://notes.igalia.com/uploads/bd3f7639-21b0-4730-be14-4021729ee961.svg&quot; alt=&quot;Bar graph&quot;&gt;&lt;/p&gt;
&lt;p&gt;We also ported most of LLVM&#39;s libc to rv32 and rv64 in September (~91% of functions enabled).
We presented the results at LLVM Developer&#39;s meeting 2024, you can watch &lt;a href=&quot;https://www.youtube.com/watch?v=GytmaH64wFo&amp;amp;ab_channel=LLVM&quot;&gt;the video of the talk&lt;/a&gt; to learn more about this.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://notes.igalia.com/uploads/e8f5db9b-a3a3-41b7-b9c8-b5638edc88e3.png&quot; alt=&quot;Pie chart&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;shader-compilation-mesa-ir3-and-dynamic-binary-translation-fex-emu&quot; tabindex=&quot;-1&quot;&gt;Shader compilation (Mesa IR3) and dynamic binary translation (FEX-Emu) &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2025/01/13/igalia-s-compilers-team-in-2024/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Shader compilation:
In shader compilation we&#39;ve been busy improving the ir3 compiler backend for the freedreno/turnip drivers for Adreno GPUs in Mesa. Some of the highlights include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Improving support for Vulkan subgroups by &lt;a href=&quot;https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/26950&quot;&gt;adding codegen for new hardware instructions&lt;/a&gt; and &lt;a href=&quot;https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/31731&quot;&gt;implementing clustered subgroup operations&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27411&quot;&gt;Adding support for multiple predicate registers&lt;/a&gt; which paved the way for &lt;a href=&quot;https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27982&quot;&gt;supporting predication&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Implementing a code compression technique called &lt;a href=&quot;https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/28341&quot;&gt;repeated instructions&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dynamic Binary Translation&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;In 2024, Igalia had the exciting opportunity to contribute to FEX (https://fex-emu.com/), marking our first year working on the project. Last year, our primary focus was improving the x87 FPU emulation. While we worked on several pull requests with targeted optimizations, we also took on a few larger tasks that made a significant impact:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Introducing a new x87 stack optimization pass was one of our major contributions. You can dive deeper into the details of it in the &lt;a href=&quot;https://p.ocmatos.com/blog/fex-x87-stack-optimization.html&quot;&gt;blog post&lt;/a&gt; and explore the work itself in the &lt;a href=&quot;https://github.com/FEX-Emu/FEX/pull/3547&quot;&gt;pull request&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Another key feature we added was explicit mode switching between MMX and x87 modes, details can be found in the &lt;a href=&quot;https://github.com/FEX-Emu/FEX/pull/4105&quot;&gt;pull request&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We also focused on SVE optimization for x87 load/store operations. The details of this work can be found in the pull request &lt;a href=&quot;https://github.com/FEX-Emu/FEX/pull/4166&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As we look ahead, we are excited to continue driving the evolution of these technologies while collaborating with our amazing partners and communities.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Summary of the October-2024 TC39 plenary</title>
		<link href="https://blogs.igalia.com/compilers/2024/11/13/summary-of-the-october-2024-tc39-plenary/"/>
		<updated>2024-11-13T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2024/11/13/summary-of-the-october-2024-tc39-plenary/</id>
		<content type="html">&lt;p&gt;In October, many colleagues from Igalia participated in a TC39 meeting organized in Tokyo, Japan by Sony Interactive Entertainment to discuss proposed features for the JavaScript standard alongside delegates from various other organizations.&lt;/p&gt;
&lt;p&gt;Let&#39;s delve together into some of the most exciting updates!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;You can also read the &lt;a href=&quot;https://github.com/tc39/agendas/blob/main/2024/10.md&quot;&gt;full agenda&lt;/a&gt; and the &lt;a href=&quot;https://github.com/tc39/notes/tree/main/meetings/2024-10&quot;&gt;meeting minutes&lt;/a&gt; on GitHub.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;day-1&quot; tabindex=&quot;-1&quot;&gt;Day 1 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/11/13/summary-of-the-october-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;import-attributes-to-stage-4&quot; tabindex=&quot;-1&quot;&gt;Import attributes to Stage 4 &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/11/13/summary-of-the-october-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tc39/proposal-import-attributes&quot;&gt;Import attributes&lt;/a&gt;, (alongside &lt;a href=&quot;https://github.com/tc39/proposal-json-modules&quot;&gt;JSON modules&lt;/a&gt;) reached Stage 4. Import attributes allow customizing how modules are imported. For example, in all JavaScript environments you&#39;ll be able to natively import JSON files using&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; myData &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./data&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The proposals reached finally reached Stage 4, after a bumpy path - including being &lt;em&gt;regressed&lt;/em&gt; from Stage 3 to Stage 2 in 2023 and needing to change their syntax.&lt;/p&gt;
&lt;p&gt;The proposals are already supported in Chrome, Safari, and all the server-side runtimes, with Firefox soon to follow!&lt;/p&gt;
&lt;h3 id=&quot;iterator-helpers-to-stage-4&quot; tabindex=&quot;-1&quot;&gt;Iterator Helpers to stage 4! &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/11/13/summary-of-the-october-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Although we didn&#39;t work directly on the Iterator Helpers proposal, we&#39;ve been eagerly anticipating its completion. It elevates Javascript&#39;s standard library iterators up to a level of developer convenience that&#39;s comparable to Python&#39;s &lt;code&gt;itertools&lt;/code&gt; module or the iterators in Rust. Here&#39;s a code snippet:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Iterator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myArray&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myPredicate&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;take&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;myTransformFunc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;	&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mySummationFunc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&#39;s often convenient to think of processing code such as the above in terms of map and filter operations. But often you&#39;d have to iterate through the array multiple times if you wrote it that way using Array&#39;s &lt;code&gt;map&lt;/code&gt; and &lt;code&gt;filter&lt;/code&gt; methods, which is inefficient. Conversely, if you wrote it with a for-of loop, you&#39;d be using &lt;code&gt;break&lt;/code&gt;, &lt;code&gt;continue&lt;/code&gt;, and possibly state-tracking variables, which is harder to reason about. Iterator helpers give you the best of both worlds.&lt;/p&gt;
&lt;h3 id=&quot;normative-changes-to-ecma-402&quot; tabindex=&quot;-1&quot;&gt;Normative changes to ECMA-402 &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/11/13/summary-of-the-october-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;ECMA-402 is the Internationalization API specification, the companion standard to JavaScript&#39;s ECMA-262. Our colleagues Ben Allen and Ujjwal Sharma are on the editorial board of ECMA-402 and their responsibilities often include proposing small changes. This round, we received consensus for PRs that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Fix a bug that caused date and time values to sometimes be rendered in the wrong numbering system for some locales.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Correctly format currency values when rendered in scientific/engineering notations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Give an explicit ordering for the plural categories returned by &lt;code&gt;Intl.PluralNames.resolvedOptions()&lt;/code&gt;. This allows for easier testing of the correctness of this method, and makes it easier for developers to discover what plural categories exist in which languages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Allow use of non-ISO 4217 data in CurrencyDigits AO
This is a small change, but one that makes the ECMA-402 specification more closely match both extant localization needs and also web reality. Previously the specification mandated the use of a standard for determining the number of &amp;quot;minor units&amp;quot; displayed when formatting currency values -- think here the number of digits used to display cents when formatting values such as 1.25 USD. The previously mandated data source is useful for some contexts, but not others. This PR allows implementors to use whichever source of data on currency minor units is best suited for that engine -- something that implementators had already been doing.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;road-to-the-source-map-standard&quot; tabindex=&quot;-1&quot;&gt;Road to the source map standard &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/11/13/summary-of-the-october-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;TG4, a task group created one year ago within TC39, has been diligently working to standardize and enhance the source maps functionality, with the goal of ensuring a good and consistent developer experience across multiple platforms.&lt;/p&gt;
&lt;p&gt;Thanks also to the efforts by our colleagues Nicolò Ribaudo and Asumu Takikawa, TC39 approved the first draft of the new specification (https://tc39.es/source-map/2024/), which can now advance through the Ecma publishing process to become an official standard.&lt;/p&gt;
&lt;h3 id=&quot;jssugar-js0&quot; tabindex=&quot;-1&quot;&gt;JSSugar / JS0 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/11/13/summary-of-the-october-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;JavaScript keeps evolving and adding many new features over time: this can significantly help JavaScript developers, but it comes with its own problems. Every new feature is something that browsers need to implement and optimize, and which might cause bugs and slowdowns.&lt;/p&gt;
&lt;p&gt;Some committee members (mostly representing browsers), initiated a discussion about whether there are possible alternative approaches to evolving the language. The primary example that was presented as a potential path forward is to leverage existing deveoper tools more extensively: many developers already transpile their code, so what if we made it &amp;quot;official&amp;quot;?&lt;/p&gt;
&lt;p&gt;We could split the language in two parts, that together compose the ECMAScript standard:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;one (JS0) would be the current language that is implemented in browsers, which is what we call today &amp;quot;JavaScript&amp;quot;&lt;/li&gt;
&lt;li&gt;the other (JSSugar), only implemented in tools, similar to how today we use JSX or type annotations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The discussion is in its very early stages, and the direction it will take is uncertain. It could evolve in many ways and it&#39;s possible that TC39 could ultimately decide that actually, the way things work today is fine. There are many voices pushing in opposite directions, and everything is still on the table. Stay tuned for more developments!&lt;/p&gt;
&lt;h2 id=&quot;day-2&quot; tabindex=&quot;-1&quot;&gt;Day 2 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/11/13/summary-of-the-october-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;decimal&quot; tabindex=&quot;-1&quot;&gt;Decimal &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/11/13/summary-of-the-october-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our colleague Jesse Alama presented Decimal, showing the latest iterations on the design and data model for decimal in response to feedback in and between plenaries. The most recent version proposed an &amp;quot;auto-canonicalize&amp;quot; variant of IEEE 754 Decimal128, in which the notion of precision (or &amp;quot;quantum&amp;quot;, to use the official term) of Decimal128 values would not be exposed. We received some feedback there, so decimal stays at stage 1. But stay tuned! We&#39;re going back to the drawing board and will keep iterating.&lt;/p&gt;
&lt;h3 id=&quot;promise-try-to-stage-4&quot; tabindex=&quot;-1&quot;&gt;Promise.try to stage 4! &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/11/13/summary-of-the-october-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;Promise.try()&lt;/code&gt; is a new API that allows you to wrap a function--whether async or not--allowing it to be treated it as though it is always asynchronous. It replaces cumbersome workarounds like &lt;code&gt;new Promise((resolve) =&amp;gt; resolve(myFunction()))&lt;/code&gt;. We didn&#39;t work on this proposal, but are nonetheless looking forward to using it!&lt;/p&gt;
&lt;h3 id=&quot;restricting-support-for-sub-classing-built-ins&quot; tabindex=&quot;-1&quot;&gt;Restricting support for sub-classing built-ins &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/11/13/summary-of-the-october-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Sometimes TC39 makes some mistakes, designing features one way only to later realise that it should have been done differently.&lt;/p&gt;
&lt;p&gt;One example of this is the level of support that JavaScript has for defining subclasses of built-in classes, such as&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyUint8Array&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8Array&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; myArr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyUint8Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;myArr &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyUint8Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// true!&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token comment&quot;&gt;// also true, even if we didn&#39;t redefine .map to return a MyUint8Array&lt;/span&gt;&lt;br&gt;myArr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It often leads to vulnerabilities in JavaScript engines, and leads to many hard-to-optimize patterns that make everybody pay the cost of this language feature, even for those who don&#39;t rely on it.&lt;/p&gt;
&lt;p&gt;After features have been shipped for years it&#39;s usually too late for TC39 to change them: our highest priority is to &amp;quot;not break the web&amp;quot;, meaning that once developers start relying on something it&#39;s going to stay there forever.&lt;/p&gt;
&lt;p&gt;The discussion focused on whether or not the use cases appeared real, conclusion was that they are for Array and Promise, but we can move forward with the conservative step of removing making only prototype methods of typed arays, Array Buffer, and Shared Array Buffer not look at their &lt;code&gt;this&lt;/code&gt; to dynamically construct the corresponding class. The commitee will investigate further, the use cases for RegExp.&lt;/p&gt;
&lt;h2 id=&quot;day-3&quot; tabindex=&quot;-1&quot;&gt;Day 3 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/11/13/summary-of-the-october-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;measure&quot; tabindex=&quot;-1&quot;&gt;Measure &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/11/13/summary-of-the-october-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We&#39;re very excited to announce that our colleague Ben Allen presented the Measure proposal, and it has reached Stage 1. Measure proposes an API for handling general-purpose unit conversion between measurement scales and measurement systems. Measure was originally part of the localization-related Smart Units proposal, but was promoted into its own proposal in response to demand for this tool in a wide range of contexts.&lt;/p&gt;
&lt;h3 id=&quot;smart-units&quot; tabindex=&quot;-1&quot;&gt;Smart units &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/11/13/summary-of-the-october-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Smart Units is a proposal to include an API for localizing measured quantities to locale-appropriate scales and measuring systems. This can be complicated by how the appropriate measuring scale for some usages varies based on the type of thing being measured; for example, many locales use a different measurement scale for the heights of people than they do for other length measurements.&lt;/p&gt;
&lt;p&gt;Although much of the action involved in developing this proposal has shifted to the related Measure proposal, in this session we considered what units and usages should be supported.&lt;/p&gt;
&lt;h3 id=&quot;other-updates&quot; tabindex=&quot;-1&quot;&gt;Other Updates &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/11/13/summary-of-the-october-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our colleague Philip Chimento presented a short update on the progress of getting Temporal into browsers. Here&#39;s the representing the test262 conformance as of last plenary!
&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/UXNCjXuceR-2404.avif 2404w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/UXNCjXuceR-2404.webp 2404w&quot;&gt;&lt;img alt=&quot;temporal graph&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/UXNCjXuceR-2404.png&quot; width=&quot;2404&quot; height=&quot;1036&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Good news from the &lt;a href=&quot;https://github.com/tc39/proposal-async-context/&quot;&gt;AsyncContext&lt;/a&gt; champions, including our colleague Andreu Botella: the proposal is almost ready for Stage 2.7! All the semantics relevant to ECMAScript have been finalized, and it&#39;s now just waiting on finalizing the integration semantics with the rest of the web APIs.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Summary of the July-August 2024 TC39 plenary</title>
		<link href="https://blogs.igalia.com/compilers/2024/09/11/summary-of-the-july-august-2024-tc39-plenary/"/>
		<updated>2024-09-11T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2024/09/11/summary-of-the-july-august-2024-tc39-plenary/</id>
		<content type="html">&lt;p&gt;The TC39 committee met again at the end of July, this time remotely, to discuss updated to various proposals at different stages of the standardization process. Let&#39;s go together through some of the most significant updates!&lt;/p&gt;
&lt;p&gt;You can also read the &lt;a href=&quot;https://github.com/tc39/agendas/blob/main/2024/07.md&quot;&gt;full agenda&lt;/a&gt; and the &lt;a href=&quot;https://github.com/tc39/notes/tree/main/meetings/2024-07&quot;&gt;meeting minutes&lt;/a&gt; on GitHub.&lt;/p&gt;
&lt;h2 id=&quot;day-1&quot; tabindex=&quot;-1&quot;&gt;Day 1 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/09/11/summary-of-the-july-august-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;test262-updates&quot; tabindex=&quot;-1&quot;&gt;Test262 Updates &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/09/11/summary-of-the-july-august-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;On the compilers team at Igalia we have several reviewers for Test262, which is the conformance test suite that ensures all JS implementations conform to the ECMA-262 specification. As of this TC39 meeting, &lt;code&gt;RegExp.escape&lt;/code&gt;, &lt;code&gt;Atomics.pause&lt;/code&gt;, &lt;code&gt;Math.sumPrecise&lt;/code&gt;, Base64, and source phase imports now have full or almost-full test coverage. Additionally, our team is working towards the goal of having a testing plan for each new proposal, to make it easier for people to write tests.&lt;/p&gt;
&lt;h3 id=&quot;intl-durationformat&quot; tabindex=&quot;-1&quot;&gt;Intl.DurationFormat &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/09/11/summary-of-the-july-august-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;DurationFormat continues its approach to Stage 4 with a fix to an edge case involving the formatting of certain negative durations when using the &lt;code&gt;&amp;quot;numeric&amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;two-digit&amp;quot;&lt;/code&gt; styles. Previously if a zero-valued &lt;code&gt;&amp;quot;numeric&amp;quot;&lt;/code&gt; style unit was the first formatted unit in a negative duration, the negative sign would get dropped.&lt;/p&gt;
&lt;h3 id=&quot;drop-assert-from-import-attributes&quot; tabindex=&quot;-1&quot;&gt;Drop assert from import attributes &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/09/11/summary-of-the-july-august-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/tc39/proposal-import-attributes&quot;&gt;import attributes&lt;/a&gt; proposal was originally called &amp;quot;import assertions&amp;quot; and had the following syntax:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; data &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./data.json&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;assert&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The semantics of this example is that &lt;code&gt;&amp;quot;./data.json&amp;quot;&lt;/code&gt; is fetched/interpreted ignoring the assertions (for example, web browsers would have known to parse the file as JSON because the server would use the &lt;code&gt;application/json&lt;/code&gt; MIME type). Then the assertions were applied, potentially throwing an error.&lt;/p&gt;
&lt;p&gt;The proposal had then been updated from &amp;quot;assertions&amp;quot; to &amp;quot;attributes&amp;quot;, and the keyword was changed to reflect the new semantics:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; data &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./data.json&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;json&quot;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Attributes can affect how a module is loaded and interpreted, rather than just causing an error if it&#39;s the &amp;quot;wrong&amp;quot; module. Web browsers can send the proper HTTP headers to servers indicating that they expect a JSON response, and other non-HTTP-based platform can use attributes to decide how they want to parse the file.&lt;/p&gt;
&lt;p&gt;Chrome, Node.js and Deno shipped the &lt;code&gt;assert&lt;/code&gt; keyword a while ago, so TC39 was not sure that removing it would have been web-compatible. Chrome succesfully unshipped support for &lt;code&gt;assert&lt;/code&gt; in Chrome 126, released in June, so now the proposal has been updated to only support &lt;code&gt;with&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;asynccontext-update&quot; tabindex=&quot;-1&quot;&gt;AsyncContext Update &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/09/11/summary-of-the-july-august-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;https://github.com/tc39/proposal-async-context&quot;&gt;&lt;code&gt;AsyncContext&lt;/code&gt;&lt;/a&gt; allows defining variables that are implicitly propagated
following the &amp;quot;async flow&amp;quot; of your code:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; clickX &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AsyncContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Variable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  clickX&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;clientX&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;30 seconds&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doSomething&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Doing something due to the click at x=&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; clickX&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the above example, &lt;code&gt;doSomething&lt;/code&gt; will log 30 seconds after each click, logging the &lt;code&gt;x&lt;/code&gt; coordinate of the mouse corresponding to the click that scheduled that &lt;code&gt;doSomething&lt;/code&gt; call.&lt;/p&gt;
&lt;p&gt;The proposal, currently at stage 2, is proceeding steadily and the champions are currently figuring out how it should be integrated with other web APIs.&lt;/p&gt;
&lt;h3 id=&quot;deferred-imports&quot; tabindex=&quot;-1&quot;&gt;Deferred imports &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/09/11/summary-of-the-july-august-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;import defer&lt;/code&gt; proposal allows importing modules while deferring their execution until when it&#39;s needed, to reduce their impact on application startup time:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; defer &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; mod &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./dep.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;$button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;number&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// ./dep.js is only evaluated at this point, when we need it.&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The main difference between using &lt;code&gt;import defer&lt;/code&gt; and dynamic &lt;code&gt;import()&lt;/code&gt; is that the former can be used &lt;em&gt;synchronously&lt;/em&gt; (without having to introduce promises or &lt;code&gt;async&lt;/code&gt;/&lt;code&gt;await&lt;/code&gt;), at the expense of only deferring code execution and not code loading.&lt;/p&gt;
&lt;p&gt;During this meeting proposal reached Stage 2.7, which means that it&#39;s almost ready to be implemented (it&#39;s only missing test262 tests). The committee confirmed the semantics around top-level await: given that modules using top-level await cannot be executed asynchronously, they will be executed at startup even if they are part of a set of modules pulled in by an &lt;code&gt;import defer&lt;/code&gt; declaration.&lt;/p&gt;
&lt;h2 id=&quot;day-2&quot; tabindex=&quot;-1&quot;&gt;Day 2 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/09/11/summary-of-the-july-august-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;intl-locale-info&quot; tabindex=&quot;-1&quot;&gt;Intl Locale Info &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/09/11/summary-of-the-july-august-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Frank Yung-Fong Tang of Google provided a minor update to the stage 3 Intl.LocaleInfo proposal, and received consensus for a PR fixing a minor bug with the handling of requests for the week of day and clarifying the result of using the &lt;code&gt;&amp;quot;-u-ca-iso8601&amp;quot;&lt;/code&gt; Unicode locale extension. He also gave an update on the implementation status of &lt;code&gt;Intl.LocaleInfo&lt;/code&gt;, noting that it is currently implemented in Chrome and Safari, with a Mozilla implementation pending.&lt;/p&gt;
&lt;h3 id=&quot;temporal-update&quot; tabindex=&quot;-1&quot;&gt;Temporal Update &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/09/11/summary-of-the-july-august-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Our colleague Philip Chimento presented another minor update on Temporal. There were two bug fixes to approve: one to correctly handle a corner case in the time zone database where the day started at half past midnight on March 31, 1919 in Toronto due to a time zone shift, and another to disallow a particular combination of options in &lt;code&gt;Temporal.Duration.prototype.round()&lt;/code&gt; where there were multiple interpretations possible for what the outcome should be.&lt;/p&gt;
&lt;p&gt;Temporal is nearing completion; JS engines continue to work on implementing it. Firefox is the closest to having a complete implementation. There is a &lt;a href=&quot;https://github.com/tc39/proposal-temporal/issues/2628&quot;&gt;checklist&lt;/a&gt; that you can follow if you are interested in further updates on the TC39 side.&lt;/p&gt;
&lt;h3 id=&quot;fingerprinting-discussion&quot; tabindex=&quot;-1&quot;&gt;Fingerprinting discussion &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/09/11/summary-of-the-july-august-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Ben Allen led a fruitful discussion on the potential for fingerprinting risk should browser implementations allow users to dynamically update locale-related information, either through adding new locales beyond the ones shipped with the browser or adding additional locale-related components, such as additional scripts or additional calendars. Including this feature would greatly improve the usability of the Web for users who speak minority languages -- but letting hosts know whether users have those non-base locales installed could result in those users having their privacy compromised in a way that in some cases could be genuinely dangerous for them.&lt;/p&gt;
&lt;p&gt;Although no browsers currently allow for dynamic locale-related updates, it is a feature under consideration among multiple browser-makers. The conversation concluded with the decision for the relevant privacy teams to consider the matter and return with feedback.&lt;/p&gt;
&lt;h3 id=&quot;regexp-escape-for-stage-3&quot; tabindex=&quot;-1&quot;&gt;&lt;code&gt;RegExp.escape&lt;/code&gt; for Stage 3 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/09/11/summary-of-the-july-august-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/tc39/proposal-regex-escaping&quot;&gt;&lt;code&gt;RegExp.escape&lt;/code&gt;&lt;/a&gt; is a new utility for escaping strings so that they can be safely used in regular expression.&lt;/p&gt;
&lt;p&gt;Consider the case where you have a string &lt;code&gt;&amp;quot;.js&amp;quot;&lt;/code&gt;, and you want to check wether another strings ends with that suffix using a regular expression. You might be tempted to write something like this:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; suffix &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; matches &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RegExp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;suffix&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filename&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, that code has a problem: &lt;code&gt;.&lt;/code&gt; has a special meaning in regular expressions, so &lt;code&gt;matches&lt;/code&gt; would also be true for &lt;code&gt;something.notjs&lt;/code&gt;! To fix this, you would need to escape the &lt;code&gt;suffix&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; suffix &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; matches &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;RegExp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;RegExp&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;escape&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;suffix&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;filename&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Thanks to the proposal&#39;s champion &lt;a href=&quot;https://github.com/ljharb&quot;&gt;Jordan Harband&lt;/a&gt; the committee approved &lt;code&gt;RegExp.escape&lt;/code&gt; to advance to Stage 3, which means that browsers can now implement and ship it.&lt;/p&gt;
&lt;h2 id=&quot;day-3&quot; tabindex=&quot;-1&quot;&gt;Day 3 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/09/11/summary-of-the-july-august-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;decimal&quot; tabindex=&quot;-1&quot;&gt;Decimal &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/09/11/summary-of-the-july-august-2024-tc39-plenary/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Decimal champion Jesse Alama gave an update about the current status of the proposal. There were minor changes to the API; the main update was to make the spec text considerable sharper, thanks to close cooperation with new co-author Waldemar Horwat. Jesse asked for decimal to advance to stage 2 in the TC39 process, but it did not, because the argument that decimal, in its current form, is too close to just being a library. In the discussion, some concerns were raised that if we were to go ahead with the current Decimal128-based data model, in which trailing zeroes are preserved, we close the door to a potential future where decimal exists JavaScript as a primitive type. Our work in decimal continues -- stay tuned!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Summary of the June 2024 TC39 plenary in Helsinki</title>
		<link href="https://blogs.igalia.com/compilers/2024/07/18/summary-of-the-june-2024-tc39-plenary-in-helsinki/"/>
		<updated>2024-07-18T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2024/07/18/summary-of-the-june-2024-tc39-plenary-in-helsinki/</id>
		<content type="html">&lt;p&gt;In June, many colleagues from Igalia participated in a TC39 meeting organized in Helsinki by Aalto University and Mozilla to discuss proposed features for the JavaScript standard alongside delegates from various other organizations.&lt;/p&gt;
&lt;p&gt;Let&#39;s delve together into some of the most exciting updates!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;You can also read the &lt;a href=&quot;https://github.com/tc39/agendas/blob/main/2024/06.md&quot;&gt;full agenda&lt;/a&gt; and the &lt;a href=&quot;https://github.com/tc39/notes/pull/330&quot;&gt;meeting minutes&lt;/a&gt; on GitHub.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;day-1&quot; tabindex=&quot;-1&quot;&gt;Day 1 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/07/18/summary-of-the-june-2024-tc39-plenary-in-helsinki/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;import-defer-to-stage-2-7&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-defer-import-eval&quot;&gt;&lt;code&gt;import defer&lt;/code&gt;&lt;/a&gt; to Stage 2.7  &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/07/18/summary-of-the-june-2024-tc39-plenary-in-helsinki/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;import defer&lt;/code&gt; proposal allows pre-loading modules while deferring their evaluation until a later time. This proposal aims at giving developers better tools to optimize the startup performance of their application.&lt;/p&gt;
&lt;p&gt;As soon as some code needs the variables exported by a deferred module, it will be  synchronously evaluated to immediately give access to its value:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// This does not cause evaluation of my-mod or its dependencies:&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; defer &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; myMod &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./my-mod.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;$button&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;click&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token comment&quot;&gt;// but this does!&lt;/span&gt;&lt;br&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;val:&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; myMod&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;val&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is similar to, when using CommonJS, moving a &lt;code&gt;require(...)&lt;/code&gt; call from the top-level of a module to inside a function. Adding a similar capability to ES modules is one further step towards helping people migrate from CommonJS to ESM.&lt;/p&gt;
&lt;p&gt;The proposal reached stage 2.7 after answering a few questions centered around the behavior of top-level await: modules with top-level await will not be deferred even if imported through &lt;code&gt;import defer&lt;/code&gt;, because they cannot be synchronously evaluted. If you application can easily handle asynchronous deferred evaluation of modules, it can as well use dynamic &lt;code&gt;import()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The proposal now needs to have &lt;a href=&quot;https://github.com/tc39/test262/&quot;&gt;test262&lt;/a&gt; tests written, to be able to go to Stage 3.&lt;/p&gt;
&lt;h3 id=&quot;promise-try-to-stage-3&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-promise-try&quot;&gt;&lt;code&gt;Promise.try&lt;/code&gt;&lt;/a&gt; to Stage 3 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/07/18/summary-of-the-june-2024-tc39-plenary-in-helsinki/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The new &lt;code&gt;Promise.try&lt;/code&gt; helper allows calling a functions that might or might not be asynchronous, unifying their error handling paths. This is useful for asynchronous APIs (that should always signal errors by returning a rejected promise) that interact with user-provided callbacks.&lt;/p&gt;
&lt;p&gt;Consider this example:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AsyncNegator&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;subtract&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; negate&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncNegator&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;negate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;negB &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; negB&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While the developer here took care of wrapping &lt;code&gt;negate&lt;/code&gt;&#39;s result in &lt;code&gt;Promise.resolve&lt;/code&gt;, in case &lt;code&gt;negate&lt;/code&gt; returns a number directly, what happens in &lt;code&gt;negate&lt;/code&gt; throws an error? In that case, &lt;code&gt;subtract&lt;/code&gt; will throw synchronously rather than returning a rejected promise!&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;Promise.try&lt;/code&gt;, you can easily handle both the success and error paths correctly:&lt;/p&gt;
&lt;pre class=&quot;language-ts&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-ts&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AsyncNegator&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;subtract&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; negate&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; AsyncNegator&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;negate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;negB &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; negB&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;day-2&quot; tabindex=&quot;-1&quot;&gt;Day 2 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/07/18/summary-of-the-june-2024-tc39-plenary-in-helsinki/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;source-maps-update&quot; tabindex=&quot;-1&quot;&gt;Source maps update &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/07/18/summary-of-the-june-2024-tc39-plenary-in-helsinki/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/articles/source-maps&quot;&gt;Source maps&lt;/a&gt; are an important tool in a developer&#39;s toolbox: they are what lets you debug transpiled/minified code in your editor or browser, while still stepping through your &lt;em&gt;original&lt;/em&gt; hand-authored code.&lt;/p&gt;
&lt;p&gt;While they are supported by most tools and browsers, there hasn&#39;t been a shared standard that defines how they should work. Tools and browsers all have to peek at what the others are doing to understand how to properly implement them, and this situation makes it very difficult to evolve the format to improve the debugging experience.&lt;/p&gt;
&lt;p&gt;TC39 recently picked up the task of formalizing the standard, as well as adding new features such as the &lt;a href=&quot;https://github.com/tc39/source-map/blob/main/proposals/scopes.md&quot;&gt;scopes&lt;/a&gt; proposal that would let devtools better understand renamed variables and inlined functions.&lt;/p&gt;
&lt;h3 id=&quot;iterator-zip-to-stage-2-7&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-joint-iteration&quot;&gt;&lt;code&gt;Iterator.zip&lt;/code&gt;&lt;/a&gt; to Stage 2.7 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/07/18/summary-of-the-june-2024-tc39-plenary-in-helsinki/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;TC39 is working on many helpers for more easily working with iterators (&amp;quot;lazy lists&amp;quot;, that only produce values as needed). While most of them are in the &lt;a href=&quot;https://github.com/tc39/proposal-iterator-helpers&quot;&gt;Iterator Helpers&lt;/a&gt; proposal, this one is advancing on its own.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Iterator.zip&lt;/code&gt; allows pairing values coming from multiple iterators:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getNums&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;start &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; step &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; val &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; start&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; start &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; step&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; step&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; naturals &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getNums&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; evens &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getNums&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; negatives &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getNums&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token comment&quot;&gt;// an iterator of [a natural, an even, a negative]&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; allTogether &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Iterators&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;naturals&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; evens&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; negative&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;allTogether&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// [0, 0, -1]&lt;/span&gt;&lt;br&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;allTogether&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// [1, 2, -2]&lt;/span&gt;&lt;br&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;allTogether&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;value&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// [2, 4, -3]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This proposal, like &lt;code&gt;import defer&lt;/code&gt;, just reached the new Stage 2.7: it will now need &lt;a href=&quot;https://github.com/tc39/test262/&quot;&gt;test262&lt;/a&gt; tests to be eligible for Stage 3.&lt;/p&gt;
&lt;h3 id=&quot;temporal-reduction&quot; tabindex=&quot;-1&quot;&gt;Temporal reduction  &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/07/18/summary-of-the-june-2024-tc39-plenary-in-helsinki/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://tc39.es/proposal-temporal&quot;&gt;Temporal&lt;/a&gt; is one of the longest awaited features of JavaScript, advancing bit by bit on its path to stage 4 as obstacles are removed. For the last 6 months or so we have been working on removing one of the final obstacles: addressing feedback from JS engines on the size and complexity of the proposal, which culminated in this meeting.&lt;/p&gt;
&lt;p&gt;As we get closer to having shipping implementations, it&#39;s become clear that the size of Temporal was an obstacle for platforms such as low-end Android devices: it added a large chunk to the size of the JS engine all at once. So, &lt;a href=&quot;https://github.com/ptomato&quot;&gt;Philip Chimento&lt;/a&gt; and &lt;a href=&quot;https://github.com/justingrant&quot;&gt;Justin Grant&lt;/a&gt; presented a slate of API removals to make the proposal smaller.&lt;/p&gt;
&lt;p&gt;What was removed? Some methods previously existed for convenience, but were removed as somewhat redundant because there was a one-line way to accomplish the same thing. A more substantial removal was &lt;code&gt;Temporal.Calendar&lt;/code&gt; and &lt;code&gt;Temporal.TimeZone&lt;/code&gt; objects, along with the ability to extend them to implement custom calendars and custom time zones. We&#39;ve received feedback that these have been the most complicated parts of the proposal for implementations, and they&#39;ve also been where the most bugs have popped up. As well, due to the existence of formats like jsCalendar (&lt;a href=&quot;https://www.rfc-editor.org/rfc/rfc8984.html&quot;&gt;RFC 8984&lt;/a&gt;), as well as learning more about the drawbacks of a callback-based design, we believe there are better designs possible for custom time zones and calendars than there were when the feature was designed.&lt;/p&gt;
&lt;p&gt;Most of the slate of removals was adopted, and Temporal continues its journey to stage 4 smaller than it was before. You can follow the progress in &lt;a href=&quot;https://github.com/tc39/proposal-temporal/issues/2628&quot;&gt;this ticket&lt;/a&gt; on Temporal&#39;s issue tracker.&lt;/p&gt;
&lt;h2 id=&quot;day-3&quot; tabindex=&quot;-1&quot;&gt;Day 3 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/07/18/summary-of-the-june-2024-tc39-plenary-in-helsinki/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;decimal-update&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-decimal&quot;&gt;Decimal update&lt;/a&gt; &lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.avif 32w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.webp 32w&quot;&gt;&lt;img alt=&quot;igalia logo&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/bJFBV9eBNh-32.png&quot; width=&quot;32&quot; height=&quot;32&quot;&gt;&lt;/picture&gt; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/07/18/summary-of-the-june-2024-tc39-plenary-in-helsinki/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you&#39;re tired of the fact that &lt;code&gt;0.1 + 0.2&lt;/code&gt; is not &lt;code&gt;0.3&lt;/code&gt; in JavaScript, then the decimal proposal is for you! This proposal, which is currently at stage 1, was presented by Jesse Alama. The goal was to present an update about some changes to the API, and go through the status of the proposal&#39;s &lt;a href=&quot;https://tc39.es/proposal-decimal/&quot;&gt;spec text&lt;/a&gt;. Although most of the committee was generally supportive of allowing this proposal to go to stage 2, it remains at stage 1 due to some concerns about missing details in the spec text and the overall motivation of the proposal.&lt;/p&gt;
&lt;h3 id=&quot;discard-bindings-update&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-discard-binding&quot;&gt;Discard bindings&lt;/a&gt; update &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/07/18/summary-of-the-june-2024-tc39-plenary-in-helsinki/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The intention of discard bindings is to formalize a pattern commonly seen out there in the wild of JavaScript:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; _&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rhs &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that underscore character (&lt;code&gt;_&lt;/code&gt;)? Although our intention is to signal to the readers of our code that we don&#39;t care what is on the left-hand side of the &lt;code&gt;.&lt;/code&gt; in our string, &lt;code&gt;_&lt;/code&gt; is actually a valid identifier. It might even contain a big value, which takes up memory. This is just the tip of the iceberg; things get even more complex when one imagines binding -- but not using! -- even more complex entities. We would like to use &lt;code&gt;_&lt;/code&gt; -- or perhaps something else, like &lt;code&gt;void&lt;/code&gt; -- to signal to the JavaScript engine that it can throw away whatever value &lt;code&gt;_&lt;/code&gt; might have held. &lt;a href=&quot;https://github.com/rbuckton&quot;&gt;Ron Buckton&lt;/a&gt; presented an update about this proposal and successfully advanced it to Stage 2 in the TC39 process.&lt;/p&gt;
&lt;h3 id=&quot;signals-update&quot; tabindex=&quot;-1&quot;&gt;&lt;a href=&quot;https://github.com/tc39/proposal-signals&quot;&gt;Signals&lt;/a&gt; update &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/07/18/summary-of-the-june-2024-tc39-plenary-in-helsinki/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Signals is an ambitious proposal that takes some of the various approaches to reactivity found out there in various JS frameworks such as Vue, React, and so on. The idea is to bring some form of reactivity into the JS Core. Of course, different approaches to reactivity are possible, and should remain valid; the idea of the Signals proposal is to provide some common abstraction that different aproaches can build on. &lt;a href=&quot;https://github.com/littledan&quot;&gt;Dan Ehrenberg&lt;/a&gt; presented an update on this new proposal, which is currently at stage 1. A lot of work remains to be done; Dan explicitly said that a request to move Signals to stage 2 might take at least a year.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>MessageFormat 2.0: A domain-specific language?</title>
		<link href="https://blogs.igalia.com/compilers/2024/05/09/messageformat-2-0-a-domain-specific-language/"/>
		<updated>2024-05-09T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2024/05/09/messageformat-2-0-a-domain-specific-language/</id>
		<content type="html">&lt;p&gt;I recommend reading the prequel to this post, &lt;a href=&quot;https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/&quot;&gt;&amp;quot;MessageFormat 2.0: a new standard for translatable messages&amp;quot;&lt;/a&gt;;
otherwise what follows won&#39;t make much sense!&lt;/p&gt;
&lt;div style=&quot;border: solid 3px&quot;&gt;
&lt;i&gt;This blog post represents the Igalia compilers team;
all opinions expressed here are our own and may not reflect the opinions
of other members of the MessageFormat Working Group or any other group.&lt;/i&gt;
&lt;/div&gt;
&lt;h2 id=&quot;what-we-ve-achieved&quot; tabindex=&quot;-1&quot;&gt;What we&#39;ve achieved &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/09/messageformat-2-0-a-domain-specific-language/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the previous post, I&#39;ve just described the work done by the members of the MF2 Working Group
to develop a specification for MF2, a process that spanned several years.
When I joined the project in 2023, my task was to implement the spec
and produce a back-end for the JavaScript &lt;code&gt;Intl.MessageFormat&lt;/code&gt; proposal.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;|-------------------------------|
| JavaScript code using the API |
|-------------------------------|
| browser engine                |
|-------------------------------|
| MF2 in ICU                    |
|-------------------------------|
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For code running in a browser, the stack looks like this: web developers write JavaScript code
that uses the API; their code runs in a JavaScript engine that&#39;s built into a Web browser;
and that browser makes API calls to the ICU library in order to execute the JS code.&lt;/p&gt;
&lt;p&gt;The bottom layer of the stack is what I&#39;ve implemented as a tech preview.
Since the major JavaScript engines are implemented in C++, I worked on ICU4C,
the C++ version of ICU.&lt;/p&gt;
&lt;p&gt;The middle level is not yet implemented. A &lt;a href=&quot;https://github.com/messageformat/messageformat/tree/main/packages/mf2-messageformat&quot;&gt;polyfill&lt;/a&gt;
makes it possible to try out the API in JavaScript now.&lt;/p&gt;
&lt;h2 id=&quot;understanding-mf2&quot; tabindex=&quot;-1&quot;&gt;Understanding MF2 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/09/messageformat-2-0-a-domain-specific-language/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To understand the remainder of this post, it&#39;s useful to have read over a few more examples
from the MF2 documentation. See:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href=&quot;https://github.com/unicode-org/message-format-wg/tree/main/spec&quot;&gt;spec&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Video: &lt;a href=&quot;https://www.youtube.com/watch?v=D4N4J_8K_T8&quot;&gt;MessageFormat 2 open house&lt;/a&gt; talk by Addison Phillips and Elango Cheran, February 2024&lt;/li&gt;
&lt;li&gt;Video: &lt;a href=&quot;https://www.youtube.com/watch?v=-DlS6KNopoU&quot;&gt;Unicode Technology Workshop talk&lt;/a&gt; by Addison Phillips, November 2023&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;is-mf2-a-programming-language-and-does-it-matter&quot; tabindex=&quot;-1&quot;&gt;Is MF2 a programming language? (And does it matter?) &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/09/messageformat-2-0-a-domain-specific-language/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Different members of the working group have expressed different opinions
on whether MF2 is a programming language:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Addison Phillips: &amp;quot;I think we made a choice (we can reconsider it
if necessary, although I don&#39;t think we need to) that MF2 is not
a resource format. I&#39;m not sure if &#39;templating language&#39; is
the right characterization, but let&#39;s go with it for now.&amp;quot; (&lt;a href=&quot;https://github.com/unicode-org/message-format-wg/pull/474#issuecomment-1719431600&quot;&gt;comment on pull request 474&lt;/a&gt;, September 2023)&lt;/li&gt;
&lt;li&gt;Stanisław Małolepszy: &amp;quot;...we’re neither resource format nor templating language.
I tend to think we’re a storage format for variants.&amp;quot; (&lt;a href=&quot;https://github.com/unicode-org/message-format-wg/pull/474#issuecomment-1719757381&quot;&gt;comment on the same PR&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Mihai Niță: &amp;quot;For me, this is a DSL designed for i18n / l10n.&amp;quot; (&lt;a href=&quot;https://github.com/unicode-org/message-format-wg/issues/507#issuecomment-1790924790&quot;&gt;comment on PR 507&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;MF2 lacks block structure and complex control flow: the &lt;code&gt;.match&lt;/code&gt; construct
can&#39;t be nested, and &lt;code&gt;.local&lt;/code&gt; variable declarations are sequential rather than nested.
Some people might expect a general-programming language
to include these features.&lt;/p&gt;
&lt;p&gt;But in implementing it, I have found that several issues arise that are familiar
from my experience studying, and implementing, compilers and interpreters
for more conventional programming languages.&lt;/p&gt;
&lt;p&gt;I wrote in &lt;a href=&quot;https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/&quot;&gt;part 1&lt;/a&gt; that when using either MF1 or MF2,
messages can be separated
from code -- but it turns out that maybe, messages &lt;em&gt;are&lt;/em&gt; code!
But they constitute code in a different programming language,
which can be cleanly separated from the host programming language,
just as with uninterpreted strings.&lt;/p&gt;
&lt;h3 id=&quot;abstract-syntax&quot; tabindex=&quot;-1&quot;&gt;Abstract syntax &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/09/messageformat-2-0-a-domain-specific-language/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As with a programming language, the syntax of MF2 is specified
using a &lt;a href=&quot;https://github.com/unicode-org/message-format-wg/blob/main/spec/message.abnf&quot;&gt;formal grammar&lt;/a&gt;,
in this case using &lt;a href=&quot;https://en.wikipedia.org/wiki/Augmented_Backus%E2%80%93Naur_form&quot;&gt;Augmented Backus-Naur Form&lt;/a&gt;.
In most compilers and interpreters, a parser (that&#39;s either generated
from a specification of the formal grammar, or written by hand to closely follow that grammar)
reads the text of the program and generates an abstract syntax tree (AST),
which is an internal representation of the program.&lt;/p&gt;
&lt;p&gt;MF2 has a data model, which is like an AST. Users can either write messages
in the text-based syntax (probably easiest for most people)
or construct a data model directly using part of the API
(useful for things like building external tools).&lt;/p&gt;
&lt;p&gt;Parsers and ASTs are familiar concepts for programming language implementors,
and writing the &amp;quot;front-end&amp;quot; for MF2 (the parser, and classes that define the data model)
was not that different from writing a front-end for a programming language.
Because it works on ASTs, the formatter itself (the part that does
all the work once everything is parsed) also looks a lot like an interpreter.
The &amp;quot;back-end&amp;quot;, producing a formatted result, is currently quite simple since
the end result is a flat string -- however, in the future, &amp;quot;formatting to parts&amp;quot;
(necessary to easily support features like markup) will be supported.&lt;/p&gt;
&lt;p&gt;For more details, see &lt;a href=&quot;https://fosdem.org/2024/schedule/event/fosdem-2024-1759-a-universal-data-model-for-localizable-messages/&quot;&gt;Eemeli Aro&#39;s FOSDEM 2024 talk&lt;/a&gt;
on the data model.&lt;/p&gt;
&lt;h3 id=&quot;naming&quot; tabindex=&quot;-1&quot;&gt;Naming &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/09/messageformat-2-0-a-domain-specific-language/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;MF2 has local variable declarations, like the &lt;code&gt;let&lt;/code&gt; construct in JavaScript
and in some functional programming languages. That means that in implementing MF2,
we&#39;ve had to think about evaluation strategies (lazy versus eager evaluation),
scope, and mutability. MF2 settled on a spec in which all local variables
are immutable and no name shadowing is permitted except in a very limited way,
with &lt;code&gt;.input&lt;/code&gt; declarations. Free variables are permitted, and don&#39;t need to be
declared explicitly: these correspond to runtime arguments provided to a message.
Eager and lazy implementations can both conform to the spec, since variables are
immutable, and lazy implementations are free to use call-by-need semantics (&lt;a href=&quot;https://en.wikipedia.org/wiki/Memoization&quot;&gt;memoization&lt;/a&gt;).
These design choices weren&#39;t obvious, and in some cases, inspired quite a lot of discussion.&lt;/p&gt;
&lt;p&gt;Naming can have subtle consequences.
In at least one case, the presence of &lt;code&gt;.local&lt;/code&gt; declarations necessitates
a dataflow analysis (albeit a simple one).
The analysis is to check for
&lt;a href=&quot;https://github.com/unicode-org/message-format-wg/blob/main/spec/errors.md#missing-selector-annotation&quot;&gt;&amp;quot;missing selector annotation&amp;quot; errors&lt;/a&gt;;
the details are outside the scope of this post, but the point is just
that error checking requires &amp;quot;looking through&amp;quot; a variable reference,
possibly multiple chains of references, to the variable&#39;s definition.
Sounds like a programming language!&lt;/p&gt;
&lt;h3 id=&quot;functions&quot; tabindex=&quot;-1&quot;&gt;Functions &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/09/messageformat-2-0-a-domain-specific-language/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Placeholders in MF2 may be expressions with annotations.
These expressions resemble function calls
in a more conventional language. Unlike in most languages, functions
cannot be implemented in MF2 itself, but must be implemented in a host language.
For example, in the ICU4C implementation, the functions would either be written
in C++ or (less likely) another language that has a foreign function interface with C++.&lt;/p&gt;
&lt;p&gt;Functions can be built-in (required in the spec to be provided), or custom.
Programmers using an implementation of the MF2 API can write their own
custom functions that format data (&amp;quot;formatters&amp;quot;), that customize the behavior
of the &lt;code&gt;.match&lt;/code&gt; construct (&amp;quot;selectors&amp;quot;), or do both.
Formatters and selectors have different interfaces.&lt;/p&gt;
&lt;p&gt;The term &amp;quot;annotation&amp;quot; in the MF2 spec is suggestive.
For example, a placeholder like &lt;code&gt;{$x :number}&lt;/code&gt; can be read:
&amp;quot;x should be formatted as a number.&amp;quot;
But custom formatters and selectors may also do much more
complicated things, as long as they conform to their interfaces.
An implementor could define a custom &lt;code&gt;:squareroot&lt;/code&gt; function,
for example, such that &lt;code&gt;{$x :squareroot}&lt;/code&gt; is replaced
with a formatted number whose value is the square root
of the runtime value of &lt;code&gt;$x&lt;/code&gt;.
It&#39;s unclear how common use cases like this will be,
but the generality of the custom function mechanism
makes them possible.&lt;/p&gt;
&lt;p&gt;Wherever there are functions, functional programmers think about types,
explicit or implicit.
MF2 is designed to use a single runtime type: it&#39;s unityped.
The spec uses the term &amp;quot;resolved value&amp;quot; to refer to the type of its
runtime values. Moreover, the spec tries to avoid
constraining the structure of &amp;quot;resolved values&amp;quot;,
to allow the implementation as much freedom as possible.
However, the implementation has to call functions written in a host language
that may have a different type system.
The challenge comes in defining the &amp;quot;function registry&amp;quot;,
which is the part of the MF2 spec that defines both the names
and behavior of built-in functions, and how to specify custom functions.&lt;/p&gt;
&lt;p&gt;Different host languages have different type systems. Specifying the interface
between MF2 and externally-defined functions is tricky,
since the goal is to be able to implement MF2 in any programming language.&lt;/p&gt;
&lt;p&gt;While a language that can call foreign functions but not define its own functions is unusual,
defining foreign function interfaces that bridge the gaps between disparate programming languages
is a common task when designing a language.
This also sounds like a programming language.&lt;/p&gt;
&lt;h3 id=&quot;pattern-matching&quot; tabindex=&quot;-1&quot;&gt;Pattern matching &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/09/messageformat-2-0-a-domain-specific-language/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;.match&lt;/code&gt; construct in MF2 looks a lot like a &lt;code&gt;case&lt;/code&gt; expression in Haskell,
or perhaps a &lt;code&gt;switch&lt;/code&gt; statement in C/C++, depending on your perspective.
Unlike &lt;code&gt;switch&lt;/code&gt;, &lt;code&gt;.match&lt;/code&gt; allows multiple expressions to be examined in order
to choose an alternative. And unlike &lt;code&gt;case&lt;/code&gt;, &lt;code&gt;.match&lt;/code&gt; only compares data against
specific string literals or a wildcard symbol, rather than destructuring the expressions
being scrutinized.&lt;/p&gt;
&lt;p&gt;The ability provided by MF2 to customize pattern-matching is unusual.
An implementation of a selector function
takes a list of keys, one per variant,
and returns a sorted list of keys in order of preference.
The list is then used by the pattern matching algorithm in the
formatter to pick the best-matching variant given that there
are multiple selectors. An abstract example is:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;.match {$x :X} {$y :Y}&lt;br&gt;A1 A2 {{1}}&lt;br&gt;B1 B2 {{2}}&lt;br&gt;C1 * {{3}}&lt;br&gt;* C2 {{4}}&lt;br&gt;* * {{5}}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, the implementation of &lt;code&gt;X&lt;/code&gt; would be called with
the list of keys &lt;code&gt;[A1, B1, C1]&lt;/code&gt; (the &lt;code&gt;*&lt;/code&gt; key is not passed
to the selector implementation) and returns a list of the
same keys, arranged in any order. Likewise, the implementation
of &lt;code&gt;Y&lt;/code&gt; would be called with &lt;code&gt;[A2, B2, C2]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I don&#39;t know of any existing programming languages
with a pattern-matching construct like this one; usually,
the comparison between values and patterns is based
on structural equality and can&#39;t be abstracted over.
But the ability to factor out the workings of
pattern matching and swap in a new kind of matching
(by defining a custom selector function)
is a &lt;em&gt;kind&lt;/em&gt; of abstraction that would be found
in a general-purpose programming language.
Of course, the goal here is not
to match patterns in general but to select a grammatically correct variant
depending on data that flows in at runtime.&lt;/p&gt;
&lt;h3 id=&quot;but-is-it-turing-complete&quot; tabindex=&quot;-1&quot;&gt;But is it Turing-complete? &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/09/messageformat-2-0-a-domain-specific-language/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;MF2 has no explicit looping constructs or recursion, but it does have function calls.
The details of how custom functions are realized are implementation-specific;
typically, using a general-purpose programming language.
That means that MF2 can &lt;em&gt;invoke&lt;/em&gt; code that does arbitrary computation,
but not &lt;em&gt;express&lt;/em&gt; it.
I think it would be fair to say that the combination of MF2
and a suitable registry of custom functions is Turing-complete, but MF2 itself
is not Turing-complete. For example, imagine a custom function named &lt;code&gt;eval&lt;/code&gt;
that accepts an arbitrary JavaScript program as a string,
and returns its output as a string.
This is not how MF2 is intended to be used; &lt;a href=&quot;https://github.com/unicode-org/message-format-wg/blob/main/spec/formatting.md#function-resolution&quot;&gt;the spec&lt;/a&gt;
notes that &amp;quot;execution time SHOULD be limited&amp;quot; for invocations of custom functions.
I&#39;m not aware of any other languages whose Turing-completeness depends
on their execution environment.
(Though there &lt;em&gt;is&lt;/em&gt; at least one &lt;a href=&quot;https://stackoverflow.com/questions/2497146/is-css-turing-complete&quot;&gt;lengthy discussion&lt;/a&gt;
of whether CSS is Turing-complete.)&lt;/p&gt;
&lt;p&gt;If custom functions were removed altogether and the registry
of functions was limited to a small built-in set, MF2 would
look much less like a programming language; its underlying
&amp;quot;instruction set&amp;quot; would be much more limited.&lt;/p&gt;
&lt;h3 id=&quot;code-versus-data&quot; tabindex=&quot;-1&quot;&gt;Code versus data &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/09/messageformat-2-0-a-domain-specific-language/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;There is an old Saturday Night Live routine: “It’s a floor wax! It’s a
dessert topping! It’s both!” XML is similar. “It’s a database! It’s a document!
It’s both!” -- Philip Wadler, &lt;a href=&quot;https://www.research.ed.ac.uk/en/publications/xquery-a-typed-functional-language-for-querying-xml&quot;&gt;&amp;quot;XQuery: a typed functional language for querying XML&amp;quot;&lt;/a&gt; (2002)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The line between code and data isn&#39;t always clear, and the MF2 data model
can be seen as a representation of the input &lt;em&gt;data&lt;/em&gt;,
rather than as an AST representing a program.
Likewise, the syntax can be seen as a serialized format
for representing the data,
rather than as the syntax of a program.&lt;/p&gt;
&lt;p&gt;There is also a &amp;quot;floor wax / dessert topping&amp;quot; dichotomy
when it comes to functions.
Is MF2 an active agent that calls functions,
or does it define data passed to an API, whose implementation
is what calls functions?&lt;/p&gt;
&lt;p&gt;&amp;quot;Language&amp;quot; has multiple meanings in software: it can refer to a
programming language, but the &amp;quot;L&amp;quot; in &amp;quot;HTML&amp;quot; and &amp;quot;XML&amp;quot; stands for
&amp;quot;language&amp;quot;. We would usually say that HTML and XML are markup
languages, &lt;em&gt;not&lt;/em&gt; programming languages, but even that point is
debatable. After all, HTML embeds JavaScript code; the relationship
between HTML and JavaScript resembles the relationship between
MF2 and function implementations.
Languages differ in how much computation they can directly
express, but there are common aspects that unite different
languages, like having a formal grammar.&lt;/p&gt;
&lt;p&gt;I view MF2 as a domain-specific language for formatting messages,
but another perspective is that it&#39;s a representation of data passed
to an API. An API itself can be viewed as a domain-specific language:
it provides verbs (functions or methods that can be called)
and nouns (data structures that the functions can accept.)&lt;/p&gt;
&lt;h3 id=&quot;summing-up&quot; tabindex=&quot;-1&quot;&gt;Summing up &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/09/messageformat-2-0-a-domain-specific-language/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;As someone with a background in programming language design and implementation,
I&#39;m naturally inclined to see everything as a language design problem.
A general-purpose programming language is complex, or at least can be used
to solve complex problems. In contrast, those who have
worked on the MF2 spec over the years have put in a lot of effort to make it as
simple and focused on a narrow domain as possible.&lt;/p&gt;
&lt;p&gt;One of the ways in which MF2 has veered towards programming language territory
is the custom function mechanism, which was added to provide extensibility.
The mechanism is general, but if there was a less general solution
that still supported the desired range of use cases,
these years of effort would have unearthed one.
The presence of name binding (with all the complexities that brings up)
and an unusual form of pattern matching also suggest to me that
it&#39;s appropriate to consider MF2 a programming language,
and to apply known programming language techniques to its
design and implementation.
This shows that programming language theory has interesting
applications in internationalization, which is a new finding
as far as I know.&lt;/p&gt;
&lt;h2 id=&quot;what-s-left-to-do&quot; tabindex=&quot;-1&quot;&gt;What&#39;s left to do? &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/09/messageformat-2-0-a-domain-specific-language/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The MessageFormat spec working group welcomes &lt;a href=&quot;https://github.com/unicode-org/message-format-wg/blob/main/README.md#messageformat-2-technical-preview&quot;&gt;feedback during the tech preview period&lt;/a&gt;.
User feedback on the MF2 spec and implementations will influence its future design.
The current tech preview spec is part of &lt;a href=&quot;https://unicode.org/reports/tr35/&quot;&gt;LDML 45&lt;/a&gt;;
the beta version, to be included in LDML 46, may include improvements
suggested by users and implementors.&lt;/p&gt;
&lt;p&gt;Igalia plans to continue collaboration to advance the &lt;code&gt;Intl.MessageFormat&lt;/code&gt; proposal in TC39.
Implementation in browser engines will be part of that process.&lt;/p&gt;
&lt;h2 id=&quot;acknowledgments&quot; tabindex=&quot;-1&quot;&gt;Acknowledgments &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/09/messageformat-2-0-a-domain-specific-language/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Thanks to my colleagues Ben Allen, &lt;a href=&quot;https://ptomato.name/&quot;&gt;Philip Chimento&lt;/a&gt;, &lt;a href=&quot;https://bkardell.com/&quot;&gt;Brian Kardell&lt;/a&gt;, &lt;a href=&quot;https://meyerweb.com/&quot;&gt;Eric Meyer&lt;/a&gt;, &lt;a href=&quot;https://asumu.org/&quot;&gt;Asumu Takikawa&lt;/a&gt;, and &lt;a href=&quot;https://wingolog.org/&quot;&gt;Andy Wingo&lt;/a&gt;; and MF2 working group members &lt;a href=&quot;https://github.com/eemeli&quot;&gt;Eemeli Aro&lt;/a&gt;, &lt;a href=&quot;https://elangocheran.com/&quot;&gt;Elango Cheran&lt;/a&gt;, &lt;a href=&quot;https://github.com/gibson042&quot;&gt;Richard Gibson&lt;/a&gt;, &lt;a href=&quot;https://github.com/mihnita&quot;&gt;Mihai Niță&lt;/a&gt;, and &lt;a href=&quot;https://github.com/aphillips&quot;&gt;Addison Phillips&lt;/a&gt; for their comments and suggestions on this post and its predecessor. Special thanks to my colleague &lt;a href=&quot;https://ryzokuken.dev/&quot;&gt;Ujjwal Sharma&lt;/a&gt;, whose work I borrowed from in parts of the first post.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>MessageFormat 2.0: a new standard for translatable messages</title>
		<link href="https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/"/>
		<updated>2024-05-06T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/</id>
		<content type="html">&lt;div style=&quot;border: solid 3px&quot;&gt;
&lt;i&gt;This blog post represents the Igalia compilers team;
all opinions expressed here are our own and may not reflect the opinions
of other members of the MessageFormat Working Group or any other group.&lt;/i&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/unicode-org/message-format-wg/tree/main&quot;&gt;MessageFormat 2.0&lt;/a&gt;
is a new standard for expressing translatable messages in user interfaces,
both in Web applications and other software.
Last week, my work on implementing MessageFormat 2.0 in C++ was released
in &lt;a href=&quot;https://blog.unicode.org/2024/04/icu-75-released.html&quot;&gt;ICU 75&lt;/a&gt;,
the latest release of the International Components for Unicode library.&lt;/p&gt;
&lt;p&gt;As a compiler engineer, when I learned about MessageFormat 2.0,
I began to see it as a programming language, albeit an unconventional one.
The message formatter is analogous to an interpreter for a programming language.
I was surprised to discover a programming language hiding in
this unexpected place.
Understanding my surprise requires some context:
first of all, what &amp;quot;messages&amp;quot; are.&lt;/p&gt;
&lt;h2 id=&quot;a-story-about-message-formatting&quot; tabindex=&quot;-1&quot;&gt;A story about message formatting &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Over the past 40 to 50 years, user interfaces (UIs) have grown increasingly complex.
As interfaces have become more interactive and dynamic,
the process of making them accessible in a multitude of natural languages
has increased in complexity as well.
Internationalization (i18n) refers to this general practice,
while the process of localization (l10n) refers to the act
of modifying a specific system for a specific natural language.&lt;/p&gt;
&lt;h3 id=&quot;i18n-history&quot; tabindex=&quot;-1&quot;&gt;i18n history &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Localization of user interfaces (both command-line and graphical)
began by translating strings embedded in code that implements UIs.
Those strings are called &amp;quot;messages&amp;quot;.
For example, consider a text-based adventure game:
messages like &lt;a href=&quot;https://github.com/MITDDC/zork/blob/d94501340842e006791fce0757dc0043b8ec8916/zork/lcf/rooms.98#L512&quot;&gt;&amp;quot;It is pitch black.  You are likely to be eaten by a grue.&amp;quot;&lt;/a&gt;
might appear anywhere in the code. As a slight improvement, the messages could all be stored
in a separate &amp;quot;resource file&amp;quot; that is selected based on the user&#39;s locale.
The &lt;em&gt;ad hoc&lt;/em&gt; approaches to translating these messages and integrating them into code
didn&#39;t scale well. In the late 1980s, C introduced a &lt;code&gt;gettext()&lt;/code&gt; function into &lt;code&gt;glibc&lt;/code&gt;,
which was never standardized but was widely adopted.
This function primarily provided string replacement functionality.
While it was limited, it inspired the work that followed.
Microsoft and Apple operating systems had more powerful i18n support
during this time, but that&#39;s beyond the scope of this post.&lt;/p&gt;
&lt;p&gt;The rise of the Web required increased flexibility. Initially, static documents and apps
with mostly static content dominated. Java, PHP, and Ruby on Rails all brought
more dynamic content to the web, and developers using these languages
needed to tinker more with message formatting.
Their applications needed to handle not just static strings, but messages
that could be customized to dynamic content in a way that produced
understandable and grammatically correct messages for the target audience.
MessageFormat arose as one solution to this problem, implemented by
&lt;a href=&quot;https://en.wikipedia.org/wiki/Taligent&quot;&gt;Taligent&lt;/a&gt; (along with
other i18n functionality).&lt;/p&gt;
&lt;p&gt;The creators of Java had an interest in making Java the preferred language
for implementing Web applications, so
Sun Microsystems incorporated Taligent&#39;s work into Java in JDK 1.1 (1997).
This version of MessageFormat
supported pattern strings, formatting basic types, and choice format.&lt;/p&gt;
&lt;p&gt;The MessageFormat implementation was then incorporated into
&lt;a href=&quot;https://icu.unicode.org/&quot;&gt;ICU&lt;/a&gt;,
the widely used library that implements internationalization functions.
Initially, Taligent and IBM (which was one of Taligent&#39;s parent companies)
worked with Sun to maintain parallel i18n implementations in ICU and
in the JDK, but eventually the two implementations diverged.
Moving at a faster pace, ICU added plural selection to MessageFormat
and expanded other capabilities,
based on feedback from developers and translators
who had worked with the previous generations of localization tools.
ICU also added a C++ port of this Java-based implementation;
hence, the main ICU project includes ICU4J (implemented in Java)
and ICU4C (implemented in C++ with some C APIs).&lt;/p&gt;
&lt;p&gt;Since ICU MessageFormat was introduced, many much more complex Web UIs,
largely based on JavaScript, have appeared. Complex programs
can generate much more interesting content, which implies
more complex localization.  This necessitates a different model
of message formatting. An update to MessageFormat has been
in the works at least since 2019, and that work culminates with the
recent release of the MessageFormat 2.0 specification.
The goals are to provide more modularity and extensibility, and easier adaptation for different locales.&lt;/p&gt;
&lt;p&gt;For brevity, we will refer to ICU MessageFormat, otherwise known
simply as &amp;quot;MessageFormat&amp;quot;, as &amp;quot;MF1&amp;quot; throughout.
Likewise, &amp;quot;MF2&amp;quot; refers to MessageFormat 2.0.&lt;/p&gt;
&lt;h3 id=&quot;why-message-formatting-not-just-for-translation&quot; tabindex=&quot;-1&quot;&gt;Why message formatting? (Not just for translation) &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The work described in this post is motivated
by the desire to make it as easy as possible
to write software that is accessible to people
regardless of the language(s) they use to communicate.
But message formatting is needed even in user interfaces
that only support a single natural language.&lt;/p&gt;
&lt;p&gt;Consider this C code, where &lt;code&gt;number&lt;/code&gt; is presumed
to be an unsigned integer variable that&#39;s
already been defined:&lt;/p&gt;
&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;You have %u files&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; number&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&#39;ve probably all used applications that informed us
that we &amp;quot;have 1 files&amp;quot;. While it&#39;s probably clear
what that means, why should human readers have to mentally
correct the grammatical errors of a computer?
A programmer trying to improve things might write:&lt;/p&gt;
&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;You have %u file%s&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; number&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; number &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;s&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which handles the case where &lt;code&gt;n&lt;/code&gt; is 1. However, English
is full of irregular plurals: consider &amp;quot;bunny&amp;quot; and &amp;quot;bunnies&amp;quot;,
&amp;quot;life&amp;quot; and &amp;quot;lives&amp;quot;, or &amp;quot;mouse&amp;quot; and &amp;quot;mice&amp;quot;. The code
would be easier to read and maintain if it
was easier to express &amp;quot;print the plural of &#39;file&#39;&amp;quot;,
instead of a conditional expression that must
be scrutinized for its meaning.
While &amp;quot;printf&amp;quot; is short for &amp;quot;print formatted&amp;quot;, its
formatting is limited to simpler tasks like
printing numbers as strings, not complex tasks like
pluralizing &amp;quot;mouse&amp;quot;.&lt;/p&gt;
&lt;p&gt;This is just one example; another example is messages
including ordinals, like &amp;quot;1st&amp;quot;, &amp;quot;2nd&amp;quot;, or &amp;quot;3rd&amp;quot;,
where the suffix (like &amp;quot;st&amp;quot;) is determined in a
complicated way from the number (consider &amp;quot;11th&amp;quot;
versus &amp;quot;21st&amp;quot;).&lt;/p&gt;
&lt;p&gt;We&#39;ve seen how messages can vary based on user input
in non-local ways: the bug in &lt;code&gt;&amp;quot;You have %u files&amp;quot;&lt;/code&gt;
is that not only does the number of files vary,
so does the word &amp;quot;files&amp;quot;.
So you might begin to see the value of
a specialized notation for expressing such messages,
which would make it easier to notice bugs like
the &amp;quot;1 files&amp;quot; bug and even prevent them in the first place.
That notation might even resemble
a &lt;a href=&quot;https://en.wikipedia.org/wiki/Domain-specific_language&quot;&gt;domain-specific language&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;why-message-formatting&quot; tabindex=&quot;-1&quot;&gt;Why message formatting? &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Turning now to translation,
you might be wondering why you would need a separate message formatter,
instead of writing code in your programming language of choice that
would look something like this (if your language of choice is C/C++):&lt;/p&gt;
&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Supposing a char* &quot;what&quot; and int &quot;planet&quot; are already defined&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;There was %s on planet %d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; what&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; planet&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, the message is the first argument to &lt;code&gt;printf&lt;/code&gt; and the other
arguments are substituted into the message at runtime; no special
message formatting functionality is used, beyond what the C standard
library offers.&lt;/p&gt;
&lt;p&gt;The problem is that if you want to translate the words in the message,
translation may require changing the &lt;em&gt;code&lt;/em&gt;,
not just the text of the message.
Suppose that in the target language, we needed to write the equivalent of:&lt;/p&gt;
&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;On planet %d, there was a %s&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; what&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; planet&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Oops! We&#39;ve reordered the text, but not the other arguments to &lt;code&gt;printf&lt;/code&gt;.
When using a modern C/C++ compiler,
this would be a compile-time error (since &lt;code&gt;what&lt;/code&gt; is a string and not an integer).
But it&#39;s easy to imagine similar cases where both arguments are strings, and
a nonsense message would result. Message formatters are necessary not only
for resilience to errors, but also for division of labor:
people building systems want to decouple the tasks of programming and translation.&lt;/p&gt;
&lt;h3 id=&quot;icu-messageformat&quot; tabindex=&quot;-1&quot;&gt;ICU MessageFormat &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In search of a better tool for the job, we turn to
one of many tools for formatting messages: ICU MessageFormat (MF1).
According to the &lt;a href=&quot;https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/classMessageFormat.html&quot;&gt;ICU4C API documentation&lt;/a&gt;,
&amp;quot;MessageFormat prepares strings for display to users,
with optional arguments (variables/placeholders)&amp;quot;.&lt;/p&gt;
&lt;p&gt;The MF2 working group describes MF1 more succinctly as &lt;a href=&quot;https://github.com/unicode-org/message-format-wg/blob/main/docs/why_mf_next.md&quot;&gt;&amp;quot;An i18n-aware printf, basically.&amp;quot;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here&#39;s an expanded version of the previous &lt;code&gt;printf&lt;/code&gt; example,
expressed in MF1 (and taken from the &amp;quot;Usage Information&amp;quot; of the API docs):&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;&quot;At {1,time,::jmm} on {1,date,::dMMMM}, there was {2} on planet {0,number}.&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Typically, the task of creating a message string like this is done by a software engineer,
perhaps one who specializes in localization. The work of translating the words in the message
from one natural language to another is done by a translator,
who is not assumed to also be a software developer.&lt;/p&gt;
&lt;p&gt;The designers of MF1 made it clear in the syntax what content needs to be translated,
and what doesn&#39;t. Any text occurring inside curly braces is non-translatable:
for example, the string &amp;quot;&lt;code&gt;number&lt;/code&gt;&amp;quot; in the last set of curly braces
doesn&#39;t mean the word &amp;quot;number&amp;quot;, but rather,
is a directive that the value of argument 0 should be formatted as a number.
This makes it easy for both developers and translators to work with a message.
In MF1, a piece of text delimited by curly braces is called a &amp;quot;placeholder&amp;quot;.&lt;/p&gt;
&lt;p&gt;The numbers inside placeholders represent arguments provided at runtime.
(Arguments can be specified either by number or name.)
Conceptually, &lt;code&gt;time&lt;/code&gt;, &lt;code&gt;date&lt;/code&gt;, and &lt;code&gt;number&lt;/code&gt; are formatting functions,
which take an argument and an optional &amp;quot;style&amp;quot; (like &lt;code&gt;::jmm&lt;/code&gt; and &lt;code&gt;::dMMMM&lt;/code&gt;
in this example). MF1 has a fixed set of these functions.
So &lt;code&gt;{1,time,::jmm}&lt;/code&gt; should be read as &amp;quot;Format argument 1 as a time value,
using the format specified by the string &lt;code&gt;::jmm&lt;/code&gt;&amp;quot;. (The details of
how the format strings work aren&#39;t important for this explanation.)
Since &lt;code&gt;{2}&lt;/code&gt; has no formatting function specified,
the value of argument 2 is formatted based on its type.
(From context, we can suppose it has a string type,
but we would need to look at the arguments to the message to know for sure.)
The set of types that can be formatted
in this way is fixed (users can&#39;t add new types of their own).&lt;/p&gt;
&lt;p&gt;For brevity, I won&#39;t show how to provide the arguments that are substituted
for the numbers 0, 1 and 2 in the message; the API documentation shows
the C++ code to create those arguments.&lt;/p&gt;
&lt;p&gt;MF1 addresses the reordering issue we noticed in the &lt;code&gt;printf&lt;/code&gt; example.
As long as they don&#39;t change what&#39;s inside the placeholders,
a translator doesn&#39;t have to worry that their translation will
disturb the relationship between placeholders and arguments.
Likewise, a developer doesn&#39;t have to worry about manually
changing the order of arguments to reflect a translation of
the message. The placeholder &lt;code&gt;{2}&lt;/code&gt; means the same thing
regardless of where it appears in the message.
(Using named rather than positional arguments would
make this point even clearer.)&lt;/p&gt;
&lt;p&gt;(The &lt;a href=&quot;https://unicode-org.github.io/icu/userguide/format_parse/messages/&quot;&gt;ICU User Guide&lt;/a&gt; contains more documentation on MF1.
A &lt;a href=&quot;https://phrase.com/blog/posts/guide-to-the-icu-message-format/&quot;&gt;tutorial&lt;/a&gt;
by Mohammad Ashour also contains some useful information on MF1.)&lt;/p&gt;
&lt;h2 id=&quot;enter-messageformat-2-0&quot; tabindex=&quot;-1&quot;&gt;Enter MessageFormat 2.0 &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To summarize a few of the shortcomings of MF1:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lack of modularity: the set of formatters (mostly for numbers, dates, and times)
is fixed. There&#39;s no way to add your own.
&lt;ul&gt;
&lt;li&gt;Like formatting, selection (choosing a different pattern
based on the runtime contents of one or more arguments) is not customizable.
It can only be done either based on plural form, or literal string matching.
This makes it hard to express
the grammatical structures of various human languages.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;No separate data model: the abstract syntax &lt;em&gt;is&lt;/em&gt; concrete syntax.&lt;/li&gt;
&lt;li&gt;There is no way to declare a local variable so that the same piece
of a message can be re-used without repeating it;
all variables are external arguments.&lt;/li&gt;
&lt;li&gt;Baggage: extending the existing spec with different syntax could
change the meaning of existing messages, so a new spec is needed.
(MF1 was not designed for forward-compatibility, and the new spec
is backward-incompatible.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;MF2 represents the best efforts of a number of experts in the field
to address these shortcomings and others.&lt;/p&gt;
&lt;p&gt;I hope the brief history I gave shows
how much work, by many tech workers, has gone into the problem
of message formatting.
Synthesizing the lessons of the past few decades into one standard
has taken years, with seemingly small details provoking
nuanced discussions.
What follows may seem complex, but
the complexity is inherent in the problem space that it addresses. The plethora
of different competing tools to address the same set of problems is evidence for that.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;quot;Inherent is Latin for not your fault.&amp;quot; -- Rich Hickey, &lt;a href=&quot;https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/SimpleMadeEasy.md&quot;&gt;&amp;quot;Simple Made Easy&amp;quot;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&quot;a-simple-example&quot; tabindex=&quot;-1&quot;&gt;A simple example &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here&#39;s the same example in MF2 syntax:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;At time {$time :datetime hour=numeric minute=|2-digit|}, on {$time :datetime day=numeric month=long},&lt;br&gt;there was {$what} on planet {$planet :number}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As in MF1, placeholders are enclosed in curly braces. Variables are prefixed with a &lt;code&gt;$&lt;/code&gt;;
since there are no local bindings for &lt;code&gt;time&lt;/code&gt;, &lt;code&gt;what&lt;/code&gt;, or &lt;code&gt;planet&lt;/code&gt;, they
are treated as external arguments. Although variable names are already
delimited by curly braces, the &lt;code&gt;$&lt;/code&gt; prefix helps make it even clearer
that variable names should not be translated.&lt;/p&gt;
&lt;p&gt;Function names are now prefixed by a &lt;code&gt;:&lt;/code&gt;, and options (like &lt;code&gt;hour&lt;/code&gt;) are named.
There can be multiple options, not just one as in MF1.
This is a loose translation of the MF1 version, since in MF2,
the &lt;code&gt;skeleton&lt;/code&gt; option is not part
of the alpha version of the spec.
(It is possible to write a custom function that takes this option,
and it may be added in the future as part of the built-in &lt;code&gt;datetime&lt;/code&gt; function.)
Instead, the &lt;code&gt;:datetime&lt;/code&gt; formatter can take a variety of
field options (shown in the example) or style options (not shown)
The full options are specified in
&lt;a href=&quot;https://github.com/unicode-org/message-format-wg/blob/main/spec/registry.md&quot;&gt;the Default Registry&lt;/a&gt;
portion of the spec.&lt;/p&gt;
&lt;p&gt;Literal strings that occur within placeholders, like &lt;code&gt;2-digit&lt;/code&gt;, are quoted.
The MF2 syntax for quoting a literal is to enclose it
in vertical bars (&lt;code&gt;|&lt;/code&gt;).
The vertical bars are optional in most cases,
but are necessary for the literal &lt;code&gt;2-digit&lt;/code&gt; because it includes a hyphen.
This syntax was chosen instead of literal quotation marks (&lt;code&gt;&amp;quot;&lt;/code&gt;) because
some use cases for MF2 messages require embedding them in a file format
that assigns meaning to quotation marks.
Vertical bars are less commonly used in this way.&lt;/p&gt;
&lt;p&gt;A shorter version of this example is:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;At time {$time :time}, on {$time :date}, there was {$what} on planet {$planet :number}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;:time&lt;/code&gt; formats the time portion of its operand with default options,
and likewise for &lt;code&gt;:date&lt;/code&gt;.
Implementations may differ on how options are interpreted
and their default values.
Thus, the formatted output of this version may be slightly
different from that of the first version.&lt;/p&gt;
&lt;h3 id=&quot;a-more-complex-example-selection-and-custom-functions&quot; tabindex=&quot;-1&quot;&gt;A more complex example: selection and custom functions &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;So far, the examples are single messages that contain
placeholders that vary based on runtime input.
But sometimes, the translatable text in a message
also depends on runtime input.
A common example is pluralization: in English, consider
&amp;quot;You have one item&amp;quot; versus &amp;quot;You have 5 items.&amp;quot;
We can call these different strings &amp;quot;variants&amp;quot;
of the same message.&lt;/p&gt;
&lt;p&gt;While you can imagine code that selects the right variant
with a conditional, that violates the separation
between code and data that we previously discussed.&lt;/p&gt;
&lt;p&gt;Another motivator for variants is grammatical case.
English has a fairly simple case system (consider
&amp;quot;She told me&amp;quot; versus &amp;quot;I told her&amp;quot;;
the &amp;quot;she&amp;quot; of the first sentence changes to &amp;quot;her&amp;quot;
when that pronoun is the object of the transitive verb
&amp;quot;tell&amp;quot;.)
Some languages have much more complex case systems.
For example, Russian
has six grammatical cases; Basque, Estonian, and Finnish
all have more than ten.
The complexity of translating messages into and between
languages like these is further motivation for organizing
all the variants of a message together.
The overall goal is to make messages as self-contained as possible,
so that changing them doesn&#39;t require changing the code
that manipulates them. MF2 makes that possible in more situations.
While MF1 supports selection based on plural categories,
MF2 also supports a general, customizable form of selection.&lt;/p&gt;
&lt;p&gt;Here&#39;s a very simple example
(necessarily simple since it&#39;s in English) of using custom selectors
in MF2 to express grammatical case:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;.match {$userName :hasCase}&lt;br&gt;vocative   {{Hello, {$userName :person case=vocative}!}}&lt;br&gt;accusative {{Please welcome {$userName :person case=accusative}!}}&lt;br&gt;*          {{Hello!}}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The keyword &lt;code&gt;.match&lt;/code&gt; designates the beginning of a &lt;em&gt;matcher&lt;/em&gt;.&lt;/p&gt;
&lt;h4 id=&quot;how-to-read-a-matcher&quot; tabindex=&quot;-1&quot;&gt;How to read a matcher &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Although MF2 is declarative,
you can read this example imperatively as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Apply &lt;code&gt;:hasCase&lt;/code&gt; to the runtime value of &lt;code&gt;$userName&lt;/code&gt; to get
a string &lt;code&gt;c&lt;/code&gt; representing a grammatical case.&lt;/li&gt;
&lt;li&gt;Compare &lt;code&gt;c&lt;/code&gt; to each of the keys in the three variants
(&amp;quot;&lt;code&gt;vocative&lt;/code&gt;&amp;quot;, &amp;quot;&lt;code&gt;accusative&lt;/code&gt;&amp;quot;, and the wildcard &amp;quot;&lt;code&gt;*&lt;/code&gt;&amp;quot;, which
matches any string.)&lt;/li&gt;
&lt;li&gt;Take the matching variant &lt;code&gt;v&lt;/code&gt; and format its pattern.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This example assumes that the runtime value of the argument &lt;code&gt;$userName&lt;/code&gt;
is a structure whose grammatical case can be determined.
This example also assumes that custom &lt;code&gt;:hasCase&lt;/code&gt; and &lt;code&gt;:person&lt;/code&gt; functions
have been defined (the details of how those functions are defined
are outside the scope of this post).
In this example, &lt;code&gt;:person&lt;/code&gt; is a formatting function,
like &lt;code&gt;:datetime&lt;/code&gt; in the simpler example. &lt;code&gt;:hasCase&lt;/code&gt; is a different
kind of function: a &lt;em&gt;selector function&lt;/em&gt;, which may extract
a field from its argument or do arbitrarily complicated computation
to determine a value to be matched against.&lt;/p&gt;
&lt;p&gt;In general: a &lt;em&gt;matcher&lt;/em&gt; includes one or more &lt;em&gt;selectors&lt;/em&gt; and one or more
&lt;em&gt;variants&lt;/em&gt;. A &lt;em&gt;variant&lt;/em&gt; includes a list of &lt;em&gt;keys&lt;/em&gt;, whose length
must equal the number of selectors in the matcher; and a single
pattern.&lt;/p&gt;
&lt;p&gt;In this example, the selector of the matcher is
the placeholder &lt;code&gt;{$userName :hasCase}&lt;/code&gt;. Selectors appear between
the &lt;code&gt;.match&lt;/code&gt; keyword and the beginning of the first variant.
There are three variants, each of which has a single key.
The strings delimited by &lt;strong&gt;double&lt;/strong&gt; sets of curly braces are patterns,
which in turn contain other placeholders. The selectors are used
to select a pattern based on whether the runtime value of
the selector matches one of the keys.&lt;/p&gt;
&lt;h4 id=&quot;formatting-the-selected-pattern&quot; tabindex=&quot;-1&quot;&gt;Formatting the selected pattern &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;Supposing that &lt;code&gt;:hasCase&lt;/code&gt; maps the value of &lt;code&gt;$userName&lt;/code&gt;
onto &lt;code&gt;&amp;quot;vocative&amp;quot;&lt;/code&gt;, the formatted pattern consists of the
string &amp;quot;Hello, &amp;quot; concatenated with the result of formatting
this placeholder:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;{$userName :person case=vocative}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;concatenated with the string &amp;quot;!&amp;quot;. (This also supposes that we
are formatting to a single string result; future versions of MF2
may also support formatting to a list of &amp;quot;parts&amp;quot;, in which case
the result strings would be returned in a more complicated
data structure, not concatenated.)&lt;/p&gt;
&lt;p&gt;You can read this placeholder like a function call with arguments:
&amp;quot;Call the &lt;code&gt;:person&lt;/code&gt; function on the value of &lt;code&gt;$userName&lt;/code&gt; with an
additional named argument, the name &amp;quot;&lt;code&gt;case&lt;/code&gt;&amp;quot; bound to the string
&lt;code&gt;&amp;quot;vocative&amp;quot;&lt;/code&gt;. We also elide the details of &lt;code&gt;:person&lt;/code&gt;, but you
can suppose it uses additional fields in &lt;code&gt;$userName&lt;/code&gt; to format
it as a personal name.
Such fields might include a title, first name, and last name
(incidentally, see
&lt;a href=&quot;https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/&quot;&gt;&amp;quot;Falsehoods Programmers Believe About Names&amp;quot;&lt;/a&gt;
for why formatting personal names is more complicated than
you might think.)&lt;/p&gt;
&lt;p&gt;Note that MF2 provides no constructs that mutate variables.
Once a variable is bound, its value doesn&#39;t change.
Moreover, built-in functions don&#39;t have side effects,
so as long as custom functions are written in a reasonable way
(that is, without side effects that cross the boundary
between MF2 and function execution), MF2 has no side effects.&lt;/p&gt;
&lt;p&gt;That means that &lt;code&gt;$userName&lt;/code&gt; represents the
same value when it appears in the selector and when it appears
in any of the patterns. Conceptually, &lt;code&gt;:hasCase&lt;/code&gt; returns a result
that is used for selection; it doesn&#39;t change what the name
&lt;code&gt;$userName&lt;/code&gt; is bound to.&lt;/p&gt;
&lt;h4 id=&quot;abstraction-over-function-implementations&quot; tabindex=&quot;-1&quot;&gt;Abstraction over function implementations &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;A developer could plug in an implementation of &lt;code&gt;:hasCase&lt;/code&gt; that requires
its argument to be an object or record that contains grammatical
metadata, and then simply returns one of the fields of this object.
Or we could plug in an implementation that can accept a string
and uses a dictionary for the target language to guess its case.
The message is structured the same way regardless, though
to make it work as expected, the structure of the arguments
must match the expectations of whatever functions consume them.
Effectively, the message is parameterized over the meanings
of its arguments and over the meanings of any custom functions
it uses. This parameterization is a key feature of MF2.&lt;/p&gt;
&lt;h4 id=&quot;summing-up&quot; tabindex=&quot;-1&quot;&gt;Summing up &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;This example couldn&#39;t be expressed in MF1, since MF1 has no custom functions.
The checking for different grammatical cases would be done in
the underlying programming language, with &lt;em&gt;ad hoc&lt;/em&gt; code for selecting
between the different strings. This would be error-prone,
and would force a code change whenever a message changes
(just as in the simple example shown previously).
MF1 does have an equivalent of &lt;code&gt;.match&lt;/code&gt; that supports a few specific
kinds of matching, like plural matching. In MF2, the ability to write
custom selector functions allows for much richer matching.&lt;/p&gt;
&lt;h2 id=&quot;further-reading-or-watching&quot; tabindex=&quot;-1&quot;&gt;Further reading (or watching) &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;For more background both on message formatting in general
and on MF2, I recommend my teammate Ujjwal Sharma&#39;s &lt;a href=&quot;https://fosdem.org/2024/schedule/event/fosdem-2024-2832-messageformat-the-future-of-i18n-on-the-web/&quot;&gt;talk at FOSDEM 2024&lt;/a&gt;,
on which portions of this post are based.
A recent &lt;a href=&quot;https://www.youtube.com/watch?v=D4N4J_8K_T8&quot;&gt;MessageFormat 2 open house&lt;/a&gt; talk
by Addison Phillips and Elango Cheran also provides some great context and motivation
for why a new standard is needed.&lt;/p&gt;
&lt;p&gt;You can also read a detailed argument in favor of a new standard
by visiting the spec repository on GitHub: &lt;a href=&quot;https://github.com/unicode-org/message-format-wg/blob/main/docs/why_mf_next.md&quot;&gt;&amp;quot;Why MessageFormat needs a successor&amp;quot;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;igalia-s-work-on-mf2-or-who-are-we-and-what-are-we-doing-here&quot; tabindex=&quot;-1&quot;&gt;Igalia&#39;s work on MF2, or: Who are we and what are we doing here? &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2024/05/06/messageformat-2-0-a-new-standard-for-translatable-messages/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;So far, I&#39;ve provided a very brief overview of the syntax and semantics of MF2.
More examples will be provided via links in the next post.&lt;/p&gt;
&lt;p&gt;A question I haven&#39;t answered is why this post is on the Igalia
compilers team blog.
I&#39;m a member of the Igalia compilers team; together with
&lt;a href=&quot;https://ryzokuken.dev/&quot;&gt;Ujjwal Sharma&lt;/a&gt;, I have been collaborating with
the MF2 working group,
a subgroup of the &lt;a href=&quot;https://cldr.unicode.org/&quot;&gt;Unicode CLDR&lt;/a&gt; technical committee.
The working group is chaired by &lt;a href=&quot;https://github.com/aphillips&quot;&gt;Addison Phillips&lt;/a&gt;
and has many other &lt;a href=&quot;https://github.com/unicode-org/message-format-wg/blob/main/spec/appendices.md#acknowledgements&quot;&gt;members and contributors&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Part of our work on the compilers team has been
to implement the MF2 specification as a C++ API in &lt;a href=&quot;https://icu.unicode.org/&quot;&gt;ICU&lt;/a&gt;.
(Mihai Niță at Google, also a member of the working group,
implemented the specification as a Java API in ICU.)&lt;/p&gt;
&lt;p&gt;So why would the compilers team work on internationalization?&lt;/p&gt;
&lt;p&gt;Part of our work as a team is to introduce and refine proposals
for new JavaScript (JS) language features
and work with TC39, the JS standards committee, to advance these proposals
with the goal of inclusion in the official JS specification.&lt;/p&gt;
&lt;p&gt;One such proposal that the compilers team has been involved with is
the &lt;code&gt;Intl.MessageFormat&lt;/code&gt; proposal.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For more information on this proposal, see a &lt;a href=&quot;https://archive.fosdem.org/2023/schedule/event/mozilla_intmessageformat/&quot;&gt;FOSDEM 2023 talk&lt;/a&gt; by working group member and proposal co-champion Eemeli Aro; and&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tc39/proposal-intl-messageformat&quot;&gt;The proposal home page&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The implementation of MessageFormat 2 in ICU provides support for browser engines
(the major ones are implemented in C++) to implement this proposal.
Prototype implementations are part of the TC39 proposal process.&lt;/p&gt;
&lt;p&gt;But there&#39;s another reason: as I hinted at the beginning,
the more I learned about MF2, the more I began to see it as
a programming language, at least a domain-specific language.
In &lt;a href=&quot;https://blogs.igalia.com/compilers/2024/05/09/messageformat-2-0-a-domain-specific-language/&quot;&gt;the next post on this blog&lt;/a&gt;, I&#39;ll talk about the implementation work
that Igalia has done on MF2 and reflect on that work from
a programming language design perspective. Stay tuned!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Porting BOLT to RISC-V</title>
		<link href="https://blogs.igalia.com/compilers/2023/06/30/porting-bolt-to-risc-v/"/>
		<updated>2023-06-30T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2023/06/30/porting-bolt-to-risc-v/</id>
		<content type="html">&lt;p&gt;Recently, initial support for RISC-V has &lt;a href=&quot;https://reviews.llvm.org/D145687&quot;&gt;landed&lt;/a&gt; in LLVM&#39;s BOLT
subproject. Even though the current functionality is limited, it was an
interesting experience of open source development to get to this point. In this
post, I will talk about what BOLT is, what it takes to teach BOLT how to process
RISC-V binaries, and the interesting detours I sometimes had to make to get this
work upstream.&lt;/p&gt;
&lt;h1 id=&quot;bolt-overview&quot; tabindex=&quot;-1&quot;&gt;BOLT overview &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/30/porting-bolt-to-risc-v/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/llvm/llvm-project/tree/main/bolt&quot;&gt;BOLT&lt;/a&gt; (Binary Optimization and Layout Tool) is a post-link optimizer
whose primary goal is to improve the layout of binaries. It uses sample-based
profiling to improve the performance of already fully-optimized binaries. That
is, the goal is to be complementary to existing optimization techniques like
&lt;a href=&quot;https://en.wikipedia.org/wiki/Profile-guided_optimization&quot;&gt;PGO&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Interprocedural_optimization&quot;&gt;LTO&lt;/a&gt;, &lt;em&gt;not&lt;/em&gt; to replace them.&lt;/p&gt;
&lt;p&gt;Sample-based profiling is used in order to make it viable to obtain profiles
from production systems as its overhead is usually negligible compared to
profiling techniques based on instrumentation. Another advantage is that no
special build configuration is needed and production binaries can directly be
profiled. The choice for binary optimization (as opposed to, say, optimizing at
the IR level) comes from the accuracy of the profile data: since the profile is
gathered at the binary level, mapping it back to a higher level representation
of the code can be a challenging problem. Since code layout optimizations can
quite easily be applied at the binary level, and the accuracy of the profile is
highest there, the choice for performing post-link optimization seems to be a
logical one.&lt;/p&gt;
&lt;p&gt;To use BOLT, it needs access to a binary and corresponding profile. As mentioned
before, the goal is to optimize production binaries so no special build steps
are required. The only hard requirement is that the binary contains a symbol
table (so stripped binaries are not supported). In order for BOLT to be able to
rearrange functions (in addition to the code within functions), it needs access
to relocations. Linkers usually remove relocations from the final binary but can
be instructed to keep them using the &lt;code&gt;--emit-relocs&lt;/code&gt; flag. For best results, it
is recommended to link your binaries with this flag.&lt;/p&gt;
&lt;p&gt;Gathering a profile on Linux systems can be done in the usual way using &lt;code&gt;perf&lt;/code&gt;.
BOLT provides the necessary tools to convert &lt;code&gt;perf&lt;/code&gt; output to an appropriate
format, and to combine multiple profiles. On systems where &lt;code&gt;perf&lt;/code&gt; is not
available, BOLT can also instrument binaries to create profiles. For more
information on how to use BOLT, see the &lt;a href=&quot;https://github.com/llvm/llvm-project/tree/main/bolt#usage&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For more details on BOLT, including design decisions and evaluation, see the
&lt;a href=&quot;https://research.fb.com/publications/bolt-a-practical-binary-optimizer-for-data-centers-and-beyond/&quot;&gt;CGO&#39;19 paper&lt;/a&gt;. Let&#39;s move on to discuss some of BOLT&#39;s internals to
understand what is needed to support RISC-V.&lt;/p&gt;
&lt;h1 id=&quot;bolt-internals&quot; tabindex=&quot;-1&quot;&gt;BOLT internals &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/30/porting-bolt-to-risc-v/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Optimizing the layout of a binary involves shuffling code around. The biggest
challenge in doing this, is making sure that all code references are still
correct. Indeed, moving a function or basic block to a different location means
changing its address and all jumps, calls, or other references to it need to be
updated because of it.&lt;/p&gt;
&lt;p&gt;To do this correctly, BOLT&#39;s &lt;em&gt;rewriting pipeline&lt;/em&gt; transforms binaries in the
following (slightly simplified) way:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Function discovery&lt;/em&gt;: using (mostly) the ELF symbol table, the boundaries of
functions are recorded;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Disassembly&lt;/em&gt;: using LLVM&#39;s &lt;a href=&quot;https://www.llvm.org/docs/CodeGenerator.html#the-mc-layer&quot;&gt;MC-layer&lt;/a&gt;, function bodies are
disassembled into lists of &lt;code&gt;MCInst&lt;/code&gt; objects;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;CFG construction&lt;/em&gt;: basic blocks are discovered in the instruction lists and
references between them resolved, resulting in a control-flow graph for each
function;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Optimizations&lt;/em&gt;: using the CFG, basic block and function layout is optimized
based on the profile;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Assembly&lt;/em&gt;: the new layout is emitted, using LLVM&#39;s &lt;code&gt;MCStreamer&lt;/code&gt; API, to an
ELF object file in memory;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Link&lt;/em&gt;: since this object file might still contain external references, it is
linked to produce the final binary.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Some of these steps are completely architecture independent. For example,
function discovery only needs the ELF symbol table. Others do need architecture
specific information. Fortunately, BOLT has supported multiple architectures
from the beginning (X86-64 and AArch64) so an abstraction layer exists that
makes it relatively straightforward to add a new target. Let&#39;s talk about what
is needed to teach BOLT to transform RISC-V binaries.&lt;/p&gt;
&lt;h1 id=&quot;teaching-bolt-risc-v&quot; tabindex=&quot;-1&quot;&gt;Teaching BOLT RISC-V &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/30/porting-bolt-to-risc-v/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Thanks to BOLT&#39;s architecture abstraction layer, adding support for a new target
turned out to be mostly straightforward. I will go over the parts of BOLT&#39;s
rewriting pipeline that need architecture-specific information while focusing on
the aspects of RISC-V that made this slightly tricky sometimes.&lt;/p&gt;
&lt;h2 id=&quot;dis-assembly&quot; tabindex=&quot;-1&quot;&gt;(Dis)assembly &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/30/porting-bolt-to-risc-v/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Assembly and disassembly of binaries is obviously architecture-dependent. BOLT
uses various MC-layer LLVM APIs to perform these tasks. More specifically,
&lt;a href=&quot;https://llvm.org/doxygen/classllvm_1_1MCDisassembler.html&quot;&gt;&lt;code&gt;MCDisassembler&lt;/code&gt;&lt;/a&gt; is used for disassembly while
&lt;a href=&quot;https://llvm.org/doxygen/classllvm_1_1MCAssembler.html&quot;&gt;&lt;code&gt;MCAssembler&lt;/code&gt;&lt;/a&gt; is used (indirectly via
&lt;a href=&quot;https://llvm.org/doxygen/classllvm_1_1MCObjectStreamer.html&quot;&gt;&lt;code&gt;MCObjectStreamer&lt;/code&gt;&lt;/a&gt;) for assembly. The good news is that
there is excellent RISC-V support in the MC-layer so this can readily be used by
BOLT.&lt;/p&gt;
&lt;h2 id=&quot;cfg-construction&quot; tabindex=&quot;-1&quot;&gt;CFG construction &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/30/porting-bolt-to-risc-v/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The result of disassembly is a linear list of instructions in the order they
appear in the binary. In the MC-layer, instructions are represented by
&lt;a href=&quot;https://llvm.org/doxygen/classllvm_1_1MCInst.html&quot;&gt;&lt;code&gt;MCInst&lt;/code&gt;&lt;/a&gt; objects. In this representation, instructions essentially
consist of an opcode and a list of operands, where operands could be registers,
immediates, or more high-level expressions (&lt;a href=&quot;https://llvm.org/doxygen/classllvm_1_1MCExpr.html&quot;&gt;&lt;code&gt;MCExpr&lt;/code&gt;&lt;/a&gt;). Expressions can
be used, for example, to refer to symbolic program locations (i.e., labels)
instead of using constant immediates.&lt;/p&gt;
&lt;p&gt;Right after disassembly, however, all operands will be registers or immediates.
For example, an instruction like&lt;/p&gt;
&lt;pre class=&quot;language-nasm&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-nasm&quot;&gt;jal ra, f&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;will be disassembled into (heavy pseudo-code here)&lt;/p&gt;
&lt;pre class=&quot;language-cpp&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;token function&quot;&gt;MCInst&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;RISCV&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;JAL&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;RISCV&lt;span class=&quot;token double-colon punctuation&quot;&gt;::&lt;/span&gt;X1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ImmOffset&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;where &lt;code&gt;ImmOffset&lt;/code&gt; is the offset from the &lt;code&gt;jal&lt;/code&gt; instruction to &lt;code&gt;f&lt;/code&gt;. This is not
convenient to handle in BOLT as nothing indicates that this &lt;code&gt;MCInst&lt;/code&gt; actually
refers to &lt;code&gt;f&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Therefore, BOLT post-processes instructions after disassembly and replaces
immediates with symbolic references where appropriate. Two different mechanisms
are used to figure out the address an instruction refers to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For control-transfer instructions (e.g., calls and branches),
&lt;a href=&quot;https://llvm.org/doxygen/classllvm_1_1MCInstrAnalysis.html&quot;&gt;&lt;code&gt;MCInstrAnalysis&lt;/code&gt;&lt;/a&gt; is used to evaluate the target. LLVM&#39;s
RISC-V backend already contained an appropriate implementation for this.&lt;/li&gt;
&lt;li&gt;For other instructions (e.g., &lt;code&gt;auipc&lt;/code&gt;/&lt;code&gt;addi&lt;/code&gt; pairs to load an address in
RISC-V), relocations are used. For this, BOLT&#39;s &lt;code&gt;Relocation&lt;/code&gt; class had to be
extended to support RISC-V ELF relocations.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once the target of an instruction had been determined, BOLT creates an
&lt;code&gt;MCSymbol&lt;/code&gt; at that location and updates the &lt;code&gt;MCInst&lt;/code&gt; to point to that symbol
instead of an immediate offset.&lt;/p&gt;
&lt;p&gt;One question remains: how does BOLT detect control-transfer instructions? Let&#39;s
first discuss how BOLT creates the control-flow graph now that all instructions
symbolically refer to their targets.&lt;/p&gt;
&lt;p&gt;A &lt;a href=&quot;https://en.wikipedia.org/wiki/Control-flow_graph&quot;&gt;CFG&lt;/a&gt; is a directed graph where the nodes are &lt;a href=&quot;https://en.wikipedia.org/wiki/Basic_block&quot;&gt;basic blocks&lt;/a&gt; and the
edges are control-flow transfers between those basic blocks. Without going into
details, BOLT has a target-independent algorithm to create a CFG from a list of
instructions (for those interested, you can find it &lt;a href=&quot;https://github.com/llvm/llvm-project/blob/243f0566dc414e8bb6e15c7a6ae490d0e3cd0656/bolt/lib/Core/BinaryFunction.cpp#L1917-L2182&quot;&gt;here&lt;/a&gt;). It
needs some target-specific information about instructions though. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Terminators&lt;/em&gt; are instructions that end basic block (e.g., branches and
returns but &lt;em&gt;not&lt;/em&gt; calls).&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Branches and jumps&lt;/em&gt; are the instructions that create edges in the CFG.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To get this information, BOLT relies again on &lt;code&gt;MCInstrAnalysis&lt;/code&gt; which provides
methods such as &lt;code&gt;isTerminator&lt;/code&gt; and &lt;code&gt;isCall&lt;/code&gt;. These methods can be specialized by
specific LLVM backends but the default implementation relies on the
&lt;a href=&quot;https://llvm.org/doxygen/classllvm_1_1MCInstrDesc.html&quot;&gt;&lt;code&gt;MCInstrDesc&lt;/code&gt;&lt;/a&gt; class. Objects of this class are generated by
various TableGen files in the backends (e.g., &lt;a href=&quot;https://github.com/llvm/llvm-project/blob/b3b54131d0a025c74082b7cb843d83fbd8814865/llvm/lib/Target/RISCV/RISCVInstrInfo.td&quot;&gt;this one&lt;/a&gt; for
RISC-V). An important property of &lt;code&gt;MCInstrDesc&lt;/code&gt; for the next discussion is that
its information is based &lt;em&gt;only&lt;/em&gt; on opcodes, operands are &lt;em&gt;not&lt;/em&gt; taken into
account.&lt;/p&gt;
&lt;p&gt;LLVM&#39;s RISC-V backend did not specialize &lt;code&gt;MCInstrAnalysis&lt;/code&gt; so BOLT was relying
&lt;code&gt;MCInstrDesc&lt;/code&gt; to get information about terminators and branches. For many
targets (e.g., X86) this might actually be fine but for RISC-V, this causes
problems. For example, take a &lt;code&gt;jal&lt;/code&gt; instruction: is this a terminator, a branch,
a call? Based solely on the opcode, we cannot actually answer these questions
because &lt;code&gt;jal&lt;/code&gt; is used both for direct jumps (terminator) and function calls
(non-terminator).&lt;/p&gt;
&lt;p&gt;The solution to this problem was to specialize &lt;code&gt;MCInstrAnalysis&lt;/code&gt; for RISC-V
taking the &lt;a href=&quot;https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc&quot;&gt;calling convention&lt;/a&gt; into account:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;jal zero, ...&lt;/code&gt; is an unconditional branch (return address discarded);&lt;/li&gt;
&lt;li&gt;&lt;code&gt;jal ra, ...&lt;/code&gt; is a call (return address stored in &lt;code&gt;ra&lt;/code&gt; (&lt;code&gt;x1&lt;/code&gt;) which the
calling convention designates as the return address register);&lt;/li&gt;
&lt;li&gt;Some more rules for &lt;code&gt;jalr&lt;/code&gt;, compressed instructions, detecting returns,...&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So the &lt;a href=&quot;https://reviews.llvm.org/D146438&quot;&gt;first patch&lt;/a&gt; that landed to pave the way for
RISC-V support in BOLT was not in the BOLT project but in the RISC-V MC-layer.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;With this in place, the &lt;a href=&quot;https://reviews.llvm.org/D145687&quot;&gt;patch&lt;/a&gt; to add a RISC-V target to BOLT
consisted mainly of implementing the necessary relocations and implementing the
architecture abstraction layer. The latter consisted mainly of instruction
manipulation (e.g., updating branch targets), detecting some types of
instructions not supported by &lt;code&gt;MCInstrAnalysis&lt;/code&gt; (e.g., nops), and analyzing
RISC-V-specific Procedure Linkage Table (PLT) entries (so BOLT knows which
function they refer to). Once I started to understand the internals of BOLT,
this was relatively straightforward. After iterating over the patch with the
BOLT maintainers (who were very helpful and responsive during this process), it
got accepted in less than a month.&lt;/p&gt;
&lt;p&gt;There was just one minor issue to resolve.&lt;/p&gt;
&lt;h2 id=&quot;linking&quot; tabindex=&quot;-1&quot;&gt;Linking &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/30/porting-bolt-to-risc-v/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The final step in the rewriting pipeline is linking the generated object file.
BOLT is able to rely on LLVM again by using the RuntimeDyld JIT linker which is
part of the &lt;a href=&quot;https://www.llvm.org/docs/MCJITDesignAndImplementation.html&quot;&gt;MCJIT&lt;/a&gt; project. Unfortunately, there was no RISC-V support
yet in RuntimeDyld. Looking at the supported targets, it seemed easy enough to
implement RISC-V support: I just needed to implement the few relocations that
BOLT emits. So I submitted a &lt;a href=&quot;https://reviews.llvm.org/D145686&quot;&gt;patch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Alas, it &lt;a href=&quot;https://reviews.llvm.org/D145686#4222642&quot;&gt;seemed&lt;/a&gt; that things might not be as easy as I hoped:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Is there something preventing Bolt from moving to ORC / JITLink? If Bolt is
able to move over then the aim should be to do that. If Bolt is unable to move
over then we need to know why so that we can address the issue. RuntimeDyld is
very much in maintenance mode at the moment, and we&#39;re working hard to reach
parity in backend coverage so that we can officially deprecate it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Even though this comment was followed up by this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;None of that is a total blocker to landing this, but the bar is high, and it
should be understood that Bolt will &lt;em&gt;need&lt;/em&gt; to migrate in the future.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;trying to push-through the patch didn&#39;t feel like the right approach. For one,
I&#39;m anticipating to need some more advanced linker features for RISC-V in the
future (e.g., linker relaxation) and I wouldn&#39;t want to implement those in a
deprecated linker. Moreover, the recommended linker, &lt;a href=&quot;https://llvm.org/docs/JITLink.html&quot;&gt;JITLink&lt;/a&gt;, has
mostly complete RISC-V support and, importantly, more users and reviewers,
making its implementation most certainly of higher quality than what I would
implement by myself in RuntimeDyld.&lt;/p&gt;
&lt;p&gt;So the way forward for bringing RISC-V support to BOLT seemed to be to first
port BOLT from using RuntimeDyld to JITLink. Since it looked like this
wasn&#39;t going to be a priority for the BOLT maintainers, I decided I might as
well give it a shot myself. Even though this would surely mean a significant
delay in finishing my ultimate goal of RISC-V support in BOLT, it felt like a
great opportunity to me: it allowed me to learn more about linkers and BOLT&#39;s
internals, as well as to invest in a project that am hoping to use in the
foreseeable future.&lt;/p&gt;
&lt;p&gt;Porting BOLT to JITLink was hard, at least for me. It had a far ranging impact
on many parts of BOLT that I had never touched before. This meant it took quite
some time to try and understand these parts, but also that I learned a lot in
the process. Besides changes to BOLT, I &lt;a href=&quot;https://reviews.llvm.org/D149138&quot;&gt;submitted&lt;/a&gt;
&lt;a href=&quot;https://reviews.llvm.org/D150778&quot;&gt;a&lt;/a&gt; &lt;a href=&quot;https://reviews.llvm.org/D151305&quot;&gt;few&lt;/a&gt; JITLink patches to
implement some missing AArch64 relocations that BOLT needed. In the end, I
managed to pass all BOLT tests and submit a &lt;a href=&quot;https://reviews.llvm.org/D147544&quot;&gt;patch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This patch took about a month and a half to get accepted. The BOLT maintainers
were &lt;em&gt;very&lt;/em&gt; helpful and responsive in the process. They were also very strict,
though. Rightfully so, of course, as BOLT is being used in production systems.
The main requirement for the patch to get accepted was that BOLT&#39;s output would
be a 100% binary match with the RuntimeDyld version. This was necessary to
ease the verification of the correctness of the patch. With the help of the BOLT
maintainers, we managed to get the patch in an acceptable state to land it.&lt;/p&gt;
&lt;h1 id=&quot;looking-forward&quot; tabindex=&quot;-1&quot;&gt;Looking forward &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/30/porting-bolt-to-risc-v/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;With BOLT being ported to JITLink, the &lt;a href=&quot;https://reviews.llvm.org/D145687&quot;&gt;patch&lt;/a&gt; to add initial
RISC-V support to BOLT could finally land. This doesn&#39;t mean that BOLT is
currently very usable for RISC-V binaries, though: most binaries can pass
through BOLT fine but many of BOLT&#39;s transformations are not supported yet.&lt;/p&gt;
&lt;p&gt;Since the initial support was added, I landed a few more patches to improve
usability. For example, support for an obscure ELF feature called &lt;a href=&quot;https://www.sco.com/developers/gabi/latest/ch4.reloc.html&quot;&gt;composed
relocations&lt;/a&gt; was &lt;a href=&quot;https://reviews.llvm.org/D146546&quot;&gt;added&lt;/a&gt;, something
RISC-V uses for &lt;code&gt;R_RISCV_ADD32/SUB32&lt;/code&gt; relocations (which BOLT
&lt;a href=&quot;https://reviews.llvm.org/D146554&quot;&gt;supports&lt;/a&gt; now). Other patches deal with
&lt;a href=&quot;https://reviews.llvm.org/D153342&quot;&gt;creation&lt;/a&gt; and &lt;a href=&quot;https://reviews.llvm.org/D153344&quot;&gt;reversal&lt;/a&gt;
of branches, something BOLT needs to fix-up basic blocks after their layout has
changed.&lt;/p&gt;
&lt;p&gt;I&#39;m currently working on handling binaries that have been relaxed during
linking. The issue is that, after BOLT has moved code around, relaxed
instructions might not fit the new addresses anymore. I plan to handle this as
follows: during disassembly, BOLT will &amp;quot;unrelax&amp;quot; instructions (e.g., translating
a &lt;code&gt;jal&lt;/code&gt; back to an &lt;code&gt;auipc&lt;/code&gt;/&lt;code&gt;jalr&lt;/code&gt; pair) to make sure new addresses will always
fit. The linker will then undo this, when possible, by performing relaxation
again. The first step for this, adding linker relaxation support to JITLink,
has been &lt;a href=&quot;https://reviews.llvm.org/D149526&quot;&gt;landed&lt;/a&gt;. More on this in a future post.&lt;/p&gt;
&lt;h1 id=&quot;wrapping-up&quot; tabindex=&quot;-1&quot;&gt;Wrapping up &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/30/porting-bolt-to-risc-v/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Bringing initial RISC-V support to BOLT has been a very interesting and
educational journey for me, both from a technical as well as a social
perspective. Having to work on multiple projects (LLVM MC, JITLink, BOLT) has
taught me new technologies and put me in contact with great communities. I
certainly hope to be able to continue this work in the future.&lt;/p&gt;
&lt;p&gt;I&#39;ll close this post with a reference of the graph at the top, showing what it
took, over a series of ~25 patches, to get RISC-V support in BOLT. I think this
demonstrates the kind of detours that are sometimes needed to get work upstream,
in this case benefiting both the RISC-V community (RISC-V support in BOLT) and
BOLT as a whole (moving away from a deprecated linker and fixing bugs
encountered along the way)&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>QuickJS: An Overview and Guide to Adding a New Feature</title>
		<link href="https://blogs.igalia.com/compilers/2023/06/12/quickjs-an-overview-and-guide-to-adding-a-new-feature/"/>
		<updated>2023-06-12T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2023/06/12/quickjs-an-overview-and-guide-to-adding-a-new-feature/</id>
		<content type="html">&lt;p&gt;In a previous blog post, I briefly mentioned QuickJS (QJS) as an alternative
implementation of JavaScript (JS) that does not run in a web browser. This
time, I&#39;d like to delve deeper into QJS and explain how it works.&lt;/p&gt;
&lt;p&gt;First, some remarks on QJS&#39;s history and overall architecture. QJS
was written by &lt;a href=&quot;https://www.bellard.org/&quot;&gt;Fabrice Bellard&lt;/a&gt;, who you may know as the
original author of Qemu and FFmpeg, and was first released in
2019. QJS is primarily a bytecode interpreter (with no &lt;a href=&quot;https://en.wikipedia.org/wiki/Just-in-time_compilation&quot;&gt;JIT compiler&lt;/a&gt; tiers) that
can execute JS relatively &lt;a href=&quot;https://bellard.org/quickjs/bench.html&quot;&gt;quickly&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;You can invoke QJS from the command-line like NodeJS and similar systems:&lt;/p&gt;
&lt;pre class=&quot;language-shell-session&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-shell-session&quot;&gt;&lt;span class=&quot;token command&quot;&gt;&lt;span class=&quot;token shell-symbol important&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;token bash language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;console.log(&#39;hello world&#39;);&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; hello.js&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token command&quot;&gt;&lt;span class=&quot;token shell-symbol important&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;token bash language-bash&quot;&gt;qjs hello.js &lt;span class=&quot;token comment&quot;&gt;# qjs is the main executable for quickjs&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token output&quot;&gt;hello world&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;QJS comes with another tool called &lt;code&gt;qjsc&lt;/code&gt; that can produce small executable
binaries from JS source code.  It does so by embedding QJS bytecode in C code
that links with the QJS runtime, which avoids the need to parse JS to bytecode
at runtime.&lt;/p&gt;
&lt;p&gt;The following example demonstrates this (note: feel free to skip over the
the details of this C code output, it&#39;s not crucial for the rest of the post):&lt;/p&gt;
&lt;pre class=&quot;language-shell-session&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-shell-session&quot;&gt;&lt;span class=&quot;token command&quot;&gt;&lt;span class=&quot;token shell-symbol important&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;token bash language-bash&quot;&gt;qjsc hello.js &lt;span class=&quot;token parameter variable&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; hello.c &lt;span class=&quot;token comment&quot;&gt;# qjsc compiles the JS instead of running directly&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token command&quot;&gt;&lt;span class=&quot;token shell-symbol important&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;token bash language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; hello.c&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token output&quot;&gt;/* File generated automatically by the QuickJS compiler. */&lt;br&gt;&lt;br&gt;#include &quot;quickjs-libc.h&quot;&lt;br&gt;&lt;br&gt;const uint32_t qjsc_hello_size = 78;&lt;br&gt;&lt;br&gt;const uint8_t qjsc_hello[78] = {&lt;br&gt; 0x02, 0x04, 0x0e, 0x63, 0x6f, 0x6e, 0x73, 0x6f,&lt;br&gt; 0x6c, 0x65, 0x06, 0x6c, 0x6f, 0x67, 0x16, 0x68,&lt;br&gt; 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72,&lt;br&gt; 0x6c, 0x64, 0x10, 0x68, 0x65, 0x6c, 0x6c, 0x6f,&lt;br&gt; 0x2e, 0x6a, 0x73, 0x0e, 0x00, 0x06, 0x00, 0xa0,&lt;br&gt; 0x01, 0x00, 0x01, 0x00, 0x03, 0x00, 0x00, 0x14,&lt;br&gt; 0x01, 0xa2, 0x01, 0x00, 0x00, 0x00, 0x38, 0xe1,&lt;br&gt; 0x00, 0x00, 0x00, 0x42, 0xe2, 0x00, 0x00, 0x00,&lt;br&gt; 0x04, 0xe3, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00,&lt;br&gt; 0xcd, 0x28, 0xc8, 0x03, 0x01, 0x00,&lt;br&gt;};&lt;br&gt;&lt;br&gt;static JSContext *JS_NewCustomContext(JSRuntime *rt)&lt;br&gt;{&lt;br&gt;  JSContext *ctx = JS_NewContextRaw(rt);&lt;br&gt;  if (!ctx)&lt;br&gt;    return NULL;&lt;br&gt;  JS_AddIntrinsicBaseObjects(ctx);&lt;br&gt;  JS_AddIntrinsicDate(ctx);&lt;br&gt;  JS_AddIntrinsicEval(ctx);&lt;br&gt;  JS_AddIntrinsicStringNormalize(ctx);&lt;br&gt;  JS_AddIntrinsicRegExp(ctx);&lt;br&gt;  JS_AddIntrinsicJSON(ctx);&lt;br&gt;  JS_AddIntrinsicProxy(ctx);&lt;br&gt;  JS_AddIntrinsicMapSet(ctx);&lt;br&gt;  JS_AddIntrinsicTypedArrays(ctx);&lt;br&gt;  JS_AddIntrinsicPromise(ctx);&lt;br&gt;  JS_AddIntrinsicBigInt(ctx);&lt;br&gt;  return ctx;&lt;br&gt;}&lt;br&gt;&lt;br&gt;int main(int argc, char **argv)&lt;br&gt;{&lt;br&gt;  JSRuntime *rt;&lt;br&gt;  JSContext *ctx;&lt;br&gt;  rt = JS_NewRuntime();&lt;br&gt;  js_std_set_worker_new_context_func(JS_NewCustomContext);&lt;br&gt;  js_std_init_handlers(rt);&lt;br&gt;  JS_SetModuleLoaderFunc(rt, NULL, js_module_loader, NULL);&lt;br&gt;  ctx = JS_NewCustomContext(rt);&lt;br&gt;  js_std_add_helpers(ctx, argc, argv);&lt;br&gt;  js_std_eval_binary(ctx, qjsc_hello, qjsc_hello_size, 0);&lt;br&gt;  js_std_loop(ctx);&lt;br&gt;  JS_FreeContext(ctx);&lt;br&gt;  JS_FreeRuntime(rt);&lt;br&gt;  return 0;&lt;br&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&#39;s possible to embed parts of this C output into a larger program, for adding the
ability to script a system in JS for example. You can also compile it, along with the QJS runtime, to WebAssembly (as
is done in tools such as the Bytecode Alliance&#39;s &lt;a href=&quot;https://github.com/bytecodealliance/javy&quot;&gt;Javy&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;QJS as it exists today supports many features in the JS standard, but not all of them.
What if you need to extend it to support modern JS features? Where would you start?&lt;/p&gt;
&lt;p&gt;To address these questions, the rest of this post explains some of the internals
of QJS by walking through the implementation of a new feature. The feature
that we will explore is the &lt;a href=&quot;https://github.com/tc39/proposal-private-fields-in-in&quot;&gt;ergonomic brand checks for private fields proposal&lt;/a&gt;,
which I picked because it is a relatively simple and straightforward feature to implement.
This proposal reached stage 4 in the &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;TC39 process&lt;/a&gt; in 2021, and is currently
part of the official &lt;a href=&quot;https://262.ecma-international.org/13.0/&quot;&gt;ECMAScript 2022 standard&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before getting into the details of adding the new feature, we&#39;ll first start with an explanation
of what the proposal we are exploring actually does. After that, I&#39;ll explain how QJS processes
JS code at a high-level before diving into the details of how to implement this proposal.&lt;/p&gt;
&lt;h1 id=&quot;explaining-ergonomic-brand-checks-for-private-fields&quot; tabindex=&quot;-1&quot;&gt;Explaining &amp;quot;ergonomic brand checks for private fields&amp;quot; &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/12/quickjs-an-overview-and-guide-to-adding-a-new-feature/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The proposal we&#39;ll be exploring is titled &lt;a href=&quot;https://github.com/tc39/proposal-private-fields-in-in&quot;&gt;&amp;quot;Ergonomic brand checks for private fields&amp;quot;&lt;/a&gt;,
which for the rest of this post I&#39;ll shorten to &amp;quot;private brand checks&amp;quot;. Since ES2022, JS has supported
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields&quot;&gt;private fields&lt;/a&gt;
in classes. For example, you can declare a private field as follows:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  #priv &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;     &lt;span class=&quot;token comment&quot;&gt;// private field declaration (needed for #priv to be in scope)&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;#priv&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// returns 0&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;#priv&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// error, it&#39;s private&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that the &lt;code&gt;#&lt;/code&gt; syntax is special and only allowed for private field names.
Ordinary identifiers cannot be used to define a private field.&lt;/p&gt;
&lt;p&gt;Private brand checks, also added in ES2022, are just a way to check if a given object has a given
private field with a convenient syntax. For example, the &lt;code&gt;isFoo&lt;/code&gt; static method in the following
snippet uses a private brand check:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  #priv&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;                                     &lt;span class=&quot;token comment&quot;&gt;// necessary declaration&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;isFoo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; #priv &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; obj&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// brand check for #priv&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Bar&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  #priv&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;                                     &lt;span class=&quot;token comment&quot;&gt;// a different #priv than above!&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;Foo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isFoo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// returns true&lt;/span&gt;&lt;br&gt;Foo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isFoo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;        &lt;span class=&quot;token comment&quot;&gt;// returns false&lt;/span&gt;&lt;br&gt;Foo&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isFoo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Bar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// returns false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The example shows that the proposal overloads the behavior of
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in&quot;&gt;&lt;code&gt;in&lt;/code&gt;&lt;/a&gt;
so that if the left-hand side is a private field name, it checks for the
presence of that private field. Note that since private names are scoped
to the class, private names that look superficially identical in different
classes may not pass the same brand checks (as the example above showed).&lt;/p&gt;
&lt;p&gt;Now that we know what this proposal does, let&#39;s talk about what it takes to implement it.
Before explaining the nitty-gritty details, we&#39;ll first talk about the architecture of
QJS at a high-level.&lt;/p&gt;
&lt;h1 id=&quot;architecture-overview&quot; tabindex=&quot;-1&quot;&gt;Architecture overview &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/12/quickjs-an-overview-and-guide-to-adding-a-new-feature/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Most people probably run JS code in a
web browser or via a runtime like NodeJS, Deno, or Bun that uses those browsers&#39; JS
engines. These engines typically use a tiered implementation strategy in which
code often starts running in an interpreter and then tiers up to a compiler,
perhaps multiple compilers, to produce faster code (see &lt;a href=&quot;https://hacks.mozilla.org/2017/02/a-crash-course-in-just-in-time-jit-compilers/&quot;&gt;this blog post&lt;/a&gt;
by Lin Clark for a high-level overview).&lt;/p&gt;
&lt;p&gt;These engines typically also compile the JS source program into bytecode,
an intermediate form that can be interpreted and compiled more easily than the source code or
its parsed abstract syntax tree (AST).&lt;/p&gt;
&lt;p&gt;QJS shares some of these steps, in that it also compiles JS to bytecode and
then interprets the bytecode. However, it has no additional execution tiers.&lt;/p&gt;
&lt;p&gt;While web browers generally have to fetch JS source code and compile to
bytecode while running (though there is &lt;a href=&quot;https://v8.dev/blog/code-caching-for-devs&quot;&gt;bytecode caching&lt;/a&gt;
to optimize this), when QJS emits an executable (e.g., the use of &lt;code&gt;qjsc&lt;/code&gt; from earlier)
it avoids the runtime parsing step by compiling the bytecode into the executable.&lt;/p&gt;
&lt;p&gt;The QJS bytecode is designed for a stack machine (unlike, say, V8&#39;s
&lt;a href=&quot;https://v8.dev/blog/ignition-interpreter&quot;&gt;Ignition&lt;/a&gt; interpreter which uses a
register machine). That is, the operations in the bytecode fetch data from
the runtime system&#39;s stack. WebAssembly (Wasm) made a similar choice,
which reflects a goal shared by both Wasm and QJS to produce small binaries. A
stack machine can save overhead in instruction encoding because the
instructions do not specify register names to fetch operands from. Instead,
instructions just fetch their operands from the stack.&lt;/p&gt;
&lt;p&gt;Thus, the overall operation of QJS is that it parses a JS file and creates a
representation of the module or script, which contains some functions. Each
function is compiled to bytecode. Then QJS interprets that bytecode to
execute the program.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/2AeF9BADg9-930.avif 930w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/2AeF9BADg9-930.webp 930w&quot;&gt;&lt;img alt=&quot;Diagram illustrating the steps in the execution pipeline for QuickJS&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/2AeF9BADg9-930.png&quot; width=&quot;930&quot; height=&quot;559&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Adding support for a new proposal will affect several parts of this pipeline.
In the case of private brand checks, we will need to modify the parser to
accept the new syntax, add a new bytecode to represent the new operation, and
add a new case in the core interpreter loop to implement that operation.&lt;/p&gt;
&lt;p&gt;With that high-level overview in mind, we&#39;ll dive into specific parts of QJS in the
following sections. Since QJS is written in C
(in fact, the bulk of the system is contained in a &lt;a href=&quot;https://raw.githubusercontent.com/bellard/quickjs/2788d71e823b522b178db3b3660ce93689534e6d/quickjs.c&quot;&gt;single 10k+ line C file&lt;/a&gt;.),
I&#39;ll be showing example snippets of C code to show what needs to change to implement private brand checks.&lt;/p&gt;
&lt;h1 id=&quot;parser&quot; tabindex=&quot;-1&quot;&gt;Parser &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/12/quickjs-an-overview-and-guide-to-adding-a-new-feature/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;The typical parsing pass in JS engines
translates the JS source code to an internal AST representation. There is a
separate bytecode generation pass that walks the AST and linearizes its
structure into bytecodes.&lt;/p&gt;
&lt;p&gt;QJS fuses these two passes and directly generates bytecode while parsing the
source code. While this saves execution time, it does add its own kind of
complexity.&lt;/p&gt;
&lt;p&gt;To understand parsing, it&#39;s useful to know where QJS kicks off the process.
&lt;a href=&quot;https://github.com/bellard/quickjs/blob/2788d71e823b522b178db3b3660ce93689534e6d/quickjs.c#L33576&quot;&gt;&lt;code&gt;JS_EvalInternal&lt;/code&gt;&lt;/a&gt; is the entry
point for evaluating JS code. This can either evaluate and construct the runtime
representation of a script or module in order to execute it, or just compile it to bytecode
to emit to a file.&lt;/p&gt;
&lt;p&gt;In turn, this will first run the lexer to create a tokenized version of the
source code. Afterwards, it calls &lt;a href=&quot;https://github.com/bellard/quickjs/blob/2788d71e823b522b178db3b3660ce93689534e6d/quickjs.c#L33458&quot;&gt;&lt;code&gt;js_parse_program&lt;/code&gt;&lt;/a&gt; to
parse the tokenized source code. The parser has its own state
(&lt;code&gt;JSParseState&lt;/code&gt;) which contains information on where the parser is in the token
stream, the bytecodes emitted so far, and so on.&lt;/p&gt;
&lt;p&gt;The parser broadly follows the structure of the JS specification&#39;s &lt;a href=&quot;https://262.ecma-international.org/12.0/#sec-ecmascript-language-statements-and-declarations&quot;&gt;grammar&lt;/a&gt;,
in which statements and expressions are organized in a particular nesting structure to avoid ambiguity. For
modifying how the &lt;code&gt;in&lt;/code&gt; operator gets parsed, we&#39;ll be interested in how &lt;a href=&quot;https://262.ecma-international.org/12.0/#sec-relational-operators&quot;&gt;relational expressions&lt;/a&gt;
in particular are parsed. As relational expressions are a kind of binary operator expression, they&#39;re handled in QJS by
the &lt;a href=&quot;https://github.com/bellard/quickjs/blob/2788d71e823b522b178db3b3660ce93689534e6d/quickjs.c#L25175&quot;&gt;&lt;code&gt;js_parse_expr_binary&lt;/code&gt;&lt;/a&gt; function.
That function handles binary operators by &amp;quot;level&amp;quot;, corresponding to how they nest in the formal grammar. The bottom level consists
of multiplicative expressions, up to bitwise logical operators. The &lt;code&gt;in&lt;/code&gt; operator is handled at &lt;a href=&quot;https://github.com/bellard/quickjs/blob/2788d71e823b522b178db3b3660ce93689534e6d/quickjs.c#L25253&quot;&gt;level 5&lt;/a&gt;, along with other relational operators like &lt;code&gt;&amp;lt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Since QJS will output the stack bytecode instructions in a single pass,
it&#39;s necessary in a binary expression like &lt;code&gt;expr_1 in expr_2&lt;/code&gt; to first parse
&lt;code&gt;expr_1&lt;/code&gt; and emit its bytecode, then parse &lt;code&gt;expr_2&lt;/code&gt; and emit that, then finally
emit the bytecode for &lt;code&gt;OP_in&lt;/code&gt; (i.e., it&#39;s a post-order traversal of the AST, since
stack instructions are essentially postfix).&lt;/p&gt;
&lt;p&gt;We won&#39;t need to change &lt;code&gt;js_parse_expr_binary&lt;/code&gt; for private brand checks,
as the main difference from normal &lt;code&gt;in&lt;/code&gt; operators is how the left-hand side is parsed.
For that, we&#39;ll be interested in &lt;a href=&quot;https://github.com/bellard/quickjs/blob/2788d71e823b522b178db3b3660ce93689534e6d/quickjs.c#L24330&quot;&gt;&lt;code&gt;js_parse_postfix_expr&lt;/code&gt;&lt;/a&gt;,
which parses references to variable names (and is eventually called by
&lt;code&gt;js_parse_expr_binary&lt;/code&gt;). The &lt;code&gt;js_parse_postfix_expr&lt;/code&gt; function,
like most other parsing functions, has a switch statement that dispatches on different
token types.&lt;/p&gt;
&lt;p&gt;For example, there are tokens such as &lt;code&gt;TOK_IDENT&lt;/code&gt; for ordinary identifiers for
variables (e.g., &lt;code&gt;foo&lt;/code&gt;) and &lt;code&gt;TOK_PRIVATE_NAME&lt;/code&gt; for private field names (e.g., &lt;code&gt;#foo&lt;/code&gt;).
We will need to add a new case for private field tokens in the switch for &lt;code&gt;js_parse_postfix_expr&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; TOK_PRIVATE_NAME&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;            JSAtom name&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token comment&quot;&gt;// Only allow this syntax if the next token is `in`.&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token comment&quot;&gt;// The left-hand side of a private brand check can&#39;t be a nested expression, it&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token comment&quot;&gt;// has to specifically be a private name.&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;peek_token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; TOK_IN&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token comment&quot;&gt;// I&#39;ll explain a bit about atoms later. This code extracts&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token comment&quot;&gt;// a handle for the string content of the private name.&lt;/span&gt;&lt;br&gt;            name &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;JS_DupAtom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; s&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;token&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;u&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ident&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;atom&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;next_token&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token comment&quot;&gt;// This is a new bytecode that we&#39;ll add that looks up that the private&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token comment&quot;&gt;// field is valid and produces data for the `in` operator.&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token function&quot;&gt;emit_op&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; OP_scope_ref_private_field&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token comment&quot;&gt;// These are the arguments for the above op code in the instruction stream.&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token function&quot;&gt;emit_u32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token function&quot;&gt;emit_u16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; s&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;cur_func&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;scope_level&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This case allows a private name to appear, and only allows
it if the next token in the stream is &lt;code&gt;in&lt;/code&gt;. We need the restriction because we don&#39;t want the
private name to appear in any other expression, as those are invalid (private names should
otherwise only appear in declarations in classes or in expressions like &lt;code&gt;this.#priv&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;It also emits the bytecode for this expression, which uses a
new &lt;code&gt;scope_ref_private_field&lt;/code&gt; operator that we add. When new opcodes get added, they&#39;re
defined in &lt;a href=&quot;https://github.com/bellard/quickjs/blob/2788d71e823b522b178db3b3660ce93689534e6d/quickjs-opcode.h&quot;&gt;&lt;code&gt;quickjs-opcode.h&lt;/code&gt;&lt;/a&gt;.
The &lt;code&gt;scope_ref_private_field&lt;/code&gt; opcode is a new variant on existing opcodes
like &lt;a href=&quot;https://github.com/bellard/quickjs/blob/2788d71e823b522b178db3b3660ce93689534e6d/quickjs-opcode.h#L280&quot;&gt;&lt;code&gt;scope_get_private_field&lt;/code&gt;&lt;/a&gt;
that are already defined in that header.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;scope_ref_private_field&lt;/code&gt; operator actually never appears in
executable bytecode, and only appears temporarily as input to another pass. When I said bytecode
is emitted from the parser in a single pass earlier, this was actually a slight simplification.
After the initial parse, the bytecode goes through a scope resolution phase (see
&lt;a href=&quot;https://github.com/bellard/quickjs/blob/2788d71e823b522b178db3b3660ce93689534e6d/quickjs.c#L30782&quot;&gt;&lt;code&gt;resolve_variables&lt;/code&gt;&lt;/a&gt;) where certain
kinds of scope violations are ruled out. For example, the phase would signal an error on the following code:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Invalid example&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;                                    &lt;span class=&quot;token comment&quot;&gt;// missing declaration of #priv&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; #priv &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; obj&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// #priv is unbound&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There&#39;s also an optimization pass on the bytecode to obtain some speedups in interpretation later.&lt;/p&gt;
&lt;p&gt;In the scope resolution phase, &lt;code&gt;scope_ref_private_field&lt;/code&gt; is translated to a &lt;code&gt;get_var_ref&lt;/code&gt; operation, which
looks up a variable in the runtime environment. This will resolve a variable to an index
that the runtime can use to look up the private field in an object&#39;s property table. The reason
we add this new operation is that existing operations like &lt;code&gt;scope_get_private_field&lt;/code&gt; also
get translated to do the actual field lookup in the object immediately, whereas we want to wait until the
&lt;code&gt;in&lt;/code&gt; operator is executed in order to do that.&lt;/p&gt;
&lt;h1 id=&quot;interpreter-and-runtime&quot; tabindex=&quot;-1&quot;&gt;Interpreter and runtime &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/12/quickjs-an-overview-and-guide-to-adding-a-new-feature/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Once the bytecode compilation process is finished, the interpreter can start
executing the program. QJS treats everything uniformly by considering all
execution to take place in a function, so for example the code that runs
in a module or script top-level is also in a special kind of function.&lt;/p&gt;
&lt;p&gt;Therefore, all execution in QJS takes place in a core interpreter loop which
runs a function body.  It loads the bytecode for that function body and
repeatedly runs the operations specified by the bytecode until it reaches the
end.  When executing the bytecode, the interpreter also maintains a
runtime stack that stores temporary values produced by the operators. The
interpreter allocates exactly enough stack space to run a particular function; the
compiler pre-computes the max stack size for each function and
encodes it in the bytecode format.&lt;/p&gt;
&lt;p&gt;To add a new instruction, usually you add a new case to the big switch statement
in the main interpreter loop in &lt;a href=&quot;https://github.com/bellard/quickjs/blob/2788d71e823b522b178db3b3660ce93689534e6d/quickjs.c#L16198&quot;&gt;&lt;code&gt;JS_CallInternal&lt;/code&gt;&lt;/a&gt;.
Since we&#39;re just extending an existing operator, this case &lt;a href=&quot;https://github.com/bellard/quickjs/blob/2788d71e823b522b178db3b3660ce93689534e6d/quickjs.c#L18413&quot;&gt;already exists&lt;/a&gt;.
So instead, we need to extend the helper function &lt;a href=&quot;https://github.com/bellard/quickjs/blob/2788d71e823b522b178db3b3660ce93689534e6d/quickjs.c#L14747&quot;&gt;&lt;code&gt;js_operator_in&lt;/code&gt;&lt;/a&gt;.
An annotated version of that function looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Note: __exception is a QJS convention to warn if the result is unused&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; __exception &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;js_operator_in&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;JSContext &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; JSValue &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;sp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    JSValue op1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; op2&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    JSAtom atom&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; ret&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// Reference the values in the top two stack slots&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// op1 is the result of executing the left-hand side of the `in`&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// op2 is the result of executing the right-hand side of the `in`&lt;/span&gt;&lt;br&gt;    op1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; sp&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    op2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; sp&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// op2 is the right-hand-side of `in`, which must be a JS object&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;JS_VALUE_GET_TAG&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;op2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; JS_TAG_OBJECT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token function&quot;&gt;JS_ThrowTypeError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;invalid &#39;in&#39; operand&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// Atoms are covered in more detail below&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// but generally this just converts a string or symbol to a&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// handle to an interned string, or it&#39;s a tagged number&lt;/span&gt;&lt;br&gt;    atom &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;JS_ValueToAtom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; op1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unlikely&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;atom &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; JS_ATOM_NULL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// Look up if the property corresponding to left-hand-side name exists in the object.&lt;/span&gt;&lt;br&gt;    ret &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;JS_HasProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; op2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; atom&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// QJS also has a reference-counting garbage collector. We need to appropriately&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// free (i.e, decrement refcounts) on values when we stop using them.&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token function&quot;&gt;JS_FreeAtom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; atom&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ret &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token function&quot;&gt;JS_FreeValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; op1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token function&quot;&gt;JS_FreeValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; op2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// Push a boolean onto the top stack slot&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// Note: the stack is shrunk after this by the main loop, so -2 is the top.&lt;/span&gt;&lt;br&gt;    sp&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;JS_NewBool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ret&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point in the code, the results of evaluating the left- and right-hand
side expressions of an &lt;code&gt;in&lt;/code&gt; are already on the stack. These are JS values, so
now might be a good time to talk about how values are represented in QJS.&lt;/p&gt;
&lt;h2 id=&quot;object-representation&quot; tabindex=&quot;-1&quot;&gt;Object Representation &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/12/quickjs-an-overview-and-guide-to-adding-a-new-feature/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;All JS engines have their own internal representation of JS values, which
include primitive values such as symbols and numbers and also object values.
Since JS is dynamically typed, a given function can be called with all kinds of
values, so the engine&#39;s representation needs a way to distinguish the values
to appropriately signal an error, or choose the correct operation.&lt;/p&gt;
&lt;p&gt;To do this, values need to come with some kind of tag.
Some engines use a tagging scheme such as NaN-boxing to store all values
inside the bit pattern of a 64-bit floating point number (using the different kinds of NaNs
that exist in the IEEE-754 standard to distinguish cases).
My colleague Andy Wingo wrote a &lt;a href=&quot;https://wingolog.org/archives/2011/05/18/value-representation-in-javascript-implementations&quot;&gt;blog post&lt;/a&gt; on
this topic a while ago, laying out various options that JS engines use.&lt;/p&gt;
&lt;p&gt;QJS uses a much simpler scheme, and dedicates 128 bits to each JS value. Half of
that is the payload (a 64-bit float, pointer, etc.) and half is the tag value. The
following definitions show how this is represented in C:&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;union&lt;/span&gt; JSValueUnion &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token class-name&quot;&gt;int32_t&lt;/span&gt; int32&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;double&lt;/span&gt; float64&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;ptr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; JSValueUnion&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;typedef&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JSValue&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    JSValueUnion u&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token class-name&quot;&gt;int64_t&lt;/span&gt; tag&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; JSValue&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On 32-bit platforms there is a different tagging scheme that I won&#39;t detail other
than to note that it uses NaN-boxing with a 64-bit representation.&lt;/p&gt;
&lt;p&gt;For the most part, the representation details are abstracted by various macros like &lt;code&gt;JS_VALUE_GET_TAG&lt;/code&gt;
used in the example code above, so there won&#39;t be much need to directly interact
with the value representation in this post.&lt;/p&gt;
&lt;h3 id=&quot;reference-counting-and-objects&quot; tabindex=&quot;-1&quot;&gt;Reference counting and objects &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/12/quickjs-an-overview-and-guide-to-adding-a-new-feature/&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Compound data, such as objects and strings, are tracked by a relatively
simple reference counting garbage collector in QJS. This is in contrast to the much more complex
collectors in web engines, such as WebKit&#39;s &lt;a href=&quot;https://webkit.org/blog/7122/introducing-riptide-webkits-retreating-wavefront-concurrent-garbage-collector/&quot;&gt;Riptide&lt;/a&gt;,
that have different design tradeoffs and requirements such as the need for concurrency.
There&#39;s a lot more to say about how reference counting and compound data work in QJS,
but I&#39;ll save most of those details for a future post.&lt;/p&gt;
&lt;h2 id=&quot;atoms-and-strings&quot; tabindex=&quot;-1&quot;&gt;Atoms and strings &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/12/quickjs-an-overview-and-guide-to-adding-a-new-feature/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Certain data types have a special representation because they are so common and
are used repeatedly in the program. These are small integers and strings. These
correspond to property names, symbols, private names, and so on.
QJS uses a datatype called an Atom for these cases (which has
already appeared in code examples above).&lt;/p&gt;
&lt;p&gt;An atom is a handle that is either tagged as an integer, or is an index that
refers to an &lt;a href=&quot;https://en.wikipedia.org/wiki/String_interning&quot;&gt;interned string&lt;/a&gt;, i.e.,
a unique string that is only allocated once and stored in a hash table.
Atoms that appear in the program&#39;s bytecode are also serialized in the bytecode
format itself, and are loaded into the runtime table on initialization.&lt;/p&gt;
&lt;p&gt;The data type &lt;code&gt;JSAtom&lt;/code&gt; is defined as a &lt;code&gt;uint32_t&lt;/code&gt;, so it&#39;s just a 32-bit integer.
Properties of objects, for example, are always accessed with atoms as the
property key. This means that property tables in objects just need to map
atoms to the stored values.&lt;/p&gt;
&lt;p&gt;You can see this in action with the &lt;code&gt;JS_HasProperty&lt;/code&gt; lookup above, which
looks like &lt;code&gt;JS_HasProperty(ctx, op2, atom)&lt;/code&gt;. This code looks up a key &lt;code&gt;atom&lt;/code&gt; in the
object &lt;code&gt;op2&lt;/code&gt;&#39;s property table. In turn, &lt;code&gt;atom&lt;/code&gt; comes
from the line &lt;code&gt;atom = JS_ValueToAtom(ctx, op1)&lt;/code&gt;, which converts the
property name value &lt;code&gt;op1&lt;/code&gt; into either an integer or a handle to an interned string.&lt;/p&gt;
&lt;h2 id=&quot;changing-the-operation-to-support-private-fields&quot; tabindex=&quot;-1&quot;&gt;Changing the operation to support private fields &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/12/quickjs-an-overview-and-guide-to-adding-a-new-feature/&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The actual change to &lt;code&gt;js_operator_in&lt;/code&gt; to support private brand checks is
very simple. In the case that the private field is a non-method field, the
resolved private name lookup via &lt;code&gt;get_var_ref&lt;/code&gt; pushes a symbol value
onto the stack. This case doesn&#39;t require any changes.&lt;/p&gt;
&lt;p&gt;In the case that the private field refers to a method, the name lookup pushes a function
object onto the stack. We then need to run a private brand check with the
target object and this private function, to ensure the private function really
is part of the object.&lt;/p&gt;
&lt;p&gt;At a high level, you can see the similarity between this operation and
the runtime semantics described in the &lt;a href=&quot;https://tc39.es/proposal-private-fields-in-in/&quot;&gt;formal spec&lt;/a&gt; for the private brand
check proposal.&lt;/p&gt;
&lt;p&gt;The modified code looks like the following:&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; __exception &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;js_operator_in&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;JSContext &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; JSValue &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;sp&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    JSValue op1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; op2&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    JSAtom atom&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; ret&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;    op1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; sp&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    op2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; sp&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;JS_VALUE_GET_TAG&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;op2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; JS_TAG_OBJECT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token function&quot;&gt;JS_ThrowTypeError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;invalid &#39;in&#39; operand&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// --- New code here ---&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// This is the same as the previous code, but now under a conditional.&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// It doesn&#39;t need to change, because after resolving the private field&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// name to a symbol via `get_var_ref` the normal `JS_HasProperty` lookup&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// works.&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;JS_VALUE_GET_TAG&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;op1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!=&lt;/span&gt; JS_TAG_OBJECT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        atom &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;JS_ValueToAtom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; op1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unlikely&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;atom &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; JS_ATOM_NULL&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        ret &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;JS_HasProperty&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; op2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; atom&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token function&quot;&gt;JS_FreeAtom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; atom&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// New conditional branch, in case the field operand is an object.&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// When a private method is referenced via `get_var_ref`, it actually&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// produces the function object for that method. We then can call&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// the `JS_CheckBrand` operation that is already defined to check the&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// validity of a private method call.&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token comment&quot;&gt;// JS_CheckBrand is modified to take a boolean (last arg) that&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token comment&quot;&gt;// determines whether to throw on failure or just indicate the&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token comment&quot;&gt;// success/fail state. This is needed as `in` doesn&#39;t throw when&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token comment&quot;&gt;// the check fails, it just returns false.&lt;/span&gt;&lt;br&gt;        ret &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;JS_CheckBrand&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; op2&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; op1&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; FALSE&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// --- New code end ---&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ret &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token function&quot;&gt;JS_FreeValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; op1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token function&quot;&gt;JS_FreeValue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; op2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;    sp&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;JS_NewBool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ret&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1 id=&quot;testing&quot; tabindex=&quot;-1&quot;&gt;Testing &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/12/quickjs-an-overview-and-guide-to-adding-a-new-feature/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We can validate this implementation against the
official &lt;a href=&quot;https://github.com/tc39/test262&quot;&gt;test262&lt;/a&gt; tests. QJS comes with a
test runner that can run against test262 (invoking &lt;code&gt;make test2&lt;/code&gt; will run it).
Since we&#39;ve added a new feature, we must also modify the tested features list
in the &lt;a href=&quot;https://github.com/bellard/quickjs/blob/2788d71e823b522b178db3b3660ce93689534e6d/test262.conf&quot;&gt;test262 configuration file&lt;/a&gt;
to specify that the feature should be tested. For private brand checks, we
change &lt;code&gt;class-fields-private-in=skip&lt;/code&gt; in that file to &lt;code&gt;class-fields-private-in&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After changing the test file, the test262 tests for the private brand check
feature all succeed with the exception of some syntax tests due to an existing
bug with how &lt;code&gt;in&lt;/code&gt; is parsed in general in QJS (the code &lt;code&gt;function f() { &amp;quot;foo&amp;quot; in {} = 0; }&lt;/code&gt; should fail to parse, but errors at runtime instead in QJS).&lt;/p&gt;
&lt;h1 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap-up &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/06/12/quickjs-an-overview-and-guide-to-adding-a-new-feature/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;With the examples above, I&#39;ve walked through what it takes to add a relatively
simple JS language feature to QuickJS. The private brand checks proposal just
adds a new use of an existing syntax, so implementing it mostly just touches
the parser and core interpreter loop. A feature that affects more of the
language, such as adding a new datatype or changing how functions are executed,
would obviously require more code and deeper changes.&lt;/p&gt;
&lt;p&gt;The full changes required to implement this feature (other than test changes)
can be reviewed in &lt;a href=&quot;https://blogs.igalia.com/compilers/code/private-brand-check.txt&quot;&gt;this patch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In future posts, I&#39;m planning to explain other parts of the QJS codebase and
potentially explore how it&#39;s being used in the WebAssembly ecosystem.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Header image credit: &lt;a href=&quot;https://www.pexels.com/photo/selective-focus-photography-of-train-610683/&quot;&gt;https://www.pexels.com/photo/selective-focus-photography-of-train-610683/&lt;/a&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Compiling Bigloo Scheme to WebAssembly</title>
		<link href="https://blogs.igalia.com/compilers/2023/05/10/compiling-bigloo-scheme-to-webassembly/"/>
		<updated>2023-05-10T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2023/05/10/compiling-bigloo-scheme-to-webassembly/</id>
		<content type="html">&lt;p&gt;In the JavaScript world, browser implementations have focused on &lt;a href=&quot;https://en.wikipedia.org/wiki/Just-in-time_compilation&quot;&gt;JIT compilation&lt;/a&gt; as a high-performance implementation technique. Recently, new applications of JS, such as on cloud compute and edge compute platforms, have driven interest in non-JIT implementations of the language. For these kinds of use cases, fast startup and predictable performance can make traditional implementation approaches appealing. An example implementation is &lt;a href=&quot;https://bellard.org/quickjs/&quot;&gt;QuickJS&lt;/a&gt;, which compiles JS to a bytecode format and interprets the bytecodes. Another approach is Manuel Serrano&#39;s &lt;a href=&quot;https://dl.acm.org/doi/abs/10.1145/3473575&quot;&gt;work on Hopc&lt;/a&gt;, which is a performant &lt;a href=&quot;https://en.wikipedia.org/wiki/Ahead-of-time_compilation&quot;&gt;AOT&lt;/a&gt; JS compiler that uses Scheme as an intermediate language.&lt;/p&gt;
&lt;p&gt;Another direction that is gaining interest is compiling &lt;a href=&quot;https://thenewstack.io/will-javascript-become-the-most-popular-webassembly-language/&quot;&gt;JavaScript to WebAssembly&lt;/a&gt; (Wasm). The motivations for this approach are explained very clearly in Lin Clark&#39;s &lt;a href=&quot;https://bytecodealliance.org/articles/making-javascript-run-fast-on-webassembly&quot;&gt;article on making JS run fast on Wasm&lt;/a&gt;, and some of my Igalia colleagues are spearheading this effort with the SpiderMonkey JS engine in collaboration with Bytecode Alliance partners.&lt;/p&gt;
&lt;p&gt;There is still an open question of if we can apply these techniques for AOT compilation of JS to compile JS to Wasm in a practical way (though the &lt;a href=&quot;https://github.com/bytecodealliance/componentize-js&quot;&gt;componentize-js&lt;/a&gt; effort appears to be building up to this using partial evaluation). One way to test this out would be to apply the previously mentioned Hopc compiler. Hopc compiles to &lt;a href=&quot;https://www.scheme.org/&quot;&gt;Scheme&lt;/a&gt; which, via the &lt;a href=&quot;https://www-sop.inria.fr/mimosa/fp/Bigloo/index.html&quot;&gt;Bigloo Scheme&lt;/a&gt; implementation, compiles to C. Using the standard C toolchain for Wasm (i.e., &lt;a href=&quot;https://emscripten.org/&quot;&gt;Emscripten&lt;/a&gt;), we can compile that C code to Wasm.&lt;/p&gt;
&lt;p&gt;To even attempt this, we would have to first make sure Bigloo Scheme&#39;s C output can be compiled to Wasm, which is the main topic of this blog post.&lt;/p&gt;
&lt;h1 id=&quot;bigloo-on-wasm&quot; tabindex=&quot;-1&quot;&gt;Bigloo on Wasm &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/05/10/compiling-bigloo-scheme-to-webassembly/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;In theory, it&#39;s simple to get Bigloo working with Wasm because it can emit C code, which you can compile with the C compiler of your choice. For example, you could use Emscripten&#39;s &lt;code&gt;emcc&lt;/code&gt; to generate the final executable. In practice, it&#39;s more complicated than that.&lt;/p&gt;
&lt;p&gt;For one, if you only compile the user Bigloo code to Wasm, it will fail to execute. The binary relies on several libraries that make up the runtime system, which themselves have to be compiled to Wasm in order to link a final executable.&lt;/p&gt;
&lt;p&gt;The diagram below illustrates the compilation pipeline. The purple boxes at the lower right are the runtime libraries that need to be linked in.&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/CZwKRIXbiR-1116.avif 1116w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/CZwKRIXbiR-1116.webp 1116w&quot;&gt;&lt;img alt=&quot;Diagram illustrating the steps in the compilation pipeline from Hopc to Wasm&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/CZwKRIXbiR-1116.png&quot; width=&quot;1116&quot; height=&quot;506&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;As a result, we will need to build Bigloo twice: once natively and once to Wasm. The latter build to Wasm will create the needed runtime libraries. This approach is also suggested in the &lt;a href=&quot;https://emscripten.org/docs/compiling/Building-Projects.html#build-system-self-execution&quot;&gt;Emscripten documentation&lt;/a&gt; for building projects that use self-execution.&lt;/p&gt;
&lt;p&gt;I&#39;ve scripted this approach in a &lt;a href=&quot;https://github.com/takikawa/bigloo-wasm-dockerfile/blob/main/Dockerfile&quot;&gt;Dockerfile&lt;/a&gt; that contains a reproducible setup for reliably compiling Bigloo to Wasm. You can see that starting at &lt;a href=&quot;https://github.com/takikawa/bigloo-wasm-dockerfile/blob/5138f818501540f79b384064313d1bb436281387/Dockerfile#L21&quot;&gt;line 21&lt;/a&gt; an ordinary native Bigloo is built, with a number of features disabled that won&#39;t work well in Wasm. Starting at &lt;a href=&quot;https://github.com/takikawa/bigloo-wasm-dockerfile/blob/5138f818501540f79b384064313d1bb436281387/Dockerfile#L42&quot;&gt;line 42&lt;/a&gt; a very similar build is done using the &lt;code&gt;emconfigure&lt;/code&gt; wrapper that handles the &lt;code&gt;configure&lt;/code&gt; script process for Emscripten. The options passed mirror the native build, but with some extra options needed for Wasm.&lt;/p&gt;
&lt;p&gt;Like many projects that use Emscripten, some modifications are needed to get Bigloo to compile properly. For example, making &lt;a href=&quot;https://gist.github.com/takikawa/a6fd03fd351f46af791844711a672cf3&quot;&gt;C types more precise&lt;/a&gt;, &lt;a href=&quot;https://gist.github.com/takikawa/e3bdb81eb987b26d7584d3f4e885d5ed&quot;&gt;backporting Emscripten compatibility&lt;/a&gt; patches for included libraries, and &lt;a href=&quot;https://gist.github.com/takikawa/1316c7dbfe6a7b3b15e92d17521f0781&quot;&gt;adjusting autoconf tests&lt;/a&gt; to return a desired result with Emscripten.&lt;/p&gt;
&lt;h1 id=&quot;1-1-4&quot; tabindex=&quot;-1&quot;&gt;1 + 1 = 4? &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/05/10/compiling-bigloo-scheme-to-webassembly/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;There are some tricky details that you need to get right to have working Wasm programs in the end. For example, when I first got a working docker environment to run Bigloo-on-Wasm programs, I got the following result:&lt;/p&gt;
&lt;pre class=&quot;language-shell-session&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-shell-session&quot;&gt;&lt;span class=&quot;token command&quot;&gt;&lt;span class=&quot;token shell-symbol important&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;token bash language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; num.scm &lt;span class=&quot;token comment&quot;&gt;# this is a Bigloo scheme module&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token output&quot;&gt;(module num)&lt;br&gt;(display (+ 1 1)) (newline)&lt;br&gt;&lt;/span&gt;&lt;span class=&quot;token command&quot;&gt;&lt;span class=&quot;token shell-symbol important&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;token bash language-bash&quot;&gt;/opt/bigloo/bin/bigloo &lt;span class=&quot;token parameter variable&quot;&gt;-O3&lt;/span&gt; num.scm &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; num.js &lt;span class=&quot;token parameter variable&quot;&gt;-cc&lt;/span&gt; /emsdk/upstream/emscripten/emcc &lt;span class=&quot;token comment&quot;&gt;# compile to wasm, more arguments are needed in practice, this is a simplified example&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token command&quot;&gt;&lt;span class=&quot;token shell-symbol important&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;token bash language-bash&quot;&gt;emsdk/node/14.18.2_64bit/bin/node num.js &lt;span class=&quot;token comment&quot;&gt;# execute the compiled wasm in nodejs&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token output&quot;&gt;4&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(Side note: if you haven&#39;t used a Wasm toolchain before, you may be confused why the output is &lt;code&gt;num.js&lt;/code&gt;. Wasm toolchains often produce JS glue code that you use to load the actual Wasm code in a browser/JS engine.)&lt;/p&gt;
&lt;p&gt;The Scheme program &lt;code&gt;num.scm&lt;/code&gt; is supposed to print the result of &amp;quot;1 + 1&amp;quot;. The wasm binary helpfully prints... 4. Other programs that I tried, like printing &amp;quot;hello world&amp;quot;, resulted in the IO system trying to print random parts of Wasm&#39;s linear memory.&lt;/p&gt;
&lt;p&gt;The proximal reason for this failure was that the value tagging code in the Bigloo runtime was being configured incorrectly. If you look at the Bigloo tagging code, you see these cpp definitions:&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;  &lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;TAG_SHIFT&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;PTR_ALIGNMENT&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;  &lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;TAG_MASK&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; PTR_ALIGNMENT&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;  &lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;TAG_MASKOBJECT&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;TAG_MASK&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;  &lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;TAG_MASKPOINTER&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;TAG_MASK&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;  &lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;TAG&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_v&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; shift&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tag&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&lt;br&gt;     &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_v&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; shift&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; tag&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;  &lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name function&quot;&gt;UNTAG&lt;/span&gt;&lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_v&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; shift&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tag&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;&lt;br&gt;     &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;long&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_v&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&lt;/span&gt; shift&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token macro property&quot;&gt;&lt;span class=&quot;token directive-hash&quot;&gt;#&lt;/span&gt;  &lt;span class=&quot;token directive keyword&quot;&gt;define&lt;/span&gt; &lt;span class=&quot;token macro-name&quot;&gt;TAG_INT&lt;/span&gt; &lt;span class=&quot;token expression&quot;&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;                   &lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/*  integer tagging       ....00 */&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;TAG&lt;/code&gt; operation is used throughout compiled Bigloo code to tag values into the &lt;a href=&quot;https://medium.com/@samth/on-typed-untyped-and-uni-typed-languages-8a3b4bedf68c&quot;&gt;unityped&lt;/a&gt; Scheme value representation. The default tagging scheme (see &lt;code&gt;TAG_SHIFT&lt;/code&gt;) is a &lt;a href=&quot;https://en.wikipedia.org/w/index.php?title=Tagged_pointer&amp;amp;oldid=1063919013#Folding_tags_into_the_pointer&quot;&gt;typical one&lt;/a&gt; that depends on the pointer alignment, which depends on the word size (4 bytes on 32-bit, 8 bytes on 64-bit). The &lt;code&gt;PTR_ALIGNMENT&lt;/code&gt; definition is defined to be the log base 2 of the word size. This means 2 bits of the value are used for a tag on 32-bit platforms and 3 bits are used on 64-bit platforms.&lt;/p&gt;
&lt;p&gt;In the case of numbers, the tag is &lt;code&gt;0&lt;/code&gt; (&lt;code&gt;TAG_INT&lt;/code&gt; above) so a discrepancy in tagging will produce a mis-shifted number value. That&#39;s exactly why the &lt;code&gt;num.js&lt;/code&gt; program printed &lt;code&gt;4&lt;/code&gt; above. It&#39;s the right answer &lt;code&gt;2&lt;/code&gt; shifted by one bit.&lt;/p&gt;
&lt;p&gt;The reason for that shift is that I was compiling native Bigloo in a 64-bit configuration since that&#39;s the architecture of the host machine. Wasm, however, is specified to have a 32-bit address space (unless the &lt;a href=&quot;https://github.com/webAssembly/memory64&quot;&gt;memory64 proposal&lt;/a&gt; is used). This discrepancy caused values to get shifted with 2 bits in some places, and 3 bits in others during tagging/untagging. After figuring this out, it was relatively easy to compile Bigloo with an i686 toolchain.&lt;/p&gt;
&lt;h1 id=&quot;function-pointers&quot; tabindex=&quot;-1&quot;&gt;Function pointers &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/05/10/compiling-bigloo-scheme-to-webassembly/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;After fixing 32-bit/64-bit discrepancies, simple Bigloo programs would run in a Wasm engine. On more complex examples, however, I was running into function pointer cast errors like the following:&lt;/p&gt;
&lt;pre class=&quot;language-shell-session&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-shell-session&quot;&gt;&lt;span class=&quot;token command&quot;&gt;&lt;span class=&quot;token shell-symbol important&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;token bash language-bash&quot;&gt;emsdk/node/15.14.0_64bit/bin/node bigloo-compiled-program.js&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token output&quot;&gt;RuntimeError: function signature mismatch&lt;br&gt;    at &amp;lt;anonymous&gt;:wasm-function[184]:0x3b430&lt;br&gt;    at &amp;lt;anonymous&gt;:wasm-function[1397]:0x3400bb&lt;br&gt;    at &amp;lt;anonymous&gt;:wasm-function[505]:0x118046&lt;br&gt;    at &amp;lt;anonymous&gt;:wasm-function[325]:0xd693e&lt;br&gt;    at &amp;lt;anonymous&gt;:wasm-function[4224]:0x71dd82&lt;br&gt;    at Ya (&amp;lt;anonymous&gt;:wasm-function[18267]:0x143d987)&lt;br&gt;    at ret.&amp;lt;computed&gt; (/test-output.js:1:112711)&lt;br&gt;    at Object.doRewind (/test-output.js:1:114339)&lt;br&gt;    at /test-output.js:1:114922&lt;br&gt;    at /test-output.js:1:99074&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a &lt;a href=&quot;https://emscripten.org/docs/porting/guidelines/function_pointer_issues.html&quot;&gt;documented issue&lt;/a&gt; that comes up when porting systems to Emscripten. It&#39;s not Emscripten&#39;s fault, because oftentimes the programs are relying on undefined behavior (UB) in C.&lt;/p&gt;
&lt;p&gt;In particular, &lt;a href=&quot;https://en.cppreference.com/w/c/language/cast&quot;&gt;CPPReference says the following&lt;/a&gt; about function pointer casts:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Any pointer to function can be cast to a pointer to any other function type. If the resulting pointer is converted back to the original type, it compares equal to the original value. If the converted pointer is used to make a function call, the behavior is undefined (unless the function types are compatible)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;which means that generally function pointer casts are undefined unless the source and target types are compatible. Bigloo has many cases where function pointers need to be cast. For example, the representation of Scheme procedures contains &lt;a href=&quot;https://github.com/manuel-serrano/bigloo/blob/9c66c638b38245538eaa9c092300de4c66f65179/runtime/Include/bigloo.h#L555&quot;&gt;a field&lt;/a&gt; for a C function pointer:&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;   &lt;span class=&quot;token comment&quot;&gt;/* procedure (closures) */&lt;/span&gt;&lt;br&gt;   &lt;span class=&quot;token keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;procedure&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;      &lt;span class=&quot;token class-name&quot;&gt;header_t&lt;/span&gt; header&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;    &lt;br&gt;      &lt;span class=&quot;token keyword&quot;&gt;union&lt;/span&gt; scmobj &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;entry&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &amp;lt;-- function pointer for the procedure entrypoint&lt;/span&gt;&lt;br&gt;      &lt;span class=&quot;token keyword&quot;&gt;union&lt;/span&gt; scmobj &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;va_entry&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;      &lt;span class=&quot;token keyword&quot;&gt;union&lt;/span&gt; scmobj &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;attr&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;      &lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt; arity&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;      &lt;span class=&quot;token keyword&quot;&gt;union&lt;/span&gt; scmobj &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;obj0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; procedure&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The function pointer&#39;s C type cannot precisely capture the actual behavior even with a uniform value representation, as the arity of the Scheme procedure needs to be represented. C does not prevent you from calling the function with whatever arity you like though, as you can see in the &lt;a href=&quot;https://github.com/manuel-serrano/bigloo/blob/9c66c638b38245538eaa9c092300de4c66f65179/api/gstreamer/src/Clib/bglgst.c#L435&quot;&gt;Gstreamer API code&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-c&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-c&quot;&gt;&lt;span class=&quot;token class-name&quot;&gt;obj_t&lt;/span&gt; proc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; cb&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;proc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// A Scheme procedure object&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; cb&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;arity &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;br&gt;     &lt;span class=&quot;token function&quot;&gt;PROCEDURE_ENTRY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; proc &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; proc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; BEOA &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Extract the function entry pointer and call it&lt;/span&gt;&lt;br&gt;     &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;     &lt;br&gt;  &lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;br&gt;     &lt;span class=&quot;token function&quot;&gt;PROCEDURE_ENTRY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; proc &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; proc&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;convert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt; cb&lt;span class=&quot;token operator&quot;&gt;-&gt;&lt;/span&gt;args&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; BTRUE &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; BEOA &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;     &lt;span class=&quot;token keyword&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;  &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In practice, this kind of UB shouldn&#39;t cause problems for a typical C compiler because its output (assembly/machine code) is untyped. What matters is whether the calling convention is followed (it should be fine in Bigloo since these functions uniformly take and return &lt;code&gt;scmobj*&lt;/code&gt; pointers).&lt;/p&gt;
&lt;p&gt;Since Wasm has a sound static type system, it doesn&#39;t allow such loose typing of functions and will crash with a runtime type check if the types do not match. It&#39;s possible to work around this by using the &lt;code&gt;EMULATE_FUNCTION_POINTER_CASTS&lt;/code&gt; Emscripten option to generate stubs that emulate the cast, but it adds significant overheads as the &lt;a href=&quot;https://emscripten.org/docs/porting/guidelines/function_pointer_issues.html#working-around-function-pointer-issues&quot;&gt;Emscripten docs&lt;/a&gt; note (emphasis mine):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Use EMULATE_FUNCTION_POINTER_CASTS. When you build with -sEMULATE_FUNCTION_POINTER_CASTS, Emscripten emits code to emulate function pointer casts at runtime, adding extra arguments/dropping them/changing their type/adding or dropping a return type/etc. &lt;em&gt;This can add significant runtime overhead, so it is not recommended, but is be worth trying.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The overhead is clear in the generated code, because the option adds dummy function parameters to virtualize calls. Here&#39;s an example showing the decompiled Wasm code with emulated casts:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/JlLNJQE1pa-1115.avif 1115w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/JlLNJQE1pa-1115.webp 1115w&quot;&gt;&lt;img alt=&quot;Screenshot of decompiled Wasm showing a large number of function parameters&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/JlLNJQE1pa-1115.png&quot; width=&quot;1115&quot; height=&quot;767&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;You can see that the function being called with &lt;code&gt;call_indirect&lt;/code&gt; has a huge number of arguments (the highlighted &lt;code&gt;(param i64 ...)&lt;/code&gt; shows the type of the function being called, and the &lt;code&gt;(i64.const 0) ...&lt;/code&gt; above the call are the concrete arguments). There are more than 70 arguments here, and most of them are unused and are present only for the virtualization of the call. This can add up to a huge binary size cost, since there can also be a large number of functions in the Wasm module&#39;s indirect function table:&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/lX1k0kpkhF-670.avif 670w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://blogs.igalia.com/compilers/img/lX1k0kpkhF-670.webp 670w&quot;&gt;&lt;img alt=&quot;Screenshot of the V8 debugger showing a Wasm module with more than 20,000 entries in its function table&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://blogs.igalia.com/compilers/img/lX1k0kpkhF-670.png&quot; width=&quot;670&quot; height=&quot;719&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The screenshot from the V8 debugger above is showing the contents of the running module. In this case the module&#39;s table (highlighted in red) has over 20,000 function entries. Calls to many of these will incur the emulation overhead. It&#39;s not clear to me that there is any good way to avoid this cost without significantly changing the representation of values in Bigloo.&lt;/p&gt;
&lt;h1 id=&quot;what-about-hopc&quot; tabindex=&quot;-1&quot;&gt;What about Hopc? &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/05/10/compiling-bigloo-scheme-to-webassembly/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;After getting Bigloo to compile to Wasm, I did go back to the initial motivation of this blog post and tried to get Hopc (the JS to Scheme compiler) working in order to have a whole pipeline to compile JS to Wasm. While I was able to get a working build, I had some trouble producing a final Wasm program that could serve as a demo without crashing. At some point, some of the runtime initialization code hits a &lt;code&gt;call_indirect&lt;/code&gt; on a null function pointer and crashes.&lt;/p&gt;
&lt;p&gt;I suspect that even if I could resolve the crashes, there would be more work needed to make this practical for the use cases I described at the beginning. The best code size I&#39;ve been able to get for a minimal JS program compiled to Wasm using this pipeline was 29MB, which is rather large. For comparison, Guy Bedford quoted in the &lt;a href=&quot;https://thenewstack.io/will-javascript-become-the-most-popular-webassembly-language/&quot;&gt;JS to Wasm article&lt;/a&gt; linked earlier suggested 5-6MB was a reasonable number for a Spidermonkey embedding.&lt;/p&gt;
&lt;p&gt;There may be opportunities to reduce this overhead. For example, disabling asyncify and function pointer cast emulation reduces the binary to 9.8MB, albeit a non-working one. &lt;a href=&quot;https://emscripten.org/docs/porting/asyncify.html&quot;&gt;Asyncify&lt;/a&gt; appears to be required to use the default &lt;a href=&quot;https://github.com/ivmai/bdwgc&quot;&gt;BDW garbage collector&lt;/a&gt; due to the use of &lt;code&gt;emscripten_scan_registers()&lt;/code&gt;. There is &lt;a href=&quot;https://github.com/emscripten-core/emscripten/issues/18251&quot;&gt;some discussion&lt;/a&gt; of possibly making the asyncify use optional (and possibly using &lt;a href=&quot;https://github.com/WebAssembly/binaryen&quot;&gt;Binaryen&lt;/a&gt;&#39;s &amp;quot;spill pointers&amp;quot; pass), but it looks like this will take more time to materialize. To avoid the asyncify overhead at the Bigloo level, it could be interesting to look into alternative GC configurations that don&#39;t use BDW at all. For the function pointer issue, maybe future changes that leverage the &lt;a href=&quot;https://github.com/WebAssembly/gc&quot;&gt;Wasm GC proposal&lt;/a&gt; (which has a &lt;code&gt;ref.cast&lt;/code&gt; instruction that can cast a function reference to a more precise type) could provide a workaround.&lt;/p&gt;
&lt;h1 id=&quot;wrap-up&quot; tabindex=&quot;-1&quot;&gt;Wrap-up &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2023/05/10/compiling-bigloo-scheme-to-webassembly/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;It was fun to explore this possibility for AOT compiling JS to Wasm, and more generally it was a good exercise in porting a programming language to Wasm. While there were some tricky problems, the Emscripten tools were good at handling many parts of the process automatically.&lt;/p&gt;
&lt;p&gt;I also had to debug a bunch of crashing Wasm code too, and found that the debug support was better than I expected. Passing the debug mode flag &lt;code&gt;-g&lt;/code&gt; to &lt;code&gt;emcc&lt;/code&gt; helped in getting useful stack traces and in utilizing the Chrome debugger. Though I did wish I had access to a &lt;a href=&quot;https://github.com/rr-debugger/rr&quot;&gt;rr-style&lt;/a&gt; time travel debugger to continue backwards from a crash site.&lt;/p&gt;
&lt;p&gt;With regard to Hopc, I think it could be worth exploring further if the runtime crashes in Wasm can be resolved and if the binary size could be brought down using some of the approaches I suggested above. For the time being though, if you wanted to compile Scheme to Wasm you have an option available now with Bigloo. The Bigloo setup can compile some non-trivial Scheme programs too, such as this demo page that uses Olin Shivers&#39; &lt;a href=&quot;https://www.ccs.neu.edu/home/shivers/mazes.html&quot;&gt;maze program&lt;/a&gt; compiled to Wasm: &lt;a href=&quot;https://people.igalia.com/atakikawa/wasm/bigloo/maze.html&quot;&gt;https://people.igalia.com/atakikawa/wasm/bigloo/maze.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For another path to use Scheme on Wasm, also check out my colleagues&#39; work to &lt;a href=&quot;https://wingolog.org/archives/2023/03/20/a-world-to-win-webassembly-for-the-rest-of-us&quot;&gt;compile Guile to Wasm&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Header image credit: &lt;a href=&quot;https://www.pexels.com/photo/close-up-photo-of-codes-1089440/&quot;&gt;https://www.pexels.com/photo/close-up-photo-of-codes-1089440/&lt;/a&gt;&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Igalia&#39;s Compilers Team in 2022H1</title>
		<link href="https://blogs.igalia.com/compilers/2022/08/04/igalias-compilers-team-in-2022h1/"/>
		<updated>2022-08-04T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2022/08/04/igalias-compilers-team-in-2022h1/</id>
		<content type="html">&lt;p&gt;As we enter the second half of 2022, we’d like to provide a summary (necessarily highly condensed and selective!) of what we’ve been up to recently, providing some insight into the breadth of technical challenges our team of over 20 compiler engineers has been tackling.&lt;/p&gt;
&lt;h1 id=&quot;low-level-js-jsc-on-32-bit-systems&quot; tabindex=&quot;-1&quot;&gt;Low-level JS / JSC on 32-bit systems &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2022/08/04/igalias-compilers-team-in-2022h1/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We have continued to maintain support for 32-bit systems (mainly ARMv7, but also MIPS) in JavaScriptCore (JSC). The work involves continuous tracking of upstream development to prevent regressions as well as the development of new features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A major milestone for this has been the completion of support for WebAssembly in the Low-Level Interpreter (LLInt) for ARMv7. The MIPS support is mostly complete.&lt;/li&gt;
&lt;li&gt;Developed an initial prototype of the concurrency compilation in the DFG tier for 32-bit systems, and the results are promising. The work continues, and we expect to upstream it in 2022H2.&lt;/li&gt;
&lt;li&gt;Code reduction and optimizations: we upstreamed several code reductions and optimizations for 32-bit systems (mainly ARMv7): 25% size reduction in DFGOSRExit blocks, 24% in baseline JIT on JetStream2 and 25% code size reduction from porting EXTRA_CTI_THUNKS.&lt;/li&gt;
&lt;li&gt;Improved our hardware testing infrastructure with more MIPS and faster ARMv7 hardware for the buildbots running in the EWS (Early Warning System), which allows for a smaller response time for regressions.&lt;/li&gt;
&lt;li&gt;Deployed two fuzzing bots that run test JSC 24/7. The bots already found a few issues upstream that we reported to Apple. The bugs that affect 64-bit systems were fixed by the team at Apple, while we are responsible for fixing the ones affecting 32-bit systems. We expect to work on them in 2022H2.&lt;/li&gt;
&lt;li&gt;Added logic to transparently re-run failing JSC tests (on 32-bit platforms) and declare them a pass if they’re simply flaky, as long as the flakiness does not rise above a threshold. This means fewer false alerts for developers submitting patches to the EWS and for the people doing QA work. Naturally, the flakiness information is stored in the WebKit resultsdb and visualized at &lt;a href=&quot;https://results.webkit.org/&quot;&gt;results.webkit.org&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;js-and-standards&quot; tabindex=&quot;-1&quot;&gt;JS and standards &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2022/08/04/igalias-compilers-team-in-2022h1/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Another aspect of our work is our contribution to the JavaScript standards effort, through involvement in the TC39 standards body, direct contribution to standards proposals, and implementation of those proposals in the major JS engines.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Further coverage of the &lt;a href=&quot;https://tc39.es/proposal-temporal/docs/&quot;&gt;Temporal&lt;/a&gt; spec in the &lt;a href=&quot;https://github.com/tc39/test262&quot;&gt;Test262&lt;/a&gt; conformance suite, as well as various specification updates. See &lt;a href=&quot;https://ptomato.wordpress.com/2022/03/03/comparing-apples-and-appleoranges/&quot;&gt;this blog post&lt;/a&gt; for insight into some of the challenges tackled by Temporal.&lt;/li&gt;
&lt;li&gt;Performance improvements for JS class features in V8, such as &lt;a href=&quot;https://joyeecheung.github.io/blog/2022/04/14/fixing-snapshot-support-of-class-fields-in-v8/&quot;&gt;faster initialisations&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Work towards supporting snapshots in node.js, including activities such as &lt;a href=&quot;https://joyeecheung.github.io/blog/2022/04/14/fixing-snapshot-support-of-class-fields-in-v8/&quot;&gt;fixing&lt;/a&gt; support for V8 startup snapshots in the presence of class field initializers.&lt;/li&gt;
&lt;li&gt;Collaborating with others on the “&lt;a href=&quot;https://github.com/tc39/proposal-type-annotations&quot;&gt;types as comments&lt;/a&gt;” proposal for JS, successfully reaching stage 1 in the &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;TC39 process&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Implementing &lt;a href=&quot;https://jgriego.net/posts/2022-03-28-shadowrealms-in-webkit.html&quot;&gt;ShadowRealm support in WebKit&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;webassembly&quot; tabindex=&quot;-1&quot;&gt;WebAssembly &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2022/08/04/igalias-compilers-team-in-2022h1/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;WebAssembly is a low-level compilation target for the web, which we have contributed to in terms of specification proposals, LLVM toolchain modifications, implementation work in the JS engines, and working with customers on use cases both on the server and in web browsers.&lt;/p&gt;
&lt;p&gt;Some highlights from the last 6 months include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creation of a &lt;a href=&quot;https://github.com/WebAssembly/stringref&quot;&gt;proposal&lt;/a&gt; for reference-typed strings in WebAssembly to ensure efficient operability with languages like JavaScript. We also landed &lt;a href=&quot;https://bugs.chromium.org/p/v8/issues/detail?id=12868&quot;&gt;patches to implement this proposal in V8&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/wingo/wasm-jit&quot;&gt;Prototyping&lt;/a&gt; Just-In-Time (JIT) compilation within WebAssembly.&lt;/li&gt;
&lt;li&gt;Working to implement support for WebAssembly &lt;a href=&quot;https://github.com/WebAssembly/gc&quot;&gt;GC types&lt;/a&gt; in Clang and LLVM (with one important &lt;a href=&quot;https://github.com/Igalia/ref-cpp&quot;&gt;use case&lt;/a&gt; being efficient and leak-free sharing of object graphs between JS and C++ compiled to Wasm).&lt;/li&gt;
&lt;li&gt;Implementation of support for GC types in WebKit’s implementation of WebAssembly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id=&quot;events&quot; tabindex=&quot;-1&quot;&gt;Events &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2022/08/04/igalias-compilers-team-in-2022h1/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;With in-person meetups becoming possible again, Igalians have been talking on a range of topics - Multi-core Javascript (BeJS), TC39 (JS Nation), RISC-V LLVM (Cambridge RISC-V meetup), and more.&lt;/p&gt;
&lt;p&gt;We’ve also had opportunities for much-needed face to face time within the team, with many of the compilers team meeting in Brussels in May, and for the company-wide summit held in A Coruña in June. These events provided a great opportunity to discuss current technical challenges, strategy, and ideas for the future, knowledge sharing, and of course socialising.&lt;/p&gt;
&lt;h1 id=&quot;team-growth&quot; tabindex=&quot;-1&quot;&gt;Team growth &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2022/08/04/igalias-compilers-team-in-2022h1/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Our team has grown further this year, being joined by:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Nicolò Ribaudo - a core maintainer of &lt;a href=&quot;https://babeljs.io/&quot;&gt;BabelJS&lt;/a&gt;, continuing work on that project after joining Igalia in June as well as contributing to work on JS modules.&lt;/li&gt;
&lt;li&gt;Aditi Singh - previously worked with the team through the &lt;a href=&quot;https://www.igalia.com/coding-experience/&quot;&gt;Coding Experience program&lt;/a&gt;, joining full time in March focusing on the Temporal project.&lt;/li&gt;
&lt;li&gt;Alex Bradbury - a long-time LLVM developer who joined in March and is focusing on WebAssembly and RISC-V work in Clang/LLVM.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We’re keen to continue to grow the team and actively hiring, so if you think you might be interested in working in any of the areas discussed above, please &lt;a href=&quot;https://www.igalia.com/jobs/javascript_engine_developer&quot;&gt;apply here&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id=&quot;more-about-igalia&quot; tabindex=&quot;-1&quot;&gt;More about Igalia &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2022/08/04/igalias-compilers-team-in-2022h1/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;If you&#39;re keen to learn more about how we work at Igalia, a&lt;a href=&quot;https://thenewstack.io/igalia-the-open-source-powerhouse-youve-never-heard-of/&quot;&gt; recent article at The New Stack&lt;/a&gt; provides a fantastic overview and includes comments from a number of customers who have supported the work described in this post.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Recent talks at GUADEC and NodeConf</title>
		<link href="https://blogs.igalia.com/compilers/2021/11/16/recent-talks-at-guadec-and-nodeconf/"/>
		<updated>2021-11-16T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2021/11/16/recent-talks-at-guadec-and-nodeconf/</id>
		<content type="html">&lt;p&gt;Over the summer and now going into autumn, Igalia compilers team members have been presenting talks at various venues about JavaScript and web engines. Today we&#39;d like to share with you two of those talks that you can watch online.&lt;/p&gt;
&lt;p&gt;First, Philip Chimento gave a talk titled &amp;quot;What&#39;s new with JavaScript in GNOME: The 2021 edition&amp;quot; at &lt;a href=&quot;https://events.gnome.org/event/9/&quot;&gt;GUADEC 2021&lt;/a&gt; about GNOME&#39;s integrated JavaScript engine &lt;a href=&quot;https://gjs.guide/&quot;&gt;GJS&lt;/a&gt;. This is part of a series of talks about JavaScript in GNOME that Philip has been giving at GUADEC for a number of years.&lt;/p&gt;
&lt;p&gt;You can watch it on Youtube &lt;a href=&quot;https://www.youtube.com/watch?v=xHqkiSd1hQQ&amp;amp;t=20669s&quot;&gt;here&lt;/a&gt; and the slides for the talk are available &lt;a href=&quot;https://ptomato.name/talks/guadec2021/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;https://www.youtube.com/watch?v=xHqkiSd1hQQ&amp;amp;t=20669s&lt;/p&gt;
&lt;p&gt;Second, Romulo Cintra gave a talk at &lt;a href=&quot;https://www.nodeconfremote.com/&quot;&gt;NodeConf Remote 2021&lt;/a&gt; titled &amp;quot;IPFS - InterPlanetary File System with Node.js&amp;quot;. In this talk, Romulo introduces IPFS: a new distributed file system protocol for sharing files and media in a peer-to-peer fashion. Romulo also talks about some of the efforts to bring this to the web (&lt;a href=&quot;https://arewedistributedyet.com&quot;&gt;https://arewedistributedyet.com/&lt;/a&gt;) and goes over how IPFS can be used with Node.js.&lt;/p&gt;
&lt;p&gt;You can watch Romulo&#39;s talk on YouTube as well by going &lt;a href=&quot;https://www.youtube.com/watch?v=ctFadWFCb2g&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;https://www.youtube.com/watch?v=ctFadWFCb2g&lt;/p&gt;
&lt;p&gt;The slides for the talk are available &lt;a href=&quot;https://ipfs.io/ipfs/QmQCZaHJBZVFncftY8YGsS3BEbgA9Pu6B3JT4gdE7EhELD&quot;&gt;here&lt;/a&gt; or you can even use IPFS to download it: ipfs://QmQCZaHJBZVFncftY8YGsS3BEbgA9Pu6B3JT4gdE7EhELD&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>JS Nation Talk: “How to Outsmart Time: Building Futuristic JavaScript Apps Using Temporal”</title>
		<link href="https://blogs.igalia.com/compilers/2021/07/06/js-nation-talk-how-to-outsmart-time-building-futuristic-javascript-apps-using-temporal/"/>
		<updated>2021-07-06T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2021/07/06/js-nation-talk-how-to-outsmart-time-building-futuristic-javascript-apps-using-temporal/</id>
		<content type="html">&lt;p&gt;Recently Compilers Team member Ujjwal Sharma gave a talk at the &lt;a href=&quot;https://live.jsnation.com/&quot;&gt;JS Nation 2021&lt;/a&gt; conference about the &lt;a href=&quot;https://github.com/tc39/proposal-temporal/&quot;&gt;Temporal&lt;/a&gt; proposal. Check out the recording here:&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://portal.gitnation.org/contents/how-to-outsmart-time-building-futuristic-javascript-apps-using-temporal&quot;&gt;https://portal.gitnation.org/contents/how-to-outsmart-time-building-futuristic-javascript-apps-using-temporal&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The talk goes over how to use Temporal&#39;s new date &amp;amp; time API in real world programming, and also how Temporal interacts with other APIs such as JS Intl.&lt;/p&gt;
&lt;p&gt;We&#39;ve written about Temporal &lt;a href=&quot;https://blogs.igalia.com/compilers/2020/06/23/dates-and-times-in-javascript/&quot;&gt;previously on this blog&lt;/a&gt; and our other teammates have also &lt;a href=&quot;https://ptomato.wordpress.com/2020/07/08/the-surrealist-clock-of-javascript/&quot;&gt;written about&lt;/a&gt; how Temporal might be useful for the GNOME desktop.&lt;/p&gt;
&lt;p&gt;If you&#39;re interested in an audio-format deep-dive about Temporal, also check out the &lt;a href=&quot;https://www.igalia.com/chats/Temporal&quot;&gt;Igalia Chats episode&lt;/a&gt; on the topic.&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Igalia&#39;s Compilers Team in 2020</title>
		<link href="https://blogs.igalia.com/compilers/2021/03/09/igalias-compilers-team-in-2020/"/>
		<updated>2021-03-09T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2021/03/09/igalias-compilers-team-in-2020/</id>
		<content type="html">&lt;p&gt;In a &lt;a href=&quot;https://blogs.igalia.com/compilers/2020/06/05/what-we-do-at-igalias-compiler-team/&quot;&gt;previous blog post&lt;/a&gt;, we introduced the kind of work the Igalia compilers team does and gave a mid-year update on our 2020 progress.&lt;/p&gt;
&lt;p&gt;Now that we have made our way into 2021, we wanted to recap our achievements from 2020 and update you on the exciting improvements we have been making to the web programming platform. Of course, we couldn&#39;t have done this work alone; all of this was brought to you through our collaborations with our clients and upstream partners in the web ecosystem.&lt;/p&gt;
&lt;p&gt;https://www.twitter.com/rkirsling/status/1276299298020290561&lt;/p&gt;
&lt;h1 id=&quot;javascript-class-features&quot; tabindex=&quot;-1&quot;&gt;JavaScript class features &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2021/03/09/igalias-compilers-team-in-2020/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Our engineers at Igalia have continued to push forward on improvements to JS &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes&quot;&gt;classes&lt;/a&gt;. Earlier in 2020, we had landed support for public field declarations in JavaScriptCore (JSC). In the latter half of 2020, we achieved major milestones such as getting &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields&quot;&gt;private class fields&lt;/a&gt; into JSC (with optimizing compiler support!):&lt;/p&gt;
&lt;p&gt;https://www.twitter.com/robpalmer2/status/1276378092349657095&lt;/p&gt;
&lt;p&gt;https://www.twitter.com/caitp88/status/1318919341467979776&lt;/p&gt;
&lt;p&gt;as well as static public and private fields.&lt;/p&gt;
&lt;p&gt;We also helped ship &lt;a href=&quot;https://v8.dev/blog/v8-release-84&quot;&gt;private methods and accessors in V8&lt;/a&gt; version 84. Our work on private methods also landed in JSC and we expect it to be available in future releases of Safari.&lt;/p&gt;
&lt;p&gt;These additions will help JS developers create better abstractions by encapsulating state and behavior in their classes.&lt;/p&gt;
&lt;h1 id=&quot;tc39-and-temporal&quot; tabindex=&quot;-1&quot;&gt;TC39 and Temporal &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2021/03/09/igalias-compilers-team-in-2020/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Our compilers team also contributed throughout 2020 to web standards through its participation in TC39 and related standards bodies.&lt;/p&gt;
&lt;p&gt;One of the big areas we have been working on is the &lt;a href=&quot;https://github.com/tc39/proposal-temporal/&quot;&gt;Temporal&lt;/a&gt; proposal, which aims to provide better date and time handling in JS. When we &lt;a href=&quot;https://blogs.igalia.com/compilers/2020/06/23/dates-and-times-in-javascript/&quot;&gt;blogged&lt;/a&gt; about this in mid-2020, the proposal was still in Stage 2 but we&#39;re expecting it to go Stage 3 soon in 2021. Igalians have been working hard on many aspects of the proposal since mid-2020, including managing community feedback, working on the polyfill, and maintaining the documentation.&lt;/p&gt;
&lt;p&gt;For more info on Temporal, also check out &lt;a href=&quot;https://www.youtube.com/watch?v=3F2A708c1o0&quot;&gt;a talk&lt;/a&gt; by one of engineers, Ujjwal Sharma, at &lt;a href=&quot;https://holyjs-piter.ru/en/&quot;&gt;Holy JS 2020 Piter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;https://twitter.com/Jason_williams/status/1276112646568382464&lt;/p&gt;
&lt;p&gt;Another area we have been contributing to for a number of years is the &lt;a href=&quot;https://github.com/tc39/ecma402&quot;&gt;ECMA-402 Internationalization&lt;/a&gt; (Intl) standard, an important effort that provides &lt;a href=&quot;https://en.wikipedia.org/wiki/Internationalization_and_localization&quot;&gt;i18n&lt;/a&gt; support for JS. We help maintain and edit the specification while also contributing tests and pushing Intl proposals forward. For example, we helped with the test suite of the &lt;a href=&quot;https://www.chromestatus.com/feature/6099397733515264&quot;&gt;&lt;code&gt;Intl.Segmenter&lt;/code&gt;&lt;/a&gt; feature for implementing localized &lt;a href=&quot;https://en.wikipedia.org/wiki/Text_segmentation&quot;&gt;text segmentation&lt;/a&gt;, which recently shipped in Chrome. For a good overview of other recent Intl efforts, check out &lt;a href=&quot;https://docs.google.com/presentation/d/1nEnkIu4BpS9S-_K4WR-glfgB9sbjWEP9DeUXuKnrkkQ/edit#slide=id.p&quot;&gt;these slides&lt;/a&gt; from &lt;a href=&quot;https://events.omg.org/iuc44/&quot;&gt;IUC44&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We&#39;re also contributing to many other proposed features for JS, such as &lt;a href=&quot;https://tc39.es/proposal-weakrefs/&quot;&gt;WeakRefs&lt;/a&gt;, &lt;a href=&quot;https://github.com/tc39/proposal-decimal&quot;&gt;Decimal&lt;/a&gt; (Daniel Ehrenberg from our team gave a &lt;a href=&quot;https://www.youtube.com/watch?v=G3Q4vWf8Peo&quot;&gt;talk&lt;/a&gt; on this at &lt;a href=&quot;https://www.nodetlv.com/2020&quot;&gt;Node.TLV 2020&lt;/a&gt;), &lt;a href=&quot;https://github.com/tc39/proposal-import-assertions&quot;&gt;Import Assertions&lt;/a&gt;, &lt;a href=&quot;https://github.com/tc39/proposal-record-tuple&quot;&gt;Records &amp;amp; Tuples&lt;/a&gt;, &lt;a href=&quot;https://github.com/tc39/proposal-top-level-await&quot;&gt;Top-level await&lt;/a&gt;, and &lt;a href=&quot;https://github.com/tc39/proposal-js-module-blocks&quot;&gt;Module blocks&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://github.com/littledan/proposal-module-fragments/&quot;&gt;module bundling&lt;/a&gt; (Daniel also gave a &lt;a href=&quot;https://www.youtube.com/watch?v=OFUanbq_8Xw&quot;&gt;talk&lt;/a&gt; on these topics at &lt;a href=&quot;https://holyjs-moscow.ru/en/&quot;&gt;Holy JS 2020 Moscow&lt;/a&gt;).&lt;/p&gt;
&lt;h1 id=&quot;node-js&quot; tabindex=&quot;-1&quot;&gt;Node.js &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2021/03/09/igalias-compilers-team-in-2020/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;In addition to our contributions to the client side of the web, we are also contributing to server side use of web engines. In particular, we have continued to contribute to Node.js throughout 2020.&lt;/p&gt;
&lt;p&gt;Some notable contributions include adding experimental support for per-context memory measurements in &lt;a href=&quot;https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V13.md&quot;&gt;version 13&lt;/a&gt; during early 2020.&lt;/p&gt;
&lt;p&gt;Since late 2020, we have been working on improving Node.js startup speed by &lt;a href=&quot;https://github.com/nodejs/node/issues/35711&quot;&gt;moving more of the bootstrap process into the startup snapshot&lt;/a&gt;. For more on this topic, you can watch a talk that one of our engineers, Joyee Cheung, presented at NodeConf Remote 2020 &lt;a href=&quot;https://www.youtube.com/watch?v=G36lrPrF09c&quot;&gt;here&lt;/a&gt; (slides are available &lt;a href=&quot;https://github.com/joyeecheung/talks/blob/master/nodeconf_remote_202011/node-startup-performance.pdf&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;https://twitter.com/mhdawson1/status/1323608062419230721&lt;/p&gt;
&lt;h1 id=&quot;jsc-support-on-32-bit-platforms&quot; tabindex=&quot;-1&quot;&gt;JSC support on 32-bit platforms &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2021/03/09/igalias-compilers-team-in-2020/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Our group also continues to maintain support in JSC for 32-bit platforms. Earlier in 2020 we contributed improvements to JSC on 32-bit such as tail call optimizations, support for checkpoints, and others.&lt;/p&gt;
&lt;p&gt;Since then we have been optimizing LLInt (the low-level interpreter for JSC) on 32-bit, and porting the support of inline caching for delete operations to 32-bit (to improve the performance of delete, you can read about the background on the original optimization from the Webkit blog &lt;a href=&quot;https://webkit.org/blog/10298/inline-caching-delete/&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;We also &lt;a href=&quot;https://linki.tools/2020/11/a-tour-of-the-for-of-implementation-for-32bits-jsc.html&quot;&gt;blogged about&lt;/a&gt; our efforts to support the &lt;code&gt;for-of&lt;/code&gt; intrinsic on 32-bit to improve iteration on JS arrays.&lt;/p&gt;
&lt;p&gt;https://twitter.com/pocmatos/status/1329814124423995396&lt;/p&gt;
&lt;h1 id=&quot;webassembly&quot; tabindex=&quot;-1&quot;&gt;WebAssembly &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2021/03/09/igalias-compilers-team-in-2020/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Finally, we have made a number of contributions to &lt;a href=&quot;https://webassembly.org/&quot;&gt;WebAssembly&lt;/a&gt; (Wasm), the new low-level compiler-target language for the web, on both the specification and implementation sides.&lt;/p&gt;
&lt;p&gt;During 2020, we helped ship and standardize several Wasm features in web engines such as support for &lt;a href=&quot;https://wingolog.org/archives/2020/04/03/multi-value-webassembly-in-firefox-from-1-to-n&quot;&gt;multiple-values&lt;/a&gt;, which can help compilers to Wasm produce better code, and support for &lt;a href=&quot;https://www.asumu.xyz/blog/2020/07/06/shipping-webassembly-s-bigint-i64-conversion-in-firefox/&quot;&gt;BigInt/I64 conversion&lt;/a&gt; in the JS API, which lifts a restriction that made it harder to interact with Wasm programs from JS.&lt;/p&gt;
&lt;p&gt;https://twitter.com/SpiderMonkeyJS/status/1247844182837866497&lt;/p&gt;
&lt;p&gt;We&#39;ve also improved support in tools such as LLVM for the &lt;a href=&quot;https://github.com/WebAssembly/reference-types/&quot;&gt;reference types&lt;/a&gt; proposal, which adds new types to the language that can represent references to values from JS or other host languages. Eventually reference types will be key to supporting the &lt;a href=&quot;https://github.com/WebAssembly/gc/&quot;&gt;garbage collection&lt;/a&gt; proposal (in which references are extended to new struct and array types), which will allow for easier compilation of languages that use GC to Wasm.&lt;/p&gt;
&lt;p&gt;https://twitter.com/pocmatos/status/1316642040906743808&lt;/p&gt;
&lt;p&gt;We&#39;re also actively working on web engine support for &lt;a href=&quot;https://github.com/WebAssembly/exception-handling&quot;&gt;exception handling&lt;/a&gt;, reference types, and other proposals while continuing to contribute to tools and specification work. We plan to help ship more WebAssembly features in browsers during 2021, so look forward to our mid-year update post!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Dates and Times in JavaScript</title>
		<link href="https://blogs.igalia.com/compilers/2020/06/23/dates-and-times-in-javascript/"/>
		<updated>2020-06-23T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2020/06/23/dates-and-times-in-javascript/</id>
		<content type="html">&lt;p&gt;&lt;strong&gt;tl;dr: We are looking for feedback on the &lt;a href=&quot;https://tc39.es/proposal-temporal/docs/index.html&quot;&gt;Temporal proposal&lt;/a&gt;. Try out the &lt;a href=&quot;https://www.npmjs.com/package/proposal-temporal&quot;&gt;polyfill&lt;/a&gt;, and complete the &lt;a href=&quot;https://forms.gle/iL9iZg7Y9LvH41Nv8&quot;&gt;survey&lt;/a&gt;; but don&#39;t use it in production yet!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;JavaScript &lt;code&gt;Date&lt;/code&gt; is broken in ways that cannot be fixed without breaking the web. As the story goes, it was included in the original 10-day JavaScript engine hack and based on java.util.Date, which itself was deprecated in 1997 due to being a terrible API and replaced with a better one. The result has been for all of JavaScript&#39;s history, the built-in &lt;code&gt;Date&lt;/code&gt; has remained very hard to work with directly.&lt;/p&gt;
&lt;p&gt;Starting a few years ago, a proposal has been developing, to add a new globally available object to JavaScript, &lt;code&gt;Temporal&lt;/code&gt;. Temporal is a robust and modern API for working with dates, times, and timestamps, and also makes it easy to do things that were hard or impossible with &lt;code&gt;Date&lt;/code&gt;, like converting dates between time zones, adding and subtracting while accounting for daylight saving time, working with date-only or time-only data, and even handling dates in non-Gregorian calendars. Although Temporal has &amp;quot;just works&amp;quot; defaults, it also provides fine-grained opt-in control of overflows, interpreting ambiguous times, and other corner cases. For more on the history of the proposal, and why it&#39;s not possible to fix &lt;code&gt;Date&lt;/code&gt; itself, read &lt;a href=&quot;https://maggiepint.com/2017/04/09/fixing-javascript-date-getting-started/&quot;&gt;Maggie Pint&#39;s two-part blog post &amp;quot;Fixing JavaScript Date&amp;quot;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For examples of the power of Temporal, check out the &lt;a href=&quot;https://tc39.es/proposal-temporal/docs/cookbook.html&quot;&gt;cookbook&lt;/a&gt;. Many of these examples would be difficult to do with legacy &lt;code&gt;Date&lt;/code&gt;, particularly the ones involving time zones. (We would have put an example in this post, but the code might soon become stale, for reasons which will hopefully become clear!)&lt;/p&gt;
&lt;p&gt;This &lt;a href=&quot;https://github.com/tc39/proposal-temporal&quot;&gt;proposal&lt;/a&gt; is currently at Stage 2 in TC39&#39;s proposal process, and we&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://blogs.igalia.com/compilers/2020/06/23/dates-and-times-in-javascript/&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; are hoping to move it along to Stage 3 soon.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://blogs.igalia.com/compilers/2020/06/23/dates-and-times-in-javascript/&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; We have been working on the feature set of &lt;code&gt;Temporal&lt;/code&gt; and the API for a long time, and we believe it&#39;s full-featured and that the API is reasonable. You don&#39;t design good APIs solely on the drawing board, however, so it&#39;s time to put it to the test and let  the JavaScript developer community try it out and see whether what we&#39;ve come up with meets people&#39;s needs.&lt;/p&gt;
&lt;p&gt;It is still early enough that we can make drastic changes to the API if we find we need to, based on the feedback that we get. So please,  try it out and let us know!&lt;/p&gt;
&lt;h1 id=&quot;how-to-try-temporal&quot; tabindex=&quot;-1&quot;&gt;How to Try Temporal &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2020/06/23/dates-and-times-in-javascript/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;If you just want to try Temporal out casually, with an interactive prompt, that&#39;s easy! Visit the &lt;a href=&quot;https://tc39.es/proposal-temporal/docs/&quot;&gt;API documentation&lt;/a&gt; in your browser. On any of the documentation or cookbook pages, you can &lt;a href=&quot;http://tinyurl.com/jscons&quot;&gt;open your browser console&lt;/a&gt; and Temporal will be already loaded, ready for you to try out the examples. Or you can try it out on &lt;a href=&quot;https://npm.runkit.com/proposal-temporal&quot;&gt;RunKit&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Or,  maybe you are interested in a bit more in-depth evaluation, like building a small test project using Temporal. We know this takes up people&#39;s valuable project time, but it&#39;s also the best way  that we can get the most valuable feedback, so we&#39;d really appreciate this! We have released a &lt;a href=&quot;https://www.npmjs.com/package/proposal-temporal&quot;&gt;polyfill&lt;/a&gt; for the Temporal API on npm. You can use it in your project with &lt;code&gt;npm install --save proposal-temporal&lt;/code&gt;, and import it in your project with &lt;code&gt;const { Temporal } = require(&#39;proposal-temporal&#39;);&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;However, don&#39;t use the polyfill in production applications! The proposal is still at Stage 2, and the polyfill has an 0.x version, so that should make it clear that the API is subject to change, and we do intend to keep changing it when we get feedback from you!&lt;/p&gt;
&lt;h1 id=&quot;how-to-give-feedback&quot; tabindex=&quot;-1&quot;&gt;How to Give Feedback &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2020/06/23/dates-and-times-in-javascript/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;We would &lt;em&gt;love&lt;/em&gt; to hear from you about your experiences with Temporal! Once you&#39;ve tried it, we have a short &lt;a href=&quot;https://forms.gle/iL9iZg7Y9LvH41Nv8&quot;&gt;survey&lt;/a&gt; for you to fill out. If you feel comfortable doing so, please leave us your contact information, since we might want to ask some follow up questions.&lt;/p&gt;
&lt;p&gt;Please also open an issue on our &lt;a href=&quot;https://github.com/tc39/proposal-temporal/issues&quot;&gt;issue tracker&lt;/a&gt; if you have some suggestion! We welcome suggestions whether or not you filled out the survey. You can also browse the feedback that&#39;s already been given in the issue tracker, and give it a thumbs-up if you agree or thumbs-down if you disagree.&lt;/p&gt;
&lt;p&gt;Thanks for participating if you can! All the feedback that we receive now will help us make the right decisions as the proposal moves along to Stage 3 and Temporal eventually appears in your browser.&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&amp;quot;We&amp;quot; in this post means the &lt;a href=&quot;https://github.com/tc39/proposal-temporal#champions&quot;&gt;Temporal champions group&lt;/a&gt;, a group of TC39 delegates and interested people. As you may guess from where this blog post is hosted, it includes members of Igalia&#39;s Compilers team, but this was written on behalf of the Temporal champions. &lt;a href=&quot;https://blogs.igalia.com/compilers/2020/06/23/dates-and-times-in-javascript/&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Read the &lt;a href=&quot;https://tc39.es/process-document/&quot;&gt;TC39 process document&lt;/a&gt; for more information on what these stages mean. tl;dr: Stage 2 is the time to give feedback on the proposal that can still be incorporated even if it requires drastic changes. Stage 3 is when the proposal remains stable except for serious problems discovered during implementation in browsers. &lt;a href=&quot;https://blogs.igalia.com/compilers/2020/06/23/dates-and-times-in-javascript/&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
	</entry>
	
	<entry>
		<title>What we do at Igalia&#39;s Compiler Team</title>
		<link href="https://blogs.igalia.com/compilers/2020/06/05/what-we-do-at-igalias-compiler-team/"/>
		<updated>2020-06-05T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2020/06/05/what-we-do-at-igalias-compiler-team/</id>
		<content type="html">&lt;h1 id=&quot;compilers-for-the-web&quot; tabindex=&quot;-1&quot;&gt;Compilers for the web &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2020/06/05/what-we-do-at-igalias-compiler-team/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;At Igalia, our development teams have included a team specializing in compilers since around 2012. Since most tech companies don&#39;t work on compilers or even more generally on programming language implementation, you might be wondering &amp;quot;What does a compilers team even do?&amp;quot;. This blog post will try to explain, as  well as highlight some of our recent work.&lt;/p&gt;
&lt;p&gt;While many companies who work on compilers own or maintain their own programming language (e.g., like Google and Go, Apple and Swift, Mozilla and Rust, etc.), domain-specific compiler or language, Igalia is a little bit different.&lt;/p&gt;
&lt;p&gt;Since we are a consulting company, our compiler team instead helps maintain and improve existing free software/open source programming language implementations, with a focus on languages for the web. In other words, we help improve JavaScript engines and, more recently, &lt;a href=&quot;https://webassembly.org/&quot;&gt;WebAssembly&lt;/a&gt; (Wasm) runtimes.&lt;/p&gt;
&lt;p&gt;To actually do the work, Igalia has grown a compilers team of developers from a variety of backgrounds. Some of our developers came into the job from a career in industry, and others from a research or academic setting. Our developers are contributors to a variety of non-web languages as well, including functional programming languages and scripting languages.&lt;/p&gt;
&lt;h1 id=&quot;our-recent-work&quot; tabindex=&quot;-1&quot;&gt;Our recent work &lt;a class=&quot;header-anchor&quot; href=&quot;https://blogs.igalia.com/compilers/2020/06/05/what-we-do-at-igalias-compiler-team/&quot;&gt;#&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;Given our team&#39;s diverse backgrounds, we are able to work on not only compiler &lt;em&gt;implementations&lt;/em&gt; (which includes compilation, testing, maintenance, and so on) but also in the &lt;em&gt;standardization process&lt;/em&gt; for language features. To be more specific, here are some examples of projects we&#39;re working on, split into several areas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Maintenance:&lt;/strong&gt; We work on the maintenance of JS engines to make sure they work well on platforms that our customers care about. For example, we maintain the support for 32-bit architectures in JavaScriptCore (WebKit&#39;s JS engine). This is especially important to us because WebKit is used on billions of embedded devices and we are the maintainers of &lt;a href=&quot;https://webkit.org/wpe/&quot;&gt;WPE&lt;/a&gt;, the official WebKit port for embdedded systems.
&lt;ul&gt;
&lt;li&gt;This involves things like making sure that CI continues to pass on platforms like ARMv7 and MIPS, and also making sure that JS engine performance is good on these platforms.&lt;/li&gt;
&lt;li&gt;Recently, some of our developers have been sharing their knowledge about JSC development in several blog posts. &lt;a href=&quot;https://linki.tools/2019/10/a-brief-look-at-the-webkit-workflow.html&quot;&gt;[1]&lt;/a&gt;, &lt;a href=&quot;https://tlog.quasinomial.net/posts/dive-into-jsc/&quot;&gt;[2]&lt;/a&gt;, &lt;a href=&quot;https://caiolima.github.io/jsc/2020/03/12/jsc-inline-cache.html&quot;&gt;[3]&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;JS feature development &amp;amp; standardization:&lt;/strong&gt; We also work on implementing features proposed by the web platform community in all of the major JS engines, and we work on standardizing features as participants in &lt;a href=&quot;https://tc39.es/&quot;&gt;TC39&lt;/a&gt;.
&lt;ul&gt;
&lt;li&gt;Recently we have been doing a lot of work around &lt;a href=&quot;https://github.com/tc39/proposal-class-fields&quot;&gt;class fields&lt;/a&gt; and &lt;a href=&quot;https://github.com/tc39/proposal-private-methods&quot;&gt;private methods&lt;/a&gt; in multiple browsers.&lt;/li&gt;
&lt;li&gt;We&#39;re also involved in the work on the &lt;a href=&quot;https://github.com/tc39/proposal-temporal&quot;&gt;Temporal&lt;/a&gt; proposal for better date/time management in JS.&lt;/li&gt;
&lt;li&gt;Another example of our recent work in standardization is the &lt;a href=&quot;https://github.com/tc39/proposal-bigint&quot;&gt;BigInt&lt;/a&gt; feature, which is now part of the &lt;a href=&quot;https://tc39.es/ecma262/&quot;&gt;language specification&lt;/a&gt; for JS. Igalians led work on both the specification and also its implementation in browsers. &lt;a href=&quot;https://vimeo.com/304865023&quot;&gt;[1]&lt;/a&gt;, &lt;a href=&quot;https://wingolog.org/archives/2019/05/23/bigint-shipping-in-firefox&quot;&gt;[2]&lt;/a&gt; We are currently working on &lt;a href=&quot;https://github.com/WebAssembly/JS-BigInt-integration&quot;&gt;integrating&lt;/a&gt; BigInts with WebAssembly as well.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WebAssembly:&lt;/strong&gt; In the last year, we have gotten more involved in helping to improve Wasm, the new low-level compiler target language for the web (so that you can write C/C++/etc. code that will run on the web).
&lt;ul&gt;
&lt;li&gt;We have some recent blog posts on &lt;a href=&quot;https://wingolog.org/archives/2020/03/25/firefoxs-low-latency-webassembly-compiler&quot;&gt;understanding Firefox&#39;s baseline wasm compiler&lt;/a&gt; and our work on implementing the &lt;a href=&quot;https://wingolog.org/archives/2020/04/03/multi-value-webassembly-in-firefox-from-1-to-n&quot;&gt;multi-value&lt;/a&gt; proposal for the language.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the future, we&#39;ll continue to periodically put pointers to our recent compilers work on this blog, so please follow along!&lt;/p&gt;
&lt;p&gt;If you think you might be interested in helping to expand the web platform as a customer, don&#39;t hesitate to &lt;a href=&quot;https://www.igalia.com/contact/&quot;&gt;get in touch&lt;/a&gt;!&lt;/p&gt;
</content>
	</entry>
	
	<entry>
		<title>Awaiting the future of JavaScript in V8</title>
		<link href="https://blogs.igalia.com/compilers/2016/05/23/awaiting-the-future-of-javascript-in-v8/"/>
		<updated>2016-05-23T00:00:00Z</updated>
		<id>https://blogs.igalia.com/compilers/2016/05/23/awaiting-the-future-of-javascript-in-v8/</id>
		<content type="html">&lt;p&gt;On the evening of Monday, May 16th, 2016, we have made history. We&#39;ve &lt;a href=&quot;https://crrev.com/d08c0304c5779223d6c468373af4815ec3ccdb84&quot;&gt;landed the initial implementation&lt;/a&gt; of &amp;quot;Async Functions&amp;quot; in &lt;a href=&quot;https://v8project.blogspot.com&quot;&gt;V8&lt;/a&gt;, the JavaScript runtime in use by the Google Chrome and Node.js. We do these things not because they are easy, but because they are hard. Because that goal will serve to organize and measure the best of our energies and skills, because that challenge is one we are willing to accept. It is very exciting to see this, roughly 2 months of implementation, codereview and standards finangling/discussion to land. It is truly an honour.&lt;/p&gt;
&lt;p&gt;To introduce you to Async Functions, it&#39;s first necessary to understand two things: the status quo of async programming in JavaScript, as well as Generators (previously implemented by fellow Igalian &lt;a href=&quot;https://wingolog.org/archives/2013/05/08/generators-in-v8&quot;&gt;Andy&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Async programming in JavaScript has historically been implemented by callbacks. &lt;code&gt;window.setTimeout(function toExecuteLaterOnceTimeHasPassed() {}, ...)&lt;/code&gt; being the common example. Callbacks on their own are not scalable: when numerous nested asynchronous operations are needed, code becomes extremely difficult to read and reason about. Abstraction libraries have been tacked on to improve this, including caolan&#39;s &lt;a href=&quot;https://www.npmjs.com/package/async&quot;&gt;async&lt;/a&gt; package, or Promise libraries such as &lt;a href=&quot;https://www.npmjs.com/package/q&quot;&gt;Q&lt;/a&gt;. These abstractions simplify control flow management and data flow management, and are a massive improvement over plain Callbacks. But we can do better! For a more detailed look at Promises, have a look at the fantastic &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&quot;&gt;MDN article&lt;/a&gt;. Some great resources on why and how callbacks can lead to utter non-scalable disaster exist too, check out &lt;a href=&quot;http://callbackhell.com&quot;&gt;http://callbackhell.com&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;The second concept, Generators, allow a runtime to return from a function at an arbitrary line, and later re-enter that function at the following instruction, in order to continue execution. So right away you can imagine where this is going --- we can continue execution of the same function, rather than writing a closure to continue execution in a new function. Async Functions rely on this same mechanism (and in fact, on the underlying Generators implementation), to achieve their goal, immensely simplifying non-trivial coordination of asynchronous operations.&lt;/p&gt;
&lt;p&gt;As a simple example, lets compare the following two approaches:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;deployApplication&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cleanDirectory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__DEPLOYMENT_DIR__&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fetchNpmDependencies&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br&gt;      &lt;span class=&quot;token parameter&quot;&gt;deps&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br&gt;        deps&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br&gt;          &lt;span class=&quot;token parameter&quot;&gt;dep&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;moveToDeploymentSite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br&gt;            dep&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;files&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;__DEPLOYMENT_DIR__&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/deps/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;dep&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;compileSources&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__SRC_DIR__&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;                              __DEPLOYMENT_DIR__&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;uploadToServer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Promise boiler plate makes this preit harder to read and follow than it could be. And what happens if an error occurs? Do we want to add catch handlers to each link in the Promise chain? That will only make it even more difficult to follow, with error handling interleaved in difficult to read ways.&lt;/p&gt;
&lt;p&gt;Lets refactor this using async functions:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;deployApplication&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cleanDIrectory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__DEPLOYMENT_DIR__&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; dependencies &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchNpmDependencies&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// *see below*&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; dep &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; dependencies&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;        &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;moveToDeploymentSite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br&gt;            dep&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;files&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;            &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;__DEPLOYMENT_DIR__&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/deps/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;dep&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;    &lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;compileSources&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__SRC_DIR__&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;                         __DEPLOYMENT_DIR__&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;uploadToServer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You&#39;ll notice that the &amp;quot;moveToDeploymentSite&amp;quot; step is slightly different in the async function version, in that it completes each operation in a serial pipeline, rather than completing each operation in parallel, and continuing once finished. This is an unfortunate limitation of the async function specification, which will hopefully be improved on in the future.&lt;/p&gt;
&lt;p&gt;In the meantime, it&#39;s still possible to use the Promise API in async functions, as you can &lt;code&gt;await&lt;/code&gt; any Promise, and continue execution after it is resolved. This grants compatibility with numerous existing Web Platform APIs (such as &lt;code&gt;fetch()&lt;/code&gt;), which is ultimately a good thing! Here&#39;s an alternative implementation of this step, which performs the &lt;code&gt;moveToDeploymentSite()&lt;/code&gt; bits in parallel, rather than serially:&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; Promise&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dependencies&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token parameter&quot;&gt;dep&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;moveToDeploymentSite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br&gt;    dep&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;files&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;__DEPLOYMENT_DIR__&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/deps/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;dep&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, it&#39;s clear from the &lt;em&gt;let dependencies = await fetchNpmDependencies();&lt;/em&gt; line that Promises are unwrapped automatically. What happens if the promise is rejected with an error, rather than resolved with a value? With try-catch blocks, we can catch rejected promise errors inside async functions! And if they are not caught, they will automatically return a rejected Promise from the async function.&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;throwsError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;oops&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;throwsError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token comment&quot;&gt;// will print the Error thrown in `throwsError`.&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; value &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;error&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// Rejected Promise is unwrapped automatically, and&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// execution continues here, allowing us to recover&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// from the error! `error` is `new Error(&quot;oops!&quot;)`&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are also lots of convenient forms of async function declarations, which hopefully serve lots of interesting use-cases! You can concisely declare methods as asynchronous in Object literals and ES6 classes, by preceding the method name with the &lt;code&gt;async&lt;/code&gt; keyword (without a preceding line terminator!)&lt;/p&gt;
&lt;pre class=&quot;language-js&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;C&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;doAsyncOperation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; obj &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getFacebookProfileAsynchronously&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br&gt;    &lt;span class=&quot;token comment&quot;&gt;/* ... */&lt;/span&gt;&lt;br&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These features allow us to write more idiomatic, easier to understand asynchronous control flow in our applications, and future extensions to the ECMAScript specification will enable even more idiomatic forms for writing complex algorithms, in a maintainable and readable fashion. We are very excited about this! There are numerous other resources on the web detailing async functions, their benefits, and perhaps ways they might be improved in the future. Some good ones include &lt;a href=&quot;https://jakearchibald.com/2014/es7-async-functions/&quot;&gt;this piece from Google&#39;s Jake Archibald&lt;/a&gt;, so give that a read for more details. It&#39;s a few years old, but it holds up nicely!&lt;/p&gt;
&lt;p&gt;So, now that you&#39;ve seen the overview of the feature, you might be wondering how you can try it out, and when it will be available for use. For the next few weeks, it&#39;s still too experimental even for the &amp;quot;Experimental Javascript&amp;quot; flag. But if you are adventurous, you can try it already! Fetch the latest Chrome Canary build, and start Chrome with the command-line-flag &lt;code&gt;--js-flags=&amp;quot;--harmony-async-await&amp;quot;&lt;/code&gt;. We can&#39;t make promises about the shipping timeline, but it could ship as early as Chrome 53 or Chrome 54, which will become stable in September or October.&lt;/p&gt;
&lt;p&gt;We owe a shout out to Bloomberg, who have provided us with resources to improve the web platform that we love. Hopefully, we are providing their engineers with ways to write more maintainable, more performant, and more beautiful code. We hope to continue this working relationship in the future!&lt;/p&gt;
&lt;p&gt;As well, shoutouts are owed to the Chromium team, who have assisted in reviewing the feature, verifying its stability, getting devtools integration working, and ultimately getting the code upstream. Terriffic! In addition, the WebKit team has also been very helpful, and hopefully we will see the feature land in JavaScriptCore in the not too distant future.&lt;/p&gt;
</content>
	</entry>
</feed>
