From cafd63440a4ad317b381a4e58acd754acd984b0b Mon Sep 17 00:00:00 2001 From: Alexander Blom Date: Thu, 12 May 2016 14:32:37 -0700 Subject: [PATCH] Add helper for installing method as hook Reviewed By: astreet Differential Revision: D3292457 fbshipit-source-id: 590637dbf868097214ca9cb7b9a6543dc48a898f --- ReactCommon/bridge/JSCExecutor.cpp | 47 +++++++++++++++++++++++++++++- ReactCommon/bridge/JSCExecutor.h | 5 ++-- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/ReactCommon/bridge/JSCExecutor.cpp b/ReactCommon/bridge/JSCExecutor.cpp index 6aa899a2d..1108f0bf6 100644 --- a/ReactCommon/bridge/JSCExecutor.cpp +++ b/ReactCommon/bridge/JSCExecutor.cpp @@ -47,6 +47,39 @@ using fbsystrace::FbSystraceSection; namespace facebook { namespace react { +namespace { + +template +inline JSObjectCallAsFunctionCallback exceptionWrapMethod() { + struct funcWrapper { + static JSValueRef call( + JSContextRef ctx, + JSObjectRef function, + JSObjectRef thisObject, + size_t argumentCount, + const JSValueRef arguments[], + JSValueRef *exception) { + try { + auto globalObj = JSContextGetGlobalObject(ctx); + auto executor = static_cast(JSObjectGetPrivate(globalObj)); + return (executor->*method)(argumentCount, arguments); + } catch (...) { + try { + auto functionName = Object(ctx, function).getProperty("name").toString().str(); + *exception = translatePendingCppExceptionToJSError(ctx, functionName.c_str()); + } catch (...) { + *exception = makeJSError(ctx, "Failed to get function name while handling exception"); + } + return JSValueMakeUndefined(ctx); + } + } + }; + + return &funcWrapper::call; +} + +} + static std::unordered_map s_globalContextRefToJSCExecutor; static JSValueRef nativeInjectHMRUpdate( @@ -148,7 +181,14 @@ void JSCExecutor::initOnJSVMThread() { #if defined(WITH_FB_JSC_TUNING) configureJSCForAndroid(m_jscConfig); #endif - m_context = JSGlobalContextCreateInGroup(nullptr, nullptr); + + auto globalClass = JSClassCreate(&kJSClassDefinitionEmpty); + m_context = JSGlobalContextCreateInGroup(nullptr, globalClass); + JSClassRelease(globalClass); + + // Add a pointer to ourselves so we can retrieve it later in our hooks + JSObjectSetPrivate(JSContextGetGlobalObject(m_context), this); + s_globalContextRefToJSCExecutor[m_context] = this; installGlobalFunction(m_context, "nativeFlushQueueImmediate", nativeFlushQueueImmediate); installGlobalFunction(m_context, "nativeStartWorker", nativeStartWorker); @@ -422,6 +462,11 @@ Object JSCExecutor::createMessageObject(const std::string& msgJson) { } // Native JS hooks +template +void JSCExecutor::installNativeHook(const char* name) { + installGlobalFunction(m_context, name, exceptionWrapMethod()); +} + JSValueRef JSCExecutor::nativePostMessage( JSContextRef ctx, JSObjectRef function, diff --git a/ReactCommon/bridge/JSCExecutor.h b/ReactCommon/bridge/JSCExecutor.h index 27baff8a0..255c8096a 100644 --- a/ReactCommon/bridge/JSCExecutor.h +++ b/ReactCommon/bridge/JSCExecutor.h @@ -77,8 +77,6 @@ public: virtual void handleMemoryPressureCritical() override; virtual void destroy() override; - void installNativeHook(const char *name, JSObjectCallAsFunctionCallback callback); - private: JSGlobalContextRef m_context; Bridge *m_bridge; @@ -117,6 +115,9 @@ private: void terminateOwnedWebWorker(int worker); Object createMessageObject(const std::string& msgData); + template< JSValueRef (JSCExecutor::*method)(size_t, const JSValueRef[])> + void installNativeHook(const char* name); + static JSValueRef nativeStartWorker( JSContextRef ctx, JSObjectRef function,