@depup/react-native-worklets 0.11.4-depup.0 → 0.12.1-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/Common/cpp/worklets/AnimationFrameQueue/AnimationFrameBatchinator.cpp +6 -3
  2. package/Common/cpp/worklets/Compat/StableApi.cpp +4 -0
  3. package/Common/cpp/worklets/Compat/StableApi.h +3 -1
  4. package/Common/cpp/worklets/NativeModules/JSIWorkletsModuleProxy.cpp +26 -43
  5. package/Common/cpp/worklets/RunLoop/EventLoop.cpp +16 -7
  6. package/Common/cpp/worklets/RunLoop/EventLoop.h +4 -2
  7. package/Common/cpp/worklets/SharedItems/MemoryManager.cpp +2 -2
  8. package/Common/cpp/worklets/SharedItems/Serializable.h +14 -16
  9. package/Common/cpp/worklets/Tools/UIScheduler.cpp +10 -0
  10. package/Common/cpp/worklets/Tools/UIScheduler.h +3 -0
  11. package/Common/cpp/worklets/Tools/WorkletsJSIUtils.h +23 -0
  12. package/Common/cpp/worklets/WorkletRuntime/RuntimeManager.cpp +7 -4
  13. package/Common/cpp/worklets/WorkletRuntime/RuntimeManager.h +2 -1
  14. package/Common/cpp/worklets/WorkletRuntime/WorkletRuntime.cpp +60 -88
  15. package/Common/cpp/worklets/WorkletRuntime/WorkletRuntime.h +335 -122
  16. package/README.md +2 -2
  17. package/android/build.gradle.kts +20 -6
  18. package/android/src/main/cpp/worklets/android/AndroidUIScheduler.cpp +10 -8
  19. package/android/src/main/cpp/worklets/android/JScriptBufferWrapper.cpp +2 -11
  20. package/android/src/main/cpp/worklets/android/JScriptBufferWrapper.h +1 -4
  21. package/android/src/main/java/com/swmansion/worklets/AndroidUIScheduler.kt +3 -0
  22. package/android/src/main/java/com/swmansion/worklets/ScriptBufferWrapper.kt +87 -43
  23. package/android/src/networking/com/swmansion/worklets/WorkletsModule.kt +1 -3
  24. package/android/src/no-networking/com/swmansion/worklets/WorkletsModule.kt +1 -3
  25. package/apple/worklets/apple/IOSUIScheduler.h +3 -0
  26. package/apple/worklets/apple/IOSUIScheduler.mm +6 -1
  27. package/apple/worklets/apple/ScriptLoader.h +11 -0
  28. package/apple/worklets/apple/ScriptLoader.mm +124 -0
  29. package/apple/worklets/apple/WorkletsModule.h +1 -16
  30. package/apple/worklets/apple/WorkletsModule.mm +4 -16
  31. package/changes.json +1 -1
  32. package/compatibility.json +4 -1
  33. package/lib/module/WorkletsModule/NativeWorklets.native.js +2 -2
  34. package/lib/module/WorkletsModule/NativeWorklets.native.js.map +1 -1
  35. package/lib/module/debug/jsVersion.js +1 -1
  36. package/lib/module/memory/serializable.native.js +59 -21
  37. package/lib/module/memory/serializable.native.js.map +1 -1
  38. package/lib/module/mock.js +58 -17
  39. package/lib/module/mock.js.map +1 -1
  40. package/lib/module/runLoop/uiRuntime/requestAnimationFrame.js +1 -2
  41. package/lib/module/runLoop/uiRuntime/requestAnimationFrame.js.map +1 -1
  42. package/lib/module/runLoop/workletRuntime/taskQueue.js +0 -1
  43. package/lib/module/runLoop/workletRuntime/taskQueue.js.map +1 -1
  44. package/lib/module/runtimes.native.js +7 -8
  45. package/lib/module/runtimes.native.js.map +1 -1
  46. package/lib/module/threads.js +35 -24
  47. package/lib/module/threads.js.map +1 -1
  48. package/lib/typescript/WorkletsModule/NativeWorklets.native.d.ts.map +1 -1
  49. package/lib/typescript/WorkletsModule/workletsModuleProxy.d.ts +1 -1
  50. package/lib/typescript/WorkletsModule/workletsModuleProxy.d.ts.map +1 -1
  51. package/lib/typescript/debug/jsVersion.d.ts +1 -1
  52. package/lib/typescript/memory/serializable.native.d.ts.map +1 -1
  53. package/lib/typescript/runLoop/uiRuntime/requestAnimationFrame.d.ts.map +1 -1
  54. package/lib/typescript/runLoop/workletRuntime/taskQueue.d.ts.map +1 -1
  55. package/lib/typescript/runtimes.native.d.ts.map +1 -1
  56. package/lib/typescript/specs/NativeWorkletsModule.d.ts +1 -1
  57. package/lib/typescript/threads.d.ts.map +1 -1
  58. package/lib/typescript/types.d.ts +38 -8
  59. package/lib/typescript/types.d.ts.map +1 -1
  60. package/package.json +14 -15
  61. package/plugin/index.js +1625 -1572
  62. package/src/WorkletsModule/NativeWorklets.native.ts +4 -2
  63. package/src/WorkletsModule/workletsModuleProxy.ts +2 -1
  64. package/src/debug/jsVersion.ts +1 -1
  65. package/src/memory/serializable.native.ts +103 -36
  66. package/src/mock.ts +85 -23
  67. package/src/runLoop/uiRuntime/requestAnimationFrame.ts +1 -2
  68. package/src/runLoop/workletRuntime/taskQueue.ts +0 -1
  69. package/src/runtimes.native.ts +12 -8
  70. package/src/threads.ts +38 -26
  71. package/src/types.ts +42 -8
  72. package/Common/cpp/worklets/Registries/EventHandlerRegistry.cpp +0 -95
  73. package/Common/cpp/worklets/Registries/EventHandlerRegistry.h +0 -44
  74. package/Common/cpp/worklets/Tools/WorkletEventHandler.cpp +0 -34
  75. package/Common/cpp/worklets/Tools/WorkletEventHandler.h +0 -44
  76. package/jest/pluginTestUtils.ts +0 -16
