@nocobase/plugin-workflow-javascript 2.1.0-beta.11 → 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,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
|