Drop support for webworkers

Reviewed By: AaaChiuuu

Differential Revision: D4916449

fbshipit-source-id: a447233d3b7cfee98db2ce00f1c0505d513e2429
This commit is contained in:
Pieter De Baets 2017-04-25 05:29:45 -07:00 committed by Facebook Github Bot
parent a20882f62e
commit 34bc6bd2ae
64 changed files with 266 additions and 1639 deletions

View File

@ -121,10 +121,6 @@ struct RCTInstanceCallback : public InstanceCallback {
}
void incrementPendingJSCalls() override {}
void decrementPendingJSCalls() override {}
ExecutorToken createExecutorToken() override {
return ExecutorToken(std::make_shared<PlatformExecutorToken>());
}
void onExecutorStopped(ExecutorToken) override {}
};
@implementation RCTCxxBridge
@ -289,7 +285,7 @@ struct RCTInstanceCallback : public InstanceCallback {
[self.delegate respondsToSelector:@selector(shouldBridgeUseCustomJSC:)] &&
[self.delegate shouldBridgeUseCustomJSC:self];
// The arg is a cache dir. It's not used with standard JSC.
executorFactory.reset(new JSCExecutorFactory("", folly::dynamic::object
executorFactory.reset(new JSCExecutorFactory(folly::dynamic::object
("UseCustomJSC", (bool)useCustomJSC)
#if RCT_PROFILE
("StartSamplingProfilerOnInit", (bool)self.devSettings.startSamplingProfilerOnLaunch)
@ -1000,8 +996,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
RCTProfileEndFlowEvent();
if (self->_reactInstance) {
self->_reactInstance->callJSFunction(self->_reactInstance->getMainExecutorToken(),
[module UTF8String], [method UTF8String],
self->_reactInstance->callJSFunction([module UTF8String], [method UTF8String],
[RCTConvert folly_dynamic:args ?: @[]]);
if (completion) {
@ -1033,7 +1028,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
if (self->_reactInstance)
self->_reactInstance->callJSCallback(
self->_reactInstance->getMainExecutorToken(), [cbID unsignedLongLongValue],
[cbID unsignedLongLongValue],
[RCTConvert folly_dynamic:args ?: @[]]);
}];
}
@ -1046,8 +1041,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithBundleURL:(__unused NSURL *)bundleUR
RCTAssertJSThread();
if (_reactInstance)
_reactInstance->callJSFunction(_reactInstance->getMainExecutorToken(),
"JSTimersExecution", "callTimers",
_reactInstance->callJSFunction("JSTimersExecution", "callTimers",
folly::dynamic::array(folly::dynamic::array([timer doubleValue])));
}

View File

@ -20,10 +20,8 @@ class RCTNativeModule : public NativeModule {
std::string getName() override;
std::vector<MethodDescriptor> getMethods() override;
folly::dynamic getConstants() override;
bool supportsWebWorkers() override;
void invoke(ExecutorToken token, unsigned int methodId, folly::dynamic &&params) override;
MethodCallResult callSerializableNativeHook(ExecutorToken token, unsigned int reactMethodId,
folly::dynamic &&params) override;
void invoke(unsigned int methodId, folly::dynamic &&params) override;
MethodCallResult callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic &&params) override;
private:
__weak RCTBridge *m_bridge;

View File

@ -50,11 +50,7 @@ folly::dynamic RCTNativeModule::getConstants() {
return ret;
}
bool RCTNativeModule::supportsWebWorkers() {
return false;
}
void RCTNativeModule::invoke(ExecutorToken token, unsigned int methodId, folly::dynamic &&params) {
void RCTNativeModule::invoke(unsigned int methodId, folly::dynamic &&params) {
// The BatchedBridge version of this buckets all the callbacks by thread, and
// queues one block on each. This is much simpler; we'll see how it goes and
// iterate.
@ -103,8 +99,7 @@ void RCTNativeModule::invoke(ExecutorToken token, unsigned int methodId, folly::
}
}
MethodCallResult RCTNativeModule::callSerializableNativeHook(
ExecutorToken token, unsigned int reactMethodId, folly::dynamic &&params) {
MethodCallResult RCTNativeModule::callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic &&params) {
RCTFatal(RCTErrorWithMessage(@"callSerializableNativeHook is not yet supported on iOS"));
return folly::none;
}

View File

@ -168,7 +168,6 @@
13F887771E29726200C3C7A1 /* JSCPerfStats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0BC1E03699D0018521A /* JSCPerfStats.cpp */; };
13F887781E29726200C3C7A1 /* JSCSamplingProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0BE1E03699D0018521A /* JSCSamplingProfiler.cpp */; };
13F887791E29726200C3C7A1 /* JSCUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0C21E03699D0018521A /* JSCUtils.cpp */; };
13F8877A1E29726200C3C7A1 /* JSCWebWorker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0C41E03699D0018521A /* JSCWebWorker.cpp */; };
13F8877B1E29726200C3C7A1 /* JSIndexedRAMBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0C61E03699D0018521A /* JSIndexedRAMBundle.cpp */; };
13F8877C1E29726200C3C7A1 /* MethodCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0CA1E03699D0018521A /* MethodCall.cpp */; };
13F8877D1E29726200C3C7A1 /* ModuleRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0CC1E03699D0018521A /* ModuleRegistry.cpp */; };
@ -185,7 +184,6 @@
13F8878A1E29726300C3C7A1 /* JSCPerfStats.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0BC1E03699D0018521A /* JSCPerfStats.cpp */; };
13F8878B1E29726300C3C7A1 /* JSCSamplingProfiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0BE1E03699D0018521A /* JSCSamplingProfiler.cpp */; };
13F8878C1E29726300C3C7A1 /* JSCUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0C21E03699D0018521A /* JSCUtils.cpp */; };
13F8878D1E29726300C3C7A1 /* JSCWebWorker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0C41E03699D0018521A /* JSCWebWorker.cpp */; };
13F8878E1E29726300C3C7A1 /* JSIndexedRAMBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0C61E03699D0018521A /* JSIndexedRAMBundle.cpp */; };
13F8878F1E29726300C3C7A1 /* MethodCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0CA1E03699D0018521A /* MethodCall.cpp */; };
13F887901E29726300C3C7A1 /* ModuleRegistry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3D92B0CC1E03699D0018521A /* ModuleRegistry.cpp */; };
@ -226,8 +224,6 @@
27595AA41E575C7800CCE2B1 /* CxxModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0A71E03699D0018521A /* CxxModule.h */; };
27595AA51E575C7800CCE2B1 /* CxxNativeModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0A91E03699D0018521A /* CxxNativeModule.h */; };
27595AA61E575C7800CCE2B1 /* Executor.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AB1E03699D0018521A /* Executor.h */; };
27595AA71E575C7800CCE2B1 /* ExecutorToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AC1E03699D0018521A /* ExecutorToken.h */; };
27595AA81E575C7800CCE2B1 /* ExecutorTokenFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AD1E03699D0018521A /* ExecutorTokenFactory.h */; };
27595AA91E575C7800CCE2B1 /* Instance.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AF1E03699D0018521A /* Instance.h */; };
27595AAA1E575C7800CCE2B1 /* JsArgumentHelpers-inl.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B01E03699D0018521A /* JsArgumentHelpers-inl.h */; };
27595AAB1E575C7800CCE2B1 /* JsArgumentHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B11E03699D0018521A /* JsArgumentHelpers.h */; };
@ -239,7 +235,6 @@
27595AB11E575C7800CCE2B1 /* JSCPerfStats.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BD1E03699D0018521A /* JSCPerfStats.h */; };
27595AB21E575C7800CCE2B1 /* JSCSamplingProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BF1E03699D0018521A /* JSCSamplingProfiler.h */; };
27595AB31E575C7800CCE2B1 /* JSCUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C31E03699D0018521A /* JSCUtils.h */; };
27595AB41E575C7800CCE2B1 /* JSCWebWorker.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C51E03699D0018521A /* JSCWebWorker.h */; };
27595AB51E575C7800CCE2B1 /* JSIndexedRAMBundle.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C71E03699D0018521A /* JSIndexedRAMBundle.h */; };
27595AB61E575C7800CCE2B1 /* MessageQueueThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C91E03699D0018521A /* MessageQueueThread.h */; };
27595AB71E575C7800CCE2B1 /* MethodCall.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0CB1E03699D0018521A /* MethodCall.h */; };
@ -252,8 +247,6 @@
27595ABF1E575C7800CCE2B1 /* CxxModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0A71E03699D0018521A /* CxxModule.h */; };
27595AC01E575C7800CCE2B1 /* CxxNativeModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0A91E03699D0018521A /* CxxNativeModule.h */; };
27595AC11E575C7800CCE2B1 /* Executor.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AB1E03699D0018521A /* Executor.h */; };
27595AC21E575C7800CCE2B1 /* ExecutorToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AC1E03699D0018521A /* ExecutorToken.h */; };
27595AC31E575C7800CCE2B1 /* ExecutorTokenFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AD1E03699D0018521A /* ExecutorTokenFactory.h */; };
27595AC41E575C7800CCE2B1 /* Instance.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AF1E03699D0018521A /* Instance.h */; };
27595AC51E575C7800CCE2B1 /* JsArgumentHelpers-inl.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B01E03699D0018521A /* JsArgumentHelpers-inl.h */; };
27595AC61E575C7800CCE2B1 /* JsArgumentHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B11E03699D0018521A /* JsArgumentHelpers.h */; };
@ -265,7 +258,6 @@
27595ACC1E575C7800CCE2B1 /* JSCPerfStats.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BD1E03699D0018521A /* JSCPerfStats.h */; };
27595ACD1E575C7800CCE2B1 /* JSCSamplingProfiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BF1E03699D0018521A /* JSCSamplingProfiler.h */; };
27595ACE1E575C7800CCE2B1 /* JSCUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C31E03699D0018521A /* JSCUtils.h */; };
27595ACF1E575C7800CCE2B1 /* JSCWebWorker.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C51E03699D0018521A /* JSCWebWorker.h */; };
27595AD01E575C7800CCE2B1 /* JSIndexedRAMBundle.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C71E03699D0018521A /* JSIndexedRAMBundle.h */; };
27595AD11E575C7800CCE2B1 /* MessageQueueThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C91E03699D0018521A /* MessageQueueThread.h */; };
27595AD21E575C7800CCE2B1 /* MethodCall.h in Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0CB1E03699D0018521A /* MethodCall.h */; };
@ -756,8 +748,6 @@
3DA981A01E5B0E34004F2374 /* CxxModule.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0A71E03699D0018521A /* CxxModule.h */; };
3DA981A11E5B0E34004F2374 /* CxxNativeModule.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0A91E03699D0018521A /* CxxNativeModule.h */; };
3DA981A21E5B0E34004F2374 /* Executor.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AB1E03699D0018521A /* Executor.h */; };
3DA981A31E5B0E34004F2374 /* ExecutorToken.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AC1E03699D0018521A /* ExecutorToken.h */; };
3DA981A41E5B0E34004F2374 /* ExecutorTokenFactory.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AD1E03699D0018521A /* ExecutorTokenFactory.h */; };
3DA981A51E5B0E34004F2374 /* Instance.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AF1E03699D0018521A /* Instance.h */; };
3DA981A61E5B0E34004F2374 /* JsArgumentHelpers-inl.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B01E03699D0018521A /* JsArgumentHelpers-inl.h */; };
3DA981A71E5B0E34004F2374 /* JsArgumentHelpers.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B11E03699D0018521A /* JsArgumentHelpers.h */; };
@ -771,7 +761,6 @@
3DA981AF1E5B0E34004F2374 /* JSCPerfStats.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BD1E03699D0018521A /* JSCPerfStats.h */; };
3DA981B01E5B0E34004F2374 /* JSCSamplingProfiler.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BF1E03699D0018521A /* JSCSamplingProfiler.h */; };
3DA981B11E5B0E34004F2374 /* JSCUtils.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C31E03699D0018521A /* JSCUtils.h */; };
3DA981B21E5B0E34004F2374 /* JSCWebWorker.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C51E03699D0018521A /* JSCWebWorker.h */; };
3DA981B31E5B0E34004F2374 /* JSIndexedRAMBundle.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C71E03699D0018521A /* JSIndexedRAMBundle.h */; };
3DA981B41E5B0E34004F2374 /* JSModulesUnbundle.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C81E03699D0018521A /* JSModulesUnbundle.h */; };
3DA981B51E5B0E34004F2374 /* MessageQueueThread.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C91E03699D0018521A /* MessageQueueThread.h */; };
@ -899,8 +888,6 @@
3DA9823B1E5B1053004F2374 /* CxxModule.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0A71E03699D0018521A /* CxxModule.h */; };
3DA9823C1E5B1053004F2374 /* CxxNativeModule.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0A91E03699D0018521A /* CxxNativeModule.h */; };
3DA9823D1E5B1053004F2374 /* Executor.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AB1E03699D0018521A /* Executor.h */; };
3DA9823E1E5B1053004F2374 /* ExecutorToken.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AC1E03699D0018521A /* ExecutorToken.h */; };
3DA9823F1E5B1053004F2374 /* ExecutorTokenFactory.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AD1E03699D0018521A /* ExecutorTokenFactory.h */; };
3DA982401E5B1053004F2374 /* Instance.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0AF1E03699D0018521A /* Instance.h */; };
3DA982411E5B1053004F2374 /* JsArgumentHelpers-inl.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B01E03699D0018521A /* JsArgumentHelpers-inl.h */; };
3DA982421E5B1053004F2374 /* JsArgumentHelpers.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0B11E03699D0018521A /* JsArgumentHelpers.h */; };
@ -914,7 +901,6 @@
3DA9824A1E5B1053004F2374 /* JSCPerfStats.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BD1E03699D0018521A /* JSCPerfStats.h */; };
3DA9824B1E5B1053004F2374 /* JSCSamplingProfiler.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0BF1E03699D0018521A /* JSCSamplingProfiler.h */; };
3DA9824C1E5B1053004F2374 /* JSCUtils.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C31E03699D0018521A /* JSCUtils.h */; };
3DA9824D1E5B1053004F2374 /* JSCWebWorker.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C51E03699D0018521A /* JSCWebWorker.h */; };
3DA9824E1E5B1053004F2374 /* JSIndexedRAMBundle.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C71E03699D0018521A /* JSIndexedRAMBundle.h */; };
3DA9824F1E5B1053004F2374 /* JSModulesUnbundle.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C81E03699D0018521A /* JSModulesUnbundle.h */; };
3DA982501E5B1053004F2374 /* MessageQueueThread.h in Copy Headers */ = {isa = PBXBuildFile; fileRef = 3D92B0C91E03699D0018521A /* MessageQueueThread.h */; };
@ -1234,8 +1220,6 @@
3DA9823B1E5B1053004F2374 /* CxxModule.h in Copy Headers */,
3DA9823C1E5B1053004F2374 /* CxxNativeModule.h in Copy Headers */,
3DA9823D1E5B1053004F2374 /* Executor.h in Copy Headers */,
3DA9823E1E5B1053004F2374 /* ExecutorToken.h in Copy Headers */,
3DA9823F1E5B1053004F2374 /* ExecutorTokenFactory.h in Copy Headers */,
3DA982401E5B1053004F2374 /* Instance.h in Copy Headers */,
3DA982411E5B1053004F2374 /* JsArgumentHelpers-inl.h in Copy Headers */,
3DA982421E5B1053004F2374 /* JsArgumentHelpers.h in Copy Headers */,
@ -1249,7 +1233,6 @@
3DA9824A1E5B1053004F2374 /* JSCPerfStats.h in Copy Headers */,
3DA9824B1E5B1053004F2374 /* JSCSamplingProfiler.h in Copy Headers */,
3DA9824C1E5B1053004F2374 /* JSCUtils.h in Copy Headers */,
3DA9824D1E5B1053004F2374 /* JSCWebWorker.h in Copy Headers */,
3DA9824E1E5B1053004F2374 /* JSIndexedRAMBundle.h in Copy Headers */,
3DA9824F1E5B1053004F2374 /* JSModulesUnbundle.h in Copy Headers */,
3DA982501E5B1053004F2374 /* MessageQueueThread.h in Copy Headers */,
@ -1431,8 +1414,6 @@
3DA981A01E5B0E34004F2374 /* CxxModule.h in Copy Headers */,
3DA981A11E5B0E34004F2374 /* CxxNativeModule.h in Copy Headers */,
3DA981A21E5B0E34004F2374 /* Executor.h in Copy Headers */,
3DA981A31E5B0E34004F2374 /* ExecutorToken.h in Copy Headers */,
3DA981A41E5B0E34004F2374 /* ExecutorTokenFactory.h in Copy Headers */,
3DA981A51E5B0E34004F2374 /* Instance.h in Copy Headers */,
3DA981A61E5B0E34004F2374 /* JsArgumentHelpers-inl.h in Copy Headers */,
3DA981A71E5B0E34004F2374 /* JsArgumentHelpers.h in Copy Headers */,
@ -1446,7 +1427,6 @@
3DA981AF1E5B0E34004F2374 /* JSCPerfStats.h in Copy Headers */,
3DA981B01E5B0E34004F2374 /* JSCSamplingProfiler.h in Copy Headers */,
3DA981B11E5B0E34004F2374 /* JSCUtils.h in Copy Headers */,
3DA981B21E5B0E34004F2374 /* JSCWebWorker.h in Copy Headers */,
3DA981B31E5B0E34004F2374 /* JSIndexedRAMBundle.h in Copy Headers */,
3DA981B41E5B0E34004F2374 /* JSModulesUnbundle.h in Copy Headers */,
3DA981B51E5B0E34004F2374 /* MessageQueueThread.h in Copy Headers */,
@ -1761,8 +1741,6 @@
3D92B0A81E03699D0018521A /* CxxNativeModule.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CxxNativeModule.cpp; sourceTree = "<group>"; };
3D92B0A91E03699D0018521A /* CxxNativeModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CxxNativeModule.h; sourceTree = "<group>"; };
3D92B0AB1E03699D0018521A /* Executor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Executor.h; sourceTree = "<group>"; };
3D92B0AC1E03699D0018521A /* ExecutorToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExecutorToken.h; sourceTree = "<group>"; };
3D92B0AD1E03699D0018521A /* ExecutorTokenFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExecutorTokenFactory.h; sourceTree = "<group>"; };
3D92B0AE1E03699D0018521A /* Instance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Instance.cpp; sourceTree = "<group>"; };
3D92B0AF1E03699D0018521A /* Instance.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Instance.h; sourceTree = "<group>"; };
3D92B0B01E03699D0018521A /* JsArgumentHelpers-inl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "JsArgumentHelpers-inl.h"; sourceTree = "<group>"; };
@ -1783,8 +1761,6 @@
3D92B0BF1E03699D0018521A /* JSCSamplingProfiler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCSamplingProfiler.h; sourceTree = "<group>"; };
3D92B0C21E03699D0018521A /* JSCUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCUtils.cpp; sourceTree = "<group>"; };
3D92B0C31E03699D0018521A /* JSCUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCUtils.h; sourceTree = "<group>"; };
3D92B0C41E03699D0018521A /* JSCWebWorker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCWebWorker.cpp; sourceTree = "<group>"; };
3D92B0C51E03699D0018521A /* JSCWebWorker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCWebWorker.h; sourceTree = "<group>"; };
3D92B0C61E03699D0018521A /* JSIndexedRAMBundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSIndexedRAMBundle.cpp; sourceTree = "<group>"; };
3D92B0C71E03699D0018521A /* JSIndexedRAMBundle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSIndexedRAMBundle.h; sourceTree = "<group>"; };
3D92B0C81E03699D0018521A /* JSModulesUnbundle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSModulesUnbundle.h; sourceTree = "<group>"; };
@ -2474,8 +2450,6 @@
3D92B0A81E03699D0018521A /* CxxNativeModule.cpp */,
3D92B0A91E03699D0018521A /* CxxNativeModule.h */,
3D92B0AB1E03699D0018521A /* Executor.h */,
3D92B0AC1E03699D0018521A /* ExecutorToken.h */,
3D92B0AD1E03699D0018521A /* ExecutorTokenFactory.h */,
3D92B0AE1E03699D0018521A /* Instance.cpp */,
3D92B0AF1E03699D0018521A /* Instance.h */,
3D92B0B01E03699D0018521A /* JsArgumentHelpers-inl.h */,
@ -2500,8 +2474,6 @@
3D92B0BF1E03699D0018521A /* JSCSamplingProfiler.h */,
3D92B0C21E03699D0018521A /* JSCUtils.cpp */,
3D92B0C31E03699D0018521A /* JSCUtils.h */,
3D92B0C41E03699D0018521A /* JSCWebWorker.cpp */,
3D92B0C51E03699D0018521A /* JSCWebWorker.h */,
3D92B0C61E03699D0018521A /* JSIndexedRAMBundle.cpp */,
3D92B0C71E03699D0018521A /* JSIndexedRAMBundle.h */,
3D92B0C81E03699D0018521A /* JSModulesUnbundle.h */,
@ -2726,11 +2698,8 @@
27595AC01E575C7800CCE2B1 /* CxxNativeModule.h in Headers */,
27595AD01E575C7800CCE2B1 /* JSIndexedRAMBundle.h in Headers */,
27595AD31E575C7800CCE2B1 /* ModuleRegistry.h in Headers */,
27595ACF1E575C7800CCE2B1 /* JSCWebWorker.h in Headers */,
27595ACC1E575C7800CCE2B1 /* JSCPerfStats.h in Headers */,
27595AC31E575C7800CCE2B1 /* ExecutorTokenFactory.h in Headers */,
27595AC11E575C7800CCE2B1 /* Executor.h in Headers */,
27595AC21E575C7800CCE2B1 /* ExecutorToken.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -2801,11 +2770,8 @@
27595AA51E575C7800CCE2B1 /* CxxNativeModule.h in Headers */,
27595AB51E575C7800CCE2B1 /* JSIndexedRAMBundle.h in Headers */,
27595AB81E575C7800CCE2B1 /* ModuleRegistry.h in Headers */,
27595AB41E575C7800CCE2B1 /* JSCWebWorker.h in Headers */,
27595AB11E575C7800CCE2B1 /* JSCPerfStats.h in Headers */,
27595AA81E575C7800CCE2B1 /* ExecutorTokenFactory.h in Headers */,
27595AA61E575C7800CCE2B1 /* Executor.h in Headers */,
27595AA71E575C7800CCE2B1 /* ExecutorToken.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -3478,7 +3444,6 @@
13F8877B1E29726200C3C7A1 /* JSIndexedRAMBundle.cpp in Sources */,
13F8877D1E29726200C3C7A1 /* ModuleRegistry.cpp in Sources */,
13F8876E1E29726200C3C7A1 /* CxxNativeModule.cpp in Sources */,
13F8877A1E29726200C3C7A1 /* JSCWebWorker.cpp in Sources */,
13F887721E29726200C3C7A1 /* JSCExecutor.cpp in Sources */,
13F887741E29726200C3C7A1 /* JSCLegacyTracing.cpp in Sources */,
13F887771E29726200C3C7A1 /* JSCPerfStats.cpp in Sources */,
@ -3503,7 +3468,6 @@
3DC159E61E83E1FA007B1282 /* JSBigString.cpp in Sources */,
13F8878E1E29726300C3C7A1 /* JSIndexedRAMBundle.cpp in Sources */,
13F887901E29726300C3C7A1 /* ModuleRegistry.cpp in Sources */,
13F8878D1E29726300C3C7A1 /* JSCWebWorker.cpp in Sources */,
13F887851E29726300C3C7A1 /* JSCExecutor.cpp in Sources */,
13F887871E29726300C3C7A1 /* JSCLegacyTracing.cpp in Sources */,
13F8878A1E29726300C3C7A1 /* JSCPerfStats.cpp in Sources */,

