Kiesel Devlog #15: Release 0.4.0
Published on 2026-10-08.This week I completed the update to Zig 0.17 and released Kiesel 0.4.0! It contains 64 commits across 2.5 months, see the changelog for the full list of user-facing changes.
Kiesel.args / Kiesel.env
I mostly build rather than use this project, and it shows — beyond the core language implementation only a few APIs needed for real-world programs are available. We did have file I/O for a while, and with the addition of arguments and environment reading a simple cat(1) clone becomes feasible:
#!/usr/bin/env kiesel
const [_exe, _script, ...files] = Kiesel.args;
if (files.length === 0) {
const contents = Kiesel.readStdin();
Kiesel.print(contents, { newline: false });
} else {
for (const file of files) {
const contents = Kiesel.readFile(file);
Kiesel.print(contents, { newline: false });
}
}$ ./cat.js cat.jsEven More Iterator Helpers
Over the last few years JS has rapidly advanced the usability of iterators from just providing the basic protocol at the language level to a large collection of Iterator.prototype methods. The initial Iterator Helpers proposal shipped in 2024, followed by Iterator Sequencing in 2025, and Joint Iteration, Iterator Join, Iterator Includes, and Iterator Chunking all this year. Phew!
The last three are newly implemented:
function* count() {
for (let i = 1; ; ++i) yield i;
}
console.log(count().take(3).join(" + "));
console.log(count().take(10).includes(5));
console.log(JSON.stringify(count().chunks(3).take(3).toArray()));$ kiesel main.js
1 + 2 + 3
true
[[1,2,3],[4,5,6],[7,8,9]]I also implemented the Await Dictionary proposal, which is still at Stage 3.
SerenityOS Port
I've done a number of fun ports over the years but this might be my favorite one yet! It's an intersection of most of my notable open source work in the past six years: SerenityOS, the Zig project, and Kiesel itself.

This required gradually upstreaming SerenityOS target support in Zig (#20913, #23192, #23198, #24561, #24633, #25457, #25779, #30756, #31916, #31931, #32172, #36465, #37064, #37065), a handful of SerenityOS LibC and Kernel changes (#25804, #26350, #26543, #26928), and the package itself (#26931), which is cross-compiled against a now minimally patched Zig standard library. I hope to have those remaining bits upstreamed by the time 0.18 is released :^)
Other notable mentions: the long-anticipated DOS port finally became reality thanks to dos.zig being revived, and OpenBSD/NetBSD binaries are now built in CI.
Inline Caches
Inline caches are one of the fundamental optimizations used by virtually all JS engines (and various other dynamic programming languages). I recommend this blog post if you want to learn more about how they work.
Kiesel had ICs for a long time, but the bytecode interpreter rewrite earlier this year left it with only a basic implementation of monomorphic property ICs. I've now fixed those gaps (#220, #221, #222):
- Polymorphic property access (up to 4 before becoming megamorphic)
- Computed property access
- Prototype lookups
The output is rather cryptic, but you can see them in the emitted bytecode:
$ kiesel --print-bytecode -c 'o = {}; o.foo = 1; o.foo'
Bytecode (command)
0: 12 00 00 00 00 00 00 create_object r0, 0
7: 4e 00 00 00 00 00 00 set_binding @0 ("o"), r0
14: 49 00 00 00 00 00 00 get_binding r0, @0 ("o")
21: 07 01 00 01 load_number_i8 r1, 1
25: 50 00 00 01 00 01 00 00 00 00 00 set_property r0, r1, @1 ("foo"), @0
36: 49 00 00 00 00 00 00 get_binding r0, @0 ("o")
43: 4a 01 00 00 00 01 00 00 00 00 00 get_property r1, r0, @1 ("foo"), @0
54: 78 01 00 return r1One (@0) set_property IC and one (@0) get_property IC. (They're indexed by type, not shared.)
The implementation is only a few hundred lines for all of them, but consistently provides speedups of 20-30% in microbenchmarks.
Plans for 0.5.0
The parser is about to get fast, stay tuned 👀