@nocobase/plugin-workflow-javascript 2.1.0-beta.10 → 2.1.0-beta.12

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 (107) hide show
  1. package/dist/externalVersion.js +4 -4
  2. package/dist/node_modules/isolated-vm/.clang-tidy +13 -0
  3. package/dist/node_modules/isolated-vm/.dockerignore +9 -0
  4. package/dist/node_modules/isolated-vm/Dockerfile.alpine +9 -0
  5. package/dist/node_modules/isolated-vm/Dockerfile.debian +12 -0
  6. package/dist/node_modules/isolated-vm/LICENSE +13 -0
  7. package/dist/node_modules/isolated-vm/binding.gyp +120 -0
  8. package/dist/node_modules/isolated-vm/include.js +3 -0
  9. package/dist/node_modules/isolated-vm/inspector-example.js +59 -0
  10. package/dist/node_modules/isolated-vm/isolated-vm.d.ts +820 -0
  11. package/dist/node_modules/isolated-vm/isolated-vm.js +1 -0
  12. package/dist/node_modules/isolated-vm/native-example/binding.gyp +23 -0
  13. package/dist/node_modules/isolated-vm/native-example/example.cc +61 -0
  14. package/dist/node_modules/isolated-vm/native-example/package.json +13 -0
  15. package/dist/node_modules/isolated-vm/native-example/usage.js +35 -0
  16. package/dist/node_modules/isolated-vm/out/isolated_vm.node +0 -0
  17. package/dist/node_modules/isolated-vm/package.json +1 -0
  18. package/dist/node_modules/isolated-vm/src/external_copy/error.h +33 -0
  19. package/dist/node_modules/isolated-vm/src/external_copy/external_copy.cc +509 -0
  20. package/dist/node_modules/isolated-vm/src/external_copy/external_copy.h +117 -0
  21. package/dist/node_modules/isolated-vm/src/external_copy/serializer.cc +85 -0
  22. package/dist/node_modules/isolated-vm/src/external_copy/serializer.h +136 -0
  23. package/dist/node_modules/isolated-vm/src/external_copy/serializer_nortti.cc +73 -0
  24. package/dist/node_modules/isolated-vm/src/external_copy/string.cc +124 -0
  25. package/dist/node_modules/isolated-vm/src/external_copy/string.h +28 -0
  26. package/dist/node_modules/isolated-vm/src/isolate/allocator.h +32 -0
  27. package/dist/node_modules/isolated-vm/src/isolate/allocator_nortti.cc +142 -0
  28. package/dist/node_modules/isolated-vm/src/isolate/class_handle.h +334 -0
  29. package/dist/node_modules/isolated-vm/src/isolate/cpu_profile_manager.cc +220 -0
  30. package/dist/node_modules/isolated-vm/src/isolate/cpu_profile_manager.h +100 -0
  31. package/dist/node_modules/isolated-vm/src/isolate/environment.cc +626 -0
  32. package/dist/node_modules/isolated-vm/src/isolate/environment.h +381 -0
  33. package/dist/node_modules/isolated-vm/src/isolate/executor.cc +198 -0
  34. package/dist/node_modules/isolated-vm/src/isolate/executor.h +183 -0
  35. package/dist/node_modules/isolated-vm/src/isolate/external.h +64 -0
  36. package/dist/node_modules/isolated-vm/src/isolate/functor_runners.h +97 -0
  37. package/dist/node_modules/isolated-vm/src/isolate/generic/array.h +145 -0
  38. package/dist/node_modules/isolated-vm/src/isolate/generic/callbacks.h +272 -0
  39. package/dist/node_modules/isolated-vm/src/isolate/generic/error.h +140 -0
  40. package/dist/node_modules/isolated-vm/src/isolate/generic/extract_params.h +145 -0
  41. package/dist/node_modules/isolated-vm/src/isolate/generic/handle_cast.h +257 -0
  42. package/dist/node_modules/isolated-vm/src/isolate/generic/read_option.h +47 -0
  43. package/dist/node_modules/isolated-vm/src/isolate/holder.cc +88 -0
  44. package/dist/node_modules/isolated-vm/src/isolate/holder.h +63 -0
  45. package/dist/node_modules/isolated-vm/src/isolate/inspector.cc +200 -0
  46. package/dist/node_modules/isolated-vm/src/isolate/inspector.h +70 -0
  47. package/dist/node_modules/isolated-vm/src/isolate/node_wrapper.h +15 -0
  48. package/dist/node_modules/isolated-vm/src/isolate/platform_delegate.cc +22 -0
  49. package/dist/node_modules/isolated-vm/src/isolate/platform_delegate.h +46 -0
  50. package/dist/node_modules/isolated-vm/src/isolate/remote_handle.h +164 -0
  51. package/dist/node_modules/isolated-vm/src/isolate/run_with_timeout.h +171 -0
  52. package/dist/node_modules/isolated-vm/src/isolate/runnable.h +29 -0
  53. package/dist/node_modules/isolated-vm/src/isolate/scheduler.cc +191 -0
  54. package/dist/node_modules/isolated-vm/src/isolate/scheduler.h +165 -0
  55. package/dist/node_modules/isolated-vm/src/isolate/specific.h +35 -0
  56. package/dist/node_modules/isolated-vm/src/isolate/stack_trace.cc +219 -0
  57. package/dist/node_modules/isolated-vm/src/isolate/stack_trace.h +24 -0
  58. package/dist/node_modules/isolated-vm/src/isolate/strings.h +127 -0
  59. package/dist/node_modules/isolated-vm/src/isolate/three_phase_task.cc +385 -0
  60. package/dist/node_modules/isolated-vm/src/isolate/three_phase_task.h +136 -0
  61. package/dist/node_modules/isolated-vm/src/isolate/transferable.h +15 -0
  62. package/dist/node_modules/isolated-vm/src/isolate/util.h +45 -0
  63. package/dist/node_modules/isolated-vm/src/isolate/v8_inspector_wrapper.h +12 -0
  64. package/dist/node_modules/isolated-vm/src/isolate/v8_version.h +12 -0
  65. package/dist/node_modules/isolated-vm/src/isolated_vm.h +71 -0
  66. package/dist/node_modules/isolated-vm/src/lib/covariant.h +50 -0
  67. package/dist/node_modules/isolated-vm/src/lib/lockable.h +178 -0
  68. package/dist/node_modules/isolated-vm/src/lib/suspend.h +106 -0
  69. package/dist/node_modules/isolated-vm/src/lib/thread_pool.cc +98 -0
  70. package/dist/node_modules/isolated-vm/src/lib/thread_pool.h +45 -0
  71. package/dist/node_modules/isolated-vm/src/lib/timer.cc +233 -0
  72. package/dist/node_modules/isolated-vm/src/lib/timer.h +36 -0
  73. package/dist/node_modules/isolated-vm/src/module/callback.cc +151 -0
  74. package/dist/node_modules/isolated-vm/src/module/callback.h +64 -0
  75. package/dist/node_modules/isolated-vm/src/module/context_handle.cc +241 -0
  76. package/dist/node_modules/isolated-vm/src/module/context_handle.h +35 -0
  77. package/dist/node_modules/isolated-vm/src/module/evaluation.cc +109 -0
  78. package/dist/node_modules/isolated-vm/src/module/evaluation.h +99 -0
  79. package/dist/node_modules/isolated-vm/src/module/external_copy_handle.cc +119 -0
  80. package/dist/node_modules/isolated-vm/src/module/external_copy_handle.h +64 -0
  81. package/dist/node_modules/isolated-vm/src/module/isolate.cc +136 -0
  82. package/dist/node_modules/isolated-vm/src/module/isolate_handle.cc +611 -0
  83. package/dist/node_modules/isolated-vm/src/module/isolate_handle.h +47 -0
  84. package/dist/node_modules/isolated-vm/src/module/lib_handle.cc +77 -0
  85. package/dist/node_modules/isolated-vm/src/module/lib_handle.h +28 -0
  86. package/dist/node_modules/isolated-vm/src/module/module_handle.cc +475 -0
  87. package/dist/node_modules/isolated-vm/src/module/module_handle.h +68 -0
  88. package/dist/node_modules/isolated-vm/src/module/native_module_handle.cc +104 -0
  89. package/dist/node_modules/isolated-vm/src/module/native_module_handle.h +49 -0
  90. package/dist/node_modules/isolated-vm/src/module/reference_handle.cc +636 -0
  91. package/dist/node_modules/isolated-vm/src/module/reference_handle.h +106 -0
  92. package/dist/node_modules/isolated-vm/src/module/script_handle.cc +107 -0
  93. package/dist/node_modules/isolated-vm/src/module/script_handle.h +37 -0
  94. package/dist/node_modules/isolated-vm/src/module/session_handle.cc +173 -0
  95. package/dist/node_modules/isolated-vm/src/module/session_handle.h +31 -0
  96. package/dist/node_modules/isolated-vm/src/module/transferable.cc +268 -0
  97. package/dist/node_modules/isolated-vm/src/module/transferable.h +42 -0
  98. package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v18.0.0.h +360 -0
  99. package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v18.3.0.h +376 -0
  100. package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v20.0.0.h +397 -0
  101. package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v22.0.0.h +419 -0
  102. package/dist/node_modules/winston-transport/package.json +1 -1
  103. package/dist/server/IsolatedVm.js +75 -0
  104. package/dist/server/ScriptInstruction.d.ts +6 -0
  105. package/dist/server/ScriptInstruction.js +11 -1
  106. package/dist/server/Vm.js +42 -27
  107. package/package.json +3 -2
