QuickJS-NG 0.9.0 released!

QuickJS is a small and embeddable JavaScript engine. It aims to support the latest ECMAScript specification. QuickJS NG is a fork of the original QuickJS project by Fabrice Bellard and Charlie Gordon, after it went dormant, with the intent of reigniting its development.

After a couple of months of development version 0.9.0 is out. A few notable changes:

  • qjs will now exit on unhandled rejections: this aligns the reference interpreter with Node, Deno and Bun
  • Tons of new C APIs: JS_IsDate, JS_IsRegExp, JS_IsMap, JS_IsPromise and more, check quickjs.h
  • QUICKJS_NG is now defined so applications wanting to support both the old version and NG have an easy way to tell them appart
  • Inline caches have been removed, see the interesting conversation here
  • Amalgamated builds, see quickjs-amalgam.zip in the release artifacts, just a C file and 2 header files!
  • Meson build system support

See the full changelog here.

TIL: the default stack size on Windows is 1MB

When compiling with MSVC. Here is how I learned that.

We are close to merging Meson support for QuickJS. During the PR review a test was failing when compiled with Clang and ubsan in debug mode. It turned out to be related to the test setting a very small stack size for the interpreter, so I suggested to remove it entirely. Tests passed! … except on Windows. They now failed on all configurations, not only in debug mode. Time to dig in.

The first step is of course try and reproduce the problem. Luckily I have an old Windows laptop where I can test stuff. I could easily reproduce the problem. The api-test target consistently failed. It simply crashed without providing any output. Checking the exit code ($LASTEXITCODE on PowerShell) yielded -1073741571.

So, since it’s 2025 I decided to ask ChatGPT and see if it could shed any light, and it was right on the money:

The exit code -1073741571 (or 0xC00000FD in hexadecimal) indicates a Stack Overflow Exception (STATUS_STACK_OVERFLOW).

Aha! I had recently updated the default interpreter stack size to 1MB, so I wondered if the default stack size on Windows would be around that value, and thus it would crash before it could be caught by the engine. Guess what, it’s exactly 1MB. Bingo! (While writing this post I ran into the conversation Ben and I had about the V8 default in that very PR, which did mention the 1MB!)

Turns out it’s also easy to set it at build time: passing the /STACKSIZE linker flag. Adding /STACK:8388608 to the linker would set it to 8MB, as the default is on Linux. I created a PR setting it to 8MB both for MSVC and MinGW (for consistency) and the tests were green, success!

Fixing 5GHz WiFi on an Archer C7 with OpenWRT

I’ve had a TP-Link Archer C7 v2 router for quite a while. I can’t remember exactly why or when I got it but I suspect it was to tinker with OpenWRT 🙂

At some point in time I was having some weird WiFi problems, specifically on the 5GHz bands. Bandwidth would tank to the point of becoming unusable even for video streaming, and I couldn’t figure out why. I ended up shelving it, but I chose to keep it since the OpenWRT support was great (modulo this) since it might come in handy later. I guess that later is now 🙂

I wanted to embark on a little routing adventure (post coming soon!) so I decided to dust off the good old Archer and updated it to the latest OpenWRT which was recently released. I remembered the 5GHz WiFi problem so I decided to search the web and see if there was any new solution to my old problem. Unconstrained by the need to get it working or by mere luck, I found an issue on GitHub which described my problem to the letter! This comment was right on the money.

Apparently OpenWRT changed the firmware driver used for the chip in this particular driver from the original ath10k to a fork called ath10k-ct which was going to be better maintained. Not sure what happened there, but it seems like ath10k is a better one for this router so the way forward here is to go ahead and use `ath10k`. The following commands are better run over a wired connection to make sure you don’t lose connectivity after we uninstall and reinstall WiFi firmware.

# First remove the old firmware
opkg remove kmod-ath10k-ct ath10k-firmware-qca988x-ct

# Update the package list
opkg update

# Install the non -ct version of the firmware
opkg install kmod-ath10k ath10k-firmware-qca988x

# Reboot
reboot

After the router comes back up the 5GHz WiFi should be stable again! Now back to tinkering…

txiki.js 24.12.0 released

txiki.js is a small and powerful JavaScript runtime. It targets the latest ECMAScript spec and implements many web platform features.

It’s built on the shoulders of giants: it uses QuickJS-ng as its JavaScript engine, libuv as the platform layer, wasm3 as the WebAssembly engine and curl as the HTTP / WebSocket client.

