@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.
- 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,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) : ¤t_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
|