@nocobase/plugin-workflow-javascript 2.1.0-beta.11 → 2.1.0-beta.13

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,70 @@
1
+ #pragma once
2
+ #include <v8.h>
3
+ #include "lib/lockable.h"
4
+ #include "runnable.h"
5
+ #include "v8_inspector_wrapper.h"
6
+ #include <condition_variable>
7
+ #include <memory>
8
+ #include <mutex>
9
+ #include <unordered_set>
10
+
11
+ namespace ivm {
12
+ class IsolateEnvironment;
13
+ class InspectorSession;
14
+
15
+ /**
16
+ * This handles communication to the v8 backend. There is only one of these per isolate, but many
17
+ * sessions may connect to this agent.
18
+ *
19
+ * This class combines the role of both V8Inspector and V8InspectorClient into a single class.
20
+ */
21
+ class InspectorAgent : public v8_inspector::V8InspectorClient {
22
+ friend class InspectorSession;
23
+ private:
24
+ IsolateEnvironment& isolate;
25
+ std::unique_ptr<v8_inspector::V8Inspector> inspector;
26
+ std::condition_variable cv;
27
+ std::mutex mutex;
28
+ lockable_t<std::unordered_set<InspectorSession*>> active_sessions;
29
+ bool running = false;
30
+ bool terminated = false;
31
+
32
+ auto ConnectSession(InspectorSession& session) -> std::unique_ptr<v8_inspector::V8InspectorSession>;
33
+ void SessionDisconnected(InspectorSession& session);
34
+ void SendInterrupt(std::unique_ptr<Runnable> task);
35
+
36
+ public:
37
+ explicit InspectorAgent(IsolateEnvironment& isolate);
38
+ ~InspectorAgent() override;
39
+ InspectorAgent(const InspectorAgent&) = delete;
40
+ auto operator= (const InspectorAgent&) -> InspectorAgent& = delete;
41
+ void runMessageLoopOnPause(int context_group_id) final;
42
+ void quitMessageLoopOnPause() final;
43
+ void ContextCreated(v8::Local<v8::Context> context, const std::string& name);
44
+ void ContextDestroyed(v8::Local<v8::Context> context);
45
+ void Terminate();
46
+ };
47
+
48
+ /**
49
+ * Individual session to the v8 inspector agent. This probably relays messages from a websocket to
50
+ * the v8 backend. To use the class you need to implement the abstract methods defined in Channel.
51
+ *
52
+ * This class combines the role of both V8Inspector::Channel and V8InspectorSession into a single
53
+ * class.
54
+ */
55
+ class InspectorSession : public v8_inspector::V8Inspector::Channel {
56
+ friend class InspectorAgent;
57
+ private:
58
+ InspectorAgent& agent;
59
+ std::shared_ptr<v8_inspector::V8InspectorSession> session;
60
+ std::mutex mutex;
61
+ public:
62
+ explicit InspectorSession(IsolateEnvironment& isolate);
63
+ ~InspectorSession() override;
64
+ InspectorSession(const InspectorSession&) = delete;
65
+ auto operator= (const InspectorSession&) -> InspectorSession& = delete;
66
+ void Disconnect();
67
+ void DispatchBackendProtocolMessage(std::vector<uint16_t> message);
68
+ };
69
+
70
+ } // namespace ivm
@@ -0,0 +1,15 @@
1
+ // node.h has some deprecated v8 calls which blow up with warnings
2
+ #pragma once
3
+ #ifdef __clang__
4
+ #pragma clang system_header
5
+ #include <node.h>
6
+ #elif __GNUC__
7
+ #pragma GCC system_header
8
+ #include <node.h>
9
+ #elif _MSC_VER
10
+ #pragma warning(push, 0)
11
+ #include <node.h>
12
+ #pragma warning(pop)
13
+ #else
14
+ #include <node.h>
15
+ #endif
@@ -0,0 +1,22 @@
1
+ #include "platform_delegate.h"
2
+
3
+ namespace ivm {
4
+ namespace {
5
+ PlatformDelegate delegate;
6
+ }
7
+
8
+ void PlatformDelegate::InitializeDelegate() {
9
+ auto context = v8::Isolate::GetCurrent()->GetCurrentContext();
10
+ auto* node_platform = node::GetMultiIsolatePlatform(node::GetCurrentEnvironment(context));
11
+ delegate = PlatformDelegate{node_platform};
12
+ }
13
+
14
+ void PlatformDelegate::RegisterIsolate(v8::Isolate* isolate, node::IsolatePlatformDelegate* isolate_delegate) {
15
+ delegate.node_platform->RegisterIsolate(isolate, isolate_delegate);
16
+ }
17
+
18
+ void PlatformDelegate::UnregisterIsolate(v8::Isolate* isolate) {
19
+ delegate.node_platform->UnregisterIsolate(isolate);
20
+ }
21
+
22
+ } // namespace ivm
@@ -0,0 +1,46 @@
1
+ #pragma once
2
+ #include "lib/lockable.h"
3
+ #include "node_wrapper.h"
4
+ #include "v8_version.h"
5
+ #include <v8-platform.h>
6
+ #include <mutex>
7
+ #include <unordered_map>
8
+
9
+ namespace ivm {
10
+
11
+ // Normalize this interface from v8
12
+ class TaskRunner : public v8::TaskRunner {
13
+ public:
14
+ // Methods for v8::TaskRunner
15
+ void PostTask(std::unique_ptr<v8::Task> task) override = 0;
16
+ void PostDelayedTask(std::unique_ptr<v8::Task> task, double delay_in_seconds) override = 0;
17
+ void PostIdleTask(std::unique_ptr<v8::IdleTask> /*task*/) final { std::terminate(); }
18
+ // Can't be final because symbol is also used in IsolatePlatformDelegate
19
+ auto IdleTasksEnabled() -> bool override { return false; };
20
+ auto NonNestableTasksEnabled() const -> bool final { return true; }
21
+ void PostNonNestableDelayedTask(std::unique_ptr<v8::Task> /*task*/, double /*delay_in_seconds*/) final { std::terminate(); }
22
+ auto NonNestableDelayedTasksEnabled() const -> bool final { return false; }
23
+ };
24
+
25
+ class PlatformDelegate {
26
+ public:
27
+ PlatformDelegate() = default;
28
+ explicit PlatformDelegate(node::MultiIsolatePlatform* node_platform) : node_platform{node_platform} {}
29
+ PlatformDelegate(const PlatformDelegate&) = delete;
30
+ PlatformDelegate(PlatformDelegate&&) = delete;
31
+ ~PlatformDelegate() = default; // NOLINT(modernize-use-override) -- this only sometimes inherits from v8::Platform
32
+
33
+ auto operator=(const PlatformDelegate&) = delete;
34
+ auto operator=(PlatformDelegate&& delegate) noexcept -> PlatformDelegate& {
35
+ node_platform = std::exchange(delegate.node_platform, nullptr);
36
+ return *this;
37
+ }
38
+
39
+ static void InitializeDelegate();
40
+ static void RegisterIsolate(v8::Isolate* isolate, node::IsolatePlatformDelegate* isolate_delegate);
41
+ static void UnregisterIsolate(v8::Isolate* isolate);
42
+
43
+ node::MultiIsolatePlatform* node_platform = nullptr;
44
+ };
45
+
46
+ } // namespace ivm
@@ -0,0 +1,164 @@
1
+ #pragma once
2
+ #include "holder.h"
3
+ #include <v8.h>
4
+ #include <memory>
5
+ #include <tuple>
6
+ #include <utility>
7
+
8
+ namespace ivm {
9
+ void AdjustRemotes(int delta);
10
+
11
+ namespace detail {
12
+
13
+ /**
14
+ * This is basically a tuple that can be constructed in place in a way that v8::Persistent<> will
15
+ * accept.
16
+ */
17
+ template <size_t Index, class Type>
18
+ struct HandleTupleElement {
19
+ HandleTupleElement(v8::Isolate* isolate, v8::Local<Type> local) : persistent{isolate, local} {}
20
+ v8::Persistent<Type, v8::NonCopyablePersistentTraits<Type>> persistent;
21
+ };
22
+
23
+ template <class Indices, class ...Types>
24
+ struct HandleTupleImpl;
25
+
26
+ template <size_t ...Indices, class ...Types_>
27
+ struct HandleTupleImpl<std::index_sequence<Indices...>, Types_...> : HandleTupleElement<Indices, Types_>... {
28
+ template <class ...Args>
29
+ explicit HandleTupleImpl(v8::Isolate* isolate, v8::Local<Types_>... locals) :
30
+ HandleTupleElement<Indices, Types_>{isolate, locals}... {
31
+ }
32
+
33
+ template <size_t Index>
34
+ auto get() -> auto& {
35
+ return HandleTupleElement<Index, std::tuple_element_t<Index, std::tuple<Types_...>>>::persistent;
36
+ }
37
+
38
+ static constexpr auto Size = sizeof...(Types_);
39
+ using Types = std::tuple<Types_...>;
40
+ };
41
+
42
+ template <class... Types>
43
+ using HandleTuple = HandleTupleImpl<std::make_index_sequence<sizeof...(Types)>, Types...>;
44
+
45
+ } // namespace detail
46
+
47
+ /**
48
+ * This holds a number of persistent handles to some values in a single isolate. It also holds a
49
+ * handle to the isolate. When the destructor of this class is called it will run `Reset()` on each
50
+ * handle in the context of the isolate. If the destructor of this class is called after the isolate
51
+ * has been disposed then Reset() will not be called (but I don't think that causes a memory leak).
52
+ */
53
+
54
+ template <class ...Types>
55
+ class RemoteTuple {
56
+ public:
57
+ RemoteTuple() = default;
58
+
59
+ template <class Disposer>
60
+ explicit RemoteTuple(v8::Local<Types>... handles, Disposer disposer) :
61
+ isolate{IsolateHolder::GetCurrent()},
62
+ handles{
63
+ new TupleType{v8::Isolate::GetCurrent(), handles...},
64
+ RemoteHandleFree<Disposer>{IsolateHolder::GetCurrent(), std::move(disposer)}
65
+ } {
66
+ AdjustRemotes(sizeof...(Types));
67
+ static_assert(!v8::NonCopyablePersistentTraits<v8::Value>::kResetInDestructor, "Do not reset in destructor");
68
+ }
69
+
70
+ explicit RemoteTuple(v8::Local<Types>... handles) : RemoteTuple{handles..., DefaultDisposer{}} {}
71
+
72
+ operator bool() const { // NOLINT(hicpp-explicit-conversions)
73
+ return static_cast<bool>(handles);
74
+ }
75
+
76
+ auto GetIsolateHolder() -> IsolateHolder* {
77
+ return isolate.get();
78
+ }
79
+
80
+ auto GetSharedIsolateHolder() -> std::shared_ptr<IsolateHolder> {
81
+ return isolate;
82
+ }
83
+
84
+ template <size_t N>
85
+ auto Deref() const {
86
+ using Type = std::tuple_element_t<N, std::tuple<Types...>>;
87
+ return v8::Local<Type>::New(v8::Isolate::GetCurrent(), handles->template get<N>());
88
+ }
89
+
90
+ private:
91
+ using TupleType = detail::HandleTuple<Types...>;
92
+
93
+ struct DefaultDisposer {
94
+ template <class Type, class ...Rest>
95
+ void operator()(v8::Persistent<Type>& value, Rest&&... rest) const {
96
+ value.Reset();
97
+ (*this)(std::forward<Rest>(rest)...);
98
+ }
99
+
100
+ void operator()() const {}
101
+ };
102
+
103
+ template <class Disposer>
104
+ class RemoteHandleFree {
105
+ public:
106
+ RemoteHandleFree(std::shared_ptr<IsolateHolder> isolate, Disposer disposer) :
107
+ isolate{std::move(isolate)}, disposer{std::move(disposer)} {}
108
+
109
+ void operator()(TupleType* handles) {
110
+ isolate->ScheduleTask(std::make_unique<DisposalTask<Disposer>>(handles, std::move(disposer)), true, false, true);
111
+ }
112
+
113
+ private:
114
+ std::shared_ptr<IsolateHolder> isolate;
115
+ Disposer disposer;
116
+ };
117
+
118
+ template <class Disposer>
119
+ class DisposalTask : public Runnable {
120
+ public:
121
+ explicit DisposalTask(TupleType* handles, Disposer disposer) :
122
+ handles{handles}, disposer{std::move(disposer)} {}
123
+
124
+ private:
125
+ template <size_t ...Indices>
126
+ void Apply(std::index_sequence<Indices...> /*unused*/) {
127
+ disposer(handles->template get<Indices>()...);
128
+ }
129
+
130
+ void Run() final {
131
+ Apply(std::make_index_sequence<TupleType::Size>{});
132
+ AdjustRemotes(-static_cast<int>(TupleType::Size));
133
+ }
134
+
135
+ std::unique_ptr<TupleType> handles;
136
+ Disposer disposer;
137
+ };
138
+
139
+ std::shared_ptr<IsolateHolder> isolate;
140
+ std::shared_ptr<TupleType> handles;
141
+ };
142
+
143
+ /**
144
+ * Convenient when you only need 1 handle
145
+ */
146
+ template <class Type>
147
+ class RemoteHandle {
148
+ public:
149
+ RemoteHandle() = default;
150
+ explicit RemoteHandle(v8::Local<Type> handle) : handle{handle} {}
151
+
152
+ template <class Disposer>
153
+ RemoteHandle(v8::Local<Type> handle, Disposer disposer) : handle{handle, std::move(disposer)} {}
154
+
155
+ operator bool() const { return bool{handle}; } // NOLINT(hicpp-explicit-conversions)
156
+ auto Deref() const { return handle.template Deref<0>(); }
157
+ auto GetIsolateHolder() { return handle.GetIsolateHolder(); }
158
+ auto GetSharedIsolateHolder() { return handle.GetSharedIsolateHolder(); }
159
+
160
+ private:
161
+ RemoteTuple<Type> handle;
162
+ };
163
+
164
+ } // namespace ivm
@@ -0,0 +1,171 @@
1
+ #pragma once
2
+ #include "environment.h"
3
+ #include "inspector.h"
4
+ #include "runnable.h"
5
+ #include "stack_trace.h"
6
+ #include "lib/suspend.h"
7
+ #include "lib/timer.h"
8
+ #include <chrono>
9
+ #include <memory>
10
+ #include <thread>
11
+
12
+ namespace ivm {
13
+
14
+ /**
15
+ * Grabs a stack trace of the runaway script
16
+ */
17
+ class TimeoutRunner final : public Runnable {
18
+ public:
19
+ struct State {
20
+ std::condition_variable cv;
21
+ std::mutex mutex;
22
+ std::string stack_trace;
23
+ bool did_finish = false;
24
+ bool did_release = false;
25
+ bool did_terminate = false;
26
+ bool did_timeout = false;
27
+ };
28
+
29
+ explicit TimeoutRunner(State& state) : state{state} {}
30
+ TimeoutRunner(const TimeoutRunner&) = delete;
31
+ auto operator=(const TimeoutRunner&) -> TimeoutRunner& = delete;
32
+
33
+ ~TimeoutRunner() final {
34
+ std::lock_guard<std::mutex> lock{state.mutex};
35
+ state.did_release = true;
36
+ state.cv.notify_all();
37
+ }
38
+
39
+ void Run() final {
40
+ bool will_terminate = [&]() {
41
+ std::lock_guard<std::mutex> lock{state.mutex};
42
+ if (state.did_finish) {
43
+ return false;
44
+ } else {
45
+ state.did_terminate = true;
46
+ return true;
47
+ }
48
+ }();
49
+ if (will_terminate) {
50
+ auto& env = IsolateEnvironment::GetCurrent();
51
+ auto* isolate = env.GetIsolate();
52
+ state.stack_trace = StackTraceHolder::RenderSingleStack(v8::StackTrace::CurrentStackTrace(isolate, 10));
53
+ isolate->TerminateExecution();
54
+ ++env.terminate_depth;
55
+ }
56
+ }
57
+
58
+ private:
59
+ State& state;
60
+ };
61
+
62
+ /**
63
+ * Run some v8 thing with a timeout. Also throws error if memory limit is hit.
64
+ */
65
+ template <typename F>
66
+ auto RunWithTimeout(uint32_t timeout_ms, F&& fn) -> v8::Local<v8::Value> {
67
+ IsolateEnvironment& isolate = IsolateEnvironment::GetCurrent();
68
+ thread_suspend_handle thread_suspend{};
69
+ bool is_default_thread = Executor::IsDefaultThread();
70
+ bool did_terminate = false;
71
+ TimeoutRunner::State state;
72
+ v8::MaybeLocal<v8::Value> result;
73
+ {
74
+ std::unique_ptr<timer_t> timer_ptr;
75
+ if (timeout_ms != 0) {
76
+ timer_ptr = std::make_unique<timer_t>(timeout_ms, &isolate.timer_holder, [&](void* next) {
77
+ auto deadline = std::chrono::steady_clock::now() + std::chrono::seconds{5};
78
+
79
+ {
80
+ std::lock_guard<std::mutex> lock{state.mutex};
81
+ if (state.did_finish) {
82
+ // Timer triggered as the function was finishing, bail early
83
+ timer_t::chain(next);
84
+ return;
85
+ }
86
+ // Set up interrupt
87
+ state.did_timeout = true;
88
+ auto timeout_runner = std::make_unique<TimeoutRunner>(state);
89
+ if (is_default_thread) {
90
+ // In this case this is a pure sync function. We should not cancel any async waits.
91
+ auto lock = isolate.scheduler->Lock();
92
+ lock->sync_interrupts.push(std::move(timeout_runner));
93
+ lock->InterruptSyncIsolate();
94
+ } else {
95
+ {
96
+ auto lock = isolate.scheduler->Lock();
97
+ lock->CancelAsync();
98
+ lock->interrupts.push(std::move(timeout_runner));
99
+ lock->InterruptIsolate();
100
+ }
101
+ }
102
+ }
103
+ timer_t::chain(next);
104
+
105
+ // Wait for TimeoutRunner release (either it ran, or was cancelled)
106
+ {
107
+ std::unique_lock<std::mutex> lock{state.mutex};
108
+ if (isolate.error_handler) {
109
+ if (!state.cv.wait_until(lock, deadline, [&] { return state.did_release || state.did_finish; })) {
110
+ assert(RaiseCatastrophicError(isolate.error_handler, "Script failed to terminate"));
111
+ thread_suspend.suspend();
112
+ return;
113
+ }
114
+ } else {
115
+ state.cv.wait(lock, [&] { return state.did_release || state.did_finish; });
116
+ }
117
+ if (state.did_finish) {
118
+ return;
119
+ }
120
+ }
121
+
122
+ // Wait for `fn()` to return
123
+ while (true) {
124
+ std::lock_guard<std::mutex> lock{state.mutex};
125
+ if (state.did_finish) {
126
+ return;
127
+ } else if (isolate.error_handler && deadline < std::chrono::steady_clock::now()) {
128
+ assert(RaiseCatastrophicError(isolate.error_handler, "Script failed to terminate"));
129
+ thread_suspend.suspend();
130
+ return;
131
+ }
132
+ // Aggressively terminate the isolate because sometimes v8 just doesn't get the hint
133
+ isolate->TerminateExecution();
134
+ }
135
+ });
136
+ }
137
+
138
+ if (!isolate.terminated) {
139
+ result = fn();
140
+ }
141
+ bool will_flush_tasks = false;
142
+ {
143
+ std::lock_guard<std::mutex> lock{state.mutex};
144
+ did_terminate = state.did_terminate;
145
+ will_flush_tasks = state.did_timeout && !state.did_release;
146
+ state.did_finish = true;
147
+ }
148
+ if (will_flush_tasks) {
149
+ // TimeoutRunner was added to interupts after v8 yielded control. In this case we flush
150
+ // interrupt tasks manually
151
+ if (is_default_thread) {
152
+ isolate.InterruptEntrySync();
153
+ } else {
154
+ isolate.InterruptEntryAsync();
155
+ }
156
+ }
157
+ }
158
+ if (isolate.DidHitMemoryLimit()) {
159
+ throw FatalRuntimeError("Isolate was disposed during execution due to memory limit");
160
+ } else if (isolate.terminated) {
161
+ throw FatalRuntimeError("Isolate was disposed during execution");
162
+ } else if (did_terminate) {
163
+ if (--isolate.terminate_depth == 0) {
164
+ isolate->CancelTerminateExecution();
165
+ }
166
+ throw RuntimeGenericError("Script execution timed out.", std::move(state.stack_trace));
167
+ }
168
+ return Unmaybe(result);
169
+ }
170
+
171
+ } // namespace ivm
@@ -0,0 +1,29 @@
1
+ #pragma once
2
+ #include <v8-platform.h>
3
+
4
+ namespace ivm {
5
+ // ivm::Runnable serves the same role as v8::Task but instances of Runnable live and die without v8
6
+ // so it might not actually make sense to use a v8 container for the job. An alias is used to avoid
7
+ // the adapter which would be needed in the case where a Runnable actually does need to be passed
8
+ // off to v8.
9
+ using Runnable = v8::Task;
10
+ /*
11
+ class Runnable {
12
+ public:
13
+ virtual ~Runnable() = default;
14
+ virtual void Run() = 0;
15
+ };
16
+
17
+ class TaskHolder : public Runnable {
18
+ private:
19
+ std::unique_ptr<v8::Task> task;
20
+ public:
21
+ explicit TaskHolder(v8::Task* task) : task{task} {}
22
+ explicit TaskHolder(std::unique_ptr<v8::Task> task) : task{std::move(task)} {}
23
+ TaskHolder(TaskHolder task) noexcept : task{std::move(task.task)} {}
24
+ void Run() final {
25
+ task->Run();
26
+ }
27
+ };
28
+ */
29
+ } // namespace ivm