mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
782e004e49
Summary: Without getting into the weeds too much, RawPropParser "requires" that props be accessed in the same order every time a Props struct is parsed in order to most optimally fetch the values in a linear-ish fashion, basically ensuring that each rawProps.at() call is an O(1) operation, and overall getting all props for a particular component is O(n) in the number of props for a given struct. If props are called out of order, this breaks and worst-case we can end up with an O(n^2) operation. Unfortunately, calling .at(x) twice with the same prop name triggers the deoptimized behavior. So as much as possible, always fetch exactly once and in the same order every time. In this case, we move initialization of two fields into the constructor body so that we can call .at() a single time instead of twice. In the debug props of ViewProps I'm also reordering the fields to fetch them in the same order the constructor fetches them in, which will make this (debug-only) method slightly faster. What's the impact of this? If you dig into the Tracery samples, the average/median RawPropsParser::at takes 1us or less. However, in /every single/ call to createNode for View components, there is at least one RawPropsParser::at call that takes 250+us. This was a huge red flag when analyzing traces, after which it was trivial (for View) to find the offending out-of-order calls. Since this is happening for every View and every type of component that derives from View, that's 1ms lost per every 4 View-type ShadowNodes created by ReactJS. After just 100 views created, that's 25ms. Etc. There are other out-of-order calls lurking in the codebase that can be addressed separately. Impact scales with the size of the screen, the number of Views they render, etc. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D36889794 fbshipit-source-id: 91e0a7ca39ed10778e60a0f0339a4b4dc8b14436
161 lines
5.1 KiB
C++
161 lines
5.1 KiB
C++
/*
|
|
* 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.
|
|
*/
|
|
|
|
#include "AccessibilityProps.h"
|
|
|
|
#include <react/renderer/components/view/accessibilityPropsConversions.h>
|
|
#include <react/renderer/components/view/propsConversions.h>
|
|
#include <react/renderer/core/propsConversions.h>
|
|
#include <react/renderer/debug/debugStringConvertibleUtils.h>
|
|
|
|
namespace facebook {
|
|
namespace react {
|
|
|
|
AccessibilityProps::AccessibilityProps(
|
|
const PropsParserContext &context,
|
|
AccessibilityProps const &sourceProps,
|
|
RawProps const &rawProps)
|
|
: accessible(convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"accessible",
|
|
sourceProps.accessible,
|
|
false)),
|
|
accessibilityState(convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"accessibilityState",
|
|
sourceProps.accessibilityState,
|
|
{})),
|
|
accessibilityLabel(convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"accessibilityLabel",
|
|
sourceProps.accessibilityLabel,
|
|
"")),
|
|
accessibilityLabelledBy(convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"accessibilityLabelledBy",
|
|
sourceProps.accessibilityLabelledBy,
|
|
{})),
|
|
accessibilityLiveRegion(convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"accessibilityLiveRegion",
|
|
sourceProps.accessibilityLiveRegion,
|
|
AccessibilityLiveRegion::None)),
|
|
accessibilityHint(convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"accessibilityHint",
|
|
sourceProps.accessibilityHint,
|
|
"")),
|
|
accessibilityLanguage(convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"accessibilityLanguage",
|
|
sourceProps.accessibilityLanguage,
|
|
"")),
|
|
accessibilityValue(convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"accessibilityValue",
|
|
sourceProps.accessibilityValue,
|
|
{})),
|
|
accessibilityActions(convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"accessibilityActions",
|
|
sourceProps.accessibilityActions,
|
|
{})),
|
|
accessibilityViewIsModal(convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"accessibilityViewIsModal",
|
|
sourceProps.accessibilityViewIsModal,
|
|
false)),
|
|
accessibilityElementsHidden(convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"accessibilityElementsHidden",
|
|
sourceProps.accessibilityElementsHidden,
|
|
false)),
|
|
accessibilityIgnoresInvertColors(convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"accessibilityIgnoresInvertColors",
|
|
sourceProps.accessibilityIgnoresInvertColors,
|
|
false)),
|
|
onAccessibilityTap(convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"onAccessibilityTap",
|
|
sourceProps.onAccessibilityTap,
|
|
{})),
|
|
onAccessibilityMagicTap(convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"onAccessibilityMagicTap",
|
|
sourceProps.onAccessibilityMagicTap,
|
|
{})),
|
|
onAccessibilityEscape(convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"onAccessibilityEscape",
|
|
sourceProps.onAccessibilityEscape,
|
|
{})),
|
|
onAccessibilityAction(convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"onAccessibilityAction",
|
|
sourceProps.onAccessibilityAction,
|
|
{})),
|
|
importantForAccessibility(convertRawProp(
|
|
context,
|
|
rawProps,
|
|
"importantForAccessibility",
|
|
sourceProps.importantForAccessibility,
|
|
ImportantForAccessibility::Auto)),
|
|
testId(
|
|
convertRawProp(context, rawProps, "testID", sourceProps.testId, "")) {
|
|
// It is a (severe!) perf deoptimization to request props out-of-order.
|
|
// Thus, since we need to request the same prop twice here
|
|
// (accessibilityRole) we "must" do them subsequently here to prevent
|
|
// a regression. It is reasonable to ask if the `at` function can be improved;
|
|
// it probably can, but this is a fairly rare edge-case that (1) is easy-ish
|
|
// to work around here, and (2) would require very careful work to address
|
|
// this case and not regress the more common cases.
|
|
const auto *rawPropValue = rawProps.at("accessibilityRole", nullptr, nullptr);
|
|
AccessibilityTraits traits;
|
|
std::string roleString;
|
|
if (rawPropValue == nullptr || !rawPropValue->hasValue()) {
|
|
traits = AccessibilityTraits::None;
|
|
roleString = "";
|
|
} else {
|
|
fromRawValue(context, *rawPropValue, traits);
|
|
fromRawValue(context, *rawPropValue, roleString);
|
|
}
|
|
|
|
accessibilityTraits = traits;
|
|
accessibilityRole = roleString;
|
|
}
|
|
|
|
#pragma mark - DebugStringConvertible
|
|
|
|
#if RN_DEBUG_STRING_CONVERTIBLE
|
|
SharedDebugStringConvertibleList AccessibilityProps::getDebugProps() const {
|
|
auto const &defaultProps = AccessibilityProps();
|
|
return SharedDebugStringConvertibleList{
|
|
debugStringConvertibleItem("testId", testId, defaultProps.testId),
|
|
};
|
|
}
|
|
#endif // RN_DEBUG_STRING_CONVERTIBLE
|
|
|
|
} // namespace react
|
|
} // namespace facebook
|