From f804af27c237e30eb22d496783046f23e7156477 Mon Sep 17 00:00:00 2001 From: Kathy Gray Date: Wed, 29 Mar 2017 02:32:35 -0700 Subject: [PATCH] Make bridge load module lazy Reviewed By: javache Differential Revision: D4762575 fbshipit-source-id: fc3be786640b8c42664d7b357ab0fe197006b28b --- .../facebook/react/bridge/BaseJavaModule.java | 55 +++++++++++++------ .../src/main/jni/xreact/jni/MethodInvoker.cpp | 8 +-- .../src/main/jni/xreact/jni/MethodInvoker.h | 2 +- 3 files changed, 44 insertions(+), 21 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java index f911938b4..41a0d65ee 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/BaseJavaModule.java @@ -168,31 +168,45 @@ public abstract class BaseJavaModule implements NativeModule { public class JavaMethod implements NativeMethod { - private Method mMethod; - private final ArgumentExtractor[] mArgumentExtractors; - private final String mSignature; - private final Object[] mArguments; + private final Method mMethod; + private final Class[] mParameterTypes; + private final int mParamLength; + private boolean mArgumentsProcessed = false; + private @Nullable ArgumentExtractor[] mArgumentExtractors; + private @Nullable String mSignature; + private @Nullable Object[] mArguments; private String mType = METHOD_TYPE_ASYNC; - private final int mJSArgumentsNeeded; - private final String mTraceName; + private @Nullable int mJSArgumentsNeeded; + private String mTraceName; public JavaMethod(Method method, boolean isSync) { mMethod = method; mMethod.setAccessible(true); + Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "callGetParameterTypes"); + mParameterTypes = mMethod.getParameterTypes(); + Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE); + mParamLength = mParameterTypes.length; if (isSync) { mType = METHOD_TYPE_SYNC; + } else if (mParamLength > 0 && (mParameterTypes[mParamLength - 1] == Promise.class)) { + mType = METHOD_TYPE_PROMISE; } - - // TODO: create these lazily - Class[] parameterTypes = method.getParameterTypes(); - mArgumentExtractors = buildArgumentExtractors(parameterTypes); - mSignature = buildSignature(mMethod, parameterTypes, isSync); - // Since native methods are invoked from a message queue executed on a single thread, it is - // save to allocate only one arguments object per method that can be reused across calls - mArguments = new Object[parameterTypes.length]; - mJSArgumentsNeeded = calculateJSArgumentsNeeded(); mTraceName = BaseJavaModule.this.getName() + "." + mMethod.getName(); + + } + + private void processArguments() { + if (mArgumentsProcessed) { + return; + } + mArgumentsProcessed = true; + mArgumentExtractors = buildArgumentExtractors(mParameterTypes); + mSignature = buildSignature(mMethod, mParameterTypes, (mType.equals(METHOD_TYPE_SYNC))); + // Since native methods are invoked from a message queue executed on a single thread, it is + // safe to allocate only one arguments object per method that can be reused across calls + mArguments = new Object[mParameterTypes.length]; + mJSArgumentsNeeded = calculateJSArgumentsNeeded(); } public Method getMethod() { @@ -200,7 +214,10 @@ public abstract class BaseJavaModule implements NativeModule { } public String getSignature() { - return mSignature; + if (!mArgumentsProcessed) { + processArguments(); + } + return assertNotNull(mSignature); } private String buildSignature(Method method, Class[] paramTypes, boolean isSync) { @@ -312,6 +329,12 @@ public abstract class BaseJavaModule implements NativeModule { .arg("method", mTraceName) .flush(); try { + if (!mArgumentsProcessed) { + processArguments(); + } + if (mArguments == null || mArgumentExtractors == null) { + throw new Error("processArguments failed"); + } if (mJSArgumentsNeeded != parameters.size()) { throw new NativeArgumentsParseException( BaseJavaModule.this.getName() + "." + mMethod.getName() + " got " + diff --git a/ReactAndroid/src/main/jni/xreact/jni/MethodInvoker.cpp b/ReactAndroid/src/main/jni/xreact/jni/MethodInvoker.cpp index e93567899..e5790acea 100644 --- a/ReactAndroid/src/main/jni/xreact/jni/MethodInvoker.cpp +++ b/ReactAndroid/src/main/jni/xreact/jni/MethodInvoker.cpp @@ -155,12 +155,12 @@ std::size_t countJsArgs(const std::string& signature) { MethodInvoker::MethodInvoker(jni::alias_ref method, std::string signature, std::string traceName, bool isSync) : method_(method->getMethodID()), - jsArgCount_(countJsArgs(signature) - 2), - signature_(std::move(signature)), + signature_(signature), + jsArgCount_(countJsArgs(signature) -2), traceName_(std::move(traceName)), isSync_(isSync) { - CHECK(signature_.at(1) == '.') << "Improper module method signature"; - CHECK(isSync || signature_.at(0) == 'v') << "Non-sync hooks cannot have a non-void return type"; + CHECK(signature_.at(1) == '.') << "Improper module method signature"; + CHECK(isSync_ || signature_.at(0) == 'v') << "Non-sync hooks cannot have a non-void return type"; } MethodCallResult MethodInvoker::invoke(std::weak_ptr& instance, jni::alias_ref module, ExecutorToken token, const folly::dynamic& params) { diff --git a/ReactAndroid/src/main/jni/xreact/jni/MethodInvoker.h b/ReactAndroid/src/main/jni/xreact/jni/MethodInvoker.h index 170273e28..75dc91ebd 100644 --- a/ReactAndroid/src/main/jni/xreact/jni/MethodInvoker.h +++ b/ReactAndroid/src/main/jni/xreact/jni/MethodInvoker.h @@ -38,8 +38,8 @@ public: } private: jmethodID method_; - std::size_t jsArgCount_; std::string signature_; + std::size_t jsArgCount_; std::string traceName_; bool isSync_; };