My penguin avatar

Kiesel Devlog #3: Accessors, Date/Map/Set, test262 history graph

Published on 2023-09-26.

Accessors in Object Expressions

I first implemented the fairly similar object method definition syntax ({ foo() {} }), but cheated with the AST representation — this would output the same structure as { foo: function() {} }, which obviously falls apart when the definition has a get or set prefix.

One small refactor later I had an object_define_method bytecode instruction tailored to this use case, which then allowed me to implement getters and setters easily by passing a method, get, or set enum argument to the instruction. The underlying accessor property mechanism was already working and used for some builtin objects.

The generated bytecode looks like this (the indices refer to the constant and function expression tables embedded in the executable):

> { foo() {}, get bar() {}, set baz(arg) {} }
Generated Bytecode
------------------
 0: object_create
 1: load
 2: store_constant "foo" [0]
 5: load
 6: object_define_method [0] (type: method)
11: load
12: store_constant "bar" [1]
15: load
16: object_define_method [1] (type: get)
21: load
22: store_constant "baz" [2]
25: load
26: object_define_method [2] (type: set)
31: <end>

{ "foo": fn foo, "bar": <accessor>, "baz": <accessor> }
>

Or, in the case of a computed property (that store_constant + load sequence can be optimized to a single load_constant instruction eventually):

> { get [foo + "bar"]() {} }
Generated Bytecode
------------------
 0: object_create
 1: load
 2: resolve_binding foo [0] (strict: false)
 7: get_value
 8: load
 9: store_constant "bar" [0]
12: load
13: apply_string_or_numeric_binary_operator (operator: +)
16: load
17: object_define_method [0] (type: get)
22: <end>

New Builtins!

TL;DR:

This amounts to a almost 100 new functions!

A lot of this was fairly repetitive (Date having a getter and setter for both local time and UTC, as well as Map and Set being nearly identical), but it was still fun to implement these :^)

Expand to see the full list of newly implemented builtins 📝

A History Graph for test262.fyi

As mentioned in the previous devlog, test262.fyi was updated to start collecting historic data instead of only keeping results for the last run. The obvious use case is a graph comparing all engines against the total number of tests, which I've implemented using Chart.js:

This isn't on the live site yet, but I hope to upstream it soon. You can also see that Kiesel passed the 30% mark two days ago! :^)

What's Next?

Promises or typed arrays probably, both of which are relatively large and will probably have an entire devlog dedicated to them, which is why I'm writing this one now to have a clean slate.

Ignoring async/await promises aren't used that much within ECMAScript itself, but typed arrays bring a whole lot of related functionality with them (ArrayBuffer/SharedArrayBuffer, DataView, Atomics).


Loading posts...