Earlier this week I released version 24.12.0 featuring standalone executables, namespace reorganization, more web platform features, initial binary releases, more filesystem APIs, REPL updates and more! Check here for the full changelog, and read-on for some highlights.

Read more

txiki.js 24.6.0 released!

Long time, no post. Time to break the dry spell!

txiki.js is a small and powerful JavaScript runtime. It targets ECMAScript 2023 and implements many web platform features.

It’s built on the shoulders of giants: it uses QuickJS-ng as its JavaScript engine, libuv as the platform layer, wasm3 as the WebAssembly engine and curl as the HTTP / WebSocket client.

This is the first release after 6 months, and a lot has happened since the last one. 103 commits to be exact. Let’s break it down.

Read more

txiki.js 23.10.0 released!

txiki.js is a small and powerful JavaScript runtime. It targets ECMAScript 2020 and implements many web platform features.

It’s built on the shoulders of giants: it uses QuickJS as its JavaScript engine, libuv as the platform layer, wasm3 as the WebAssembly engine and curl as the HTTP / WebSocket client.

After a few months of hiatus I’m happy to announce a new txiki.js release: 23.10.0, and it’s a good one!

This new release is packed with new features:

  • Faster startup time
  • New fs features
  • SQLite builtin module
  • Storage web APIs support
  • curl integration fixes
  • Added import.meta.path
  • Better CLI errors
  • Improved types documentation

Check the full changelog here!

This release is particularly exciting because I’ve been looking forward to integrating SQLite support for a while. I started implementing the Storage API support thinking I’d use a file for persistence, but at one point I thought I’d use a SQLite databse instead, so I went for it!

There is likely stuff to be improved specially in this new builtin, the SQLite module, but I’m happy it’s in now!

The last release was over 6 months ago, so please do check the full changelog, I almost didn’t remember all the things that were added in the months past…

Thinking ahead, it might be time to start bringing in Mbed TLS support. Maybe just hasing at first, then TLS sockets, then WebCrypto. Step by step…

txiki.js 23.1.0 released, and it’s a big one!

txiki.js is a small and powerful JavaScript runtime. It’s built on the shoulders of giants: it uses QuickJSas its JavaScript engine, libuv as the platform layer, wasm3 as the WebAssembly engine and curl as the HTTP client.

After a few months of more work I’m happy to announce a new txiki.js release, version 23.1.0, quite possibly the biggest release I’ve made, and one that paves the way for the future. Let’s dive right in!

Standard library refactor

I’ve actually gone back and forth on this one. The standard library modules started being importable as @tjs/ modules, but I later switched to having it all bundled together in @tjs/stdlib. While easier to work with, that was a mistake. It’s slower to load and the churn due to the bundles being in the repo is just annoying.

It’s also important to look around and see what others are doing. Both Node and Bun seem to have settled in using namespace:module naming for builtins, so that’s what I went with. All standard library modules are now imported like so: tjs:module.

These modules are now documented too, so you can see the full API at a glance.

CLI refactor

The CLI also got some much needed love on this one. Generally speaking the CLI allowed one to either launch a file or eval an expression, plus some modifiers for each. After giving it some though, the idea of using subcommands sounded the most appealing, so now you can do tjs run foo.js and tjs eval ”console.log(42)”

But there is more. There is a also a builtin test runner now so tjs test is a thing too!

Last, running WASI binaries directly was too easy not to do, so you can also tjs run foo.wasm now and it works as expected.

Top level await

Just when I was about ready to cut the release I noticed zamfofex had sent a patch adding top level await support to QuickJS to the mailing list. That was too good to pass so I quickly incorporated it, and it worked beautifully!

This makes writing simple scripts (and tests!) so much more pleasant! So off I went and migrated the test suite to use TLA, the examples too, and added some initial support to the REPL while I was at it!

There is even more!

While these are the highlights, there are a lot more fixes that went into the release. Please checkout the full release notes here.

Migrating an ArchLinux install from an SSD to an NVMe drive

Today I’m going back to the roots of when I started tinkering with Linux. I have recently got a new (old) workstation and I decided to install ArchLinux on a test SSD drive I had lying around. Once I got things working I thought I’d migrate to an NVMe drive, instead of reinstalling. This post describes the process. All of it can be found on the wiki, but since there are many options available, I’m posting the route I took.

Read more