Revert "Cleanup all the JSC 1st party code. (#51949)"

This reverts commit 8174d02811.
This commit is contained in:
Riccardo Cipolleschi
2025-06-17 10:40:33 +02:00
parent 7f25e6cbf4
commit d04bb7daac
18 changed files with 404 additions and 13 deletions
@@ -126,8 +126,6 @@ internal object NdkConfiguratorUtils {
): Pair<List<String>, List<String>> {
val excludes = mutableListOf<String>()
val includes = mutableListOf<String>()
// note: libjsctooling.so is kept here for backward compatibility.
when {
hermesEnabled -> {
excludes.add("**/libjsc.so")
@@ -1230,7 +1230,10 @@ static NSString *RCTRecursiveAccessibilityLabel(UIView *view)
return label;
}
return RCTRecursiveAccessibilityLabel(self.currentContainerView);
if (self.isAccessibilityElement) {
return RCTRecursiveAccessibilityLabel(self.currentContainerView);
}
return nil;
}
- (NSString *)accessibilityLabelForCoopting
+4 -1
View File
@@ -240,7 +240,10 @@ RCT_NOT_IMPLEMENTED(-(instancetype)initWithCoder : unused)
if (label) {
return label;
}
return RCTRecursiveAccessibilityLabel(self);
if (self.isAccessibilityElement) {
return RCTRecursiveAccessibilityLabel(self);
}
return nil;
}
- (NSArray<UIAccessibilityCustomAction *> *)accessibilityCustomActions
@@ -2448,6 +2448,19 @@ public abstract interface class com/facebook/react/interfaces/fabric/ReactSurfac
public abstract fun stop ()Lcom/facebook/react/interfaces/TaskInterface;
}
public final class com/facebook/react/jscexecutor/JSCExecutor : com/facebook/react/bridge/JavaScriptExecutor {
public fun getName ()Ljava/lang/String;
public static final fun loadLibrary ()V
}
public final class com/facebook/react/jscexecutor/JSCExecutorFactory : com/facebook/react/bridge/JavaScriptExecutorFactory {
public fun <init> (Ljava/lang/String;Ljava/lang/String;)V
public fun create ()Lcom/facebook/react/bridge/JavaScriptExecutor;
public fun startSamplingProfiler ()V
public fun stopSamplingProfiler (Ljava/lang/String;)V
public fun toString ()Ljava/lang/String;
}
public final class com/facebook/react/jstasks/HeadlessJsTaskConfig {
public fun <init> (Lcom/facebook/react/jstasks/HeadlessJsTaskConfig;)V
public fun <init> (Ljava/lang/String;Lcom/facebook/react/bridge/WritableMap;)V
@@ -3122,6 +3135,10 @@ public class com/facebook/react/runtime/CoreReactPackage$$ReactModuleInfoProvide
public fun getReactModuleInfos ()Ljava/util/Map;
}
public final class com/facebook/react/runtime/JSCInstance : com/facebook/react/runtime/JSRuntimeFactory {
public fun <init> ()V
}
public abstract class com/facebook/react/runtime/JSRuntimeFactory {
public fun <init> (Lcom/facebook/jni/HybridData;)V
}
@@ -3236,6 +3253,10 @@ public final class com/facebook/react/soloader/OpenSourceMergedSoMapping : com/f
public final fun libhermes_executor_so ()I
public final fun libhermesinstancejni_so ()I
public final fun libhermestooling_so ()I
public final fun libjscexecutor_so ()I
public final fun libjscinstance_so ()I
public final fun libjscruntime_so ()I
public final fun libjsctooling_so ()I
public final fun libjsijniprofiler_so ()I
public final fun libjsinspector_so ()I
public final fun libmapbufferjni_so ()I
@@ -87,6 +87,8 @@ val preparePrefab by
// hermes_executor
// This prefab targets is used by Expo & Reanimated
Pair("../ReactCommon/hermes/inspector-modern/", "hermes/inspector-modern/"),
// jscexecutor
Pair("../ReactCommon/jsc/", "jsc/"),
// fabricjni
Pair("src/main/jni/react/fabric", "react/fabric/"),
// glog
@@ -234,6 +236,10 @@ val preparePrefab by
"hermestooling",
// hermes_executor
Pair("../ReactCommon/hermes/inspector-modern/", "hermes/inspector-modern/")),
PrefabPreprocessingEntry(
"jsctooling",
// jsc
Pair("../ReactCommon/jsc/", "jsc/")),
))
outputDir.set(prefabHeadersDir)
}
@@ -528,6 +534,7 @@ android {
"reactnative",
"jsi",
"hermestooling",
"jsctooling",
)
}
}
@@ -576,9 +583,10 @@ android {
resources.excludes.add("META-INF/LICENSE")
// We intentionally don't want to bundle any JS Runtime inside the Android AAR
// we produce. The reason behind this is that we want to allow users to pick the
// JS engine by specifying a dependency on either `hermes-engine` or other engines
// JS engine by specifying a dependency on either `hermes-engine` or `android-jsc`
// that will include the necessary .so files to load.
jniLibs.excludes.add("**/libhermes.so")
jniLibs.excludes.add("**/libjsc.so")
}
buildFeatures {
@@ -591,6 +599,7 @@ android {
create("jsi") { headers = File(prefabHeadersDir, "jsi").absolutePath }
create("reactnative") { headers = File(prefabHeadersDir, "reactnative").absolutePath }
create("hermestooling") { headers = File(prefabHeadersDir, "hermestooling").absolutePath }
create("jsctooling") { headers = File(prefabHeadersDir, "jsctooling").absolutePath }
}
publishing {
@@ -635,9 +644,10 @@ dependencies {
compileOnly(libs.javax.annotation.api)
api(libs.javax.inject)
// It's up to the consumer to decide if hermes or other engines should be included or not.
// Therefore hermes-engine is a compileOnly dependencies.
// It's up to the consumer to decide if hermes/jsc should be included or not.
// Therefore hermes-engine and jsc are compileOnly dependencies.
compileOnly(project(":packages:react-native:ReactAndroid:hermes-engine"))
compileOnly(libs.jsc.android)
testImplementation(libs.junit)
testImplementation(libs.assertj)
@@ -17,6 +17,7 @@ import com.facebook.react.common.annotations.UnstableReactNativeAPI
import com.facebook.react.common.build.ReactBuildConfig
import com.facebook.react.fabric.ComponentFactory
import com.facebook.react.runtime.BindingsInstaller
import com.facebook.react.runtime.JSCInstance
import com.facebook.react.runtime.JSRuntimeFactory
import com.facebook.react.runtime.ReactHostImpl
import com.facebook.react.runtime.cxxreactpackage.CxxReactPackage
@@ -207,7 +208,7 @@ public object DefaultReactHost {
jsMainModulePath,
jsBundleAssetPath,
jsBundleFilePath,
HermesInstance(),
if (isHermesEnabled) HermesInstance() else JSCInstance(),
useDevSupport,
cxxReactPackageProviders,
exceptionHandler,
@@ -263,7 +264,7 @@ public object DefaultReactHost {
jsMainModulePath,
jsBundleAssetPath,
jsBundleFilePath,
HermesInstance(),
if (isHermesEnabled) HermesInstance() else JSCInstance(),
useDevSupport,
cxxReactPackageProviders,
)
@@ -17,6 +17,7 @@ import com.facebook.react.bridge.UIManagerProvider
import com.facebook.react.common.annotations.UnstableReactNativeAPI
import com.facebook.react.fabric.ComponentFactory
import com.facebook.react.fabric.FabricUIManagerProviderImpl
import com.facebook.react.runtime.JSCInstance
import com.facebook.react.runtime.JSRuntimeFactory
import com.facebook.react.runtime.hermes.HermesInstance
import com.facebook.react.uimanager.ViewManagerRegistry
@@ -92,9 +93,6 @@ protected constructor(
* If true, the app will load the Hermes engine, and fail if not found. If false, the app will
* load the JSC engine, and fail if not found.
*/
@Deprecated(
"Setting isHermesEnabled inside `ReactNativeHost` is deprecated and this field will be ignored. If this field is set to true, you can safely remove it. If this field is set to false, please follow the setup on https://github.com/react-native-community/javascriptcore to continue using JSC",
ReplaceWith(""))
protected open val isHermesEnabled: Boolean
get() = true
@@ -108,7 +106,8 @@ protected constructor(
context: Context,
jsRuntimeFactory: JSRuntimeFactory? = null
): ReactHost {
val concreteJSRuntimeFactory = jsRuntimeFactory ?: HermesInstance()
val concreteJSRuntimeFactory =
jsRuntimeFactory ?: if (isHermesEnabled) HermesInstance() else JSCInstance()
return DefaultReactHost.getDefaultReactHost(
context,
packages,
@@ -0,0 +1,41 @@
/*
* 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.
*/
package com.facebook.react.jscexecutor
import com.facebook.jni.HybridData
import com.facebook.proguard.annotations.DoNotStrip
import com.facebook.react.bridge.JavaScriptExecutor
import com.facebook.react.bridge.ReadableNativeMap
import com.facebook.react.common.annotations.internal.LegacyArchitecture
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
import com.facebook.soloader.SoLoader
@DoNotStrip
@LegacyArchitecture
public class JSCExecutor internal constructor(jscConfig: ReadableNativeMap) :
JavaScriptExecutor(initHybrid(jscConfig)) {
override fun getName(): String {
return "JSCExecutor"
}
internal companion object {
init {
loadLibrary()
LegacyArchitectureLogger.assertLegacyArchitecture("JSCExecutor")
}
@JvmStatic
@Throws(UnsatisfiedLinkError::class)
fun loadLibrary() {
SoLoader.loadLibrary("jscexecutor")
}
@JvmStatic private external fun initHybrid(jscConfig: ReadableNativeMap): HybridData
}
}
@@ -0,0 +1,46 @@
/*
* 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.
*/
package com.facebook.react.jscexecutor
import com.facebook.react.bridge.JavaScriptExecutor
import com.facebook.react.bridge.JavaScriptExecutorFactory
import com.facebook.react.bridge.WritableNativeMap
import com.facebook.react.common.annotations.internal.LegacyArchitecture
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogLevel
import com.facebook.react.common.annotations.internal.LegacyArchitectureLogger
@LegacyArchitecture(logLevel = LegacyArchitectureLogLevel.ERROR)
public class JSCExecutorFactory(private val appName: String, private val deviceName: String) :
JavaScriptExecutorFactory {
init {
LegacyArchitectureLogger.assertLegacyArchitecture(
"JSCExecutorFactory", LegacyArchitectureLogLevel.ERROR)
}
@Throws(Exception::class)
override fun create(): JavaScriptExecutor {
val jscConfig =
WritableNativeMap().apply {
putString("OwnerIdentity", "ReactNative")
putString("AppIdentity", appName)
putString("DeviceIdentity", deviceName)
}
return JSCExecutor(jscConfig)
}
override fun startSamplingProfiler() {
throw UnsupportedOperationException("Starting sampling profiler not supported on ${toString()}")
}
override fun stopSamplingProfiler(filename: String) {
throw UnsupportedOperationException("Stopping sampling profiler not supported on ${toString()}")
}
override fun toString(): String = "JSIExecutor+JSCRuntime"
}
@@ -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.
*/
package com.facebook.react.runtime
import com.facebook.jni.HybridData
import com.facebook.jni.annotations.DoNotStrip
import com.facebook.jni.annotations.DoNotStripAny
import com.facebook.soloader.SoLoader
@DoNotStripAny
public class JSCInstance : JSRuntimeFactory(initHybrid()) {
private companion object {
init {
SoLoader.loadLibrary("jscinstance")
}
@DoNotStrip @JvmStatic private external fun initHybrid(): HybridData
}
}
@@ -42,6 +42,11 @@ public object OpenSourceMergedSoMapping : ExternalSoMapping {
"jsijniprofiler" -> {
"hermestooling"
}
"jscexecutor",
"jscruntime",
"jscinstance" -> {
"jsctooling"
}
else -> input
}
@@ -51,6 +56,10 @@ public object OpenSourceMergedSoMapping : ExternalSoMapping {
"hermes_executor" -> libhermes_executor_so()
"hermesinstancejni" -> libhermesinstancejni_so()
"hermestooling" -> libhermestooling_so()
"jscexecutor" -> libjscexecutor_so()
"jscinstance" -> libjscinstance_so()
"jscruntime" -> libjscruntime_so()
"jsctooling" -> libjsctooling_so()
"jsijniprofiler" -> libjsijniprofiler_so()
"jsinspector" -> libjsinspector_so()
"mapbufferjni" -> libmapbufferjni_so()
@@ -76,6 +85,14 @@ public object OpenSourceMergedSoMapping : ExternalSoMapping {
public external fun libhermestooling_so(): Int
public external fun libjscexecutor_so(): Int
public external fun libjscinstance_so(): Int
public external fun libjscruntime_so(): Int
public external fun libjsctooling_so(): Int
public external fun libjsijniprofiler_so(): Int
public external fun libjsinspector_so(): Int
@@ -51,7 +51,9 @@ endfunction()
# Third-party prefabs
find_package(hermes-engine REQUIRED CONFIG)
find_package(fbjni REQUIRED CONFIG)
find_package(jsc-android REQUIRED CONFIG)
add_library(fbjni ALIAS fbjni::fbjni)
add_library(jsc ALIAS jsc-android::jsc)
# Third-party downloaded targets
add_react_third_party_ndk_subdir(glog)
@@ -69,6 +71,7 @@ add_react_common_subdir(logger)
add_react_common_subdir(jsiexecutor)
add_react_common_subdir(jsitooling)
add_react_common_subdir(cxxreact)
add_react_common_subdir(jsc)
add_react_common_subdir(jsi)
add_react_common_subdir(callinvoker)
add_react_common_subdir(oscompat)
@@ -137,6 +140,8 @@ add_react_android_subdir(src/main/jni/first-party/yogajni)
add_react_android_subdir(src/main/jni/first-party/jni-lib-merge)
add_react_android_subdir(src/main/jni/react/jni)
add_react_android_subdir(src/main/jni/react/reactperflogger)
add_react_android_subdir(src/main/jni/react/jscexecutor)
add_react_android_subdir(src/main/jni/react/jsctooling)
add_react_android_subdir(src/main/jni/react/turbomodule)
add_react_android_subdir(src/main/jni/react/uimanager)
add_react_android_subdir(src/main/jni/react/mapbuffer)
@@ -150,6 +155,7 @@ add_react_android_subdir(src/main/jni/react/hermes/instrumentation/)
add_react_android_subdir(src/main/jni/react/runtime/cxxreactpackage)
add_react_android_subdir(src/main/jni/react/runtime/jni)
add_react_android_subdir(src/main/jni/react/runtime/hermes/jni)
add_react_android_subdir(src/main/jni/react/runtime/jsc/jni)
add_react_android_subdir(src/main/jni/react/devsupport)
# SoMerging Utils
@@ -12,6 +12,7 @@ include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
# hermestooling is a shared library where we merge all the hermes* related libraries.
#
# It acts as an 'umbrella' library and gets removed by RNGP (see `configureJsEnginePackagingOptions`)
# Please note that this library gets removed for users that opt to use JSC as their JS engine.
add_library(hermestooling
SHARED
@@ -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.
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
add_compile_options(-fvisibility=hidden -fexceptions -frtti)
include(${REACT_ANDROID_DIR}/src/main/jni/first-party/jni-lib-merge/SoMerging-utils.cmake)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
file(GLOB jscexecutor_SRC CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp)
add_library(jscexecutor OBJECT ${jscexecutor_SRC})
target_include_directories(jscexecutor PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_merge_so(jscexecutor)
# Patch from Expo: https://github.com/expo/react-native/blob/02714ab44d1e206fa80e81aef618e61017cccdc1/ReactAndroid/src/main/java/com/facebook/react/jscexecutor/CMakeLists.txt#L16-L25
# Explicitly link libgcc.a to prevent undefined `_Unwind_Resume` symbol and crash from throwing c++ exceptions even someone tries to catch the exceptions.
# according to https://android.googlesource.com/platform/ndk/+/master/docs/BuildSystemMaintainers.md#unwinding,
# we should put the unwinder between static libs and shared libs.
#
# TODO(ncor): we don't need this patch anymore after upgrading to ndk r23
if(ANDROID_NDK_REVISION VERSION_LESS "23.0.0")
set(LIB_UNWIND gcc)
else()
set(LIB_UNWIND unwind)
endif()
target_link_libraries(jscexecutor
${LIB_UNWIND}
jscruntime
jsi
reactnative)
target_compile_reactnative_options(jscexecutor PRIVATE)
@@ -0,0 +1,74 @@
/*
* 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 <fbjni/fbjni.h>
#include <jsc/JSCRuntime.h>
#include <jsireact/JSIExecutor.h>
#include <react/jni/JReactMarker.h>
#include <react/jni/JSLogging.h>
#include <react/jni/JavaScriptExecutorHolder.h>
#include <react/jni/ReadableNativeMap.h>
#include <memory>
namespace facebook::react {
namespace {
class JSCExecutorFactory : public JSExecutorFactory {
public:
std::unique_ptr<JSExecutor> createJSExecutor(
std::shared_ptr<ExecutorDelegate> delegate,
std::shared_ptr<MessageQueueThread> jsQueue) override {
return std::make_unique<JSIExecutor>(
jsc::makeJSCRuntime(),
delegate,
JSIExecutor::defaultTimeoutInvoker,
[](jsi::Runtime& runtime) {
react::bindNativeLogger(runtime, &reactAndroidLoggingHook);
});
}
};
} // namespace
// This is not like JSCJavaScriptExecutor, which calls JSC directly. This uses
// JSIExecutor with JSCRuntime.
class JSCExecutorHolder
: public jni::HybridClass<JSCExecutorHolder, JavaScriptExecutorHolder> {
public:
static constexpr auto kJavaDescriptor =
"Lcom/facebook/react/jscexecutor/JSCExecutor;";
static jni::local_ref<jhybriddata> initHybrid(
jni::alias_ref<jclass>,
ReadableNativeMap*) {
// This is kind of a weird place for stuff, but there's no other
// good place for initialization which is specific to JSC on
// Android.
JReactMarker::setLogPerfMarkerIfNeeded();
// TODO mhorowitz T28461666 fill in some missing nice to have glue
return makeCxxInstance(std::make_unique<JSCExecutorFactory>());
}
static void registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", JSCExecutorHolder::initHybrid),
});
}
private:
friend HybridBase;
using HybridBase::HybridBase;
};
} // namespace facebook::react
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
return facebook::jni::initialize(
vm, [] { facebook::react::JSCExecutorHolder::registerNatives(); });
}
@@ -0,0 +1,36 @@
# 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_ANDROID_DIR}/src/main/jni/first-party/jni-lib-merge/SoMerging-utils.cmake)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
# jsctooling is a shared library where we merge all the jsc* related libraries.
#
# It acts as an 'umbrella' library and gets removed by RNGP (see `configureJsEnginePackagingOptions`)
# Please note that this library gets removed for users that opt to use Hermes as their JS engine.
add_library(jsctooling
SHARED
$<TARGET_OBJECTS:jni_lib_merge_glue>
$<TARGET_OBJECTS:jscinstance>
$<TARGET_OBJECTS:jscruntime>
$<TARGET_OBJECTS:jscexecutor>
)
target_merge_so(jsctooling)
target_link_libraries(jsctooling
PUBLIC
reactnative
jsc
)
target_include_directories(jsctooling
PUBLIC
$<TARGET_PROPERTY:jscexecutor,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:jscruntime,INTERFACE_INCLUDE_DIRECTORIES>
$<TARGET_PROPERTY:jscinstance,INTERFACE_INCLUDE_DIRECTORIES>
)
target_compile_reactnative_options(jsctooling PRIVATE)
@@ -0,0 +1,26 @@
# 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_ANDROID_DIR}/src/main/jni/first-party/jni-lib-merge/SoMerging-utils.cmake)
include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake)
file(GLOB jscinstance_SRC CONFIGURE_DEPENDS "*.cpp")
add_library(jscinstance OBJECT ${jscinstance_SRC})
target_include_directories(jscinstance PUBLIC .)
target_merge_so(jscinstance)
target_link_libraries(jscinstance
jscruntime
fbjni
reactnative
)
target_compile_reactnative_options(jscinstance PRIVATE)
target_compile_options(jscinstance PRIVATE -fvisibility=hidden)
@@ -0,0 +1,48 @@
/*
* 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 <cxxreact/MessageQueueThread.h>
#include <fbjni/fbjni.h>
#include <jsc/JSCRuntime.h>
#include <jsi/jsi.h>
#include <react/jni/ReadableNativeMap.h>
#include <react/runtime/JSRuntimeFactory.h>
#include <react/runtime/jni/JJSRuntimeFactory.h>
namespace facebook::react {
class JSCInstance : public jni::HybridClass<JSCInstance, JJSRuntimeFactory> {
public:
static constexpr auto kJavaDescriptor =
"Lcom/facebook/react/runtime/JSCInstance;";
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject>) {
return makeCxxInstance();
}
static void registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", JSCInstance::initHybrid),
});
}
std::unique_ptr<JSRuntime> createJSRuntime(
std::shared_ptr<MessageQueueThread> msgQueueThread) noexcept {
return std::make_unique<JSIRuntimeHolder>(jsc::makeJSCRuntime());
}
private:
friend HybridBase;
using HybridBase::HybridBase;
};
} // namespace facebook::react
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved) {
return facebook::jni::initialize(
vm, [] { facebook::react::JSCInstance::registerNatives(); });
}