mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
5030e08575
Summary:
Refs, as stable values that the rules of react around mutability do not apply to, currently are treated as having mutable ranges, and through aliasing, this can extend the mutable range for other values and disrupt good memoization for those values. This PR excludes refs and their .current values from having mutable ranges.
Note that this is unsafe if ref access is allowed in render: if a mutable value is assigned to ref.current and then ref.current is mutated later, we won't realize that the original mutable value's range extends.
ghstack-source-id: e8f36ac25e
Pull Request resolved: https://github.com/facebook/react/pull/30713
55 lines
1.5 KiB
TypeScript
55 lines
1.5 KiB
TypeScript
/**
|
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
import {
|
|
HIRFunction,
|
|
Identifier,
|
|
InstructionId,
|
|
isRefOrRefValue,
|
|
} from '../HIR/HIR';
|
|
import DisjointSet from '../Utils/DisjointSet';
|
|
|
|
export function inferMutableRangesForAlias(
|
|
_fn: HIRFunction,
|
|
aliases: DisjointSet<Identifier>,
|
|
): void {
|
|
const aliasSets = aliases.buildSets();
|
|
for (const aliasSet of aliasSets) {
|
|
/*
|
|
* Update mutableRange.end only if the identifiers have actually been
|
|
* mutated.
|
|
*/
|
|
const mutatingIdentifiers = [...aliasSet].filter(
|
|
id =>
|
|
id.mutableRange.end - id.mutableRange.start > 1 && !isRefOrRefValue(id),
|
|
);
|
|
|
|
if (mutatingIdentifiers.length > 0) {
|
|
// Find final instruction which mutates this alias set.
|
|
let lastMutatingInstructionId = 0;
|
|
for (const id of mutatingIdentifiers) {
|
|
if (id.mutableRange.end > lastMutatingInstructionId) {
|
|
lastMutatingInstructionId = id.mutableRange.end;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Update mutableRange.end for all aliases in this set ending before the
|
|
* last mutation.
|
|
*/
|
|
for (const alias of aliasSet) {
|
|
if (
|
|
alias.mutableRange.end < lastMutatingInstructionId &&
|
|
!isRefOrRefValue(alias)
|
|
) {
|
|
alias.mutableRange.end = lastMutatingInstructionId as InstructionId;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|