mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Make LValue non-nullable in HIR
This commit is contained in:
@@ -697,7 +697,13 @@ function lowerStatement(
|
||||
case "WithStatement": {
|
||||
builder.push({
|
||||
id: makeInstructionId(0),
|
||||
lvalue: null,
|
||||
lvalue: {
|
||||
place: buildTemporaryPlace(
|
||||
builder,
|
||||
stmtPath.node.loc ?? GeneratedSource
|
||||
),
|
||||
kind: InstructionKind.Const,
|
||||
},
|
||||
loc: stmtPath.node.loc ?? GeneratedSource,
|
||||
value: {
|
||||
kind: "OtherStatement",
|
||||
@@ -1330,7 +1336,10 @@ function lowerExpressionToVoid(
|
||||
id: makeInstructionId(0),
|
||||
value: instr,
|
||||
loc: exprLoc,
|
||||
lvalue: null,
|
||||
lvalue: {
|
||||
place: buildTemporaryPlace(builder, exprLoc),
|
||||
kind: InstructionKind.Const,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
InstructionValue,
|
||||
LValue,
|
||||
Place,
|
||||
ReactiveInstruction,
|
||||
SourceLocation,
|
||||
} from "./HIR";
|
||||
import { BlockTerminal, Visitor, visitTree } from "./HIRTreeVisitor";
|
||||
@@ -293,7 +294,7 @@ export function codegenLabel(id: BlockId): string {
|
||||
|
||||
export function codegenInstruction(
|
||||
temp: Temporaries,
|
||||
instr: Instruction,
|
||||
instr: ReactiveInstruction,
|
||||
value: t.Expression
|
||||
): t.Statement {
|
||||
if (t.isStatement(value)) {
|
||||
|
||||
@@ -65,10 +65,17 @@ export type ReactiveValueBlock = {
|
||||
};
|
||||
|
||||
export type ReactiveStatement =
|
||||
| { kind: "instruction"; instruction: Instruction }
|
||||
| { kind: "instruction"; instruction: ReactiveInstruction }
|
||||
| { kind: "terminal"; terminal: ReactiveTerminal; label: BlockId | null }
|
||||
| ReactiveScopeBlock;
|
||||
|
||||
export type ReactiveInstruction = {
|
||||
id: InstructionId;
|
||||
lvalue: LValue | null;
|
||||
value: InstructionValue;
|
||||
loc: SourceLocation;
|
||||
};
|
||||
|
||||
export type ReactiveTerminal =
|
||||
| { kind: "break"; label: BlockId | null }
|
||||
| { kind: "continue"; label: BlockId | null }
|
||||
@@ -225,7 +232,7 @@ export type ForTerminal = {
|
||||
*/
|
||||
export type Instruction = {
|
||||
id: InstructionId;
|
||||
lvalue: LValue | null;
|
||||
lvalue: LValue;
|
||||
value: InstructionValue;
|
||||
loc: SourceLocation;
|
||||
};
|
||||
|
||||
@@ -497,14 +497,6 @@ class Driver<
|
||||
let lastValue: { value: InstructionValue; id: InstructionId } | null = null;
|
||||
if (terminalValue != null) {
|
||||
lastValue = terminalValue;
|
||||
} else {
|
||||
if (
|
||||
instructions.length &&
|
||||
instructions[instructions.length - 1].lvalue === null
|
||||
) {
|
||||
const last = instructions.pop()!;
|
||||
lastValue = { value: last.value, id: last.id };
|
||||
}
|
||||
}
|
||||
for (const instr of instructions) {
|
||||
const value = this.visitor.visitValue(instr.value, instr.id);
|
||||
|
||||
@@ -38,9 +38,5 @@ function inferInstr(instr: Instruction, state: AliasAnalyser) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (lvalue === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
state.alias(lvalue, alias);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ export function inferAliasForStores(
|
||||
for (const [_, block] of func.body.blocks) {
|
||||
for (const instr of block.instructions) {
|
||||
const { value, lvalue } = instr;
|
||||
if (lvalue === null || lvalue.place.effect !== Effect.Store) {
|
||||
if (lvalue.place.effect !== Effect.Store) {
|
||||
continue;
|
||||
}
|
||||
switch (value.kind) {
|
||||
|
||||
@@ -121,17 +121,15 @@ export function inferMutableLifetimes(
|
||||
inferPlace(input, instr, inferMutableRangeForStores);
|
||||
}
|
||||
|
||||
if (instr.lvalue !== null) {
|
||||
const lvalueId = instr.lvalue.place.identifier;
|
||||
const lvalueId = instr.lvalue.place.identifier;
|
||||
|
||||
// lvalue start being mutable when they're initially assigned a
|
||||
// value.
|
||||
lvalueId.mutableRange.start = instr.id;
|
||||
// lvalue start being mutable when they're initially assigned a
|
||||
// value.
|
||||
lvalueId.mutableRange.start = instr.id;
|
||||
|
||||
// Let's be optimistic and assume this lvalue is not mutable by
|
||||
// default.
|
||||
lvalueId.mutableRange.end = makeInstructionId(instr.id + 1);
|
||||
}
|
||||
// Let's be optimistic and assume this lvalue is not mutable by
|
||||
// default.
|
||||
lvalueId.mutableRange.end = makeInstructionId(instr.id + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,10 +581,8 @@ function inferBlock(env: Environment, block: BasicBlock) {
|
||||
env.reference(instrValue.object, effect);
|
||||
|
||||
const lvalue = instr.lvalue;
|
||||
if (lvalue !== null) {
|
||||
env.alias(lvalue.place, instrValue.value);
|
||||
lvalue.place.effect = Effect.Store;
|
||||
}
|
||||
env.alias(lvalue.place, instrValue.value);
|
||||
lvalue.place.effect = Effect.Store;
|
||||
continue;
|
||||
}
|
||||
case "PropertyLoad": {
|
||||
@@ -601,10 +599,8 @@ function inferBlock(env: Environment, block: BasicBlock) {
|
||||
|
||||
env.reference(instrValue.object, Effect.Read);
|
||||
const lvalue = instr.lvalue;
|
||||
if (lvalue !== null) {
|
||||
env.initialize(instrValue, env.kind(instrValue.object));
|
||||
env.define(lvalue.place, instrValue);
|
||||
}
|
||||
env.initialize(instrValue, env.kind(instrValue.object));
|
||||
env.define(lvalue.place, instrValue);
|
||||
continue;
|
||||
}
|
||||
case "ComputedStore": {
|
||||
@@ -616,10 +612,8 @@ function inferBlock(env: Environment, block: BasicBlock) {
|
||||
env.reference(instrValue.object, effect);
|
||||
|
||||
const lvalue = instr.lvalue;
|
||||
if (lvalue !== null) {
|
||||
env.alias(lvalue.place, instrValue.value);
|
||||
lvalue.place.effect = Effect.Store;
|
||||
}
|
||||
env.alias(lvalue.place, instrValue.value);
|
||||
lvalue.place.effect = Effect.Store;
|
||||
continue;
|
||||
}
|
||||
case "ComputedLoad": {
|
||||
@@ -637,20 +631,16 @@ function inferBlock(env: Environment, block: BasicBlock) {
|
||||
env.reference(instrValue.object, Effect.Read);
|
||||
env.reference(instrValue.property, Effect.Read);
|
||||
const lvalue = instr.lvalue;
|
||||
if (lvalue !== null) {
|
||||
env.initialize(instrValue, env.kind(instrValue.object));
|
||||
env.define(lvalue.place, instrValue);
|
||||
}
|
||||
env.initialize(instrValue, env.kind(instrValue.object));
|
||||
env.define(lvalue.place, instrValue);
|
||||
continue;
|
||||
}
|
||||
case "Identifier": {
|
||||
env.reference(instrValue, Effect.Read);
|
||||
const lvalue = instr.lvalue;
|
||||
if (lvalue !== null) {
|
||||
lvalue.place.effect = Effect.Mutate;
|
||||
// direct aliasing: `a = b`;
|
||||
env.alias(lvalue.place, instrValue);
|
||||
}
|
||||
lvalue.place.effect = Effect.Mutate;
|
||||
// direct aliasing: `a = b`;
|
||||
env.alias(lvalue.place, instrValue);
|
||||
continue;
|
||||
}
|
||||
default: {
|
||||
@@ -668,10 +658,8 @@ function inferBlock(env: Environment, block: BasicBlock) {
|
||||
}
|
||||
|
||||
env.initialize(instrValue, valueKind);
|
||||
if (instr.lvalue !== null) {
|
||||
env.define(instr.lvalue.place, instrValue);
|
||||
instr.lvalue.place.effect = lvalueEffect;
|
||||
}
|
||||
env.define(instr.lvalue.place, instrValue);
|
||||
instr.lvalue.place.effect = lvalueEffect;
|
||||
}
|
||||
|
||||
const effect =
|
||||
|
||||
@@ -55,11 +55,7 @@ function apply(func: HIRFunction, unifier: Unifier) {
|
||||
place.identifier.type = unifier.get(place.identifier.type);
|
||||
}
|
||||
const { lvalue } = instr;
|
||||
if (lvalue !== null) {
|
||||
lvalue.place.identifier.type = unifier.get(
|
||||
lvalue.place.identifier.type
|
||||
);
|
||||
}
|
||||
lvalue.place.identifier.type = unifier.get(lvalue.place.identifier.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
MutableRange,
|
||||
Phi,
|
||||
Place,
|
||||
ReactiveInstruction,
|
||||
ReactiveScope,
|
||||
SourceLocation,
|
||||
Terminal,
|
||||
@@ -96,7 +97,7 @@ export function printMixedHIR(
|
||||
}
|
||||
}
|
||||
|
||||
export function printInstruction(instr: Instruction): string {
|
||||
export function printInstruction(instr: ReactiveInstruction): string {
|
||||
const id = `[${instr.id}]`;
|
||||
const value = printInstructionValue(instr.value);
|
||||
|
||||
|
||||
@@ -301,9 +301,7 @@ class ReactiveFunctionBuilder
|
||||
}
|
||||
|
||||
function getInstructionScope(instr: Instruction): ReactiveScope | null {
|
||||
let scope: ReactiveScope | null = null;
|
||||
if (
|
||||
instr.lvalue !== null &&
|
||||
instr.lvalue.place.identifier.scope !== null &&
|
||||
isScopeActive(instr.lvalue.place.identifier.scope, instr.id)
|
||||
) {
|
||||
|
||||
@@ -18,10 +18,10 @@ import {
|
||||
} from "../HIR/Codegen";
|
||||
import {
|
||||
Identifier,
|
||||
Instruction,
|
||||
InstructionKind,
|
||||
ReactiveBlock,
|
||||
ReactiveFunction,
|
||||
ReactiveInstruction,
|
||||
ReactiveScope,
|
||||
ReactiveScopeDependency,
|
||||
ReactiveTerminal,
|
||||
@@ -301,7 +301,7 @@ function codegenTerminal(cx: Context, terminal: ReactiveTerminal): t.Statement {
|
||||
|
||||
export function codegenInstructionNullable(
|
||||
cx: Context,
|
||||
instr: Instruction,
|
||||
instr: ReactiveInstruction,
|
||||
value: t.Expression
|
||||
): t.Statement | null {
|
||||
let statement;
|
||||
|
||||
@@ -78,11 +78,9 @@ export function inferReactiveScopeVariables(fn: HIRFunction) {
|
||||
|
||||
for (const instr of block.instructions) {
|
||||
const operands: Array<Identifier> = [];
|
||||
if (instr.lvalue !== null) {
|
||||
const range = instr.lvalue.place.identifier.mutableRange;
|
||||
if (range.end > range.start + 1 || mayAllocate(instr.value)) {
|
||||
operands.push(instr.lvalue!.place.identifier);
|
||||
}
|
||||
const range = instr.lvalue.place.identifier.mutableRange;
|
||||
if (range.end > range.start + 1 || mayAllocate(instr.value)) {
|
||||
operands.push(instr.lvalue!.place.identifier);
|
||||
}
|
||||
for (const operand of eachInstructionOperand(instr)) {
|
||||
if (
|
||||
|
||||
@@ -286,7 +286,6 @@ class MergeOverlappingReactiveScopesVisitor
|
||||
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
|
||||
@@ -443,7 +442,6 @@ class AlignReactiveScopesToBlockScopeRangeVisitor
|
||||
|
||||
function getInstructionScope(instr: Instruction): ReactiveScope | null {
|
||||
if (
|
||||
instr.lvalue !== null &&
|
||||
instr.lvalue.place.identifier.scope !== null &&
|
||||
isActive(instr, instr.lvalue.place.identifier.scope.range)
|
||||
) {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
import {
|
||||
Identifier,
|
||||
Instruction,
|
||||
InstructionId,
|
||||
InstructionKind,
|
||||
InstructionValue,
|
||||
@@ -16,6 +15,7 @@ import {
|
||||
Place,
|
||||
ReactiveBlock,
|
||||
ReactiveFunction,
|
||||
ReactiveInstruction,
|
||||
ReactiveScope,
|
||||
ReactiveScopeDependency,
|
||||
ReactiveValueBlock,
|
||||
@@ -280,7 +280,7 @@ function visitInstructionValue(
|
||||
}
|
||||
}
|
||||
|
||||
function visitInstruction(context: Context, instr: Instruction): void {
|
||||
function visitInstruction(context: Context, instr: ReactiveInstruction): void {
|
||||
const { lvalue } = instr;
|
||||
visitInstructionValue(context, instr.value, lvalue);
|
||||
if (lvalue !== null && lvalue.kind !== InstructionKind.Reassign) {
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
import {
|
||||
Identifier,
|
||||
Instruction,
|
||||
InstructionKind,
|
||||
ReactiveFunction,
|
||||
ReactiveInstruction,
|
||||
} from "../HIR/HIR";
|
||||
import { visitFunction } from "./visitors";
|
||||
|
||||
@@ -18,7 +18,7 @@ import { visitFunction } from "./visitors";
|
||||
* nulls out the lvalue itself, it does not remove the corresponding instructions.
|
||||
*/
|
||||
export function pruneTemporaryLValues(fn: ReactiveFunction): void {
|
||||
const lvalues = new Map<Identifier, Instruction>();
|
||||
const lvalues = new Map<Identifier, ReactiveInstruction>();
|
||||
visitFunction(fn, {
|
||||
visitInstruction: (instr) => {
|
||||
if (
|
||||
|
||||
@@ -13,10 +13,7 @@ import {
|
||||
ReactiveTerminal,
|
||||
ReactiveValueBlock,
|
||||
} from "../HIR/HIR";
|
||||
import {
|
||||
eachInstructionOperand,
|
||||
eachInstructionValueOperand,
|
||||
} from "../HIR/visitors";
|
||||
import { eachInstructionValueOperand } from "../HIR/visitors";
|
||||
import { invariant } from "../Utils/CompilerError";
|
||||
import { assertExhaustive } from "../Utils/utils";
|
||||
|
||||
@@ -49,7 +46,9 @@ function visitBlockInner(scopes: Scopes, block: ReactiveBlock): void {
|
||||
for (const stmt of block) {
|
||||
switch (stmt.kind) {
|
||||
case "instruction": {
|
||||
for (const operand of eachInstructionOperand(stmt.instruction)) {
|
||||
for (const operand of eachInstructionValueOperand(
|
||||
stmt.instruction.value
|
||||
)) {
|
||||
scopes.visit(operand.identifier);
|
||||
}
|
||||
if (stmt.instruction.lvalue !== null) {
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
Instruction,
|
||||
InstructionValue,
|
||||
Place,
|
||||
ReactiveBlock,
|
||||
ReactiveFunction,
|
||||
ReactiveInstruction,
|
||||
ReactiveScope,
|
||||
ReactiveTerminal,
|
||||
ReactiveValueBlock,
|
||||
@@ -22,7 +22,7 @@ export function visitFunction(
|
||||
fn: ReactiveFunction,
|
||||
visitors: {
|
||||
visitValue?: (value: InstructionValue) => void;
|
||||
visitInstruction?: (instr: Instruction) => void;
|
||||
visitInstruction?: (instr: ReactiveInstruction) => void;
|
||||
visitTerminal?: (terminal: ReactiveTerminal) => void;
|
||||
visitScope?: (scope: ReactiveScope) => void;
|
||||
}
|
||||
|
||||
@@ -82,10 +82,7 @@ export function eliminateRedundantPhi(fn: HIRFunction) {
|
||||
for (const place of eachInstructionOperand(instr)) {
|
||||
rewritePlace(place, rewrites);
|
||||
}
|
||||
const { lvalue } = instr;
|
||||
if (lvalue !== null) {
|
||||
rewritePlace(lvalue.place, rewrites);
|
||||
}
|
||||
rewritePlace(instr.lvalue.place, rewrites);
|
||||
}
|
||||
|
||||
// Rewrite all terminal operands
|
||||
|
||||
@@ -281,21 +281,19 @@ export function leaveSSA(fn: HIRFunction) {
|
||||
// SSA variables to `const` where possible
|
||||
for (const instr of block.instructions) {
|
||||
const { lvalue } = instr;
|
||||
if (lvalue !== null) {
|
||||
if (
|
||||
lvalue.kind === InstructionKind.Const &&
|
||||
rewrites.has(lvalue.place.identifier)
|
||||
) {
|
||||
// For rewrites, the declaration of the canonical identifier has to be `let`,
|
||||
// all other assignments are reassignments (which we annotate for codegen
|
||||
// purposes).
|
||||
lvalue.kind =
|
||||
rewrites.get(lvalue.place.identifier) === lvalue.place.identifier
|
||||
? InstructionKind.Let
|
||||
: InstructionKind.Reassign;
|
||||
}
|
||||
rewritePlace(lvalue.place, rewrites);
|
||||
if (
|
||||
lvalue.kind === InstructionKind.Const &&
|
||||
rewrites.has(lvalue.place.identifier)
|
||||
) {
|
||||
// For rewrites, the declaration of the canonical identifier has to be `let`,
|
||||
// all other assignments are reassignments (which we annotate for codegen
|
||||
// purposes).
|
||||
lvalue.kind =
|
||||
rewrites.get(lvalue.place.identifier) === lvalue.place.identifier
|
||||
? InstructionKind.Let
|
||||
: InstructionKind.Reassign;
|
||||
}
|
||||
rewritePlace(lvalue.place, rewrites);
|
||||
for (const operand of eachInstructionValueOperand(instr.value)) {
|
||||
rewritePlace(operand, rewrites);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user