Skip to content

Commit 35375c4

Browse files
committed
[compiler] Post/Pre-FixUpdate, try/catch, ConditionallyMutateIterator support
ghstack-source-id: e065e42 Pull Request resolved: #33427
1 parent 09da20a commit 35375c4

File tree

3 files changed

+105
-63
lines changed

3 files changed

+105
-63
lines changed

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

Lines changed: 85 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,7 @@ export function inferMutationAliasingEffects(
155155
}
156156
queue(fn.body.entry, initialState);
157157

158-
const signatureCache: Map<Instruction, InstructionSignature> = new Map();
159-
const effectInstructionValueCache: Map<AliasingEffect, InstructionValue> =
160-
new Map();
158+
const context = new Context();
161159

162160
let count = 0;
163161
while (queuedStates.size !== 0) {
@@ -179,7 +177,7 @@ export function inferMutationAliasingEffects(
179177

180178
statesByBlock.set(blockId, incomingState);
181179
const state = incomingState.clone();
182-
inferBlock(state, block, signatureCache, effectInstructionValueCache);
180+
inferBlock(context, state, block);
183181

184182
for (const nextBlockId of eachTerminalSuccessor(block.terminal)) {
185183
queue(nextBlockId, state);
@@ -189,6 +187,13 @@ export function inferMutationAliasingEffects(
189187
return Ok(undefined);
190188
}
191189

190+
class Context {
191+
instructionSignatureCache: Map<Instruction, InstructionSignature> = new Map();
192+
effectInstructionValueCache: Map<AliasingEffect, InstructionValue> =
193+
new Map();
194+
catchHandlers: Map<BlockId, Place> = new Map();
195+
}
196+
192197
function inferParam(
193198
param: Place | SpreadPattern,
194199
initialState: InferenceState,
@@ -205,29 +210,45 @@ function inferParam(
205210
}
206211

207212
function inferBlock(
213+
context: Context,
208214
state: InferenceState,
209215
block: BasicBlock,
210-
instructionSignatureCache: Map<Instruction, InstructionSignature>,
211-
effectInstructionValueCache: Map<AliasingEffect, InstructionValue>,
212216
): void {
213217
for (const phi of block.phis) {
214218
state.inferPhi(phi);
215219
}
216220

217221
for (const instr of block.instructions) {
218-
let instructionSignature = instructionSignatureCache.get(instr);
222+
let instructionSignature = context.instructionSignatureCache.get(instr);
219223
if (instructionSignature == null) {
220224
instructionSignature = computeSignatureForInstruction(state.env, instr);
221-
instructionSignatureCache.set(instr, instructionSignature);
225+
context.instructionSignatureCache.set(instr, instructionSignature);
222226
}
223-
const effects = applySignature(
224-
state,
225-
instructionSignature,
226-
instr,
227-
effectInstructionValueCache,
228-
);
227+
const effects = applySignature(context, state, instructionSignature, instr);
229228
instr.effects = effects;
230229
}
230+
const terminal = block.terminal;
231+
if (terminal.kind === 'try' && terminal.handlerBinding != null) {
232+
context.catchHandlers.set(terminal.handler, terminal.handlerBinding);
233+
} else if (terminal.kind === 'maybe-throw') {
234+
const handlerParam = context.catchHandlers.get(terminal.handler);
235+
if (handlerParam != null) {
236+
for (const instr of block.instructions) {
237+
if (
238+
instr.value.kind === 'CallExpression' ||
239+
instr.value.kind === 'MethodCall'
240+
) {
241+
/**
242+
* Many instructions can error, but only calls can throw their result as the error
243+
* itself. For example, `c = a.b` can throw if `a` is nullish, but the thrown value
244+
* is an error object synthesized by the JS runtime. Whereas `throwsInput(x)` can
245+
* throw (effectively) the result of the call.
246+
*/
247+
state.appendAlias(handlerParam, instr.lvalue);
248+
}
249+
}
250+
}
251+
}
231252
}
232253

233254
/**
@@ -240,10 +261,10 @@ function inferBlock(
240261
* This phase may also emit errors, for example MutateLocal on a frozen value is invalid.
241262
*/
242263
function applySignature(
264+
context: Context,
243265
state: InferenceState,
244266
signature: InstructionSignature,
245267
instruction: Instruction,
246-
effectInstructionValueCache: Map<AliasingEffect, InstructionValue>,
247268
): Array<AliasingEffect> | null {
248269
const effects: Array<AliasingEffect> = [];
249270
/**
@@ -305,14 +326,7 @@ function applySignature(
305326
}
306327

307328
for (const effect of signature.effects) {
308-
applyEffect(
309-
state,
310-
effect,
311-
instruction,
312-
effectInstructionValueCache,
313-
aliased,
314-
effects,
315-
);
329+
applyEffect(context, state, effect, instruction, aliased, effects);
316330
}
317331
if (DEBUG) {
318332
console.log(
@@ -334,10 +348,10 @@ function applySignature(
334348
}
335349

336350
function applyEffect(
351+
context: Context,
337352
state: InferenceState,
338353
effect: AliasingEffect,
339354
instruction: Instruction,
340-
effectInstructionValueCache: Map<AliasingEffect, InstructionValue>,
341355
aliased: Set<IdentifierId>,
342356
effects: Array<AliasingEffect>,
343357
): void {
@@ -353,14 +367,14 @@ function applyEffect(
353367
break;
354368
}
355369
case 'Create': {
356-
let value = effectInstructionValueCache.get(effect);
370+
let value = context.effectInstructionValueCache.get(effect);
357371
if (value == null) {
358372
value = {
359373
kind: 'ObjectExpression',
360374
properties: [],
361375
loc: effect.into.loc,
362376
};
363-
effectInstructionValueCache.set(effect, value);
377+
context.effectInstructionValueCache.set(effect, value);
364378
}
365379
state.initialize(value, {
366380
kind: effect.value,
@@ -385,14 +399,14 @@ function applyEffect(
385399
}
386400
case 'CreateFrom': {
387401
const kind = state.kind(effect.from).kind;
388-
let value = effectInstructionValueCache.get(effect);
402+
let value = context.effectInstructionValueCache.get(effect);
389403
if (value == null) {
390404
value = {
391405
kind: 'ObjectExpression',
392406
properties: [],
393407
loc: effect.into.loc,
394408
};
395-
effectInstructionValueCache.set(effect, value);
409+
context.effectInstructionValueCache.set(effect, value);
396410
}
397411
state.initialize(value, {
398412
kind,
@@ -456,14 +470,14 @@ function applyEffect(
456470
state.define(effect.into, effect.function);
457471
for (const capture of effect.captures) {
458472
applyEffect(
473+
context,
459474
state,
460475
{
461476
kind: 'Capture',
462477
from: capture,
463478
into: effect.into,
464479
},
465480
instruction,
466-
effectInstructionValueCache,
467481
aliased,
468482
effects,
469483
);
@@ -531,29 +545,29 @@ function applyEffect(
531545
from: effect.from,
532546
into: effect.into,
533547
});
534-
let value = effectInstructionValueCache.get(effect);
548+
let value = context.effectInstructionValueCache.get(effect);
535549
if (value == null) {
536550
value = {
537551
kind: 'Primitive',
538552
value: undefined,
539553
loc: effect.from.loc,
540554
};
541-
effectInstructionValueCache.set(effect, value);
555+
context.effectInstructionValueCache.set(effect, value);
542556
}
543557
state.initialize(value, {kind: fromKind, reason: new Set([])});
544558
state.define(effect.into, value);
545559
break;
546560
}
547561
case ValueKind.Global:
548562
case ValueKind.Primitive: {
549-
let value = effectInstructionValueCache.get(effect);
563+
let value = context.effectInstructionValueCache.get(effect);
550564
if (value == null) {
551565
value = {
552566
kind: 'Primitive',
553567
value: undefined,
554568
loc: effect.from.loc,
555569
};
556-
effectInstructionValueCache.set(effect, value);
570+
context.effectInstructionValueCache.set(effect, value);
557571
}
558572
state.initialize(value, {kind: fromKind, reason: new Set([])});
559573
state.define(effect.into, value);
@@ -605,10 +619,10 @@ function applyEffect(
605619
}
606620
for (const signatureEffect of signatureEffects) {
607621
applyEffect(
622+
context,
608623
state,
609624
signatureEffect,
610625
instruction,
611-
effectInstructionValueCache,
612626
aliased,
613627
effects,
614628
);
@@ -632,10 +646,10 @@ function applyEffect(
632646
}
633647
for (const signatureEffect of signatureEffects) {
634648
applyEffect(
649+
context,
635650
state,
636651
signatureEffect,
637652
instruction,
638-
effectInstructionValueCache,
639653
aliased,
640654
effects,
641655
);
@@ -653,10 +667,10 @@ function applyEffect(
653667
);
654668
for (const legacyEffect of legacyEffects) {
655669
applyEffect(
670+
context,
656671
state,
657672
legacyEffect,
658673
instruction,
659-
effectInstructionValueCache,
660674
aliased,
661675
effects,
662676
);
@@ -666,14 +680,14 @@ function applyEffect(
666680
console.log('default effects');
667681
}
668682
applyEffect(
683+
context,
669684
state,
670685
{
671686
kind: 'Create',
672687
into: effect.into,
673688
value: ValueKind.Mutable,
674689
},
675690
instruction,
676-
effectInstructionValueCache,
677691
aliased,
678692
effects,
679693
);
@@ -691,23 +705,23 @@ function applyEffect(
691705
const operand = arg.kind === 'Identifier' ? arg : arg.place;
692706
if (operand !== effect.function || effect.mutatesFunction) {
693707
applyEffect(
708+
context,
694709
state,
695710
{
696711
kind: 'MutateTransitiveConditionally',
697712
value: operand,
698713
},
699714
instruction,
700-
effectInstructionValueCache,
701715
aliased,
702716
effects,
703717
);
704718
}
705719
applyEffect(
720+
context,
706721
state,
707722
// OK: recording information flow
708723
{kind: 'Alias', from: operand, into: effect.into},
709724
instruction,
710-
effectInstructionValueCache,
711725
aliased,
712726
effects,
713727
);
@@ -725,6 +739,7 @@ function applyEffect(
725739
continue;
726740
}
727741
applyEffect(
742+
context,
728743
state,
729744
{
730745
/*
@@ -736,7 +751,6 @@ function applyEffect(
736751
into: other,
737752
},
738753
instruction,
739-
effectInstructionValueCache,
740754
aliased,
741755
effects,
742756
);
@@ -984,7 +998,6 @@ class InferenceState {
984998
| 'MutateTransitiveConditionally',
985999
place: Place,
9861000
): 'none' | 'mutate' | 'mutate-frozen' | 'mutate-global' {
987-
// TODO: consider handling of function expressions by looking at their effects
9881001
const kind = this.kind(place).kind;
9891002
switch (variant) {
9901003
case 'MutateConditionally':
@@ -1348,18 +1361,6 @@ function computeSignatureForInstruction(
13481361
effects.push({kind: 'Assign', from: value.value, into: lvalue});
13491362
break;
13501363
}
1351-
case 'PostfixUpdate':
1352-
case 'PrefixUpdate': {
1353-
effects.push({
1354-
kind: 'Create',
1355-
into: lvalue,
1356-
value: ValueKind.Primitive,
1357-
});
1358-
CompilerError.throwTodo({
1359-
reason: `Handle ${value.kind} in new inference`,
1360-
loc: instr.loc,
1361-
});
1362-
}
13631364
case 'ObjectMethod':
13641365
case 'FunctionExpression': {
13651366
/**
@@ -1570,6 +1571,15 @@ function computeSignatureForInstruction(
15701571
effects.push({kind: 'Assign', from: value.value, into: lvalue});
15711572
break;
15721573
}
1574+
case 'PostfixUpdate':
1575+
case 'PrefixUpdate': {
1576+
effects.push({
1577+
kind: 'Create',
1578+
into: lvalue,
1579+
value: ValueKind.Primitive,
1580+
});
1581+
break;
1582+
}
15731583
case 'StoreGlobal': {
15741584
CompilerError.throwTodo({
15751585
reason: `Handle StoreGlobal in new inference`,
@@ -1677,15 +1687,28 @@ function computeEffectsForLegacySignature(
16771687
break;
16781688
}
16791689
case Effect.ConditionallyMutateIterator: {
1680-
effects.push({
1681-
kind: 'Capture',
1682-
from: place,
1683-
into: lvalue,
1684-
});
1685-
effects.push({
1686-
kind: 'MutateTransitiveConditionally',
1687-
value: place,
1688-
});
1690+
if (
1691+
isArrayType(place.identifier) ||
1692+
isSetType(place.identifier) ||
1693+
isMapType(place.identifier)
1694+
) {
1695+
effects.push({
1696+
kind: 'Capture',
1697+
from: place,
1698+
into: lvalue,
1699+
});
1700+
} else {
1701+
effects.push({
1702+
kind: 'Capture',
1703+
from: place,
1704+
into: lvalue,
1705+
});
1706+
captures.push(place);
1707+
effects.push({
1708+
kind: 'MutateTransitiveConditionally',
1709+
value: place,
1710+
});
1711+
}
16891712
break;
16901713
}
16911714
case Effect.Freeze: {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* LICENSE file in the root directory of this source tree.
66
*/
77

8-
import {HIRFunction, IdentifierId, Place, ScopeId, ValueKind} from '../HIR';
8+
import {HIRFunction, IdentifierId, Place, ValueKind} from '../HIR';
99
import {getOrInsertDefault} from '../Utils/utils';
1010
import {AliasingEffect} from './InferMutationAliasingEffects';
1111

0 commit comments

Comments
 (0)