@@ -0,0 +1,381 @@
1
+ #pragma once
2
+ #include <ratio>
3
+ #include <string>
4
+ #include <v8.h>
5
+ #include <uv.h>
6
+
7
+ #include "executor.h"
8
+ #include "holder.h"
9
+ #include "remote_handle.h"
10
+ #include "runnable.h"
11
+ #include "scheduler.h"
12
+ #include "specific.h"
13
+ #include "strings.h"
14
+ #include "cpu_profile_manager.h"
15
+ #include "lib/covariant.h"
16
+ #include "lib/lockable.h"
17
+ #include "lib/thread_pool.h"
18
+ #include "v8-profiler.h"
19
+
20
+ #include <atomic>
21
+ #include <cassert>
22
+ #include <chrono>
23
+ #include <deque>
24
+ #include <functional>
25
+ #include <memory>
26
+ #include <mutex>
27
+ #include <queue>
28
+ #include <set>
29
+ #include <unordered_map>
30
+ #include <vector>
31
+ #include <list>
32
+
33
+ namespace ivm {
34
+
35
+ /**
36
+ * Wrapper around Isolate with helpers to make working with multiple isolates easier.
37
+ */
38
+ class IsolateEnvironment {
39
+ // These are here so they can adjust `extra_allocated_memory`. TODO: Make this a method
40
+ friend class ExternalCopyString;
41
+
42
+ friend class Executor;
43
+ friend class InspectorAgent;
44
+ friend class InspectorSession;
45
+ friend class IsolateHolder;
46
+ friend class LimitedAllocator;
47
+ friend class LockedScheduler;
48
+ friend StringTable;
49
+ friend class ThreePhaseTask;
50
+ template <class>
51
+ friend class IsolateSpecific;
52
+ template <typename F>
53
+ friend auto RunWithTimeout(uint32_t timeout_ms, F&& fn) -> v8::Local<v8::Value>;
54
+
55
+ public:
56
+ /**
57
+ * Ensures we don't blow up the v8 heap while transferring arbitrary data
58
+ */
59
+ class HeapCheck {
60
+ private:
61
+ IsolateEnvironment& env;
62
+ size_t extra_size_before;
63
+ bool force;
64
+ public:
65
+ explicit HeapCheck(IsolateEnvironment& env, bool force = false);
66
+ HeapCheck(const HeapCheck&) = delete;
67
+ auto operator= (const HeapCheck&) -> HeapCheck& = delete;
68
+ ~HeapCheck() = default;
69
+ void Epilogue();
70
+ };
71
+
72
+ private:
73
+
74
+ struct ReleaseAndJoinHandle {
75
+ std::shared_ptr<IsolateDisposeWait> dispose_wait;
76
+ std::weak_ptr<IsolateHolder> holder;
77
+
78
+ auto operator<(const ReleaseAndJoinHandle& right) const -> bool {
79
+ return dispose_wait.owner_before(right.dispose_wait);
80
+ }
81
+ };
82
+
83
+ // Another good candidate for std::optional<> (because this is only used by the root isolate)
84
+ using OwnedIsolates = lockable_t<std::set<ReleaseAndJoinHandle>, true>;
85
+ std::unique_ptr<OwnedIsolates> owned_isolates;
86
+
87
+ v8::Isolate* isolate{};
88
+ covariant_t<LockedScheduler, IsolatedScheduler, UvScheduler> scheduler;
89
+ Executor executor;
90
+ std::shared_ptr<IsolateDisposeWait> dispose_wait{std::make_shared<IsolateDisposeWait>()};
91
+ std::weak_ptr<IsolateHolder> holder;
92
+ std::shared_ptr<IsolateTaskRunner> task_runner;
93
+ std::unique_ptr<class InspectorAgent> inspector_agent;
94
+ v8::Persistent<v8::Context> default_context;
95
+ std::shared_ptr<v8::ArrayBuffer::Allocator> allocator_ptr;
96
+ std::shared_ptr<v8::BackingStore> snapshot_blob_ptr;
97
+ v8::StartupData startup_data{};
98
+ void* timer_holder = nullptr;
99
+ size_t memory_limit = 0;
100
+ size_t initial_heap_size_limit = 0;
101
+ size_t misc_memory_size = 0;
102
+ std::atomic<size_t> extra_allocated_memory = 0;
103
+ v8::MemoryPressureLevel memory_pressure = v8::MemoryPressureLevel::kNone;
104
+ v8::MemoryPressureLevel last_memory_pressure = v8::MemoryPressureLevel::kNone;
105
+ bool hit_memory_limit = false;
106
+ bool did_adjust_heap_limit = false;
107
+ bool nodejs_isolate = false;
108
+ std::atomic<unsigned int> remotes_count{0};
109
+ v8::HeapStatistics last_heap {};
110
+ // Copyable traits used to opt into destructor handle reset
111
+ std::deque<v8::Persistent<v8::Promise, v8::CopyablePersistentTraits<v8::Promise>>> unhandled_promise_rejections;
112
+ StringTable string_table;
113
+
114
+ std::vector<v8::Eternal<v8::Data>> specifics;
115
+ std::unordered_map<v8::Persistent<v8::Value>*, std::pair<void(*)(void*), void*>> weak_persistents;
116
+ std::shared_ptr<CpuProfileManager> cpu_profile_manager;
117
+
118
+ public:
119
+ RemoteHandle<v8::Function> error_handler;
120
+ std::unordered_multimap<int, struct ModuleInfo*> module_handles;
121
+ std::unordered_map<class NativeModule*, std::shared_ptr<NativeModule>> native_modules;
122
+ int terminate_depth = 0;
123
+ std::atomic<bool> terminated { false };
124
+
125
+ private:
126
+
127
+ /**
128
+ * If this function is called then I have failed you.
129
+ */
130
+ static void OOMErrorCallback(const char* location, bool is_heap_oom);
131
+ #if V8_AT_LEAST(10, 4, 9)
132
+ static void OOMErrorCallback(const char* location, const v8::OOMDetails& details) {
133
+ OOMErrorCallback(location, details.is_heap_oom);
134
+ }
135
+ #endif
136
+
137
+ /**
138
+ * Called when an isolate has an uncaught error in a promise. This makes no distinction between
139
+ * contexts so we have to handle that ourselves.
140
+ */
141
+ static void PromiseRejectCallback(v8::PromiseRejectMessage rejection);
142
+ public:
143
+ void PromiseWasHandled(v8::Local<v8::Promise> promise);
144
+
145
+ private:
146
+ static auto CodeGenCallback(v8::Local<v8::Context> context, v8::Local<v8::Value> source) -> v8::ModifyCodeGenerationFromStringsResult;
147
+ static auto CodeGenCallback2(v8::Local<v8::Context> context, v8::Local<v8::Value> source, bool) -> v8::ModifyCodeGenerationFromStringsResult;
148
+
149
+ /**
150
+ * GC hooks to kill this isolate before it runs out of memory
151
+ */
152
+ static void MarkSweepCompactEpilogue(v8::Isolate* isolate, v8::GCType gc_type, v8::GCCallbackFlags gc_flags, void* data);
153
+ static auto NearHeapLimitCallback(void* data, size_t current_heap_limit, size_t initial_heap_limit) -> size_t;
154
+ void RequestMemoryPressureNotification(v8::MemoryPressureLevel memory_pressure, bool as_interrupt = false);
155
+ static void MemoryPressureInterrupt(v8::Isolate* isolate, void* data);
156
+ void CheckMemoryPressure();
157
+
158
+ /**
159
+ * Wrap an existing Isolate. This should only be called for the main node Isolate.
160
+ */
161
+ void IsolateCtor(v8::Isolate* isolate, v8::Local<v8::Context> context);
162
+
163
+ /**
164
+ * Create a new wrapped Isolate.
165
+ */
166
+ void IsolateCtor(size_t memory_limit_in_mb, std::shared_ptr<v8::BackingStore> snapshot_blob, size_t snapshot_length);
167
+
168
+ public:
169
+ /**
170
+ * The constructor should be called through the factory.
171
+ */
172
+ IsolateEnvironment();
173
+ explicit IsolateEnvironment(UvScheduler& default_scheduler);
174
+ IsolateEnvironment(const IsolateEnvironment&) = delete;
175
+ auto operator= (const IsolateEnvironment&) -> IsolateEnvironment = delete;
176
+ ~IsolateEnvironment();
177
+
178
+ /**
179
+ * Factory method which generates an IsolateHolder.
180
+ */
181
+ static auto New(v8::Isolate* isolate, v8::Local<v8::Context> context) -> std::shared_ptr<IsolateHolder> {
182
+ auto env = std::make_shared<IsolateEnvironment>();
183
+ auto holder = std::make_shared<IsolateHolder>(env);
184
+ env->holder = holder;
185
+ env->IsolateCtor(isolate, context);
186
+ return holder;
187
+ }
188
+
189
+ static auto New(size_t memory_limit_in_mb, std::shared_ptr<v8::BackingStore> snapshot_blob, size_t snapshot_length) -> std::shared_ptr<IsolateHolder> {
190
+ auto env = std::make_shared<IsolateEnvironment>(static_cast<UvScheduler&>(*Executor::GetDefaultEnvironment().scheduler));
191
+ auto holder = std::make_shared<IsolateHolder>(env);
192
+ env->holder = holder;
193
+ env->IsolateCtor(memory_limit_in_mb, std::move(snapshot_blob), snapshot_length);
194
+ return holder;
195
+ }
196
+
197
+ /**
198
+ * Return pointer the currently running IsolateEnvironment
199
+ */
200
+ static auto GetCurrent() -> IsolateEnvironment& {
201
+ auto* environment = Executor::GetCurrentEnvironment();
202
+ assert(environment != nullptr);
203
+ return *environment;
204
+
205
+ }
206
+
207
+ /**
208
+ * Return shared_ptr to current IsolateHolder
209
+ */
210
+ static auto GetCurrentHolder() -> std::shared_ptr<IsolateHolder> {
211
+ return Executor::GetCurrentEnvironment()->holder.lock();
212
+ }
213
+
214
+ auto GetScheduler() -> LockedScheduler& {
215
+ return *scheduler;
216
+ }
217
+
218
+ auto GetTaskRunner() -> const std::shared_ptr<IsolateTaskRunner>& {
219
+ return task_runner;
220
+ }
221
+
222
+ /**
223
+ * Convenience operators to work with underlying isolate
224
+ */
225
+ operator v8::Isolate*() const { // NOLINT
226
+ return isolate;
227
+ }
228
+
229
+ auto operator->() const -> v8::Isolate* { // Should probably remove this one..
230
+ return isolate;
231
+ }
232
+
233
+ auto GetIsolate() const -> v8::Isolate* {
234
+ return isolate;
235
+ }
236
+
237
+ /**
238
+ * Default context, useful for generating certain objects when we aren't in a context.
239
+ */
240
+ auto DefaultContext() const -> v8::Local<v8::Context> {
241
+ return v8::Local<v8::Context>::New(isolate, default_context);
242
+ }
243
+
244
+ /**
245
+ * Creates a new context. Must be used instead of Context::New() because of snapshot deserialization
246
+ */
247
+ auto NewContext() -> v8::Local<v8::Context>;
248
+
249
+ /**
250
+ * Called by Scheduler when there is work to be done in this isolate.
251
+ */
252
+ void AsyncEntry();
253
+ private:
254
+ template <std::queue<std::unique_ptr<Runnable>> Scheduler::*Tasks>
255
+ void InterruptEntryImplementation();
256
+ public:
257
+ void InterruptEntryAsync();
258
+ void InterruptEntrySync();
259
+
260
+ /**
261
+ * This is called after user code runs. This throws a fatal error if the memory limit was hit.
262
+ * If an asyncronous exception (promise) was lost, this will throw it for real.
263
+ */
264
+ auto TaskEpilogue() -> std::unique_ptr<class ExternalCopy>;
265
+
266
+ /**
267
+ * Get allocator used by this isolate. Will return nullptr for the default isolate.
268
+ */
269
+ auto GetLimitedAllocator() const -> class LimitedAllocator*;
270
+
271
+ /**
272
+ * Get the initial v8 heap_size_limit when the isolate was created.
273
+ */
274
+ auto GetInitialHeapSizeLimit() const -> size_t {
275
+ return initial_heap_size_limit;
276
+ }
277
+
278
+ /**
279
+ * Enables the inspector for this isolate.
280
+ */
281
+ void EnableInspectorAgent();
282
+
283
+ /**
284
+ * Returns the InspectorAgent for this Isolate.
285
+ */
286
+ auto GetInspectorAgent() const -> InspectorAgent*;
287
+
288
+ // Return IsolateHolder
289
+ auto GetHolder() { return holder; }
290
+
291
+ auto GetDisposeWaitHandle() {
292
+ return dispose_wait;
293
+ }
294
+
295
+ /**
296
+ * Check memory limit flag
297
+ */
298
+ auto DidHitMemoryLimit() const -> bool {
299
+ return hit_memory_limit;
300
+ }
301
+
302
+ /**
303
+ * Not to be confused with v8's `ExternalAllocatedMemory`. This counts up how much memory this
304
+ * isolate is holding onto outside of v8's heap, even if that memory is shared amongst other
305
+ * isolates.
306
+ */
307
+ auto GetExtraAllocatedMemory() const -> size_t {
308
+ return extra_allocated_memory;
309
+ }
310
+ void AdjustExtraAllocatedMemory(int size) {
311
+ extra_allocated_memory += size;
312
+ }
313
+
314
+ /**
315
+ * Returns the current number of outstanding RemoteHandles<> to this isolate.
316
+ */
317
+ auto GetRemotesCount() const -> unsigned int {
318
+ return remotes_count.load();
319
+ }
320
+ void AdjustRemotes(int delta) {
321
+ remotes_count.fetch_add(delta);
322
+ }
323
+
324
+ /**
325
+ * Is this the default nodejs isolate?
326
+ */
327
+ auto IsDefault() const -> bool {
328
+ return nodejs_isolate;
329
+ }
330
+
331
+ /**
332
+ * Timer getters
333
+ */
334
+ auto GetCpuTime() -> std::chrono::nanoseconds;
335
+ auto GetWallTime() -> std::chrono::nanoseconds;
336
+
337
+ /**
338
+ * CPU Profiler
339
+ */
340
+ auto GetCpuProfileManager() -> CpuProfileManager*;
341
+
342
+ /**
343
+ * Ask this isolate to finish everything it's doing.
344
+ */
345
+ void Terminate();
346
+
347
+ /**
348
+ * Since a created Isolate can be disposed of at any time we need to keep track of weak
349
+ * persistents to call those destructors on isolate disposal.
350
+ */
351
+ void AddWeakCallback(v8::Persistent<v8::Value>* handle, void(*fn)(void*), void* param);
352
+ void RemoveWeakCallback(v8::Persistent<v8::Value>* handle);
353
+ };
354
+
355
+ template <class Type>
356
+ template <class Functor>
357
+ auto IsolateSpecific<Type>::Deref(Functor callback) -> v8::Local<Type> {
358
+ auto& env = *Executor::GetCurrentEnvironment();
359
+ if (env.specifics.size() <= key) {
360
+ assert(key <= detail::IsolateSpecificSize);
361
+ env.specifics.resize(detail::IsolateSpecificSize);
362
+ }
363
+ auto& eternal = env.specifics[key];
364
+ if (eternal.IsEmpty()) {
365
+ auto handle = callback();
366
+ // After `callback` is invoked `eternal` is no longer valid! The callback may reference
367
+ // new IsolateSpecifics which will end up calling `resize` on the underlying vector.
368
+ env.specifics[key].Set(env.isolate, handle);
369
+ return handle;
370
+ }
371
+ // This is dangerous but `Local` doesn't let you upcast from `Data` to `Value`
372
+ return HandleConvert{eternal.Get(env.isolate)}.value;
373
+ }
374
+
375
+ inline auto StringTable::Get() -> auto& {
376
+ return Executor::GetCurrentEnvironment()->string_table;
377
+ }
378
+
379
+ auto RaiseCatastrophicError(RemoteHandle<v8::Function>& handler, const char* message) -> bool;
380
+
381
+ } // namespace ivm
@@ -0,0 +1,198 @@
1
+ #include "executor.h"
2
+ #include "environment.h"
3
+ #include "isolate/util.h"
4
+ #include "lib/timer.h"
5
+ #include "v8-profiler.h"
6
+ #include "v8.h"
7
+ #include <cstddef>
8
+ #include <cstdio>
9
+
10
+ namespace ivm {
11
+
12
+ /**
13
+ * Executor implementation
14
+ */
15
+ Executor::Executor(IsolateEnvironment& env) :
16
+ env{env},
17
+ default_executor{*(current_executor == nullptr ? (current_executor = this) : &current_executor->default_executor)},
18
+ default_thread{&default_executor == this ? std::this_thread::get_id() : default_executor.default_thread} {}
19
+
20
+ Executor::~Executor() {
21
+ if (this == &default_executor) {
22
+ assert(current_executor == &default_executor);
23
+ current_executor = nullptr;
24
+ }
25
+ }
26
+
27
+ auto Executor::MayRunInlineTasks(IsolateEnvironment& env) -> bool {
28
+ if (current_executor == &env.executor) {
29
+ if (env.nodejs_isolate) {
30
+ // nodejs isolates are active by default in their owned thread even if there is no Scope up.
31
+ // This can cause problems when the GC runs and invokes weak callbacks because there is no
32
+ // v8::HandleScope set up.
33
+ return current_executor->depth > 0;
34
+ } else {
35
+ return true;
36
+ }
37
+ }
38
+ return false;
39
+ }
40
+
41
+ thread_local Executor* Executor::current_executor = nullptr;
42
+ thread_local Executor::CpuTimer* Executor::cpu_timer_thread = nullptr;
43
+
44
+ /**
45
+ * CpuTimer implementation
46
+ */
47
+ Executor::CpuTimer::CpuTimer(Executor& executor) :
48
+ executor{executor}, last{cpu_timer_thread}, time{Now()}
49
+ #if USE_CLOCK_THREAD_CPUTIME_ID
50
+ , steady_time{std::chrono::steady_clock::now()}
51
+ #endif
52
+ {
53
+ cpu_timer_thread = this;
54
+ std::lock_guard<std::mutex> lock{executor.timer_mutex};
55
+ assert(executor.cpu_timer == nullptr);
56
+ executor.cpu_timer = this;
57
+ }
58
+
59
+ Executor::CpuTimer::~CpuTimer() {
60
+ cpu_timer_thread = last;
61
+ std::lock_guard<std::mutex> lock{executor.timer_mutex};
62
+ executor.cpu_time += Now() - time;
63
+ assert(executor.cpu_timer == this);
64
+ executor.cpu_timer = nullptr;
65
+ }
66
+
67
+ auto Executor::CpuTimer::Delta(const std::lock_guard<std::mutex>& /*lock*/) const -> std::chrono::nanoseconds {
68
+ #if USE_CLOCK_THREAD_CPUTIME_ID
69
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now() - steady_time);
70
+ #else
71
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(Now() - time);
72
+ #endif
73
+ }
74
+
75
+ void Executor::CpuTimer::Pause() {
76
+ std::lock_guard<std::mutex> lock{executor.timer_mutex};
77
+ executor.cpu_time += Now() - time;
78
+ assert(executor.cpu_timer == this);
79
+ executor.cpu_timer = nullptr;
80
+ timer_t::pause(executor.env.timer_holder);
81
+ }
82
+
83
+ void Executor::CpuTimer::Resume() {
84
+ std::lock_guard<std::mutex> lock{executor.timer_mutex};
85
+ time = Now();
86
+ #if USE_CLOCK_THREAD_CPUTIME_ID
87
+ steady_time = std::chrono::steady_clock::now();
88
+ #endif
89
+ assert(executor.cpu_timer == nullptr);
90
+ executor.cpu_timer = this;
91
+ timer_t::resume(executor.env.timer_holder);
92
+ }
93
+
94
+ #if USE_CLOCK_THREAD_CPUTIME_ID
95
+ auto Executor::CpuTimer::Now() -> TimePoint {
96
+ timespec ts{};
97
+ assert(clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts) == 0);
98
+ return TimePoint{std::chrono::duration_cast<std::chrono::system_clock::duration>(
99
+ std::chrono::seconds{ts.tv_sec} + std::chrono::nanoseconds{ts.tv_nsec}
100
+ )};
101
+ }
102
+ #else
103
+ auto Executor::CpuTimer::Now() -> TimePoint {
104
+ return std::chrono::steady_clock::now();
105
+ }
106
+ #endif
107
+
108
+ /**
109
+ * WallTimer implementation
110
+ */
111
+ Executor::WallTimer::WallTimer(Executor& executor) :
112
+ executor{executor}, cpu_timer{cpu_timer_thread} {
113
+ // Pause current CPU timer which may not belong to this isolate
114
+ if (cpu_timer != nullptr) {
115
+ cpu_timer->Pause();
116
+ }
117
+ // Maybe start wall timer
118
+ if (executor.wall_timer == nullptr) {
119
+ std::lock_guard<std::mutex> lock{executor.timer_mutex};
120
+ executor.wall_timer = this;
121
+ time = std::chrono::steady_clock::now();
122
+ }
123
+ }
124
+
125
+ Executor::WallTimer::~WallTimer() {
126
+ // Resume old CPU timer
127
+ if (cpu_timer != nullptr) {
128
+ cpu_timer->Resume();
129
+ }
130
+ // Maybe update wall time
131
+ if (executor.wall_timer == this) {
132
+ std::lock_guard<std::mutex> lock{executor.timer_mutex};
133
+ executor.wall_timer = nullptr;
134
+ executor.wall_time += std::chrono::steady_clock::now() - time;
135
+ }
136
+ }
137
+
138
+ auto Executor::WallTimer::Delta(const std::lock_guard<std::mutex>& /*lock*/) const -> std::chrono::nanoseconds {
139
+ return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now() - time);
140
+ }
141
+
142
+ /**
143
+ * Scope ctor
144
+ */
145
+ Executor::Scope::Scope(IsolateEnvironment& env) : last{current_executor} {
146
+ current_executor = &env.executor;
147
+ ++current_executor->depth;
148
+ }
149
+
150
+ Executor::Scope::~Scope() {
151
+ --current_executor->depth;
152
+ current_executor = last;
153
+ }
154
+
155
+ Executor::Profiler::Profiler(IsolateEnvironment& env) {
156
+ environment = &env;
157
+ executor = &env.executor;
158
+ isolate = env.isolate;
159
+ profiler = nullptr;
160
+
161
+ if (env.GetCpuProfileManager()->IsProfiling()) {
162
+ profiler = v8::CpuProfiler::New(isolate, v8::kDebugNaming, v8::kEagerLogging);
163
+ const v8::Local<v8::String> title = v8::String::NewFromUtf8(isolate, "isolated-vm").ToLocalChecked();
164
+ profiler->StartProfiling(title, true);
165
+ }
166
+ }
167
+
168
+ Executor::Profiler::~Profiler() {
169
+ if (profiler == nullptr) {
170
+ return;
171
+ }
172
+
173
+ auto DeleterLambda =[](v8::CpuProfile *profile){
174
+ profile->Delete();
175
+ };
176
+ const v8::Local<v8::String> title = v8::String::NewFromUtf8(isolate, "isolated-vm").ToLocalChecked();
177
+ const std::shared_ptr<v8::CpuProfile> profile{profiler->StopProfiling(title),DeleterLambda};
178
+ environment->GetCpuProfileManager()->InjestCpuProfile(profile);
179
+ }
180
+
181
+ /**
182
+ * Lock implementation
183
+ */
184
+ Executor::Lock::Lock(IsolateEnvironment& env) :
185
+ scope{env},
186
+ wall_timer{env.executor},
187
+ locker{env.isolate},
188
+ cpu_timer{env.executor},
189
+ isolate_scope{env.isolate},
190
+ handle_scope{env.isolate},
191
+ profiler(env) {}
192
+
193
+ /**
194
+ * Unlock implementation
195
+ */
196
+ Executor::Unlock::Unlock(IsolateEnvironment& env) : pause_scope{env.executor.cpu_timer}, unlocker{env.isolate} {}
197
+
198
+ } // namespace ivm