WebAssembly as a Python extension platform

Software above some complexity level tends to sport an extension language, becoming a kind of software platform itself. Lua fills this role well, and of course there’s JavaScript for web technologies. WebAssembly generalizes this, and any Wasm-targeting programming language can extend a Wasm-hosting application. It has more friction than supplying a script in a text file, but extension authors can write in their language of choice, and use more polished development tools — debugging, testing, etc. — than typically available for a typical extension language. Python is traditionally extended through native code behind a C interface, but it’s recently become practical to extend Python with Wasm. That is we can ship an architecture-independent Wasm blob inside a Python library, and use it without requiring a native toolchain on the host system. Let’s discuss two different use cases and their pitfalls.

[]

Freestyle linked lists tricks

Linked lists are a data structure basic building block, with especially flexible allocation behavior. They’re not just a useful starting point, but sometimes a sound foundation for future growth. I’m going to start with the beginner stuff, then without disrupting the original linked list, enhance it with new capabilities.

[]

Unix "find" expressions compiled to bytecode

In preparation for a future project, I was thinking about at the unix find utility. It operates a file system hierarchies, with basic operations selected and filtered using a specialized expression language. Users compose operations using unary and binary operators, grouping with parentheses for precedence. find may apply the expression to a great many files, so compiling it into a bytecode, resolving as much as possible ahead of time, and minimizing the per-element work, seems like a prudent implementation strategy. With some thought, I worked out a technique to do so, which was simpler than I expected, and I’m pleased with the results. I was later surprised all the real world find implementations I examined use tree-walk interpreters instead. This article describes how my compiler works, with a runnable example, and lists ideas for improvements.

[]

Closures as Win32 window procedures

Back in 2017 I wrote about a technique for creating closures in C using JIT-compiled wrapper. It’s neat, though rarely necessary in real programs, so I don’t think about it often. I applied it to qsort, which sadly accepts no context pointer. More practical would be working around insufficient custom allocator interfaces, to create allocation functions at run-time bound to a particular allocation region. I’ve learned a lot since I last wrote about this subject, and a recent article had me thinking about it again, and how I could do better than before. In this article I will enhance Win32 window procedure callbacks with a fifth argument, allowing us to more directly pass extra context. I’m using w64devkit on x64, but the everything here should work out-of-the-box with any x64 toolchain that speaks GNU assembly.

[]

Speculations on arenas and non-trivial destructors

As I continue to reflect on arenas and lifetimes in C++, I realized that dealing with destructors is not so onerous. In fact, it does not even impact my established arena usage! That is, implicit RAII-style deallocation at scope termination, which works even in plain old C. With a small change we can safely place resource-managing objects in arenas, such as those owning file handles, sockets, threads, etc. (Though the ideal remains resource management avoidance when possible.) We can also place traditional, memory-managing C++ objects in arenas, too. Their own allocations won’t come from the arena — either because they lack the interfaces to do so, or they’re simply ineffective at it (pmr) — but they will reliably clean up after themselves. It’s all exception-safe, too. In this article I’ll update my arena allocator with this new feature. The change requires one additional arena pointer member, a bit of overhead for objects with non-trivial destructors, and no impact for other objects.

[]

More speculations on arenas in C++

Update October 2025: further enhancements.

Patrice Roy’s new book, C++ Memory Management, has made me more conscious of object lifetimes. C++ is stricter than C about lifetimes, and common, textbook memory management that’s sound in C is less so in C++ — more than I realized. The book also presents a form of arena allocation so watered down as to enjoy none of the benefits. (Despite its precision otherwise, the second half is also littered with integer overflows lacking the appropriate checks, and near the end has some pointer overflows invalidating the check.) However, I’m grateful for the new insights, and it’s made me revisit my own C++ arena allocation. In this new light I see I got it subtly wrong myself!

[]

Hierarchical field sort with string interning

In a recent, real world problem I needed to load a heterogeneous sequence of records from a buffer. Record layout is defined in a header before the sequence. Each field is numeric, with a unique name composed of non-empty alphanumeric period-delimited segments, where segments signify nested structure. Field names are a comma-delimited list, in order of the record layout. The catch motivating this article is that nested structures are not necessarily contiguous. In my transformed representation I needed nested structures to be contiguous. For illustrative purposes here, it will be for JSON output. I came up with what I think is an interesting solution, which I’ve implemented in C using techniques previously discussed.

[]

Assemblers in w64devkit, and other updates

Today I’m releasing w64devkit 2.4.0, mostly for GCC 15.2. As usual, it includes the continuous background improvements, and ideally each release is the best so far. The first release included the Netwide Assembler, NASM, but it’s now been a year since I removed NASM from the distribution (2.0.0). I’m asked on occasion why, or how to get it back. Because I value thorough source control logs, my justifications for this, and all changes, are captured in these logs, so git log is a kind of miniature, project blog. I understand this is neither discoverable nor obvious, especially because the GitHub UI (ugh) lacks anything like git log in the terminal. So let’s talk about it here, along with other recent changes.

[]

Parameterized types in C using the new tag compatibility rule

C23 has a new rule for struct, union, and enum compatibility finally appearing in compilers starting with GCC 15, released this past April, and Clang later this year. The same struct defined in different translation units (TU) has always been compatible — essential to how they work. Until this rule change, each such definition within a TU was a distinct, incompatible type. The new rule says that, ackshually, they are compatible! This unlocks some type parameterization using macros.

[]

WebAssembly: How to allocate your allocator

An early, small hurdle diving into WebAssembly was allocating my allocator. On a server or desktop with virtual memory, the allocator asks the operating system to map fresh pages into its address space (sbrk, anonymous mmap, VirtualAlloc), which it then dynamically allocates to different purposes. In an embedded context, dynamic allocation memory is typically a fixed, static region chosen at link time. The Wasm execution environment more resembles an embedded system, but both kinds of obtaining raw memory are viable and useful in different situations.

[]

null program

Chris Wellons

wellons@nullprogram.com (PGP)
~skeeto/public-inbox@lists.sr.ht (view)