react-native-reanimated 3.0.0-rc.2 → 3.0.0-rc.3

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 (127) hide show
  1. package/Common/cpp/AnimatedSensor/AnimatedSensorModule.cpp +3 -0
  2. package/Common/cpp/{headers/AnimatedSensor → AnimatedSensor}/AnimatedSensorModule.h +0 -0
  3. package/Common/cpp/Fabric/FabricUtils.cpp +1 -1
  4. package/Common/cpp/{headers/Fabric → Fabric}/FabricUtils.h +0 -0
  5. package/Common/cpp/Fabric/ReanimatedUIManagerBinding.cpp +2 -0
  6. package/Common/cpp/{headers/Fabric → Fabric}/ReanimatedUIManagerBinding.h +0 -0
  7. package/Common/cpp/{headers/Fabric → Fabric}/ShadowTreeCloner.h +1 -1
  8. package/Common/cpp/LayoutAnimations/LayoutAnimationsProxy.cpp +2 -0
  9. package/Common/cpp/{headers/LayoutAnimations → LayoutAnimations}/LayoutAnimationsProxy.h +0 -0
  10. package/Common/cpp/NativeModules/NativeReanimatedModule.cpp +1 -0
  11. package/Common/cpp/{headers/NativeModules → NativeModules}/NativeReanimatedModule.h +5 -0
  12. package/Common/cpp/NativeModules/NativeReanimatedModuleSpec.cpp +2 -0
  13. package/Common/cpp/{headers/NativeModules → NativeModules}/NativeReanimatedModuleSpec.h +1 -1
  14. package/Common/cpp/ReanimatedRuntime/ReanimatedHermesRuntime.cpp +93 -0
  15. package/Common/cpp/ReanimatedRuntime/ReanimatedHermesRuntime.h +125 -0
  16. package/Common/cpp/ReanimatedRuntime/ReanimatedRuntime.cpp +50 -0
  17. package/Common/cpp/ReanimatedRuntime/ReanimatedRuntime.h +27 -0
  18. package/Common/cpp/ReanimatedRuntime/RuntimeInitialization.md +194 -0
  19. package/Common/cpp/{headers/Registries → Registries}/EventHandlerRegistry.h +0 -0
  20. package/Common/cpp/Registries/MapperRegistry.cpp +3 -1
  21. package/Common/cpp/{headers/Registries → Registries}/MapperRegistry.h +0 -0
  22. package/Common/cpp/{headers/Registries → Registries}/NewestShadowNodesRegistry.h +0 -0
  23. package/Common/cpp/Registries/WorkletsCache.cpp +8 -1
  24. package/Common/cpp/{headers/Registries → Registries}/WorkletsCache.h +0 -0
  25. package/Common/cpp/{headers/SharedItems → SharedItems}/FrozenObject.h +0 -0
  26. package/Common/cpp/{headers/SharedItems → SharedItems}/HostFunctionHandler.h +0 -0
  27. package/Common/cpp/SharedItems/MutableValue.cpp +2 -0
  28. package/Common/cpp/{headers/SharedItems → SharedItems}/MutableValue.h +0 -0
  29. package/Common/cpp/{headers/SharedItems → SharedItems}/MutableValueSetterProxy.h +0 -0
  30. package/Common/cpp/{headers/SharedItems → SharedItems}/RemoteObject.h +0 -0
  31. package/Common/cpp/{headers/SharedItems → SharedItems}/RuntimeManager.h +0 -0
  32. package/Common/cpp/SharedItems/ShareableValue.cpp +6 -0
  33. package/Common/cpp/{headers/SharedItems → SharedItems}/ShareableValue.h +0 -0
  34. package/Common/cpp/{headers/SharedItems → SharedItems}/SharedParent.h +0 -0
  35. package/Common/cpp/{headers/SharedItems → SharedItems}/ValueWrapper.h +0 -0
  36. package/Common/cpp/{headers/SpecTools → SpecTools}/ErrorHandler.h +0 -0
  37. package/Common/cpp/{headers/Tools → Tools}/FeaturesConfig.h +0 -0
  38. package/Common/cpp/Tools/JSIStoreValueUser.cpp +2 -2
  39. package/Common/cpp/{headers/Tools → Tools}/JSIStoreValueUser.h +0 -0
  40. package/Common/cpp/{headers/Tools → Tools}/Mapper.h +0 -0
  41. package/Common/cpp/{headers/Tools → Tools}/PlatformDepMethodsHolder.h +0 -0
  42. package/Common/cpp/{headers/Tools → Tools}/ReanimatedHiddenHeaders.h +1 -1
  43. package/Common/cpp/{headers/Tools → Tools}/RuntimeDecorator.h +0 -0
  44. package/Common/cpp/{headers/Tools → Tools}/Scheduler.h +0 -0
  45. package/Common/cpp/Tools/SingleInstanceChecker.h +58 -0
  46. package/Common/cpp/{headers/Tools → Tools}/WorkletEventHandler.h +0 -0
  47. package/RNReanimated.podspec +25 -23
  48. package/android/CMakeLists.txt +41 -38
  49. package/android/build.gradle +91 -72
  50. package/android/src/fabric/java/com/swmansion/reanimated/NativeProxy.java +10 -8
  51. package/android/src/main/cpp/{headers/AndroidErrorHandler.h → AndroidErrorHandler.h} +0 -0
  52. package/android/src/main/cpp/AndroidLogger.cpp +4 -1
  53. package/android/src/main/cpp/{headers/AndroidLogger.h → AndroidLogger.h} +0 -0
  54. package/android/src/main/cpp/{headers/AndroidScheduler.h → AndroidScheduler.h} +0 -0
  55. package/android/src/main/cpp/{headers/JNIHelper.h → JNIHelper.h} +0 -0
  56. package/android/src/main/cpp/{headers/LayoutAnimations.h → LayoutAnimations.h} +0 -0
  57. package/android/src/main/cpp/NativeProxy.cpp +12 -28
  58. package/android/src/main/cpp/{headers/NativeProxy.h → NativeProxy.h} +3 -1
  59. package/android/src/main/cpp/{headers/TurboModule.h → TurboModule.h} +0 -0
  60. package/android/src/main/java/com/swmansion/reanimated/ReanimatedMessageQueueThread.java +77 -0
  61. package/android/src/main/java/com/swmansion/reanimated/keyboardObserver/ReanimatedKeyboardEventListener.java +2 -1
  62. package/android/src/paper/java/com/swmansion/reanimated/NativeProxy.java +7 -7
  63. package/ios/REAModule.mm +10 -0
  64. package/ios/native/NativeProxy.mm +12 -19
  65. package/ios/native/REAInitializer.h +2 -2
  66. package/ios/native/REAInitializer.mm +2 -2
  67. package/ios/native/REAMessageThread.h +22 -0
  68. package/ios/native/REAMessageThread.mm +38 -0
  69. package/ios/native/UIResponder+Reanimated.mm +1 -1
  70. package/lib/commonjs/reanimated2/NativeMethods.js +20 -24
  71. package/lib/commonjs/reanimated2/NativeMethods.js.map +1 -1
  72. package/lib/commonjs/reanimated2/animation/delay.js +0 -12
  73. package/lib/commonjs/reanimated2/animation/delay.js.map +1 -1
  74. package/lib/commonjs/reanimated2/animation/repeat.js +0 -24
  75. package/lib/commonjs/reanimated2/animation/repeat.js.map +1 -1
  76. package/lib/commonjs/reanimated2/animation/sequence.js +0 -12
  77. package/lib/commonjs/reanimated2/animation/sequence.js.map +1 -1
  78. package/lib/commonjs/reanimated2/commonTypes.js.map +1 -1
  79. package/lib/commonjs/reanimated2/frameCallback/FrameCallbackRegistryJS.js +4 -4
  80. package/lib/commonjs/reanimated2/frameCallback/FrameCallbackRegistryJS.js.map +1 -1
  81. package/lib/commonjs/reanimated2/frameCallback/FrameCallbackRegistryUI.js +51 -19
  82. package/lib/commonjs/reanimated2/frameCallback/FrameCallbackRegistryUI.js.map +1 -1
  83. package/lib/commonjs/reanimated2/hook/index.js +8 -0
  84. package/lib/commonjs/reanimated2/hook/index.js.map +1 -1
  85. package/lib/commonjs/reanimated2/hook/useAnimatedScrollHandler.js.map +1 -1
  86. package/lib/commonjs/reanimated2/hook/useFrameCallback.js.map +1 -1
  87. package/lib/commonjs/reanimated2/hook/useScrollViewOffset.js +31 -0
  88. package/lib/commonjs/reanimated2/hook/useScrollViewOffset.js.map +1 -0
  89. package/lib/commonjs/reanimated2/utils.js +12 -3
  90. package/lib/commonjs/reanimated2/utils.js.map +1 -1
  91. package/lib/module/reanimated2/NativeMethods.js +20 -24
  92. package/lib/module/reanimated2/NativeMethods.js.map +1 -1
  93. package/lib/module/reanimated2/animation/delay.js +0 -10
  94. package/lib/module/reanimated2/animation/delay.js.map +1 -1
  95. package/lib/module/reanimated2/animation/repeat.js +0 -20
  96. package/lib/module/reanimated2/animation/repeat.js.map +1 -1
  97. package/lib/module/reanimated2/animation/sequence.js +0 -10
  98. package/lib/module/reanimated2/animation/sequence.js.map +1 -1
  99. package/lib/module/reanimated2/commonTypes.js.map +1 -1
  100. package/lib/module/reanimated2/frameCallback/FrameCallbackRegistryJS.js +4 -4
  101. package/lib/module/reanimated2/frameCallback/FrameCallbackRegistryJS.js.map +1 -1
  102. package/lib/module/reanimated2/frameCallback/FrameCallbackRegistryUI.js +51 -19
  103. package/lib/module/reanimated2/frameCallback/FrameCallbackRegistryUI.js.map +1 -1
  104. package/lib/module/reanimated2/hook/index.js +1 -0
  105. package/lib/module/reanimated2/hook/index.js.map +1 -1
  106. package/lib/module/reanimated2/hook/useAnimatedScrollHandler.js.map +1 -1
  107. package/lib/module/reanimated2/hook/useFrameCallback.js.map +1 -1
  108. package/lib/module/reanimated2/hook/useScrollViewOffset.js +20 -0
  109. package/lib/module/reanimated2/hook/useScrollViewOffset.js.map +1 -0
  110. package/lib/module/reanimated2/utils.js +13 -3
  111. package/lib/module/reanimated2/utils.js.map +1 -1
  112. package/package.json +6 -4
  113. package/plugin.js +105 -47
  114. package/react-native-reanimated.d.ts +13 -9
  115. package/src/reanimated2/NativeMethods.ts +28 -33
  116. package/src/reanimated2/animation/delay.ts +0 -12
  117. package/src/reanimated2/animation/repeat.ts +0 -25
  118. package/src/reanimated2/animation/sequence.ts +0 -13
  119. package/src/reanimated2/commonTypes.ts +9 -0
  120. package/src/reanimated2/frameCallback/FrameCallbackRegistryJS.ts +6 -9
  121. package/src/reanimated2/frameCallback/FrameCallbackRegistryUI.ts +78 -27
  122. package/src/reanimated2/hook/index.ts +1 -0
  123. package/src/reanimated2/hook/useAnimatedScrollHandler.ts +3 -1
  124. package/src/reanimated2/hook/useFrameCallback.ts +2 -1
  125. package/src/reanimated2/hook/useScrollViewOffset.ts +36 -0
  126. package/src/reanimated2/utils.ts +12 -5
  127. package/android/src/main/java/com/swmansion/reanimated/ReanimatedJSIModulePackage.java +0 -29
