From 87476317f73e9114765a6a17aac1582268737879 Mon Sep 17 00:00:00 2001 From: karol-bisztyga Date: Fri, 20 Nov 2020 11:25:33 +0100 Subject: [PATCH 1/6] attempts - experimental --- .../NativeModules/NativeReanimatedModule.cpp | 74 ++++++++++++++++++- .../NativeReanimatedModuleSpec.cpp | 13 ++++ .../NativeModules/NativeReanimatedModule.h | 8 +- .../NativeReanimatedModuleSpec.h | 2 + Example/src/AnimatedStyleUpdateExample.js | 6 ++ ios/native/NativeProxy.mm | 23 ++++-- src/reanimated2/Hooks.js | 4 + 7 files changed, 118 insertions(+), 12 deletions(-) diff --git a/Common/cpp/NativeModules/NativeReanimatedModule.cpp b/Common/cpp/NativeModules/NativeReanimatedModule.cpp index a9bb968b846..dbfa6641d7b 100644 --- a/Common/cpp/NativeModules/NativeReanimatedModule.cpp +++ b/Common/cpp/NativeModules/NativeReanimatedModule.cpp @@ -10,6 +10,7 @@ #include "FrozenObject.h" #include #include +#include #include #include "JSIStoreValueUser.h" @@ -61,7 +62,8 @@ NativeReanimatedModule::NativeReanimatedModule(std::shared_ptr jsIn std::unique_ptr rt, std::shared_ptr errorHandler, std::function propObtainer, - PlatformDepMethodsHolder platformDepMethodsHolder) : NativeReanimatedModuleSpec(jsInvoker), + PlatformDepMethodsHolder platformDepMethodsHolder, + std::function()> runtimeObtainer) : NativeReanimatedModuleSpec(jsInvoker), runtime(std::move(rt)), mapperRegistry(new MapperRegistry()), eventHandlerRegistry(new EventHandlerRegistry()), @@ -69,7 +71,8 @@ NativeReanimatedModule::NativeReanimatedModule(std::shared_ptr jsIn propObtainer(propObtainer), errorHandler(errorHandler), workletsCache(new WorkletsCache()), - scheduler(scheduler) + scheduler(scheduler), + runtimeObtainer(runtimeObtainer) { auto requestAnimationFrame = [=](FrameCallback callback) { frameCallbacks.push_back(callback); @@ -190,6 +193,73 @@ jsi::Value NativeReanimatedModule::getViewProp(jsi::Runtime &rt, const jsi::Valu return jsi::Value::undefined(); } +jsi::Value NativeReanimatedModule::spawnThread(jsi::Runtime &rt, const jsi::Value &operations) { + Logger::log("HERE spawning thread..."); + jsi::Object object = operations.asObject(rt); + if (object.isFunction(rt)) { + if (!object.getProperty(rt, "__worklet").isUndefined()) { + + const size_t thread_id = std::hash{}(std::this_thread::get_id()); + std::string str = "here 1 thread id: "; + str += std::to_string(thread_id); + Logger::log(str.c_str()); + + std::unique_ptr customRuntime = runtimeObtainer(); + + std::string strutf8 = object.getProperty(rt, "asString").asString(rt).utf8(rt); + jsi::String jsis = jsi::String::createFromUtf8(*customRuntime, strutf8); + jsi::Value v(*customRuntime , jsis); + std::shared_ptr buf = std::make_shared(strutf8); + //jsi::Value val = customRuntime->evaluateJavaScript(buf, "experimental_call"); + + auto customGlobal = customRuntime->global();//.getPropertyAsFunction(rt, "eval"); + auto global = rt.global(); + + auto arr1 = global.getPropertyNames(rt); + auto arr2 = customGlobal.getPropertyNames(*customRuntime); + + // ...there's no eval on custom global... :/ + + //jsi::Object o = v.getObject(*customRuntime); // error + // auto pureCxxFun = object.asFunction(rt).getHostFunction(rt); // not working + + //jsi::Function jsiFunction = object.asFunction(*customRuntime); // error + //jsi::Function fff = jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "customFunc"), 0, warnFunction); + volatile int x = 9; +/* + jsi::Value val(std::move(operations)); + volatile int x = 9; + //Logger::log("calling worklet"); + //jsiFunction.call(rt, jsi::Value::undefined()); +/* + auto fun = [&rt, &jsiFunction]() -> void { + const size_t thread_id2 = std::hash{}(std::this_thread::get_id()); + std::string str = "here 2 thread id: "; + str += std::to_string(thread_id2); + Logger::log(str.c_str()); + // ... + + jsiFunction.call(rt, jsi::Value::undefined()); + }; + //std::thread t1(fun); + //t1.join(); + std::async(fun); + */ + } + } + /* + auto fun = [&rt, &thisValue, &res]() -> void { + const size_t thread_id2 = std::hash{}(std::this_thread::get_id()); + std::string str = "here 2 thread id: "; + str += std::to_string(thread_id2); + Logger::log(str.c_str()); + // ... + }; + std::thread t1(fun); + */ + return jsi::Value::undefined(); +} + void NativeReanimatedModule::onEvent(std::string eventName, std::string eventAsString) { try diff --git a/Common/cpp/NativeModules/NativeReanimatedModuleSpec.cpp b/Common/cpp/NativeModules/NativeReanimatedModuleSpec.cpp index 22927a73074..34adb2a96df 100644 --- a/Common/cpp/NativeModules/NativeReanimatedModuleSpec.cpp +++ b/Common/cpp/NativeModules/NativeReanimatedModuleSpec.cpp @@ -89,6 +89,16 @@ static jsi::Value __hostFunction_NativeReanimatedModuleSpec_getViewProp( return jsi::Value::undefined(); } +static jsi::Value __hostFunction_NativeReanimatedModuleSpec_spawnThread( + jsi::Runtime &rt, + TurboModule &turboModule, + const jsi::Value *args, + size_t count) { + static_cast(&turboModule) + ->spawnThread(rt, std::move(args[0])); + return jsi::Value::undefined(); +} + NativeReanimatedModuleSpec::NativeReanimatedModuleSpec(std::shared_ptr jsInvoker) : TurboModule("NativeReanimated", jsInvoker) { methodMap_["installCoreFunctions"] = MethodMetadata{ @@ -115,6 +125,9 @@ NativeReanimatedModuleSpec::NativeReanimatedModuleSpec(std::shared_ptr rt, std::shared_ptr errorHandler, std::function propObtainer, - PlatformDepMethodsHolder platformDepMethodsHolder); + PlatformDepMethodsHolder platformDepMethodsHolder, + std::function()> runtimeObtainer); virtual ~NativeReanimatedModule(); @@ -48,7 +49,9 @@ class NativeReanimatedModule : public NativeReanimatedModuleSpec void unregisterEventHandler(jsi::Runtime &rt, const jsi::Value ®istrationId) override; jsi::Value getViewProp(jsi::Runtime &rt, const jsi::Value &viewTag, const jsi::Value &propName, const jsi::Value &callback) override; - + + jsi::Value spawnThread(jsi::Runtime &rt, const jsi::Value &operations) override; + void onRender(double timestampMs); void onEvent(std::string eventName, std::string eventAsString); bool isAnyHandlerWaitingForEvent(std::string eventName); @@ -67,6 +70,7 @@ class NativeReanimatedModule : public NativeReanimatedModuleSpec std::vector frameCallbacks; bool renderRequested = false; std::function propObtainer; + std::function()> runtimeObtainer; public: std::shared_ptr errorHandler; std::shared_ptr workletsCache; diff --git a/Common/cpp/headers/NativeModules/NativeReanimatedModuleSpec.h b/Common/cpp/headers/NativeModules/NativeReanimatedModuleSpec.h index aa6eb42f05a..a67ed022506 100644 --- a/Common/cpp/headers/NativeModules/NativeReanimatedModuleSpec.h +++ b/Common/cpp/headers/NativeModules/NativeReanimatedModuleSpec.h @@ -40,6 +40,8 @@ class JSI_EXPORT NativeReanimatedModuleSpec : public TurboModule { // views virtual jsi::Value getViewProp(jsi::Runtime &rt, const jsi::Value &viewTag, const jsi::Value &propName, const jsi::Value &callback) = 0; + + virtual jsi::Value spawnThread(jsi::Runtime &rt, const jsi::Value &operations) = 0; }; } // namespace reanimated diff --git a/Example/src/AnimatedStyleUpdateExample.js b/Example/src/AnimatedStyleUpdateExample.js index b44a99d5bdc..3186f1f89b5 100644 --- a/Example/src/AnimatedStyleUpdateExample.js +++ b/Example/src/AnimatedStyleUpdateExample.js @@ -3,6 +3,7 @@ import Animated, { withTiming, useAnimatedStyle, Easing, + spawnThread, } from 'react-native-reanimated'; import { View, Button } from 'react-native'; import React from 'react'; @@ -21,6 +22,11 @@ export default function AnimatedStyleUpdateExample(props) { }; }); + spawnThread(() => { + 'worklet'; + console.log('huge calculations in progress...'); + }); + return ( scheduler(new REAIOSScheduler(jsInvoker)); std::unique_ptr animatedRuntime = facebook::jsc::makeJSCRuntime(); + std::string str = animatedRuntime->description(); + /**/ + auto runtimeObtainer = []() -> std::unique_ptr { + return facebook::jsc::makeJSCRuntime(); + }; + /**/ + std::shared_ptr errorHandler = std::make_shared(scheduler); std::shared_ptr module; @@ -132,14 +139,14 @@ static id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &v getCurrentTime, }; -module = std::make_shared(jsInvoker, - scheduler, - std::move(animatedRuntime), - errorHandler, - propObtainer, - platformDepMethodsHolder - ); - + module = std::make_shared(jsInvoker, + scheduler, + std::move(animatedRuntime), + errorHandler, + propObtainer, + platformDepMethodsHolder, + runtimeObtainer + ); scheduler->setModule(module); [reanimatedModule.nodesManager registerEventHandler:^(NSString *eventName, id event) { diff --git a/src/reanimated2/Hooks.js b/src/reanimated2/Hooks.js index 3ee7f949987..0dde7a565d7 100644 --- a/src/reanimated2/Hooks.js +++ b/src/reanimated2/Hooks.js @@ -647,3 +647,7 @@ export function useWorkletCallback(fun, deps) { export function createWorklet(fun) { return fun; } + +export function spawnThread(operations) { + return NativeReanimated.spawnThread(operations); +} From e7a7d04d60f3623956997b1f53e6e95ca3df9509 Mon Sep 17 00:00:00 2001 From: karol-bisztyga Date: Wed, 9 Dec 2020 14:10:21 +0100 Subject: [PATCH 2/6] fix native reanimated --- src/reanimated2/NativeReanimated.native.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/reanimated2/NativeReanimated.native.js b/src/reanimated2/NativeReanimated.native.js index df26dfbce56..a0d1a63f12b 100644 --- a/src/reanimated2/NativeReanimated.native.js +++ b/src/reanimated2/NativeReanimated.native.js @@ -42,6 +42,10 @@ const NativeReanimated = { getViewProp(viewTag, propName, callback) { return InnerNativeModule.getViewProp(viewTag, propName, callback); }, + + spawnThread(operations) { + return InnerNativeModule.spawnThread(operations); + }, }; export default NativeReanimated; From 3da39405c45b0e8dbe0932fc4621c9291728763c Mon Sep 17 00:00:00 2001 From: karol-bisztyga Date: Wed, 9 Dec 2020 15:41:11 +0100 Subject: [PATCH 3/6] run code on the custom runtime --- .../NativeModules/NativeReanimatedModule.cpp | 88 ++++++++++--------- 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/Common/cpp/NativeModules/NativeReanimatedModule.cpp b/Common/cpp/NativeModules/NativeReanimatedModule.cpp index dbfa6641d7b..09aa7a833b2 100644 --- a/Common/cpp/NativeModules/NativeReanimatedModule.cpp +++ b/Common/cpp/NativeModules/NativeReanimatedModule.cpp @@ -207,56 +207,58 @@ jsi::Value NativeReanimatedModule::spawnThread(jsi::Runtime &rt, const jsi::Valu std::unique_ptr customRuntime = runtimeObtainer(); std::string strutf8 = object.getProperty(rt, "asString").asString(rt).utf8(rt); - jsi::String jsis = jsi::String::createFromUtf8(*customRuntime, strutf8); - jsi::Value v(*customRuntime , jsis); - std::shared_ptr buf = std::make_shared(strutf8); - //jsi::Value val = customRuntime->evaluateJavaScript(buf, "experimental_call"); + jsi::String jsis = jsi::String::createFromUtf8(*customRuntime, strutf8); + jsi::Value v(*customRuntime , jsis); + std::shared_ptr buf = std::make_shared(strutf8); + //jsi::Value val = customRuntime->evaluateJavaScript(buf, "experimental_call"); + + auto customGlobal = customRuntime->global();//.getPropertyAsFunction(rt, "eval"); + auto global = rt.global(); + auto arr1 = global.getPropertyNames(rt); + std::string s = "------------------------- normal global " + std::to_string((int)arr1.size(rt)); + Logger::log(s.c_str()); + int count = 0; + for (int i=0;iglobal();//.getPropertyAsFunction(rt, "eval"); - auto global = rt.global(); + // EVAL TEST... + const char* code1 = "(function(){console.log('siema1'); return 66;})"; + const char* code2 = "(function(){console.log('siema2'); return 77;})"; - auto arr1 = global.getPropertyNames(rt); - auto arr2 = customGlobal.getPropertyNames(*customRuntime); + jsi::Function aaa = rt.global().getPropertyAsFunction(rt, "eval").call(rt, code1).getObject(rt).getFunction(rt); - // ...there's no eval on custom global... :/ + jsi::Function bbb = customRuntime->global().getPropertyAsFunction(*customRuntime, "eval").call(*customRuntime, code2).getObject(*customRuntime).getFunction(*customRuntime); + + try { + jsi::Value v1 = aaa.call(rt, nullptr, 0); + jsi::Value v2 = bbb.call(*customRuntime, nullptr, 0); + volatile int xa = 99; + } catch(std::exception &e) { + std::string se = e.what(); + Logger::log(se.c_str()); + } - //jsi::Object o = v.getObject(*customRuntime); // error - // auto pureCxxFun = object.asFunction(rt).getHostFunction(rt); // not working - - //jsi::Function jsiFunction = object.asFunction(*customRuntime); // error - //jsi::Function fff = jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "customFunc"), 0, warnFunction); - volatile int x = 9; -/* - jsi::Value val(std::move(operations)); volatile int x = 9; - //Logger::log("calling worklet"); - //jsiFunction.call(rt, jsi::Value::undefined()); -/* - auto fun = [&rt, &jsiFunction]() -> void { - const size_t thread_id2 = std::hash{}(std::this_thread::get_id()); - std::string str = "here 2 thread id: "; - str += std::to_string(thread_id2); - Logger::log(str.c_str()); - // ... - - jsiFunction.call(rt, jsi::Value::undefined()); - }; - //std::thread t1(fun); - //t1.join(); - std::async(fun); - */ } } - /* - auto fun = [&rt, &thisValue, &res]() -> void { - const size_t thread_id2 = std::hash{}(std::this_thread::get_id()); - std::string str = "here 2 thread id: "; - str += std::to_string(thread_id2); - Logger::log(str.c_str()); - // ... - }; - std::thread t1(fun); - */ return jsi::Value::undefined(); } From cff9f2c780ad02c415ed00eb6a63462a081a9aa2 Mon Sep 17 00:00:00 2001 From: karol-bisztyga Date: Thu, 10 Dec 2020 13:37:49 +0100 Subject: [PATCH 4/6] run worklet on custom thread --- .../NativeModules/NativeReanimatedModule.cpp | 92 ++++++------------- Common/cpp/Registries/WorkletsCache.cpp | 11 +-- Common/cpp/Tools/RuntimeDecorator.cpp | 46 +++++----- .../NativeModules/NativeReanimatedModule.h | 9 ++ Common/cpp/headers/Registries/WorkletsCache.h | 1 + Common/cpp/headers/Tools/RuntimeDecorator.h | 1 + 6 files changed, 68 insertions(+), 92 deletions(-) diff --git a/Common/cpp/NativeModules/NativeReanimatedModule.cpp b/Common/cpp/NativeModules/NativeReanimatedModule.cpp index 09aa7a833b2..5735e1f1b43 100644 --- a/Common/cpp/NativeModules/NativeReanimatedModule.cpp +++ b/Common/cpp/NativeModules/NativeReanimatedModule.cpp @@ -196,71 +196,37 @@ jsi::Value NativeReanimatedModule::getViewProp(jsi::Runtime &rt, const jsi::Valu jsi::Value NativeReanimatedModule::spawnThread(jsi::Runtime &rt, const jsi::Value &operations) { Logger::log("HERE spawning thread..."); jsi::Object object = operations.asObject(rt); - if (object.isFunction(rt)) { - if (!object.getProperty(rt, "__worklet").isUndefined()) { - - const size_t thread_id = std::hash{}(std::this_thread::get_id()); - std::string str = "here 1 thread id: "; - str += std::to_string(thread_id); - Logger::log(str.c_str()); - - std::unique_ptr customRuntime = runtimeObtainer(); - - std::string strutf8 = object.getProperty(rt, "asString").asString(rt).utf8(rt); - jsi::String jsis = jsi::String::createFromUtf8(*customRuntime, strutf8); - jsi::Value v(*customRuntime , jsis); - std::shared_ptr buf = std::make_shared(strutf8); - //jsi::Value val = customRuntime->evaluateJavaScript(buf, "experimental_call"); - - auto customGlobal = customRuntime->global();//.getPropertyAsFunction(rt, "eval"); - auto global = rt.global(); - auto arr1 = global.getPropertyNames(rt); - std::string s = "------------------------- normal global " + std::to_string((int)arr1.size(rt)); - Logger::log(s.c_str()); - int count = 0; - for (int i=0;iglobal().getPropertyAsFunction(*customRuntime, "eval").call(*customRuntime, code2).getObject(*customRuntime).getFunction(*customRuntime); - - try { - jsi::Value v1 = aaa.call(rt, nullptr, 0); - jsi::Value v2 = bbb.call(*customRuntime, nullptr, 0); - volatile int xa = 99; - } catch(std::exception &e) { - std::string se = e.what(); - Logger::log(se.c_str()); - } - - volatile int x = 9; - } + + if (!object.isFunction(rt) || object.getProperty(rt, "__worklet").isUndefined()) { + errorHandler->setError("Function passed to spawnThread doesn't seem to be a worklet"); + errorHandler->raise(); + return jsi::Value::undefined(); } + std::string asString = "(" + object.getProperty(rt, "asString").asString(rt).utf8(rt) + ")"; + const int threadId = ++this->currentThreadId; + Th th = {asString, nullptr}; + this->threads.insert(std::make_pair(threadId, th)); + + auto job = [this, threadId]() { + Th th = this->threads.at(threadId); + std::unique_ptr customRuntime = runtimeObtainer(); + RuntimeDecorator::addLog(*customRuntime); + jsi::Function fun = workletsCache->functionFromString(*customRuntime, th.str); + jsi::Value result = jsi::Value::undefined(); + try { + result = fun.call(*customRuntime, nullptr, 0); + } + catch (std::exception &e) { + std::string str = e.what(); + errorHandler->setError(str); + errorHandler->raise(); + } + return result; + }; + + threads.at(threadId).thread = std::make_shared(job); return jsi::Value::undefined(); -} + } void NativeReanimatedModule::onEvent(std::string eventName, std::string eventAsString) { diff --git a/Common/cpp/Registries/WorkletsCache.cpp b/Common/cpp/Registries/WorkletsCache.cpp index 4cf01fe91c5..f8770253943 100644 --- a/Common/cpp/Registries/WorkletsCache.cpp +++ b/Common/cpp/Registries/WorkletsCache.cpp @@ -7,18 +7,15 @@ using namespace facebook; namespace reanimated { -jsi::Value eval(jsi::Runtime &rt, const char *code) { - return rt.global().getPropertyAsFunction(rt, "eval").call(rt, code); -} - -jsi::Function function(jsi::Runtime &rt, const std::string& code) { - return eval(rt, ("(" + code + ")").c_str()).getObject(rt).getFunction(rt); +jsi::Function WorkletsCache::functionFromString(jsi::Runtime &rt, const std::string &code) +{ + return rt.global().getPropertyAsFunction(rt, "eval").call(rt, ("(" + code + ")").c_str()).getObject(rt).getFunction(rt); } std::shared_ptr WorkletsCache::getFunction(jsi::Runtime &rt, std::shared_ptr frozenObj) { long long workletHash = frozenObj->map["__workletHash"]->numberValue; if (worklets.count(workletHash) == 0) { - jsi::Function fun = function(rt, frozenObj->map["asString"]->stringValue); + jsi::Function fun = functionFromString(rt, frozenObj->map["asString"]->stringValue); std::shared_ptr funPtr(new jsi::Function(std::move(fun))); worklets[workletHash] = funPtr; } diff --git a/Common/cpp/Tools/RuntimeDecorator.cpp b/Common/cpp/Tools/RuntimeDecorator.cpp index d5b43540a86..3e2419250f9 100644 --- a/Common/cpp/Tools/RuntimeDecorator.cpp +++ b/Common/cpp/Tools/RuntimeDecorator.cpp @@ -5,6 +5,29 @@ namespace reanimated { +void RuntimeDecorator::addLog(jsi::Runtime &rt) { + auto callback = []( + jsi::Runtime &rt, + const jsi::Value &thisValue, + const jsi::Value *args, + size_t count + ) -> jsi::Value { + const jsi::Value *value = &args[0]; + if (value->isString()) { + Logger::log(value->getString(rt).utf8(rt).c_str()); + } else if (value->isNumber()) { + Logger::log(value->getNumber()); + } else if (value->isUndefined()) { + Logger::log("undefined"); + } else { + Logger::log("unsupported value type"); + } + return jsi::Value::undefined(); + }; + jsi::Value log = jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "_log"), 1, callback); + rt.global().setProperty(rt, "_log", log); +} + void RuntimeDecorator::addNativeObjects(jsi::Runtime &rt, UpdaterFunction updater, RequestFrameFunction requestFrame, @@ -29,28 +52,6 @@ void RuntimeDecorator::addNativeObjects(jsi::Runtime &rt, rt.global().setProperty(rt, "jsThis", jsi::Value::undefined()); - auto callback = []( - jsi::Runtime &rt, - const jsi::Value &thisValue, - const jsi::Value *args, - size_t count - ) -> jsi::Value { - const jsi::Value *value = &args[0]; - if (value->isString()) { - Logger::log(value->getString(rt).utf8(rt).c_str()); - } else if (value->isNumber()) { - Logger::log(value->getNumber()); - } else if (value->isUndefined()) { - Logger::log("undefined"); - } else { - Logger::log("unsupported value type"); - } - return jsi::Value::undefined(); - }; - jsi::Value log = jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "_log"), 1, callback); - rt.global().setProperty(rt, "_log", log); - - auto clb = [updater]( jsi::Runtime &rt, const jsi::Value &thisValue, @@ -66,6 +67,7 @@ void RuntimeDecorator::addNativeObjects(jsi::Runtime &rt, jsi::Value updateProps = jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "_updateProps"), 2, clb); rt.global().setProperty(rt, "_updateProps", updateProps); + addLog(rt); auto clb2 = [requestFrame]( jsi::Runtime &rt, diff --git a/Common/cpp/headers/NativeModules/NativeReanimatedModule.h b/Common/cpp/headers/NativeModules/NativeReanimatedModule.h index f8f52ee0584..225ea274ca1 100644 --- a/Common/cpp/headers/NativeModules/NativeReanimatedModule.h +++ b/Common/cpp/headers/NativeModules/NativeReanimatedModule.h @@ -9,6 +9,8 @@ #include #include #include +#include +#include namespace reanimated { @@ -76,6 +78,13 @@ class NativeReanimatedModule : public NativeReanimatedModuleSpec std::shared_ptr workletsCache; std::shared_ptr valueSetter; std::shared_ptr scheduler; + + struct Th { + std::string str; + std::shared_ptr thread; + }; + int currentThreadId = 0; + std::unordered_map threads; }; } // namespace reanimated diff --git a/Common/cpp/headers/Registries/WorkletsCache.h b/Common/cpp/headers/Registries/WorkletsCache.h index 0ede04ce1c9..0047f57a1de 100644 --- a/Common/cpp/headers/Registries/WorkletsCache.h +++ b/Common/cpp/headers/Registries/WorkletsCache.h @@ -15,6 +15,7 @@ class FrozenObject; class WorkletsCache { std::unordered_map> worklets; public: + jsi::Function functionFromString(jsi::Runtime &rt, const std::string &code); std::shared_ptr getFunction(jsi::Runtime & rt, std::shared_ptr frozenObj); }; diff --git a/Common/cpp/headers/Tools/RuntimeDecorator.h b/Common/cpp/headers/Tools/RuntimeDecorator.h index 0b53361693f..c6356811bd9 100644 --- a/Common/cpp/headers/Tools/RuntimeDecorator.h +++ b/Common/cpp/headers/Tools/RuntimeDecorator.h @@ -18,6 +18,7 @@ class RuntimeDecorator { ScrollToFunction scrollTo, MeasuringFunction measure, TimeProviderFunction getCurrentTime); + static void addLog(jsi::Runtime &rt); }; } From 1a7df9022c7a71b2d72bc172136372a1bd3d0d3a Mon Sep 17 00:00:00 2001 From: karol-bisztyga Date: Mon, 21 Dec 2020 10:07:42 +0100 Subject: [PATCH 5/6] setting sv in custom thread works --- .../NativeModules/NativeReanimatedModule.cpp | 55 +++++++------ Common/cpp/Registries/WorkletsCache.cpp | 19 +++-- Common/cpp/SharedItems/FrozenObject.cpp | 4 +- Common/cpp/SharedItems/ShareableValue.cpp | 26 +++--- Common/cpp/Tools/RuntimeDecorator.cpp | 3 +- .../NativeModules/NativeReanimatedModule.h | 5 +- Common/cpp/headers/Registries/WorkletsCache.h | 3 +- Common/cpp/headers/SharedItems/FrozenObject.h | 3 +- .../cpp/headers/SharedItems/ShareableValue.h | 5 +- Example/src/AnimatedStyleUpdateExample.js | 81 +++++++++++++------ 10 files changed, 127 insertions(+), 77 deletions(-) diff --git a/Common/cpp/NativeModules/NativeReanimatedModule.cpp b/Common/cpp/NativeModules/NativeReanimatedModule.cpp index 5735e1f1b43..fcbf860b64c 100644 --- a/Common/cpp/NativeModules/NativeReanimatedModule.cpp +++ b/Common/cpp/NativeModules/NativeReanimatedModule.cpp @@ -194,7 +194,6 @@ jsi::Value NativeReanimatedModule::getViewProp(jsi::Runtime &rt, const jsi::Valu } jsi::Value NativeReanimatedModule::spawnThread(jsi::Runtime &rt, const jsi::Value &operations) { - Logger::log("HERE spawning thread..."); jsi::Object object = operations.asObject(rt); if (!object.isFunction(rt) || object.getProperty(rt, "__worklet").isUndefined()) { @@ -202,31 +201,37 @@ jsi::Value NativeReanimatedModule::spawnThread(jsi::Runtime &rt, const jsi::Valu errorHandler->raise(); return jsi::Value::undefined(); } - std::string asString = "(" + object.getProperty(rt, "asString").asString(rt).utf8(rt) + ")"; - const int threadId = ++this->currentThreadId; - Th th = {asString, nullptr}; - this->threads.insert(std::make_pair(threadId, th)); - - auto job = [this, threadId]() { - Th th = this->threads.at(threadId); - std::unique_ptr customRuntime = runtimeObtainer(); - RuntimeDecorator::addLog(*customRuntime); - jsi::Function fun = workletsCache->functionFromString(*customRuntime, th.str); - jsi::Value result = jsi::Value::undefined(); - try { - result = fun.call(*customRuntime, nullptr, 0); - } - catch (std::exception &e) { - std::string str = e.what(); - errorHandler->setError(str); - errorHandler->raise(); - } - return result; - }; - threads.at(threadId).thread = std::make_shared(job); - return jsi::Value::undefined(); - } + const int threadId = ++this->currentThreadId; + + std::shared_ptr workletShareable = ShareableValue::adapt(rt, operations, this, ValueType::UndefinedType, threadId); + + std::shared_ptr th = std::make_shared(); + this->threads.insert(std::make_pair(threadId, th)); + + auto job = [=]() { + std::unique_ptr customRuntime = runtimeObtainer(); + std::shared_ptr th = this->threads.at(threadId); + th->rt = std::move(customRuntime); + RuntimeDecorator::addLog(*th->rt); + jsi::Value result = jsi::Value::undefined(); + + jsi::Function func = workletShareable->getValue(*th->rt).asObject(*th->rt).asFunction(*th->rt); + std::shared_ptr funcPtr = std::make_shared(std::move(func)); + try { + result = funcPtr->callWithThis(*th->rt, *funcPtr); + } + catch (std::exception &e) { + std::string str = e.what(); + errorHandler->setError(str); + errorHandler->raise(); + } + return result; + }; + + threads.at(threadId)->thread = std::make_shared(job); + return jsi::Value::undefined(); +} void NativeReanimatedModule::onEvent(std::string eventName, std::string eventAsString) { diff --git a/Common/cpp/Registries/WorkletsCache.cpp b/Common/cpp/Registries/WorkletsCache.cpp index f8770253943..c704585b15f 100644 --- a/Common/cpp/Registries/WorkletsCache.cpp +++ b/Common/cpp/Registries/WorkletsCache.cpp @@ -7,17 +7,24 @@ using namespace facebook; namespace reanimated { -jsi::Function WorkletsCache::functionFromString(jsi::Runtime &rt, const std::string &code) -{ +jsi::Function WorkletsCache::functionFromString(jsi::Runtime &rt, const std::string &code) { return rt.global().getPropertyAsFunction(rt, "eval").call(rt, ("(" + code + ")").c_str()).getObject(rt).getFunction(rt); } -std::shared_ptr WorkletsCache::getFunction(jsi::Runtime &rt, std::shared_ptr frozenObj) { +std::shared_ptr WorkletsCache::obtainFunction(jsi::Runtime &rt, const std::string &code) { + jsi::Function fun = functionFromString(rt, code); + std::shared_ptr funPtr(new jsi::Function(std::move(fun))); + return std::move(funPtr); +} + +std::shared_ptr WorkletsCache::getFunction(jsi::Runtime &rt, std::shared_ptr frozenObj, const int customThreadId) { + if (customThreadId != -1) { + // worklets cache wouldn't work for custom threads as every time we have a different RT + return obtainFunction(rt, frozenObj->map["asString"]->stringValue); + } long long workletHash = frozenObj->map["__workletHash"]->numberValue; if (worklets.count(workletHash) == 0) { - jsi::Function fun = functionFromString(rt, frozenObj->map["asString"]->stringValue); - std::shared_ptr funPtr(new jsi::Function(std::move(fun))); - worklets[workletHash] = funPtr; + worklets[workletHash] = obtainFunction(rt, frozenObj->map["asString"]->stringValue); } return worklets[workletHash]; } diff --git a/Common/cpp/SharedItems/FrozenObject.cpp b/Common/cpp/SharedItems/FrozenObject.cpp index 9c2c2c3a5be..c08d12afb18 100644 --- a/Common/cpp/SharedItems/FrozenObject.cpp +++ b/Common/cpp/SharedItems/FrozenObject.cpp @@ -4,11 +4,11 @@ namespace reanimated { -FrozenObject::FrozenObject(jsi::Runtime &rt, const jsi::Object &object, NativeReanimatedModule *module) { +FrozenObject::FrozenObject(jsi::Runtime &rt, const jsi::Object &object, NativeReanimatedModule *module, const int customThreadId) : customThreadId(customThreadId) { auto propertyNames = object.getPropertyNames(rt); for (size_t i = 0, count = propertyNames.size(rt); i < count; i++) { auto propertyName = propertyNames.getValueAtIndex(rt, i).asString(rt); - map[propertyName.utf8(rt)] = ShareableValue::adapt(rt, object.getProperty(rt, propertyName), module); + map[propertyName.utf8(rt)] = ShareableValue::adapt(rt, object.getProperty(rt, propertyName), module, ValueType::UndefinedType, customThreadId); } } diff --git a/Common/cpp/SharedItems/ShareableValue.cpp b/Common/cpp/SharedItems/ShareableValue.cpp index 92401e37c24..e0d6ed927be 100644 --- a/Common/cpp/SharedItems/ShareableValue.cpp +++ b/Common/cpp/SharedItems/ShareableValue.cpp @@ -52,7 +52,7 @@ void ShareableValue::adaptCache(jsi::Runtime &rt, const jsi::Value &value) { } void ShareableValue::adapt(jsi::Runtime &rt, const jsi::Value &value, ValueType objectType) { - bool isRNRuntime = !(module->isUIRuntime(rt)); + bool isNotUIRuntime = !(module->isUIRuntime(rt)); if (value.isObject()) { jsi::Object object = value.asObject(rt); jsi::Value hiddenValue = object.getProperty(rt, HIDDEN_HOST_OBJECT_PROP); @@ -99,8 +99,8 @@ void ShareableValue::adapt(jsi::Runtime &rt, const jsi::Value &value, ValueType } else { // a worklet type = ValueType::WorkletFunctionType; - frozenObject = std::make_shared(rt, object, module); - if (isRNRuntime) { + frozenObject = std::make_shared(rt, object, module, customThreadId); + if (isNotUIRuntime) { addHiddenProperty(rt, createHost(rt, frozenObject), object, HIDDEN_HOST_OBJECT_PROP); } } @@ -124,8 +124,8 @@ void ShareableValue::adapt(jsi::Runtime &rt, const jsi::Value &value, ValueType } else { // create frozen object based on a copy of a given object type = ValueType::ObjectType; - frozenObject = std::make_shared(rt, object, module); - if (isRNRuntime) { + frozenObject = std::make_shared(rt, object, module, customThreadId); + if (isNotUIRuntime) { addHiddenProperty(rt, createHost(rt, frozenObject), object, HIDDEN_HOST_OBJECT_PROP); freeze(rt, object); } @@ -138,15 +138,15 @@ void ShareableValue::adapt(jsi::Runtime &rt, const jsi::Value &value, ValueType } } -std::shared_ptr ShareableValue::adapt(jsi::Runtime &rt, const jsi::Value &value, NativeReanimatedModule *module, ValueType valueType) { - auto sv = std::shared_ptr(new ShareableValue(module, module->scheduler)); +std::shared_ptr ShareableValue::adapt(jsi::Runtime &rt, const jsi::Value &value, NativeReanimatedModule *module, ValueType valueType, const int customThreadId) { + auto sv = std::shared_ptr(new ShareableValue(module, module->scheduler, customThreadId)); sv->adapt(rt, value, valueType); return sv; } jsi::Value ShareableValue::getValue(jsi::Runtime &rt) { // TODO: maybe we can cache toJSValue results on a per-runtime basis, need to avoid ref loops - if (module->isUIRuntime(rt)) { + if (module->isUIRuntime(rt) || customThreadId != -1) { if (remoteValue.expired()) { auto ref = getWeakRef(rt); remoteValue = ref; @@ -200,7 +200,7 @@ jsi::Value ShareableValue::toJSValue(jsi::Runtime &rt) { return array; } case ValueType::RemoteObjectType: - if (module->isUIRuntime(rt)) { + if (module->isUIRuntime(rt) || customThreadId != -1) { // todo check this(custom threads) remoteObject->maybeInitializeOnUIRuntime(rt); } return createHost(rt, remoteObject); @@ -270,11 +270,13 @@ jsi::Value ShareableValue::toJSValue(jsi::Runtime &rt) { case ValueType::WorkletFunctionType: auto module = this->module; auto frozenObject = this->frozenObject; - if (module->isUIRuntime(rt)) { + if (module->isUIRuntime(rt) || customThreadId != -1) { // when running on UI thread we prep a function + // for the custom threads we also just want to prepare - auto jsThis = std::make_shared(frozenObject->shallowClone(*module->runtime)); - std::shared_ptr funPtr(module->workletsCache->getFunction(rt, frozenObject)); + auto jsThis = std::make_shared(frozenObject->shallowClone(rt)); + // cache will not work for custom threads because for every thread we have a different RT + std::shared_ptr funPtr(module->workletsCache->getFunction(rt, frozenObject, customThreadId)); auto name = funPtr->getProperty(rt, "name").asString(rt).utf8(rt); auto clb = [=]( diff --git a/Common/cpp/Tools/RuntimeDecorator.cpp b/Common/cpp/Tools/RuntimeDecorator.cpp index 3e2419250f9..6217e23bb6c 100644 --- a/Common/cpp/Tools/RuntimeDecorator.cpp +++ b/Common/cpp/Tools/RuntimeDecorator.cpp @@ -25,7 +25,8 @@ void RuntimeDecorator::addLog(jsi::Runtime &rt) { return jsi::Value::undefined(); }; jsi::Value log = jsi::Function::createFromHostFunction(rt, jsi::PropNameID::forAscii(rt, "_log"), 1, callback); - rt.global().setProperty(rt, "_log", log); + rt.global().setProperty(rt, "_log", log); + rt.global().setProperty(rt, "jsThis", jsi::Value::undefined()); } void RuntimeDecorator::addNativeObjects(jsi::Runtime &rt, diff --git a/Common/cpp/headers/NativeModules/NativeReanimatedModule.h b/Common/cpp/headers/NativeModules/NativeReanimatedModule.h index 225ea274ca1..cdaba5d6e70 100644 --- a/Common/cpp/headers/NativeModules/NativeReanimatedModule.h +++ b/Common/cpp/headers/NativeModules/NativeReanimatedModule.h @@ -80,11 +80,12 @@ class NativeReanimatedModule : public NativeReanimatedModuleSpec std::shared_ptr scheduler; struct Th { - std::string str; + std::unique_ptr rt; std::shared_ptr thread; + std::shared_ptr worklet; }; int currentThreadId = 0; - std::unordered_map threads; + std::unordered_map> threads; }; } // namespace reanimated diff --git a/Common/cpp/headers/Registries/WorkletsCache.h b/Common/cpp/headers/Registries/WorkletsCache.h index 0047f57a1de..8f514c4dca1 100644 --- a/Common/cpp/headers/Registries/WorkletsCache.h +++ b/Common/cpp/headers/Registries/WorkletsCache.h @@ -14,9 +14,10 @@ class FrozenObject; class WorkletsCache { std::unordered_map> worklets; + std::shared_ptr obtainFunction(jsi::Runtime &rt, const std::string &code); public: jsi::Function functionFromString(jsi::Runtime &rt, const std::string &code); - std::shared_ptr getFunction(jsi::Runtime & rt, std::shared_ptr frozenObj); + std::shared_ptr getFunction(jsi::Runtime & rt, std::shared_ptr frozenObj, const int customThreadId = -1); }; } // namespace reanimated diff --git a/Common/cpp/headers/SharedItems/FrozenObject.h b/Common/cpp/headers/SharedItems/FrozenObject.h index 126fd41d870..c71eb64455c 100644 --- a/Common/cpp/headers/SharedItems/FrozenObject.h +++ b/Common/cpp/headers/SharedItems/FrozenObject.h @@ -19,10 +19,11 @@ class FrozenObject : public jsi::HostObject { private: std::unordered_map> map; + const int customThreadId; public: - FrozenObject(jsi::Runtime &rt, const jsi::Object &object, NativeReanimatedModule *module); + FrozenObject(jsi::Runtime &rt, const jsi::Object &object, NativeReanimatedModule *module, const int customThreadId = -1); jsi::Object shallowClone(jsi::Runtime &rt); }; diff --git a/Common/cpp/headers/SharedItems/ShareableValue.h b/Common/cpp/headers/SharedItems/ShareableValue.h index 9790698801b..0f523d7242f 100644 --- a/Common/cpp/headers/SharedItems/ShareableValue.h +++ b/Common/cpp/headers/SharedItems/ShareableValue.h @@ -42,6 +42,7 @@ friend void extractMutables(jsi::Runtime &rt, std::shared_ptr remoteObjectInitializer; std::shared_ptr remoteObject; std::vector> frozenArray; + const int customThreadId; std::unique_ptr hostValue; std::weak_ptr remoteValue; @@ -50,14 +51,14 @@ friend void extractMutables(jsi::Runtime &rt, jsi::Object createHost(jsi::Runtime &rt, std::shared_ptr host); - ShareableValue(NativeReanimatedModule *module, std::shared_ptr s): StoreUser(s), module(module) {} + ShareableValue(NativeReanimatedModule *module, std::shared_ptr s, const int customThreadId = -1) : StoreUser(s), module(module), customThreadId(customThreadId) {} void adapt(jsi::Runtime &rt, const jsi::Value &value, ValueType objectType); void adaptCache(jsi::Runtime &rt, const jsi::Value &value); public: ValueType type = ValueType::UndefinedType; std::shared_ptr mutableValue; - static std::shared_ptr adapt(jsi::Runtime &rt, const jsi::Value &value, NativeReanimatedModule *module, ValueType objectType = ValueType::UndefinedType); + static std::shared_ptr adapt(jsi::Runtime &rt, const jsi::Value &value, NativeReanimatedModule *module, ValueType valueType = ValueType::UndefinedType, const int customThreadId = -1); jsi::Value getValue(jsi::Runtime &rt); }; diff --git a/Example/src/AnimatedStyleUpdateExample.js b/Example/src/AnimatedStyleUpdateExample.js index 3186f1f89b5..3e3b45d68bc 100644 --- a/Example/src/AnimatedStyleUpdateExample.js +++ b/Example/src/AnimatedStyleUpdateExample.js @@ -4,45 +4,76 @@ import Animated, { useAnimatedStyle, Easing, spawnThread, + runOnUI, + runOnJS, } from 'react-native-reanimated'; import { View, Button } from 'react-native'; import React from 'react'; -export default function AnimatedStyleUpdateExample(props) { - const randomWidth = useSharedValue(10); +export default function App() { + const sv = useSharedValue(0); - const config = { - duration: 500, - easing: Easing.bezier(0.5, 0.01, 0, 1), - }; + console.log('here 1'); + // for(let i=0;i<3000000000;++i) {} + console.log('here 2'); + /* * / + useAnimatedStyle(() => { + sv; + console.log('siema', _WORKLET) + return {}; + }) +/* + runOnUI(() => { + 'worklet'; + sv.value = 1; + console.log('> run on ui #1 begin', _WORKLET); + // for(let i=0;i<3000000000;++i) {} + console.log('> run on ui #1 end', _WORKLET); + })(); - const style = useAnimatedStyle(() => { - return { - width: withTiming(randomWidth.value, config), - }; + console.log('here 3'); +/* */ +/* */ + // thread 1 + const vvv = 99; + spawnThread(() => { + 'worklet'; + _log('> spawn thread #1 start ' + vvv); + sv.value = 1; + // vvv;// nie ma krasha + // sv.value; // jest krasz + // po prostu shared value nie jest przystosowane do innych watkow niz js/ui najwyrazniej... + // vvv; + for (let i = 0; i < 3000000000; ++i) {} + sv.value = 2; + _log('> spawn thread #1 end'); + return Math.random() * 100; }); - + // thread 2 + /* * / spawnThread(() => { 'worklet'; - console.log('huge calculations in progress...'); + _log('> spawn thread #2 start'); + // sv.value = 3; + for (let i = 0; i < 3000000000; ++i) {} + _log('> spawn thread #2 end'); + return Math.random() * 100; }); + */ + // + + setTimeout(() => { + console.log('here timeout'); + }, 100); + console.log('here 4'); +/* */ return ( - - +