react-native-windows 0.71.24 → 0.71.25

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 (77) hide show
  1. package/Directory.Build.props +5 -0
  2. package/Libraries/Network/RCTNetworking.windows.js +10 -16
  3. package/Microsoft.ReactNative/IReactDispatcher.cpp +4 -0
  4. package/Microsoft.ReactNative/IReactDispatcher.h +1 -0
  5. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +3 -7
  6. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters +0 -7
  7. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +43 -21
  8. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.h +0 -2
  9. package/Microsoft.ReactNative/Views/DevMenu.cpp +3 -3
  10. package/Microsoft.ReactNative.Cxx/JSI/NodeApiJsiLoader.cpp +16 -0
  11. package/Microsoft.ReactNative.Cxx/Microsoft.ReactNative.Cxx.vcxitems +43 -12
  12. package/Microsoft.ReactNative.Cxx/Microsoft.ReactNative.Cxx.vcxitems.filters +17 -6
  13. package/PropertySheets/External/Microsoft.ReactNative.Uwp.CSharpApp.targets +1 -1
  14. package/PropertySheets/External/Microsoft.ReactNative.Uwp.CppApp.targets +1 -1
  15. package/PropertySheets/External/Microsoft.ReactNative.WinAppSDK.CSharpApp.targets +1 -1
  16. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  17. package/PropertySheets/JSEngine.props +4 -4
  18. package/PropertySheets/React.Cpp.props +3 -3
  19. package/PropertySheets/Warnings.props +6 -0
  20. package/ReactCommon/ReactCommon.vcxproj +53 -1
  21. package/ReactCommon/cgmanifest.json +15 -0
  22. package/Scripts/Tfs/Layout-MSRN-Headers.ps1 +36 -0
  23. package/Shared/BaseFileReaderResource.cpp +95 -0
  24. package/Shared/BaseFileReaderResource.h +41 -0
  25. package/Shared/CreateModules.h +27 -5
  26. package/Shared/DevSupportManager.cpp +2 -9
  27. package/Shared/DevSupportManager.h +2 -6
  28. package/Shared/HermesRuntimeHolder.cpp +344 -84
  29. package/Shared/HermesRuntimeHolder.h +32 -21
  30. package/Shared/HermesSamplingProfiler.cpp +66 -14
  31. package/Shared/HermesSamplingProfiler.h +5 -3
  32. package/Shared/IFileReaderResource.h +36 -0
  33. package/Shared/InspectorPackagerConnection.cpp +62 -108
  34. package/Shared/InspectorPackagerConnection.h +9 -21
  35. package/Shared/JSI/RuntimeHolder.h +2 -2
  36. package/Shared/JSI/ScriptStore.h +18 -20
  37. package/Shared/JSI/V8RuntimeHolder.cpp +260 -0
  38. package/Shared/JSI/V8RuntimeHolder.h +37 -0
  39. package/Shared/Modules/BlobModule.cpp +93 -298
  40. package/Shared/Modules/BlobModule.h +25 -91
  41. package/Shared/Modules/CxxModuleUtilities.cpp +32 -0
  42. package/Shared/Modules/CxxModuleUtilities.h +17 -0
  43. package/Shared/Modules/FileReaderModule.cpp +118 -51
  44. package/Shared/Modules/FileReaderModule.h +27 -1
  45. package/Shared/Modules/HttpModule.cpp +133 -9
  46. package/Shared/Modules/HttpModule.h +33 -0
  47. package/Shared/Modules/IRequestBodyHandler.h +6 -4
  48. package/Shared/Modules/IResponseHandler.h +3 -3
  49. package/Shared/Modules/IUriHandler.h +3 -3
  50. package/Shared/Modules/IWebSocketModuleContentHandler.h +6 -4
  51. package/Shared/Modules/WebSocketModule.cpp +190 -7
  52. package/Shared/Modules/WebSocketTurboModule.h +52 -0
  53. package/Shared/Networking/DefaultBlobResource.cpp +323 -0
  54. package/Shared/Networking/DefaultBlobResource.h +133 -0
  55. package/Shared/Networking/IBlobResource.h +56 -0
  56. package/Shared/Networking/IHttpResource.h +6 -5
  57. package/Shared/Networking/WinRTHttpResource.cpp +40 -32
  58. package/Shared/Networking/WinRTHttpResource.h +4 -3
  59. package/Shared/Networking/WinRTTypes.h +3 -3
  60. package/Shared/OInstance.cpp +17 -33
  61. package/Shared/SafeLoadLibrary.cpp +41 -0
  62. package/Shared/SafeLoadLibrary.h +15 -0
  63. package/Shared/Shared.vcxitems +27 -9
  64. package/Shared/Shared.vcxitems.filters +47 -33
  65. package/package.json +2 -2
  66. package/template/cs-app-WinAppSDK/proj/ExperimentalFeatures.props +1 -1
  67. package/Microsoft.ReactNative/Base/CoreNativeModules.cpp +0 -59
  68. package/Microsoft.ReactNative/Base/CoreNativeModules.h +0 -30
  69. package/Microsoft.ReactNative.Cxx/JSI/NodeApiJsiRuntime.cpp +0 -2103
  70. package/Microsoft.ReactNative.Cxx/JSI/NodeApiJsiRuntime.h +0 -73
  71. package/Shared/HermesShim.cpp +0 -118
  72. package/Shared/HermesShim.h +0 -21
  73. package/Shared/JSI/NapiJsiV8RuntimeHolder.cpp +0 -209
  74. package/Shared/JSI/NapiJsiV8RuntimeHolder.h +0 -44
  75. package/Shared/V8JSIRuntimeHolder.cpp +0 -70
  76. package/Shared/V8JSIRuntimeHolder.h +0 -53
  77. /package/Shared/{Modules/IBlobPersistor.h → IBlobPersistor.h} +0 -0
