My penguin avatar

Kiesel Devlog #14: Release 0.3.0

Published on 2026-07-17.

It's a lovely day 1 at Electromagnetic Field and I spent a few hours between talks and watching Hackers (1995) to release Kiesel 0.3.0! It contains 76 commits across two months, see the changelog for the full list of user-facing changes.

Performance

This release is a big leap for real-world JS performance in Kiesel — mostly thanks to object layout improvements and a basic implementation of fast local variables, the v8-v7 benchmark runs 33% faster and uses 42% less memory:

Benchmark 1 (3 runs): kiesel-0.2.0 v8-v7.js
  measurement          mean ± σ            min … max           outliers         delta
  wall_time          88.5s  ± 2.68s     87.0s  … 91.6s           0 ( 0%)        0%
  peak_rss            388MB ±  305KB     388MB …  388MB          0 ( 0%)        0%
  cpu_cycles          555G  ± 17.3G      545G  …  575G           0 ( 0%)        0%
  instructions       1.07T  ± 21.9G     1.05T  … 1.09T           0 ( 0%)        0%
  cache_references   12.2G  ±  427M     11.7G  … 12.5G           0 ( 0%)        0%
  cache_misses       1.55G  ± 55.2M     1.50G  … 1.61G           0 ( 0%)        0%
  branch_misses       561M  ± 20.9M      539M  …  581M           0 ( 0%)        0%
Benchmark 2 (3 runs): kiesel-0.3.0 v8-v7.js
  measurement          mean ± σ            min … max           outliers         delta
  wall_time          59.0s  ± 1.08s     58.3s  … 60.3s           0 ( 0%)        ⚡- 33.3% ±  5.2%
  peak_rss            224MB ± 1.24MB     223MB …  225MB          0 ( 0%)        ⚡- 42.2% ±  0.5%
  cpu_cycles          343G  ± 3.21G      341G  …  347G           0 ( 0%)        ⚡- 38.2% ±  5.1%
  instructions        759G  ± 5.22G      755G  …  765G           0 ( 0%)        ⚡- 29.2% ±  3.4%
  cache_references   8.60G  ±  234M     8.33G  … 8.75G           0 ( 0%)        ⚡- 29.3% ±  6.4%
  cache_misses        866M  ± 5.70M      862M  …  872M           0 ( 0%)        ⚡- 44.0% ±  5.8%
  branch_misses       442M  ± 8.16M      436M  …  451M           0 ( 0%)        ⚡- 21.3% ±  6.4%

Kiesel now outperforms Boa, the most popular Rust JS engine, on every benchmark of the v8-v7 suite as can be seen on their benchmarks page.

Explicit Resource Management

This is a TC39 proposal that reached stage 4 in May. using statements provide syntax for managing disposable resources, and the new DisposableStack and AsyncDisposableStack builtins can be used for more complex use cases. See MDN for more details.

class Disposable {
  constructor(name) {
    this.name = name;
    console.log(`${this.name} constructed`);
  }

  [Symbol.dispose]() {
    console.log(`${this.name} disposed`);
  }
}

{
  using stack = new DisposableStack();
  const d1 = stack.use(new Disposable("d1"));
  const d2 = stack.use(new Disposable("d2"));
  {
    using d3 = new Disposable("d3");
  }
  using d4 = new Disposable("d4");
}
$ kiesel main.js
d1 constructed
d2 constructed
d3 constructed
d3 disposed
d4 constructed
d4 disposed
d2 disposed
d1 disposed

Error.prototype.stack

Another recent stage 4 proposal that has long been present in all major engines as a non-standard feature (MDN). Error.prototype.stack provides an implementation-defined string representing the error stack trace, in Kiesel's case it matches the output of uncaught exceptions:

function bar() {
  throw new Error("Oops!");
}

function foo() {
  bar();
}

// Caught
try {
  foo();
} catch (e) {
  console.log(`Caught exception: ${e.stack}`);
}

// Uncaught
foo();
$ kiesel main.js
Caught exception: Error: Oops!
  at fn bar
  at fn foo
Uncaught exception: Error: Oops!
  at fn bar
  at fn foo

Destructuring Assignment Patterns

There was partial support for this using lowering of binding patterns already, but assignment patterns support additional syntax:

> const o = {}, a = [];
undefined
> [o.foo, a[0]] = [123, 456];
[ 123, 456 ]
> o
{ "foo": 123 }
> a
[ 456 ]
>

This leads to unreadable code pretty quickly and I haven't seen it much in the wild but we have it now :^)

Handling of Invalid UTF-8 in Scripts

Kiesel now normalizes invalid UTF-8 input using replacement characters instead of rejecting it outright, thus allowing arbitrary byte sequences in comments. This can be used for polyglot programs, for example:


Loading posts...