mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Fix crash in PreAllocation optimization
Summary: PreAllocation currently always happens at revision 0 (after ShadowNode creation), and all CREATE mutations are triggered for ShadowNodes at revision 1 or higher (since CREATE mutations are generated by the differ, it means that all ShadowNodes have revision 1 or higher when CompleteRoot is called). This means that between PreAllocation and CREATE, we /always/ expect at least one clone. It is possible for a node to be "non-view-forming" at revision 0, causing view preallocation to be skipped, and "view-forming" at revision 1 (causing the CREATE mutation to be thrown away, since all CREATE mutations of revision 0 or 1 are thrown away). This causes a crash. It is extremely marginal, but there are repros in the wild. Thus, I'm introducing one new UIManager and Scheduler delegate method that allows the mounting layer to be notified of clones. If a clone from rev 0->1 results in a node going from non-view-forming to view-forming, we can preallocate then, as well. This resolves this crash, and allows us to keep experimenting safely with this View PreAllocation optimization. I believe all edge-cases are accounted for. Changelog: [Internal] Reviewed By: sammy-SC Differential Revision: D29043426 fbshipit-source-id: dff11d3140ded1cbb02a5518a3aeb52dc812cc50
This commit is contained in:
committed by
Facebook GitHub Bot
parent
36c0a7dec1
commit
f2e0b2f45f
@@ -1128,13 +1128,9 @@ void Binding::driveCxxAnimations() {
|
||||
scheduler_->animationTick();
|
||||
}
|
||||
|
||||
void Binding::schedulerDidRequestPreliminaryViewAllocation(
|
||||
void Binding::preallocateShadowView(
|
||||
const SurfaceId surfaceId,
|
||||
const ShadowView &shadowView) {
|
||||
if (disablePreallocateViews_) {
|
||||
return;
|
||||
}
|
||||
|
||||
jni::global_ref<jobject> localJavaUIManager = getJavaUIManager();
|
||||
if (!localJavaUIManager) {
|
||||
LOG(ERROR)
|
||||
@@ -1144,11 +1140,6 @@ void Binding::schedulerDidRequestPreliminaryViewAllocation(
|
||||
|
||||
bool isLayoutableShadowNode = shadowView.layoutMetrics != EmptyLayoutMetrics;
|
||||
|
||||
if (disableVirtualNodePreallocation_ &&
|
||||
!shadowView.traits.check(ShadowNodeTraits::Trait::FormsView)) {
|
||||
return;
|
||||
}
|
||||
|
||||
static auto preallocateView =
|
||||
jni::findClassStatic(Binding::UIManagerJavaDescriptor)
|
||||
->getMethod<void(
|
||||
@@ -1191,6 +1182,53 @@ void Binding::schedulerDidRequestPreliminaryViewAllocation(
|
||||
isLayoutableShadowNode);
|
||||
}
|
||||
|
||||
void Binding::schedulerDidRequestPreliminaryViewAllocation(
|
||||
const SurfaceId surfaceId,
|
||||
const ShadowNode &shadowNode) {
|
||||
if (disablePreallocateViews_) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto shadowView = ShadowView(shadowNode);
|
||||
|
||||
if (disableVirtualNodePreallocation_ &&
|
||||
!shadowView.traits.check(ShadowNodeTraits::Trait::FormsView)) {
|
||||
return;
|
||||
}
|
||||
|
||||
preallocateShadowView(surfaceId, shadowView);
|
||||
}
|
||||
|
||||
void Binding::schedulerDidCloneShadowNode(
|
||||
SurfaceId surfaceId,
|
||||
const ShadowNode &oldShadowNode,
|
||||
const ShadowNode &newShadowNode) {
|
||||
// This is only necessary if view preallocation was skipped during
|
||||
// createShadowNode
|
||||
if (!disableVirtualNodePreallocation_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We may need to PreAllocate a ShadowNode at this point if this is the
|
||||
// earliest point it is possible to do so:
|
||||
// 1. The revision is exactly 1
|
||||
// 2. At revision 0 (the old node), View Preallocation would have been skipped
|
||||
|
||||
if (newShadowNode.getProps()->revision != 1) {
|
||||
return;
|
||||
}
|
||||
if (oldShadowNode.getProps()->revision != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the new node is concrete and the old wasn't, we can preallocate
|
||||
if (!oldShadowNode.getTraits().check(ShadowNodeTraits::Trait::FormsView) &&
|
||||
newShadowNode.getTraits().check(ShadowNodeTraits::Trait::FormsView)) {
|
||||
auto shadowView = ShadowView(newShadowNode);
|
||||
preallocateShadowView(surfaceId, shadowView);
|
||||
}
|
||||
}
|
||||
|
||||
void Binding::schedulerDidDispatchCommand(
|
||||
const ShadowView &shadowView,
|
||||
std::string const &commandName,
|
||||
|
||||
@@ -135,9 +135,18 @@ class Binding : public jni::HybridClass<Binding>,
|
||||
void schedulerDidFinishTransaction(
|
||||
MountingCoordinator::Shared const &mountingCoordinator) override;
|
||||
|
||||
void preallocateShadowView(
|
||||
const SurfaceId surfaceId,
|
||||
const ShadowView &shadowView);
|
||||
|
||||
void schedulerDidRequestPreliminaryViewAllocation(
|
||||
const SurfaceId surfaceId,
|
||||
const ShadowView &shadowView) override;
|
||||
const ShadowNode &shadowNode) override;
|
||||
|
||||
void schedulerDidCloneShadowNode(
|
||||
SurfaceId surfaceId,
|
||||
const ShadowNode &oldShadowNode,
|
||||
const ShadowNode &newShadowNode) override;
|
||||
|
||||
void schedulerDidDispatchCommand(
|
||||
const ShadowView &shadowView,
|
||||
|
||||
Reference in New Issue
Block a user