We should change how dart2js stores static variables to make it more friendly to JavaScript VMs.
dart2js uses a single object $ to store all the static (and top-level) variables, e.g., foo is stored as $.foo.
Static variables with a lazy initializer expression have getters.
These getters for initialized static variables are also stored on $, e.g. $.$get$foo().
The getters for static variables are updated after the initializer is evaluated with a fast-path that returns the current value.
The idea is that this 'overwrite' pattern is supported by JavaScript VMs - they often ignore the first value when starting to track the values of call target, so the JavaScript VM optimizes for the fast-path only, and can inline the simple target.
The problem with this scheme is that $ is very large, and churned by both updating functions stored in the object, and adding properties in deferred loading.
Both of these attributes (size, churn) are uses as signals by JavaScript VMs to stop JIT-optimizing the accesses and fall back on slow 'dictionary mode' accesses.
The improvements seen with 405734f18bae2a71ecc56d49552e4f0707229800 hint that the $ accesses are slow.
A better scheme would partition $ into more manageable pieces, and perhaps put the getters on a separate object, or use a sentinel value instead of updating a property containing a function value. Any scheme with more objects will likely result in slightly larger code.
We should change how dart2js stores static variables to make it more friendly to JavaScript VMs.
dart2js uses a single object
$
to store all the static (and top-level) variables, e.g.,foo
is stored as$.foo
. Static variables with a lazy initializer expression have getters. These getters for initialized static variables are also stored on$
, e.g.$.$get$foo()
. The getters for static variables are updated after the initializer is evaluated with a fast-path that returns the current value. The idea is that this 'overwrite' pattern is supported by JavaScript VMs - they often ignore the first value when starting to track the values of call target, so the JavaScript VM optimizes for the fast-path only, and can inline the simple target.The problem with this scheme is that
$
is very large, and churned by both updating functions stored in the object, and adding properties in deferred loading. Both of these attributes (size, churn) are uses as signals by JavaScript VMs to stop JIT-optimizing the accesses and fall back on slow 'dictionary mode' accesses.The improvements seen with 405734f18bae2a71ecc56d49552e4f0707229800 hint that the
$
accesses are slow.A better scheme would partition
$
into more manageable pieces, and perhaps put the getters on a separate object, or use a sentinel value instead of updating a property containing a function value. Any scheme with more objects will likely result in slightly larger code.