Open rakudrama opened 5 years ago
Regarding general field assignment chaining, the middle one is clearly an improvement. Is the last one a bridge too far?
last = this._last;
cell._previous = last;
last._next = cell;
this._last = cell;
-->
last = this._last;
cell._previous = last;
this._last = last._next = cell;
-->
this._last = (cell._previous = this._last)._next = cell;
If you worry about !t1
being slower than t1 == null
, consider swapping the branches and just do t1 ? t1 : this._data = this._computer$0()
.
(That is, if the test of a two-branch condition is a negation, remove the negation and swap the branches. That should be safe since !
use the same falsy-logic as the condition).
That migth also be easier for a JS-level optimizier to recongize as equivalent to t1 || this._data = this._compute$0()
.
@lrhn
A JS-level peephole optimizer would work, but since dart2js does variable allocation ahead of generating JavaScript, doing so would leave a temporary that is assigned once and used once, i.e.
var t1 = this._data;
return t1 || (this._data = this._compute$());
which is quite a bit larger than
return this._data || (this._data = this._compute$());
I'm not worried about !t1 ? ...
vs t1 ? ...
, they are pretty much the same - both incur a full ToBoolean conversion, which has 9 tests to cover the full glory of JavaScript truthiness. What we are giving up is that t1 == null
can be done with 3 tests (null
, undefined
, and undetectable objects) vs the full 9 tests.
The generated code for a typical lazy-initialized field ...
... is a bit verbose:
What would it take to compile this to the following?
[x] Let HFieldSet be used in an expression context to allow chaining.
[x] (Side task) Use chaining for adjacent field assignments like
this.next = this.prev = null
.[x] Chain the field setter into the phi node:
t1 = this._data = this._compute$0()
At this point SsaConditionMerger should recognize that a conditional (?:) can generated
t1 == null
can be replaced with!t1
. (We need to take care here, since== null
is a faster operation that!t1
orif(t1)
.)[ ] Do additional checks in SsaConditionMerger that
t1
is used exactly twice in this pattern, registert1
as generate-at-use, and mark theHIf
node to generate the||
code.[ ] Methods like
get data
are frequently inlined (e.g. called from one place, and generally more attractive if the inlined code it compact). Ensure code quality at inlined sites is good.