Add feature flag to use JSI NativeState instead of HostObject (#36395)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/36395

NativeState is a lighter-weight alternative to HostObject, which may simplify some of our use-cases of interacting with JS in the renderer. The down-side is that this approach doesn't allow exposing custom props or functions.

This diffs adds new feature flags to enable experimenting with this functionality and measure any perf impact.

Changelog: [Internal]

Reviewed By: sammy-SC

Differential Revision: D41553421

fbshipit-source-id: 3065bd7b60f0fa7b63c390e92a785582eee7e613
This commit is contained in:
Pieter De Baets authored and Facebook GitHub Bot committed 2023-03-07 08:11:02 -08:00
1 parent 4a925c43c2
commit 3a06cca9dc
11 files changed
+87 -32

No files matched your search

+4
View File
@@ -277,6 +277,10 @@ static BackgroundExecutor RCTGetBackgroundExecutor()
CoreFeatures::enablePropIteratorSetter = true;
}
if (reactNativeConfig && reactNativeConfig->getBool("react_fabric:use_native_state")) {
CoreFeatures::useNativeState = true;
}
auto componentRegistryFactory =
[factory = wrapManagedObject(_mountingManager.componentViewRegistry.componentViewFactory)](
EventDispatcher::Weak const &eventDispatcher, ContextContainer::Shared const &contextContainer) {
@@ -118,4 +118,10 @@ public class ReactFeatureFlags {
* SurfaceMountingManager.
*/
public static boolean reduceDeleteCreateMutation = false;
/**
* Use JSI NativeState API to store references to native objects rather than the more expensive
* HostObject pattern
*/
public static boolean useNativeState = false;
}
@@ -433,6 +433,9 @@ void Binding::installFabricUIManager(
CoreFeatures::enablePropIteratorSetter =
getFeatureFlagValue("enableCppPropsIteratorSetter");
// NativeState experiment
CoreFeatures::useNativeState = getFeatureFlagValue("useNativeState");
// RemoveDelete mega-op
ShadowViewMutation::PlatformSupportsRemoveDeleteTreeInstruction =
getFeatureFlagValue("enableRemoveDeleteTreeInstruction");
@@ -13,6 +13,7 @@ namespace react {
bool CoreFeatures::enablePropIteratorSetter = false;
bool CoreFeatures::enableMapBuffer = false;
bool CoreFeatures::blockPaintForUseLayoutEffect = false;
bool CoreFeatures::useNativeState = false;
} // namespace react
} // namespace facebook
@@ -30,6 +30,10 @@ class CoreFeatures {
// useLayoutEffect hooks to be processed. This changes affects scheduling of
// when a transaction is mounted.
static bool blockPaintForUseLayoutEffect;
// Whether to use Hermes' NativeState instead of HostObject
// in simple data passing scenarios with JS
static bool useNativeState;
};
} // namespace react
+3 -1
View File
@@ -29,7 +29,9 @@ static constexpr const int kShadowNodeChildrenSmallVectorSize = 8;
class ComponentDescriptor;
struct ShadowNodeFragment;
class ShadowNode : public Sealable, public DebugStringConvertible {
class ShadowNode : public Sealable,
public DebugStringConvertible,
public jsi::NativeState {
public:
using Shared = std::shared_ptr<ShadowNode const>;
using Weak = std::weak_ptr<ShadowNode const>;
+1 -2
View File
@@ -8,7 +8,6 @@ load(
"get_apple_compiler_flags",
"get_apple_inspector_flags",
"get_preprocessor_flags_for_build_mode",
"react_native_target",
"react_native_xplat_target",
"rn_xplat_cxx_library",
"subdir_glob",
@@ -53,7 +52,7 @@ rn_xplat_cxx_library(
fbandroid_allow_jni_merging = True,
fbandroid_deps = [
FBJNI_TARGET,
react_native_target("jni/react/jni:jni"),
"//xplat/folly:dynamic",
],
fbandroid_exported_headers = subdir_glob(
[
@@ -49,6 +49,7 @@ rn_xplat_cxx_library(
deps = [
"//xplat/folly:dynamic",
react_native_xplat_target("runtimeexecutor:runtimeexecutor"),
react_native_xplat_target("react/renderer/core:core"),
react_native_xplat_target("react/renderer/debug:debug"),
react_native_xplat_target("butter:butter"),
react_native_xplat_target("callinvoker:callinvoker"),
@@ -21,7 +21,7 @@ class TaskPriorityComparer;
using RawCallback = std::function<void(jsi::Runtime &)>;
struct Task final {
struct Task final : public jsi::NativeState {
Task(
SchedulerPriority priority,
jsi::Function callback,
@@ -9,6 +9,7 @@
#include <folly/dynamic.h>
#include <jsi/jsi.h>
#include <react/renderer/core/CoreFeatures.h>
#include <react/renderer/runtimescheduler/Task.h>
namespace facebook {
@@ -22,9 +23,15 @@ struct TaskWrapper : public jsi::HostObject {
inline static jsi::Value valueFromTask(
jsi::Runtime &runtime,
std::shared_ptr<Task> const &task) {
return jsi::Object::createFromHostObject(
runtime, std::make_shared<TaskWrapper>(task));
std::shared_ptr<Task> task) {
if (CoreFeatures::useNativeState) {
jsi::Object obj(runtime);
obj.setNativeState(runtime, std::move(task));
return obj;
} else {
return jsi::Object::createFromHostObject(
runtime, std::make_shared<TaskWrapper>(task));
}
}
inline static std::shared_ptr<Task> taskFromValue(
@@ -34,7 +41,11 @@ inline static std::shared_ptr<Task> taskFromValue(
return nullptr;
}
return value.getObject(runtime).getHostObject<TaskWrapper>(runtime)->task;
if (CoreFeatures::useNativeState) {
return value.getObject(runtime).getNativeState<Task>(runtime);
} else {
return value.getObject(runtime).getHostObject<TaskWrapper>(runtime)->task;
}
}
} // namespace react
@@ -11,6 +11,7 @@
#include <jsi/JSIDynamic.h>
#include <jsi/jsi.h>
#include <react/debug/react_native_assert.h>
#include <react/renderer/core/CoreFeatures.h>
#include <react/renderer/core/EventHandler.h>
#include <react/renderer/core/ShadowNode.h>
@@ -38,9 +39,9 @@ struct ShadowNodeWrapper : public jsi::HostObject {
ShadowNode::Shared shadowNode;
};
struct ShadowNodeListWrapper : public jsi::HostObject {
struct ShadowNodeListWrapper : public jsi::HostObject, public jsi::NativeState {
ShadowNodeListWrapper(ShadowNode::UnsharedListOfShared shadowNodeList)
: shadowNodeList(shadowNodeList) {}
: shadowNodeList(std::move(shadowNodeList)) {}
// The below method needs to be implemented out-of-line in order for the class
// to have at least one "key function" (see
@@ -52,29 +53,63 @@ struct ShadowNodeListWrapper : public jsi::HostObject {
inline static ShadowNode::Shared shadowNodeFromValue(
jsi::Runtime &runtime,
jsi::Value const &value) {
const jsi::Value &value) {
if (value.isNull()) {
return nullptr;
}
return value.getObject(runtime)
.getHostObject<ShadowNodeWrapper>(runtime)
->shadowNode;
if (CoreFeatures::useNativeState) {
return value.getObject(runtime).getNativeState<ShadowNode>(runtime);
} else {
return value.getObject(runtime)
.getHostObject<ShadowNodeWrapper>(runtime)
->shadowNode;
}
}
inline static jsi::Value valueFromShadowNode(
jsi::Runtime &runtime,
ShadowNode::Shared shadowNode) {
return jsi::Object::createFromHostObject(
runtime, std::make_shared<ShadowNodeWrapper>(std::move(shadowNode)));
if (CoreFeatures::useNativeState) {
jsi::Object obj(runtime);
// Need to const_cast since JSI only allows non-const pointees
obj.setNativeState(
runtime, std::const_pointer_cast<ShadowNode>(std::move(shadowNode)));
return obj;
} else {
return jsi::Object::createFromHostObject(
runtime, std::make_shared<ShadowNodeWrapper>(std::move(shadowNode)));
}
}
inline static ShadowNode::UnsharedListOfShared shadowNodeListFromValue(
jsi::Runtime &runtime,
jsi::Value const &value) {
return value.getObject(runtime)
.getHostObject<ShadowNodeListWrapper>(runtime)
->shadowNodeList;
const jsi::Value &value) {
if (CoreFeatures::useNativeState) {
return value.getObject(runtime)
.getNativeState<ShadowNodeListWrapper>(runtime)
->shadowNodeList;
} else {
return value.getObject(runtime)
.getHostObject<ShadowNodeListWrapper>(runtime)
->shadowNodeList;
}
}
inline static jsi::Value valueFromShadowNodeList(
jsi::Runtime &runtime,
ShadowNode::UnsharedListOfShared shadowNodeList) {
auto wrapper =
std::make_shared<ShadowNodeListWrapper>(std::move(shadowNodeList));
if (CoreFeatures::useNativeState) {
// Use the wrapper for NativeState too, otherwise we can't implement
// the marker interface. Could be simplifed to a simple struct wrapper.
jsi::Object obj(runtime);
obj.setNativeState(runtime, std::move(wrapper));
return obj;
} else {
return jsi::Object::createFromHostObject(runtime, std::move(wrapper));
}
}
inline static ShadowNode::UnsharedListOfShared shadowNodeListFromWeakList(
@@ -93,25 +128,14 @@ inline static ShadowNode::UnsharedListOfShared shadowNodeListFromWeakList(
inline static ShadowNode::UnsharedListOfWeak weakShadowNodeListFromValue(
jsi::Runtime &runtime,
jsi::Value const &value) {
auto shadowNodeList = value.getObject(runtime)
.getHostObject<ShadowNodeListWrapper>(runtime)
->shadowNodeList;
auto shadowNodeList = shadowNodeListFromValue(runtime, value);
auto weakShadowNodeList = std::make_shared<ShadowNode::ListOfWeak>();
for (auto const &shadowNode : *shadowNodeList) {
weakShadowNodeList->push_back(shadowNode);
}
return weakShadowNodeList;
}
inline static jsi::Value valueFromShadowNodeList(
jsi::Runtime &runtime,
const ShadowNode::UnsharedListOfShared &shadowNodeList) {
return jsi::Object::createFromHostObject(
runtime, std::make_unique<ShadowNodeListWrapper>(shadowNodeList));
}
inline static Tag tagFromValue(jsi::Value const &value) {
return (Tag)value.getNumber();
}