mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
InferReactiveScopes considers all operands, incl terminals
This commit is contained in:
@@ -66,7 +66,9 @@ class Driver<TBlock, TValue, TItem, TCase> {
|
||||
switch (terminal.kind) {
|
||||
case "return": {
|
||||
const value =
|
||||
terminal.value != null ? this.visitPlace(terminal.value) : null;
|
||||
terminal.value != null
|
||||
? this.visitPlace(terminal.value, terminal.id)
|
||||
: null;
|
||||
this.visitor.visitTerminalId(terminal.id);
|
||||
this.visitor.appendBlock(
|
||||
blockValue,
|
||||
@@ -78,7 +80,7 @@ class Driver<TBlock, TValue, TItem, TCase> {
|
||||
break;
|
||||
}
|
||||
case "throw": {
|
||||
const value = this.visitPlace(terminal.value);
|
||||
const value = this.visitPlace(terminal.value, terminal.id);
|
||||
this.visitor.visitTerminalId(terminal.id);
|
||||
this.visitor.appendBlock(
|
||||
blockValue,
|
||||
@@ -90,7 +92,7 @@ class Driver<TBlock, TValue, TItem, TCase> {
|
||||
break;
|
||||
}
|
||||
case "if": {
|
||||
const test = this.visitPlace(terminal.test);
|
||||
const test = this.visitPlace(terminal.test, terminal.id);
|
||||
const fallthroughId =
|
||||
terminal.fallthrough !== null &&
|
||||
!this.cx.isScheduled(terminal.fallthrough)
|
||||
@@ -152,7 +154,7 @@ class Driver<TBlock, TValue, TItem, TCase> {
|
||||
break;
|
||||
}
|
||||
case "switch": {
|
||||
const test = this.visitPlace(terminal.test);
|
||||
const test = this.visitPlace(terminal.test, terminal.id);
|
||||
const fallthroughId =
|
||||
terminal.fallthrough !== null &&
|
||||
!this.cx.isScheduled(terminal.fallthrough)
|
||||
@@ -166,7 +168,10 @@ class Driver<TBlock, TValue, TItem, TCase> {
|
||||
this.visitor.visitTerminalId(terminal.id);
|
||||
const cases: Array<TCase> = [];
|
||||
[...terminal.cases].reverse().forEach((case_, index) => {
|
||||
const test = case_.test !== null ? this.visitPlace(case_.test) : null;
|
||||
const test =
|
||||
case_.test !== null
|
||||
? this.visitPlace(case_.test, terminal.id)
|
||||
: null;
|
||||
|
||||
let consequent;
|
||||
if (this.cx.isScheduled(case_.block)) {
|
||||
@@ -241,7 +246,7 @@ class Driver<TBlock, TValue, TItem, TCase> {
|
||||
// body.length === bodyLength,
|
||||
// "Expected test to produce only temporaries"
|
||||
// );
|
||||
const testValue = this.visitPlace(testTerminal.test);
|
||||
const testValue = this.visitPlace(testTerminal.test, terminal.id);
|
||||
const fallthroughId =
|
||||
terminal.fallthrough !== null &&
|
||||
!this.cx.isScheduled(terminal.fallthrough)
|
||||
@@ -391,13 +396,13 @@ class Driver<TBlock, TValue, TItem, TCase> {
|
||||
}
|
||||
|
||||
visitInstr(instr: Instruction, blockValue: TBlock): void {
|
||||
const value = this.visitor.visitValue(instr.value);
|
||||
const value = this.visitor.visitValue(instr.value, instr.id);
|
||||
const item = this.visitor.visitInstruction(instr, value);
|
||||
this.visitor.appendBlock(blockValue, item);
|
||||
}
|
||||
|
||||
visitPlace(place: Place): TValue {
|
||||
return this.visitor.visitValue(place);
|
||||
visitPlace(place: Place, id: InstructionId): TValue {
|
||||
return this.visitor.visitValue(place, id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,7 +647,7 @@ export interface Visitor<TBlock, TValue, TItem, TCase> {
|
||||
* Convert an InstructionValue into the visitor's own representation
|
||||
* of a value.
|
||||
*/
|
||||
visitValue(value: InstructionValue): TValue;
|
||||
visitValue(value: InstructionValue, id: InstructionId): TValue;
|
||||
|
||||
/**
|
||||
* Convert an Instruction into the visitor's own representation of
|
||||
|
||||
@@ -17,7 +17,10 @@ import {
|
||||
ScopeId,
|
||||
} from "./HIR";
|
||||
import { BlockTerminal, Visitor, visitTree } from "./HIRTreeVisitor";
|
||||
import { eachInstructionOperand } from "./visitors";
|
||||
import {
|
||||
eachInstructionOperand,
|
||||
eachInstructionValueOperand,
|
||||
} from "./visitors";
|
||||
|
||||
/**
|
||||
* This is a second (final) stage of constructing reactive scopes. Prior to this pass,
|
||||
@@ -249,13 +252,28 @@ class MergeOverlappingReactiveScopesVisitor
|
||||
enterBlock(): void {
|
||||
this.scopes.push(new BlockScope());
|
||||
}
|
||||
visitValue(value: InstructionValue): void {}
|
||||
visitInstruction(instruction: Instruction, value: void): void {
|
||||
const scope = getInstructionScope(instruction);
|
||||
if (scope !== null && instruction.id < scope.range.end) {
|
||||
this.visitScope(scope);
|
||||
visitValue(value: InstructionValue, id: InstructionId): void {
|
||||
this.visitId(id);
|
||||
for (const operand of eachInstructionValueOperand(value)) {
|
||||
if (
|
||||
operand.identifier.scope !== null &&
|
||||
id >= operand.identifier.scope.range.start &&
|
||||
id < operand.identifier.scope.range.end
|
||||
) {
|
||||
this.visitScope(operand.identifier.scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
visitInstruction(instruction: Instruction, value: void): void {
|
||||
this.visitId(instruction.id);
|
||||
if (
|
||||
instruction.lvalue !== null &&
|
||||
instruction.lvalue.place.identifier.scope !== null &&
|
||||
instruction.id >= instruction.lvalue.place.identifier.scope.range.start &&
|
||||
instruction.id < instruction.lvalue.place.identifier.scope.range.end
|
||||
) {
|
||||
this.visitScope(instruction.lvalue.place.identifier.scope);
|
||||
}
|
||||
}
|
||||
visitTerminalId(id: InstructionId): void {
|
||||
this.visitId(id);
|
||||
|
||||
@@ -10,13 +10,18 @@ import {
|
||||
BasicBlock,
|
||||
BlockId,
|
||||
Instruction,
|
||||
InstructionValue,
|
||||
makeInstructionId,
|
||||
Place,
|
||||
Terminal,
|
||||
} from "./HIR";
|
||||
|
||||
export function* eachInstructionOperand(instr: Instruction): Iterable<Place> {
|
||||
const instrValue = instr.value;
|
||||
yield* eachInstructionValueOperand(instr.value);
|
||||
}
|
||||
export function* eachInstructionValueOperand(
|
||||
instrValue: InstructionValue
|
||||
): Iterable<Place> {
|
||||
switch (instrValue.kind) {
|
||||
case "NewExpression":
|
||||
case "CallExpression": {
|
||||
|
||||
@@ -33,8 +33,8 @@ bb4:
|
||||
[4] If (read c$9) then:bb6 else:bb1
|
||||
bb6:
|
||||
predecessor blocks: bb4
|
||||
[5] Const mutate $11_@0[1:8] = 0
|
||||
[6] Call mutate x$10_@0.push(read $11_@0)
|
||||
[5] Const mutate $11_@1 = 0
|
||||
[6] Call mutate x$10_@0.push(read $11_@1)
|
||||
[7] Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb6 bb4 bb2 bb0
|
||||
@@ -67,8 +67,8 @@ flowchart TB
|
||||
end
|
||||
subgraph bb6
|
||||
bb6_instrs["
|
||||
[5] Const mutate $11_@0[1:8] = 0
|
||||
[6] Call mutate x$10_@0.push(read $11_@0)
|
||||
[5] Const mutate $11_@1 = 0
|
||||
[6] Call mutate x$10_@0.push(read $11_@1)
|
||||
"]
|
||||
bb6_instrs --> bb6_terminal(["Goto"])
|
||||
end
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
function foo(a, b, c) {
|
||||
const x = [];
|
||||
const y = [];
|
||||
|
||||
if (x) {
|
||||
}
|
||||
|
||||
y.push(a);
|
||||
x.push(b);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## HIR
|
||||
|
||||
```
|
||||
bb0:
|
||||
[1] Const mutate x$9_@0[1:6] = Array []
|
||||
[2] Const mutate y$10_@0[1:6] = Array []
|
||||
[3] If (read x$9_@0) then:bb1 else:bb1
|
||||
bb1:
|
||||
predecessor blocks: bb0
|
||||
[4] Call mutate y$10_@0.push(read a$6)
|
||||
[5] Call mutate x$9_@0.push(read b$7)
|
||||
[6] Return
|
||||
```
|
||||
|
||||
### CFG
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
%% Basic Blocks
|
||||
subgraph bb0
|
||||
bb0_instrs["
|
||||
[1] Const mutate x$9_@0[1:6] = Array []
|
||||
[2] Const mutate y$10_@0[1:6] = Array []
|
||||
"]
|
||||
bb0_instrs --> bb0_terminal(["If (read x$9_@0)"])
|
||||
end
|
||||
subgraph bb1
|
||||
bb1_instrs["
|
||||
[4] Call mutate y$10_@0.push(read a$6)
|
||||
[5] Call mutate x$9_@0.push(read b$7)
|
||||
"]
|
||||
bb1_instrs --> bb1_terminal(["Return"])
|
||||
end
|
||||
|
||||
%% Jumps
|
||||
bb0_terminal -- "then" --> bb1
|
||||
bb0_terminal -- "else" --> bb1
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
function foo$0(a$1, b$2, c$3) {
|
||||
const x$4 = [];
|
||||
const y$5 = [];
|
||||
bb1: if (x$4) {
|
||||
}
|
||||
|
||||
y$5.push(a$1);
|
||||
x$4.push(b$2);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
function foo(a, b, c) {
|
||||
const x = [];
|
||||
const y = [];
|
||||
|
||||
if (x) {
|
||||
}
|
||||
|
||||
y.push(a);
|
||||
x.push(b);
|
||||
}
|
||||
+4
-4
@@ -34,8 +34,8 @@ bb4:
|
||||
bb3:
|
||||
predecessor blocks: bb4 bb2
|
||||
[7] Const mutate $13_@2 = "div"
|
||||
[8] Const mutate $15_@0[1:11] = JSX <read $13_@2>{freeze y$12_@1}</read $13_@2>
|
||||
[9] Call mutate x$11_@0.push(read $15_@0)
|
||||
[8] Const mutate $15_@3 = JSX <read $13_@2>{freeze y$12_@1}</read $13_@2>
|
||||
[9] Call mutate x$11_@0.push(read $15_@3)
|
||||
[10] Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb3 bb0
|
||||
@@ -68,8 +68,8 @@ flowchart TB
|
||||
subgraph bb3
|
||||
bb3_instrs["
|
||||
[7] Const mutate $13_@2 = 'div'
|
||||
[8] Const mutate $15_@0[1:11] = JSX <read $13_@2>{freeze y$12_@1}</read $13_@2>
|
||||
[9] Call mutate x$11_@0.push(read $15_@0)
|
||||
[8] Const mutate $15_@3 = JSX <read $13_@2>{freeze y$12_@1}</read $13_@2>
|
||||
[9] Call mutate x$11_@0.push(read $15_@3)
|
||||
"]
|
||||
bb3_instrs --> bb3_terminal(["Goto"])
|
||||
end
|
||||
|
||||
@@ -47,7 +47,7 @@ function log$0() {}
|
||||
|
||||
```
|
||||
bb0:
|
||||
[1] Let mutate str$6_@2[0:9] = ""
|
||||
[1] Let mutate str$6_@0[1:8] = ""
|
||||
[2] If (read cond$5) then:bb2 else:bb3
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
@@ -56,12 +56,12 @@ bb2:
|
||||
[5] Goto bb1
|
||||
bb3:
|
||||
predecessor blocks: bb0
|
||||
[6] Reassign mutate str$8_@2[0:9] = "fallthrough test"
|
||||
[6] Reassign mutate str$8_@0[1:8] = "fallthrough test"
|
||||
[7] Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb2 bb3
|
||||
str$10_@2[0:9]: phi(bb2: str$6_@2, bb3: str$8_@2)
|
||||
[8] Call mutate log$4_@2(read str$10_@2)
|
||||
str$10_@0[1:8]: phi(bb2: str$6_@0, bb3: str$8_@0)
|
||||
[8] Call mutate log$4_@2(read str$10_@0)
|
||||
[9] Return
|
||||
```
|
||||
|
||||
@@ -72,7 +72,7 @@ flowchart TB
|
||||
%% Basic Blocks
|
||||
subgraph bb0
|
||||
bb0_instrs["
|
||||
[1] Let mutate str$6_@2[0:9] = ''
|
||||
[1] Let mutate str$6_@0[1:8] = ''
|
||||
"]
|
||||
bb0_instrs --> bb0_terminal(["If (read cond$5)"])
|
||||
end
|
||||
@@ -85,13 +85,13 @@ flowchart TB
|
||||
end
|
||||
subgraph bb3
|
||||
bb3_instrs["
|
||||
[6] Reassign mutate str$8_@2[0:9] = 'fallthrough test'
|
||||
[6] Reassign mutate str$8_@0[1:8] = 'fallthrough test'
|
||||
"]
|
||||
bb3_instrs --> bb3_terminal(["Goto"])
|
||||
end
|
||||
subgraph bb1
|
||||
bb1_instrs["
|
||||
[8] Call mutate log$4_@2(read str$10_@2)
|
||||
[8] Call mutate log$4_@2(read str$10_@0)
|
||||
"]
|
||||
bb1_instrs --> bb1_terminal(["Return"])
|
||||
end
|
||||
|
||||
@@ -39,23 +39,23 @@ bb0:
|
||||
Default: bb2
|
||||
bb5:
|
||||
predecessor blocks: bb0
|
||||
[7] Const mutate $15_@6[7:17] = 1
|
||||
[8] Reassign mutate x$16_@6[7:17] = Binary read x$10_@0 + read $15_@6
|
||||
[7] Const mutate $15_@5 = 1
|
||||
[8] Reassign mutate x$16_@6[8:17] = Binary read x$10_@0 + read $15_@5
|
||||
[9] Goto bb1
|
||||
bb3:
|
||||
predecessor blocks: bb0
|
||||
[10] Const mutate $17_@6[7:17] = 2
|
||||
[11] Reassign mutate x$18_@6[7:17] = Binary read x$10_@0 + read $17_@6
|
||||
[10] Const mutate $17_@7 = 2
|
||||
[11] Reassign mutate x$18_@6[8:17] = Binary read x$10_@0 + read $17_@7
|
||||
[12] Goto bb1
|
||||
bb2:
|
||||
predecessor blocks: bb0
|
||||
[13] Const mutate $19_@8 = 3
|
||||
[14] Reassign mutate x$20_@6[7:17] = Binary read x$10_@0 + read $19_@8
|
||||
[14] Reassign mutate x$20_@6[8:17] = Binary read x$10_@0 + read $19_@8
|
||||
[15] Goto bb1
|
||||
bb1:
|
||||
predecessor blocks: bb5 bb3 bb2
|
||||
x$21_@6[7:17]: phi(bb5: x$16_@6, bb3: x$18_@6, bb2: x$20_@6)
|
||||
[16] Let mutate y$22_@6[7:17] = read x$21_@6
|
||||
x$21_@6[8:17]: phi(bb5: x$16_@6, bb3: x$18_@6, bb2: x$20_@6)
|
||||
[16] Let mutate y$22_@6[8:17] = read x$21_@6
|
||||
[17] Return
|
||||
```
|
||||
|
||||
@@ -76,28 +76,28 @@ flowchart TB
|
||||
end
|
||||
subgraph bb5
|
||||
bb5_instrs["
|
||||
[7] Const mutate $15_@6[7:17] = 1
|
||||
[8] Reassign mutate x$16_@6[7:17] = Binary read x$10_@0 + read $15_@6
|
||||
[7] Const mutate $15_@5 = 1
|
||||
[8] Reassign mutate x$16_@6[8:17] = Binary read x$10_@0 + read $15_@5
|
||||
"]
|
||||
bb5_instrs --> bb5_terminal(["Goto"])
|
||||
end
|
||||
subgraph bb3
|
||||
bb3_instrs["
|
||||
[10] Const mutate $17_@6[7:17] = 2
|
||||
[11] Reassign mutate x$18_@6[7:17] = Binary read x$10_@0 + read $17_@6
|
||||
[10] Const mutate $17_@7 = 2
|
||||
[11] Reassign mutate x$18_@6[8:17] = Binary read x$10_@0 + read $17_@7
|
||||
"]
|
||||
bb3_instrs --> bb3_terminal(["Goto"])
|
||||
end
|
||||
subgraph bb2
|
||||
bb2_instrs["
|
||||
[13] Const mutate $19_@8 = 3
|
||||
[14] Reassign mutate x$20_@6[7:17] = Binary read x$10_@0 + read $19_@8
|
||||
[14] Reassign mutate x$20_@6[8:17] = Binary read x$10_@0 + read $19_@8
|
||||
"]
|
||||
bb2_instrs --> bb2_terminal(["Goto"])
|
||||
end
|
||||
subgraph bb1
|
||||
bb1_instrs["
|
||||
[16] Let mutate y$22_@6[7:17] = read x$21_@6
|
||||
[16] Let mutate y$22_@6[8:17] = read x$21_@6
|
||||
"]
|
||||
bb1_instrs --> bb1_terminal(["Return"])
|
||||
end
|
||||
|
||||
@@ -27,8 +27,8 @@ bb1:
|
||||
[5] If (read $8_@2) then:bb3 else:bb2
|
||||
bb3:
|
||||
predecessor blocks: bb1
|
||||
[6] Const mutate $9_@0[0:9] = 1
|
||||
[7] Reassign mutate x$10_@0[0:9] = Binary read x$7_@0 + read $9_@0
|
||||
[6] Const mutate $9_@3 = 1
|
||||
[7] Reassign mutate x$10_@0[0:9] = Binary read x$7_@0 + read $9_@3
|
||||
[8] Goto(Continue) bb1
|
||||
bb2:
|
||||
predecessor blocks: bb1
|
||||
@@ -55,8 +55,8 @@ flowchart TB
|
||||
end
|
||||
subgraph bb3
|
||||
bb3_instrs["
|
||||
[6] Const mutate $9_@0[0:9] = 1
|
||||
[7] Reassign mutate x$10_@0[0:9] = Binary read x$7_@0 + read $9_@0
|
||||
[6] Const mutate $9_@3 = 1
|
||||
[7] Reassign mutate x$10_@0[0:9] = Binary read x$7_@0 + read $9_@3
|
||||
"]
|
||||
bb3_instrs --> bb3_terminal(["Goto"])
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user