@@ -3,134 +3,394 @@
3
3
 
4
4
  #include "pch.h"
5
5
 
6
- #include <memory>
7
- #include <mutex>
6
+ #include "HermesRuntimeHolder.h"
8
7
 
8
+ #include <ApiLoaders/HermesApi.h>
9
9
  #include <JSI/decorator.h>
10
- #include <cxxreact/MessageQueueThread.h>
10
+ #include <NodeApiJsiRuntime.h>
11
+ #include <crash/verifyElseCrash.h>
11
12
  #include <cxxreact/SystraceSection.h>
12
- #include <hermes/hermes.h>
13
- #include "HermesRuntimeHolder.h"
14
- #include "HermesShim.h"
13
+ #include <jsinspector/InspectorInterfaces.h>
14
+ #include <mutex>
15
+ #include "SafeLoadLibrary.h"
15
16
 
16
- #if defined(HERMES_ENABLE_DEBUGGER)
17
- #include <hermes/inspector/chrome/Registration.h>
18
- #endif
17
+ #define CRASH_ON_ERROR(result) VerifyElseCrash(result == napi_ok);
19
18
 
20
- using namespace facebook;
21
- using namespace Microsoft::ReactNative;
19
+ namespace React {
20
+ using namespace winrt::Microsoft::ReactNative;
21
+ }
22
+
23
+ using namespace Microsoft::NodeApiJsi;
22
24
 
