@@ -58,6 +58,28 @@ JavaTurboModule::~JavaTurboModule() {
5858
5959namespace {
6060
61+ constexpr auto kReactFeatureFlagsJavaDescriptor =
62+ " com/facebook/react/config/ReactFeatureFlags" ;
63+
64+ bool getFeatureFlagBoolValue (const char * name) {
65+ static const auto reactFeatureFlagsClass =
66+ facebook::jni::findClassStatic (kReactFeatureFlagsJavaDescriptor );
67+ const auto field = reactFeatureFlagsClass->getStaticField <jboolean>(name);
68+ return reactFeatureFlagsClass->getStaticFieldValue (field);
69+ }
70+
71+ bool traceTurboModulePromiseRejections () {
72+ static bool traceRejections =
73+ getFeatureFlagBoolValue (" traceTurboModulePromiseRejections" );
74+ return traceRejections;
75+ }
76+
77+ bool rejectTurboModulePromiseOnNativeError () {
78+ static bool rejectOnError =
79+ getFeatureFlagBoolValue (" rejectTurboModulePromiseOnNativeError" );
80+ return rejectOnError;
81+ }
82+
6183struct JNIArgs {
6284 JNIArgs (size_t count) : args_(count) {}
6385 std::vector<jvalue> args_;
@@ -396,7 +418,7 @@ jsi::Value createJSRuntimeError(
396418 */
397419jsi::JSError convertThrowableToJSError (
398420 jsi::Runtime& runtime,
399- jni::local_ref <jni::JThrowable> throwable) {
421+ jni::alias_ref <jni::JThrowable> throwable) {
400422 auto stackTrace = throwable->getStackTrace ();
401423
402424 jsi::Array stackElements (runtime, stackTrace->size ());
@@ -424,6 +446,22 @@ jsi::JSError convertThrowableToJSError(
424446 return {runtime, std::move (error)};
425447}
426448
449+ void rejectWithException (
450+ AsyncCallback<>& reject,
451+ std::exception_ptr exception,
452+ std::optional<std::string>& jsInvocationStack) {
453+ auto throwable = jni::getJavaExceptionForCppException (exception);
454+ reject.call ([jsInvocationStack, throwable = jni::make_global (throwable)](
455+ jsi::Runtime& rt, jsi::Function& jsFunction) {
456+ auto jsError = convertThrowableToJSError (rt, throwable);
457+ if (jsInvocationStack.has_value ()) {
458+ jsError.value ().asObject (rt).setProperty (
459+ rt, " stack" , jsInvocationStack.value ());
460+ }
461+ jsFunction.call (rt, jsError.value ());
462+ });
463+ }
464+
427465} // namespace
428466
429467jsi::Value JavaTurboModule::invokeJavaMethod (
@@ -783,6 +821,10 @@ jsi::Value JavaTurboModule::invokeJavaMethod(
783821 jsi::Function Promise =
784822 runtime.global ().getPropertyAsFunction (runtime, " Promise" );
785823
824+ // The callback is used for auto rejecting if error is caught from method
825+ // invocation
826+ std::optional<AsyncCallback<>> nativeRejectCallback;
827+
786828 // The promise constructor runs its arg immediately, so this is safe
787829 jobject javaPromise;
788830 jsi::Value jsPromise = Promise.callAsConstructor (
@@ -799,6 +841,13 @@ jsi::Value JavaTurboModule::invokeJavaMethod(
799841 throw jsi::JSError (runtime, " Incorrect number of arguments" );
800842 }
801843
844+ if (rejectTurboModulePromiseOnNativeError ()) {
845+ nativeRejectCallback = AsyncCallback (
846+ runtime,
847+ args[1 ].getObject (runtime).getFunction (runtime),
848+ jsInvoker_);
849+ }
850+
802851 auto resolve = createJavaCallback (
803852 runtime,
804853 args[0 ].getObject (runtime).getFunction (runtime),
@@ -817,14 +866,25 @@ jsi::Value JavaTurboModule::invokeJavaMethod(
817866 env->DeleteLocalRef (javaPromise);
818867 jargs[argCount].l = globalPromise;
819868
869+ // JS Stack at the time when the promise is created.
870+ std::optional<std::string> jsInvocationStack;
871+ if (traceTurboModulePromiseRejections ()) {
872+ jsInvocationStack = createJSRuntimeError (runtime, " " )
873+ .asObject (runtime)
874+ .getProperty (runtime, " stack" )
875+ .toString (runtime)
876+ .utf8 (runtime);
877+ }
878+
820879 const char * moduleName = name_.c_str ();
821880 const char * methodName = methodNameStr.c_str ();
822881 TMPL::asyncMethodCallArgConversionEnd (moduleName, methodName);
823-
824882 TMPL::asyncMethodCallDispatch (moduleName, methodName);
825883 nativeMethodCallInvoker_->invokeAsync (
826884 methodName,
827885 [jargs,
886+ rejectCallback = std::move (nativeRejectCallback),
887+ jsInvocationStack = std::move (jsInvocationStack),
828888 globalRefs,
829889 methodID,
830890 instance_ = jni::make_weak (instance_),
@@ -856,7 +916,14 @@ jsi::Value JavaTurboModule::invokeJavaMethod(
856916 FACEBOOK_JNI_THROW_PENDING_EXCEPTION ();
857917 } catch (...) {
858918 TMPL::asyncMethodCallExecutionFail (moduleName, methodName, id);
859- throw ;
919+ if (rejectTurboModulePromiseOnNativeError () && rejectCallback) {
920+ auto exception = std::current_exception ();
921+ rejectWithException (
922+ *rejectCallback, exception, jsInvocationStack);
923+ rejectCallback = std::nullopt ;
924+ } else {
925+ throw ;
926+ }
860927 }
861928
862929 for (auto globalRef : globalRefs) {
0 commit comments