Improve field initializer bytecode
Categories
(Core :: JavaScript Engine, task, P2)
Tracking
()
People
(Reporter: iain, Unassigned)
References
(Blocks 1 open bug)
Details
(Whiteboard: [js-perf-next])
For class C { x = 0; #y = 0}, we generate the following bytecode:
00000: 6 FunctionThis # (intermediate value)
00001: 6 SetLocal 0 # (intermediate value)
00005: 6 Pop #
main:
00006: 6 GetAliasedVar ".initializers" (hops = 0, slot = 4) # .initializers
00012: 6 CheckAliasedLexical ".initializers" (hops = 0, slot = 4) # .initializers
00018: 6 Dup # .initializers .initializers
00019: 6 Zero # .initializers .initializers 0
00020: 6 GetElem # .initializers .initializers[0]
00021: 6 GetLocal 0 # .initializers .initializers[0] this
00025: 6 CallIgnoresRv 0 # .initializers .initializers[0]()
00028: 6 Pop # .initializers
00029: 6 One # .initializers 1
00030: 6 GetElem # .initializers[1]
00031: 6 GetLocal 0 # .initializers[1] this
00035: 6 CallIgnoresRv 0 # .initializers[1]()
00038: 6 Pop #
00039: 6 RetRval #
We retrieve an initializer array out of the environment, with one entry per field. Then we call each of those initializers in sequence.
This is actually quite difficult to optimize away. The JITs have no way to know that the array is immutable. Even if we inline each of the calls, we still need to load the array, load each element individually, and guard that the initializer function hasn't changed, even in Ion. For small constructors, like Vector in JS3's raytrace-private-fields benchmark, the guards alone add up to ~35% of all samples in the function:
class Vector {
#x = 0;
#y = 0;
#z = 0;
constructor(x,y,z) {
this.#x = x;
this.#y = y;
this.#z = z;
}
}
It would be nice if we could at least coalesce these initializers into a single function. (It looks like this is what V8 does.) It would be even nicer if we could inline them directly into the constructor.
js-perf-next: raytrace-private-fields and raytrace-public-fields are two of our biggest gaps vs Chrome in JS3. Within those benchmarks, most of the individual functions with the biggest gaps are constructors with field initializers. It looks like matching V8's performance on those constructors would get us a 20% improvement on the two benchmarks. (That number might be inflated somewhat by the fact that inlining is disabled for comparison reports, but some quick tests seem to indicate that both engines suffer about equally from disabling inlining.)
Updated•1 month ago
|
Comment 1•1 month ago
|
||
See also bug 1827197 for previous discussions.
Description
•