diff --git a/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.cpp b/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.cpp index 9b474c1e1391..d70a4463761e 100644 --- a/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.cpp +++ b/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.cpp @@ -90,17 +90,23 @@ parseErrorStack(const jsi::JSError& error, bool isFatal, bool isHermes) { JsErrorHandler::JsErrorHandler( JsErrorHandler::JsErrorHandlingFunc jsErrorHandlingFunc) - : _jsErrorHandlingFunc(std::move(jsErrorHandlingFunc)){ + : _jsErrorHandlingFunc(std::move(jsErrorHandlingFunc)), + _hasHandledFatalError(false){ }; JsErrorHandler::~JsErrorHandler() {} -void JsErrorHandler::handleJsError(const jsi::JSError& error, bool isFatal) { +void JsErrorHandler::handleFatalError(const jsi::JSError& error) { // TODO: Current error parsing works and is stable. Can investigate using // REGEX_HERMES to get additional Hermes data, though it requires JS setup. - ParsedError parsedError = parseErrorStack(error, isFatal, false); + _hasHandledFatalError = true; + ParsedError parsedError = parseErrorStack(error, true, false); _jsErrorHandlingFunc(parsedError); } +bool JsErrorHandler::hasHandledFatalError() { + return _hasHandledFatalError; +} + } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.h b/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.h index 69f714d48536..53a03367989f 100644 --- a/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.h +++ b/packages/react-native/ReactCommon/jserrorhandler/JsErrorHandler.h @@ -32,10 +32,12 @@ class JsErrorHandler { explicit JsErrorHandler(JsErrorHandlingFunc jsErrorHandlingFunc); ~JsErrorHandler(); - void handleJsError(const jsi::JSError& error, bool isFatal); + void handleFatalError(const jsi::JSError& error); + bool hasHandledFatalError(); private: JsErrorHandlingFunc _jsErrorHandlingFunc; + bool _hasHandledFatalError; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/ErrorUtils.h b/packages/react-native/ReactCommon/react/renderer/runtimescheduler/ErrorUtils.h deleted file mode 100644 index c15de49aac6b..000000000000 --- a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/ErrorUtils.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * 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. - */ - -#pragma once - -#include - -namespace facebook::react { - -inline static void handleFatalError( - jsi::Runtime& runtime, - const jsi::JSError& error) { - auto reportFatalError = "reportFatalError"; - auto errorUtils = runtime.global().getProperty(runtime, "ErrorUtils"); - if (errorUtils.isUndefined() || !errorUtils.isObject() || - !errorUtils.getObject(runtime).hasProperty(runtime, reportFatalError)) { - // ErrorUtils was not set up. This probably means the bundle didn't - // load properly. - throw jsi::JSError( - runtime, - "ErrorUtils is not set up properly. Something probably went wrong trying to load the JS bundle. Trying to report error " + - error.getMessage(), - error.getStack()); - } - - auto func = errorUtils.asObject(runtime).getPropertyAsFunction( - runtime, reportFatalError); - - func.call(runtime, error.value()); -} - -} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler.cpp b/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler.cpp index ffad447dc366..804e7cf10be9 100644 --- a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler.cpp +++ b/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler.cpp @@ -13,7 +13,6 @@ #include #include #include -#include "ErrorUtils.h" namespace facebook::react { diff --git a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Legacy.cpp b/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Legacy.cpp index 2d13b9b8e645..e16188137413 100644 --- a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Legacy.cpp +++ b/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Legacy.cpp @@ -8,10 +8,10 @@ #include "RuntimeScheduler_Legacy.h" #include "SchedulerPriorityUtils.h" +#include #include #include #include -#include "ErrorUtils.h" namespace facebook::react { @@ -139,7 +139,7 @@ void RuntimeScheduler_Legacy::callExpiredTasks(jsi::Runtime& runtime) { executeTask(runtime, topPriorityTask, didUserCallbackTimeout); } } catch (jsi::JSError& error) { - handleFatalError(runtime, error); + handleJSError(runtime, error, true); } currentPriority_ = previousPriority; @@ -191,7 +191,7 @@ void RuntimeScheduler_Legacy::startWorkLoop(jsi::Runtime& runtime) { executeTask(runtime, topPriorityTask, didUserCallbackTimeout); } } catch (jsi::JSError& error) { - handleFatalError(runtime, error); + handleJSError(runtime, error, true); } currentPriority_ = previousPriority; diff --git a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Legacy.h b/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Legacy.h index d5f673d39b66..502c0def5ef0 100644 --- a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Legacy.h +++ b/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Legacy.h @@ -22,8 +22,7 @@ class RuntimeScheduler_Legacy final : public RuntimeSchedulerBase { public: explicit RuntimeScheduler_Legacy( RuntimeExecutor runtimeExecutor, - std::function now = - RuntimeSchedulerClock::now); + std::function now); /* * Not copyable. diff --git a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Modern.cpp b/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Modern.cpp index c07e2f8c2e9c..8cc6a6deebb0 100644 --- a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Modern.cpp +++ b/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Modern.cpp @@ -14,7 +14,6 @@ #include #include #include -#include "ErrorUtils.h" namespace facebook::react { @@ -211,7 +210,7 @@ void RuntimeScheduler_Modern::startWorkLoop( executeTask(runtime, topPriorityTask, currentTime); } } catch (jsi::JSError& error) { - handleFatalError(runtime, error); + handleJSError(runtime, error, true); } currentPriority_ = previousPriority; diff --git a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Modern.h b/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Modern.h index 372d8c5da19a..f730509928ba 100644 --- a/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Modern.h +++ b/packages/react-native/ReactCommon/react/renderer/runtimescheduler/RuntimeScheduler_Modern.h @@ -23,8 +23,7 @@ class RuntimeScheduler_Modern final : public RuntimeSchedulerBase { public: explicit RuntimeScheduler_Modern( RuntimeExecutor runtimeExecutor, - std::function now = - RuntimeSchedulerClock::now); + std::function now); /* * Not copyable. diff --git a/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp b/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp index 3ed3b1342151..440e9f5de576 100644 --- a/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp +++ b/packages/react-native/ReactCommon/react/runtime/ReactInstance.cpp @@ -36,25 +36,25 @@ ReactInstance::ReactInstance( : runtime_(std::move(runtime)), jsMessageQueueThread_(jsMessageQueueThread), timerManager_(std::move(timerManager)), - jsErrorHandler_(std::move(jsErrorHandlingFunc)), - hasFatalJsError_(std::make_shared(false)), + jsErrorHandler_( + std::make_shared(std::move(jsErrorHandlingFunc))), parentInspectorTarget_(parentInspectorTarget) { RuntimeExecutor runtimeExecutor = [weakRuntime = std::weak_ptr(runtime_), weakTimerManager = std::weak_ptr(timerManager_), weakJsMessageQueueThread = std::weak_ptr(jsMessageQueueThread_), - weakHasFatalJsError = std::weak_ptr( - hasFatalJsError_)](auto callback) { - if (std::shared_ptr sharedHasFatalJsError = - weakHasFatalJsError.lock()) { - if (*sharedHasFatalJsError) { - LOG(INFO) - << "Calling into JS using runtimeExecutor but hasFatalJsError_ is true"; - return; - } + weakJsErrorHander = std::weak_ptr( + jsErrorHandler_)](auto callback) { + auto jsErrorHandler = weakJsErrorHander.lock(); + if (weakRuntime.expired() || !jsErrorHandler) { + return; } - if (weakRuntime.expired()) { + + if (jsErrorHandler->hasHandledFatalError()) { + LOG(INFO) + << "RuntimeExecutor: Detected fatal js error. Dropping work on non-js thread." + << std::endl; return; } @@ -163,6 +163,8 @@ RuntimeExecutor ReactInstance::getBufferedRuntimeExecutor() noexcept { }; } +// TODO(T184010230): Should the RuntimeScheduler returned from this method be +// buffered? std::shared_ptr ReactInstance::getRuntimeScheduler() noexcept { return runtimeScheduler_; @@ -220,9 +222,7 @@ void ReactInstance::loadScript( strongBufferedRuntimeExecuter->flush(); } } catch (jsi::JSError& error) { - // Handle uncaught JS errors during loading JS bundle - *hasFatalJsError_ = true; - this->jsErrorHandler_.handleJsError(error, true); + jsErrorHandler_->handleFatalError(error); } }); } diff --git a/packages/react-native/ReactCommon/react/runtime/ReactInstance.h b/packages/react-native/ReactCommon/react/runtime/ReactInstance.h index c785147f72bc..d44b539bd7eb 100644 --- a/packages/react-native/ReactCommon/react/runtime/ReactInstance.h +++ b/packages/react-native/ReactCommon/react/runtime/ReactInstance.h @@ -80,10 +80,7 @@ class ReactInstance final : private jsinspector_modern::InstanceTargetDelegate { std::shared_ptr timerManager_; std::unordered_map> modules_; std::shared_ptr runtimeScheduler_; - JsErrorHandler jsErrorHandler_; - - // Whether there are errors caught during bundle loading - std::shared_ptr hasFatalJsError_; + std::shared_ptr jsErrorHandler_; jsinspector_modern::InstanceTarget* inspectorTarget_{nullptr}; jsinspector_modern::RuntimeTarget* runtimeInspectorTarget_{nullptr};