@@ -45,9 +45,12 @@ void AnimationFrameBatchinator::flush() {
45
45
  strongThis->flushRequested_ = false;
46
46
 
47
47
  auto &uiWorkletRuntime = strongThis->uiWorkletRuntime_;
48
- for (const auto &callback : callbacks) {
49
- uiWorkletRuntime->runSync(*callback, timestampMs);
50
- }
48
+ uiWorkletRuntime->runSync([&](jsi::Runtime &rt) {
49
+ for (const auto &callback : callbacks) {
50
+ uiWorkletRuntime->runSync(*callback, timestampMs);
51
+ }
52
+ jsi_utils::triggerWeakRefCleanup(uiWorkletRuntime->getJSIRuntime());
53
+ });
51
54
  });
52
55
  }
53
56
 
@@ -22,6 +22,10 @@ void scheduleOnUI(const std::shared_ptr<UIScheduler> &uiScheduler, const std::fu
22
22
  uiScheduler->scheduleOnUI(job);
23
23
  }
24
24
 
25
+ bool isOnUIThread(const std::shared_ptr<UIScheduler> &uiScheduler) {
26
+ return uiScheduler->isOnUIThread();
27
+ }
28
+
25
29
  facebook::jsi::Runtime &getJSIRuntimeFromWorkletRuntime(const std::shared_ptr<WorkletRuntime> &workletRuntime) {
26
30
  return workletRuntime->getJSIRuntime();
27
31
  }
@@ -5,7 +5,7 @@
5
5
  * It can be used by libraries to verify they use a compatible version
6
6
  * of `react-native-worklets` installed when integrating in C++.
7
7
  */
8
- #define WORKLETS_STABLE_API_VERSION "0.9.0"
8
+ #define WORKLETS_STABLE_API_VERSION "0.12.1"
9
9
 
10
10
  #include <cstdint>
11
11
  #include <functional>
