Skip to content

Commit

Permalink
Construct RawValue directly from jsi::Value (#48047)
Browse files Browse the repository at this point in the history
Summary:
### Motivation:

We are looking for a way to access the "raw" jsi value in our fabric view components, so that we can pass complex types like `HostObjects` or `jsi::Object` with `NativeState` attached to our components directly.
Currently the props are converted from `jsi::Object` to `folly::dynamic`, which prevents us from accessing these values directly.

### Changes

This PR is a implementation of the proposal discussed here:

- #44966 (comment)

These changes extend `RawValue` so that it can be directly constructed from `RawValue(Runtime*, jsi::Value&)` (not just from `folly::dynamic`).

`RawValue`s are created by the `RawPropParser.cpp`. By default it will use the `RawValue(folly::dynamic)` constructor, but we added a feature flag called `useRawPropsJsiValue`, which will sue the JSI constructor.
This enables to test this feature at runtime incrementally.

This change might also be tested on a component basis, by setting a flag in the component descriptor to enable JSI prop parsing for the RawPropParser, as outlined in this PR:

- hannojg#2

## Changelog:

<!-- Help reviewers and the release process by writing your own changelog entry.

Pick one each for the category and type tags:

[ANDROID|GENERAL|IOS|INTERNAL] [BREAKING|ADDED|CHANGED|DEPRECATED|REMOVED|FIXED|SECURITY] - Message

For more details, see:
https://reactnative.dev/contributing/changelogs-in-pull-requests
-->

[General] [Added] - Add `useRawPropsJsiValue` feature flag to represent props internally as `jsi::Value`s instead of converting them to `folly::dynamic`

[General] [Added] - Added `RawValue(Runtime*, jsi::Value&)` constructor to make a `RawValue` from a `jsi::Value`.

Pull Request resolved: #48047

Test Plan: Enable the `useRawPropsJsiValue` feature flag and test the rn-tester app on android and iOS. Make sure you get no new errors / warnings in the native console.

Reviewed By: NickGerleman

Differential Revision: D66877093

Pulled By: javache

fbshipit-source-id: 7342e5f86d2492ad63a9ccf5508f04e7eb252def
  • Loading branch information
hannojg authored and facebook-github-bot committed Dec 11, 2024
1 parent 7d0338c commit 03d2186
Show file tree
Hide file tree
Showing 24 changed files with 468 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<124d445f029ae3e23652f355cbd28765>>
* @generated SignedSource<<609b55df15ac72da5a3c14dde18a4814>>
*/

/**
Expand Down Expand Up @@ -286,6 +286,12 @@ public object ReactNativeFeatureFlags {
@JvmStatic
public fun useOptimizedEventBatchingOnAndroid(): Boolean = accessor.useOptimizedEventBatchingOnAndroid()

/**
* Instead of using folly::dynamic as internal representation in RawProps and RawValue, use jsi::Value
*/
@JvmStatic
public fun useRawPropsJsiValue(): Boolean = accessor.useRawPropsJsiValue()

/**
* When enabled, cloning shadow nodes within react native will update the reference held by the current JS fiber tree.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<08711c50ae5a1ffabcc561bbfe05896e>>
* @generated SignedSource<<0be0090ba864cd4fe0bd2c22e419923c>>
*/

/**
Expand Down Expand Up @@ -63,6 +63,7 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso
private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null
private var useOptimisedViewPreallocationOnAndroidCache: Boolean? = null
private var useOptimizedEventBatchingOnAndroidCache: Boolean? = null
private var useRawPropsJsiValueCache: Boolean? = null
private var useRuntimeShadowNodeReferenceUpdateCache: Boolean? = null
private var useTurboModuleInteropCache: Boolean? = null
private var useTurboModulesCache: Boolean? = null
Expand Down Expand Up @@ -454,6 +455,15 @@ public class ReactNativeFeatureFlagsCxxAccessor : ReactNativeFeatureFlagsAccesso
return cached
}

override fun useRawPropsJsiValue(): Boolean {
var cached = useRawPropsJsiValueCache
if (cached == null) {
cached = ReactNativeFeatureFlagsCxxInterop.useRawPropsJsiValue()
useRawPropsJsiValueCache = cached
}
return cached
}

override fun useRuntimeShadowNodeReferenceUpdate(): Boolean {
var cached = useRuntimeShadowNodeReferenceUpdateCache
if (cached == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<1079b38c8b5c0c16e658fa1a4ff0b619>>
* @generated SignedSource<<b92feb26341cd20ea526620ffef11352>>
*/

/**
Expand Down Expand Up @@ -114,6 +114,8 @@ public object ReactNativeFeatureFlagsCxxInterop {

@DoNotStrip @JvmStatic public external fun useOptimizedEventBatchingOnAndroid(): Boolean

@DoNotStrip @JvmStatic public external fun useRawPropsJsiValue(): Boolean

@DoNotStrip @JvmStatic public external fun useRuntimeShadowNodeReferenceUpdate(): Boolean

@DoNotStrip @JvmStatic public external fun useTurboModuleInterop(): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<cb4ab9f84d7333655f4e436e551825b0>>
* @generated SignedSource<<04ac11c085b2880db40d44e431db42f2>>
*/

/**
Expand Down Expand Up @@ -109,6 +109,8 @@ public open class ReactNativeFeatureFlagsDefaults : ReactNativeFeatureFlagsProvi

override fun useOptimizedEventBatchingOnAndroid(): Boolean = false

override fun useRawPropsJsiValue(): Boolean = false

override fun useRuntimeShadowNodeReferenceUpdate(): Boolean = true

override fun useTurboModuleInterop(): Boolean = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<afbce922bb8e83bfd3f57179046c5049>>
* @generated SignedSource<<0f7a852c7c44b4074bf618252fecb2f6>>
*/

/**
Expand Down Expand Up @@ -67,6 +67,7 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces
private var useNativeViewConfigsInBridgelessModeCache: Boolean? = null
private var useOptimisedViewPreallocationOnAndroidCache: Boolean? = null
private var useOptimizedEventBatchingOnAndroidCache: Boolean? = null
private var useRawPropsJsiValueCache: Boolean? = null
private var useRuntimeShadowNodeReferenceUpdateCache: Boolean? = null
private var useTurboModuleInteropCache: Boolean? = null
private var useTurboModulesCache: Boolean? = null
Expand Down Expand Up @@ -501,6 +502,16 @@ public class ReactNativeFeatureFlagsLocalAccessor : ReactNativeFeatureFlagsAcces
return cached
}

override fun useRawPropsJsiValue(): Boolean {
var cached = useRawPropsJsiValueCache
if (cached == null) {
cached = currentProvider.useRawPropsJsiValue()
accessedFeatureFlags.add("useRawPropsJsiValue")
useRawPropsJsiValueCache = cached
}
return cached
}

override fun useRuntimeShadowNodeReferenceUpdate(): Boolean {
var cached = useRuntimeShadowNodeReferenceUpdateCache
if (cached == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<fa21a158fae72045c1b63590ba54d640>>
* @generated SignedSource<<190f00e954f343b076cfe5ef75ee4539>>
*/

/**
Expand Down Expand Up @@ -109,6 +109,8 @@ public interface ReactNativeFeatureFlagsProvider {

@DoNotStrip public fun useOptimizedEventBatchingOnAndroid(): Boolean

@DoNotStrip public fun useRawPropsJsiValue(): Boolean

@DoNotStrip public fun useRuntimeShadowNodeReferenceUpdate(): Boolean

@DoNotStrip public fun useTurboModuleInterop(): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<0f603eaf15eb01cb23a2485d5a525275>>
* @generated SignedSource<<8a9673f2f81917b3466fb955d5641720>>
*/

/**
Expand Down Expand Up @@ -297,6 +297,12 @@ class ReactNativeFeatureFlagsProviderHolder
return method(javaProvider_);
}

bool useRawPropsJsiValue() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("useRawPropsJsiValue");
return method(javaProvider_);
}

bool useRuntimeShadowNodeReferenceUpdate() override {
static const auto method =
getReactNativeFeatureFlagsProviderJavaClass()->getMethod<jboolean()>("useRuntimeShadowNodeReferenceUpdate");
Expand Down Expand Up @@ -534,6 +540,11 @@ bool JReactNativeFeatureFlagsCxxInterop::useOptimizedEventBatchingOnAndroid(
return ReactNativeFeatureFlags::useOptimizedEventBatchingOnAndroid();
}

bool JReactNativeFeatureFlagsCxxInterop::useRawPropsJsiValue(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::useRawPropsJsiValue();
}

bool JReactNativeFeatureFlagsCxxInterop::useRuntimeShadowNodeReferenceUpdate(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop> /*unused*/) {
return ReactNativeFeatureFlags::useRuntimeShadowNodeReferenceUpdate();
Expand Down Expand Up @@ -709,6 +720,9 @@ void JReactNativeFeatureFlagsCxxInterop::registerNatives() {
makeNativeMethod(
"useOptimizedEventBatchingOnAndroid",
JReactNativeFeatureFlagsCxxInterop::useOptimizedEventBatchingOnAndroid),
makeNativeMethod(
"useRawPropsJsiValue",
JReactNativeFeatureFlagsCxxInterop::useRawPropsJsiValue),
makeNativeMethod(
"useRuntimeShadowNodeReferenceUpdate",
JReactNativeFeatureFlagsCxxInterop::useRuntimeShadowNodeReferenceUpdate),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<ca05791857a963b64d1b75dccd0d5033>>
* @generated SignedSource<<cf7e9685a1739386706934b8c249ed03>>
*/

/**
Expand Down Expand Up @@ -159,6 +159,9 @@ class JReactNativeFeatureFlagsCxxInterop
static bool useOptimizedEventBatchingOnAndroid(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);

static bool useRawPropsJsiValue(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);

static bool useRuntimeShadowNodeReferenceUpdate(
facebook::jni::alias_ref<JReactNativeFeatureFlagsCxxInterop>);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<88103b9e29549d8bc3971f254a3529b6>>
* @generated SignedSource<<debbf54b108cfb6727b6408d99e7d056>>
*/

/**
Expand Down Expand Up @@ -198,6 +198,10 @@ bool ReactNativeFeatureFlags::useOptimizedEventBatchingOnAndroid() {
return getAccessor().useOptimizedEventBatchingOnAndroid();
}

bool ReactNativeFeatureFlags::useRawPropsJsiValue() {
return getAccessor().useRawPropsJsiValue();
}

bool ReactNativeFeatureFlags::useRuntimeShadowNodeReferenceUpdate() {
return getAccessor().useRuntimeShadowNodeReferenceUpdate();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<9657126869d2fb6edb9074d71c0989ac>>
* @generated SignedSource<<e4e20a183ab2272062286bd0503530ac>>
*/

/**
Expand Down Expand Up @@ -254,6 +254,11 @@ class ReactNativeFeatureFlags {
*/
RN_EXPORT static bool useOptimizedEventBatchingOnAndroid();

/**
* Instead of using folly::dynamic as internal representation in RawProps and RawValue, use jsi::Value
*/
RN_EXPORT static bool useRawPropsJsiValue();

/**
* When enabled, cloning shadow nodes within react native will update the reference held by the current JS fiber tree.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<01cf526d22b18b9f43f715a84db8422f>>
* @generated SignedSource<<1cd2586e0118ba4a828fd99fdda97187>>
*/

/**
Expand Down Expand Up @@ -803,6 +803,24 @@ bool ReactNativeFeatureFlagsAccessor::useOptimizedEventBatchingOnAndroid() {
return flagValue.value();
}

bool ReactNativeFeatureFlagsAccessor::useRawPropsJsiValue() {
auto flagValue = useRawPropsJsiValue_.load();

if (!flagValue.has_value()) {
// This block is not exclusive but it is not necessary.
// If multiple threads try to initialize the feature flag, we would only
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.

markFlagAsAccessed(43, "useRawPropsJsiValue");

flagValue = currentProvider_->useRawPropsJsiValue();
useRawPropsJsiValue_ = flagValue;
}

return flagValue.value();
}

bool ReactNativeFeatureFlagsAccessor::useRuntimeShadowNodeReferenceUpdate() {
auto flagValue = useRuntimeShadowNodeReferenceUpdate_.load();

Expand All @@ -812,7 +830,7 @@ bool ReactNativeFeatureFlagsAccessor::useRuntimeShadowNodeReferenceUpdate() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.

markFlagAsAccessed(43, "useRuntimeShadowNodeReferenceUpdate");
markFlagAsAccessed(44, "useRuntimeShadowNodeReferenceUpdate");

flagValue = currentProvider_->useRuntimeShadowNodeReferenceUpdate();
useRuntimeShadowNodeReferenceUpdate_ = flagValue;
Expand All @@ -830,7 +848,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModuleInterop() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.

markFlagAsAccessed(44, "useTurboModuleInterop");
markFlagAsAccessed(45, "useTurboModuleInterop");

flagValue = currentProvider_->useTurboModuleInterop();
useTurboModuleInterop_ = flagValue;
Expand All @@ -848,7 +866,7 @@ bool ReactNativeFeatureFlagsAccessor::useTurboModules() {
// be accessing the provider multiple times but the end state of this
// instance and the returned flag value would be the same.

markFlagAsAccessed(45, "useTurboModules");
markFlagAsAccessed(46, "useTurboModules");

flagValue = currentProvider_->useTurboModules();
useTurboModules_ = flagValue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<485a7e88ec81935a6c45b1ce5de0cbf2>>
* @generated SignedSource<<6be37ce8729f305b92161c7263366c7b>>
*/

/**
Expand Down Expand Up @@ -75,6 +75,7 @@ class ReactNativeFeatureFlagsAccessor {
bool useNativeViewConfigsInBridgelessMode();
bool useOptimisedViewPreallocationOnAndroid();
bool useOptimizedEventBatchingOnAndroid();
bool useRawPropsJsiValue();
bool useRuntimeShadowNodeReferenceUpdate();
bool useTurboModuleInterop();
bool useTurboModules();
Expand All @@ -89,7 +90,7 @@ class ReactNativeFeatureFlagsAccessor {
std::unique_ptr<ReactNativeFeatureFlagsProvider> currentProvider_;
bool wasOverridden_;

std::array<std::atomic<const char*>, 46> accessedFeatureFlags_;
std::array<std::atomic<const char*>, 47> accessedFeatureFlags_;

std::atomic<std::optional<bool>> commonTestFlag_;
std::atomic<std::optional<bool>> completeReactInstanceCreationOnBgThreadOnAndroid_;
Expand Down Expand Up @@ -134,6 +135,7 @@ class ReactNativeFeatureFlagsAccessor {
std::atomic<std::optional<bool>> useNativeViewConfigsInBridgelessMode_;
std::atomic<std::optional<bool>> useOptimisedViewPreallocationOnAndroid_;
std::atomic<std::optional<bool>> useOptimizedEventBatchingOnAndroid_;
std::atomic<std::optional<bool>> useRawPropsJsiValue_;
std::atomic<std::optional<bool>> useRuntimeShadowNodeReferenceUpdate_;
std::atomic<std::optional<bool>> useTurboModuleInterop_;
std::atomic<std::optional<bool>> useTurboModules_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<3a027e8944a9d20b04f16f99e8097c65>>
* @generated SignedSource<<93d8b298331642e4dfc7aa0ebf0978c2>>
*/

/**
Expand Down Expand Up @@ -199,6 +199,10 @@ class ReactNativeFeatureFlagsDefaults : public ReactNativeFeatureFlagsProvider {
return false;
}

bool useRawPropsJsiValue() override {
return false;
}

bool useRuntimeShadowNodeReferenceUpdate() override {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @generated SignedSource<<5b91c17d725f3a6a140e9fd4a9849707>>
* @generated SignedSource<<d4b9353fbaff57c4cb7431ba2b1c4074>>
*/

/**
Expand Down Expand Up @@ -432,6 +432,15 @@ class ReactNativeFeatureFlagsDynamicProvider : public ReactNativeFeatureFlagsDef
return ReactNativeFeatureFlagsDefaults::useOptimizedEventBatchingOnAndroid();
}

bool useRawPropsJsiValue() override {
auto value = values_["useRawPropsJsiValue"];
if (!value.isNull()) {
return value.getBool();
}

return ReactNativeFeatureFlagsDefaults::useRawPropsJsiValue();
}

bool useRuntimeShadowNodeReferenceUpdate() override {
auto value = values_["useRuntimeShadowNodeReferenceUpdate"];
if (!value.isNull()) {
Expand Down
Loading

0 comments on commit 03d2186

Please sign in to comment.