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:
- Finished implementing
Array.prototype
- Added most of
Date
including basic parsing, no non-UTC time zones yet - Added all of
Map
andSet
, including their iterators
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 π
Array.prototype.concat()
Array.prototype.copyWithin()
Array.prototype.fill()
Array.prototype.flat()
Array.prototype.flatMap()
Array.prototype.reduce()
Array.prototype.reduceRight()
Array.prototype.reverse()
Array.prototype.slice()
Array.prototype.sort()
Array.prototype.splice()
Array.prototype.toReversed()
Array.prototype.toSorted()
Array.prototype.toSpliced()
Date()
Date.now()
Date.parse()
Date.prototype.getDate()
Date.prototype.getDay()
Date.prototype.getFullYear()
Date.prototype.getHours()
Date.prototype.getMilliseconds()
Date.prototype.getMinutes()
Date.prototype.getMonth()
Date.prototype.getSeconds()
Date.prototype.getTime()
Date.prototype.getTimezoneOffset()
Date.prototype.getUTCDate()
Date.prototype.getUTCDay()
Date.prototype.getUTCFullYear()
Date.prototype.getUTCHours()
Date.prototype.getUTCMilliseconds()
Date.prototype.getUTCMinutes()
Date.prototype.getUTCMonth()
Date.prototype.getUTCSeconds()
Date.prototype.setDate()
Date.prototype.setFullYear()
Date.prototype.setHours()
Date.prototype.setMilliseconds()
Date.prototype.setMinutes()
Date.prototype.setMonth()
Date.prototype.setSeconds()
Date.prototype.setTime()
Date.prototype.setUTCDate()
Date.prototype.setUTCFullYear()
Date.prototype.setUTCHours()
Date.prototype.setUTCMilliseconds()
Date.prototype.setUTCMinutes()
Date.prototype.setUTCMonth()
Date.prototype.setUTCSeconds()
Date.prototype.toDateString()
Date.prototype.toISOString()
Date.prototype.toJSON()
Date.prototype.toLocaleDateString()
Date.prototype.toLocaleString()
Date.prototype.toLocaleTimeString()
Date.prototype.toString()
Date.prototype.toTimeString()
Date.prototype.toUTCString()
Date.prototype.valueOf()
Date.prototype[@@toPrimitive]()
Date.UTC()
Map()
Map.prototype.clear()
Map.prototype.delete()
Map.prototype.entries()
Map.prototype.forEach()
Map.prototype.get()
Map.prototype.has()
Map.prototype.keys()
Map.prototype.set()
Map.prototype.size
Map.prototype.values()
Map.prototype[@@iterator]()
Map.prototype[@@toStringTag]
Math.max()
Math.min()
Set()
Set.prototype.add()
Set.prototype.clear()
Set.prototype.delete()
Set.prototype.entries()
Set.prototype.forEach()
Set.prototype.has()
Set.prototype.keys()
Set.prototype.size
Set.prototype.values()
Set.prototype[@@iterator]()
Set.prototype[@@toStringTag]
String.prototype.concat()
String.prototype.repeat()
String.prototype.slice()
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
).
Also check out these posts from friends across the web!
-
Messenger Rooms Bug Bounty Write-up
2020-04-24 β Jane Manchun Wongβs Personal Blog -
Bringing SerenityOS to real hardware, one driver at a time
2025-01-08 β sdomi's weblog -
Time to break some habits
2024-11-05 β lnl's weblog -
Porffor's January 2025 Goals
2025-01-06 β goose.icu