View File

@ -28,7 +28,6 @@ import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.SoftAssertions;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.common.ApplicationHolder;
import com.facebook.react.common.futures.SimpleSettableFuture;
import com.facebook.react.devsupport.interfaces.DevSupportManager;
import com.facebook.react.modules.core.Timing;
@ -178,7 +177,6 @@ public abstract class ReactIntegrationTestCase extends AndroidTestCase {
protected void setUp() throws Exception {
super.setUp();
SoLoader.init(getContext(), /* native exopackage */ false);
ApplicationHolder.setApplication((Application) getContext().getApplicationContext());
}
@Override

View File

@ -42,7 +42,6 @@ import com.facebook.react.bridge.ReactMarker;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec;
import com.facebook.react.common.ApplicationHolder;
import com.facebook.react.common.LifecycleState;
import com.facebook.react.common.ReactConstants;
import com.facebook.react.common.annotations.VisibleForTesting;
@ -229,8 +228,6 @@ public class ReactInstanceManager {
initializeSoLoaderIfNecessary(applicationContext);
// TODO(9577825): remove this
ApplicationHolder.setApplication((Application) applicationContext.getApplicationContext());
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(applicationContext);
mApplicationContext = applicationContext;

View File

@ -66,11 +66,6 @@ public abstract class BaseJavaModule implements NativeModule {
// do nothing
}
@Override
public boolean supportsWebWorkers() {
return false;
}
public boolean hasConstants() {
return false;
}

View File

@ -15,13 +15,11 @@ package com.facebook.react.bridge;
public final class CallbackImpl implements Callback {
private final JSInstance mJSInstance;
private final ExecutorToken mExecutorToken;
private final int mCallbackId;
private boolean mInvoked;
public CallbackImpl(JSInstance jsInstance, ExecutorToken executorToken, int callbackId) {
public CallbackImpl(JSInstance jsInstance, int callbackId) {
mJSInstance = jsInstance;
mExecutorToken = executorToken;
mCallbackId = callbackId;
mInvoked = false;
}
@ -33,7 +31,7 @@ public final class CallbackImpl implements Callback {
"module. This callback type only permits a single invocation from "+
"native code.");
}
mJSInstance.invokeCallback(mExecutorToken, mCallbackId, Arguments.fromJavaArgs(args));
mJSInstance.invokeCallback(mCallbackId, Arguments.fromJavaArgs(args));
mInvoked = true;
}
}

View File

@ -37,12 +37,10 @@ public interface CatalystInstance
// which this prevents.
@Override @DoNotStrip
void invokeCallback(
ExecutorToken executorToken,
int callbackID,
NativeArray arguments);
@DoNotStrip
void callFunction(
ExecutorToken executorToken,
String module,
String method,
NativeArray arguments);
@ -63,7 +61,6 @@ public interface CatalystInstance
ReactQueueConfiguration getReactQueueConfiguration();
<T extends JavaScriptModule> T getJSModule(Class<T> jsInterface);
<T extends JavaScriptModule> T getJSModule(ExecutorToken executorToken, Class<T> jsInterface);
<T extends NativeModule> boolean hasNativeModule(Class<T> nativeModuleInterface);
<T extends NativeModule> T getNativeModule(Class<T> nativeModuleInterface);
Collection<NativeModule> getNativeModules();

View File

@ -1,24 +0,0 @@
package com.facebook.react.bridge;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
/**
* Class corresponding to a JS VM that can call into native modules. In Java, this should
* just be treated as a black box to be used to help the framework route native->JS calls back to
* the proper JS VM. See {@link ReactContext#getJSModule(ExecutorToken, Class)} and
* {@link BaseJavaModule#supportsWebWorkers()}.
*
* Note: If your application doesn't use web workers, it will only have a single ExecutorToken
* per instance of React Native.
*/
@DoNotStrip
public class ExecutorToken {
private final HybridData mHybridData;
@DoNotStrip
private ExecutorToken(HybridData hybridData) {
mHybridData = hybridData;
}
}

View File

@ -16,7 +16,6 @@ package com.facebook.react.bridge;
*/
public interface JSInstance {
void invokeCallback(
ExecutorToken executorToken,
int callbackID,
NativeArray arguments);
// TODO if this interface survives refactoring, think about adding

View File

@ -31,11 +31,11 @@ import com.facebook.react.common.ReactConstants;
* JavaScript.
*/
public class JavaScriptModuleRegistry {
private final WeakHashMap<ExecutorToken, HashMap<Class<? extends JavaScriptModule>, JavaScriptModule>> mModuleInstances;
private final HashMap<Class<? extends JavaScriptModule>, JavaScriptModule> mModuleInstances;
private final HashMap<Class<? extends JavaScriptModule>, JavaScriptModuleRegistration> mModuleRegistrations;
public JavaScriptModuleRegistry(List<JavaScriptModuleRegistration> config) {
mModuleInstances = new WeakHashMap<>();
mModuleInstances = new HashMap<>();
mModuleRegistrations = new HashMap<>();
for (JavaScriptModuleRegistration registration : config) {
mModuleRegistrations.put(registration.getModuleInterface(), registration);
@ -43,17 +43,9 @@ public class JavaScriptModuleRegistry {
}
public synchronized <T extends JavaScriptModule> T getJavaScriptModule(
CatalystInstance instance,
ExecutorToken executorToken,
Class<T> moduleInterface) {
HashMap<Class<? extends JavaScriptModule>, JavaScriptModule> instancesForContext =
mModuleInstances.get(executorToken);
if (instancesForContext == null) {
instancesForContext = new HashMap<>();
mModuleInstances.put(executorToken, instancesForContext);
}
JavaScriptModule module = instancesForContext.get(moduleInterface);
CatalystInstance instance,
Class<T> moduleInterface) {
JavaScriptModule module = mModuleInstances.get(moduleInterface);
if (module != null) {
return (T) module;
}
@ -65,8 +57,8 @@ public class JavaScriptModuleRegistry {
JavaScriptModule interfaceProxy = (JavaScriptModule) Proxy.newProxyInstance(
moduleInterface.getClassLoader(),
new Class[]{moduleInterface},
new JavaScriptModuleInvocationHandler(executorToken, instance, registration));
instancesForContext.put(moduleInterface, interfaceProxy);
new JavaScriptModuleInvocationHandler(instance, registration));
mModuleInstances.put(moduleInterface, interfaceProxy);
return (T) interfaceProxy;
}
@ -85,30 +77,20 @@ public class JavaScriptModuleRegistry {
}
private static class JavaScriptModuleInvocationHandler implements InvocationHandler {
private final WeakReference<ExecutorToken> mExecutorToken;
private final CatalystInstance mCatalystInstance;
private final JavaScriptModuleRegistration mModuleRegistration;
public JavaScriptModuleInvocationHandler(
ExecutorToken executorToken,
CatalystInstance catalystInstance,
JavaScriptModuleRegistration moduleRegistration) {
mExecutorToken = new WeakReference<>(executorToken);
mCatalystInstance = catalystInstance;
mModuleRegistration = moduleRegistration;
}
@Override
public @Nullable Object invoke(Object proxy, Method method, @Nullable Object[] args) throws Throwable {
ExecutorToken executorToken = mExecutorToken.get();
if (executorToken == null) {
FLog.w(ReactConstants.TAG, "Dropping JS call, ExecutorToken went away...");
return null;
}
NativeArray jsArgs = args != null ? Arguments.fromJavaArgs(args) : new WritableNativeArray();
mCatalystInstance.callFunction(
executorToken,
mModuleRegistration.getName(),
method.getName(),
jsArgs

View File

@ -9,10 +9,7 @@
package com.facebook.react.bridge;
import javax.annotation.Nullable;
import java.lang.reflect.Method;
import java.util.Map;
/**
* A native module whose API can be provided to JS catalyst instances. {@link NativeModule}s whose
@ -23,7 +20,7 @@ import java.util.Map;
*/
public interface NativeModule {
interface NativeMethod {
void invoke(JSInstance jsInstance, ExecutorToken executorToken, ReadableNativeArray parameters);
void invoke(JSInstance jsInstance, ReadableNativeArray parameters);
String getType();
}
@ -52,27 +49,4 @@ public interface NativeModule {
* Called before {CatalystInstance#onHostDestroy}
*/
void onCatalystInstanceDestroy();
/**
* In order to support web workers, a module must be aware that it can be invoked from multiple
* different JS VMs. Supporting web workers means recognizing things like:
*
* 1) ids (e.g. timer ids, request ids, etc.) may only unique on a per-VM basis
* 2) the module needs to make sure to enqueue callbacks and JS module calls to the correct VM
*
* In order to facilitate this, modules that support web workers will have all their @ReactMethod-
* annotated methods passed a {@link ExecutorToken} as the first parameter before any arguments
* from JS. This ExecutorToken internally maps to a specific JS VM and can be used by the
* framework to route calls appropriately. In order to make JS module calls correctly, start using
* the version of {@link ReactContext#getJSModule(ExecutorToken, Class)} that takes an
* ExecutorToken. It will ensure that any calls you dispatch to the returned object will go to
* the right VM. For Callbacks, you don't have to do anything special -- the framework
* automatically tags them with the correct ExecutorToken when the are created.
*
* Note: even though calls can come from multiple JS VMs on multiple threads, calls to this module
* will still only occur on a single thread.
*
* @return whether this module supports web workers.
*/
boolean supportsWebWorkers();
}

View File

@ -1,22 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.bridge;
/**
* Interface for a module that will be notified when JS executors have been unregistered from the bridge.
* Note that this will NOT notify listeners about the main executor being destroyed: use
* {@link NativeModule#onCatalystInstanceDestroy()} for that. Once a module has received a
* {@link NativeModule#onCatalystInstanceDestroy()} call, it will not receive any onExecutorUnregistered
* calls.
*/
public interface OnExecutorUnregisteredListener {
void onExecutorDestroyed(ExecutorToken executorToken);
}

View File

@ -107,15 +107,6 @@ public class ReactContext extends ContextWrapper {
return mCatalystInstance.getJSModule(jsInterface);
}
public <T extends JavaScriptModule> T getJSModule(
ExecutorToken executorToken,
Class<T> jsInterface) {
if (mCatalystInstance == null) {
throw new RuntimeException(EARLY_JS_ACCESS_EXCEPTION_MESSAGE);
}
return mCatalystInstance.getJSModule(executorToken, jsInterface);
}
public <T extends NativeModule> boolean hasNativeModule(Class<T> nativeModuleInterface) {
if (mCatalystInstance == null) {
throw new RuntimeException(

View File

@ -1,15 +0,0 @@
// Copyright 2004-present Facebook. All Rights Reserved.
package com.facebook.react.bridge;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotation indicating that a JS module should be made available to web
* workers spawned by the main JS executor.
*/
@Retention(RUNTIME)
public @interface SupportsWebWorkers {
}

View File

@ -1,37 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.common;
import android.app.Application;
import com.facebook.infer.annotation.Assertions;
import com.facebook.proguard.annotations.DoNotStrip;
/**
* Holds the current Application Object.
*
* TODO(9577825): This is a bad pattern, we should thread through an Environment object instead.
* Remove once bridge is unforked.
*/
@DoNotStrip
@Deprecated
public class ApplicationHolder {
private static Application sApplication;
public static void setApplication(Application application) {
sApplication = application;
}
@DoNotStrip
public static Application getApplication() {
return Assertions.assertNotNull(sApplication);
}
}

View File

@ -24,7 +24,6 @@ import com.facebook.infer.annotation.Assertions;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.CatalystInstance;
import com.facebook.react.bridge.ExecutorToken;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.JavaScriptModuleRegistry;
import com.facebook.react.bridge.MemoryPressure;
@ -60,17 +59,14 @@ public class CatalystInstanceImpl implements CatalystInstance {
private static class PendingJSCall {
public ExecutorToken mExecutorToken;
public String mModule;
public String mMethod;
public NativeArray mArguments;
public PendingJSCall(
ExecutorToken executorToken,
String module,
String method,
NativeArray arguments) {
mExecutorToken = executorToken;
mModule = module;
mMethod = method;
mArguments = arguments;
@ -89,7 +85,6 @@ public class CatalystInstanceImpl implements CatalystInstance {
private final JSBundleLoader mJSBundleLoader;
private final ArrayList<PendingJSCall> mJSCallsPendingInit = new ArrayList<PendingJSCall>();
private final Object mJSCallsPendingInitLock = new Object();
private ExecutorToken mMainExecutorToken;
private final NativeModuleRegistry mJavaRegistry;
private final NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
@ -134,7 +129,6 @@ public class CatalystInstanceImpl implements CatalystInstance {
mJavaRegistry.getJavaModules(this),
mJavaRegistry.getCxxModules());
FLog.d(ReactConstants.TAG, "Initializing React Xplat Bridge after initializeBridge");
mMainExecutorToken = getMainExecutorToken();
}
private static class BridgeCallback implements ReactCallback {
@ -224,7 +218,7 @@ public class CatalystInstanceImpl implements CatalystInstance {
mAcceptCalls = true;
for (PendingJSCall call : mJSCallsPendingInit) {
jniCallJSFunction(call.mExecutorToken, call.mModule, call.mMethod, call.mArguments);
jniCallJSFunction(call.mModule, call.mMethod, call.mArguments);
}
mJSCallsPendingInit.clear();
}
@ -239,14 +233,12 @@ public class CatalystInstanceImpl implements CatalystInstance {
}
private native void jniCallJSFunction(
ExecutorToken token,
String module,
String method,
NativeArray arguments);
@Override
public void callFunction(
ExecutorToken executorToken,
final String module,
final String method,
final NativeArray arguments) {
@ -258,25 +250,25 @@ public class CatalystInstanceImpl implements CatalystInstance {
// Most of the time the instance is initialized and we don't need to acquire the lock
synchronized (mJSCallsPendingInitLock) {
if (!mAcceptCalls) {
mJSCallsPendingInit.add(new PendingJSCall(executorToken, module, method, arguments));
mJSCallsPendingInit.add(new PendingJSCall(module, method, arguments));
return;
}
}
}
jniCallJSFunction(executorToken, module, method, arguments);
jniCallJSFunction(module, method, arguments);
}
private native void jniCallJSCallback(ExecutorToken executorToken, int callbackID, NativeArray arguments);
private native void jniCallJSCallback(int callbackID, NativeArray arguments);
@Override
public void invokeCallback(ExecutorToken executorToken, final int callbackID, final NativeArray arguments) {
public void invokeCallback(final int callbackID, final NativeArray arguments) {
if (mDestroyed) {
FLog.w(ReactConstants.TAG, "Invoking JS callback after bridge has been destroyed.");
return;
}
jniCallJSCallback(executorToken, callbackID, arguments);
jniCallJSCallback(callbackID, arguments);
}
/**
@ -348,17 +340,9 @@ public class CatalystInstanceImpl implements CatalystInstance {
@Override
public <T extends JavaScriptModule> T getJSModule(Class<T> jsInterface) {
return getJSModule(mMainExecutorToken, jsInterface);
return mJSModuleRegistry.getJavaScriptModule(this, jsInterface);
}
@Override
public <T extends JavaScriptModule> T getJSModule(ExecutorToken executorToken, Class<T> jsInterface) {
return Assertions.assertNotNull(mJSModuleRegistry)
.getJavaScriptModule(this, executorToken, jsInterface);
}
private native ExecutorToken getMainExecutorToken();
@Override
public <T extends NativeModule> boolean hasNativeModule(Class<T> nativeModuleInterface) {
return mJavaRegistry.hasModule(nativeModuleInterface);

View File

@ -2,7 +2,6 @@
package com.facebook.react.cxxbridge;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.NativeModule;
@ -37,11 +36,6 @@ public class CxxModuleWrapperBase implements NativeModule
return false;
}
@Override
public boolean supportsWebWorkers() {
return false;
}
@Override
public void onCatalystInstanceDestroy() {
mHybridData.resetNative();

View File

@ -14,11 +14,22 @@ import javax.annotation.Nullable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.facebook.react.bridge.*;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.cxxbridge.JavaModuleWrapper;
import com.facebook.systrace.Systrace;
import com.facebook.react.bridge.BaseJavaModule;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.Dynamic;
import com.facebook.react.bridge.DynamicFromArray;
import com.facebook.react.bridge.JSInstance;
import com.facebook.react.bridge.NativeArgumentsParseException;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.PromiseImpl;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableNativeArray;
import com.facebook.react.bridge.UnexpectedNativeTypeException;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.systrace.SystraceMessage;
import static com.facebook.infer.annotation.Assertions.assertNotNull;
@ -32,14 +43,14 @@ public class JavaMethodWrapper implements NativeModule.NativeMethod {
}
public abstract @Nullable T extractArgument(
JSInstance jsInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex);
JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex);
}
static final private ArgumentExtractor<Boolean> ARGUMENT_EXTRACTOR_BOOLEAN =
new ArgumentExtractor<Boolean>() {
@Override
public Boolean extractArgument(
JSInstance jsInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
return jsArguments.getBoolean(atIndex);
}
};
@ -48,7 +59,7 @@ public class JavaMethodWrapper implements NativeModule.NativeMethod {
new ArgumentExtractor<Double>() {
@Override
public Double extractArgument(
JSInstance jsInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
return jsArguments.getDouble(atIndex);
}
};
@ -57,7 +68,7 @@ public class JavaMethodWrapper implements NativeModule.NativeMethod {
new ArgumentExtractor<Float>() {
@Override
public Float extractArgument(
JSInstance jsInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
return (float) jsArguments.getDouble(atIndex);
}
};
@ -66,7 +77,7 @@ public class JavaMethodWrapper implements NativeModule.NativeMethod {
new ArgumentExtractor<Integer>() {
@Override
public Integer extractArgument(
JSInstance jsInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
return (int) jsArguments.getDouble(atIndex);
}
};
@ -75,7 +86,7 @@ public class JavaMethodWrapper implements NativeModule.NativeMethod {
new ArgumentExtractor<String>() {
@Override
public String extractArgument(
JSInstance jsInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
return jsArguments.getString(atIndex);
}
};
@ -84,7 +95,7 @@ public class JavaMethodWrapper implements NativeModule.NativeMethod {
new ArgumentExtractor<ReadableNativeArray>() {
@Override
public ReadableNativeArray extractArgument(
JSInstance jsInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
return jsArguments.getArray(atIndex);
}
};
@ -93,7 +104,7 @@ public class JavaMethodWrapper implements NativeModule.NativeMethod {
new ArgumentExtractor<Dynamic>() {
@Override
public Dynamic extractArgument(
JSInstance jsInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
return DynamicFromArray.create(jsArguments, atIndex);
}
};
@ -102,7 +113,7 @@ public class JavaMethodWrapper implements NativeModule.NativeMethod {
new ArgumentExtractor<ReadableMap>() {
@Override
public ReadableMap extractArgument(
JSInstance jsInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
return jsArguments.getMap(atIndex);
}
};
@ -111,12 +122,12 @@ public class JavaMethodWrapper implements NativeModule.NativeMethod {
new ArgumentExtractor<Callback>() {
@Override
public @Nullable Callback extractArgument(
JSInstance jsInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
if (jsArguments.isNull(atIndex)) {
return null;
} else {
int id = (int) jsArguments.getDouble(atIndex);
return new com.facebook.react.bridge.CallbackImpl(jsInstance, executorToken, id);
return new com.facebook.react.bridge.CallbackImpl(jsInstance, id);
}
}
};
@ -130,11 +141,11 @@ public class JavaMethodWrapper implements NativeModule.NativeMethod {
@Override
public Promise extractArgument(
JSInstance jsInstance, ExecutorToken executorToken, ReadableNativeArray jsArguments, int atIndex) {
JSInstance jsInstance, ReadableNativeArray jsArguments, int atIndex) {
Callback resolve = ARGUMENT_EXTRACTOR_CALLBACK
.extractArgument(jsInstance, executorToken, jsArguments, atIndex);
.extractArgument(jsInstance, jsArguments, atIndex);
Callback reject = ARGUMENT_EXTRACTOR_CALLBACK
.extractArgument(jsInstance, executorToken, jsArguments, atIndex + 1);
.extractArgument(jsInstance, jsArguments, atIndex + 1);
return new PromiseImpl(resolve, reject);
}
};
@ -144,9 +155,7 @@ public class JavaMethodWrapper implements NativeModule.NativeMethod {
if (tryCommon != '\0') {
return tryCommon;
}
if (paramClass == ExecutorToken.class) {
return 'T';
} else if (paramClass == Callback.class) {
if (paramClass == Callback.class) {
return 'X';
} else if (paramClass == Promise.class) {
return 'P';
@ -269,50 +278,20 @@ public class JavaMethodWrapper implements NativeModule.NativeMethod {
for (int i = 0; i < paramTypes.length; i++) {
Class paramClass = paramTypes[i];
if (paramClass == ExecutorToken.class) {
if (!mModuleWrapper.supportsWebWorkers()) {
throw new RuntimeException(
"Module " + mModuleWrapper.getName() + " doesn't support web workers, but " +
mMethod.getName() +
" takes an ExecutorToken.");
}
} else if (paramClass == Promise.class) {
if (paramClass == Promise.class) {
Assertions.assertCondition(
i == paramTypes.length - 1, "Promise must be used as last parameter only");
}
builder.append(paramTypeToChar(paramClass));
}
// Modules that support web workers are expected to take an ExecutorToken as the first
// parameter to all their @ReactMethod-annotated methods.
if (mModuleWrapper.supportsWebWorkers()) {
if (builder.charAt(2) != 'T') {
throw new RuntimeException(
"Module " + mModuleWrapper.getName() + " supports web workers, but " + mMethod.getName() +
"does not take an ExecutorToken as its first parameter.");
}
}
return builder.toString();
}
private ArgumentExtractor[] buildArgumentExtractors(Class[] paramTypes) {
// Modules that support web workers are expected to take an ExecutorToken as the first
// parameter to all their @ReactMethod-annotated methods. We compensate for that here.
int executorTokenOffset = 0;
if (mModuleWrapper.supportsWebWorkers()) {
if (paramTypes[0] != ExecutorToken.class) {
throw new RuntimeException(
"Module " + mModuleWrapper.getName() + " supports web workers, but " + mMethod.getName() +
"does not take an ExecutorToken as its first parameter.");
}
executorTokenOffset = 1;
}
ArgumentExtractor[] argumentExtractors = new ArgumentExtractor[paramTypes.length - executorTokenOffset];
for (int i = 0; i < paramTypes.length - executorTokenOffset; i += argumentExtractors[i].getJSArgumentsNeeded()) {
int paramIndex = i + executorTokenOffset;
Class argumentClass = paramTypes[paramIndex];
ArgumentExtractor[] argumentExtractors = new ArgumentExtractor[paramTypes.length];
for (int i = 0; i < paramTypes.length; i += argumentExtractors[i].getJSArgumentsNeeded()) {
Class argumentClass = paramTypes[i];
if (argumentClass == Boolean.class || argumentClass == boolean.class) {
argumentExtractors[i] = ARGUMENT_EXTRACTOR_BOOLEAN;
} else if (argumentClass == Integer.class || argumentClass == int.class) {
@ -328,7 +307,7 @@ public class JavaMethodWrapper implements NativeModule.NativeMethod {
} else if (argumentClass == Promise.class) {
argumentExtractors[i] = ARGUMENT_EXTRACTOR_PROMISE;
Assertions.assertCondition(
paramIndex == paramTypes.length - 1, "Promise must be used as last parameter only");
i == paramTypes.length - 1, "Promise must be used as last parameter only");
} else if (argumentClass == ReadableMap.class) {
argumentExtractors[i] = ARGUMENT_EXTRACTOR_MAP;
} else if (argumentClass == ReadableArray.class) {
@ -357,7 +336,7 @@ public class JavaMethodWrapper implements NativeModule.NativeMethod {
}
@Override
public void invoke(JSInstance jsInstance, ExecutorToken executorToken, ReadableNativeArray parameters) {
public void invoke(JSInstance jsInstance, ReadableNativeArray parameters) {
String traceName = mModuleWrapper.getName() + "." + mMethod.getName();
SystraceMessage.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "callJavaModuleMethod")
.arg("method", traceName)
@ -374,18 +353,11 @@ public class JavaMethodWrapper implements NativeModule.NativeMethod {
traceName + " got " + parameters.size() + " arguments, expected " + mJSArgumentsNeeded);
}
// Modules that support web workers are expected to take an ExecutorToken as the first
// parameter to all their @ReactMethod-annotated methods. We compensate for that here.
int i = 0, jsArgumentsConsumed = 0;
int executorTokenOffset = 0;
if (mModuleWrapper.supportsWebWorkers()) {
mArguments[0] = executorToken;
executorTokenOffset = 1;
}
try {
for (; i < mArgumentExtractors.length; i++) {
mArguments[i + executorTokenOffset] = mArgumentExtractors[i].extractArgument(
jsInstance, executorToken, parameters, jsArgumentsConsumed);
mArguments[i] = mArgumentExtractors[i].extractArgument(
jsInstance, parameters, jsArgumentsConsumed);
jsArgumentsConsumed += mArgumentExtractors[i].getJSArgumentsNeeded();
}
} catch (UnexpectedNativeTypeException e) {

View File

@ -20,7 +20,6 @@ import java.util.Set;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.BaseJavaModule;
import com.facebook.react.bridge.ExecutorToken;
import com.facebook.react.bridge.JSInstance;
import com.facebook.react.bridge.NativeArray;
import com.facebook.react.bridge.NativeModule;
@ -155,16 +154,11 @@ public class JavaModuleWrapper {
}
@DoNotStrip
public boolean supportsWebWorkers() {
return mModuleHolder.getSupportsWebWorkers();
}
@DoNotStrip
public void invoke(ExecutorToken token, int methodId, ReadableNativeArray parameters) {
public void invoke(int methodId, ReadableNativeArray parameters) {
if (mMethods == null || methodId >= mMethods.size()) {
return;
}
mMethods.get(methodId).invoke(mJSInstance, token, parameters);
mMethods.get(methodId).invoke(mJSInstance, parameters);
}
}

View File

@ -32,7 +32,6 @@ public class ModuleHolder {
private final String mName;
private final boolean mCanOverrideExistingModule;
private final boolean mSupportsWebWorkers;
private final boolean mHasConstants;
private @Nullable Provider<? extends NativeModule> mProvider;
@ -42,7 +41,6 @@ public class ModuleHolder {
public ModuleHolder(ReactModuleInfo moduleInfo, Provider<? extends NativeModule> provider) {
mName = moduleInfo.name();
mCanOverrideExistingModule = moduleInfo.canOverrideExistingModule();
mSupportsWebWorkers = moduleInfo.supportsWebWorkers();
mHasConstants = moduleInfo.hasConstants();
mProvider = provider;
if (moduleInfo.needsEagerInit()) {
@ -53,7 +51,6 @@ public class ModuleHolder {
public ModuleHolder(NativeModule nativeModule) {
mName = nativeModule.getName();
mCanOverrideExistingModule = nativeModule.canOverrideExistingModule();
mSupportsWebWorkers = nativeModule.supportsWebWorkers();
mHasConstants = true;
mModule = nativeModule;
}
@ -85,10 +82,6 @@ public class ModuleHolder {
return mCanOverrideExistingModule;
}
public boolean getSupportsWebWorkers() {
return mSupportsWebWorkers;
}
public boolean getHasConstants() {
return mHasConstants;
}

View File

@ -13,8 +13,6 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import com.facebook.react.bridge.BaseJavaModule;
import com.facebook.react.bridge.ExecutorToken;
import com.facebook.react.bridge.ReactContext;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@ -38,29 +36,6 @@ public @interface ReactModule {
*/
boolean canOverrideExistingModule() default false;
/**
* In order to support web workers, a module must be aware that it can be invoked from multiple
* different JS VMs. Supporting web workers means recognizing things like:
*
* 1) ids (e.g. timer ids, request ids, etc.) may only unique on a per-VM basis
* 2) the module needs to make sure to enqueue callbacks and JS module calls to the correct VM
*
* In order to facilitate this, modules that support web workers will have all their @ReactMethod-
* annotated methods passed a {@link ExecutorToken} as the first parameter before any arguments
* from JS. This ExecutorToken internally maps to a specific JS VM and can be used by the
* framework to route calls appropriately. In order to make JS module calls correctly, start using
* the version of {@link ReactContext#getJSModule(ExecutorToken, Class)} that takes an
* ExecutorToken. It will ensure that any calls you dispatch to the returned object will go to
* the right VM. For Callbacks, you don't have to do anything special -- the framework
* automatically tags them with the correct ExecutorToken when the are created.
*
* Note: even though calls can come from multiple JS VMs on multiple threads, calls to this module
* will still only occur on a single thread.
*
* @return whether this module supports web workers.
*/
boolean supportsWebWorkers() default false;
/**
* Whether this module needs to be loaded immediately.
*/

View File

@ -10,19 +10,16 @@ public class ReactModuleInfo {
private final String mName;
private final boolean mCanOverrideExistingModule;
private final boolean mSupportsWebWorkers;
private final boolean mNeedsEagerInit;
private final boolean mHasConstants;
public ReactModuleInfo(
String name,
boolean canOverrideExistingModule,
boolean supportsWebWorkers,
boolean needsEagerInit,
boolean hasConstants) {
mName = name;
mCanOverrideExistingModule = canOverrideExistingModule;
mSupportsWebWorkers = supportsWebWorkers;
mNeedsEagerInit = needsEagerInit;
mHasConstants = hasConstants;
}
@ -35,10 +32,6 @@ public class ReactModuleInfo {
return mCanOverrideExistingModule;
}
public boolean supportsWebWorkers() {
return mSupportsWebWorkers;
}
public boolean needsEagerInit() {
return mNeedsEagerInit;
}

View File

@ -175,7 +175,6 @@ public class ReactModuleSpecProcessor extends AbstractProcessor {
.append("new ReactModuleInfo(")
.append("\"").append(reactModule.name()).append("\"").append(", ")
.append(reactModule.canOverrideExistingModule()).append(", ")
.append(reactModule.supportsWebWorkers()).append(", ")
.append(reactModule.needsEagerInit()).append(", ")
.append(hasConstants)
.append(")")

View File

@ -18,7 +18,6 @@ import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.JavaScriptModule;
import com.facebook.react.bridge.SupportsWebWorkers;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.module.annotations.ReactModule;
@ -29,7 +28,6 @@ import com.facebook.react.module.annotations.ReactModule;
@ReactModule(name = "DeviceEventManager")
public class DeviceEventManagerModule extends ReactContextBaseJavaModule {
@SupportsWebWorkers
public interface RCTDeviceEventEmitter extends JavaScriptModule {
void emit(String eventName, @Nullable Object data);
}

View File

@ -8,7 +8,6 @@ LOCAL_SRC_FILES := \
CatalystInstanceImpl.cpp \
CxxModuleWrapper.cpp \
JavaModuleWrapper.cpp \
JExecutorToken.cpp \
JMessageQueueThread.cpp \
JniJSModulesUnbundle.cpp \
JSCPerfLogging.cpp \

View File

@ -8,7 +8,6 @@ LOCAL_SRC_FILES := \
CatalystInstanceImpl.cpp \
CxxModuleWrapper.cpp \
JavaModuleWrapper.cpp \
JExecutorToken.cpp \
JMessageQueueThread.cpp \
JSCPerfLogging.cpp \
JSLoader.cpp \

View File

@ -5,7 +5,6 @@ EXPORTED_HEADERS = [
"CxxModuleWrapperBase.h",
"CxxSharedModuleWrapper.h",
"JavaModuleWrapper.h",
"JExecutorToken.h",
"JSLoader.h",
"MethodInvoker.h",
"ModuleRegistryBuilder.h",

View File

@ -24,7 +24,6 @@
#include "JavaScriptExecutorHolder.h"
#include "JniJSModulesUnbundle.h"
#include "JNativeRunnable.h"
#include "JSLoader.h"
#include "NativeArray.h"
using namespace facebook::jni;
@ -71,13 +70,6 @@ class JInstanceCallback : public InstanceCallback {
method(jobj_);
}
ExecutorToken createExecutorToken() override {
auto jobj = JExecutorToken::newObjectCxxArgs();
return jobj->cthis()->getExecutorToken(jobj);
}
void onExecutorStopped(ExecutorToken) override {}
private:
global_ref<ReactCallback::javaobject> jobj_;
std::shared_ptr<JMessageQueueThread> messageQueueThread_;
@ -107,7 +99,6 @@ void CatalystInstanceImpl::registerNatives() {
makeNativeMethod("jniLoadScriptFromFile", CatalystInstanceImpl::jniLoadScriptFromFile),
makeNativeMethod("jniCallJSFunction", CatalystInstanceImpl::jniCallJSFunction),
makeNativeMethod("jniCallJSCallback", CatalystInstanceImpl::jniCallJSCallback),
makeNativeMethod("getMainExecutorToken", CatalystInstanceImpl::getMainExecutorToken),
makeNativeMethod("setGlobalVariable", CatalystInstanceImpl::setGlobalVariable),
makeNativeMethod("getJavaScriptContext", CatalystInstanceImpl::getJavaScriptContext),
makeNativeMethod("handleMemoryPressureUiHidden", CatalystInstanceImpl::handleMemoryPressureUiHidden),
@ -167,8 +158,8 @@ void CatalystInstanceImpl::jniLoadScriptFromAssets(
const int kAssetsLength = 9; // strlen("assets://");
auto sourceURL = assetURL.substr(kAssetsLength);
auto manager = react::extractAssetManager(assetManager);
auto script = react::loadScriptFromAssets(manager, sourceURL);
auto manager = extractAssetManager(assetManager);
auto script = loadScriptFromAssets(manager, sourceURL);
if (JniJSModulesUnbundle::isUnbundle(manager, sourceURL)) {
instance_->loadUnbundle(
folly::make_unique<JniJSModulesUnbundle>(manager, sourceURL),
@ -206,8 +197,7 @@ void CatalystInstanceImpl::jniLoadScriptFromFile(const std::string& fileName,
}
}
void CatalystInstanceImpl::jniCallJSFunction(
JExecutorToken* token, std::string module, std::string method, NativeArray* arguments) {
void CatalystInstanceImpl::jniCallJSFunction(std::string module, std::string method, NativeArray* arguments) {
// We want to share the C++ code, and on iOS, modules pass module/method
// names as strings all the way through to JS, and there's no way to do
// string -> id mapping on the objc side. So on Android, we convert the
@ -215,18 +205,13 @@ void CatalystInstanceImpl::jniCallJSFunction(
// used as ids if isFinite(), which handles this case, and looked up as
// strings otherwise. Eventually, we'll probably want to modify the stack
// from the JS proxy through here to use strings, too.
instance_->callJSFunction(token->getExecutorToken(nullptr),
std::move(module),
instance_->callJSFunction(std::move(module),
std::move(method),
arguments->consume());
}
void CatalystInstanceImpl::jniCallJSCallback(JExecutorToken* token, jint callbackId, NativeArray* arguments) {
instance_->callJSCallback(token->getExecutorToken(nullptr), callbackId, arguments->consume());
}
local_ref<JExecutorToken::JavaPart> CatalystInstanceImpl::getMainExecutorToken() {
return JExecutorToken::extractJavaPartFromToken(instance_->getMainExecutorToken());
void CatalystInstanceImpl::jniCallJSCallback(jint callbackId, NativeArray* arguments) {
instance_->callJSCallback(callbackId, arguments->consume());
}
void CatalystInstanceImpl::setGlobalVariable(std::string propName,

View File

@ -6,10 +6,9 @@
#include <folly/Memory.h>
#include "CxxModuleWrapper.h"
#include "JExecutorToken.h"
#include "JavaModuleWrapper.h"
#include "JMessageQueueThread.h"
#include "JSLoader.h"
#include "JavaModuleWrapper.h"
#include "ModuleRegistryBuilder.h"
namespace facebook {
@ -59,9 +58,8 @@ class CatalystInstanceImpl : public jni::HybridClass<CatalystInstanceImpl> {
void jniLoadScriptFromAssets(jni::alias_ref<JAssetManager::javaobject> assetManager, const std::string& assetURL);
void jniLoadScriptFromFile(const std::string& fileName, const std::string& sourceURL);
void jniCallJSFunction(JExecutorToken* token, std::string module, std::string method, NativeArray* arguments);
void jniCallJSCallback(JExecutorToken* token, jint callbackId, NativeArray* arguments);
local_ref<JExecutorToken::JavaPart> getMainExecutorToken();
void jniCallJSFunction(std::string module, std::string method, NativeArray* arguments);
void jniCallJSCallback(jint callbackId, NativeArray* arguments);
void setGlobalVariable(std::string propName,
std::string&& jsonValue);
jlong getJavaScriptContext();

View File

@ -1,25 +0,0 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include "JExecutorToken.h"
using namespace facebook::jni;
namespace facebook {
namespace react {
ExecutorToken JExecutorToken::getExecutorToken(alias_ref<JExecutorToken::javaobject> jobj) {
std::lock_guard<std::mutex> guard(createTokenGuard_);
auto sharedOwner = owner_.lock();
if (!sharedOwner) {
sharedOwner = std::shared_ptr<PlatformExecutorToken>(new JExecutorTokenHolder(jobj));
owner_ = sharedOwner;
}
return ExecutorToken(sharedOwner);
}
local_ref<JExecutorToken::JavaPart> JExecutorToken::extractJavaPartFromToken(ExecutorToken token) {
return make_local(static_cast<JExecutorTokenHolder*>(token.getPlatformExecutorToken().get())->getJobj());
}
} }

View File

@ -1,61 +0,0 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#pragma once
#include <mutex>
#include <fb/fbjni.h>
#include <cxxreact/ExecutorToken.h>
#include <jschelpers/noncopyable.h>
using namespace facebook::jni;
namespace facebook {
namespace react {
class JExecutorTokenHolder;
class JExecutorToken : public HybridClass<JExecutorToken> {
public:
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/ExecutorToken;";
ExecutorToken getExecutorToken(alias_ref<JExecutorToken::javaobject> jobj);
static local_ref<JavaPart> extractJavaPartFromToken(ExecutorToken token);
private:
friend HybridBase;
friend JExecutorTokenHolder;
JExecutorToken() {}
std::weak_ptr<PlatformExecutorToken> owner_;
std::mutex createTokenGuard_;
};
/**
* Wrapper class to hold references to both the c++ and Java parts of the
* ExecutorToken object. The goal is to allow a reference to a token from either
* c++ or Java to keep both the Java object and c++ hybrid part alive. For c++
* references, we accomplish this by having JExecutorTokenHolder keep a reference
* to the Java object (which has a reference to the JExecutorToken hybrid part).
* For Java references, we allow the JExecutorTokenHolder to be deallocated if there
* are no references to it in c++ from a PlatformExecutorToken, but will dynamically
* create a new one in JExecutorToken.getExecutorToken if needed.
*/
class JExecutorTokenHolder : public PlatformExecutorToken, public noncopyable {
public:
explicit JExecutorTokenHolder(alias_ref<JExecutorToken::javaobject> jobj) :
jobj_(make_global(jobj)),
impl_(cthis(jobj)) {
}
JExecutorToken::javaobject getJobj() {
return jobj_.get();
}
private:
global_ref<JExecutorToken::javaobject> jobj_;
JExecutorToken *impl_;
};
} }

View File

@ -21,31 +21,6 @@ using namespace facebook::jni;
namespace facebook {
namespace react {
struct JApplication : JavaClass<JApplication> {
static constexpr auto kJavaDescriptor = "Landroid/app/Application;";
local_ref<JAssetManager::javaobject> getAssets() {
static auto method = javaClassStatic()->getMethod<JAssetManager::javaobject()>("getAssets");
return method(self());
}
};
struct JApplicationHolder : JavaClass<JApplicationHolder> {
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/common/ApplicationHolder;";
static local_ref<JApplication::javaobject> getApplication() {
static auto method = javaClassStatic()
->getStaticMethod<JApplication::javaobject()>("getApplication");
return method(javaClassStatic());
}
};
std::unique_ptr<const JSBigString> loadScriptFromAssets(const std::string& assetName) {
auto env = Environment::current();
auto assetManager = JApplicationHolder::getApplication()->getAssets();
return loadScriptFromAssets(AAssetManager_fromJava(env, assetManager.get()), assetName);
}
__attribute__((visibility("default")))
AAssetManager *extractAssetManager(alias_ref<JAssetManager::javaobject> assetManager) {
auto env = Environment::current();

View File

@ -15,12 +15,6 @@ struct JAssetManager : jni::JavaClass<JAssetManager> {
static constexpr auto kJavaDescriptor = "Landroid/content/res/AssetManager;";
};
/**
* Helper method for loading a JS script from Android assets without
* a reference to an AssetManager.
*/
std::unique_ptr<const JSBigString> loadScriptFromAssets(const std::string& assetName);
/**
* Helper method for loading JS script from android asset
*/

View File

@ -80,24 +80,17 @@ folly::dynamic JavaNativeModule::getConstants() {
}
}
bool JavaNativeModule::supportsWebWorkers() {
static auto supportsWebWorkersMethod =
wrapper_->getClass()->getMethod<jboolean()>("supportsWebWorkers");
return supportsWebWorkersMethod(wrapper_);
}
void JavaNativeModule::invoke(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) {
messageQueueThread_->runOnQueue([this, token, reactMethodId, params=std::move(params)] {
static auto invokeMethod = wrapper_->getClass()->
getMethod<void(JExecutorToken::javaobject, jint, ReadableNativeArray::javaobject)>("invoke");
invokeMethod(wrapper_,
JExecutorToken::extractJavaPartFromToken(token).get(),
static_cast<jint>(reactMethodId),
ReadableNativeArray::newObjectCxxArgs(std::move(params)).get());
void JavaNativeModule::invoke(unsigned int reactMethodId, folly::dynamic&& params) {
messageQueueThread_->runOnQueue([this, reactMethodId, params=std::move(params)] {
static auto invokeMethod = wrapper_->getClass()->getMethod<void(jint, ReadableNativeArray::javaobject)>("invoke");
invokeMethod(
wrapper_,
static_cast<jint>(reactMethodId),
ReadableNativeArray::newObjectCxxArgs(std::move(params)).get());
});
}
MethodCallResult JavaNativeModule::callSerializableNativeHook(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) {
MethodCallResult JavaNativeModule::callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic&& params) {
// TODO: evaluate whether calling through invoke is potentially faster
if (reactMethodId >= syncMethods_.size()) {
throw std::invalid_argument(
@ -106,7 +99,7 @@ MethodCallResult JavaNativeModule::callSerializableNativeHook(ExecutorToken toke
auto& method = syncMethods_[reactMethodId];
CHECK(method.hasValue() && method->isSyncHook()) << "Trying to invoke a asynchronous method as synchronous hook";
return method->invoke(instance_, wrapper_->getModule(), token, params);
return method->invoke(instance_, wrapper_->getModule(), params);
}
NewJavaNativeModule::NewJavaNativeModule(
@ -155,34 +148,28 @@ folly::dynamic NewJavaNativeModule::getConstants() {
}
}
bool NewJavaNativeModule::supportsWebWorkers() {
static auto supportsWebWorkersMethod =
wrapper_->getClass()->getMethod<jboolean()>("supportsWebWorkers");
return supportsWebWorkersMethod(wrapper_);
}
void NewJavaNativeModule::invoke(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) {
void NewJavaNativeModule::invoke(unsigned int reactMethodId, folly::dynamic&& params) {
if (reactMethodId >= methods_.size()) {
throw std::invalid_argument(
folly::to<std::string>("methodId ", reactMethodId, " out of range [0..", methods_.size(), "]"));
}
CHECK(!methods_[reactMethodId].isSyncHook()) << "Trying to invoke a synchronous hook asynchronously";
messageQueueThread_->runOnQueue([this, token, reactMethodId, params=std::move(params)] () mutable {
invokeInner(token, reactMethodId, std::move(params));
messageQueueThread_->runOnQueue([this, reactMethodId, params=std::move(params)] () mutable {
invokeInner(reactMethodId, std::move(params));
});
}
MethodCallResult NewJavaNativeModule::callSerializableNativeHook(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) {
MethodCallResult NewJavaNativeModule::callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic&& params) {
if (reactMethodId >= methods_.size()) {
throw std::invalid_argument(
folly::to<std::string>("methodId ", reactMethodId, " out of range [0..", methods_.size(), "]"));
}
CHECK(methods_[reactMethodId].isSyncHook()) << "Trying to invoke a asynchronous method as synchronous hook";
return invokeInner(token, reactMethodId, std::move(params));
return invokeInner(reactMethodId, std::move(params));
}
MethodCallResult NewJavaNativeModule::invokeInner(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) {
return methods_[reactMethodId].invoke(instance_, module_.get(), token, params);
MethodCallResult NewJavaNativeModule::invokeInner(unsigned int reactMethodId, folly::dynamic&& params) {
return methods_[reactMethodId].invoke(instance_, module_.get(), params);
}
jni::local_ref<JReflectMethod::javaobject> JMethodDescriptor::getMethod() const {

View File

@ -54,9 +54,8 @@ class JavaNativeModule : public NativeModule {
std::string getName() override;
folly::dynamic getConstants() override;
std::vector<MethodDescriptor> getMethods() override;
bool supportsWebWorkers() override;
void invoke(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) override;
MethodCallResult callSerializableNativeHook(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) override;
void invoke(unsigned int reactMethodId, folly::dynamic&& params) override;
MethodCallResult callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic&& params) override;
private:
std::weak_ptr<Instance> instance_;
@ -76,9 +75,8 @@ class NewJavaNativeModule : public NativeModule {
std::string getName() override;
std::vector<MethodDescriptor> getMethods() override;
folly::dynamic getConstants() override;
bool supportsWebWorkers() override;
void invoke(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) override;
MethodCallResult callSerializableNativeHook(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) override;
void invoke(unsigned int reactMethodId, folly::dynamic&& params) override;
MethodCallResult callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic&& params) override;
private:
std::weak_ptr<Instance> instance_;
@ -88,7 +86,7 @@ class NewJavaNativeModule : public NativeModule {
std::vector<MethodInvoker> methods_;
std::vector<MethodDescriptor> methodDescriptors_;
MethodCallResult invokeInner(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params);
MethodCallResult invokeInner(unsigned int reactMethodId, folly::dynamic&& params);
};
}}

View File

@ -1,32 +0,0 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#pragma once
#include <memory>
#include <jni.h>
#include <folly/Memory.h>
#include "JMessageQueueThread.h"
#include <react/MessageQueue.h>
using namespace facebook::jni;
namespace facebook {
namespace react {
class JniWebWorkers : public JavaClass<JniWebWorkers> {
public:
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/webworkers/WebWorkers;";
static std::unique_ptr<MessageQueue> createWebWorkerQueue(int id, MessageQueue* ownerMessageQueue) {
static auto method = JniWebWorkers::javaClassStatic()->
getStaticMethod<MessageQueueThread::javaobject(jint, MessageQueueThread::javaobject)>("createWebWorkerThread");
JMessageQueueThread* ownerMessageQueueThread = static_cast<JMessageQueueThread*>(ownerMessageQueue);
auto res = method(JniWebWorkers::javaClassStatic(), id, ownerMessageQueueThread->jobj());
return folly::make_unique<JMessageQueueThread>(res);
}
};
} }

View File

@ -7,14 +7,16 @@
#endif
#include <cxxreact/CxxNativeModule.h>
#include <fb/fbjni.h>
#include "JCallback.h"
#include "JExecutorToken.h"
#include "ReadableNativeArray.h"
#include "ReadableNativeMap.h"
#include "WritableNativeArray.h"
#include "WritableNativeMap.h"
using namespace facebook::jni;
namespace facebook {
namespace react {
@ -22,10 +24,10 @@ namespace {
using dynamic_iterator = folly::dynamic::const_iterator;
struct JPromiseImpl : public jni::JavaClass<JPromiseImpl> {
struct JPromiseImpl : public JavaClass<JPromiseImpl> {
constexpr static auto kJavaDescriptor = "Lcom/facebook/react/bridge/PromiseImpl;";
static jni::local_ref<javaobject> create(jni::local_ref<JCallback::javaobject> resolve, jni::local_ref<JCallback::javaobject> reject) {
static local_ref<javaobject> create(local_ref<JCallback::javaobject> resolve, local_ref<JCallback::javaobject> reject) {
return newInstance(resolve, reject);
}
};
@ -44,18 +46,18 @@ jdouble extractDouble(const folly::dynamic& value) {
}
}
jni::local_ref<JCallbackImpl::jhybridobject> extractCallback(std::weak_ptr<Instance>& instance, ExecutorToken token, const folly::dynamic& value) {
local_ref<JCallbackImpl::jhybridobject> extractCallback(std::weak_ptr<Instance>& instance, const folly::dynamic& value) {
if (value.isNull()) {
return jni::local_ref<JCallbackImpl::jhybridobject>(nullptr);
return local_ref<JCallbackImpl::jhybridobject>(nullptr);
} else {
return JCallbackImpl::newObjectCxxArgs(makeCallback(instance, token, value));
return JCallbackImpl::newObjectCxxArgs(makeCallback(instance, value));
}
}
jni::local_ref<JPromiseImpl::javaobject> extractPromise(std::weak_ptr<Instance>& instance, ExecutorToken token, dynamic_iterator& it, dynamic_iterator& end) {
auto resolve = extractCallback(instance, token, *it++);
local_ref<JPromiseImpl::javaobject> extractPromise(std::weak_ptr<Instance>& instance, dynamic_iterator& it, dynamic_iterator& end) {
auto resolve = extractCallback(instance, *it++);
CHECK(it != end);
auto reject = extractCallback(instance, token, *it++);
auto reject = extractCallback(instance, *it++);
return JPromiseImpl::create(resolve, reject);
}
@ -74,14 +76,11 @@ bool isNullable(char type) {
}
}
jvalue extract(std::weak_ptr<Instance>& instance, ExecutorToken token, char type, dynamic_iterator& it, dynamic_iterator& end) {
jvalue extract(std::weak_ptr<Instance>& instance, char type, dynamic_iterator& it, dynamic_iterator& end) {
CHECK(it != end);
jvalue value;
if (type == 'P') {
value.l = extractPromise(instance, token, it, end).release();
return value;
} else if (type == 'T') {
value.l = JExecutorToken::extractJavaPartFromToken(token).release();
value.l = extractPromise(instance, it, end).release();
return value;
}
@ -117,7 +116,7 @@ jvalue extract(std::weak_ptr<Instance>& instance, ExecutorToken token, char type
value.l = JDouble::valueOf(extractDouble(arg)).release();
break;
case 'S':
value.l = jni::make_jstring(arg.getString().c_str()).release();
value.l = make_jstring(arg.getString().c_str()).release();
break;
case 'A':
value.l = ReadableNativeArray::newObjectCxxArgs(arg).release();
@ -126,7 +125,7 @@ jvalue extract(std::weak_ptr<Instance>& instance, ExecutorToken token, char type
value.l = ReadableNativeMap::newObjectCxxArgs(arg).release();
break;
case 'X':
value.l = extractCallback(instance, token, arg).release();
value.l = extractCallback(instance, arg).release();
break;
default:
LOG(FATAL) << "Unknown param type: " << type;
@ -138,8 +137,6 @@ std::size_t countJsArgs(const std::string& signature) {
std::size_t count = 0;
for (char c : signature) {
switch (c) {
case 'T':
break;
case 'P':
count += 2;
break;
@ -153,7 +150,7 @@ std::size_t countJsArgs(const std::string& signature) {
}
MethodInvoker::MethodInvoker(jni::alias_ref<JReflectMethod::javaobject> method, std::string signature, std::string traceName, bool isSync)
MethodInvoker::MethodInvoker(alias_ref<JReflectMethod::javaobject> method, std::string signature, std::string traceName, bool isSync)
: method_(method->getMethodID()),
signature_(signature),
jsArgCount_(countJsArgs(signature) -2),
@ -163,7 +160,7 @@ MethodInvoker::MethodInvoker(jni::alias_ref<JReflectMethod::javaobject> method,
CHECK(isSync_ || signature_.at(0) == 'v') << "Non-sync hooks cannot have a non-void return type";
}
MethodCallResult MethodInvoker::invoke(std::weak_ptr<Instance>& instance, jni::alias_ref<JBaseJavaModule::javaobject> module, ExecutorToken token, const folly::dynamic& params) {
MethodCallResult MethodInvoker::invoke(std::weak_ptr<Instance>& instance, alias_ref<JBaseJavaModule::javaobject> module, const folly::dynamic& params) {
#ifdef WITH_FBSYSTRACE
fbsystrace::FbSystraceSection s(
TRACE_TAG_REACT_CXX_BRIDGE,
@ -176,29 +173,29 @@ MethodCallResult MethodInvoker::invoke(std::weak_ptr<Instance>& instance, jni::a
throw std::invalid_argument(folly::to<std::string>("expected ", jsArgCount_, " arguments, got ", params.size()));
}
auto env = jni::Environment::current();
auto env = Environment::current();
auto argCount = signature_.size() - 2;
jni::JniLocalScope scope(env, argCount);
JniLocalScope scope(env, argCount);
jvalue args[argCount];
std::transform(
signature_.begin() + 2,
signature_.end(),
args,
[&instance, token, it = params.begin(), end = params.end()] (char type) mutable {
return extract(instance, token, type, it, end);
[&instance, it = params.begin(), end = params.end()] (char type) mutable {
return extract(instance, type, it, end);
});
#define CASE_PRIMITIVE(KEY, TYPE, METHOD) \
case KEY: { \
auto result = env->Call ## METHOD ## MethodA(module.get(), method_, args); \
jni::throwPendingJniExceptionAsCppException(); \
throwPendingJniExceptionAsCppException(); \
return folly::dynamic(result); \
}
#define CASE_OBJECT(KEY, JNI_CLASS, ACTIONS) \
case KEY: { \
auto jobject = env->CallObjectMethodA(module.get(), method_, args); \
jni::throwPendingJniExceptionAsCppException(); \
throwPendingJniExceptionAsCppException(); \
auto result = adopt_local(static_cast<JNI_CLASS::javaobject>(jobject)); \
return folly::dynamic(result->ACTIONS); \
}
@ -207,7 +204,7 @@ MethodCallResult MethodInvoker::invoke(std::weak_ptr<Instance>& instance, jni::a
switch (returnType) {
case 'v':
env->CallVoidMethodA(module.get(), method_, args);
jni::throwPendingJniExceptionAsCppException();
throwPendingJniExceptionAsCppException();
return folly::none;
CASE_PRIMITIVE('z', jboolean, Boolean)

View File

@ -4,9 +4,9 @@
#include <vector>
#include <cxxreact/ExecutorToken.h>
#include <fb/fbjni.h>
#include <folly/dynamic.h>
#include <cxxreact/Executor.h>
namespace facebook {
namespace react {
@ -31,7 +31,7 @@ class MethodInvoker {
public:
MethodInvoker(jni::alias_ref<JReflectMethod::javaobject> method, std::string signature, std::string traceName, bool isSync);
MethodCallResult invoke(std::weak_ptr<Instance>& instance, jni::alias_ref<JBaseJavaModule::javaobject> module, ExecutorToken token, const folly::dynamic& params);
MethodCallResult invoke(std::weak_ptr<Instance>& instance, jni::alias_ref<JBaseJavaModule::javaobject> module, const folly::dynamic& params);
bool isSyncHook() const {
return isSync_;

View File

@ -12,9 +12,7 @@
#include "CxxModuleWrapper.h"
#include "JavaScriptExecutorHolder.h"
#include "JSCPerfLogging.h"
#include "JSLoader.h"
#include "ProxyExecutor.h"
#include "WebWorkers.h"
#include "JCallback.h"
#include "JSLogging.h"
@ -34,51 +32,6 @@ namespace react {
namespace {
static std::string getApplicationCacheDir(void) {
// Get the Application Context object
auto getApplicationClass = findClassLocal(
"com/facebook/react/common/ApplicationHolder");
auto getApplicationMethod = getApplicationClass->getStaticMethod<jobject()>(
"getApplication",
"()Landroid/app/Application;"
);
auto application = getApplicationMethod(getApplicationClass);
// Get getCacheDir() from the context
auto getDirMethod = findClassLocal("android/app/Application")
->getMethod<jobject()>("getCacheDir",
"()Ljava/io/File;"
);
auto dirObj = getDirMethod(application);
// Call getAbsolutePath() on the returned File object
auto getAbsolutePathMethod = findClassLocal("java/io/File")
->getMethod<jstring()>("getAbsolutePath");
return getAbsolutePathMethod(dirObj)->toStdString();
}
static JSValueRef nativePerformanceNow(
JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
size_t argumentCount,
const JSValueRef arguments[], JSValueRef *exception) {
static const int64_t NANOSECONDS_IN_SECOND = 1000000000LL;
static const int64_t NANOSECONDS_IN_MILLISECOND = 1000000LL;
// Since SystemClock.uptimeMillis() is commonly used for performance measurement in Java
// and uptimeMillis() internally uses clock_gettime(CLOCK_MONOTONIC),
// we use the same API here.
// We need that to make sure we use the same time system on both JS and Java sides.
// Links to the source code:
// https://android.googlesource.com/platform/frameworks/native/+/jb-mr1-release/libs/utils/SystemClock.cpp
// https://android.googlesource.com/platform/system/core/+/master/libutils/Timers.cpp
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
int64_t nano = now.tv_sec * NANOSECONDS_IN_SECOND + now.tv_nsec;
return Value::makeNumber(ctx, (nano / (double)NANOSECONDS_IN_MILLISECOND));
}
class JSCJavaScriptExecutorHolder : public HybridClass<JSCJavaScriptExecutorHolder,
JavaScriptExecutorHolder> {
public:
@ -87,8 +40,7 @@ class JSCJavaScriptExecutorHolder : public HybridClass<JSCJavaScriptExecutorHold
static local_ref<jhybriddata> initHybrid(alias_ref<jclass>, ReadableNativeArray* jscConfigArray) {
// See JSCJavaScriptExecutor.Factory() for the other side of this hack.
folly::dynamic jscConfigMap = jscConfigArray->consume()[0];
return makeCxxInstance(
std::make_shared<JSCExecutorFactory>(getApplicationCacheDir(), std::move(jscConfigMap)));
return makeCxxInstance(std::make_shared<JSCExecutorFactory>(std::move(jscConfigMap)));
}
static void registerNatives() {
@ -129,7 +81,6 @@ class ProxyJavaScriptExecutorHolder : public HybridClass<ProxyJavaScriptExecutor
using HybridBase::HybridBase;
};
class JReactMarker : public JavaClass<JReactMarker> {
public:
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/ReactMarker;";
@ -140,41 +91,59 @@ class JReactMarker : public JavaClass<JReactMarker> {
}
};
static JSValueRef nativePerformanceNow(
JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
size_t argumentCount,
const JSValueRef arguments[], JSValueRef *exception) {
static const int64_t NANOSECONDS_IN_SECOND = 1000000000LL;
static const int64_t NANOSECONDS_IN_MILLISECOND = 1000000LL;
// Since SystemClock.uptimeMillis() is commonly used for performance measurement in Java
// and uptimeMillis() internally uses clock_gettime(CLOCK_MONOTONIC),
// we use the same API here.
// We need that to make sure we use the same time system on both JS and Java sides.
// Links to the source code:
// https://android.googlesource.com/platform/frameworks/native/+/jb-mr1-release/libs/utils/SystemClock.cpp
// https://android.googlesource.com/platform/system/core/+/master/libutils/Timers.cpp
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
int64_t nano = now.tv_sec * NANOSECONDS_IN_SECOND + now.tv_nsec;
return Value::makeNumber(ctx, (nano / (double)NANOSECONDS_IN_MILLISECOND));
}
static void logPerfMarker(const ReactMarker::ReactMarkerId markerId) {
switch (markerId) {
case ReactMarker::RUN_JS_BUNDLE_START:
JReactMarker::logMarker("RUN_JS_BUNDLE_START");
break;
case ReactMarker::RUN_JS_BUNDLE_STOP:
JReactMarker::logMarker("RUN_JS_BUNDLE_END");
break;
case ReactMarker::CREATE_REACT_CONTEXT_STOP:
JReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
break;
case ReactMarker::JS_BUNDLE_STRING_CONVERT_START:
JReactMarker::logMarker("loadApplicationScript_startStringConvert");
break;
case ReactMarker::JS_BUNDLE_STRING_CONVERT_STOP:
JReactMarker::logMarker("loadApplicationScript_endStringConvert");
break;
case ReactMarker::NATIVE_REQUIRE_START:
case ReactMarker::NATIVE_REQUIRE_STOP:
// These are not used on Android.
break;
}
}
}
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
return initialize(vm, [] {
gloginit::initialize();
// Inject some behavior into react/
ReactMarker::logMarker = [](const ReactMarker::ReactMarkerId markerId) {
switch (markerId) {
case ReactMarker::RUN_JS_BUNDLE_START:
JReactMarker::logMarker("RUN_JS_BUNDLE_START");
break;
case ReactMarker::RUN_JS_BUNDLE_STOP:
JReactMarker::logMarker("RUN_JS_BUNDLE_END");
break;
case ReactMarker::CREATE_REACT_CONTEXT_STOP:
JReactMarker::logMarker("CREATE_REACT_CONTEXT_END");
break;
case ReactMarker::JS_BUNDLE_STRING_CONVERT_START:
JReactMarker::logMarker("loadApplicationScript_startStringConvert");
break;
case ReactMarker::JS_BUNDLE_STRING_CONVERT_STOP:
JReactMarker::logMarker("loadApplicationScript_endStringConvert");
break;
case ReactMarker::NATIVE_REQUIRE_START:
case ReactMarker::NATIVE_REQUIRE_STOP:
// These are not used on Android.
break;
}
};
WebWorkerUtil::createWebWorkerThread = WebWorkers::createWebWorkerThread;
WebWorkerUtil::loadScriptFromAssets =
[] (const std::string& assetName) {
return loadScriptFromAssets(assetName);
};
WebWorkerUtil::loadScriptFromNetworkSync = WebWorkers::loadScriptFromNetworkSync;
ReactMarker::logMarker = logPerfMarker;
PerfLogging::installNativeHooks = addNativePerfLoggingHooks;
JSNativeHooks::loggingHook = nativeLoggingHook;
JSNativeHooks::nowHook = nativePerformanceNow;

View File

@ -1,50 +0,0 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#pragma once
#include <fstream>
#include <memory>
#include <string>
#include <sstream>
#include <jni.h>
#include <folly/Memory.h>
#include "JMessageQueueThread.h"
using namespace facebook::jni;
namespace facebook {
namespace react {
class WebWorkers : public JavaClass<WebWorkers> {
public:
static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/webworkers/WebWorkers;";
static std::unique_ptr<JMessageQueueThread> createWebWorkerThread(int id, MessageQueueThread *ownerMessageQueueThread) {
static auto method = WebWorkers::javaClassStatic()->
getStaticMethod<JavaMessageQueueThread::javaobject(jint, JavaMessageQueueThread::javaobject)>("createWebWorkerThread");
auto res = method(WebWorkers::javaClassStatic(), id, static_cast<JMessageQueueThread*>(ownerMessageQueueThread)->jobj());
return folly::make_unique<JMessageQueueThread>(res);
}
static std::string loadScriptFromNetworkSync(const std::string& url, const std::string& tempfileName) {
static auto method = WebWorkers::javaClassStatic()->
getStaticMethod<void(jstring, jstring)>("downloadScriptToFileSync");
method(
WebWorkers::javaClassStatic(),
jni::make_jstring(url).get(),
jni::make_jstring(tempfileName).get());
std::ifstream tempFile(tempfileName);
if (!tempFile.good()) {
throw std::runtime_error("Didn't find worker script file at " + tempfileName);
}
std::stringstream buffer;
buffer << tempFile.rdbuf();
std::remove(tempfileName.c_str());
return buffer.str();
}
};
} }

View File

@ -71,14 +71,14 @@ public class BaseJavaModuleTest {
public void testCallMethodWithoutEnoughArgs() throws Exception {
int methodId = findMethod("regularMethod",mMethods);
Mockito.stub(mArguments.size()).toReturn(1);
mWrapper.invoke(null, methodId, mArguments);
mWrapper.invoke(methodId, mArguments);
}
@Test
public void testCallMethodWithEnoughArgs() {
int methodId = findMethod("regularMethod", mMethods);
Mockito.stub(mArguments.size()).toReturn(2);
mWrapper.invoke(null, methodId, mArguments);
mWrapper.invoke(methodId, mArguments);
}
@Test
@ -86,14 +86,14 @@ public class BaseJavaModuleTest {
// Promise block evaluates to 2 args needing to be passed from JS
int methodId = findMethod("asyncMethod", mMethods);
Mockito.stub(mArguments.size()).toReturn(3);
mWrapper.invoke(null, methodId, mArguments);
mWrapper.invoke(methodId, mArguments);
}
@Test
public void testCallSyncMethod() {
int methodId = findMethod("syncMethod", mMethods);
Mockito.stub(mArguments.size()).toReturn(2);
mWrapper.invoke(null, methodId, mArguments);
mWrapper.invoke(methodId, mArguments);
}
private static class MethodsModule extends BaseJavaModule {

View File

@ -16,7 +16,6 @@ LOCAL_SRC_FILES := \
JSCNativeModules.cpp \
JSCPerfStats.cpp \
JSCTracing.cpp \
JSCWebWorker.cpp \
JSIndexedRAMBundle.cpp \
MethodCall.cpp \
ModuleRegistry.cpp \

View File

@ -129,14 +129,11 @@ cxx_library(
CXXREACT_PUBLIC_HEADERS = [
"CxxNativeModule.h",
"Executor.h",
"ExecutorToken.h",
"ExecutorTokenFactory.h",
"Instance.h",
"JSBigString.h",
"JSBundleType.h",
"JSCExecutor.h",
"JSCNativeModules.h",
"JSCWebWorker.h",
"JSIndexedRAMBundle.h",
"JSModulesUnbundle.h",
"MessageQueueThread.h",

View File

@ -15,15 +15,15 @@ namespace facebook {
namespace react {
std::function<void(folly::dynamic)> makeCallback(
std::weak_ptr<Instance> instance, ExecutorToken token, const folly::dynamic& callbackId) {
std::weak_ptr<Instance> instance, const folly::dynamic& callbackId) {
if (!callbackId.isInt()) {
throw std::invalid_argument("Expected callback(s) as final argument");
}
auto id = callbackId.getInt();
return [winstance = std::move(instance), token, id](folly::dynamic args) {
return [winstance = std::move(instance), id](folly::dynamic args) {
if (auto instance = winstance.lock()) {
instance->callJSCallback(token, id, std::move(args));
instance->callJSCallback(id, std::move(args));
}
};
}
@ -75,12 +75,7 @@ folly::dynamic CxxNativeModule::getConstants() {
return constants;
}
bool CxxNativeModule::supportsWebWorkers() {
// TODO(andrews): web worker support in cxxmodules
return false;
}
void CxxNativeModule::invoke(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) {
void CxxNativeModule::invoke(unsigned int reactMethodId, folly::dynamic&& params) {
if (reactMethodId >= methods_.size()) {
throw std::invalid_argument(folly::to<std::string>("methodId ", reactMethodId,
" out of range [0..", methods_.size(), "]"));
@ -106,10 +101,10 @@ void CxxNativeModule::invoke(ExecutorToken token, unsigned int reactMethodId, fo
}
if (method.callbacks == 1) {
first = convertCallback(makeCallback(instance_, token, params[params.size() - 1]));
first = convertCallback(makeCallback(instance_, params[params.size() - 1]));
} else if (method.callbacks == 2) {
first = convertCallback(makeCallback(instance_, token, params[params.size() - 2]));
second = convertCallback(makeCallback(instance_, token, params[params.size() - 1]));
first = convertCallback(makeCallback(instance_, params[params.size() - 2]));
second = convertCallback(makeCallback(instance_, params[params.size() - 1]));
}
params.resize(params.size() - method.callbacks);
@ -146,8 +141,7 @@ void CxxNativeModule::invoke(ExecutorToken token, unsigned int reactMethodId, fo
});
}
MethodCallResult CxxNativeModule::callSerializableNativeHook(
ExecutorToken token, unsigned int hookId, folly::dynamic&& args) {
MethodCallResult CxxNativeModule::callSerializableNativeHook(unsigned int hookId, folly::dynamic&& args) {
if (hookId >= methods_.size()) {
throw std::invalid_argument(
folly::to<std::string>("methodId ", hookId, " out of range [0..", methods_.size(), "]"));

View File

@ -11,7 +11,7 @@ namespace react {
class Instance;
std::function<void(folly::dynamic)> makeCallback(
std::weak_ptr<Instance> instance, ExecutorToken token, const folly::dynamic& callbackId);
std::weak_ptr<Instance> instance, const folly::dynamic& callbackId);
class CxxNativeModule : public NativeModule {
public:
@ -27,10 +27,8 @@ public:
std::string getName() override;
std::vector<MethodDescriptor> getMethods() override;
folly::dynamic getConstants() override;
bool supportsWebWorkers() override;
void invoke(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) override;
MethodCallResult callSerializableNativeHook(
ExecutorToken token, unsigned int hookId, folly::dynamic&& args) override;
void invoke(unsigned int reactMethodId, folly::dynamic&& params) override;
MethodCallResult callSerializableNativeHook(unsigned int hookId, folly::dynamic&& args) override;
private:
void lazyInit();

View File

@ -38,10 +38,6 @@ class ExecutorDelegate {
public:
virtual ~ExecutorDelegate() {}
virtual void registerExecutor(std::unique_ptr<JSExecutor> executor,
std::shared_ptr<MessageQueueThread> queue) = 0;
virtual std::unique_ptr<JSExecutor> unregisterExecutor(JSExecutor& executor) = 0;
virtual std::shared_ptr<ModuleRegistry> getModuleRegistry() = 0;
virtual void callNativeModules(

View File

@ -1,54 +0,0 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#pragma once
#include <cxxreact/Executor.h>
namespace facebook {
namespace react {
/**
* This class exists so that we have a type for the shared_ptr on ExecutorToken
* that implements a virtual destructor.
*/
class PlatformExecutorToken {
public:
virtual ~PlatformExecutorToken() {}
};
/**
* Class corresponding to a JS VM that can call into native modules. This is
* passed to native modules to allow their JS module calls/callbacks to be
* routed back to the proper JS VM on the proper thread.
*/
class ExecutorToken {
public:
/**
* This should only be used by the implementation of the platform ExecutorToken.
* Do not use as a client of ExecutorToken.
*/
explicit ExecutorToken(std::shared_ptr<PlatformExecutorToken> platformToken) :
platformToken_(platformToken) {}
std::shared_ptr<PlatformExecutorToken> getPlatformExecutorToken() const {
return platformToken_;
}
bool operator==(const ExecutorToken& other) const {
return platformToken_.get() == other.platformToken_.get();
}
private:
std::shared_ptr<PlatformExecutorToken> platformToken_;
};
} }
namespace std {
template<>
struct hash<facebook::react::ExecutorToken> {
size_t operator()(const facebook::react::ExecutorToken& token) const {
return (size_t) token.getPlatformExecutorToken().get();
}
};
}

View File

@ -1,25 +0,0 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#pragma once
#include <cxxreact/Executor.h>
#include <cxxreact/ExecutorToken.h>
namespace facebook {
namespace react {
/**
* Class that knows how to create the platform-specific implementation
* of ExecutorToken.
*/
class ExecutorTokenFactory {
public:
virtual ~ExecutorTokenFactory() {}
/**
* Creates a new ExecutorToken.
*/
virtual ExecutorToken createExecutorToken() const = 0;
};
} }

View File

@ -128,20 +128,15 @@ void *Instance::getJavaScriptContext() {
return nativeToJsBridge_->getJavaScriptContext();
}
void Instance::callJSFunction(ExecutorToken token, std::string&& module, std::string&& method,
folly::dynamic&& params) {
void Instance::callJSFunction(std::string&& module, std::string&& method, folly::dynamic&& params) {
callback_->incrementPendingJSCalls();
nativeToJsBridge_->callFunction(token, std::move(module), std::move(method), std::move(params));
nativeToJsBridge_->callFunction(std::move(module), std::move(method), std::move(params));
}
void Instance::callJSCallback(ExecutorToken token, uint64_t callbackId, folly::dynamic&& params) {
void Instance::callJSCallback(uint64_t callbackId, folly::dynamic&& params) {
SystraceSection s("<callback>");
callback_->incrementPendingJSCalls();
nativeToJsBridge_->invokeCallback(token, (double) callbackId, std::move(params));
}
ExecutorToken Instance::getMainExecutorToken() {
return nativeToJsBridge_->getMainExecutorToken();
nativeToJsBridge_->invokeCallback((double) callbackId, std::move(params));
}
void Instance::handleMemoryPressureUiHidden() {

View File

@ -19,8 +19,6 @@ struct InstanceCallback {
virtual void onBatchComplete() = 0;
virtual void incrementPendingJSCalls() = 0;
virtual void decrementPendingJSCalls() = 0;
virtual ExecutorToken createExecutorToken() = 0;
virtual void onExecutorStopped(ExecutorToken) = 0;
};
class Instance {
@ -50,11 +48,9 @@ class Instance {
void stopProfiler(const std::string& title, const std::string& filename);
void setGlobalVariable(std::string propName, std::unique_ptr<const JSBigString> jsonValue);
void *getJavaScriptContext();
void callJSFunction(ExecutorToken token, std::string&& module, std::string&& method,
folly::dynamic&& params);
void callJSCallback(ExecutorToken token, uint64_t callbackId, folly::dynamic&& params);
MethodCallResult callSerializableNativeHook(ExecutorToken token, unsigned int moduleId,
unsigned int methodId, folly::dynamic&& args);
void callJSFunction(std::string&& module, std::string&& method, folly::dynamic&& params);
void callJSCallback(uint64_t callbackId, folly::dynamic&& params);
MethodCallResult callSerializableNativeHook(unsigned int moduleId, unsigned int methodId, folly::dynamic&& args);
// This method is experimental, and may be modified or removed.
template <typename T>
Value callFunctionSync(const std::string& module, const std::string& method, T&& args) {
@ -62,13 +58,12 @@ class Instance {
return nativeToJsBridge_->callFunctionSync(module, method, std::forward<T>(args));
}
ExecutorToken getMainExecutorToken();
void handleMemoryPressureUiHidden();
void handleMemoryPressureModerate();
void handleMemoryPressureCritical();
private:
void callNativeModules(ExecutorToken token, folly::dynamic&& calls, bool isEndOfBatch);
void callNativeModules(folly::dynamic&& calls, bool isEndOfBatch);
std::shared_ptr<InstanceCallback> callback_;
std::unique_ptr<NativeToJsBridge> nativeToJsBridge_;

View File

@ -132,16 +132,13 @@ static JSValueRef nativeInjectHMRUpdate(
std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(
std::shared_ptr<ExecutorDelegate> delegate, std::shared_ptr<MessageQueueThread> jsQueue) {
return std::unique_ptr<JSExecutor>(
new JSCExecutor(delegate, jsQueue, m_cacheDir, m_jscConfig));
return folly::make_unique<JSCExecutor>(delegate, jsQueue, m_jscConfig);
}
JSCExecutor::JSCExecutor(std::shared_ptr<ExecutorDelegate> delegate,
std::shared_ptr<MessageQueueThread> messageQueueThread,
const std::string& cacheDir,
const folly::dynamic& jscConfig) throw(JSException) :
m_delegate(delegate),
m_deviceCacheDir(cacheDir),
m_messageQueueThread(messageQueueThread),
m_nativeModules(delegate ? delegate->getModuleRegistry() : nullptr),
m_jscConfig(jscConfig) {
@ -154,52 +151,6 @@ JSCExecutor::JSCExecutor(std::shared_ptr<ExecutorDelegate> delegate,
}
}
JSCExecutor::JSCExecutor(
std::shared_ptr<ExecutorDelegate> delegate,
std::shared_ptr<MessageQueueThread> messageQueueThread,
int workerId,
JSCExecutor *owner,
std::string scriptURL,
std::unordered_map<std::string, std::string> globalObjAsJSON,
const folly::dynamic& jscConfig) :
m_delegate(delegate),
m_workerId(workerId),
m_owner(owner),
m_deviceCacheDir(owner->m_deviceCacheDir),
m_messageQueueThread(messageQueueThread),
m_nativeModules(delegate->getModuleRegistry()),
m_jscConfig(jscConfig) {
// We post initOnJSVMThread here so that the owner doesn't have to wait for
// initialization on its own thread
m_messageQueueThread->runOnQueue([this, scriptURL,
globalObjAsJSON=std::move(globalObjAsJSON)] () {
initOnJSVMThread();
installNativeHook<&JSCExecutor::nativePostMessage>("postMessage");
for (auto& it : globalObjAsJSON) {
setGlobalVariable(std::move(it.first),
folly::make_unique<JSBigStdString>(std::move(it.second)));
}
// Try to load the script from the network if script is a URL
// NB: For security, this will only work in debug builds
std::unique_ptr<const JSBigString> script;
if (scriptURL.find("http://") == 0 || scriptURL.find("https://") == 0) {
std::stringstream outfileBuilder;
outfileBuilder << m_deviceCacheDir << "/workerScript" << m_workerId << ".js";
script = folly::make_unique<JSBigStdString>(
WebWorkerUtil::loadScriptFromNetworkSync(scriptURL, outfileBuilder.str()));
} else {
// TODO(9604438): Protect against script does not exist
script = WebWorkerUtil::loadScriptFromAssets(scriptURL);
}
// TODO(9994180): Throw on error
loadApplicationScript(std::move(script), std::move(scriptURL));
});
}
JSCExecutor::~JSCExecutor() {
CHECK(*m_isDestroyed) << "JSCExecutor::destroy() must be called before its destructor!";
}
@ -260,11 +211,6 @@ void JSCExecutor::initOnJSVMThread() throw(JSException) {
installNativeHook<&JSCExecutor::nativeFlushQueueImmediate>("nativeFlushQueueImmediate");
installNativeHook<&JSCExecutor::nativeCallSyncHook>("nativeCallSyncHook");
// Webworker support
installNativeHook<&JSCExecutor::nativeStartWorker>("nativeStartWorker");
installNativeHook<&JSCExecutor::nativePostMessageToWorker>("nativePostMessageToWorker");
installNativeHook<&JSCExecutor::nativeTerminateWorker>("nativeTerminateWorker");
installGlobalFunction(m_context, "nativeLoggingHook", JSNativeHooks::loggingHook);
installGlobalFunction(m_context, "nativePerformanceNow", JSNativeHooks::nowHook);
@ -299,16 +245,6 @@ void JSCExecutor::initOnJSVMThread() throw(JSException) {
}
void JSCExecutor::terminateOnJSVMThread() {
// terminateOwnedWebWorker mutates m_ownedWorkers so collect all the workers
// to terminate first
std::vector<int> workerIds;
for (auto& it : m_ownedWorkers) {
workerIds.push_back(it.first);
}
for (int workerId : workerIds) {
terminateOwnedWebWorker(workerId);
}
m_nativeModules.reset();
#ifdef WITH_INSPECTOR
@ -635,115 +571,6 @@ void JSCExecutor::loadModule(uint32_t moduleId) {
evaluateScript(m_context, source, sourceUrl);
}
int JSCExecutor::addWebWorker(
std::string scriptURL,
JSValueRef workerRef,
JSValueRef globalObjRef) {
static std::atomic_int nextWorkerId(1);
int workerId = nextWorkerId++;
Object globalObj = Value(m_context, globalObjRef).asObject();
auto workerJscConfig = m_jscConfig;
workerJscConfig["isWebWorker"] = true;
std::shared_ptr<MessageQueueThread> workerMQT =
WebWorkerUtil::createWebWorkerThread(workerId, m_messageQueueThread.get());
std::unique_ptr<JSCExecutor> worker;
workerMQT->runOnQueueSync([this, &worker, &workerMQT, &scriptURL, &globalObj, workerId, &workerJscConfig] () {
worker.reset(new JSCExecutor(m_delegate, workerMQT, workerId, this, std::move(scriptURL),
globalObj.toJSONMap(), workerJscConfig));
});
Object workerObj = Value(m_context, workerRef).asObject();
workerObj.makeProtected();
JSCExecutor *workerPtr = worker.get();
std::shared_ptr<MessageQueueThread> sharedMessageQueueThread = worker->m_messageQueueThread;
m_delegate->registerExecutor(
std::move(worker),
std::move(sharedMessageQueueThread));
m_ownedWorkers.emplace(
std::piecewise_construct,
std::forward_as_tuple(workerId),
std::forward_as_tuple(workerPtr, std::move(workerObj)));
return workerId;
}
void JSCExecutor::postMessageToOwnedWebWorker(int workerId, JSValueRef message) {
auto worker = m_ownedWorkers.at(workerId).executor;
std::string msgString = Value(m_context, message).toJSONString();
std::shared_ptr<bool> isWorkerDestroyed = worker->m_isDestroyed;
worker->m_messageQueueThread->runOnQueue([isWorkerDestroyed, worker, msgString] () {
if (*isWorkerDestroyed) {
return;
}
worker->receiveMessageFromOwner(msgString);
});
}
void JSCExecutor::postMessageToOwner(JSValueRef msg) {
std::string msgString = Value(m_context, msg).toJSONString();
std::shared_ptr<bool> ownerIsDestroyed = m_owner->m_isDestroyed;
m_owner->m_messageQueueThread->runOnQueue([workerId=m_workerId, owner=m_owner, ownerIsDestroyed, msgString] () {
if (*ownerIsDestroyed) {
return;
}
owner->receiveMessageFromOwnedWebWorker(workerId, msgString);
});
}
void JSCExecutor::receiveMessageFromOwnedWebWorker(int workerId, const std::string& json) {
Object* workerObj;
try {
workerObj = &m_ownedWorkers.at(workerId).jsObj;
} catch (std::out_of_range& e) {
// Worker was already terminated
return;
}
Value onmessageValue = workerObj->getProperty("onmessage");
if (onmessageValue.isUndefined()) {
return;
}
JSValueRef args[] = { createMessageObject(json) };
onmessageValue.asObject().callAsFunction(1, args);
flush();
}
void JSCExecutor::receiveMessageFromOwner(const std::string& msgString) {
CHECK(m_owner) << "Received message in a Executor that doesn't have an owner!";
JSValueRef args[] = { createMessageObject(msgString) };
Value onmessageValue = Object::getGlobalObject(m_context).getProperty("onmessage");
onmessageValue.asObject().callAsFunction(1, args);
}
void JSCExecutor::terminateOwnedWebWorker(int workerId) {
auto& workerRegistration = m_ownedWorkers.at(workerId);
std::shared_ptr<MessageQueueThread> workerMQT = workerRegistration.executor->m_messageQueueThread;
m_ownedWorkers.erase(workerId);
workerMQT->runOnQueueSync([this, &workerMQT] {
workerMQT->quitSynchronous();
std::unique_ptr<JSExecutor> worker = m_delegate->unregisterExecutor(*this);
worker->destroy();
worker.reset();
});
}
Object JSCExecutor::createMessageObject(const std::string& msgJson) {
Value rebornJSMsg = Value::fromJSON(m_context, String(m_context, msgJson.c_str()));
Object messageObject = Object::create(m_context);
messageObject.setProperty("data", rebornJSMsg);
return messageObject;
}
// Native JS hooks
template<JSValueRef (JSCExecutor::*method)(size_t, const JSValueRef[])>
void JSCExecutor::installNativeHook(const char* name) {
@ -758,18 +585,6 @@ JSValueRef JSCExecutor::getNativeModule(JSObjectRef object, JSStringRef property
return m_nativeModules.getModule(m_context, propertyName);
}
JSValueRef JSCExecutor::nativePostMessage(
size_t argumentCount,
const JSValueRef arguments[]) {
if (argumentCount != 1) {
throw std::invalid_argument("Got wrong number of args");
}
JSValueRef msg = arguments[0];
postMessageToOwner(msg);
return Value::makeUndefined(m_context);
}
JSValueRef JSCExecutor::nativeRequire(
size_t argumentCount,
const JSValueRef arguments[]) {
@ -801,57 +616,6 @@ JSValueRef JSCExecutor::nativeFlushQueueImmediate(
return Value::makeUndefined(m_context);
}
JSValueRef JSCExecutor::nativeStartWorker(
size_t argumentCount,
const JSValueRef arguments[]) {
if (argumentCount != 3) {
throw std::invalid_argument("Got wrong number of args");
}
std::string scriptFile = Value(m_context, arguments[0]).toString().str();
JSValueRef worker = arguments[1];
JSValueRef globalObj = arguments[2];
int workerId = addWebWorker(scriptFile, worker, globalObj);
return Value::makeNumber(m_context, workerId);
}
JSValueRef JSCExecutor::nativePostMessageToWorker(
size_t argumentCount,
const JSValueRef arguments[]) {
if (argumentCount != 2) {
throw std::invalid_argument("Got wrong number of args");
}
double workerDouble = Value(m_context, arguments[0]).asNumber();
if (workerDouble != workerDouble) {
throw std::invalid_argument("Got invalid worker id");
}
postMessageToOwnedWebWorker((int) workerDouble, arguments[1]);
return Value::makeUndefined(m_context);
}
JSValueRef JSCExecutor::nativeTerminateWorker(
size_t argumentCount,
const JSValueRef arguments[]) {
if (argumentCount != 1) {
throw std::invalid_argument("Got wrong number of args");
}
double workerDouble = Value(m_context, arguments[0]).asNumber();
if (workerDouble != workerDouble) {
std::invalid_argument("Got invalid worker id");
}
terminateOwnedWebWorker((int) workerDouble);
return Value::makeUndefined(m_context);
}
JSValueRef JSCExecutor::nativeCallSyncHook(
size_t argumentCount,
const JSValueRef arguments[]) {

View File

@ -8,7 +8,6 @@
#include <unordered_map>
#include <cxxreact/Executor.h>
#include <cxxreact/ExecutorToken.h>
#include <cxxreact/JSCNativeModules.h>
#include <folly/Optional.h>
#include <folly/json.h>
@ -23,10 +22,9 @@ class MessageQueueThread;
class RN_EXPORT JSCExecutorFactory : public JSExecutorFactory {
public:
JSCExecutorFactory(const std::string& cacheDir, const folly::dynamic& jscConfig) :
m_cacheDir(cacheDir),
m_jscConfig(jscConfig) {}
virtual std::unique_ptr<JSExecutor> createJSExecutor(
JSCExecutorFactory(const folly::dynamic& jscConfig) :
m_jscConfig(jscConfig) {}
std::unique_ptr<JSExecutor> createJSExecutor(
std::shared_ptr<ExecutorDelegate> delegate,
std::shared_ptr<MessageQueueThread> jsQueue) override;
private:
@ -34,17 +32,6 @@ private:
folly::dynamic m_jscConfig;
};
class JSCExecutor;
class WorkerRegistration : public noncopyable {
public:
explicit WorkerRegistration(JSCExecutor* executor_, Object jsObj_) :
executor(executor_),
jsObj(std::move(jsObj_)) {}
JSCExecutor *executor;
Object jsObj;
};
template <typename T>
struct ValueEncoder;
@ -55,7 +42,6 @@ public:
*/
explicit JSCExecutor(std::shared_ptr<ExecutorDelegate> delegate,
std::shared_ptr<MessageQueueThread> messageQueueThread,
const std::string& cacheDir,
const folly::dynamic& jscConfig) throw(JSException);
~JSCExecutor() override;
@ -104,11 +90,7 @@ public:
private:
JSGlobalContextRef m_context;
std::shared_ptr<ExecutorDelegate> m_delegate;
int m_workerId = 0; // if this is a worker executor, this is non-zero
JSCExecutor *m_owner = nullptr; // if this is a worker executor, this is non-null
std::shared_ptr<bool> m_isDestroyed = std::shared_ptr<bool>(new bool(false));
std::unordered_map<int, WorkerRegistration> m_ownedWorkers;
std::string m_deviceCacheDir;
std::shared_ptr<MessageQueueThread> m_messageQueueThread;
std::unique_ptr<JSModulesUnbundle> m_unbundle;
JSCNativeModules m_nativeModules;
@ -120,18 +102,6 @@ private:
folly::Optional<Object> m_flushedQueueJS;
folly::Optional<Object> m_callFunctionReturnResultAndFlushedQueueJS;
/**
* WebWorker constructor. Must be invoked from thread this Executor will run on.
*/
JSCExecutor(
std::shared_ptr<ExecutorDelegate> delegate,
std::shared_ptr<MessageQueueThread> messageQueueThread,
int workerId,
JSCExecutor *owner,
std::string scriptURL,
std::unordered_map<std::string, std::string> globalObjAsJSON,
const folly::dynamic& jscConfig);
void initOnJSVMThread() throw(JSException);
// This method is experimental, and may be modified or removed.
Value callFunctionSyncWithValue(
@ -143,30 +113,10 @@ private:
void flushQueueImmediate(Value&&);
void loadModule(uint32_t moduleId);
int addWebWorker(std::string scriptURL, JSValueRef workerRef, JSValueRef globalObjRef);
void postMessageToOwnedWebWorker(int worker, JSValueRef message);
void postMessageToOwner(JSValueRef result);
void receiveMessageFromOwnedWebWorker(int workerId, const std::string& message);
void receiveMessageFromOwner(const std::string &msgString);
void terminateOwnedWebWorker(int worker);
Object createMessageObject(const std::string& msgData);
template<JSValueRef (JSCExecutor::*method)(size_t, const JSValueRef[])>
void installNativeHook(const char* name);
JSValueRef getNativeModule(JSObjectRef object, JSStringRef propertyName);
JSValueRef nativeStartWorker(
size_t argumentCount,
const JSValueRef arguments[]);
JSValueRef nativePostMessageToWorker(
size_t argumentCount,
const JSValueRef arguments[]);
JSValueRef nativeTerminateWorker(
size_t argumentCount,
const JSValueRef arguments[]);
JSValueRef nativePostMessage(
size_t argumentCount,
const JSValueRef arguments[]);
JSValueRef nativeRequire(
size_t argumentCount,
const JSValueRef arguments[]);

View File

@ -1,135 +0,0 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include "JSCWebWorker.h"
#include <condition_variable>
#include <mutex>
#include <unordered_map>
#include <folly/Memory.h>
#include <glog/logging.h>
#include <jschelpers/JSCHelpers.h>
#include <jschelpers/Value.h>
#include "MessageQueueThread.h"
#include "Platform.h"
#include "JSCUtils.h"
namespace facebook {
namespace react {
// TODO(9604425): thread safety
static std::unordered_map<JSContextRef, JSCWebWorker*> s_globalContextRefToJSCWebWorker;
JSCWebWorker::JSCWebWorker(int id, JSCWebWorkerOwner *owner, std::string scriptSrc) :
id_(id),
scriptName_(std::move(scriptSrc)),
owner_(owner) {
ownerMessageQueueThread_ = owner->getMessageQueueThread();
CHECK(ownerMessageQueueThread_) << "Owner MessageQueue must not be null";
workerMessageQueueThread_ = WebWorkerUtil::createWebWorkerThread(id, ownerMessageQueueThread_.get());
CHECK(workerMessageQueueThread_) << "Failed to create worker thread";
workerMessageQueueThread_->runOnQueue([this] () {
initJSVMAndLoadScript();
});
}
JSCWebWorker::~JSCWebWorker() {
CHECK(isTerminated()) << "Didn't terminate the web worker before releasing it!";;
}
void JSCWebWorker::postMessage(JSValueRef msg) {
std::string msgString = Value(owner_->getContext(), msg).toJSONString();
workerMessageQueueThread_->runOnQueue([this, msgString] () {
if (isTerminated()) {
return;
}
JSValueRef args[] = { createMessageObject(context_, msgString) };
Value onmessageValue = Object::getGlobalObject(context_).getProperty("onmessage");
onmessageValue.asObject().callAsFunction(1, args);
});
}
void JSCWebWorker::terminate() {
if (isTerminated()) {
return;
}
isTerminated_.store(true, std::memory_order_release);
workerMessageQueueThread_->runOnQueueSync([this] {
terminateOnWorkerThread();
});
}
void JSCWebWorker::terminateOnWorkerThread() {
s_globalContextRefToJSCWebWorker.erase(context_);
JSC_JSGlobalContextRelease(context_);
context_ = nullptr;
workerMessageQueueThread_->quitSynchronous();
}
bool JSCWebWorker::isTerminated() {
return isTerminated_.load(std::memory_order_acquire);
}
void JSCWebWorker::initJSVMAndLoadScript() {
CHECK(!isTerminated()) << "Worker was already finished!";
CHECK(!context_) << "Worker JS VM was already created!";
context_ = JSC_JSGlobalContextCreateInGroup(
false, // no support required for custom JSC
NULL, // use default JS 'global' object
NULL // create new group (i.e. new VM)
);
s_globalContextRefToJSCWebWorker[context_] = this;
// TODO(9604438): Protect against script does not exist
std::unique_ptr<const JSBigString> script = WebWorkerUtil::loadScriptFromAssets(scriptName_);
evaluateScript(context_, jsStringFromBigString(context_, *script), String(context_, scriptName_.c_str()));
installGlobalFunction(context_, "postMessage", nativePostMessage);
}
void JSCWebWorker::postMessageToOwner(JSValueRef msg) {
std::string msgString = Value(context_, msg).toJSONString();
ownerMessageQueueThread_->runOnQueue([this, msgString] () {
owner_->onMessageReceived(id_, msgString);
});
}
JSValueRef JSCWebWorker::nativePostMessage(
JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
size_t argumentCount,
const JSValueRef arguments[],
JSValueRef *exception) {
if (argumentCount != 1) {
*exception = Value::makeError(ctx, "postMessage got wrong number of arguments");
return Value::makeUndefined(ctx);
}
JSValueRef msg = arguments[0];
JSCWebWorker *webWorker = s_globalContextRefToJSCWebWorker.at(JSC_JSContextGetGlobalContext(ctx));
if (!webWorker->isTerminated()) {
webWorker->postMessageToOwner(msg);
}
return Value::makeUndefined(ctx);
}
/*static*/
Object JSCWebWorker::createMessageObject(JSContextRef context, const std::string& msgJson) {
Value rebornJSMsg = Value::fromJSON(context, String(context, msgJson.c_str()));
Object messageObject = Object::create(context);
messageObject.setProperty("data", rebornJSMsg);
return messageObject;
}
}
}

View File

@ -1,93 +0,0 @@
// Copyright 2004-present Facebook. All Rights Reserved.
#include <atomic>
#include <functional>
#include <mutex>
#include <string>
#include <thread>
#include <queue>
#include <jschelpers/JavaScriptCore.h>
#include <jschelpers/Value.h>
namespace facebook {
namespace react {
class MessageQueueThread;
/**
* A class that can own the lifecycle, receive messages from, and dispatch messages
* to JSCWebWorkers.
*/
class JSCWebWorkerOwner {
public:
/**
* Called when a worker has posted a message with `postMessage`.
*/
virtual void onMessageReceived(int workerId, const std::string& message) = 0;
virtual JSGlobalContextRef getContext() = 0;
/**
* Should return the owner's MessageQueueThread. Calls to onMessageReceived will be enqueued
* on this thread.
*/
virtual std::shared_ptr<MessageQueueThread> getMessageQueueThread() = 0;
};
/**
* Implementation of a web worker for JSC. The web worker should be created from the owner's
* (e.g., owning JSCExecutor instance) JS MessageQueueThread. The worker is responsible for
* creating its own MessageQueueThread.
*
* During operation, the JSCExecutor should call postMessage **from its own MessageQueueThread**
* to send messages to the worker. The worker will handle enqueueing those messages on its own
* MessageQueueThread as appropriate. When the worker has a message to post to the owner, it will
* enqueue a call to owner->onMessageReceived on the owner's MessageQueueThread.
*/
class JSCWebWorker {
public:
explicit JSCWebWorker(int id, JSCWebWorkerOwner *owner, std::string script);
~JSCWebWorker();
/**
* Post a message to be received by the worker on its thread. This must be called from
* ownerMessageQueueThread_.
*/
void postMessage(JSValueRef msg);
/**
* Synchronously quits the current worker and cleans up its VM.
*/
void terminate();
/**
* Whether terminate() has been called on this worker.
*/
bool isTerminated();
static Object createMessageObject(JSContextRef context, const std::string& msgData);
private:
void initJSVMAndLoadScript();
void postRunnableToEventLoop(std::function<void()>&& runnable);
void postMessageToOwner(JSValueRef result);
void terminateOnWorkerThread();
int id_;
std::atomic_bool isTerminated_ = ATOMIC_VAR_INIT(false);
std::string scriptName_;
JSCWebWorkerOwner *owner_ = nullptr;
std::shared_ptr<MessageQueueThread> ownerMessageQueueThread_;
std::unique_ptr<MessageQueueThread> workerMessageQueueThread_;
JSGlobalContextRef context_ = nullptr;
static JSValueRef nativePostMessage(
JSContextRef ctx,
JSObjectRef function,
JSObjectRef thisObject,
size_t argumentCount,
const JSValueRef arguments[],
JSValueRef *exception);
};
}
}

View File

@ -113,8 +113,7 @@ folly::Optional<ModuleConfig> ModuleRegistry::getConfig(const std::string& name)
}
}
void ModuleRegistry::callNativeMethod(ExecutorToken token, unsigned int moduleId, unsigned int methodId,
folly::dynamic&& params, int callId) {
void ModuleRegistry::callNativeMethod(unsigned int moduleId, unsigned int methodId, folly::dynamic&& params, int callId) {
if (moduleId >= modules_.size()) {
throw std::runtime_error(
folly::to<std::string>("moduleId ", moduleId, " out of range [0..", modules_.size(), ")"));
@ -126,15 +125,15 @@ void ModuleRegistry::callNativeMethod(ExecutorToken token, unsigned int moduleId
}
#endif
modules_[moduleId]->invoke(token, methodId, std::move(params));
modules_[moduleId]->invoke(methodId, std::move(params));
}
MethodCallResult ModuleRegistry::callSerializableNativeHook(ExecutorToken token, unsigned int moduleId, unsigned int methodId, folly::dynamic&& params) {
MethodCallResult ModuleRegistry::callSerializableNativeHook(unsigned int moduleId, unsigned int methodId, folly::dynamic&& params) {
if (moduleId >= modules_.size()) {
throw std::runtime_error(
folly::to<std::string>("moduleId ", moduleId, "out of range [0..", modules_.size(), ")"));
}
return modules_[moduleId]->callSerializableNativeHook(token, methodId, std::move(params));
return modules_[moduleId]->callSerializableNativeHook(methodId, std::move(params));
}
}}

View File

@ -5,7 +5,6 @@
#include <memory>
#include <vector>
#include <cxxreact/ExecutorToken.h>
#include <cxxreact/NativeModule.h>
#include <folly/Optional.h>
#include <folly/dynamic.h>
@ -36,9 +35,8 @@ class ModuleRegistry {
folly::Optional<ModuleConfig> getConfig(const std::string& name);
void callNativeMethod(ExecutorToken token, unsigned int moduleId, unsigned int methodId,
folly::dynamic&& params, int callId);
MethodCallResult callSerializableNativeHook(ExecutorToken token, unsigned int moduleId, unsigned int methodId, folly::dynamic&& args);
void callNativeMethod(unsigned int moduleId, unsigned int methodId, folly::dynamic&& params, int callId);
MethodCallResult callSerializableNativeHook(unsigned int moduleId, unsigned int methodId, folly::dynamic&& args);
private:
// This is always populated

View File

@ -5,8 +5,8 @@
#include <string>
#include <vector>
#include <cxxreact/ExecutorToken.h>
#include <folly/dynamic.h>
#include <cxxreact/Executor.h>
namespace facebook {
namespace react {
@ -27,11 +27,10 @@ class NativeModule {
virtual std::string getName() = 0;
virtual std::vector<MethodDescriptor> getMethods() = 0;
virtual folly::dynamic getConstants() = 0;
virtual bool supportsWebWorkers() = 0;
// TODO mhorowitz: do we need initialize()/onCatalystInstanceDestroy() in C++
// or only Java?
virtual void invoke(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& params) = 0;
virtual MethodCallResult callSerializableNativeHook(ExecutorToken token, unsigned int reactMethodId, folly::dynamic&& args) = 0;
virtual void invoke(unsigned int reactMethodId, folly::dynamic&& params) = 0;
virtual MethodCallResult callSerializableNativeHook(unsigned int reactMethodId, folly::dynamic&& args) = 0;
};
}

View File

@ -22,23 +22,11 @@ namespace react {
// This class manages calls from JS to native code.
class JsToNativeBridge : public react::ExecutorDelegate {
public:
JsToNativeBridge(NativeToJsBridge* nativeToJs,
std::shared_ptr<ModuleRegistry> registry,
JsToNativeBridge(std::shared_ptr<ModuleRegistry> registry,
std::shared_ptr<InstanceCallback> callback)
: m_nativeToJs(nativeToJs)
, m_registry(registry)
: m_registry(registry)
, m_callback(callback) {}
void registerExecutor(std::unique_ptr<JSExecutor> executor,
std::shared_ptr<MessageQueueThread> queue) override {
m_nativeToJs->registerExecutor(m_callback->createExecutorToken(), std::move(executor), queue);
}
std::unique_ptr<JSExecutor> unregisterExecutor(JSExecutor& executor) override {
m_callback->onExecutorStopped(m_nativeToJs->getTokenForExecutor(executor));
return m_nativeToJs->unregisterExecutor(executor);
}
std::shared_ptr<ModuleRegistry> getModuleRegistry() override {
return m_registry;
}
@ -48,15 +36,13 @@ public:
CHECK(m_registry || calls.empty()) <<
"native module calls cannot be completed with no native modules";
ExecutorToken token = m_nativeToJs->getTokenForExecutor(executor);
m_batchHadNativeModuleCalls = m_batchHadNativeModuleCalls || !calls.empty();
// An exception anywhere in here stops processing of the batch. This
// was the behavior of the Android bridge, and since exception handling
// terminates the whole bridge, there's not much point in continuing.
for (auto& call : parseMethodCalls(std::move(calls))) {
m_registry->callNativeMethod(
token, call.moduleId, call.methodId, std::move(call.arguments), call.callId);
m_registry->callNativeMethod(call.moduleId, call.methodId, std::move(call.arguments), call.callId);
}
if (isEndOfBatch) {
// onBatchComplete will be called on the native (module) queue, but
@ -73,18 +59,14 @@ public:
MethodCallResult callSerializableNativeHook(
JSExecutor& executor, unsigned int moduleId, unsigned int methodId,
folly::dynamic&& args) override {
ExecutorToken token = m_nativeToJs->getTokenForExecutor(executor);
return m_registry->callSerializableNativeHook(token, moduleId, methodId, std::move(args));
return m_registry->callSerializableNativeHook(moduleId, methodId, std::move(args));
}
private:
// These methods are always invoked from an Executor. The NativeToJsBridge
// keeps a reference to the root executor, and when destroy() is
// called, the Executors are all destroyed synchronously on their
// bridges. So, the bridge pointer will will always point to a
// valid object during a call to a delegate method from an exectuto.
NativeToJsBridge* m_nativeToJs;
// keeps a reference to the executor, and when destroy() is called, the
// executor is destroyed synchronously on its queue.
std::shared_ptr<ModuleRegistry> m_registry;
std::shared_ptr<InstanceCallback> m_callback;
bool m_batchHadNativeModuleCalls = false;
@ -96,14 +78,9 @@ NativeToJsBridge::NativeToJsBridge(
std::shared_ptr<MessageQueueThread> jsQueue,
std::shared_ptr<InstanceCallback> callback)
: m_destroyed(std::make_shared<bool>(false))
, m_mainExecutorToken(callback->createExecutorToken())
, m_delegate(std::make_shared<JsToNativeBridge>(this, registry, callback)) {
std::unique_ptr<JSExecutor> mainExecutor =
jsExecutorFactory->createJSExecutor(m_delegate, jsQueue);
// cached to avoid locked map lookup in the common case
m_mainExecutor = mainExecutor.get();
registerExecutor(m_mainExecutorToken, std::move(mainExecutor), jsQueue);
}
, m_delegate(std::make_shared<JsToNativeBridge>(registry, callback))
, m_executor(jsExecutorFactory->createJSExecutor(m_delegate, jsQueue))
, m_executorMessageQueueThread(std::move(jsQueue)) {}
// This must be called on the same thread on which the constructor was called.
NativeToJsBridge::~NativeToJsBridge() {
@ -116,7 +93,6 @@ void NativeToJsBridge::loadApplication(
std::unique_ptr<const JSBigString> startupScript,
std::string startupScriptSourceURL) {
runOnExecutorQueue(
m_mainExecutorToken,
[unbundleWrap=folly::makeMoveWrapper(std::move(unbundle)),
startupScript=folly::makeMoveWrapper(std::move(startupScript)),
startupScriptSourceURL=std::move(startupScriptSourceURL)]
@ -135,14 +111,13 @@ void NativeToJsBridge::loadApplicationSync(
std::unique_ptr<const JSBigString> startupScript,
std::string startupScriptSourceURL) {
if (unbundle) {
m_mainExecutor->setJSModulesUnbundle(std::move(unbundle));
m_executor->setJSModulesUnbundle(std::move(unbundle));
}
m_mainExecutor->loadApplicationScript(std::move(startupScript),
m_executor->loadApplicationScript(std::move(startupScript),
std::move(startupScriptSourceURL));
}
void NativeToJsBridge::callFunction(
ExecutorToken executorToken,
std::string&& module,
std::string&& method,
folly::dynamic&& arguments) {
@ -160,23 +135,24 @@ void NativeToJsBridge::callFunction(
std::string tracingName;
#endif
runOnExecutorQueue(executorToken, [module = std::move(module), method = std::move(method), arguments = std::move(arguments), tracingName = std::move(tracingName), systraceCookie] (JSExecutor* executor) {
#ifdef WITH_FBSYSTRACE
FbSystraceAsyncFlow::end(
TRACE_TAG_REACT_CXX_BRIDGE,
tracingName.c_str(),
systraceCookie);
SystraceSection s(tracingName.c_str());
#endif
runOnExecutorQueue([module = std::move(module), method = std::move(method), arguments = std::move(arguments), tracingName = std::move(tracingName), systraceCookie]
(JSExecutor* executor) {
#ifdef WITH_FBSYSTRACE
FbSystraceAsyncFlow::end(
TRACE_TAG_REACT_CXX_BRIDGE,
tracingName.c_str(),
systraceCookie);
SystraceSection s(tracingName.c_str());
#endif
// This is safe because we are running on the executor's thread: it won't
// destruct until after it's been unregistered (which we check above) and
// that will happen on this thread
executor->callFunction(module, method, arguments);
});
// This is safe because we are running on the executor's thread: it won't
// destruct until after it's been unregistered (which we check above) and
// that will happen on this thread
executor->callFunction(module, method, arguments);
});
}
void NativeToJsBridge::invokeCallback(ExecutorToken executorToken, double callbackId, folly::dynamic&& arguments) {
void NativeToJsBridge::invokeCallback(double callbackId, folly::dynamic&& arguments) {
int systraceCookie = -1;
#ifdef WITH_FBSYSTRACE
systraceCookie = m_systraceCookie++;
@ -186,24 +162,23 @@ void NativeToJsBridge::invokeCallback(ExecutorToken executorToken, double callba
systraceCookie);
#endif
runOnExecutorQueue(executorToken, [callbackId, arguments = std::move(arguments), systraceCookie] (JSExecutor* executor) {
#ifdef WITH_FBSYSTRACE
FbSystraceAsyncFlow::end(
TRACE_TAG_REACT_CXX_BRIDGE,
"<callback>",
systraceCookie);
SystraceSection s("NativeToJsBridge.invokeCallback");
#endif
runOnExecutorQueue([callbackId, arguments = std::move(arguments), systraceCookie]
(JSExecutor* executor) {
#ifdef WITH_FBSYSTRACE
FbSystraceAsyncFlow::end(
TRACE_TAG_REACT_CXX_BRIDGE,
"<callback>",
systraceCookie);
SystraceSection s("NativeToJsBridge.invokeCallback");
#endif
executor->invokeCallback(callbackId, arguments);
});
executor->invokeCallback(callbackId, arguments);
});
}
void NativeToJsBridge::setGlobalVariable(std::string propName,
std::unique_ptr<const JSBigString> jsonValue) {
runOnExecutorQueue(
m_mainExecutorToken,
[propName=std::move(propName), jsonValue=folly::makeMoveWrapper(std::move(jsonValue))]
runOnExecutorQueue([propName=std::move(propName), jsonValue=folly::makeMoveWrapper(std::move(jsonValue))]
(JSExecutor* executor) mutable {
executor->setGlobalVariable(propName, jsonValue.move());
});
@ -211,149 +186,72 @@ void NativeToJsBridge::setGlobalVariable(std::string propName,
void* NativeToJsBridge::getJavaScriptContext() {
// TODO(cjhopman): this seems unsafe unless we require that it is only called on the main js queue.
return m_mainExecutor->getJavaScriptContext();
return m_executor->getJavaScriptContext();
}
bool NativeToJsBridge::supportsProfiling() {
// Intentionally doesn't post to jsqueue. supportsProfiling() can be called from any thread.
return m_mainExecutor->supportsProfiling();
return m_executor->supportsProfiling();
}
void NativeToJsBridge::startProfiler(const std::string& title) {
runOnExecutorQueue(m_mainExecutorToken, [=] (JSExecutor* executor) {
runOnExecutorQueue([=] (JSExecutor* executor) {
executor->startProfiler(title);
});
}
void NativeToJsBridge::stopProfiler(const std::string& title, const std::string& filename) {
runOnExecutorQueue(m_mainExecutorToken, [=] (JSExecutor* executor) {
runOnExecutorQueue([=] (JSExecutor* executor) {
executor->stopProfiler(title, filename);
});
}
void NativeToJsBridge::handleMemoryPressureUiHidden() {
runOnExecutorQueue(m_mainExecutorToken, [=] (JSExecutor* executor) {
runOnExecutorQueue([=] (JSExecutor* executor) {
executor->handleMemoryPressureUiHidden();
});
}
void NativeToJsBridge::handleMemoryPressureModerate() {
runOnExecutorQueue(m_mainExecutorToken, [=] (JSExecutor* executor) {
runOnExecutorQueue([=] (JSExecutor* executor) {
executor->handleMemoryPressureModerate();
});
}
void NativeToJsBridge::handleMemoryPressureCritical() {
runOnExecutorQueue(m_mainExecutorToken, [=] (JSExecutor* executor) {
runOnExecutorQueue([=] (JSExecutor* executor) {
executor->handleMemoryPressureCritical();
});
}
ExecutorToken NativeToJsBridge::getMainExecutorToken() const {
return m_mainExecutorToken;
}
ExecutorToken NativeToJsBridge::registerExecutor(
ExecutorToken token,
std::unique_ptr<JSExecutor> executor,
std::shared_ptr<MessageQueueThread> messageQueueThread) {
std::lock_guard<std::mutex> registrationGuard(m_registrationMutex);
CHECK(m_executorTokenMap.find(executor.get()) == m_executorTokenMap.end())
<< "Trying to register an already registered executor!";
m_executorTokenMap.emplace(executor.get(), token);
m_executorMap.emplace(
token,
ExecutorRegistration(std::move(executor), messageQueueThread));
return token;
}
std::unique_ptr<JSExecutor> NativeToJsBridge::unregisterExecutor(JSExecutor& executor) {
std::unique_ptr<JSExecutor> ret;
{
std::lock_guard<std::mutex> registrationGuard(m_registrationMutex);
auto it = m_executorTokenMap.find(&executor);
CHECK(it != m_executorTokenMap.end())
<< "Trying to unregister an executor that was never registered!";
auto it2 = m_executorMap.find(it->second);
ret = std::move(it2->second.executor_);
m_executorTokenMap.erase(it);
m_executorMap.erase(it2);
}
return ret;
}
MessageQueueThread* NativeToJsBridge::getMessageQueueThread(const ExecutorToken& executorToken) {
std::lock_guard<std::mutex> registrationGuard(m_registrationMutex);
auto it = m_executorMap.find(executorToken);
if (it == m_executorMap.end()) {
return nullptr;
}
return it->second.messageQueueThread_.get();
}
JSExecutor* NativeToJsBridge::getExecutor(const ExecutorToken& executorToken) {
std::lock_guard<std::mutex> registrationGuard(m_registrationMutex);
auto it = m_executorMap.find(executorToken);
if (it == m_executorMap.end()) {
return nullptr;
}
return it->second.executor_.get();
}
ExecutorToken NativeToJsBridge::getTokenForExecutor(JSExecutor& executor) {
std::lock_guard<std::mutex> registrationGuard(m_registrationMutex);
return m_executorTokenMap.at(&executor);
}
void NativeToJsBridge::destroy() {
auto* executorMessageQueueThread = getMessageQueueThread(m_mainExecutorToken);
// All calls made through runOnExecutorQueue have an early exit if
// m_destroyed is true. Setting this before the runOnQueueSync will cause
// pending work to be cancelled and we won't have to wait for it.
*m_destroyed = true;
executorMessageQueueThread->runOnQueueSync([this, executorMessageQueueThread] {
m_mainExecutor->destroy();
executorMessageQueueThread->quitSynchronous();
m_delegate->unregisterExecutor(*m_mainExecutor);
m_mainExecutor = nullptr;
m_executorMessageQueueThread->runOnQueueSync([this] {
m_executor->destroy();
m_executorMessageQueueThread->quitSynchronous();
m_executor = nullptr;
});
}
void NativeToJsBridge::runOnExecutorQueue(ExecutorToken executorToken, std::function<void(JSExecutor*)> task) {
void NativeToJsBridge::runOnExecutorQueue(std::function<void(JSExecutor*)> task) {
if (*m_destroyed) {
return;
}
auto executorMessageQueueThread = getMessageQueueThread(executorToken);
if (executorMessageQueueThread == nullptr) {
LOG(WARNING) << "Dropping JS action for executor that has been unregistered...";
return;
}
std::shared_ptr<bool> isDestroyed = m_destroyed;
executorMessageQueueThread->runOnQueue([this, isDestroyed, executorToken, task=std::move(task)] {
m_executorMessageQueueThread->runOnQueue([this, isDestroyed, task=std::move(task)] {
if (*isDestroyed) {
return;
}
JSExecutor *executor = getExecutor(executorToken);
if (executor == nullptr) {
LOG(WARNING) << "Dropping JS call for executor that has been unregistered...";
return;
}
// The executor is guaranteed to be valid for the duration of the task because:
// 1. the executor is only destroyed after it is unregistered
// 2. the executor is unregistered on this queue
// 3. we just confirmed that the executor hasn't been unregistered above
task(executor);
task(m_executor.get());
});
}

View File

@ -8,7 +8,6 @@
#include <vector>
#include <cxxreact/Executor.h>
#include <cxxreact/ExecutorToken.h>
#include <cxxreact/JSCExecutor.h>
#include <cxxreact/JSModulesUnbundle.h>
#include <cxxreact/MessageQueueThread.h>
@ -26,22 +25,9 @@ struct dynamic;
namespace facebook {
namespace react {
struct InstanceCallback;
class ModuleRegistry;
class ExecutorRegistration {
public:
ExecutorRegistration(
std::unique_ptr<JSExecutor> executor,
std::shared_ptr<MessageQueueThread> executorMessageQueueThread) :
executor_(std::move(executor)),
messageQueueThread_(executorMessageQueueThread) {}
std::unique_ptr<JSExecutor> executor_;
std::shared_ptr<MessageQueueThread> messageQueueThread_;
};
class JsToNativeBridge;
struct InstanceCallback;
// This class manages calls from native code to JS. It also manages
// executors and their threads. All functions here can be called from
@ -68,16 +54,12 @@ public:
* Executes a function with the module ID and method ID and any additional
* arguments in JS.
*/
void callFunction(
ExecutorToken executorToken,
std::string&& module,
std::string&& method,
folly::dynamic&& args);
void callFunction(std::string&& module, std::string&& method, folly::dynamic&& args);
/**
* Invokes a callback with the cbID, and optional additional arguments in JS.
*/
void invokeCallback(ExecutorToken executorToken, double callbackId, folly::dynamic&& args);
void invokeCallback(double callbackId, folly::dynamic&& args);
/**
* Executes a JS method on the given executor synchronously, returning its
@ -98,10 +80,10 @@ public:
" after bridge is destroyed"));
}
JSCExecutor *jscExecutor = dynamic_cast<JSCExecutor*>(m_mainExecutor);
JSCExecutor *jscExecutor = dynamic_cast<JSCExecutor*>(m_executor.get());
if (!jscExecutor) {
throw std::invalid_argument(
folly::to<std::string>("Executor type ", typeid(*m_mainExecutor).name(),
folly::to<std::string>("Executor type ", typeid(m_executor.get()).name(),
" does not support synchronous calls"));
}
@ -131,56 +113,25 @@ public:
void handleMemoryPressureModerate();
void handleMemoryPressureCritical();
/**
* Returns the ExecutorToken corresponding to the main JSExecutor.
*/
ExecutorToken getMainExecutorToken() const;
/**
* Synchronously tears down the bridge and the main executor.
*/
void destroy();
private:
/**
* Registers the given JSExecutor which runs on the given MessageQueueThread
* with the NativeToJsBridge. Part of this registration is transfering
* ownership of this JSExecutor to the NativeToJsBridge for the duration of
* the registration.
*
* Returns a ExecutorToken which can be used to refer to this JSExecutor
* in the NativeToJsBridge.
*/
ExecutorToken registerExecutor(
ExecutorToken token,
std::unique_ptr<JSExecutor> executor,
std::shared_ptr<MessageQueueThread> executorMessageQueueThread);
/**
* Unregisters a JSExecutor that was previously registered with this NativeToJsBridge
* using registerExecutor.
*/
std::unique_ptr<JSExecutor> unregisterExecutor(JSExecutor& executorToken);
void runOnExecutorQueue(ExecutorToken token, std::function<void(JSExecutor*)> task);
void runOnExecutorQueue(std::function<void(JSExecutor*)> task);
// This is used to avoid a race condition where a proxyCallback gets queued
// after ~NativeToJsBridge(), on the same thread. In that case, the callback
// will try to run the task on m_callback which will have been destroyed
// within ~NativeToJsBridge(), thus causing a SIGSEGV.
std::shared_ptr<bool> m_destroyed;
JSExecutor* m_mainExecutor;
ExecutorToken m_mainExecutorToken;
std::shared_ptr<JsToNativeBridge> m_delegate;
std::unordered_map<JSExecutor*, ExecutorToken> m_executorTokenMap;
std::unordered_map<ExecutorToken, ExecutorRegistration> m_executorMap;
std::mutex m_registrationMutex;
std::unique_ptr<JSExecutor> m_executor;
std::shared_ptr<MessageQueueThread> m_executorMessageQueueThread;
#ifdef WITH_FBSYSTRACE
std::atomic_uint_least32_t m_systraceCookie = ATOMIC_VAR_INIT();
#endif
MessageQueueThread* getMessageQueueThread(const ExecutorToken& executorToken);
JSExecutor* getExecutor(const ExecutorToken& executorToken);
ExecutorToken getTokenForExecutor(JSExecutor& executor);
};
} }

View File

@ -9,12 +9,6 @@ namespace ReactMarker {
LogMarker logMarker;
};
namespace WebWorkerUtil {
WebWorkerQueueFactory createWebWorkerThread;
LoadScriptFromAssets loadScriptFromAssets;
LoadScriptFromNetworkSync loadScriptFromNetworkSync;
};
namespace PerfLogging {
InstallNativeHooks installNativeHooks;
};

View File

@ -27,17 +27,6 @@ using LogMarker = std::function<void(const ReactMarkerId)>;
extern LogMarker logMarker;
};
namespace WebWorkerUtil {
using WebWorkerQueueFactory = std::function<std::unique_ptr<MessageQueueThread>(int id, MessageQueueThread* ownerMessageQueue)>;
extern WebWorkerQueueFactory createWebWorkerThread;
using LoadScriptFromAssets = std::function<std::unique_ptr<const JSBigString>(const std::string& assetName)>;
extern LoadScriptFromAssets loadScriptFromAssets;
using LoadScriptFromNetworkSync = std::function<std::string(const std::string& url, const std::string& tempfileName)>;
extern LoadScriptFromNetworkSync loadScriptFromNetworkSync;
};
namespace PerfLogging {
using InstallNativeHooks = std::function<void(JSGlobalContextRef)>;
extern InstallNativeHooks installNativeHooks;