@@ -83,6 +83,8 @@ extern std::weak_ptr<WorkletRuntime> getWeakRuntimeFromJSIRuntime(facebook::jsi:
83
83
 
84
84
  extern void scheduleOnUI(const std::shared_ptr<UIScheduler> &uiScheduler, const std::function<void()> &job);
85
85
 
86
+ extern bool isOnUIThread(const std::shared_ptr<UIScheduler> &uiScheduler);
87
+
86
88
  extern std::string JSIValueToStdString(facebook::jsi::Runtime &rt, const facebook::jsi::Value &value);
87
89
 
88
90
  extern std::shared_ptr<Serializable>
@@ -71,37 +71,11 @@ inline void scheduleOnUI(
71
71
  if (!uiWorkletRuntime) {
72
72
  return;
73
73
  }
74
- uiWorkletRuntime->schedule([worklets = std::move(worklets),
75
74
  #ifndef NDEBUG
76
- scheduleStacks = std::move(scheduleStacks),
77
- #endif // NDEBUG
78
- weakUIWorkletRuntime]() {
79
- // This callback can outlive the WorkletsModuleProxy object during the
80
- // invalidation of React Native. This happens when WorkletsModuleProxy
81
- // destructor is called on the JS thread and the UI thread is
82
- // executing callbacks from the `scheduleOnUI` queue. Therefore, we
83
- // need to make sure it's still alive before we try to access it.
84
- auto uiWorkletRuntime = weakUIWorkletRuntime.lock();
85
- if (!uiWorkletRuntime) {
86
- return;
87
- }
88
-
89
- // JSI's scope defined here allows for JSI-objects to be cleared up
90
- // after each runtime loop. Within these loops we typically create
91
- // some temporary JSI objects and hence it allows for such objects to
92
- // be garbage collected much sooner.
93
- const auto scope = jsi::Scope(uiWorkletRuntime->getJSIRuntime());
94
-
95
- for (size_t i = 0; i < worklets.size(); i++) {
96
- #ifndef NDEBUG
97
- uiWorkletRuntime->runSyncWithStack(worklets[i], scheduleStacks[i]);
75
+ uiWorkletRuntime->scheduleWithStack(std::move(worklets), std::move(scheduleStacks));
98
76
  #else
99
- uiWorkletRuntime->runSync(worklets[i]);
77
+ uiWorkletRuntime->schedule(std::move(worklets));
100
78
  #endif // NDEBUG
101
- }
102
-
103
- uiWorkletRuntime->callMicrotasks();
104
- });
105
79
  }
106
80
 
107
81
  #ifndef NDEBUG
@@ -113,7 +87,8 @@ inline jsi::Value runOnUISync(
113
87
  if (auto uiWorkletRuntime = weakUIWorkletRuntime.lock()) {
114
88
  auto serializableWorklet = extractSerializableOrThrow<SerializableWorklet>(
115
89
  rt, worklet, "[Worklets] Only worklets can be executed on UI runtime.");
116
- auto serializedResult = uiWorkletRuntime->runSyncSerializedWithStack(serializableWorklet, scheduleStack);
90
+ auto serializedResult =
91
+ uiWorkletRuntime->runSyncWithStack<std::shared_ptr<Serializable>>(serializableWorklet, scheduleStack);
117
92
  return serializedResult->toJSValue(rt);
118
93
  }
119
94
  return jsi::Value::undefined();
@@ -140,7 +115,8 @@ jsi::Value runOnRuntimeSync(
140
115
  auto workletRuntime = workletRuntimeValue.getObject(rt).getHostObject<WorkletRuntime>(rt);
141
116
  auto worklet = extractSerializableOrThrow<SerializableWorklet>(
142
117
  rt, serializableWorkletValue, "[Worklets] Only worklets can be executed on a worklet runtime.");
143
- return workletRuntime->runSyncSerializedWithStack(worklet, scheduleStack)->toJSValue(rt);
118
+ auto serializedResult = workletRuntime->runSyncWithStack<std::shared_ptr<Serializable>>(worklet, scheduleStack);
119
+ return serializedResult->toJSValue(rt);
144
120
  }
145
121
  #else
146
122
  jsi::Value
@@ -148,7 +124,8 @@ runOnRuntimeSync(jsi::Runtime &rt, const jsi::Value &workletRuntimeValue, const
148
124
  auto workletRuntime = workletRuntimeValue.getObject(rt).getHostObject<WorkletRuntime>(rt);
149
125
  auto worklet = extractSerializableOrThrow<SerializableWorklet>(
150
126
  rt, serializableWorkletValue, "[Worklets] Only worklets can be executed on a worklet runtime.");
151
- return workletRuntime->runSyncSerialized(worklet)->toJSValue(rt);
127
+ auto serializedResult = workletRuntime->runSyncSerialized(worklet);
128
+ return serializedResult->toJSValue(rt);
152
129
  }
153
130
  #endif // NDEBUG
154
131
 
@@ -159,9 +136,10 @@ inline jsi::Value createWorkletRuntime(
159
136
  const std::string &name,
160
137
  std::shared_ptr<SerializableWorklet> &initializer,
161
138
  const std::shared_ptr<AsyncQueue> &queue,
162
- bool enableEventLoop) {
139
+ bool enableEventLoop,
140
+ bool enableLocking) {
163
141
  const auto workletRuntime =
164
- runtimeManager->createWorkletRuntime(sourceProxy, name, initializer, queue, enableEventLoop);
142
+ runtimeManager->createWorkletRuntime(sourceProxy, name, initializer, queue, enableEventLoop, enableLocking);
165
143
  return jsi::Object::createFromHostObject(originRuntime, workletRuntime);
166
144
  }
167
145
 
@@ -202,7 +180,9 @@ inline void registerCustomSerializable(
202
180
  runtimeManager->withRegistrationPaused([&] {
203
181
  memoryManager->registerCustomSerializable(data);
204
182
  for (const auto &runtime : runtimeManager->getAllRuntimes()) {
205
- memoryManager->loadCustomSerializable(runtime, data);
183
+ if (runtime->isLockingEnabled()) {
184
+ memoryManager->loadCustomSerializable(runtime, data);
185
+ }
206
186
  }
207
187
  });
208
188
  }
@@ -505,21 +485,23 @@ jsi::Object JSIWorkletsModuleProxy::toOptimizedObject(jsi::Runtime &rt) const {
505
485
  if (at<2>(args).isString()) {
506
486
  scheduleStack = at<2>(args).asString(rt).utf8(rt);
507
487
  }
508
- return workletRuntime->runSyncSerializedWithStack(serializableWorklet, scheduleStack)->toJSValue(rt);
488
+ auto serializedResult =
489
+ workletRuntime->runSyncWithStack<std::shared_ptr<Serializable>>(serializableWorklet, scheduleStack);
509
490
  #else
510
- return workletRuntime->runSyncSerialized(serializableWorklet)->toJSValue(rt);
491
+ auto serializedResult = workletRuntime->runSyncSerialized(serializableWorklet);
511
492
  #endif // NDEBUG
493
+ return serializedResult->toJSValue(rt);
512
494
  });
513
495
 
514
- jsi_utils::addMethod<5>(
496
+ jsi_utils::addMethod<6>(
515
497
  rt,
516
498
  obj,
517
499
  "createWorkletRuntime",
518
- [sourceProxy = shared_from_this()](jsi::Runtime &rt, const jsi::Value &, const jsi::Value(&args)[5]) {
519
- const auto name = at<0>(args).asString(rt).utf8(rt);
500
+ [sourceProxy = shared_from_this()](jsi::Runtime &rt, const jsi::Value &, const jsi::Value(&args)[6]) {
501
+ const auto name = at<0>(args).getString(rt).utf8(rt);
520
502
  auto serializableInitializer = extractSerializableOrThrow<SerializableWorklet>(
521
503
  rt, at<1>(args), "[Worklets] Initializer must be a worklet.");
522
- const auto useDefaultQueue = at<2>(args).asBool();
504
+ const auto useDefaultQueue = at<2>(args).getBool();
523
505
 
524
506
  std::shared_ptr<AsyncQueue> asyncQueue;
525
507
  if (useDefaultQueue) {
@@ -528,11 +510,12 @@ jsi::Object JSIWorkletsModuleProxy::toOptimizedObject(jsi::Runtime &rt) const {
528
510
  asyncQueue = extractAsyncQueue(rt, at<3>(args));
529
511
  }
530
512
 
531
- const auto enableEventLoop = at<4>(args).asBool();
513
+ const auto enableEventLoop = at<4>(args).getBool();
514
+ const auto enableLocking = at<5>(args).getBool();
532
515
  const auto runtimeManager = sourceProxy->getRuntimeManager();
533
516
 
534
517
  return createWorkletRuntime(
535
- rt, runtimeManager, sourceProxy, name, serializableInitializer, asyncQueue, enableEventLoop);
518
+ rt, runtimeManager, sourceProxy, name, serializableInitializer, asyncQueue, enableEventLoop, enableLocking);
536
519
  });
537
520
 
538
521
  jsi_utils::addMethod<3>(
@@ -566,7 +549,7 @@ jsi::Object JSIWorkletsModuleProxy::toOptimizedObject(jsi::Runtime &rt) const {
566
549
  if (at<2>(args).isString()) {
567
550
  scheduleStack = at<2>(args).asString(rt).utf8(rt);
568
551
  }
569
- workletRuntime->schedule(worklet, scheduleStack);
552
+ workletRuntime->scheduleWithStack(worklet, scheduleStack);
570
553
  #else
571
554
  workletRuntime->schedule(worklet);
572
555
  #endif // NDEBUG
@@ -1,4 +1,5 @@
1
1
  #include <worklets/RunLoop/EventLoop.h>
2
+ #include <worklets/Tools/WorkletsJSIUtils.h>
2
3
 
3
4
  #include <memory>
4
5
  #include <string>
@@ -11,8 +12,13 @@ namespace worklets {
11
12
  EventLoop::EventLoop(
12
13
  const std::string &name,
13
14
  const std::shared_ptr<jsi::Runtime> &runtime,
14
- const std::shared_ptr<AsyncQueue> &queue)
15
- : runtime_(runtime), queue_(queue), timeoutsQueueState_(std::make_shared<TimeoutsQueueState>()), name_(name) {}
15
+ const std::shared_ptr<AsyncQueue> &queue,
16
+ const std::shared_ptr<std::recursive_mutex> &runtimeMutex)
17
+ : runtime_(runtime),
18
+ queue_(queue),
19
+ runtimeMutex_(runtimeMutex),
20
+ timeoutsQueueState_(std::make_shared<TimeoutsQueueState>()),
21
+ name_(name) {}
16
22
 
17
23
  EventLoop::~EventLoop() {
18
24
  {
@@ -76,11 +82,14 @@ void EventLoop::run() {
76
82
  }
77
83
 
78
84
  void EventLoop::pushTask(std::function<void(jsi::Runtime &rt)> &&job) {
79
- queue_->push([weakRuntime = std::weak_ptr<jsi::Runtime>{runtime_}, job = std::move(job)] {
80
- if (auto runtime = weakRuntime.lock()) {
81
- job(*runtime);
82
- }
83
- });
85
+ queue_->push(
86
+ [weakRuntime = std::weak_ptr<jsi::Runtime>{runtime_}, runtimeMutex = runtimeMutex_, job = std::move(job)] {
87
+ if (auto runtime = weakRuntime.lock()) {
88
+ std::unique_lock lock(*runtimeMutex);
89
+ job(*runtime);
90
+ jsi_utils::drainMicrotasks(*runtime);
91
+ }
92
+ });
84
93
  }
85
94
 
86
95
  void EventLoop::pushTimeout(std::function<void(jsi::Runtime &rt)> &&job, int64_t delay) {
@@ -6,7 +6,7 @@
6
6
  #include <atomic>
7
7
  #include <condition_variable>
8
8
  #include <memory>
9
- #include <queue>
9
+ #include <mutex>
10
10
  #include <string>
11
11
  #include <vector>
12
12
 
@@ -34,7 +34,8 @@ class EventLoop : public std::enable_shared_from_this<EventLoop> {
34
34
  EventLoop(
35
35
  const std::string &name,
36
36
  const std::shared_ptr<jsi::Runtime> &runtime,
37
- const std::shared_ptr<AsyncQueue> &queue);
37
+ const std::shared_ptr<AsyncQueue> &queue,
38
+ const std::shared_ptr<std::recursive_mutex> &runtimeMutex);
38
39
  ~EventLoop();
39
40
  void run();
40
41
  void pushTask(std::function<void(jsi::Runtime &rt)> &&job);
@@ -43,6 +44,7 @@ class EventLoop : public std::enable_shared_from_this<EventLoop> {
43
44
  private:
44
45
  const std::shared_ptr<jsi::Runtime> runtime_;
45
46
  const std::shared_ptr<AsyncQueue> queue_;
47
+ const std::shared_ptr<std::recursive_mutex> runtimeMutex_;
46
48
  const std::shared_ptr<TimeoutsQueueState> timeoutsQueueState_;
47
49
  const std::string name_;
48
50
 
@@ -7,7 +7,7 @@
7
7
  namespace worklets {
8
8
  void MemoryManager::loadAllCustomSerializables(const std::shared_ptr<WorkletRuntime> &runtime) {
9
9
  std::lock_guard lock(customSerializationDataMutex_);
10
- runtime->executeSync([&](jsi::Runtime &rt) -> jsi::Value {
10
+ runtime->runSync([&](jsi::Runtime &rt) -> jsi::Value {
11
11
  const auto registry = getCustomSerializationRegistry(rt);
12
12
  for (const auto &data : customSerializationData_) {
13
13
  loadCustomSerializable(rt, registry, data);
@@ -20,7 +20,7 @@ void MemoryManager::loadCustomSerializable(
20
20
  const std::shared_ptr<WorkletRuntime> &runtime,
21
21
  const SerializationData &data) {
22
22
  std::lock_guard lock(customSerializationDataMutex_);
23
- runtime->executeSync([this, data](jsi::Runtime &rt) -> jsi::Value {
23
+ runtime->runSync([this, data](jsi::Runtime &rt) -> jsi::Value {
24
24
  const auto registry = getCustomSerializationRegistry(rt);
25
25
  loadCustomSerializable(rt, registry, data);
26
26
  return jsi::Value::undefined();
@@ -6,6 +6,7 @@
6
6
  #include <worklets/Tools/JSScheduler.h>
7
7
  #include <worklets/WorkletRuntime/RuntimeData.h>
8
8
 
9
+ #include <atomic>
9
10
  #include <memory>
10
11
  #include <mutex>
11
12
  #include <optional>
@@ -46,8 +47,9 @@ template <typename BaseClass>
46
47
  class RetainingSerializable : virtual public BaseClass {
47
48
  private:
48
49
  jsi::Runtime *primaryRuntime_;
49
- jsi::Runtime *secondaryRuntime_;
50
50
  std::unique_ptr<jsi::Value> secondaryValue_;
51
+ std::atomic<jsi::Runtime *> secondaryRuntime_{nullptr};
52
+ std::mutex secondaryCacheMutex_;
51
53
 
52
54
  public:
53
55
  template <typename... Args>
@@ -56,28 +58,24 @@ class RetainingSerializable : virtual public BaseClass {
56
58
 
57
59
  jsi::Value toJSValue(jsi::Runtime &rt) override {
58
60
  if (&rt == primaryRuntime_) {
59
- // TODO: it is suboptimal to generate new object every time getJS is
60
- // called on host runtime – the objects we are generating already exists
61
- // and we should possibly just grab a hold of such object and use it here
62
- // instead of creating a new JS representation. As far as I understand the
63
- // only case where it can be realistically called this way is when a
64
- // shared value is created and then accessed on the same runtime
65
61
  return BaseClass::toJSValue(rt);
66
62
  }
67
- if (secondaryValue_ == nullptr) {
68
- auto value = BaseClass::toJSValue(rt);
69
- secondaryValue_ = std::make_unique<jsi::Value>(rt, value);
70
- secondaryRuntime_ = &rt;
71
- return value;
72
- }
73
- if (&rt == secondaryRuntime_) {
63
+ if (secondaryRuntime_.load(std::memory_order_acquire) == &rt) {
74
64
  return jsi::Value(rt, *secondaryValue_);
75
65
  }
76
- return BaseClass::toJSValue(rt);
66
+ auto value = BaseClass::toJSValue(rt);
67
+ {
68
+ std::lock_guard<std::mutex> lock(secondaryCacheMutex_);
69
+ if (secondaryRuntime_.load(std::memory_order_relaxed) == nullptr) {
70
+ secondaryValue_ = std::make_unique<jsi::Value>(rt, value);
71
+ secondaryRuntime_.store(&rt, std::memory_order_release);
72
+ }
73
+ }
74
+ return value;
77
75
  }
78
76
 
79
77
  ~RetainingSerializable() override {
80
- cleanupRuntimeAware(secondaryRuntime_, secondaryValue_);
78
+ cleanupRuntimeAware(secondaryRuntime_.load(std::memory_order_relaxed), secondaryValue_);
81
79
  }
82
80
  };
83
81
 
@@ -1,9 +1,12 @@
1
1
  #include <worklets/Tools/UIScheduler.h>
2
2
 
3
+ #include <optional>
3
4
  #include <utility>
4
5
 
5
6
  namespace worklets {
6
7
 
8
+ static thread_local std::optional<bool> tls_isOnUIThread;
9
+
7
10
  void UIScheduler::scheduleOnUI(std::function<void()> job) {
8
11
  uiJobs_.push(std::move(job));
9
12
  }
@@ -16,4 +19,11 @@ void UIScheduler::triggerUI() {
16
19
  }
17
20
  }
18
21
 
22
+ bool UIScheduler::isOnUIThread() const {
23
+ if (!tls_isOnUIThread.has_value()) {
24
+ tls_isOnUIThread = queryIsOnUIThread();
25
+ }
26
+ return *tls_isOnUIThread;
27
+ }
28
+
19
29
  } // namespace worklets
@@ -12,9 +12,12 @@ class UIScheduler {
12
12
  public:
13
13
  virtual void scheduleOnUI(std::function<void()> job);
14
14
  virtual void triggerUI();
15
+ bool isOnUIThread() const;
15
16
  virtual ~UIScheduler() = default;
16
17
 
17
18
  protected:
19
+ virtual bool queryIsOnUIThread() const = 0;
20
+
18
21
  std::atomic<bool> scheduledOnUI_{false};
19
22
  ThreadSafeQueue<std::function<void()>> uiJobs_;
20
23
  };
@@ -11,6 +11,29 @@ using namespace facebook;
11
11
 
12
12
  namespace worklets::jsi_utils {
13
13
 
14
+ /**
15
+ * Drains Hermes microtasks - we don't use these, but Hermes WeakRefs are
16
+ * cleaned during Hermes microtask checkpoint.
17
+ */
18
+ inline void triggerWeakRefCleanup(jsi::Runtime &rt) {
19
+ rt.drainMicrotasks();
20
+ }
21
+
22
+ /**
23
+ * Drains both Worklets and Hermes microtasks.
24
+ */
25
+ inline void drainMicrotasks(jsi::Runtime &rt) {
26
+ auto callMicrotasks = rt.global().getProperty(rt, "__callMicrotasks");
27
+ if (callMicrotasks.isObject()) {
28
+ auto callMicrotasksObject = callMicrotasks.getObject(rt);
29
+ if (callMicrotasksObject.isFunction(rt)) {
30
+ callMicrotasksObject.getFunction(rt).call(rt);
31
+ }
32
+ }
33
+
34
+ triggerWeakRefCleanup(rt);
35
+ }
36
+
14
37
  // `get` functions take a pointer to `jsi::Value` and
15
38
  // call an appropriate method to cast to the native type
16
39
  template <typename T>
@@ -55,11 +55,12 @@ std::shared_ptr<WorkletRuntime> RuntimeManager::createWorkletRuntime(
55
55
  const std::string &name,
56
56
  const std::shared_ptr<SerializableWorklet> &initializer,
57
57
  const std::shared_ptr<AsyncQueue> &queue,
58
- bool enableEventLoop) {
58
+ bool enableEventLoop,
59
+ bool enableLocking) {
59
60
  const auto runtimeId = getNextRuntimeId();
60
61
 
61
- const auto workletRuntime =
62
- std::make_shared<WorkletRuntime>(runtimeId, RuntimeData::RuntimeKind::Worker, name, queue, enableEventLoop);
62
+ const auto workletRuntime = std::make_shared<WorkletRuntime>(
63
+ runtimeId, RuntimeData::RuntimeKind::Worker, name, queue, enableEventLoop, enableLocking);
63
64
  const auto targetProxy = JSIWorkletsModuleProxy::createForNewRuntime(sourceProxy, runtimeId);
64
65
 
65
66
  workletRuntime->init(targetProxy);
@@ -84,7 +85,9 @@ void RuntimeManager::propagateModuleUpdate(const std::string &code, const std::s
84
85
  moduleUpdates_.push_back(ModuleUpdate{.sourceUrl = sourceUrl, .code = code});
85
86
 
86
87
  for (const auto &runtime : getAllRuntimes()) {
87
- evaluateModuleUpdate(runtime, code, sourceUrl);
88
+ if (runtime->isLockingEnabled()) {
89
+ evaluateModuleUpdate(runtime, code, sourceUrl);
90
+ }
88
91
  }
89
92
  }
90
93
 
@@ -35,7 +35,8 @@ class RuntimeManager {
35
35
  const std::string &name,
36
36
  const std::shared_ptr<SerializableWorklet> &initializer = nullptr,
37
37
  const std::shared_ptr<AsyncQueue> &queue = nullptr,
38
- bool enableEventLoop = true);
38
+ bool enableEventLoop = true,
39
+ bool enableLocking = true);
39
40
 
40
41
  std::shared_ptr<WorkletRuntime> createUninitializedUIRuntime(const std::shared_ptr<AsyncQueue> &uiAsyncQueue);
41
42