23
- namespace facebook {
24
- namespace react {
25
+ namespace Microsoft::ReactNative {
26
+
27
+ React::ReactPropertyId<React::ReactNonAbiValue<std::shared_ptr<HermesRuntimeHolder>>>
28
+ HermesRuntimeHolderProperty() noexcept {
29
+ static React::ReactPropertyId<React::ReactNonAbiValue<std::shared_ptr<HermesRuntimeHolder>>> propId{
30
+ L"ReactNative.HermesRuntimeHolder", L"HermesRuntimeHolder"};
31
+ return propId;
32
+ }
25
33
 
26
34
  namespace {
27
35
 
28
- std::unique_ptr<facebook::hermes::HermesRuntime> makeHermesRuntimeSystraced(bool enableDefaultCrashHandler) {
29
- SystraceSection s("HermesExecutorFactory::makeHermesRuntimeSystraced");
30
- if (enableDefaultCrashHandler) {
31
- return HermesShim::makeHermesRuntimeWithWER();
32
- } else {
33
- auto runtimeConfig = ::hermes::vm::RuntimeConfig();
34
- return HermesShim::makeHermesRuntime(runtimeConfig);
36
+ int32_t NAPI_CDECL addInspectorPage(const char *title, const char *vm, void *connectFunc) noexcept;
37
+ void NAPI_CDECL removeInspectorPage(int32_t pageId) noexcept;
38
+
39
+ class HermesFuncResolver : public IFuncResolver {
40
+ public:
41
+ HermesFuncResolver() : libHandle_(SafeLoadLibrary(L"hermes.dll")) {}
42
+
43
+ FuncPtr getFuncPtr(const char *funcName) override {
44
+ return reinterpret_cast<FuncPtr>(GetProcAddress(libHandle_, funcName));
35
45
  }
46
+
47
+ private:
48
+ HMODULE libHandle_;
49
+ };
50
+
51
+ HermesApi &initHermesApi() noexcept {
52
+ static HermesFuncResolver funcResolver;
53
+ static HermesApi s_hermesApi(&funcResolver);
54
+ HermesApi::setCurrent(&s_hermesApi);
55
+ CRASH_ON_ERROR(s_hermesApi.hermes_set_inspector(&addInspectorPage, &removeInspectorPage));
56
+ return s_hermesApi;
57
+ }
58
+
59
+ HermesApi &getHermesApi() noexcept {
60
+ static HermesApi &s_hermesApi = initHermesApi();
61
+ return s_hermesApi;
36
62
  }
37
63
 
38
- #ifdef HERMES_ENABLE_DEBUGGER
39
- class HermesExecutorRuntimeAdapter final : public facebook::hermes::inspector::RuntimeAdapter {
64
+ class HermesTask {
65
+ public:
66
+ HermesTask(
67
+ void *taskData,
68
+ jsr_task_run_cb taskRunCallback,
69
+ jsr_data_delete_cb taskDataDeleteCallback,
70
+ void *deleterData)
71
+ : taskData_(taskData),
72
+ taskRunCallback_(taskRunCallback),
73
+ taskDataDeleteCallback_(taskDataDeleteCallback),
74
+ deleterData_(deleterData) {}
75
+
76
+ HermesTask(const HermesTask &other) = delete;
77
+ HermesTask &operator=(const HermesTask &other) = delete;
78
+
79
+ ~HermesTask() {
80
+ if (taskDataDeleteCallback_ != nullptr) {
81
+ taskDataDeleteCallback_(taskData_, deleterData_);
82
+ }
83
+ }
84
+
85
+ void Run() const {
86
+ if (taskRunCallback_ != nullptr) {
87
+ taskRunCallback_(taskData_);
88
+ }
89
+ }
90
+
91
+ private:
92
+ void *taskData_;
93
+ jsr_task_run_cb taskRunCallback_;
94
+ jsr_data_delete_cb taskDataDeleteCallback_;
95
+ void *deleterData_;
96
+ };
97
+
98
+ class HermesTaskRunner {
99
+ public:
100
+ static void Create(jsr_config config, std::shared_ptr<facebook::react::MessageQueueThread> queue) {
101
+ CRASH_ON_ERROR(getHermesApi().jsr_config_set_task_runner(
102
+ config, new HermesTaskRunner(std::move(queue)), &PostTask, &Delete, nullptr));
103
+ }
104
+
105
+ private:
106
+ HermesTaskRunner(std::shared_ptr<facebook::react::MessageQueueThread> queue) : queue_(std::move(queue)) {}
107
+
108
+ static void NAPI_CDECL PostTask(
109
+ void *taskRunnerData,
110
+ void *taskData,
111
+ jsr_task_run_cb taskRunCallback,
112
+ jsr_data_delete_cb taskDataDeleteCallback,
113
+ void *deleterData) {
114
+ auto task = std::make_shared<HermesTask>(taskData, taskRunCallback, taskDataDeleteCallback, deleterData);
115
+ reinterpret_cast<HermesTaskRunner *>(taskRunnerData)->queue_->runOnQueue([task = std::move(task)] { task->Run(); });
116
+ }
117
+
118
+ static void NAPI_CDECL Delete(void *taskRunner, void * /*deleterData*/) {
119
+ delete reinterpret_cast<HermesTaskRunner *>(taskRunner);
120
+ }
121
+
122
+ private:
123
+ std::shared_ptr<facebook::react::MessageQueueThread> queue_;
124
+ };
125
+
126
+ struct HermesJsiBuffer : facebook::jsi::Buffer {
127
+ static std::shared_ptr<const facebook::jsi::Buffer>
128
+ Create(const uint8_t *buffer, size_t bufferSize, jsr_data_delete_cb bufferDeleteCallback, void *deleterData) {
129
+ return std::shared_ptr<const facebook::jsi::Buffer>(
130
+ new HermesJsiBuffer(buffer, bufferSize, bufferDeleteCallback, deleterData));
131
+ }
132
+
133
+ HermesJsiBuffer(
134
+ const uint8_t *buffer,
135
+ size_t bufferSize,
136
+ jsr_data_delete_cb bufferDeleteCallback,
137
+ void *deleterData) noexcept
138
+ : buffer_(buffer),
139
+ bufferSize_(bufferSize),
140
+ bufferDeleteCallback_(bufferDeleteCallback),
141
+ deleterData_(deleterData) {}
142
+
143
+ ~HermesJsiBuffer() override {
144
+ if (bufferDeleteCallback_) {
145
+ bufferDeleteCallback_(const_cast<uint8_t *>(buffer_), deleterData_);
146
+ }
147
+ }
148
+
149
+ const uint8_t *data() const override {
150
+ return buffer_;
151
+ }
152
+
153
+ size_t size() const override {
154
+ return bufferSize_;
155
+ }
156
+
157
+ private:
158
+ const uint8_t *buffer_;
159
+ size_t bufferSize_;
160
+ jsr_data_delete_cb bufferDeleteCallback_;
161
+ void *deleterData_;
162
+ };
163
+
164
+ class HermesScriptCache {
40
165
  public:
41
- HermesExecutorRuntimeAdapter(
42
- std::shared_ptr<jsi::Runtime> runtime,
43
- facebook::hermes::HermesRuntime &hermesRuntime,
44
- std::shared_ptr<MessageQueueThread> thread)
45
- : m_runtime(runtime), m_hermesRuntime(hermesRuntime), m_thread(std::move(thread)) {}
166
+ static void Create(jsr_config config, std::shared_ptr<facebook::jsi::PreparedScriptStore> scriptStore) {
167
+ CRASH_ON_ERROR(getHermesApi().jsr_config_set_script_cache(
168
+ config, new HermesScriptCache(std::move(scriptStore)), &LoadScript, &StoreScript, &Delete, nullptr));
169
+ }
46
170
 
47
- virtual ~HermesExecutorRuntimeAdapter() = default;
171
+ private:
172
+ HermesScriptCache(std::shared_ptr<facebook::jsi::PreparedScriptStore> scriptStore)
173
+ : scriptStore_(std::move(scriptStore)) {}
174
+
175
+ static void NAPI_CDECL LoadScript(
176
+ void *scriptCache,
177
+ const char *sourceUrl,
178
+ uint64_t sourceHash,
179
+ const char *runtimeName,
180
+ uint64_t runtimeVersion,
181
+ const char *cacheTag,
182
+ const uint8_t **buffer,
183
+ size_t *bufferSize,
184
+ jsr_data_delete_cb *bufferDeleteCallback,
185
+ void **deleterData) {
186
+ auto &scriptStore = reinterpret_cast<HermesScriptCache *>(scriptCache)->scriptStore_;
187
+ std::shared_ptr<const facebook::jsi::Buffer> preparedScript = scriptStore->tryGetPreparedScript(
188
+ facebook::jsi::ScriptSignature{sourceUrl, sourceHash},
189
+ facebook::jsi::JSRuntimeSignature{runtimeName, runtimeVersion},
190
+ cacheTag);
191
+ if (preparedScript) {
192
+ *buffer = preparedScript->data();
193
+ *bufferSize = preparedScript->size();
194
+ *bufferDeleteCallback = [](void * /*data*/, void *deleterData) noexcept {
195
+ delete reinterpret_cast<std::shared_ptr<const facebook::jsi::Buffer> *>(deleterData);
196
+ };
197
+ *deleterData = new std::shared_ptr<const facebook::jsi::Buffer>(std::move(preparedScript));
198
+ } else {
199
+ *buffer = nullptr;
200
+ *bufferSize = 0;
201
+ *bufferDeleteCallback = nullptr;
202
+ *deleterData = nullptr;
203
+ }
204
+ }
205
+
206
+ static void NAPI_CDECL StoreScript(
207
+ void *scriptCache,
208
+ const char *sourceUrl,
209
+ uint64_t sourceHash,
210
+ const char *runtimeName,
211
+ uint64_t runtimeVersion,
212
+ const char *cacheTag,
213
+ const uint8_t *buffer,
214
+ size_t bufferSize,
215
+ jsr_data_delete_cb bufferDeleteCallback,
216
+ void *deleterData) {
217
+ auto &scriptStore = reinterpret_cast<HermesScriptCache *>(scriptCache)->scriptStore_;
218
+ scriptStore->persistPreparedScript(
219
+ HermesJsiBuffer::Create(buffer, bufferSize, bufferDeleteCallback, deleterData),
220
+ facebook::jsi::ScriptSignature{sourceUrl, sourceHash},
221
+ facebook::jsi::JSRuntimeSignature{runtimeName, runtimeVersion},
222
+ cacheTag);
223
+ }
224
+
225
+ static void NAPI_CDECL Delete(void *scriptCache, void * /*deleterData*/) {
226
+ delete reinterpret_cast<HermesScriptCache *>(scriptCache);
227
+ }
228
+
229
+ private:
230
+ std::shared_ptr<facebook::jsi::PreparedScriptStore> scriptStore_;
231
+ };
232
+
233
+ class HermesLocalConnection : public facebook::react::ILocalConnection {
234
+ public:
235
+ HermesLocalConnection(
236
+ std::unique_ptr<facebook::react::IRemoteConnection> remoteConneciton,
237
+ void *connectFunc) noexcept {
238
+ CRASH_ON_ERROR(getHermesApi().hermes_create_local_connection(
239
+ connectFunc,
240
+ reinterpret_cast<hermes_remote_connection>(remoteConneciton.release()),
241
+ &OnRemoteConnectionSendMessage,
242
+ &OnRemoteConnectionDisconnect,
243
+ &OnRemoteConnectionDelete,
244
+ nullptr,
245
+ &localConnection_));
246
+ }
48
247
 
49
- jsi::Runtime &getRuntime() override {
50
- return *m_runtime;
248
+ ~HermesLocalConnection() override {
249
+ CRASH_ON_ERROR(getHermesApi().hermes_delete_local_connection(localConnection_));
51
250
  }
52
251
 
53
- facebook::hermes::debugger::Debugger &getDebugger() override {
54
- return m_hermesRuntime.getDebugger();
252
+ void sendMessage(std::string message) {
253
+ CRASH_ON_ERROR(getHermesApi().hermes_local_connection_send_message(localConnection_, message.c_str()));
55
254
  }
56
255
 
57
- void tickleJs() override {
58
- // The queue will ensure that runtime_ is still valid when this
59
- // gets invoked.
60
- m_thread->runOnQueue([&runtime = m_runtime]() {
61
- auto func = runtime->global().getPropertyAsFunction(*runtime, "__tickleJs");
62
- func.call(*runtime);
63
- });
256
+ void disconnect() {
257
+ CRASH_ON_ERROR(getHermesApi().hermes_local_connection_disconnect(localConnection_));
64
258
  }
65
259
 
66
260
  private:
67
- std::shared_ptr<jsi::Runtime> m_runtime;
68
- facebook::hermes::HermesRuntime &m_hermesRuntime;
261
+ static void NAPI_CDECL OnRemoteConnectionSendMessage(hermes_remote_connection remoteConnection, const char *message) {
262
+ reinterpret_cast<facebook::react::IRemoteConnection *>(remoteConnection)->onMessage(message);
263
+ }
264
+
265
+ static void NAPI_CDECL OnRemoteConnectionDisconnect(hermes_remote_connection remoteConnection) {
266
+ reinterpret_cast<facebook::react::IRemoteConnection *>(remoteConnection)->onDisconnect();
267
+ }
69
268
 
70
- std::shared_ptr<MessageQueueThread> m_thread;
269
+ static void NAPI_CDECL OnRemoteConnectionDelete(void *remoteConnection, void * /*deleterData*/) {
270
+ delete reinterpret_cast<facebook::react::IRemoteConnection *>(remoteConnection);
271
+ }
272
+
273
+ private:
274
+ hermes_local_connection localConnection_{};
71
275
  };
72
- #endif
276
+
277
+ int32_t NAPI_CDECL addInspectorPage(const char *title, const char *vm, void *connectFunc) noexcept {
278
+ return facebook::react::getInspectorInstance().addPage(
279
+ title,
280
+ vm,
281
+ [connectFunc,
282
+ hermesApi = HermesApi::current()](std::unique_ptr<facebook::react::IRemoteConnection> remoteConneciton) {
283
+ HermesApi::Scope apiScope(hermesApi);
284
+ return std::make_unique<HermesLocalConnection>(std::move(remoteConneciton), connectFunc);
285
+ });
286
+ }
287
+
288
+ void NAPI_CDECL removeInspectorPage(int32_t pageId) noexcept {
289
+ facebook::react::getInspectorInstance().removePage(pageId);
290
+ }
73
291
 
74
292
  } // namespace
75
293
 
76
- void HermesRuntimeHolder::crashHandler(int fileDescriptor) noexcept {
77
- HermesShim::hermesCrashHandler(*m_hermesRuntime, fileDescriptor);
294
+ HermesRuntimeHolder::HermesRuntimeHolder(
295
+ std::shared_ptr<facebook::react::DevSettings> devSettings,
296
+ std::shared_ptr<facebook::react::MessageQueueThread> jsQueue,
297
+ std::shared_ptr<facebook::jsi::PreparedScriptStore> preparedScriptStore) noexcept
298
+ : m_weakDevSettings(devSettings),
299
+ m_jsQueue(std::move(jsQueue)),
300
+ m_preparedScriptStore(std::move(preparedScriptStore)) {}
301
+
302
+ HermesRuntimeHolder::~HermesRuntimeHolder() {
303
+ if (m_runtime) {
304
+ CRASH_ON_ERROR(getHermesApi().jsr_delete_runtime(m_runtime));
305
+ }
78
306
  }
79
307
 
80
- void HermesRuntimeHolder::teardown() noexcept {
81
- #ifdef HERMES_ENABLE_DEBUGGER
82
- if (auto devSettings = m_weakDevSettings.lock(); devSettings && devSettings->useDirectDebugger) {
83
- facebook::hermes::inspector::chrome::disableDebugging(*m_hermesRuntime);
308
+ void HermesRuntimeHolder::initRuntime() noexcept {
309
+ facebook::react::SystraceSection s("HermesExecutorFactory::makeHermesRuntimeSystraced");
310
+ std::shared_ptr<facebook::react::DevSettings> devSettings = m_weakDevSettings.lock();
311
+ VerifyElseCrash(devSettings);
312
+
313
+ HermesApi &api = getHermesApi();
314
+ HermesApi::setCurrent(&api);
315
+ jsr_config config{};
316
+ CRASH_ON_ERROR(api.jsr_create_config(&config));
317
+ CRASH_ON_ERROR(api.hermes_config_enable_default_crash_handler(config, devSettings->enableDefaultCrashHandler));
318
+ CRASH_ON_ERROR(api.jsr_config_enable_inspector(config, devSettings->useDirectDebugger));
319
+ CRASH_ON_ERROR(api.jsr_config_set_inspector_runtime_name(config, devSettings->debuggerRuntimeName.c_str()));
320
+ CRASH_ON_ERROR(api.jsr_config_set_inspector_port(config, devSettings->debuggerPort));
321
+ CRASH_ON_ERROR(api.jsr_config_set_inspector_break_on_start(config, devSettings->debuggerBreakOnNextLine));
322
+ if (m_jsQueue) {
323
+ HermesTaskRunner::Create(config, m_jsQueue);
324
+ }
325
+ if (m_preparedScriptStore) {
326
+ HermesScriptCache::Create(config, m_preparedScriptStore);
84
327
  }
85
- #endif
328
+ jsr_runtime runtime{};
329
+ CRASH_ON_ERROR(api.jsr_create_runtime(config, &runtime));
330
+ CRASH_ON_ERROR(api.jsr_delete_config(config));
331
+
332
+ napi_env env{};
333
+ CRASH_ON_ERROR(api.jsr_runtime_get_node_api_env(runtime, &env));
334
+
335
+ m_jsiRuntime = makeNodeApiJsiRuntime(
336
+ env, &api, [runtime]() { CRASH_ON_ERROR(HermesApi::current()->jsr_delete_runtime(runtime)); });
337
+ m_ownThreadId = std::this_thread::get_id();
338
+
339
+ // Add JS engine information to Error.prototype so in error reporting we
340
+ // can send this information.
341
+ auto errorPrototype = m_jsiRuntime->global()
342
+ .getPropertyAsObject(*m_jsiRuntime, "Error")
343
+ .getPropertyAsObject(*m_jsiRuntime, "prototype");
344
+ errorPrototype.setProperty(*m_jsiRuntime, "jsEngine", "hermes");
86
345
  }
87
346
 
88
347
  facebook::react::JSIEngineOverride HermesRuntimeHolder::getRuntimeType() noexcept {
89
348
  return facebook::react::JSIEngineOverride::Hermes;
90
349
  }
91
350
 
92
- std::shared_ptr<jsi::Runtime> HermesRuntimeHolder::getRuntime() noexcept {
93
- std::call_once(m_once_flag, [this]() { initRuntime(); });
351
+ std::shared_ptr<facebook::jsi::Runtime> HermesRuntimeHolder::getRuntime() noexcept {
352
+ std::call_once(m_onceFlag, [this]() { initRuntime(); });
353
+ VerifyElseCrash(m_jsiRuntime);
354
+ return m_jsiRuntime;
355
+ }
356
+
357
+ void HermesRuntimeHolder::crashHandler(int fileDescriptor) noexcept {
358
+ CRASH_ON_ERROR(getHermesApi().hermes_dump_crash_data(m_runtime, fileDescriptor));
359
+ }
94
360
 
95
- if (!m_hermesRuntime)
96
- std::terminate();
361
+ void HermesRuntimeHolder::teardown() noexcept {
362
+ // TODO: (vmoroz) Implement
363
+ }
97
364
 
98
- // Make sure that the runtime instance is not consumed from multiple threads.
99
- if (m_own_thread_id != std::this_thread::get_id())
100
- std::terminate();
365
+ std::shared_ptr<HermesRuntimeHolder> HermesRuntimeHolder::loadFrom(
366
+ React::ReactPropertyBag const &propertyBag) noexcept {
367
+ return *(propertyBag.Get(HermesRuntimeHolderProperty()));
368
+ }
101
369
 
102
- return m_hermesRuntime;
370
+ void HermesRuntimeHolder::storeTo(
371
+ React::ReactPropertyBag const &propertyBag,
372
+ std::shared_ptr<HermesRuntimeHolder> const &holder) noexcept {
373
+ propertyBag.Set(HermesRuntimeHolderProperty(), holder);
103
374
  }
104
375
 
105
- HermesRuntimeHolder::HermesRuntimeHolder(
106
- std::shared_ptr<facebook::react::DevSettings> devSettings,
107
- std::shared_ptr<facebook::react::MessageQueueThread> jsQueue) noexcept
108
- : m_weakDevSettings(devSettings), m_jsQueue(std::move(jsQueue)) {}
376
+ void HermesRuntimeHolder::addToProfiling() const noexcept {
377
+ CRASH_ON_ERROR(getHermesApi().hermes_sampling_profiler_add(m_runtime));
378
+ }
109
379
 
110
- void HermesRuntimeHolder::initRuntime() noexcept {
111
- auto devSettings = m_weakDevSettings.lock();
112
- if (!devSettings)
113
- std::terminate();
380
+ void HermesRuntimeHolder::removeFromProfiling() const noexcept {
381
+ CRASH_ON_ERROR(getHermesApi().hermes_sampling_profiler_remove(m_runtime));
382
+ }
114
383
 
115
- m_hermesRuntime = makeHermesRuntimeSystraced(devSettings->enableDefaultCrashHandler);
116
- m_own_thread_id = std::this_thread::get_id();
384
+ /*static*/ void HermesRuntimeHolder::enableSamplingProfiler() noexcept {
385
+ CRASH_ON_ERROR(getHermesApi().hermes_sampling_profiler_enable());
386
+ }
117
387
 
118
- #ifdef HERMES_ENABLE_DEBUGGER
119
- if (devSettings->useDirectDebugger) {
120
- auto adapter = std::make_unique<HermesExecutorRuntimeAdapter>(m_hermesRuntime, *m_hermesRuntime, m_jsQueue);
121
- facebook::hermes::inspector::chrome::enableDebugging(
122
- std::move(adapter),
123
- devSettings->debuggerRuntimeName.empty() ? "Hermes React Native" : devSettings->debuggerRuntimeName);
124
- }
125
- #endif
388
+ /*static*/ void HermesRuntimeHolder::disableSamplingProfiler() noexcept {
389
+ CRASH_ON_ERROR(getHermesApi().hermes_sampling_profiler_disable());
390
+ }
126
391
 
127
- // Add js engine information to Error.prototype so in error reporting we
128
- // can send this information.
129
- auto errorPrototype = m_hermesRuntime->global()
130
- .getPropertyAsObject(*m_hermesRuntime, "Error")
131
- .getPropertyAsObject(*m_hermesRuntime, "prototype");
132
- errorPrototype.setProperty(*m_hermesRuntime, "jsEngine", "hermes");
392
+ /*static*/ void HermesRuntimeHolder::dumpSampledTraceToFile(const std::string &fileName) noexcept {
393
+ CRASH_ON_ERROR(getHermesApi().hermes_sampling_profiler_dump_to_file(fileName.c_str()));
133
394
  }
134
395
 
135
- } // namespace react
136
- } // namespace facebook
396
+ } // namespace Microsoft::ReactNative
@@ -2,43 +2,54 @@
2
2
  // Licensed under the MIT License.
3
3
 
4
4
  #pragma once
5
- #include <JSI/RuntimeHolder.h>
6
-
7
- #include <jsi/jsi.h>
8
- #include <thread>
9
-
10
5
  #include <DevSettings.h>
6
+ #include <JSI/RuntimeHolder.h>
7
+ #include <JSI/ScriptStore.h>
8
+ #include <ReactPropertyBag.h>
9
+ #include <cxxreact/MessageQueueThread.h>
10
+ #include <hermes/hermes_api.h>
11
11
 
12
- namespace facebook::hermes {
13
- class HermesRuntime;
14
- }
15
-
16
- namespace facebook {
17
- namespace react {
12
+ namespace Microsoft::ReactNative {
18
13
 
19
14
  class HermesRuntimeHolder : public Microsoft::JSI::RuntimeHolderLazyInit {
20
- public:
15
+ public: // RuntimeHolderLazyInit implementation.
21
16
  std::shared_ptr<facebook::jsi::Runtime> getRuntime() noexcept override;
22
17
  facebook::react::JSIEngineOverride getRuntimeType() noexcept override;
23
-
24
18
  void crashHandler(int fileDescriptor) noexcept override;
25
-
26
19
  void teardown() noexcept override;
27
20
 
21
+ public:
28
22
  HermesRuntimeHolder(
29
23
  std::shared_ptr<facebook::react::DevSettings> devSettings,
30
- std::shared_ptr<facebook::react::MessageQueueThread> jsQueue) noexcept;
24
+ std::shared_ptr<facebook::react::MessageQueueThread> jsQueue,
25
+ std::shared_ptr<facebook::jsi::PreparedScriptStore> preparedScriptStore) noexcept;
26
+ ~HermesRuntimeHolder();
27
+
28
+ static std::shared_ptr<HermesRuntimeHolder> loadFrom(
29
+ winrt::Microsoft::ReactNative::ReactPropertyBag const &propertyBag) noexcept;
30
+
31
+ static void storeTo(
32
+ winrt::Microsoft::ReactNative::ReactPropertyBag const &propertyBag,
33
+ std::shared_ptr<HermesRuntimeHolder> const &holder) noexcept;
34
+
35
+ void addToProfiling() const noexcept;
36
+ void removeFromProfiling() const noexcept;
37
+
38
+ static void enableSamplingProfiler() noexcept;
39
+ static void disableSamplingProfiler() noexcept;
40
+ static void dumpSampledTraceToFile(const std::string &fileName) noexcept;
31
41
 
32
42
  private:
33
43
  void initRuntime() noexcept;
34
- std::shared_ptr<facebook::hermes::HermesRuntime> m_hermesRuntime;
35
-
36
- std::once_flag m_once_flag;
37
- std::thread::id m_own_thread_id;
38
44
 
45
+ private:
46
+ jsr_runtime m_runtime{};
47
+ std::shared_ptr<facebook::jsi::Runtime> m_jsiRuntime;
48
+ std::once_flag m_onceFlag{};
49
+ std::thread::id m_ownThreadId{};
39
50
  std::weak_ptr<facebook::react::DevSettings> m_weakDevSettings;
40
51
  std::shared_ptr<facebook::react::MessageQueueThread> m_jsQueue;
52
+ std::shared_ptr<facebook::jsi::PreparedScriptStore> m_preparedScriptStore;
41
53
  };
42
54
 
43
- } // namespace react
44
- } // namespace facebook
55
+ } // namespace Microsoft::ReactNative
@@ -3,19 +3,51 @@
3
3
 
4
4
  #include "pch.h"
5
5
 
6
- #include <hermes/hermes.h>
6
+ #include <hermes/hermes_api.h>
7
7
  #include <chrono>
8
8
  #include <future>
9
9
 
10
+ #include "HermesRuntimeHolder.h"
10
11
  #include "HermesSamplingProfiler.h"
11
- #include "HermesShim.h"
12
+ #include "IReactDispatcher.h"
13
+ #include "ReactPropertyBag.h"
12
14
  #include "Utils.h"
13
15
 
16
+ using namespace winrt::Microsoft::ReactNative;
17
+ using namespace facebook::react;
18
+
14
19
  namespace Microsoft::ReactNative {
15
20
 
16
21
  namespace {
22
+
23
+ // Implements an awaiter for Mso::DispatchQueue
24
+ auto resume_in_dispatcher(const IReactDispatcher &dispatcher) noexcept {
25
+ struct awaitable {
26
+ awaitable(const IReactDispatcher &dispatcher) noexcept : dispatcher_(dispatcher) {}
27
+
28
+ bool await_ready() const noexcept {
29
+ return false;
30
+ }
31
+
32
+ void await_resume() const noexcept {}
33
+
34
+ void await_suspend(std::experimental::coroutine_handle<> resume) noexcept {
35
+ callback_ = [context = resume.address()]() noexcept {
36
+ std::experimental::coroutine_handle<>::from_address(context)();
37
+ };
38
+ dispatcher_.Post(std::move(callback_));
39
+ }
40
+
41
+ private:
42
+ IReactDispatcher dispatcher_;
43
+ ReactDispatcherCallback callback_;
44
+ };
45
+
46
+ return awaitable{dispatcher};
47
+ }
48
+
17
49
  std::future<std::string> getTraceFilePath() noexcept {
18
- auto hermesDataPath = co_await Microsoft::React::getApplicationDataPath(L"Hermes");
50
+ std::string hermesDataPath = co_await Microsoft::React::getApplicationDataPath(L"Hermes");
19
51
  std::ostringstream os;
20
52
  auto now = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch())
21
53
  .count();
@@ -23,39 +55,59 @@ std::future<std::string> getTraceFilePath() noexcept {
23
55
  os << hermesDataPath << "\\cpu_" << now << ".cpuprofile";
24
56
  co_return os.str();
25
57
  }
58
+
26
59
  } // namespace
27
60
 
28
- bool HermesSamplingProfiler::s_isStarted = false;
61
+ std::atomic_bool HermesSamplingProfiler::s_isStarted{false};
29
62
  std::string HermesSamplingProfiler::s_lastTraceFilePath;
30
63
 
31
64
  std::string HermesSamplingProfiler::GetLastTraceFilePath() noexcept {
32
65
  return s_lastTraceFilePath;
33
66
  }
34
67
 
35
- winrt::fire_and_forget HermesSamplingProfiler::Start() noexcept {
36
- if (!s_isStarted) {
37
- s_isStarted = true;
68
+ winrt::fire_and_forget HermesSamplingProfiler::Start(
69
+ Mso::CntPtr<Mso::React::IReactContext> const &reactContext) noexcept {
70
+ bool expectedIsStarted = false;
71
+ if (s_isStarted.compare_exchange_strong(expectedIsStarted, true)) {
72
+ IReactDispatcher jsDispatcher = implementation::ReactDispatcher::GetJSDispatcher(reactContext->Properties());
73
+ ReactPropertyBag propertyBag = ReactPropertyBag(reactContext->Properties());
74
+
75
+ co_await resume_in_dispatcher(jsDispatcher);
76
+ std::shared_ptr<HermesRuntimeHolder> hermesRuntimeHolder = HermesRuntimeHolder::loadFrom(propertyBag);
77
+ hermesRuntimeHolder->addToProfiling();
78
+
38
79
  co_await winrt::resume_background();
39
- HermesShim::enableSamplingProfiler();
80
+ HermesRuntimeHolder::enableSamplingProfiler();
40
81
  }
41
82
 
42
83
  co_return;
43
84
  }
44
85
 
45
- std::future<std::string> HermesSamplingProfiler::Stop() noexcept {
46
- if (s_isStarted) {
47
- s_isStarted = false;
86
+ std::future<std::string> HermesSamplingProfiler::Stop(
87
+ Mso::CntPtr<Mso::React::IReactContext> const &reactContext) noexcept {
88
+ bool expectedIsStarted = true;
89
+ if (s_isStarted.compare_exchange_strong(expectedIsStarted, false)) {
90
+ IReactDispatcher jsDispatcher = implementation::ReactDispatcher::GetJSDispatcher(reactContext->Properties());
91
+ ReactPropertyBag propertyBag = ReactPropertyBag(reactContext->Properties());
92
+
48
93
  co_await winrt::resume_background();
49
- HermesShim::disableSamplingProfiler();
94
+ HermesRuntimeHolder::disableSamplingProfiler();
95
+
50
96
  s_lastTraceFilePath = co_await getTraceFilePath();
51
- HermesShim::dumpSampledTraceToFile(s_lastTraceFilePath);
97
+ HermesRuntimeHolder::dumpSampledTraceToFile(s_lastTraceFilePath);
98
+
99
+ co_await resume_in_dispatcher(jsDispatcher);
100
+ std::shared_ptr<HermesRuntimeHolder> hermesRuntimeHolder = HermesRuntimeHolder::loadFrom(propertyBag);
101
+ hermesRuntimeHolder->removeFromProfiling();
102
+
103
+ co_await winrt::resume_background();
52
104
  }
53
105
 
54
106
  co_return s_lastTraceFilePath;
55
107
  }
56
108
 
57
109
  bool HermesSamplingProfiler::IsStarted() noexcept {
58
- return s_isStarted;
110
+ return s_isStarted.load();
59
111
  }
60
112
 
61
113
  } // namespace Microsoft::ReactNative