Skip to content

Commit 193b7dd

Browse files
dmytrorykunfacebook-github-bot
authored andcommitted
Make RawPropsParser::iterateOverValues more performant (facebook#45088)
Summary: Pull Request resolved: facebook#45088 This diff should make iterator-style prop setting more performant. - It removes some layers of indirection. Now `ConcreteComponentDescriptor` calls into `setProp` directly. - On both platforms, we will use `folly::dynamic` parser, it seems it is slightly faster. - On Android, we will reuse `props->rawProps` parsed as a `folly::dynamic` representation, instead of parsing stuff twice. Changelog: [Internal] - This hasn't been rolled out to OSS yet. Reviewed By: sammy-SC Differential Revision: D58593492
1 parent 4a8f0ee commit 193b7dd

File tree

6 files changed

+36
-106
lines changed

6 files changed

+36
-106
lines changed

packages/react-native/ReactCommon/react/renderer/core/ConcreteComponentDescriptor.h

+13-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
#pragma once
99

10-
#include <functional>
1110
#include <memory>
1211

1312
#include <react/debug/react_native_assert.h>
@@ -119,11 +118,19 @@ class ConcreteComponentDescriptor : public ComponentDescriptor {
119118
// Note that we just check if `Props` has this flag set, no matter
120119
// the type of ShadowNode; it acts as the single global flag.
121120
if (CoreFeatures::enablePropIteratorSetter) {
122-
rawProps.iterateOverValues([&](RawPropsPropNameHash hash,
123-
const char* propName,
124-
const RawValue& fn) {
125-
shadowNodeProps.get()->setProp(context, hash, propName, fn);
126-
});
121+
#ifdef ANDROID
122+
const auto& dynamic = shadowNodeProps->rawProps;
123+
#else
124+
const auto& dynamic = static_cast<folly::dynamic>(rawProps);
125+
#endif
126+
for (const auto& key : dynamic.keys()) {
127+
const auto name = key.getString();
128+
shadowNodeProps->setProp(
129+
context,
130+
RAW_PROPS_KEY_HASH(name),
131+
name.c_str(),
132+
RawValue{dynamic[key]});
133+
}
127134
}
128135

129136
return shadowNodeProps;

packages/react-native/ReactCommon/react/renderer/core/RawProps.cpp

-6
Original file line numberDiff line numberDiff line change
@@ -209,10 +209,4 @@ const RawValue* RawProps::at(
209209
return parser_->at(*this, RawPropsKey{prefix, name, suffix});
210210
}
211211

212-
void RawProps::iterateOverValues(
213-
const std::function<
214-
void(RawPropsPropNameHash, const char*, const RawValue&)>& fn) const {
215-
return parser_->iterateOverValues(*this, fn);
216-
}
217-
218212
} // namespace facebook::react

packages/react-native/ReactCommon/react/renderer/core/RawProps.h

-8
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,6 @@ class RawProps final {
9595
const RawValue* at(const char* name, const char* prefix, const char* suffix)
9696
const noexcept;
9797

98-
/**
99-
* Iterator functions: for when you want to iterate over values in-order
100-
* instead of using `at` to access values randomly.
101-
*/
102-
void iterateOverValues(
103-
const std::function<
104-
void(RawPropsPropNameHash, const char*, const RawValue&)>& fn) const;
105-
10698
private:
10799
friend class RawPropsParser;
108100

packages/react-native/ReactCommon/react/renderer/core/RawPropsParser.cpp

+17-70
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,23 @@ const RawValue* RawPropsParser::at(
4545
return nullptr;
4646
}
4747

48-
// Normally, keys are looked up in-order. For performance we can simply
49-
// increment this key counter, and if the key is equal to the key at the next
50-
// index, there's no need to do any lookups. However, it's possible for keys
51-
// to be accessed out-of-order or multiple times, in which case we start
52-
// searching again from index 0.
53-
// To prevent infinite loops (which can occur if you look up a key that
54-
// doesn't exist) we keep track of whether or not we've already looped around,
55-
// and log and return nullptr if so. However, we ONLY do this in debug mode,
56-
// where you're more likely to look up a nonexistent key as part of debugging.
57-
// You can (and must) ensure infinite loops are not possible in production by:
58-
// (1) constructing all props objects without conditionals, or (2) if there
59-
// are conditionals, ensure that in the parsing setup case, the Props
60-
// constructor will access _all_ possible props. To ensure this performance
61-
// optimization is utilized, always access props in the same order every time.
62-
// This is trivial if you have a simple Props constructor, but difficult or
63-
// impossible if you have a shared sub-prop Struct that is used by multiple
64-
// parent Props.
48+
// Normally, keys are looked up in-order. For performance we can simply
49+
// increment this key counter, and if the key is equal to the key at the next
50+
// index, there's no need to do any lookups. However, it's possible for keys
51+
// to be accessed out-of-order or multiple times, in which case we start
52+
// searching again from index 0.
53+
// To prevent infinite loops (which can occur if you look up a key that
54+
// doesn't exist) we keep track of whether or not we've already looped around,
55+
// and log and return nullptr if so. However, we ONLY do this in debug mode,
56+
// where you're more likely to look up a nonexistent key as part of debugging.
57+
// You can (and must) ensure infinite loops are not possible in production by:
58+
// (1) constructing all props objects without conditionals, or (2) if there
59+
// are conditionals, ensure that in the parsing setup case, the Props
60+
// constructor will access _all_ possible props. To ensure this performance
61+
// optimization is utilized, always access props in the same order every time.
62+
// This is trivial if you have a simple Props constructor, but difficult or
63+
// impossible if you have a shared sub-prop Struct that is used by multiple
64+
// parent Props.
6565
#ifdef REACT_NATIVE_DEBUG
6666
bool resetLoop = false;
6767
#endif
@@ -168,57 +168,4 @@ void RawPropsParser::preparse(const RawProps& rawProps) const noexcept {
168168
}
169169
}
170170

171-
/**
172-
* To be used by RawProps only. Value iterator functions.
173-
*/
174-
void RawPropsParser::iterateOverValues(
175-
const RawProps& rawProps,
176-
const std::function<
177-
void(RawPropsPropNameHash, const char*, const RawValue&)>& visit)
178-
const {
179-
switch (rawProps.mode_) {
180-
case RawProps::Mode::Empty:
181-
return;
182-
183-
case RawProps::Mode::JSI: {
184-
auto& runtime = *rawProps.runtime_;
185-
if (!rawProps.value_.isObject()) {
186-
LOG(ERROR) << "Preparse props: rawProps value is not object";
187-
}
188-
react_native_assert(rawProps.value_.isObject());
189-
auto object = rawProps.value_.asObject(runtime);
190-
191-
auto names = object.getPropertyNames(runtime);
192-
auto count = names.size(runtime);
193-
194-
for (size_t i = 0; i < count; i++) {
195-
auto nameValue = names.getValueAtIndex(runtime, i).getString(runtime);
196-
auto value = object.getProperty(runtime, nameValue);
197-
198-
auto name = nameValue.utf8(runtime);
199-
200-
auto nameHash = RAW_PROPS_KEY_HASH(name);
201-
auto rawValue = RawValue(jsi::dynamicFromValue(runtime, value));
202-
203-
visit(nameHash, name.c_str(), rawValue);
204-
}
205-
206-
break;
207-
}
208-
209-
case RawProps::Mode::Dynamic: {
210-
const auto& dynamic = rawProps.dynamic_;
211-
212-
for (const auto& pair : dynamic.items()) {
213-
auto name = pair.first.getString();
214-
215-
auto nameHash = RAW_PROPS_KEY_HASH(name);
216-
auto rawValue = RawValue{pair.second};
217-
visit(nameHash, name.c_str(), rawValue);
218-
}
219-
break;
220-
}
221-
}
222-
}
223-
224171
} // namespace facebook::react

