diff --git a/ReactCommon/bridge/JSCExecutor.cpp b/ReactCommon/bridge/JSCExecutor.cpp index b708b0dfe..f2ee46cb6 100644 --- a/ReactCommon/bridge/JSCExecutor.cpp +++ b/ReactCommon/bridge/JSCExecutor.cpp @@ -628,14 +628,19 @@ JSValueRef JSCExecutor::nativeCallSyncHook( return JSValueMakeUndefined(ctx); } - MethodCallResult result = executor->m_bridge->callSerializableNativeHook( - moduleId, - methodId, - argsJson); - if (result.isUndefined) { + try { + MethodCallResult result = executor->m_bridge->callSerializableNativeHook( + moduleId, + methodId, + argsJson); + if (result.isUndefined) { + return JSValueMakeUndefined(ctx); + } + return Value::fromJSON(ctx, String(folly::toJson(result.result).c_str())); + } catch (...) { + *exception = translatePendingCppExceptionToJSError(ctx, "nativeCallSyncHook"); return JSValueMakeUndefined(ctx); } - return Value::fromJSON(ctx, String(folly::toJson(result.result).c_str())); } static JSValueRef nativeInjectHMRUpdate( diff --git a/ReactCommon/bridge/JSCHelpers.cpp b/ReactCommon/bridge/JSCHelpers.cpp index f768bedaf..1028e1ba0 100644 --- a/ReactCommon/bridge/JSCHelpers.cpp +++ b/ReactCommon/bridge/JSCHelpers.cpp @@ -52,4 +52,32 @@ JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef return result; } +JSValueRef makeJSError(JSContextRef ctx, const char *error) { + JSValueRef nestedException = nullptr; + JSValueRef args[] = { Value(ctx, String(error)) }; + JSObjectRef errorObj = JSObjectMakeError(ctx, 1, args, &nestedException); + if (nestedException != nullptr) { + return std::move(args[0]); + } + return errorObj; +} + +JSValueRef translatePendingCppExceptionToJSError(JSContextRef ctx, const char *exceptionLocation) { + std::ostringstream msg; + try { + throw; + } catch (const std::bad_alloc& ex) { + throw; // We probably shouldn't try to handle this in JS + } catch (const std::exception& ex) { + msg << "C++ Exception in '" << exceptionLocation << "': " << ex.what(); + return makeJSError(ctx, msg.str().c_str()); + } catch (const char* ex) { + msg << "C++ Exception (thrown as a char*) in '" << exceptionLocation << "': " << ex; + return makeJSError(ctx, msg.str().c_str()); + } catch (...) { + msg << "Unknown C++ Exception in '" << exceptionLocation << "'"; + return makeJSError(ctx, msg.str().c_str()); + } +} + } } diff --git a/ReactCommon/bridge/JSCHelpers.h b/ReactCommon/bridge/JSCHelpers.h index 976e4fdc8..b14fa0e30 100644 --- a/ReactCommon/bridge/JSCHelpers.h +++ b/ReactCommon/bridge/JSCHelpers.h @@ -9,6 +9,8 @@ #include #include +#include "Value.h" + namespace facebook { namespace react { @@ -43,4 +45,8 @@ JSValueRef evaluateScript( JSStringRef script, JSStringRef sourceURL); +JSValueRef makeJSError(JSContextRef ctx, const char *error); + +JSValueRef translatePendingCppExceptionToJSError(JSContextRef ctx, const char *exceptionLocation); + } } diff --git a/ReactCommon/bridge/Value.cpp b/ReactCommon/bridge/Value.cpp index 84e6e7b89..a8ccf6614 100644 --- a/ReactCommon/bridge/Value.cpp +++ b/ReactCommon/bridge/Value.cpp @@ -13,6 +13,12 @@ Value::Value(JSContextRef context, JSValueRef value) : { } +Value::Value(JSContextRef context, JSStringRef str) : + m_context(context), + m_value(JSValueMakeString(context, str)) +{ +} + Value::Value(Value&& other) : m_context(other.m_context), m_value(other.m_value) diff --git a/ReactCommon/bridge/Value.h b/ReactCommon/bridge/Value.h index 08bf8dc04..e78be3807 100644 --- a/ReactCommon/bridge/Value.h +++ b/ReactCommon/bridge/Value.h @@ -171,6 +171,7 @@ private: class Value : public noncopyable { public: Value(JSContextRef context, JSValueRef value); + Value(JSContextRef context, JSStringRef value); Value(Value&&); operator JSValueRef() const {