Skip to content

Commit 41984c8

Browse files
committed
[compiler] InferEffects uses effects as value keys
In InferReferenceEffects we used `InstructionValue` as the key to represent values, since each time we process an instruction this object will be the same. However this was always a bit of a hack, and in the new model and InferMutationAliasingEffects we can instead use the (creation) effect as the stable value. This avoids an extra layer of memoization since the effects are already interned anyway.
1 parent 2ba9a6c commit 41984c8

File tree

1 file changed

+52
-95
lines changed

1 file changed

+52
-95
lines changed

compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts

Lines changed: 52 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import {
2323
IdentifierId,
2424
Instruction,
2525
InstructionKind,
26-
InstructionValue,
2726
isArrayType,
2827
isJsxType,
2928
isMapType,
@@ -60,7 +59,6 @@ import {
6059
printAliasingSignature,
6160
printIdentifier,
6261
printInstruction,
63-
printInstructionValue,
6462
printPlace,
6563
printSourceLocation,
6664
} from '../HIR/PrintHIR';
@@ -106,11 +104,11 @@ export function inferMutationAliasingEffects(
106104
const statesByBlock: Map<BlockId, InferenceState> = new Map();
107105

108106
for (const ref of fn.context) {
109-
// TODO: using InstructionValue as a bit of a hack, but it's pragmatic
110-
const value: InstructionValue = {
111-
kind: 'ObjectExpression',
112-
properties: [],
113-
loc: ref.loc,
107+
const value: AliasingEffect = {
108+
kind: 'Create',
109+
into: ref,
110+
value: ValueKind.Context,
111+
reason: ValueReason.Other,
114112
};
115113
initialState.initialize(value, {
116114
kind: ValueKind.Context,
@@ -143,10 +141,11 @@ export function inferMutationAliasingEffects(
143141
}
144142
if (ref != null) {
145143
const place = ref.kind === 'Identifier' ? ref : ref.place;
146-
const value: InstructionValue = {
147-
kind: 'ObjectExpression',
148-
properties: [],
149-
loc: place.loc,
144+
const value: AliasingEffect = {
145+
kind: 'Create',
146+
into: place,
147+
value: ValueKind.Mutable,
148+
reason: ValueReason.Other,
150149
};
151150
initialState.initialize(value, {
152151
kind: ValueKind.Mutable,
@@ -263,8 +262,6 @@ function findHoistedContextDeclarations(
263262
class Context {
264263
internedEffects: Map<string, AliasingEffect> = new Map();
265264
instructionSignatureCache: Map<Instruction, InstructionSignature> = new Map();
266-
effectInstructionValueCache: Map<AliasingEffect, InstructionValue> =
267-
new Map();
268265
applySignatureCache: Map<
269266
AliasingSignature,
270267
Map<AliasingEffect, Array<AliasingEffect> | null>
@@ -316,10 +313,11 @@ function inferParam(
316313
paramKind: AbstractValue,
317314
): void {
318315
const place = param.kind === 'Identifier' ? param : param.place;
319-
const value: InstructionValue = {
320-
kind: 'Primitive',
321-
loc: place.loc,
322-
value: undefined,
316+
const value: AliasingEffect = {
317+
kind: 'Create',
318+
into: place,
319+
value: paramKind.kind,
320+
reason: ValueReason.Other,
323321
};
324322
initialState.initialize(value, paramKind);
325323
initialState.define(place, value);
@@ -527,20 +525,11 @@ function applyEffect(
527525
});
528526
initialized.add(effect.into.identifier.id);
529527

530-
let value = context.effectInstructionValueCache.get(effect);
531-
if (value == null) {
532-
value = {
533-
kind: 'ObjectExpression',
534-
properties: [],
535-
loc: effect.into.loc,
536-
};
537-
context.effectInstructionValueCache.set(effect, value);
538-
}
539-
state.initialize(value, {
528+
state.initialize(effect, {
540529
kind: effect.value,
541530
reason: new Set([effect.reason]),
542531
});
543-
state.define(effect.into, value);
532+
state.define(effect.into, effect);
544533
effects.push(effect);
545534
break;
546535
}
@@ -567,20 +556,11 @@ function applyEffect(
567556
initialized.add(effect.into.identifier.id);
568557

569558
const fromValue = state.kind(effect.from);
570-
let value = context.effectInstructionValueCache.get(effect);
571-
if (value == null) {
572-
value = {
573-
kind: 'ObjectExpression',
574-
properties: [],
575-
loc: effect.into.loc,
576-
};
577-
context.effectInstructionValueCache.set(effect, value);
578-
}
579-
state.initialize(value, {
559+
state.initialize(effect, {
580560
kind: fromValue.kind,
581561
reason: new Set(fromValue.reason),
582562
});
583-
state.define(effect.into, value);
563+
state.define(effect.into, effect);
584564
switch (fromValue.kind) {
585565
case ValueKind.Primitive:
586566
case ValueKind.Global: {
@@ -668,11 +648,11 @@ function applyEffect(
668648
operand.effect = Effect.Read;
669649
}
670650
}
671-
state.initialize(effect.function, {
651+
state.initialize(effect, {
672652
kind: isMutable ? ValueKind.Mutable : ValueKind.Frozen,
673653
reason: new Set([]),
674654
});
675-
state.define(effect.into, effect.function);
655+
state.define(effect.into, effect);
676656
for (const capture of effect.captures) {
677657
applyEffect(
678658
context,
@@ -777,38 +757,20 @@ function applyEffect(
777757
initialized,
778758
effects,
779759
);
780-
let value = context.effectInstructionValueCache.get(effect);
781-
if (value == null) {
782-
value = {
783-
kind: 'Primitive',
784-
value: undefined,
785-
loc: effect.from.loc,
786-
};
787-
context.effectInstructionValueCache.set(effect, value);
788-
}
789-
state.initialize(value, {
760+
state.initialize(effect, {
790761
kind: fromKind,
791762
reason: new Set(fromValue.reason),
792763
});
793-
state.define(effect.into, value);
764+
state.define(effect.into, effect);
794765
break;
795766
}
796767
case ValueKind.Global:
797768
case ValueKind.Primitive: {
798-
let value = context.effectInstructionValueCache.get(effect);
799-
if (value == null) {
800-
value = {
801-
kind: 'Primitive',
802-
value: undefined,
803-
loc: effect.from.loc,
804-
};
805-
context.effectInstructionValueCache.set(effect, value);
806-
}
807-
state.initialize(value, {
769+
state.initialize(effect, {
808770
kind: fromKind,
809771
reason: new Set(fromValue.reason),
810772
});
811-
state.define(effect.into, value);
773+
state.define(effect.into, effect);
812774
break;
813775
}
814776
default: {
@@ -823,14 +785,15 @@ function applyEffect(
823785
const functionValues = state.values(effect.function);
824786
if (
825787
functionValues.length === 1 &&
826-
functionValues[0].kind === 'FunctionExpression' &&
827-
functionValues[0].loweredFunc.func.aliasingEffects != null
788+
functionValues[0].kind === 'CreateFunction' &&
789+
functionValues[0].function.kind === 'FunctionExpression' &&
790+
functionValues[0].function.loweredFunc.func.aliasingEffects != null
828791
) {
829792
/*
830793
* We're calling a locally declared function, we already know it's effects!
831794
* We just have to substitute in the args for the params
832795
*/
833-
const functionExpr = functionValues[0];
796+
const functionExpr = functionValues[0].function;
834797
let signature = context.functionSignatureCache.get(functionExpr);
835798
if (signature == null) {
836799
signature = buildSignatureFromFunctionExpression(
@@ -1115,19 +1078,19 @@ class InferenceState {
11151078
#isFunctionExpression: boolean;
11161079

11171080
// The kind of each value, based on its allocation site
1118-
#values: Map<InstructionValue, AbstractValue>;
1081+
#values: Map<AliasingEffect, AbstractValue>;
11191082
/*
11201083
* The set of values pointed to by each identifier. This is a set
11211084
* to accomodate phi points (where a variable may have different
11221085
* values from different control flow paths).
11231086
*/
1124-
#variables: Map<IdentifierId, Set<InstructionValue>>;
1087+
#variables: Map<IdentifierId, Set<AliasingEffect>>;
11251088

11261089
constructor(
11271090
env: Environment,
11281091
isFunctionExpression: boolean,
1129-
values: Map<InstructionValue, AbstractValue>,
1130-
variables: Map<IdentifierId, Set<InstructionValue>>,
1092+
values: Map<AliasingEffect, AbstractValue>,
1093+
variables: Map<IdentifierId, Set<AliasingEffect>>,
11311094
) {
11321095
this.env = env;
11331096
this.#isFunctionExpression = isFunctionExpression;
@@ -1147,18 +1110,11 @@ class InferenceState {
11471110
}
11481111

11491112
// (Re)initializes a @param value with its default @param kind.
1150-
initialize(value: InstructionValue, kind: AbstractValue): void {
1151-
CompilerError.invariant(value.kind !== 'LoadLocal', {
1152-
reason:
1153-
'[InferMutationAliasingEffects] Expected all top-level identifiers to be defined as variables, not values',
1154-
description: null,
1155-
loc: value.loc,
1156-
suggestions: null,
1157-
});
1113+
initialize(value: AliasingEffect, kind: AbstractValue): void {
11581114
this.#values.set(value, kind);
11591115
}
11601116

1161-
values(place: Place): Array<InstructionValue> {
1117+
values(place: Place): Array<AliasingEffect> {
11621118
const values = this.#variables.get(place.identifier.id);
11631119
CompilerError.invariant(values != null, {
11641120
reason: `[InferMutationAliasingEffects] Expected value kind to be initialized`,
@@ -1221,13 +1177,13 @@ class InferenceState {
12211177
}
12221178

12231179
// Defines (initializing or updating) a variable with a specific kind of value.
1224-
define(place: Place, value: InstructionValue): void {
1180+
define(place: Place, value: AliasingEffect): void {
12251181
CompilerError.invariant(this.#values.has(value), {
12261182
reason: `[InferMutationAliasingEffects] Expected value to be initialized at '${printSourceLocation(
1227-
value.loc,
1183+
place.loc,
12281184
)}'`,
1229-
description: printInstructionValue(value),
1230-
loc: value.loc,
1185+
description: printAliasingEffect(value),
1186+
loc: place.loc,
12311187
suggestions: null,
12321188
});
12331189
this.#variables.set(place.identifier.id, new Set([value]));
@@ -1267,17 +1223,17 @@ class InferenceState {
12671223
}
12681224
}
12691225

1270-
freezeValue(value: InstructionValue, reason: ValueReason): void {
1226+
freezeValue(value: AliasingEffect, reason: ValueReason): void {
12711227
this.#values.set(value, {
12721228
kind: ValueKind.Frozen,
12731229
reason: new Set([reason]),
12741230
});
12751231
if (
1276-
value.kind === 'FunctionExpression' &&
1232+
value.kind === 'CreateFunction' &&
12771233
(this.env.config.enablePreserveExistingMemoizationGuarantees ||
12781234
this.env.config.enableTransitivelyFreezeFunctionExpressions)
12791235
) {
1280-
for (const place of value.loweredFunc.func.context) {
1236+
for (const place of value.function.loweredFunc.func.context) {
12811237
this.freeze(place, reason);
12821238
}
12831239
}
@@ -1352,8 +1308,8 @@ class InferenceState {
13521308
* termination.
13531309
*/
13541310
merge(other: InferenceState): InferenceState | null {
1355-
let nextValues: Map<InstructionValue, AbstractValue> | null = null;
1356-
let nextVariables: Map<IdentifierId, Set<InstructionValue>> | null = null;
1311+
let nextValues: Map<AliasingEffect, AbstractValue> | null = null;
1312+
let nextVariables: Map<IdentifierId, Set<AliasingEffect>> | null = null;
13571313

13581314
for (const [id, thisValue] of this.#values) {
13591315
const otherValue = other.#values.get(id);
@@ -1377,7 +1333,7 @@ class InferenceState {
13771333
for (const [id, thisValues] of this.#variables) {
13781334
const otherValues = other.#variables.get(id);
13791335
if (otherValues !== undefined) {
1380-
let mergedValues: Set<InstructionValue> | null = null;
1336+
let mergedValues: Set<AliasingEffect> | null = null;
13811337
for (const otherValue of otherValues) {
13821338
if (!thisValues.has(otherValue)) {
13831339
mergedValues = mergedValues ?? new Set(thisValues);
@@ -1430,8 +1386,8 @@ class InferenceState {
14301386
*/
14311387
debug(): any {
14321388
const result: any = {values: {}, variables: {}};
1433-
const objects: Map<InstructionValue, number> = new Map();
1434-
function identify(value: InstructionValue): number {
1389+
const objects: Map<AliasingEffect, number> = new Map();
1390+
function identify(value: AliasingEffect): number {
14351391
let id = objects.get(value);
14361392
if (id == null) {
14371393
id = objects.size;
@@ -1443,7 +1399,7 @@ class InferenceState {
14431399
const id = identify(value);
14441400
result.values[id] = {
14451401
abstract: this.debugAbstractValue(kind),
1446-
value: printInstructionValue(value),
1402+
value: printAliasingEffect(value),
14471403
};
14481404
}
14491405
for (const [variable, values] of this.#variables) {
@@ -1460,7 +1416,7 @@ class InferenceState {
14601416
}
14611417

14621418
inferPhi(phi: Phi): void {
1463-
const values: Set<InstructionValue> = new Set();
1419+
const values: Set<AliasingEffect> = new Set();
14641420
for (const [_, operand] of phi.operands) {
14651421
const operandValues = this.#variables.get(operand.identifier.id);
14661422
// This is a backedge that will be handled later by State.merge
@@ -2291,8 +2247,9 @@ function areArgumentsImmutableAndNonMutating(
22912247
const values = state.values(place);
22922248
for (const value of values) {
22932249
if (
2294-
value.kind === 'FunctionExpression' &&
2295-
value.loweredFunc.func.params.some(param => {
2250+
value.kind === 'CreateFunction' &&
2251+
value.function.kind === 'FunctionExpression' &&
2252+
value.function.loweredFunc.func.params.some(param => {
22962253
const place = param.kind === 'Identifier' ? param : param.place;
22972254
const range = place.identifier.mutableRange;
22982255
return range.end > range.start + 1;

0 commit comments

Comments
 (0)