packages/react-native/ReactCommon/react/renderer/core/RawPropsParser.h

-9
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,6 @@ class RawPropsParser final {
7373
const RawValue* at(const RawProps& rawProps, const RawPropsKey& key)
7474
const noexcept;
7575

76-
/**
77-
* To be used by RawProps only. Value iterator functions.
78-
*/
79-
void iterateOverValues(
80-
const RawProps& rawProps,
81-
const std::function<
82-
void(RawPropsPropNameHash, const char*, const RawValue&)>& visit)
83-
const;
84-
8576
mutable std::vector<RawPropsKey> keys_{};
8677
mutable RawPropsKeyMap nameToIndex_{};
8778
mutable bool ready_{false};

packages/react-native/ReactCommon/react/renderer/core/RawValue.h

+6-7
Original file line numberDiff line numberDiff line change
@@ -65,18 +65,17 @@ class RawValue {
6565
return *this;
6666
}
6767

68+
explicit RawValue(const folly::dynamic& dynamic) noexcept
69+
: dynamic_(dynamic) {}
70+
71+
explicit RawValue(folly::dynamic&& dynamic) noexcept
72+
: dynamic_(std::move(dynamic)) {}
73+
6874
private:
6975
friend class RawProps;
7076
friend class RawPropsParser;
7177
friend class UIManagerBinding;
7278

73-
/*
74-
* Arbitrary constructors are private only for RawProps and internal usage.
75-
*/
76-
RawValue(const folly::dynamic& dynamic) noexcept : dynamic_(dynamic) {}
77-
78-
RawValue(folly::dynamic&& dynamic) noexcept : dynamic_(std::move(dynamic)) {}
79-
8079
/*
8180
* Copy constructor and copy assignment operator would be private and only for
8281
* internal use, but it's needed for user-code that does `auto val =

0 commit comments

Comments
 (0)