HermesInstance::createJSRuntime integration (#52111)

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

Changelog: [Internal]

JSRuntime integration with executor on messagequeue.

Inching closer to full integration with the rest of RN.

Reviewed By: rshest

Differential Revision: D76752667

fbshipit-source-id: 0ef8fe0c615dc1eb45355f7502e01663772ebf13
This commit is contained in:
Andrew Datsenko
2025-06-20 07:08:28 -07:00
committed by Facebook GitHub Bot
parent 281f48daf4
commit 386a930afb
16 changed files with 422 additions and 51 deletions
@@ -14,6 +14,10 @@ set(CMAKE_VERBOSE_MAKEFILE on)
# This function will take care of forcefully including the jni_lib_merge.h header that takes
# care of redefining the JNI_OnLoad function to JNI_OnLoad_Weak.
function(target_merge_so target_name)
if(NOT ANDROID)
return()
endif()
target_compile_options(${target_name}
PRIVATE
-DORIGINAL_SONAME=\"lib${target_name}.so\"
@@ -13,7 +13,11 @@ add_library(react_debug OBJECT ${react_debug_SRC})
target_include_directories(react_debug PUBLIC ${REACT_COMMON_DIR})
target_link_libraries(react_debug log folly_runtime)
target_link_libraries(react_debug folly_runtime)
if(ANDROID)
target_link_libraries(react_debug log)
endif()
target_compile_reactnative_options(react_debug PRIVATE)
target_compile_options(react_debug PRIVATE -Wpedantic)
+29 -4
View File
@@ -25,7 +25,8 @@ val downloadsDir =
File("$buildDir/downloads")
}
val thirdParty = File("$buildDir/third-party")
val reactNativeRootDir = projectDir.parent
val reactNativeRootDir = projectDir.parentFile.parentFile
val reactAndroidBuildDir = File("$reactNativeRootDir/packages/react-native/ReactAndroid/build")
val createNativeDepsDirectories by
tasks.registering {
@@ -54,12 +55,36 @@ val prepareGflags by
outputDir.set(File(thirdParty, "gflags"))
}
// Tasks used by Fantom to download the Native 3p dependencies used.
val prepareNative3pDependencies by
var codegenSrcDir = File("$reactAndroidBuildDir/generated/source/codegen/jni/react")
var codegenOutDir = File("$buildDir/codegen/react")
val prepareRNCodegen by
tasks.registering(Copy::class) {
dependsOn(":packages:react-native:ReactAndroid:generateCodegenArtifactsFromSchema")
from(codegenSrcDir)
from("tester/codegen/react")
include(
"**/FBReactNativeSpecJSI.h", "**/FBReactNativeSpecJSI-generated.cpp", "CMakeLists.txt")
includeEmptyDirs = false
into(codegenOutDir)
}
val prepareHermesDependencies by
tasks.registering {
dependsOn(
prepareGflags,
":packages:react-native:ReactAndroid:hermes-engine:buildHermesLib",
":packages:react-native:ReactAndroid:hermes-engine:prepareHeadersForPrefab",
)
}
val prepareNative3pDependencies by
tasks.registering {
dependsOn(
prepareGflags,
":packages:react-native:ReactAndroid:prepareNative3pDependencies",
)
}
val prepareAllDependencies by
tasks.registering {
dependsOn(prepareRNCodegen, prepareHermesDependencies, prepareNative3pDependencies)
}
@@ -7,6 +7,5 @@
set -e
pushd ../..
./gradlew :packages:react-native:ReactAndroid:prepareNative3pDependencies
./gradlew :private:react-native-fantom:prepareNative3pDependencies
./gradlew :private:react-native-fantom:prepareAllDependencies
popd
@@ -7,64 +7,111 @@ cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
project(fantom_tester)
find_library(LIB_HERMES libhermes
HINTS ${REACT_ANDROID_DIR}/hermes-engine/build/hermes/API/hermes
REQUIRED)
# Ensure the library path is correct and the library exists
if(NOT LIB_HERMES)
message(FATAL_ERROR "libhermes not found at the specified path.")
endif()
# Check if the found library is a framework (macOS specific)
get_filename_component(LIB_EXT ${LIB_HERMES} EXT)
if(LIB_EXT STREQUAL ".framework")
# For frameworks, we need to use a different approach
add_library(hermes-engine::libhermes INTERFACE IMPORTED)
set_target_properties(hermes-engine::libhermes PROPERTIES
INTERFACE_LINK_LIBRARIES ${LIB_HERMES})
else()
# For regular libraries, use ALIAS as before
add_library(hermes-engine::libhermes ALIAS ${LIB_HERMES})
endif()
include_directories(${REACT_ANDROID_DIR}/hermes-engine/build/prefab-headers)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
# Convert input paths to CMake format (with forward slashes)
file(TO_CMAKE_PATH "${REACT_THIRD_PARTY_NDK_DIR}" REACT_THIRD_PARTY_NDK_DIR)
file(TO_CMAKE_PATH "${REACT_COMMON_DIR}" REACT_COMMON_DIR)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/")
function(add_react_third_party_ndk_subdir relative_path)
add_subdirectory(${REACT_THIRD_PARTY_NDK_DIR}/${relative_path} ${relative_path})
endfunction()
include(Deps)
function(add_third_party_subdir relative_path)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/third-party/${relative_path} ${relative_path})
endfunction()
function(add_react_common_subdir relative_path)
add_subdirectory(${REACT_COMMON_DIR}/${relative_path} ReactCommon/${relative_path})
endfunction()
function(add_fantom_third_party_subdir relative_path)
add_subdirectory(${FANTOM_THIRD_PARTY_DIR}/${relative_path} ${relative_path})
endfunction()
# Boost in NDK is not compatible with desktop build
add_third_party_subdir(boost)
# Third-party downloaded targets
add_react_third_party_ndk_subdir(glog)
# Boost in NDK is not compatible with desktop build
add_third_party_subdir(boost)
add_react_third_party_ndk_subdir(double-conversion)
add_react_third_party_ndk_subdir(fast_float)
add_react_third_party_ndk_subdir(fmt)
add_react_third_party_ndk_subdir(folly)
add_fantom_third_party_subdir(gflags)
# Common targets
add_react_common_subdir(yoga)
add_fantom_codegen_subdir(react)
#add_react_common_subdir(hermes/executor)
#add_react_common_subdir(hermes/inspector-modern)
#add_react_common_subdir(react/runtime/hermes)
add_react_common_subdir(callinvoker)
add_react_common_subdir(cxxreact)
add_react_common_subdir(jsi)
add_react_common_subdir(jsiexecutor)
add_react_common_subdir(jsinspector-modern)
add_react_common_subdir(jsinspector-modern/cdp)
add_react_common_subdir(jsinspector-modern/network)
add_react_common_subdir(jsinspector-modern/tracing)
add_react_common_subdir(jsitooling)
add_react_common_subdir(logger)
add_react_common_subdir(oscompat)
add_react_common_subdir(react/bridging)
add_react_common_subdir(react/debug)
add_react_common_subdir(react/featureflags)
add_react_common_subdir(react/performance/timeline)
add_react_common_subdir(react/timing)
add_react_common_subdir(reactperflogger)
add_react_common_subdir(runtimeexecutor)
add_react_common_subdir(yoga)
add_fantom_react_common_subdir(react/nativemodule/core)
add_fantom_react_common_subdir(react/utils)
add_fantom_react_common_subdir(react/runtime/hermes)
add_fantom_react_common_subdir(hermes/inspector-modern)
add_fantom_react_common_subdir(hermes/executor)
file(GLOB SOURCES "src/*.cpp" "src/*.h")
add_executable(fantom_tester ${SOURCES})
target_link_libraries(fantom_tester
PRIVATE
glog
gflags
jsi
${LIB_HERMES}
boost
double-conversion
fast_float
bridgelesshermes
callinvoker
folly_runtime
gflags
glog
hermes_executor_common
hermes_inspector_modern
jsi
jsinspector
jsinspector_cdp
jsinspector_network
jsinspector_tracing
jsireact
jsitooling
logger
oscompat
react_bridging
react_codegen_rncore
react_cxxreact
react_debug
react_featureflags
yogacore)
react_nativemodule_core
react_performance_timeline
react_timing
react_utils
reactperflogger
runtimeexecutor
yogacore
)
target_compile_options(fantom_tester
PRIVATE
@@ -0,0 +1,38 @@
# 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.
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
file(GLOB_RECURSE hermes_executor_SRC CONFIGURE_DEPENDS ${hermes_executor_DIR}/*.cpp)
add_library(
hermes_executor_common
OBJECT
${hermes_executor_SRC}
)
target_include_directories(hermes_executor_common PUBLIC ${hermes_executor_DIR}/.)
target_link_libraries(hermes_executor_common
hermes-engine::libhermes
hermes_inspector_modern
jsi
jsireact
)
target_compile_reactnative_options(hermes_executor_common PRIVATE)
if(${CMAKE_BUILD_TYPE} MATCHES Debug)
target_compile_options(
hermes_executor_common
PRIVATE
-DHERMES_ENABLE_DEBUGGER=1
)
else()
target_compile_options(
hermes_executor_common
PRIVATE
-DNDEBUG
)
endif()
@@ -0,0 +1,31 @@
# 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.
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
file(GLOB hermes_inspector_modern_SRC CONFIGURE_DEPENDS ${hermes_inspector_modern_DIR}/chrome/*.cpp)
add_library(hermes_inspector_modern
OBJECT
${hermes_inspector_modern_SRC})
target_compile_reactnative_options(hermes_inspector_modern PRIVATE)
if(${CMAKE_BUILD_TYPE} MATCHES Debug)
target_compile_options(
hermes_inspector_modern
PRIVATE
-DHERMES_ENABLE_DEBUGGER=1
)
endif()
target_include_directories(hermes_inspector_modern PUBLIC ${REACT_COMMON_DIR})
target_link_libraries(hermes_inspector_modern
hermes-engine::libhermes
jsi
jsinspector)
@@ -0,0 +1,33 @@
# 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.
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
file(GLOB react_nativemodule_core_SRC CONFIGURE_DEPENDS
${react_nativemodule_core_DIR}/ReactCommon/*.cpp)
add_library(react_nativemodule_core
OBJECT
${react_nativemodule_core_SRC})
target_include_directories(react_nativemodule_core
PUBLIC
${react_nativemodule_core_DIR}
)
target_link_libraries(react_nativemodule_core
folly_runtime
glog
jsi
callinvoker
react_bridging
react_debug
react_utils
react_featureflags
reactperflogger)
target_compile_reactnative_options(react_nativemodule_core PRIVATE)
target_compile_options(react_nativemodule_core PRIVATE -Wpedantic)
@@ -0,0 +1,35 @@
# 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.
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
file(GLOB_RECURSE bridgelesshermes_SRC CONFIGURE_DEPENDS ${react_runtime_hermes_DIR}/*.cpp)
add_library(
bridgelesshermes
OBJECT
${bridgelesshermes_SRC}
)
target_include_directories(bridgelesshermes PUBLIC ${react_runtime_hermes_DIR}/.)
target_link_libraries(bridgelesshermes
hermes-engine::libhermes
hermes_executor_common
hermes_inspector_modern
jsitooling
jsi
jsinspector
)
target_compile_reactnative_options(bridgelesshermes PRIVATE)
if(${CMAKE_BUILD_TYPE} MATCHES Debug)
target_compile_options(
bridgelesshermes
PRIVATE
-DHERMES_ENABLE_DEBUGGER=1
)
endif()
@@ -0,0 +1,24 @@
# 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.
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
file(GLOB react_utils_SRC CONFIGURE_DEPENDS ${react_utils_DIR}/*.cpp)
add_library(react_utils OBJECT ${react_utils_SRC})
target_include_directories(react_utils
PUBLIC
${REACT_COMMON_DIR}
)
target_link_libraries(react_utils
glog
jsireact
react_debug)
target_compile_reactnative_options(react_utils PRIVATE)
target_compile_options(react_utils PRIVATE -Wpedantic)
@@ -13,6 +13,7 @@ REACT_NATIVE_ROOT_DIR=$(readlink -f "$SCRIPT_DIR/../../../packages/react-native"
cmake -S "$SCRIPT_DIR" -B "$BUILD_DIR" \
-DREACT_ANDROID_DIR="${REACT_NATIVE_ROOT_DIR}/ReactAndroid" \
-DFANTOM_THIRD_PARTY_DIR="${SCRIPT_DIR}/../build/third-party" \
-DFANTOM_CODEGEN_DIR="${SCRIPT_DIR}/../build/codegen" \
-DREACT_THIRD_PARTY_NDK_DIR="${REACT_NATIVE_ROOT_DIR}/ReactAndroid/build/third-party-ndk" \
-DREACT_COMMON_DIR="${REACT_NATIVE_ROOT_DIR}/ReactCommon"
@@ -0,0 +1,37 @@
# 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.
# Convert input paths to CMake format (with forward slashes)
file(TO_CMAKE_PATH "${REACT_THIRD_PARTY_NDK_DIR}" REACT_THIRD_PARTY_NDK_DIR)
file(TO_CMAKE_PATH "${REACT_COMMON_DIR}" REACT_COMMON_DIR)
file(TO_CMAKE_PATH "${FANTOM_CODEGEN_DIR}" FANTOM_CODEGEN_DIR)
file(TO_CMAKE_PATH "${FANTOM_THIRD_PARTY_DIR}" FANTOM_THIRD_PARTY_DIR)
function(add_react_third_party_ndk_subdir relative_path)
add_subdirectory(${REACT_THIRD_PARTY_NDK_DIR}/${relative_path} ${relative_path})
endfunction()
function(add_third_party_subdir relative_path)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/third-party/${relative_path} ${relative_path})
endfunction()
function(add_react_common_subdir relative_path)
add_subdirectory(${REACT_COMMON_DIR}/${relative_path} ReactCommon/${relative_path})
endfunction()
function(add_fantom_codegen_subdir relative_path)
add_subdirectory(${FANTOM_CODEGEN_DIR}/${relative_path} ${relative_path})
endfunction()
function(add_fantom_react_common_subdir relative_path)
string(REPLACE "/" "_" var_name ${relative_path})
string(REPLACE "-" "_" var_name ${var_name})
set(${var_name}_DIR ${REACT_COMMON_DIR}/${relative_path})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ReactCommon/${relative_path} ReactCommon/${relative_path})
endfunction()
function(add_fantom_third_party_subdir relative_path)
add_subdirectory(${FANTOM_THIRD_PARTY_DIR}/${relative_path} ${relative_path})
endfunction()
@@ -0,0 +1,25 @@
# 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.
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
file(GLOB react_codegen_SRCS CONFIGURE_DEPENDS renderer/components/FBReactNativeSpec/*.cpp)
add_library(
react_codegen_rncore
OBJECT
${react_codegen_SRCS}
)
target_include_directories(react_codegen_rncore PUBLIC react/renderer/components/FBReactNativeSpec)
target_link_libraries(
react_codegen_rncore
jsi
react_nativemodule_core
)
target_compile_reactnative_options(react_codegen_rncore PRIVATE)
@@ -0,0 +1,40 @@
// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
#include "StubQueue.h"
namespace facebook::react {
void StubQueue::runOnQueue(std::function<void()>&& func) {
callbackQueue_.push(func);
}
void StubQueue::runOnQueueSync(std::function<void()>&& runnable) {
flush();
runnable();
}
void StubQueue::quitSynchronous() {
flush();
}
void StubQueue::flush() {
while (!callbackQueue_.empty()) {
tick();
}
}
bool StubQueue::hasPendingCallbacks() {
return !callbackQueue_.empty();
}
void StubQueue::tick() {
if (!callbackQueue_.empty()) {
auto callback = callbackQueue_.front();
callbackQueue_.pop();
if (callback) {
callback();
}
}
}
} // namespace facebook::react
@@ -0,0 +1,30 @@
// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
#pragma once
#include <cxxreact/MessageQueueThread.h>
#include <glog/logging.h>
#include <condition_variable>
#include <queue>
namespace facebook::react {
class StubQueue : public MessageQueueThread {
public:
void runOnQueue(std::function<void()>&& func) override;
void runOnQueueSync(std::function<void()>&& runnable) override;
void quitSynchronous() override;
bool hasPendingCallbacks();
void flush();
private:
void tick();
std::queue<std::function<void()>> callbackQueue_;
};
} // namespace facebook::react
+14 -16
View File
@@ -5,6 +5,8 @@
* LICENSE file in the root directory of this source tree.
*/
#include "StubQueue.h"
#include <folly/json.h>
#include <gflags/gflags.h>
#include <glog/logging.h>
@@ -12,6 +14,7 @@
#include <jsi/jsi.h>
#include <react/featureflags/ReactNativeFeatureFlags.h>
#include <react/featureflags/ReactNativeFeatureFlagsDynamicProvider.h>
#include <react/runtime/hermes/HermesInstance.h>
#include <yoga/YGEnums.h>
#include <yoga/YGValue.h>
@@ -51,28 +54,23 @@ static folly::dynamic setUpFeatureFlags() {
}
void createHermesInstance() {
auto gcConfig = ::hermes::vm::GCConfig::Builder()
// Default to 3GB
.withMaxHeapSize(3072 << 20)
.withName("RNBridgeless");
::hermes::vm::RuntimeConfig::Builder runtimeConfigBuilder =
::hermes::vm::RuntimeConfig::Builder()
.withGCConfig(gcConfig.build())
.withEnableSampleProfiling(true);
auto queue = std::make_shared<StubQueue>();
std::unique_ptr<JSRuntime> jsRuntime = HermesInstance::createJSRuntime(
nullptr,
queue,
/* allocInOldGenBeforeTTI */ false);
std::unique_ptr<HermesRuntime> hermesRuntime =
makeHermesRuntime(runtimeConfigBuilder.build());
hermesRuntime->evaluateJavaScript(
facebook::jsi::Runtime& runtime = jsRuntime->getRuntime();
runtime.evaluateJavaScript(
std::make_unique<StringBuffer>(
"var fantom = 'Hello, I am fantom_tester'"),
"script.js");
LOG(INFO) << "JS evaluated value: "
<< hermesRuntime->global()
.getProperty(*hermesRuntime, "fantom")
.getString(*hermesRuntime)
.utf8(*hermesRuntime);
<< runtime.global()
.getProperty(runtime, "fantom")
.getString(runtime)
.utf8(runtime);
}
int main(int argc, char* argv[]) {