Skip to content

Commit 946d551

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 7bf2cc9 commit 946d551

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
@@ -24,7 +24,6 @@ import {
2424
IdentifierId,
2525
Instruction,
2626
InstructionKind,
27-
InstructionValue,
2827
isArrayType,
2928
isJsxType,
3029
isMapType,
@@ -61,7 +60,6 @@ import {
6160
printAliasingSignature,
6261
printIdentifier,
6362
printInstruction,
64-
printInstructionValue,
6563
printPlace,
6664
printSourceLocation,
6765
} from '../HIR/PrintHIR';
@@ -107,11 +105,11 @@ export function inferMutationAliasingEffects(
107105
const statesByBlock: Map<BlockId, InferenceState> = new Map();
108106

109107
for (const ref of fn.context) {
110-
// TODO: using InstructionValue as a bit of a hack, but it's pragmatic
111-
const value: InstructionValue = {
112-
kind: 'ObjectExpression',
113-
properties: [],
114-
loc: ref.loc,
108+
const value: AliasingEffect = {
109+
kind: 'Create',
110+
into: ref,
111+
value: ValueKind.Context,
112+
reason: ValueReason.Other,
115113
};
116114
initialState.initialize(value, {
117115
kind: ValueKind.Context,
@@ -144,10 +142,11 @@ export function inferMutationAliasingEffects(
144142
}
145143
if (ref != null) {
146144
const place = ref.kind === 'Identifier' ? ref : ref.place;
147-
const value: InstructionValue = {
148-
kind: 'ObjectExpression',
149-
properties: [],
150-
loc: place.loc,
145+
const value: AliasingEffect = {
146+
kind: 'Create',
147+
into: place,
148+
value: ValueKind.Mutable,
149+
reason: ValueReason.Other,
151150
};
152151
initialState.initialize(value, {
153152
kind: ValueKind.Mutable,
@@ -264,8 +263,6 @@ function findHoistedContextDeclarations(
264263
class Context {
265264
internedEffects: Map<string, AliasingEffect> = new Map();
266265
instructionSignatureCache: Map<Instruction, InstructionSignature> = new Map();
267-
effectInstructionValueCache: Map<AliasingEffect, InstructionValue> =
268-
new Map();
269266
applySignatureCache: Map<
270267
AliasingSignature,
271268
Map<AliasingEffect, Array<AliasingEffect> | null>
@@ -317,10 +314,11 @@ function inferParam(
317314
paramKind: AbstractValue,
318315
): void {
319316
const place = param.kind === 'Identifier' ? param : param.place;
320-
const value: InstructionValue = {
321-
kind: 'Primitive',
322-
loc: place.loc,
323-
value: undefined,
317+
const value: AliasingEffect = {
318+
kind: 'Create',
319+
into: place,
320+
value: paramKind.kind,
321+
reason: ValueReason.Other,
324322
};
325323
initialState.initialize(value, paramKind);
326324
initialState.define(place, value);
@@ -531,20 +529,11 @@ function applyEffect(
531529
});
532530
initialized.add(effect.into.identifier.id);
533531

534-
let value = context.effectInstructionValueCache.get(effect);
535-
if (value == null) {
536-
value = {
537-
kind: 'ObjectExpression',
538-
properties: [],
539-
loc: effect.into.loc,
540-
};
541-
context.effectInstructionValueCache.set(effect, value);
542-
}
543-
state.initialize(value, {
532+
state.initialize(effect, {
544533
kind: effect.value,
545534
reason: new Set([effect.reason]),
546535
});
547-
state.define(effect.into, value);
536+
state.define(effect.into, effect);
548537
effects.push(effect);
549538
break;
550539
}
@@ -571,20 +560,11 @@ function applyEffect(
571560
initialized.add(effect.into.identifier.id);
572561

573562
const fromValue = state.kind(effect.from);
574-
let value = context.effectInstructionValueCache.get(effect);
575-
if (value == null) {
576-
value = {
577-
kind: 'ObjectExpression',
578-
properties: [],
579-
loc: effect.into.loc,
580-
};
581-
context.effectInstructionValueCache.set(effect, value);
582-
}
583-
state.initialize(value, {
563+
state.initialize(effect, {
584564
kind: fromValue.kind,
585565
reason: new Set(fromValue.reason),
586566
});
587-
state.define(effect.into, value);
567+
state.define(effect.into, effect);
588568
switch (fromValue.kind) {
589569
case ValueKind.Primitive:
590570
case ValueKind.Global: {
@@ -672,11 +652,11 @@ function applyEffect(
672652
operand.effect = Effect.Read;
673653
}
674654
}
675-
state.initialize(effect.function, {
655+
state.initialize(effect, {
676656
kind: isMutable ? ValueKind.Mutable : ValueKind.Frozen,
677657
reason: new Set([]),
678658
});
679-
state.define(effect.into, effect.function);
659+
state.define(effect.into, effect);
680660
for (const capture of effect.captures) {
681661
applyEffect(
682662
context,
@@ -782,38 +762,20 @@ function applyEffect(
782762
initialized,
783763
effects,
784764
);
785-
let value = context.effectInstructionValueCache.get(effect);
786-
if (value == null) {
787-
value = {
788-
kind: 'Primitive',
789-
value: undefined,
790-
loc: effect.from.loc,
791-
};
792-
context.effectInstructionValueCache.set(effect, value);
793-
}
794-
state.initialize(value, {
765+
state.initialize(effect, {
795766
kind: fromKind,
796767
reason: new Set(fromValue.reason),
797768
});
798-
state.define(effect.into, value);
769+
state.define(effect.into, effect);
799770
break;
800771
}
801772
case ValueKind.Global:
802773
case ValueKind.Primitive: {
803-
let value = context.effectInstructionValueCache.get(effect);
804-
if (value == null) {
805-
value = {
806-
kind: 'Primitive',
807-
value: undefined,
808-
loc: effect.from.loc,
809-
};
810-
context.effectInstructionValueCache.set(effect, value);
811-
}
812-
state.initialize(value, {
774+
state.initialize(effect, {
813775
kind: fromKind,
814776
reason: new Set(fromValue.reason),
815777
});
816-
state.define(effect.into, value);
778+
state.define(effect.into, effect);
817779
break;
818780
}
819781
default: {
@@ -828,14 +790,15 @@ function applyEffect(
828790
const functionValues = state.values(effect.function);
829791
if (
830792
functionValues.length === 1 &&
831-
functionValues[0].kind === 'FunctionExpression' &&
832-
functionValues[0].loweredFunc.func.aliasingEffects != null
793+
functionValues[0].kind === 'CreateFunction' &&
794+
functionValues[0].function.kind === 'FunctionExpression' &&
795+
functionValues[0].function.loweredFunc.func.aliasingEffects != null
833796
) {
834797
/*
835798
* We're calling a locally declared function, we already know it's effects!
836799
* We just have to substitute in the args for the params
837800
*/
838-
const functionExpr = functionValues[0];
801+
const functionExpr = functionValues[0].function;
839802
let signature = context.functionSignatureCache.get(functionExpr);
840803
if (signature == null) {
841804
signature = buildSignatureFromFunctionExpression(
@@ -1114,19 +1077,19 @@ class InferenceState {
11141077
#isFunctionExpression: boolean;
11151078

11161079
// The kind of each value, based on its allocation site
1117-
#values: Map<InstructionValue, AbstractValue>;
1080+
#values: Map<AliasingEffect, AbstractValue>;
11181081
/*
11191082
* The set of values pointed to by each identifier. This is a set
11201083
* to accomodate phi points (where a variable may have different
11211084
* values from different control flow paths).
11221085
*/
1123-
#variables: Map<IdentifierId, Set<InstructionValue>>;
1086+
#variables: Map<IdentifierId, Set<AliasingEffect>>;
11241087

11251088
constructor(
11261089
env: Environment,
11271090
isFunctionExpression: boolean,
1128-
values: Map<InstructionValue, AbstractValue>,
1129-
variables: Map<IdentifierId, Set<InstructionValue>>,
1091+
values: Map<AliasingEffect, AbstractValue>,
1092+
variables: Map<IdentifierId, Set<AliasingEffect>>,
11301093
) {
11311094
this.env = env;
11321095
this.#isFunctionExpression = isFunctionExpression;
@@ -1146,18 +1109,11 @@ class InferenceState {
11461109
}
11471110

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

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

12221178
// Defines (initializing or updating) a variable with a specific kind of value.
1223-
define(place: Place, value: InstructionValue): void {
1179+
define(place: Place, value: AliasingEffect): void {
12241180
CompilerError.invariant(this.#values.has(value), {
12251181
reason: `[InferMutationAliasingEffects] Expected value to be initialized at '${printSourceLocation(
1226-
value.loc,
1182+
place.loc,
12271183
)}'`,
1228-
description: printInstructionValue(value),
1229-
loc: value.loc,
1184+
description: printAliasingEffect(value),
1185+
loc: place.loc,
12301186
suggestions: null,
12311187
});
12321188
this.#variables.set(place.identifier.id, new Set([value]));
@@ -1266,17 +1222,17 @@ class InferenceState {
12661222
}
12671223
}
12681224

1269-
freezeValue(value: InstructionValue, reason: ValueReason): void {
1225+
freezeValue(value: AliasingEffect, reason: ValueReason): void {
12701226
this.#values.set(value, {
12711227
kind: ValueKind.Frozen,
12721228
reason: new Set([reason]),
12731229
});
12741230
if (
1275-
value.kind === 'FunctionExpression' &&
1231+
value.kind === 'CreateFunction' &&
12761232
(this.env.config.enablePreserveExistingMemoizationGuarantees ||
12771233
this.env.config.enableTransitivelyFreezeFunctionExpressions)
12781234
) {
1279-
for (const place of value.loweredFunc.func.context) {
1235+
for (const place of value.function.loweredFunc.func.context) {
12801236
this.freeze(place, reason);
12811237
}
12821238
}
@@ -1351,8 +1307,8 @@ class InferenceState {
13511307
* termination.
13521308
*/
13531309
merge(other: InferenceState): InferenceState | null {
1354-
let nextValues: Map<InstructionValue, AbstractValue> | null = null;
1355-
let nextVariables: Map<IdentifierId, Set<InstructionValue>> | null = null;
1310+
let nextValues: Map<AliasingEffect, AbstractValue> | null = null;
1311+
let nextVariables: Map<IdentifierId, Set<AliasingEffect>> | null = null;
13561312

13571313
for (const [id, thisValue] of this.#values) {
13581314
const otherValue = other.#values.get(id);
@@ -1376,7 +1332,7 @@ class InferenceState {
13761332
for (const [id, thisValues] of this.#variables) {
13771333
const otherValues = other.#variables.get(id);
13781334
if (otherValues !== undefined) {
1379-
let mergedValues: Set<InstructionValue> | null = null;
1335+
let mergedValues: Set<AliasingEffect> | null = null;
13801336
for (const otherValue of otherValues) {
13811337
if (!thisValues.has(otherValue)) {
13821338
mergedValues = mergedValues ?? new Set(thisValues);
@@ -1429,8 +1385,8 @@ class InferenceState {
14291385
*/
14301386
debug(): any {
14311387
const result: any = {values: {}, variables: {}};
1432-
const objects: Map<InstructionValue, number> = new Map();
1433-
function identify(value: InstructionValue): number {
1388+
const objects: Map<AliasingEffect, number> = new Map();
1389+
function identify(value: AliasingEffect): number {
14341390
let id = objects.get(value);
14351391
if (id == null) {
14361392
id = objects.size;
@@ -1442,7 +1398,7 @@ class InferenceState {
14421398
const id = identify(value);
14431399
result.values[id] = {
14441400
abstract: this.debugAbstractValue(kind),
1445-
value: printInstructionValue(value),
1401+
value: printAliasingEffect(value),
14461402
};
14471403
}
14481404
for (const [variable, values] of this.#variables) {
@@ -1459,7 +1415,7 @@ class InferenceState {
14591415
}
14601416

14611417
inferPhi(phi: Phi): void {
1462-
const values: Set<InstructionValue> = new Set();
1418+
const values: Set<AliasingEffect> = new Set();
14631419
for (const [_, operand] of phi.operands) {
14641420
const operandValues = this.#variables.get(operand.identifier.id);
14651421
// This is a backedge that will be handled later by State.merge
@@ -2315,8 +2271,9 @@ function areArgumentsImmutableAndNonMutating(
23152271
const values = state.values(place);
23162272
for (const value of values) {
23172273
if (
2318-
value.kind === 'FunctionExpression' &&
2319-
value.loweredFunc.func.params.some(param => {
2274+
value.kind === 'CreateFunction' &&
2275+
value.function.kind === 'FunctionExpression' &&
2276+
value.function.loweredFunc.func.params.some(param => {
23202277
const place = param.kind === 'Identifier' ? param : param.place;
23212278
const range = place.identifier.mutableRange;
23222279
return range.end > range.start + 1;

0 commit comments

Comments
 (0)