@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.
- package/dist/externalVersion.js +4 -4
- package/dist/node_modules/isolated-vm/.clang-tidy +13 -0
- package/dist/node_modules/isolated-vm/.dockerignore +9 -0
- package/dist/node_modules/isolated-vm/Dockerfile.alpine +9 -0
- package/dist/node_modules/isolated-vm/Dockerfile.debian +12 -0
- package/dist/node_modules/isolated-vm/LICENSE +13 -0
- package/dist/node_modules/isolated-vm/binding.gyp +120 -0
- package/dist/node_modules/isolated-vm/include.js +3 -0
- package/dist/node_modules/isolated-vm/inspector-example.js +59 -0
- package/dist/node_modules/isolated-vm/isolated-vm.d.ts +820 -0
- package/dist/node_modules/isolated-vm/isolated-vm.js +1 -0
- package/dist/node_modules/isolated-vm/native-example/binding.gyp +23 -0
- package/dist/node_modules/isolated-vm/native-example/example.cc +61 -0
- package/dist/node_modules/isolated-vm/native-example/package.json +13 -0
- package/dist/node_modules/isolated-vm/native-example/usage.js +35 -0
- package/dist/node_modules/isolated-vm/out/isolated_vm.node +0 -0
- package/dist/node_modules/isolated-vm/package.json +1 -0
- package/dist/node_modules/isolated-vm/src/external_copy/error.h +33 -0
- package/dist/node_modules/isolated-vm/src/external_copy/external_copy.cc +509 -0
- package/dist/node_modules/isolated-vm/src/external_copy/external_copy.h +117 -0
- package/dist/node_modules/isolated-vm/src/external_copy/serializer.cc +85 -0
- package/dist/node_modules/isolated-vm/src/external_copy/serializer.h +136 -0
- package/dist/node_modules/isolated-vm/src/external_copy/serializer_nortti.cc +73 -0
- package/dist/node_modules/isolated-vm/src/external_copy/string.cc +124 -0
- package/dist/node_modules/isolated-vm/src/external_copy/string.h +28 -0
- package/dist/node_modules/isolated-vm/src/isolate/allocator.h +32 -0
- package/dist/node_modules/isolated-vm/src/isolate/allocator_nortti.cc +142 -0
- package/dist/node_modules/isolated-vm/src/isolate/class_handle.h +334 -0
- package/dist/node_modules/isolated-vm/src/isolate/cpu_profile_manager.cc +220 -0
- package/dist/node_modules/isolated-vm/src/isolate/cpu_profile_manager.h +100 -0
- package/dist/node_modules/isolated-vm/src/isolate/environment.cc +626 -0
- package/dist/node_modules/isolated-vm/src/isolate/environment.h +381 -0
- package/dist/node_modules/isolated-vm/src/isolate/executor.cc +198 -0
- package/dist/node_modules/isolated-vm/src/isolate/executor.h +183 -0
- package/dist/node_modules/isolated-vm/src/isolate/external.h +64 -0
- package/dist/node_modules/isolated-vm/src/isolate/functor_runners.h +97 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/array.h +145 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/callbacks.h +272 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/error.h +140 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/extract_params.h +145 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/handle_cast.h +257 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/read_option.h +47 -0
- package/dist/node_modules/isolated-vm/src/isolate/holder.cc +88 -0
- package/dist/node_modules/isolated-vm/src/isolate/holder.h +63 -0
- package/dist/node_modules/isolated-vm/src/isolate/inspector.cc +200 -0
- package/dist/node_modules/isolated-vm/src/isolate/inspector.h +70 -0
- package/dist/node_modules/isolated-vm/src/isolate/node_wrapper.h +15 -0
- package/dist/node_modules/isolated-vm/src/isolate/platform_delegate.cc +22 -0
- package/dist/node_modules/isolated-vm/src/isolate/platform_delegate.h +46 -0
- package/dist/node_modules/isolated-vm/src/isolate/remote_handle.h +164 -0
- package/dist/node_modules/isolated-vm/src/isolate/run_with_timeout.h +171 -0
- package/dist/node_modules/isolated-vm/src/isolate/runnable.h +29 -0
- package/dist/node_modules/isolated-vm/src/isolate/scheduler.cc +191 -0
- package/dist/node_modules/isolated-vm/src/isolate/scheduler.h +165 -0
- package/dist/node_modules/isolated-vm/src/isolate/specific.h +35 -0
- package/dist/node_modules/isolated-vm/src/isolate/stack_trace.cc +219 -0
- package/dist/node_modules/isolated-vm/src/isolate/stack_trace.h +24 -0
- package/dist/node_modules/isolated-vm/src/isolate/strings.h +127 -0
- package/dist/node_modules/isolated-vm/src/isolate/three_phase_task.cc +385 -0
- package/dist/node_modules/isolated-vm/src/isolate/three_phase_task.h +136 -0
- package/dist/node_modules/isolated-vm/src/isolate/transferable.h +15 -0
- package/dist/node_modules/isolated-vm/src/isolate/util.h +45 -0
- package/dist/node_modules/isolated-vm/src/isolate/v8_inspector_wrapper.h +12 -0
- package/dist/node_modules/isolated-vm/src/isolate/v8_version.h +12 -0
- package/dist/node_modules/isolated-vm/src/isolated_vm.h +71 -0
- package/dist/node_modules/isolated-vm/src/lib/covariant.h +50 -0
- package/dist/node_modules/isolated-vm/src/lib/lockable.h +178 -0
- package/dist/node_modules/isolated-vm/src/lib/suspend.h +106 -0
- package/dist/node_modules/isolated-vm/src/lib/thread_pool.cc +98 -0
- package/dist/node_modules/isolated-vm/src/lib/thread_pool.h +45 -0
- package/dist/node_modules/isolated-vm/src/lib/timer.cc +233 -0
- package/dist/node_modules/isolated-vm/src/lib/timer.h +36 -0
- package/dist/node_modules/isolated-vm/src/module/callback.cc +151 -0
- package/dist/node_modules/isolated-vm/src/module/callback.h +64 -0
- package/dist/node_modules/isolated-vm/src/module/context_handle.cc +241 -0
- package/dist/node_modules/isolated-vm/src/module/context_handle.h +35 -0
- package/dist/node_modules/isolated-vm/src/module/evaluation.cc +109 -0
- package/dist/node_modules/isolated-vm/src/module/evaluation.h +99 -0
- package/dist/node_modules/isolated-vm/src/module/external_copy_handle.cc +119 -0
- package/dist/node_modules/isolated-vm/src/module/external_copy_handle.h +64 -0
- package/dist/node_modules/isolated-vm/src/module/isolate.cc +136 -0
- package/dist/node_modules/isolated-vm/src/module/isolate_handle.cc +611 -0
- package/dist/node_modules/isolated-vm/src/module/isolate_handle.h +47 -0
- package/dist/node_modules/isolated-vm/src/module/lib_handle.cc +77 -0
- package/dist/node_modules/isolated-vm/src/module/lib_handle.h +28 -0
- package/dist/node_modules/isolated-vm/src/module/module_handle.cc +475 -0
- package/dist/node_modules/isolated-vm/src/module/module_handle.h +68 -0
- package/dist/node_modules/isolated-vm/src/module/native_module_handle.cc +104 -0
- package/dist/node_modules/isolated-vm/src/module/native_module_handle.h +49 -0
- package/dist/node_modules/isolated-vm/src/module/reference_handle.cc +636 -0
- package/dist/node_modules/isolated-vm/src/module/reference_handle.h +106 -0
- package/dist/node_modules/isolated-vm/src/module/script_handle.cc +107 -0
- package/dist/node_modules/isolated-vm/src/module/script_handle.h +37 -0
- package/dist/node_modules/isolated-vm/src/module/session_handle.cc +173 -0
- package/dist/node_modules/isolated-vm/src/module/session_handle.h +31 -0
- package/dist/node_modules/isolated-vm/src/module/transferable.cc +268 -0
- package/dist/node_modules/isolated-vm/src/module/transferable.h +42 -0
- package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v18.0.0.h +360 -0
- package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v18.3.0.h +376 -0
- package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v20.0.0.h +397 -0
- package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v22.0.0.h +419 -0
- package/dist/node_modules/winston-transport/package.json +1 -1
- package/dist/server/IsolatedVm.js +75 -0
- package/dist/server/ScriptInstruction.d.ts +6 -0
- package/dist/server/ScriptInstruction.js +11 -1
- package/dist/server/Vm.js +42 -27
- package/package.json +3 -2
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
#include "timer.h"
|
|
2
|
+
#include <cassert>
|
|
3
|
+
#include <chrono>
|
|
4
|
+
#include <condition_variable>
|
|
5
|
+
#include <mutex>
|
|
6
|
+
#include <queue>
|
|
7
|
+
#include <thread>
|
|
8
|
+
#include <utility>
|
|
9
|
+
#include <unordered_set>
|
|
10
|
+
|
|
11
|
+
namespace ivm {
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Contains data on a timer. This is shared between the timer_t handle and the thread responsible
|
|
15
|
+
* for the timer.
|
|
16
|
+
*/
|
|
17
|
+
struct timer_data_t {
|
|
18
|
+
timer_data_t(
|
|
19
|
+
std::chrono::steady_clock::time_point timeout,
|
|
20
|
+
void** holder,
|
|
21
|
+
timer_t::callback_t callback,
|
|
22
|
+
const std::lock_guard<std::mutex>& /*lock*/
|
|
23
|
+
) : callback{std::move(callback)}, holder{holder}, timeout{timeout} {
|
|
24
|
+
if (holder != nullptr) {
|
|
25
|
+
last_holder_value = std::exchange(*holder, static_cast<void*>(this));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
auto adjust() -> bool {
|
|
30
|
+
if (paused_duration == std::chrono::steady_clock::duration{}) {
|
|
31
|
+
return false;
|
|
32
|
+
} else {
|
|
33
|
+
timeout += paused_duration;
|
|
34
|
+
paused_duration = {};
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
auto is_paused() const -> bool {
|
|
40
|
+
return paused_at != std::chrono::steady_clock::time_point{};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
void pause() {
|
|
44
|
+
paused_at = std::chrono::steady_clock::now();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
void resume() {
|
|
48
|
+
paused_duration += std::chrono::steady_clock::now() - paused_at;
|
|
49
|
+
paused_at = {};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
struct cmp {
|
|
53
|
+
auto operator()(const std::shared_ptr<timer_data_t>& left, const std::shared_ptr<timer_data_t>& right) const {
|
|
54
|
+
return left->timeout > right->timeout;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
timer_t::callback_t callback;
|
|
59
|
+
void** holder = nullptr;
|
|
60
|
+
void* last_holder_value;
|
|
61
|
+
std::chrono::steady_clock::time_point timeout;
|
|
62
|
+
std::chrono::steady_clock::time_point paused_at{};
|
|
63
|
+
std::chrono::steady_clock::duration paused_duration{};
|
|
64
|
+
std::shared_ptr<timer_data_t> threadless_self;
|
|
65
|
+
bool is_alive = true;
|
|
66
|
+
bool is_running = false;
|
|
67
|
+
bool is_dtor_waiting = false;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
namespace {
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Stash these here in case statics are destroyed while the module is unloading but timers are still
|
|
74
|
+
* active
|
|
75
|
+
*/
|
|
76
|
+
struct shared_state_t {
|
|
77
|
+
std::unordered_set<struct timer_thread_t*> threads;
|
|
78
|
+
std::condition_variable cv;
|
|
79
|
+
std::mutex mutex;
|
|
80
|
+
};
|
|
81
|
+
auto global_shared_state = std::make_shared<shared_state_t>();
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Manager for a thread which handles 1 or many timers.
|
|
85
|
+
*/
|
|
86
|
+
struct timer_thread_t {
|
|
87
|
+
explicit timer_thread_t(std::shared_ptr<timer_data_t> first_timer) :
|
|
88
|
+
next_timeout{first_timer->timeout}, shared_state{global_shared_state} {
|
|
89
|
+
queue.emplace(std::move(first_timer));
|
|
90
|
+
std::thread thread{[this] { entry(); }};
|
|
91
|
+
thread.detach();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
void entry() {
|
|
95
|
+
std::unique_lock<std::mutex> lock{shared_state->mutex, std::defer_lock};
|
|
96
|
+
while (true) {
|
|
97
|
+
std::this_thread::sleep_until(next_timeout);
|
|
98
|
+
lock.lock();
|
|
99
|
+
next_timeout = std::chrono::steady_clock::now();
|
|
100
|
+
run_next(lock);
|
|
101
|
+
if (queue.empty()) {
|
|
102
|
+
auto ii = shared_state->threads.find(this);
|
|
103
|
+
assert(ii != shared_state->threads.end());
|
|
104
|
+
shared_state->threads.erase(ii);
|
|
105
|
+
lock.unlock();
|
|
106
|
+
delete this;
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
next_timeout = queue.top()->timeout;
|
|
110
|
+
lock.unlock();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
void maybe_run_next(std::unique_lock<std::mutex>& lock) {
|
|
115
|
+
if (!queue.empty() && queue.top()->timeout <= next_timeout) {
|
|
116
|
+
run_next(lock);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
void run_next(std::unique_lock<std::mutex>& lock) {
|
|
121
|
+
auto data = queue.top();
|
|
122
|
+
queue.pop();
|
|
123
|
+
{
|
|
124
|
+
if (data->is_alive) {
|
|
125
|
+
if (data->is_paused()) {
|
|
126
|
+
data->threadless_self = std::move(data);
|
|
127
|
+
} else if (data->adjust()) {
|
|
128
|
+
start_or_join_timer(std::move(data), lock);
|
|
129
|
+
} else {
|
|
130
|
+
data->is_running = true;
|
|
131
|
+
lock.unlock();
|
|
132
|
+
data->callback(reinterpret_cast<void*>(this));
|
|
133
|
+
lock.lock();
|
|
134
|
+
data->is_running = false;
|
|
135
|
+
if (data->is_dtor_waiting) {
|
|
136
|
+
shared_state->cv.notify_all();
|
|
137
|
+
}
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
data.reset();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
maybe_run_next(lock);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Requires lock
|
|
148
|
+
template <template<class> class Lock>
|
|
149
|
+
static void start_or_join_timer(std::shared_ptr<timer_data_t> data, const Lock<std::mutex>& /*lock*/) {
|
|
150
|
+
// Try to find a thread to put this timer into
|
|
151
|
+
for (const auto& thread : global_shared_state->threads) {
|
|
152
|
+
if (thread->next_timeout < data->timeout) {
|
|
153
|
+
thread->queue.push(std::move(data));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Time to spawn a new thread
|
|
159
|
+
global_shared_state->threads.insert(new timer_thread_t(std::move(data)));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
std::priority_queue<
|
|
163
|
+
std::shared_ptr<timer_data_t>,
|
|
164
|
+
std::deque<std::shared_ptr<timer_data_t>>,
|
|
165
|
+
timer_data_t::cmp
|
|
166
|
+
> queue;
|
|
167
|
+
std::chrono::steady_clock::time_point next_timeout;
|
|
168
|
+
std::shared_ptr<shared_state_t> shared_state;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
} // anonymous namespace
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* timer_t implementation
|
|
175
|
+
*/
|
|
176
|
+
timer_t::timer_t(uint32_t ms, void** holder, const callback_t& callback) {
|
|
177
|
+
std::lock_guard<std::mutex> lock{global_shared_state->mutex};
|
|
178
|
+
data = std::make_shared<timer_data_t>(
|
|
179
|
+
std::chrono::steady_clock::now() + std::chrono::milliseconds{ms},
|
|
180
|
+
holder, callback,
|
|
181
|
+
lock
|
|
182
|
+
);
|
|
183
|
+
timer_thread_t::start_or_join_timer(data, lock);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
timer_t::~timer_t() {
|
|
187
|
+
std::unique_lock<std::mutex> lock{global_shared_state->mutex};
|
|
188
|
+
if (data->is_running) {
|
|
189
|
+
data->is_dtor_waiting = true;
|
|
190
|
+
do {
|
|
191
|
+
global_shared_state->cv.wait(lock);
|
|
192
|
+
} while (data->is_running);
|
|
193
|
+
}
|
|
194
|
+
data->is_alive = false;
|
|
195
|
+
if (data->holder != nullptr) {
|
|
196
|
+
*data->holder = data->last_holder_value;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
void timer_t::chain(void* ptr) {
|
|
201
|
+
auto& thread = *reinterpret_cast<timer_thread_t*>(ptr);
|
|
202
|
+
std::unique_lock<std::mutex> lock{global_shared_state->mutex};
|
|
203
|
+
thread.maybe_run_next(lock);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
void timer_t::pause(void*& holder) {
|
|
207
|
+
std::unique_lock<std::mutex> lock{global_shared_state->mutex};
|
|
208
|
+
if (holder != nullptr) {
|
|
209
|
+
auto& data = *static_cast<timer_data_t*>(holder);
|
|
210
|
+
data.pause();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
void timer_t::resume(void*& holder) {
|
|
215
|
+
std::unique_lock<std::mutex> lock{global_shared_state->mutex};
|
|
216
|
+
if (holder != nullptr) {
|
|
217
|
+
auto& data = *static_cast<timer_data_t*>(holder);
|
|
218
|
+
data.resume();
|
|
219
|
+
if (data.threadless_self) {
|
|
220
|
+
timer_thread_t::start_or_join_timer(std::move(data.threadless_self), lock);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
void timer_t::wait_detached(uint32_t ms, const callback_t& callback) {
|
|
226
|
+
std::lock_guard<std::mutex> lock{global_shared_state->mutex};
|
|
227
|
+
timer_thread_t::start_or_join_timer(std::make_shared<timer_data_t>(
|
|
228
|
+
std::chrono::steady_clock::now() + std::chrono::milliseconds{ms},
|
|
229
|
+
nullptr, callback, lock
|
|
230
|
+
), lock);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
} // namespace ivm
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <memory>
|
|
3
|
+
#include <functional>
|
|
4
|
+
|
|
5
|
+
namespace ivm {
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* isolated-vm could start timers from different threads which libuv isn't really cut out for, so
|
|
9
|
+
* I'm rolling my own here. The goal of the library is to have atomic timers without spawning a new
|
|
10
|
+
* thread for each timer.
|
|
11
|
+
*/
|
|
12
|
+
struct timer_data_t;
|
|
13
|
+
class timer_t {
|
|
14
|
+
public:
|
|
15
|
+
using callback_t = std::function<void(void*)>;
|
|
16
|
+
|
|
17
|
+
// Runs a callback unless the `timer_t` destructor is called.
|
|
18
|
+
timer_t(uint32_t ms, void** holder, const callback_t& callback);
|
|
19
|
+
timer_t(uint32_t ms, const callback_t& callback) : timer_t{ms, nullptr, callback} {}
|
|
20
|
+
timer_t(const timer_t&) = delete;
|
|
21
|
+
~timer_t();
|
|
22
|
+
auto operator= (const timer_t&) = delete;
|
|
23
|
+
|
|
24
|
+
// Runs a callback in `ms` with no `timer_t` object.
|
|
25
|
+
static void wait_detached(uint32_t ms, const callback_t& callback);
|
|
26
|
+
// Invoked from callbacks when they are done scheduling and may need to wait
|
|
27
|
+
static void chain(void* ptr);
|
|
28
|
+
// Pause/unpause timer callbacks
|
|
29
|
+
static void pause(void*& holder);
|
|
30
|
+
static void resume(void*& holder);
|
|
31
|
+
|
|
32
|
+
private:
|
|
33
|
+
std::shared_ptr<timer_data_t> data;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
} // namespace ivm
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#include "callback.h"
|
|
2
|
+
|
|
3
|
+
#include <utility>
|
|
4
|
+
#include "external_copy/serializer.h"
|
|
5
|
+
#include "isolate/external.h"
|
|
6
|
+
#include "isolate/three_phase_task.h"
|
|
7
|
+
|
|
8
|
+
using namespace v8;
|
|
9
|
+
|
|
10
|
+
namespace ivm {
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* CallbackHandle implementation
|
|
14
|
+
*/
|
|
15
|
+
auto CallbackHandle::Definition() -> Local<FunctionTemplate> {
|
|
16
|
+
return Inherit<TransferableHandle>(MakeClass(
|
|
17
|
+
"Callback", ConstructorFunction<decltype(&New), &New>{}
|
|
18
|
+
));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
auto CallbackHandle::New(Local<Function> fn, MaybeLocal<Object> options) -> std::unique_ptr<CallbackHandle> {
|
|
22
|
+
auto context = Isolate::GetCurrent()->GetCurrentContext();
|
|
23
|
+
|
|
24
|
+
// Get function parameter count
|
|
25
|
+
auto maybe_length = Unmaybe(fn->Get(context, StringTable::Get().length))->Int32Value(context);
|
|
26
|
+
int length;
|
|
27
|
+
if (!maybe_length.To(&length)) {
|
|
28
|
+
length = 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Read options
|
|
32
|
+
auto apply = CallbackHandle::InvokeData::Apply::Sync;
|
|
33
|
+
if (ReadOption(options, StringTable::Get().async, false)) {
|
|
34
|
+
apply = CallbackHandle::InvokeData::Apply::Async;
|
|
35
|
+
} else if (ReadOption(options, StringTable::Get().ignored, false)) {
|
|
36
|
+
apply = CallbackHandle::InvokeData::Apply::Ignored;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Return handle instance
|
|
40
|
+
return std::make_unique<CallbackHandle>(CallbackHandle::Data{
|
|
41
|
+
HandleCast<std::string>(fn->GetDebugName()),
|
|
42
|
+
length,
|
|
43
|
+
RemoteHandle<Function>{fn},
|
|
44
|
+
RemoteHandle<Context>{context},
|
|
45
|
+
apply});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
auto CallbackHandle::TransferOut() -> std::unique_ptr<Transferable> {
|
|
49
|
+
return std::make_unique<CallbackTransferable>(data);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Runner for invocation of functions created by `Callback`
|
|
54
|
+
*/
|
|
55
|
+
class InvokeRunner : public ThreePhaseTask {
|
|
56
|
+
public:
|
|
57
|
+
InvokeRunner(CallbackHandle::Data data, const FunctionCallbackInfo<Value>& info) : data{std::move(data)} {
|
|
58
|
+
// Transfer arguments out
|
|
59
|
+
argv = std::make_unique<SerializedVector>(info);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
void Phase2() final {
|
|
63
|
+
// Setup context
|
|
64
|
+
auto* isolate = Isolate::GetCurrent();
|
|
65
|
+
auto& env = IsolateEnvironment::GetCurrent();
|
|
66
|
+
auto context = Deref(data.context);
|
|
67
|
+
Context::Scope context_scope{context};
|
|
68
|
+
auto fn = Deref(data.callback);
|
|
69
|
+
// Copy arguments into isolate
|
|
70
|
+
auto argv_inner = argv->CopyIntoAsVector();
|
|
71
|
+
// Run function and transfer out
|
|
72
|
+
auto maybe_value = fn->Call(context, Undefined(isolate), argv_inner.size(), argv_inner.empty() ? nullptr : &argv_inner[0]);
|
|
73
|
+
if (env.DidHitMemoryLimit()) {
|
|
74
|
+
throw FatalRuntimeError("Isolate was disposed during execution due to memory limit");
|
|
75
|
+
} else if (env.terminated) {
|
|
76
|
+
throw FatalRuntimeError("Isolate was disposed during execution");
|
|
77
|
+
}
|
|
78
|
+
auto value = Unmaybe(maybe_value);
|
|
79
|
+
if (data.apply != CallbackHandle::Data::Apply::Ignored) {
|
|
80
|
+
result = TransferOut(value, TransferOptions{TransferOptions::Type::Copy});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
auto Phase3() -> Local<Value> final {
|
|
85
|
+
if (result) {
|
|
86
|
+
return result->TransferIn();
|
|
87
|
+
} else {
|
|
88
|
+
return Undefined(Isolate::GetCurrent());
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private:
|
|
93
|
+
CallbackHandle::InvokeData data;
|
|
94
|
+
std::unique_ptr<SerializedVector> argv;
|
|
95
|
+
std::unique_ptr<Transferable> result;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* CallbackHandleTransferable implementation
|
|
100
|
+
*/
|
|
101
|
+
CallbackTransferable::CallbackTransferable(CallbackHandle::Data& data) : data{data} {}
|
|
102
|
+
|
|
103
|
+
CallbackTransferable::CallbackTransferable(Local<Function> data) :
|
|
104
|
+
CallbackTransferable{data, Isolate::GetCurrent()->GetCurrentContext()} {}
|
|
105
|
+
|
|
106
|
+
CallbackTransferable::CallbackTransferable(Local<Function> fn, Local<Context> context) : data{
|
|
107
|
+
[&]() {
|
|
108
|
+
const auto name = fn->GetDebugName();
|
|
109
|
+
if (name->IsString()) {
|
|
110
|
+
return std::optional{HandleCast<std::string>(name)};
|
|
111
|
+
} else {
|
|
112
|
+
return std::optional<std::string>{};
|
|
113
|
+
}
|
|
114
|
+
}(),
|
|
115
|
+
HandleCast<int>(Unmaybe(fn->Get(context, StringTable::Get().length))),
|
|
116
|
+
RemoteHandle<Function>{fn},
|
|
117
|
+
RemoteHandle<Context>{context},
|
|
118
|
+
CallbackHandle::InvokeData::Apply::Sync
|
|
119
|
+
} {}
|
|
120
|
+
|
|
121
|
+
auto CallbackTransferable::TransferIn() -> Local<Value> {
|
|
122
|
+
|
|
123
|
+
// Instantiate function in isolate
|
|
124
|
+
auto* isolate = Isolate::GetCurrent();
|
|
125
|
+
auto context = isolate->GetCurrentContext();
|
|
126
|
+
auto external = MakeExternal<CallbackHandle::Data>(data);
|
|
127
|
+
auto fn = Unmaybe(Function::New(context, Invoke, external, data.length, ConstructorBehavior::kThrow));
|
|
128
|
+
if (data.name) {
|
|
129
|
+
fn->SetName(HandleCast<Local<String>>(*data.name));
|
|
130
|
+
}
|
|
131
|
+
return fn;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
void CallbackTransferable::Invoke(const FunctionCallbackInfo<Value>& info) {
|
|
135
|
+
FunctorRunners::RunCallback(info, [&]() {
|
|
136
|
+
auto& data = *static_cast<CallbackHandle::Data*>(info.Data().As<External>()->Value());
|
|
137
|
+
auto& isolate = *data.context.GetIsolateHolder();
|
|
138
|
+
switch (data.apply) {
|
|
139
|
+
case CallbackHandle::Data::Apply::Sync:
|
|
140
|
+
return ThreePhaseTask::Run<0, InvokeRunner>(isolate, data, info);
|
|
141
|
+
case CallbackHandle::Data::Apply::Async:
|
|
142
|
+
return ThreePhaseTask::Run<1, InvokeRunner>(isolate, data, info);
|
|
143
|
+
case CallbackHandle::Data::Apply::Ignored:
|
|
144
|
+
return ThreePhaseTask::Run<2, InvokeRunner>(isolate, data, info);
|
|
145
|
+
default:
|
|
146
|
+
throw std::logic_error{"Unknown callback flag"};
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
} // namespace ivm
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include "transferable.h"
|
|
3
|
+
#include <optional>
|
|
4
|
+
#include <v8.h>
|
|
5
|
+
#include <tuple>
|
|
6
|
+
#include <utility>
|
|
7
|
+
|
|
8
|
+
namespace ivm {
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Holds a reference to a function in an arbitrary isolate
|
|
12
|
+
*/
|
|
13
|
+
class CallbackHandle : public TransferableHandle {
|
|
14
|
+
public:
|
|
15
|
+
template <class ...Args>
|
|
16
|
+
explicit CallbackHandle(Args&&... args) : data{std::forward<Args>(args)...} {}
|
|
17
|
+
|
|
18
|
+
static auto Definition() -> v8::Local<v8::FunctionTemplate>;
|
|
19
|
+
static auto New(v8::Local<v8::Function> fn, v8::MaybeLocal<v8::Object> maybe_options) ->
|
|
20
|
+
std::unique_ptr<CallbackHandle>;
|
|
21
|
+
auto TransferOut() -> std::unique_ptr<Transferable> final;
|
|
22
|
+
|
|
23
|
+
void Release();
|
|
24
|
+
|
|
25
|
+
struct InvokeData {
|
|
26
|
+
enum class Apply { Async, Ignored, Sync };
|
|
27
|
+
RemoteHandle<v8::Function> callback;
|
|
28
|
+
RemoteHandle<v8::Context> context;
|
|
29
|
+
Apply apply{};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
struct Data : public InvokeData {
|
|
33
|
+
Data() = default;
|
|
34
|
+
|
|
35
|
+
template <class ...Args>
|
|
36
|
+
Data(std::optional<std::string> name, int length, Args&&... args) :
|
|
37
|
+
InvokeData{std::forward<Args>(args)...},
|
|
38
|
+
name{std::move(name)}, length{length} {}
|
|
39
|
+
|
|
40
|
+
std::optional<std::string> name;
|
|
41
|
+
int length = 0;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
private:
|
|
45
|
+
Data data;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Internal transferable handle for callback
|
|
50
|
+
*/
|
|
51
|
+
class CallbackTransferable : public Transferable {
|
|
52
|
+
public:
|
|
53
|
+
explicit CallbackTransferable(CallbackHandle::Data& data);
|
|
54
|
+
explicit CallbackTransferable(v8::Local<v8::Function> data);
|
|
55
|
+
CallbackTransferable(v8::Local<v8::Function> fn, v8::Local<v8::Context> context);
|
|
56
|
+
|
|
57
|
+
auto TransferIn() -> v8::Local<v8::Value> final;
|
|
58
|
+
|
|
59
|
+
private:
|
|
60
|
+
static void Invoke(const v8::FunctionCallbackInfo<v8::Value>& info);
|
|
61
|
+
CallbackHandle::Data data;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
} // namespace ivm
|