Skip to content

Commit

Permalink
Update on "[compiler] Optimize emission in normal (non-value) blocks"
Browse files Browse the repository at this point in the history
In #29863 I tried to find a clean way to share code for emitting instructions between value blocks and regular blocks. The catch is that value blocks have special meaning for their final instruction — that's the value of the block — so reordering can't change the last instruction. However, in finding a clean way to share code for these two categories of code, i also inadvertently reduced the effectiveness of the optimization.

This PR updates to use different strategies for these two kinds of blocks: value blocks use the code from #29863 where we first emit all non-reorderable instructions in their original order, _then_ try to emit reorderable values. The reason this is suboptimal, though, is that we want to move instructions closer to their dependencies so that they can invalidate (merge) together. Emitting the reorderable values last prevents this.

So for normal blocks, we now emit terminal operands first. This will invariably cause _some_ of the non-reorderable instructions to be emitted, but it will intersperse reoderable instructions in between, right after their dependencies. This maximizes our ability to merge scopes.

I think the complexity cost of two strategies is worth the benefit, though i still need to double-check all the output changes.

[ghstack-poisoned]
  • Loading branch information
josephsavona committed Jun 18, 2024
2 parents 13a5a77 + b6bbb0e commit 8fdc2b7
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -379,7 +379,7 @@ function getDepth(env: Environment, nodes: Nodes, id: IdentifierId): number {
return node.depth;
}
node.depth = 0; // in case of cycles
let depth = node.reorderability === Reorderability.Reorderable ? 0 : 1;
let depth = node.reorderability === Reorderability.Reorderable ? 1 : 10;
for (const dep of node.dependencies) {
depth += getDepth(env, nodes, dep);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,31 +21,24 @@ function Component(props) {
```javascript
import { c as _c } from "react/compiler-runtime";
function Component(props) {
const $ = _c(2);
const $ = _c(1);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
const count = new MaybeMutable();

t0 = <span>{maybeMutate(count)}</span>;
$[0] = t0;
} else {
t0 = $[0];
}
let t1;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t1 = (
t0 = (
<View>
<View>
<span>Text</span>
{t0}
<span>{maybeMutate(count)}</span>
</View>
</View>
);
$[1] = t1;
$[0] = t0;
} else {
t1 = $[1];
t0 = $[0];
}
return t1;
return t0;
}

```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,39 +36,29 @@ import { c as _c } from "react/compiler-runtime";
import { StaticText1 } from "shared-runtime";

function Component() {
const $ = _c(3);
const $ = _c(1);
let t0;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t0 = <StaticText1 />;
$[0] = t0;
} else {
t0 = $[0];
}
let t1;
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
t1 = <StaticText1 />;
$[1] = t1;
} else {
t1 = $[1];
}
let t2;
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t2 = (
t0 = (
<div>
Before text{t0}Middle text
Before text
<StaticText1 />
Middle text
<StaticText1>
Inner before text{t1}Inner middle text
Inner before text
<StaticText1 />
Inner middle text
<StaticText1 />
Inner after text
</StaticText1>
After text
</div>
);
$[2] = t2;
$[0] = t0;
} else {
t2 = $[2];
t0 = $[0];
}
return t2;
return t0;
}

export const FIXTURE_ENTRYPOINT = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,31 +29,39 @@ import { c as _c } from "react/compiler-runtime";
import { Stringify } from "shared-runtime";

function Component(t0) {
const $ = _c(3);
const $ = _c(5);
const { id } = t0;

const t1 = id ? true : false;
let t2;
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
t2 = <Stringify title={undefined} />;
$[0] = t2;
if ($[0] !== t1) {
t2 = <Stringify title={t1} />;
$[0] = t1;
$[1] = t2;
} else {
t2 = $[0];
t2 = $[1];
}
let t3;
if ($[1] !== t1) {
t3 = (
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
t3 = <Stringify title={undefined} />;
$[2] = t3;
} else {
t3 = $[2];
}
let t4;
if ($[3] !== t2) {
t4 = (
<>
{t3}
{t2}
<Stringify title={t1} />
</>
);
$[1] = t1;
$[2] = t3;
$[3] = t2;
$[4] = t4;
} else {
t3 = $[2];
t4 = $[4];
}
return t3;
return t4;
}

export const FIXTURE_ENTRYPOINT = {
Expand Down

0 comments on commit 8fdc2b7

Please sign in to comment.