@@ -2,6 +2,9 @@
2
2
  #include "MutableValue.h"
3
3
  #include "ValueWrapper.h"
4
4
 
5
+ #include <memory>
6
+ #include <utility>
7
+
5
8
  namespace reanimated {
6
9
 
7
10
  AnimatedSensorModule::AnimatedSensorModule(
@@ -1,6 +1,6 @@
1
1
  #ifdef RCT_NEW_ARCH_ENABLED
2
2
 
3
- #if RNVERSION < 69
3
+ #if REACT_NATIVE_MINOR_VERSION < 69
4
4
  #error \
5
5
  "Reanimated 3 does not support React Native 0.68.x when Fabric is enabled. Please upgrade to React Native 0.69.0 or newer if you want to use Reanimated with the new architecture."
6
6
  #endif
@@ -4,6 +4,8 @@
4
4
  #include "FabricUtils.h"
5
5
  #include "NewestShadowNodesRegistry.h"
6
6
 
7
+ #include <utility>
8
+
7
9
  using namespace facebook;
8
10
  using namespace react;
9
11
 
@@ -31,8 +31,8 @@ class ShadowTreeCloner {
31
31
  void updateYogaChildren();
32
32
 
33
33
  private:
34
- PropsParserContext propsParserContext_;
35
34
  std::shared_ptr<NewestShadowNodesRegistry> newestShadowNodesRegistry_;
35
+ PropsParserContext propsParserContext_;
36
36
  std::set<ShadowNode *> yogaChildrenUpdates_;
37
37
  };
38
38
 
@@ -4,6 +4,8 @@
4
4
  #include "ShareableValue.h"
5
5
  #include "ValueWrapper.h"
6
6
 
7
+ #include <utility>
8
+
7
9
  namespace reanimated {
8
10
 
9
11
  const long long idOffset = 1e9;
@@ -8,6 +8,7 @@
8
8
  #include <functional>
9
9
  #include <memory>
10
10
  #include <thread>
11
+ #include <unordered_map>
11
12
 
12
13
  #ifdef RCT_NEW_ARCH_ENABLED
13
14
  #include "FabricUtils.h"
@@ -19,6 +19,7 @@
19
19
  #include "RuntimeDecorator.h"
20
20
  #include "RuntimeManager.h"
21
21
  #include "Scheduler.h"
22
+ #include "SingleInstanceChecker.h"
22
23
 
23
24
  namespace reanimated {
24
25
 
@@ -182,6 +183,10 @@ class NativeReanimatedModule : public NativeReanimatedModuleSpec,
182
183
 
183
184
  KeyboardEventSubscribeFunction subscribeForKeyboardEventsFunction;
184
185
  KeyboardEventUnsubscribeFunction unsubscribeFromKeyboardEventsFunction;
186
+
187
+ #ifdef DEBUG
188
+ SingleInstanceChecker<NativeReanimatedModule> singleInstanceChecker_;
189
+ #endif
185
190
  };
186
191
 
187
192
  } // namespace reanimated
@@ -1,5 +1,7 @@
1
1
  #include "NativeReanimatedModuleSpec.h"
2
2
 
3
+ #include <utility>
4
+
3
5
  #define SPEC_PREFIX(FN_NAME) __hostFunction_NativeReanimatedModuleSpec_##FN_NAME
4
6
 
5
7
  namespace reanimated {
@@ -4,7 +4,7 @@
4
4
  #include <string>
5
5
  #include <vector>
6
6
 
7
- #ifdef ONANDROID
7
+ #ifdef ANDROID
8
8
  #include "TurboModule.h"
9
9
  #else
10
10
  #include <ReactCommon/TurboModule.h>
@@ -0,0 +1,93 @@
1
+ #include "ReanimatedHermesRuntime.h"
2
+
3
+ // Only include this file in Hermes-enabled builds as some platforms (like tvOS)
4
+ // don't support hermes and it causes the compilation to fail.
5
+ #if JS_RUNTIME_HERMES
6
+
7
+ #include <cxxreact/MessageQueueThread.h>
8
+ #include <jsi/decorator.h>
9
+ #include <jsi/jsi.h>
10
+
11
+ #include <memory>
12
+ #include <utility>
13
+
14
+ #if __has_include(<reacthermes/HermesExecutorFactory.h>)
15
+ #include <reacthermes/HermesExecutorFactory.h>
16
+ #else // __has_include(<hermes/hermes.h>) || ANDROID
17
+ #include <hermes/hermes.h>
18
+ #endif
19
+
20
+ #include <hermes/inspector/RuntimeAdapter.h>
21
+ #include <hermes/inspector/chrome/Registration.h>
22
+
23
+ namespace reanimated {
24
+
25
+ using namespace facebook;
26
+ using namespace react;
27
+
28
+ #if HERMES_ENABLE_DEBUGGER
29
+
30
+ class HermesExecutorRuntimeAdapter
31
+ : public facebook::hermes::inspector::RuntimeAdapter {
32
+ public:
33
+ HermesExecutorRuntimeAdapter(
34
+ facebook::hermes::HermesRuntime &hermesRuntime,
35
+ std::shared_ptr<MessageQueueThread> thread)
36
+ : hermesRuntime_(hermesRuntime), thread_(std::move(thread)) {}
37
+
38
+ virtual ~HermesExecutorRuntimeAdapter() {
39
+ // This is required by iOS, because there is an assertion in the destructor
40
+ // that the thread was indeed `quit` before
41
+ thread_->quitSynchronous();
42
+ }
43
+
44
+ facebook::jsi::Runtime &getRuntime() override {
45
+ return hermesRuntime_;
46
+ }
47
+
48
+ facebook::hermes::debugger::Debugger &getDebugger() override {
49
+ return hermesRuntime_.getDebugger();
50
+ }
51
+
52
+ // This is not empty in the original implementation, but we decided to tickle
53
+ // the runtime by running a small piece of code on every frame as using this
54
+ // required us to hold a refernce to the runtime inside this adapter which
55
+ // caused issues while reloading the app.
56
+ void tickleJs() override {}
57
+
58
+ public:
59
+ facebook::hermes::HermesRuntime &hermesRuntime_;
60
+ std::shared_ptr<MessageQueueThread> thread_;
61
+ };
62
+
63
+ #endif // HERMES_ENABLE_DEBUGGER
64
+
65
+ ReanimatedHermesRuntime::ReanimatedHermesRuntime(
66
+ std::unique_ptr<facebook::hermes::HermesRuntime> runtime,
67
+ std::shared_ptr<MessageQueueThread> jsQueue)
68
+ : jsi::WithRuntimeDecorator<ReanimatedReentrancyCheck>(
69
+ *runtime,
70
+ reentrancyCheck_),
71
+ runtime_(std::move(runtime)) {
72
+ #if HERMES_ENABLE_DEBUGGER
73
+ auto adapter =
74
+ std::make_unique<HermesExecutorRuntimeAdapter>(*runtime_, jsQueue);
75
+ facebook::hermes::inspector::chrome::enableDebugging(
76
+ std::move(adapter), "Reanimated Runtime");
77
+ #else
78
+ // This is required by iOS, because there is an assertion in the destructor
79
+ // that the thread was indeed `quit` before
80
+ jsQueue->quitSynchronous();
81
+ #endif
82
+ }
83
+
84
+ ReanimatedHermesRuntime::~ReanimatedHermesRuntime() {
85
+ #if HERMES_ENABLE_DEBUGGER
86
+ // We have to disable debugging before the runtime is destroyed.
87
+ facebook::hermes::inspector::chrome::disableDebugging(*runtime_);
88
+ #endif
89
+ }
90
+
91
+ } // namespace reanimated
92
+
93
+ #endif // JS_RUNTIME_HERMES
@@ -0,0 +1,125 @@
1
+ #pragma once
2
+
3
+ // JS_RUNTIME_HERMES is only set on Android so we have to check __has_include
4
+ // on iOS.
5
+ #if __APPLE__ && \
6
+ (__has_include( \
7
+ <reacthermes/HermesExecutorFactory.h>) || __has_include(<hermes/hermes.h>))
8
+ #define JS_RUNTIME_HERMES 1
9
+ #endif
10
+
11
+ // Only include this file in Hermes-enabled builds as some platforms (like tvOS)
12
+ // don't support hermes and it causes the compilation to fail.
13
+ #if JS_RUNTIME_HERMES
14
+
15
+ #include <cxxreact/MessageQueueThread.h>
16
+ #include <jsi/decorator.h>
17
+ #include <jsi/jsi.h>
18
+
19
+ #include <memory>
20
+ #include <thread>
21
+
22
+ #if __has_include(<reacthermes/HermesExecutorFactory.h>)
23
+ #include <reacthermes/HermesExecutorFactory.h>
24
+ #else // __has_include(<hermes/hermes.h>) || ANDROID
25
+ #include <hermes/hermes.h>
26
+ #endif
27
+
28
+ namespace reanimated {
29
+
30
+ using namespace facebook;
31
+ using namespace react;
32
+
33
+ // ReentrancyCheck is copied from React Native
34
+ // from ReactCommon/hermes/executor/HermesExecutorFactory.cpp
35
+ // https://github.com/facebook/react-native/blob/main/ReactCommon/hermes/executor/HermesExecutorFactory.cpp
36
+ struct ReanimatedReentrancyCheck {
37
+ // This is effectively a very subtle and complex assert, so only
38
+ // include it in builds which would include asserts.
39
+ #ifndef NDEBUG
40
+ ReanimatedReentrancyCheck() : tid(std::thread::id()), depth(0) {}
41
+
42
+ void before() {
43
+ std::thread::id this_id = std::this_thread::get_id();
44
+ std::thread::id expected = std::thread::id();
45
+
46
+ // A note on memory ordering: the main purpose of these checks is
47
+ // to observe a before/before race, without an intervening after.
48
+ // This will be detected by the compare_exchange_strong atomicity
49
+ // properties, regardless of memory order.
50
+ //
51
+ // For everything else, it is easiest to think of 'depth' as a
52
+ // proxy for any access made inside the VM. If access to depth
53
+ // are reordered incorrectly, the same could be true of any other
54
+ // operation made by the VM. In fact, using acquire/release
55
+ // memory ordering could create barriers which mask a programmer
56
+ // error. So, we use relaxed memory order, to avoid masking
57
+ // actual ordering errors. Although, in practice, ordering errors
58
+ // of this sort would be surprising, because the decorator would
59
+ // need to call after() without before().
60
+
61
+ if (tid.compare_exchange_strong(
62
+ expected, this_id, std::memory_order_relaxed)) {
63
+ // Returns true if tid and expected were the same. If they
64
+ // were, then the stored tid referred to no thread, and we
65
+ // atomically saved this thread's tid. Now increment depth.
66
+ assert(depth == 0 && "No thread id, but depth != 0");
67
+ ++depth;
68
+ } else if (expected == this_id) {
69
+ // If the stored tid referred to a thread, expected was set to
70
+ // that value. If that value is this thread's tid, that's ok,
71
+ // just increment depth again.
72
+ assert(depth != 0 && "Thread id was set, but depth == 0");
73
+ ++depth;
74
+ } else {
75
+ // The stored tid was some other thread. This indicates a bad
76
+ // programmer error, where VM methods were called on two
77
+ // different threads unsafely. Fail fast (and hard) so the
78
+ // crash can be analyzed.
79
+ __builtin_trap();
80
+ }
81
+ }
82
+
83
+ void after() {
84
+ assert(
85
+ tid.load(std::memory_order_relaxed) == std::this_thread::get_id() &&
86
+ "No thread id in after()");
87
+ if (--depth == 0) {
88
+ // If we decremented depth to zero, store no-thread into tid.
89
+ std::thread::id expected = std::this_thread::get_id();
90
+ bool didWrite = tid.compare_exchange_strong(
91
+ expected, std::thread::id(), std::memory_order_relaxed);
92
+ assert(didWrite && "Decremented to zero, but no tid write");
93
+ }
94
+ }
95
+
96
+ std::atomic<std::thread::id> tid;
97
+ // This is not atomic, as it is only written or read from the owning
98
+ // thread.
99
+ unsigned int depth;
100
+ #endif // NDEBUG
101
+ };
102
+
103
+ // This is in fact a subclass of jsi::Runtime! WithRuntimeDecorator is a
104
+ // template class that is a subclass of DecoratedRuntime which is also a
105
+ // template class that then inherits its template, which in this case is
106
+ // jsi::Runtime. So the inheritance is: ReanimatedHermesRuntime ->
107
+ // WithRuntimeDecorator -> DecoratedRuntime -> jsi::Runtime You can find out
108
+ // more about this in ReactCommon/jsi/jsi/Decorator.h or by following this link:
109
+ // https://github.com/facebook/react-native/blob/main/ReactCommon/jsi/jsi/decorator.h
110
+ class ReanimatedHermesRuntime
111
+ : public jsi::WithRuntimeDecorator<ReanimatedReentrancyCheck> {
112
+ public:
113
+ ReanimatedHermesRuntime(
114
+ std::unique_ptr<facebook::hermes::HermesRuntime> runtime,
115
+ std::shared_ptr<MessageQueueThread> jsQueue);
116
+ ~ReanimatedHermesRuntime();
117
+
118
+ private:
119
+ std::shared_ptr<facebook::hermes::HermesRuntime> runtime_;
120
+ ReanimatedReentrancyCheck reentrancyCheck_;
121
+ };
122
+
123
+ } // namespace reanimated
124
+
125
+ #endif // JS_RUNTIME_HERMES
@@ -0,0 +1,50 @@
1
+ #include "ReanimatedRuntime.h"
2
+
3
+ #include <cxxreact/MessageQueueThread.h>
4
+ #include <jsi/jsi.h>
5
+
6
+ #include <memory>
7
+ #include <utility>
8
+
9
+ #if JS_RUNTIME_HERMES
10
+ #include "ReanimatedHermesRuntime.h"
11
+ #elif JS_RUNTIME_V8
12
+ #include <v8runtime/V8RuntimeFactory.h>
13
+ #else
14
+ #include <jsi/JSCRuntime.h>
15
+ #endif
16
+
17
+ namespace reanimated {
18
+
19
+ using namespace facebook;
20
+ using namespace react;
21
+
22
+ std::shared_ptr<jsi::Runtime> ReanimatedRuntime::make(
23
+ std::shared_ptr<MessageQueueThread> jsQueue) {
24
+ #if JS_RUNTIME_HERMES
25
+ std::unique_ptr<facebook::hermes::HermesRuntime> runtime =
26
+ facebook::hermes::makeHermesRuntime();
27
+
28
+ // We don't call `jsQueue->quitSynchronous()` here, since it will be done
29
+ // later in ReanimatedHermesRuntime
30
+
31
+ return std::make_shared<ReanimatedHermesRuntime>(std::move(runtime), jsQueue);
32
+ #elif JS_RUNTIME_V8
33
+ // This is required by iOS, because there is an assertion in the destructor
34
+ // that the thread was indeed `quit` before.
35
+ jsQueue->quitSynchronous();
36
+
37
+ auto config = std::make_unique<rnv8::V8RuntimeConfig>();
38
+ config->enableInspector = false;
39
+ config->appName = "reanimated";
40
+ return rnv8::createSharedV8Runtime(runtime_, std::move(config));
41
+ #else
42
+ // This is required by iOS, because there is an assertion in the destructor
43
+ // that the thread was indeed `quit` before
44
+ jsQueue->quitSynchronous();
45
+
46
+ return facebook::jsc::makeJSCRuntime();
47
+ #endif
48
+ }
49
+
50
+ } // namespace reanimated
@@ -0,0 +1,27 @@
1
+ #pragma once
2
+
3
+ // JS_RUNTIME_HERMES is only set on Android so we have to check __has_include
4
+ // on iOS.
5
+ #if __APPLE__ && \
6
+ (__has_include( \
7
+ <reacthermes/HermesExecutorFactory.h>) || __has_include(<hermes/hermes.h>))
8
+ #define JS_RUNTIME_HERMES 1
9
+ #endif
10
+
11
+ #include <cxxreact/MessageQueueThread.h>
12
+ #include <jsi/jsi.h>
13
+
14
+ #include <memory>
15
+
16
+ namespace reanimated {
17
+
18
+ using namespace facebook;
19
+ using namespace react;
20
+
21
+ class ReanimatedRuntime {
22
+ public:
23
+ static std::shared_ptr<jsi::Runtime> make(
24
+ std::shared_ptr<MessageQueueThread> jsQueue);
25
+ };
26
+
27
+ } // namespace reanimated
@@ -0,0 +1,194 @@
1
+ # Hermes Runtime initialization
2
+
3
+ _Last updated_: 13/09/2022 by @Kwasow
4
+
5
+ This document describes the current way of initializing Hermes and connecting
6
+ it to the debugger. The work I did was mainly based on
7
+ [HermesExecutorFactory.cpp](https://github.com/facebook/react-native/blob/main/ReactCommon/hermes/executor/HermesExecutorFactory.cpp)
8
+ from React Native.
9
+
10
+ ## Runtime initalization
11
+
12
+ If you take a look at `NativeProxy` (both on Android and iOS) you'll find
13
+ that it only makes a call to `ReanimatedRuntime::make(jsQueue)`. This
14
+ static function will return the correct runtime based on the user's configuration.
15
+
16
+ The initialization process is pretty simple and has only been moved out of
17
+ `NativeProxy` into `ReanimatedRuntime` without any major changes.
18
+
19
+ ## Hermes runtime debugging
20
+
21
+ To enable debugging on the Hermes runtime we need to do two things:
22
+
23
+ 1. Include source maps in JavaScript files
24
+
25
+ This part is done purely in JavaScript via the Babel plugin. The `makeWorklet`
26
+ function received an AST tree, which is aware of the modifications it made to
27
+ the code and therefore can generate the necessary source maps. It is important
28
+ that when we want to create a string from the AST we use the `generate` function
29
+ and enable source map generation so line mappings are not lost. Then when
30
+ transforming that code (ex. with `transformSync`) we have to pass the source
31
+ map as input so it can be updated.
32
+
33
+ Source map settings should always be set to `inline` so they are automatically
34
+ appended to the source code. The generated source map will be a base64 encoded
35
+ json.
36
+
37
+ A workletized function would look like this (after formattings):
38
+ ```js
39
+ function _f(number) {
40
+ console.log(_WORKLET, number);
41
+ }
42
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJtYXBwaW5ncyI6IkFBYXNCLFNBQUNBLEVBQUQsQ0FBQ0EsTUFBRCxFQUFvQjtBQUV0Q0MsU0FBTyxDQUFDQyxHQUFSRCxDQUFZRSxRQUFaRixFQUFzQkQsTUFBdEJDO0FBRmtCIiwibmFtZXMiOlsibnVtYmVyIiwiY29uc29sZSIsImxvZyIsIl9XT1JLTEVUIl0sInNvdXJjZXMiOlsiL1VzZXJzL2thcm9sL0dpdC9yZWFjdC1uYXRpdmUtcmVhbmltYXRlZC9GYWJyaWNFeGFtcGxlL3NyYy9Xb3JrbGV0RXhhbXBsZS50c3giXSwic291cmNlc0NvbnRlbnQiOlsiLyogZ2xvYmFsIF9XT1JLTEVUICovXG5pbXBvcnQgeyBCdXR0b24sIFZpZXcsIFN0eWxlU2hlZXQgfSBmcm9tICdyZWFjdC1uYXRpdmUnO1xuaW1wb3J0IHtcbiAgcnVuT25KUyxcbiAgcnVuT25VSSxcbiAgdXNlRGVyaXZlZFZhbHVlLFxuICB1c2VTaGFyZWRWYWx1ZSxcbn0gZnJvbSAncmVhY3QtbmF0aXZlLXJlYW5pbWF0ZWQnO1xuXG5pbXBvcnQgUmVhY3QgZnJvbSAncmVhY3QnO1xuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBXb3JrbGV0RXhhbXBsZSgpIHtcbiAgLy8gcnVuT25VSSBkZW1vXG4gIGNvbnN0IHNvbWVXb3JrbGV0ID0gKG51bWJlcjogbnVtYmVyKSA9PiB7XG4gICAgJ3dvcmtsZXQnO1xuICAgIGNvbnNvbGUubG9nKF9XT1JLTEVULCBudW1iZXIpOyAvLyBfV09SS0xFVCBzaG91bGQgYmUgdHJ1ZVxuICB9O1xuXG4gIGNvbnN0IGhhbmRsZVByZXNzMSA9ICgpID0+IHtcbiAgICBydW5PblVJKHNvbWVXb3JrbGV0KShNYXRoLnJhbmRvbSgpKTtcbiAgfTtcblxuICAvLyBydW5PbkpTIGRlbW9cbiAgY29uc3QgeCA9IHVzZVNoYXJlZFZhbHVlKDApO1xuXG4gIGNvbnN0IHNvbWVGdW5jdGlvbiA9IChudW1iZXI6IG51bWJlcikgPT4ge1xuICAgIGNvbnNvbGUubG9nKF9XT1JLTEVULCBudW1iZXIpOyAvLyBfV09SS0xFVCBzaG91bGQgYmUgZmFsc2VcbiAgfTtcblxuICB1c2VEZXJpdmVkVmFsdWUoKCkgPT4ge1xuICAgIHJ1bk9uSlMoc29tZUZ1bmN0aW9uKSh4LnZhbHVlKTtcbiAgfSk7XG5cbiAgY29uc3QgaGFuZGxlUHJlc3MyID0gKCkgPT4ge1xuICAgIHgudmFsdWUgPSBNYXRoLnJhbmRvbSgpO1xuICB9O1xuXG4gIHJldHVybiAoXG4gICAgPFZpZXcgc3R5bGU9e3N0eWxlcy5jb250YWluZXJ9PlxuICAgICAgPEJ1dHRvbiBvblByZXNzPXtoYW5kbGVQcmVzczF9IHRpdGxlPVwicnVuT25VSSBkZW1vXCIgLz5cbiAgICAgIDxCdXR0b24gb25QcmVzcz17aGFuZGxlUHJlc3MyfSB0aXRsZT1cInJ1bk9uSlMgZGVtb1wiIC8+XG4gICAgPC9WaWV3PlxuICApO1xufVxuXG5jb25zdCBzdHlsZXMgPSBTdHlsZVNoZWV0LmNyZWF0ZSh7XG4gIGNvbnRhaW5lcjoge1xuICAgIGZsZXg6IDEsXG4gICAgYWxpZ25JdGVtczogJ2NlbnRlcicsXG4gICAganVzdGlmeUNvbnRlbnQ6ICdjZW50ZXInLFxuICB9LFxufSk7XG4iXX0=
43
+ ```
44
+
45
+ And the base64 string after decoding is:
46
+
47
+ ```json
48
+ {
49
+ "version": 3,
50
+ "mappings": "AAasB,SAACA,EAAD,CAACA,MAAD,EAAoB;AAEtCC,SAAO,CAACC,GAARD,CAAYE,QAAZF,EAAsBD,MAAtBC;AAFkB",
51
+ "names": [
52
+ "number",
53
+ "console",
54
+ "log",
55
+ "_WORKLET"
56
+ ],
57
+ "sources": [
58
+ "/Users/karol/Git/react-native-reanimated/FabricExample/src/WorkletExample.tsx"
59
+ ],
60
+ "sourcesContent": [
61
+ "/* global _WORKLET */\nimport { Button, View, StyleSheet } from 'react-native';\nimport {\n runOnJS,\n runOnUI,\n useDerivedValue,\n useSharedValue,\n} from 'react-native-reanimated';\n\nimport React from 'react';\n\nexport default function WorkletExample() {\n // runOnUI demo\n const someWorklet = (number: number) => {\n 'worklet';\n console.log(_WORKLET, number); // _WORKLET should be true\n };\n\n const handlePress1 = () => {\n runOnUI(someWorklet)(Math.random());\n };\n\n // runOnJS demo\n const x = useSharedValue(0);\n\n const someFunction = (number: number) => {\n console.log(_WORKLET, number); // _WORKLET should be false\n };\n\n useDerivedValue(() => {\n runOnJS(someFunction)(x.value);\n });\n\n const handlePress2 = () => {\n x.value = Math.random();\n };\n\n return (\n <View style={styles.container}>\n <Button onPress={handlePress1} title=\"runOnUI demo\" />\n <Button onPress={handlePress2} title=\"runOnJS demo\" />\n </View>\n );\n}\n\nconst styles = StyleSheet.create({\n container: {\n flex: 1,\n alignItems: 'center',\n justifyContent: 'center',\n },\n});\n"
62
+ ]
63
+ }
64
+ ```
65
+
66
+ We run jest tests in release mode, because source maps will contain absolute
67
+ paths, which will be different on every machine and therefore would also alter
68
+ worklet hashes. Running in release mode prevents this.
69
+
70
+ 2. Enable debugging on the runtime object
71
+
72
+ This is done by creating an adapter (`HermesExecutorRuntimeAdapter` inside of
73
+ `ReanimatedHermesRuntime.cpp`) which holds the runtime and allows the debugger
74
+ to communicate with it. The adapter is managed by a `Connection` (`ConnectionDemux`)
75
+ object, but this is not important in our case. We just have to make a call
76
+ to `facebook::hermes::inspector::chrome::enableDebugging()` and pass the adapter
77
+ and runtime name as parameters.
78
+
79
+ It is important to also `disableDebugging()` before the runtime is destroyed.
80
+ Failing to do so will probably crash the app as the debugger will try to
81
+ connect to a non-existent runtime.
82
+
83
+ The runtime should also be destroyed before the Reanimated module, because
84
+ otherwise there might be weird BAD_ACCESS errors when the gc gets it
85
+ hand on the runtime.
86
+
87
+ ## Metro endpoint
88
+
89
+ Flipper and Chrome DevTools in general use the `localhost:8081/json` (where `8081`
90
+ is the port metro is running on) endpoint of metro to get the list of debuggable
91
+ targets (runtimes). For a normal React Native app the output would look something
92
+ like this:
93
+
94
+ ```json
95
+ [
96
+ {
97
+ "id": "0-1",
98
+ "description": "org.reactjs.native.example.FabricExample",
99
+ "title": "Hermes React Native",
100
+ "faviconUrl": "https://reactjs.org/favicon.ico",
101
+ "devtoolsFrontendUrl": "devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws=%5B%3A%3A1%5D%3A8081%2Finspector%2Fdebug%3Fdevice%3D0%26page%3D1",
102
+ "type": "node",
103
+ "webSocketDebuggerUrl": "ws://[::1]:8081/inspector/debug?device=0&page=1",
104
+ "vm": "Hermes"
105
+ },
106
+ {
107
+ "id": "0--1",
108
+ "description": "org.reactjs.native.example.FabricExample",
109
+ "title": "React Native Experimental (Improved Chrome Reloads)",
110
+ "faviconUrl": "https://reactjs.org/favicon.ico",
111
+ "devtoolsFrontendUrl": "devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws=%5B%3A%3A1%5D%3A8081%2Finspector%2Fdebug%3Fdevice%3D0%26page%3D-1",
112
+ "type": "node",
113
+ "webSocketDebuggerUrl": "ws://[::1]:8081/inspector/debug?device=0&page=-1",
114
+ "vm": "don't use"
115
+ }
116
+ ]
117
+ ```
118
+
119
+ For an Android app with Reanimated it should include the Reanimated runtime like
120
+ this:
121
+
122
+ ```json
123
+ [
124
+ {
125
+ "id": "0-2",
126
+ "description": "com.fabricexample",
127
+ "title": "Reanimated Runtime",
128
+ "faviconUrl": "https://reactjs.org/favicon.ico",
129
+ "devtoolsFrontendUrl": "devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws=%5B%3A%3A1%5D%3A8081%2Finspector%2Fdebug%3Fdevice%3D0%26page%3D3",
130
+ "type": "node",
131
+ "webSocketDebuggerUrl": "ws://[::1]:8081/inspector/debug?device=1&page=2",
132
+ "vm": "Hermes"
133
+ },
134
+ {
135
+ "id": "0-1",
136
+ "description": "com.fabricexample",
137
+ "title": "Hermes React Native",
138
+ "faviconUrl": "https://reactjs.org/favicon.ico",
139
+ "devtoolsFrontendUrl": "devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws=%5B%3A%3A1%5D%3A8081%2Finspector%2Fdebug%3Fdevice%3D0%26page%3D2",
140
+ "type": "node",
141
+ "webSocketDebuggerUrl": "ws://[::1]:8081/inspector/debug?device=1&page=1",
142
+ "vm": "Hermes"
143
+ },
144
+ {
145
+ "id": "0--1",
146
+ "description": "com.fabricexample",
147
+ "title": "React Native Experimental (Improved Chrome Reloads)",
148
+ "faviconUrl": "https://reactjs.org/favicon.ico",
149
+ "devtoolsFrontendUrl": "devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws=%5B%3A%3A1%5D%3A8081%2Finspector%2Fdebug%3Fdevice%3D0%26page%3D-1",
150
+ "type": "node",
151
+ "webSocketDebuggerUrl": "ws://[::1]:8081/inspector/debug?device=1&page=-1",
152
+ "vm": "don't use"
153
+ },
154
+ {
155
+ "id": "0--2",
156
+ "description": "com.fabricexample",
157
+ "title": "Reanimated Runtime Experimental (Improved Chrome Reloads)",
158
+ "faviconUrl": "https://reactjs.org/favicon.ico",
159
+ "devtoolsFrontendUrl": "devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws=%5B%3A%3A1%5D%3A8081%2Finspector%2Fdebug%3Fdevice%3D0%26page%3D-2",
160
+ "type": "node",
161
+ "webSocketDebuggerUrl": "ws://[::1]:8081/inspector/debug?device=1&page=-2",
162
+ "vm": "don't use"
163
+ }
164
+ ]
165
+ ```
166
+
167
+ Runtimes with negative IDs are 'virtual' - they are just references to the real
168
+ runtimes but their IDs don't change after a reload. If we were to connect to
169
+ the normal runtime and reload the app it would crash, as the debugger would try
170
+ to communicate with a non-existent runtime. These 'virtual' runtimes are made
171
+ and managed by metro (PR: [facebook/metro#864](https://github.com/facebook/metro/pull/864)).
172
+
173
+ ## Known issues
174
+
175
+ **IFrame sandboxing**
176
+
177
+ Source maps always define a `sources` array, which contain names of files used
178
+ to generate the source map. For Chrome DevTools this is sufficient as it will
179
+ read files from disk, but the `IFrame` interface used by Flipper is sandboxed
180
+ and doesn't allow filesystem access. Therefore we also need to include the files
181
+ content in the `sourcesContent` array.
182
+
183
+ **Chrome version 105.0.5195.102 doesn't load source maps**
184
+
185
+ This version of Chrome introduced a regression into DevTools that broke source
186
+ maps loading for node.js apps. This issue is not caused by Reanimated in any
187
+ way and should be fixed by Chrome developers in later versions.
188
+
189
+ The issue was tracked here: https://bugs.chromium.org/p/chromium/issues/detail?id=1358497
190
+
191
+ **App reloads don't work**
192
+
193
+ On iOS the app will crash on every reload if a debugger is connected to the runtime.
194
+ On Android it will also crash but only after a few reloads.
@@ -1,8 +1,10 @@
1
1
  #include "MapperRegistry.h"
2
+ #include "Mapper.h"
3
+
2
4
  #include <array>
3
5
  #include <map>
4
6
  #include <set>
5
- #include "Mapper.h"
7
+ #include <utility>
6
8
 
7
9
  namespace reanimated {
8
10
 
@@ -2,6 +2,9 @@
2
2
  #include "FrozenObject.h"
3
3
  #include "ShareableValue.h"
4
4
 
5
+ #include <string>
6
+ #include <utility>
7
+
5
8
  using namespace facebook;
6
9
 
7
10
  namespace reanimated {
@@ -20,10 +23,14 @@ std::shared_ptr<jsi::Function> WorkletsCache::getFunction(
20
23
  long long workletHash =
21
24
  ValueWrapper::asNumber(frozenObj->map["__workletHash"]->valueContainer);
22
25
  if (worklets.count(workletHash) == 0) {
26
+ // We need to add a newline before the closing bracket, because in debug
27
+ // builds the last line will be a source map, which is a comment and that
28
+ // would make the bracket part of the comment and cause an error due to a
29
+ // missing closing bracket.
23
30
  auto codeBuffer = std::make_shared<const jsi::StringBuffer>(
24
31
  "(" +
25
32
  ValueWrapper::asString(frozenObj->map["asString"]->valueContainer) +
26
- ")");
33
+ "\n)");
27
34
  auto func = rt.evaluateJavaScript(
28
35
  codeBuffer,
29
36
  ValueWrapper::asString(
@@ -4,6 +4,8 @@
4
4
  #include "ShareableValue.h"
5
5
  #include "SharedParent.h"
6
6
 
7
+ #include <string>
8
+
7
9
  namespace reanimated {
8
10
 
9
11
  void MutableValue::setValue(jsi::Runtime &rt, const jsi::Value &newValue) {