WebWorkers: Allow web worker owner to inject globals into worker, supply modified __fbBatchedBridgeConfig
Summary: Now that web workers are just JSCExecutors, we can move forward with adding native module support. The means we need to supply the worker with a correct __fbBatchedBridgeConfig global so it can appropriately set up its JS MessageQueue. Unfortunately, native modules can't support multiple JS execution contexts out-of-the-box, so we need to whitelist those modules that actually can be referenced from a webworker. In order to do that, we add the supportsWebWorkers call in NativeModule and the SupportsWebWorkers annotation for JS modules. These add metadata to __fbBatchedBridgeConfig which allows us to create a new config with only those modules that support web workers. Reviewed By: lexs Differential Revision: D2927091 fb-gh-sync-id: 9b47331253b277940b552e7d899198b5f0a3ed8c shipit-source-id: 9b47331253b277940b552e7d899198b5f0a3ed8c
This commit is contained in:
parent
febb1fbe13
commit
2b251638a6
|
@ -341,4 +341,9 @@ public abstract class BaseJavaModule implements NativeModule {
|
|||
public void onCatalystInstanceDestroy() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsWebWorkers() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,9 @@ public class JavaScriptModulesConfig {
|
|||
jg.writeEndObject();
|
||||
}
|
||||
jg.writeEndObject();
|
||||
if (registration.getModuleInterface().isAnnotationPresent(SupportsWebWorkers.class)) {
|
||||
jg.writeBooleanField("supportsWebWorkers", true);
|
||||
}
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
|
|
@ -72,4 +72,9 @@ public interface NativeModule {
|
|||
* Called before {CatalystInstance#onHostDestroy}
|
||||
*/
|
||||
void onCatalystInstanceDestroy();
|
||||
|
||||
/**
|
||||
* Whether this native module supports calls from web workers. Ignored for now.
|
||||
*/
|
||||
boolean supportsWebWorkers();
|
||||
}
|
||||
|
|
|
@ -65,6 +65,7 @@ public class NativeModuleRegistry {
|
|||
for (ModuleDefinition moduleDef : mModuleTable) {
|
||||
jg.writeObjectFieldStart(moduleDef.name);
|
||||
jg.writeNumberField("moduleID", moduleDef.id);
|
||||
jg.writeBooleanField("supportsWebWorkers", moduleDef.target.supportsWebWorkers());
|
||||
jg.writeObjectFieldStart("methods");
|
||||
for (int i = 0; i < moduleDef.methods.size(); i++) {
|
||||
MethodRegistration method = moduleDef.methods.get(i);
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
// 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 {
|
||||
}
|
|
@ -97,7 +97,8 @@ JSCExecutor::JSCExecutor(
|
|||
Bridge *bridge,
|
||||
int workerId,
|
||||
JSCExecutor *owner,
|
||||
const std::string& script) :
|
||||
const std::string& script,
|
||||
const std::unordered_map<std::string, std::string>& globalObjAsJSON) :
|
||||
m_bridge(bridge),
|
||||
m_workerId(workerId),
|
||||
m_owner(owner),
|
||||
|
@ -105,11 +106,15 @@ JSCExecutor::JSCExecutor(
|
|||
m_messageQueueThread(MessageQueues::getCurrentMessageQueueThread()) {
|
||||
// We post initOnJSVMThread here so that the owner doesn't have to wait for
|
||||
// initialization on its own thread
|
||||
m_messageQueueThread->runOnQueue([this, script] () {
|
||||
m_messageQueueThread->runOnQueue([this, script, globalObjAsJSON] () {
|
||||
initOnJSVMThread();
|
||||
|
||||
installGlobalFunction(m_context, "postMessage", nativePostMessage);
|
||||
|
||||
for (auto& it : globalObjAsJSON) {
|
||||
setGlobalVariable(it.first, it.second);
|
||||
}
|
||||
|
||||
// TODO(9604438): Protect against script does not exist
|
||||
std::string scriptSrc = WebWorkerUtil::loadScriptFromAssets(script);
|
||||
// TODO(9994180): Throw on error
|
||||
|
@ -302,14 +307,17 @@ void JSCExecutor::loadModule(uint32_t moduleId) {
|
|||
|
||||
int JSCExecutor::addWebWorker(
|
||||
const std::string& script,
|
||||
JSValueRef workerRef) {
|
||||
JSValueRef workerRef,
|
||||
JSValueRef globalObjRef) {
|
||||
static std::atomic_int nextWorkerId(1);
|
||||
int workerId = nextWorkerId++;
|
||||
|
||||
Object globalObj = Value(m_context, globalObjRef).asObject();
|
||||
|
||||
auto workerMQT = WebWorkerUtil::createWebWorkerThread(workerId, m_messageQueueThread.get());
|
||||
std::unique_ptr<JSCExecutor> worker;
|
||||
workerMQT->runOnQueueSync([this, &worker, &script, workerId] () {
|
||||
worker.reset(new JSCExecutor(m_bridge, workerId, this, script));
|
||||
workerMQT->runOnQueueSync([this, &worker, &script, &globalObj, workerId] () {
|
||||
worker.reset(new JSCExecutor(m_bridge, workerId, this, script, globalObj.toJSONMap()));
|
||||
});
|
||||
|
||||
Object workerObj = Value(m_context, workerRef).asObject();
|
||||
|
@ -487,7 +495,7 @@ JSValueRef JSCExecutor::nativeStartWorker(
|
|||
size_t argumentCount,
|
||||
const JSValueRef arguments[],
|
||||
JSValueRef *exception) {
|
||||
if (argumentCount != 2) {
|
||||
if (argumentCount != 3) {
|
||||
*exception = createErrorString(ctx, "Got wrong number of args");
|
||||
return JSValueMakeUndefined(ctx);
|
||||
}
|
||||
|
@ -495,6 +503,7 @@ JSValueRef JSCExecutor::nativeStartWorker(
|
|||
std::string scriptFile = Value(ctx, arguments[0]).toString().str();
|
||||
|
||||
JSValueRef worker = arguments[1];
|
||||
JSValueRef globalObj = arguments[2];
|
||||
|
||||
JSCExecutor *executor;
|
||||
try {
|
||||
|
@ -504,7 +513,7 @@ JSValueRef JSCExecutor::nativeStartWorker(
|
|||
return JSValueMakeUndefined(ctx);
|
||||
}
|
||||
|
||||
int workerId = executor->addWebWorker(scriptFile, worker);
|
||||
int workerId = executor->addWebWorker(scriptFile, worker, globalObj);
|
||||
|
||||
return JSValueMakeNumber(ctx, workerId);
|
||||
}
|
||||
|
|
|
@ -92,7 +92,8 @@ private:
|
|||
Bridge *bridge,
|
||||
int workerId,
|
||||
JSCExecutor *owner,
|
||||
const std::string& script);
|
||||
const std::string& script,
|
||||
const std::unordered_map<std::string, std::string>& globalObjAsJSON);
|
||||
|
||||
void initOnJSVMThread();
|
||||
void terminateOnJSVMThread();
|
||||
|
@ -100,7 +101,7 @@ private:
|
|||
void flushQueueImmediate(std::string queueJSON);
|
||||
void loadModule(uint32_t moduleId);
|
||||
|
||||
int addWebWorker(const std::string& script, JSValueRef workerRef);
|
||||
int addWebWorker(const std::string& script, JSValueRef workerRef, JSValueRef globalObjRef);
|
||||
void postMessageToOwnedWebWorker(int worker, JSValueRef message, JSValueRef *exn);
|
||||
void postMessageToOwner(JSValueRef result);
|
||||
void receiveMessageFromOwnedWebWorker(int workerId, const std::string& message);
|
||||
|
|
Loading…
Reference in New Issue