@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,127 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include "isolate/generic/error.h"
|
|
3
|
+
#include "isolate/generic/handle_cast.h"
|
|
4
|
+
#include <v8.h>
|
|
5
|
+
|
|
6
|
+
namespace ivm {
|
|
7
|
+
|
|
8
|
+
class StringTable {
|
|
9
|
+
public:
|
|
10
|
+
class String {
|
|
11
|
+
public:
|
|
12
|
+
String(const char* value) : value{value} {} // NOLINT(hicpp-explicit-conversions)
|
|
13
|
+
String(const String&) = delete;
|
|
14
|
+
String(String&&) = delete;
|
|
15
|
+
~String() = default;
|
|
16
|
+
auto operator=(const String&) = delete;
|
|
17
|
+
auto operator=(String&&) = delete;
|
|
18
|
+
|
|
19
|
+
operator v8::Local<v8::Name>() { // NOLINT(hicpp-explicit-conversions)
|
|
20
|
+
return v8::Local<v8::String>{*this}.As<v8::Name>();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
operator v8::Local<v8::Value>() { // NOLINT(hicpp-explicit-conversions)
|
|
24
|
+
return v8::Local<v8::String>{*this}.As<v8::Value>();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
operator v8::Local<v8::String>() { // NOLINT(hicpp-explicit-conversions)
|
|
28
|
+
auto* isolate = v8::Isolate::GetCurrent();
|
|
29
|
+
if (handle.IsEmpty()) {
|
|
30
|
+
auto local = Unmaybe(v8::String::NewFromOneByte(
|
|
31
|
+
isolate, (const uint8_t*)value, v8::NewStringType::kInternalized));
|
|
32
|
+
handle.Set(isolate, local);
|
|
33
|
+
return local;
|
|
34
|
+
} else {
|
|
35
|
+
return handle.Get(isolate);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private:
|
|
40
|
+
const char* value;
|
|
41
|
+
v8::Eternal<v8::String> handle;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
static auto Get() -> auto&;
|
|
45
|
+
|
|
46
|
+
// StringTable::Get().
|
|
47
|
+
String accessors{"accessors"};
|
|
48
|
+
String arguments{"arguments"};
|
|
49
|
+
String async{"async"};
|
|
50
|
+
String boolean{"boolean"};
|
|
51
|
+
String cachedData{"cachedData"};
|
|
52
|
+
String cachedDataRejected{"cachedDataRejected"};
|
|
53
|
+
String code{"code"};
|
|
54
|
+
// String codeGenerationError{"Code generation from large string was denied"};
|
|
55
|
+
String colonSpace{": "};
|
|
56
|
+
String columnOffset{"columnOffset"};
|
|
57
|
+
String copy{"copy"};
|
|
58
|
+
String externalCopy{"externalCopy"};
|
|
59
|
+
String filename{"filename"};
|
|
60
|
+
String function{"function"};
|
|
61
|
+
String global{"global"};
|
|
62
|
+
String ignored{"ignored"};
|
|
63
|
+
String inspector{"inspector"};
|
|
64
|
+
String isolateIsDisposed{"Isolate is disposed"};
|
|
65
|
+
String isolatedVm{"isolated-vm"};
|
|
66
|
+
String length{"length"};
|
|
67
|
+
String lineOffset{"lineOffset"};
|
|
68
|
+
String message{"message"};
|
|
69
|
+
String meta{"meta"};
|
|
70
|
+
String name{"name"};
|
|
71
|
+
String null{"null"};
|
|
72
|
+
String number{"number"};
|
|
73
|
+
String object{"object"};
|
|
74
|
+
String onCatastrophicError{"onCatastrophicError"};
|
|
75
|
+
String produceCachedData{"produceCachedData"};
|
|
76
|
+
String promise{"promise"};
|
|
77
|
+
String reference{"reference"};
|
|
78
|
+
String release{"release"};
|
|
79
|
+
String result{"result"};
|
|
80
|
+
String snapshot{"snapshot"};
|
|
81
|
+
String stack{"stack"};
|
|
82
|
+
String string{"string"};
|
|
83
|
+
String timeout{"timeout"};
|
|
84
|
+
String transferIn{"transferIn"};
|
|
85
|
+
String transferList{"transferList"};
|
|
86
|
+
String transferOut{"transferOut"};
|
|
87
|
+
String undefined{"undefined"};
|
|
88
|
+
String unsafeInherit{"unsafeInherit"};
|
|
89
|
+
|
|
90
|
+
String does_zap_garbage{"does_zap_garbage"};
|
|
91
|
+
String externally_allocated_size{"externally_allocated_size"};
|
|
92
|
+
String heap_size_limit{"heap_size_limit"};
|
|
93
|
+
String malloced_memory{"malloced_memory"};
|
|
94
|
+
String peak_malloced_memory{"peak_malloced_memory"};
|
|
95
|
+
String total_available_size{"total_available_size"};
|
|
96
|
+
String total_heap_size{"total_heap_size"};
|
|
97
|
+
String total_heap_size_executable{"total_heap_size_executable"};
|
|
98
|
+
String total_physical_size{"total_physical_size"};
|
|
99
|
+
String used_heap_size{"used_heap_size"};
|
|
100
|
+
|
|
101
|
+
// CPU Profiler specific keys
|
|
102
|
+
String threadId{"threadId"};
|
|
103
|
+
String profile{"profile"};
|
|
104
|
+
String startTime{"startTime"};
|
|
105
|
+
String endTime{"endTime"};
|
|
106
|
+
String samples{"samples"};
|
|
107
|
+
String timeDeltas{"timeDeltas"};
|
|
108
|
+
String nodes{"nodes"};
|
|
109
|
+
String id{"id"};
|
|
110
|
+
String callFrame{"callFrame"};
|
|
111
|
+
String functionName{"functionName"};
|
|
112
|
+
String scriptId{"scriptId"};
|
|
113
|
+
String url{"url"};
|
|
114
|
+
String lineNumber{"lineNumber"};
|
|
115
|
+
String columnNumber{"columnNumber"};
|
|
116
|
+
String hitCount{"hitCount"};
|
|
117
|
+
String children{"children"};
|
|
118
|
+
String title{"title"};
|
|
119
|
+
String bailoutReason{"bailoutReason"};
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
inline auto HandleCastImpl(
|
|
123
|
+
StringTable::String& value, const HandleCastArguments& /*arguments*/, HandleCastTag<v8::Local<v8::String>> /*tag*/) {
|
|
124
|
+
return v8::Local<v8::String>{value};
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
} // namespace ivm
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
#include "three_phase_task.h"
|
|
2
|
+
#include "external_copy/external_copy.h"
|
|
3
|
+
#include <cstring>
|
|
4
|
+
|
|
5
|
+
using namespace v8;
|
|
6
|
+
using std::unique_ptr;
|
|
7
|
+
|
|
8
|
+
namespace ivm {
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* CalleeInfo implementation
|
|
12
|
+
*/
|
|
13
|
+
ThreePhaseTask::CalleeInfo::CalleeInfo(
|
|
14
|
+
Local<Promise::Resolver> resolver,
|
|
15
|
+
Local<Context> context,
|
|
16
|
+
Local<StackTrace> stack_trace
|
|
17
|
+
) : remotes(resolver, context, stack_trace) {
|
|
18
|
+
auto& env = IsolateEnvironment::GetCurrent();
|
|
19
|
+
if (env.IsDefault()) {
|
|
20
|
+
async = node::EmitAsyncInit(env.GetIsolate(), resolver->GetPromise(), StringTable::Get().isolatedVm);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
ThreePhaseTask::CalleeInfo::CalleeInfo(CalleeInfo&& that) noexcept :
|
|
25
|
+
remotes{std::move(that.remotes)}, async{std::exchange(that.async, {0, 0})} {}
|
|
26
|
+
|
|
27
|
+
ThreePhaseTask::CalleeInfo::~CalleeInfo() {
|
|
28
|
+
auto& env = IsolateEnvironment::GetCurrent();
|
|
29
|
+
node::async_context tmp{0, 0};
|
|
30
|
+
if (env.IsDefault() && std::memcmp(&async, &tmp, sizeof(node::async_context)) != 0) {
|
|
31
|
+
node::EmitAsyncDestroy(env.GetIsolate(), async);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Wrapper around node's version of the same class which does nothing if this isn't the node
|
|
37
|
+
* isolate.
|
|
38
|
+
*
|
|
39
|
+
* nb: CallbackScope sets up a v8::TryCatch so if you need to catch an exception do this *before*
|
|
40
|
+
* the v8::TryCatch.
|
|
41
|
+
*/
|
|
42
|
+
struct CallbackScope {
|
|
43
|
+
unique_ptr<node::CallbackScope> scope;
|
|
44
|
+
|
|
45
|
+
CallbackScope(node::async_context async, Local<Object> resource) {
|
|
46
|
+
auto& env = IsolateEnvironment::GetCurrent();
|
|
47
|
+
if (env.IsDefault()) {
|
|
48
|
+
scope = std::make_unique<node::CallbackScope>(env.GetIsolate(), resource, async);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Phase2Runner implementation
|
|
55
|
+
*/
|
|
56
|
+
ThreePhaseTask::Phase2Runner::Phase2Runner(
|
|
57
|
+
unique_ptr<ThreePhaseTask> self,
|
|
58
|
+
CalleeInfo info
|
|
59
|
+
) :
|
|
60
|
+
self(std::move(self)),
|
|
61
|
+
info(std::move(info)) {}
|
|
62
|
+
|
|
63
|
+
ThreePhaseTask::Phase2Runner::~Phase2Runner() {
|
|
64
|
+
if (!did_run) {
|
|
65
|
+
// The task never got to run
|
|
66
|
+
struct Phase3Orphan : public Runnable {
|
|
67
|
+
unique_ptr<ThreePhaseTask> self;
|
|
68
|
+
CalleeInfo info;
|
|
69
|
+
|
|
70
|
+
Phase3Orphan(
|
|
71
|
+
unique_ptr<ThreePhaseTask> self,
|
|
72
|
+
CalleeInfo info
|
|
73
|
+
) :
|
|
74
|
+
self(std::move(self)),
|
|
75
|
+
info(std::move(info)) {}
|
|
76
|
+
|
|
77
|
+
void Run() final {
|
|
78
|
+
// Revive our persistent handles
|
|
79
|
+
Isolate* isolate = Isolate::GetCurrent();
|
|
80
|
+
auto context_local = info.remotes.Deref<1>();
|
|
81
|
+
Context::Scope context_scope(context_local);
|
|
82
|
+
auto promise_local = info.remotes.Deref<0>();
|
|
83
|
+
CallbackScope callback_scope(info.async, promise_local);
|
|
84
|
+
// Throw from promise
|
|
85
|
+
Local<Object> error = Exception::Error(StringTable::Get().isolateIsDisposed).As<Object>();
|
|
86
|
+
StackTraceHolder::AttachStack(error, info.remotes.Deref<2>());
|
|
87
|
+
Unmaybe(promise_local->Reject(context_local, error));
|
|
88
|
+
isolate->PerformMicrotaskCheckpoint();
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
// Schedule a throw task back in first isolate
|
|
92
|
+
auto* holder = info.remotes.GetIsolateHolder();
|
|
93
|
+
holder->ScheduleTask(
|
|
94
|
+
std::make_unique<Phase3Orphan>(
|
|
95
|
+
std::move(self),
|
|
96
|
+
std::move(info)
|
|
97
|
+
), false, true
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
void ThreePhaseTask::Phase2Runner::Run() {
|
|
103
|
+
|
|
104
|
+
// This class will be used if Phase2() throws an error
|
|
105
|
+
struct Phase3Failure : public Runnable {
|
|
106
|
+
unique_ptr<ThreePhaseTask> self;
|
|
107
|
+
CalleeInfo info;
|
|
108
|
+
unique_ptr<ExternalCopy> error;
|
|
109
|
+
|
|
110
|
+
Phase3Failure(
|
|
111
|
+
unique_ptr<ThreePhaseTask> self,
|
|
112
|
+
CalleeInfo info,
|
|
113
|
+
unique_ptr<ExternalCopy> error
|
|
114
|
+
) :
|
|
115
|
+
self(std::move(self)),
|
|
116
|
+
info(std::move(info)),
|
|
117
|
+
error(std::move(error)) {}
|
|
118
|
+
|
|
119
|
+
void Run() final {
|
|
120
|
+
// Revive our persistent handles
|
|
121
|
+
Isolate* isolate = Isolate::GetCurrent();
|
|
122
|
+
auto context_local = info.remotes.Deref<1>();
|
|
123
|
+
Context::Scope context_scope(context_local);
|
|
124
|
+
auto promise_local = info.remotes.Deref<0>();
|
|
125
|
+
CallbackScope callback_scope(info.async, promise_local);
|
|
126
|
+
Local<Value> rejection;
|
|
127
|
+
if (error) {
|
|
128
|
+
rejection = error->CopyInto();
|
|
129
|
+
} else {
|
|
130
|
+
rejection = Exception::Error(v8_string("An exception was thrown. Sorry I don't know more."));
|
|
131
|
+
}
|
|
132
|
+
if (rejection->IsObject()) {
|
|
133
|
+
StackTraceHolder::ChainStack(rejection.As<Object>(), info.remotes.Deref<2>());
|
|
134
|
+
}
|
|
135
|
+
// If Reject fails then I think that's bad..
|
|
136
|
+
Unmaybe(promise_local->Reject(context_local, rejection));
|
|
137
|
+
isolate->PerformMicrotaskCheckpoint();
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// This is called if Phase2() does not throw
|
|
142
|
+
struct Phase3Success : public Runnable {
|
|
143
|
+
unique_ptr<ThreePhaseTask> self;
|
|
144
|
+
CalleeInfo info;
|
|
145
|
+
|
|
146
|
+
Phase3Success(
|
|
147
|
+
unique_ptr<ThreePhaseTask> self,
|
|
148
|
+
CalleeInfo info
|
|
149
|
+
) :
|
|
150
|
+
self(std::move(self)),
|
|
151
|
+
info(std::move(info)) {}
|
|
152
|
+
|
|
153
|
+
void Run() final {
|
|
154
|
+
Isolate* isolate = Isolate::GetCurrent();
|
|
155
|
+
auto context_local = info.remotes.Deref<1>();
|
|
156
|
+
Context::Scope context_scope(context_local);
|
|
157
|
+
auto promise_local = info.remotes.Deref<0>();
|
|
158
|
+
CallbackScope callback_scope(info.async, promise_local);
|
|
159
|
+
FunctorRunners::RunCatchValue([&]() {
|
|
160
|
+
// Final callback
|
|
161
|
+
Unmaybe(promise_local->Resolve(context_local, self->Phase3()));
|
|
162
|
+
}, [&](Local<Value> error) {
|
|
163
|
+
// Error was thrown
|
|
164
|
+
if (error->IsObject()) {
|
|
165
|
+
StackTraceHolder::AttachStack(error.As<Object>(), info.remotes.Deref<2>());
|
|
166
|
+
}
|
|
167
|
+
Unmaybe(promise_local->Reject(context_local, error));
|
|
168
|
+
});
|
|
169
|
+
isolate->PerformMicrotaskCheckpoint();
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
did_run = true;
|
|
174
|
+
auto schedule_error = [&](std::unique_ptr<ExternalCopy> error) {
|
|
175
|
+
// Schedule a task to enter the first isolate so we can throw the error at the promise
|
|
176
|
+
auto* holder = info.remotes.GetIsolateHolder();
|
|
177
|
+
holder->ScheduleTask(std::make_unique<Phase3Failure>(std::move(self), std::move(info), std::move(error)), false, true);
|
|
178
|
+
};
|
|
179
|
+
FunctorRunners::RunCatchExternal(IsolateEnvironment::GetCurrent().DefaultContext(), [&]() {
|
|
180
|
+
// Continue the task
|
|
181
|
+
self->Phase2();
|
|
182
|
+
auto epilogue_error = IsolateEnvironment::GetCurrent().TaskEpilogue();
|
|
183
|
+
if (epilogue_error) {
|
|
184
|
+
schedule_error(std::move(epilogue_error));
|
|
185
|
+
} else {
|
|
186
|
+
auto* holder = info.remotes.GetIsolateHolder();
|
|
187
|
+
holder->ScheduleTask(std::make_unique<Phase3Success>(std::move(self), std::move(info)), false, true);
|
|
188
|
+
}
|
|
189
|
+
}, schedule_error);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Phase2RunnerIgnored implementation
|
|
194
|
+
*/
|
|
195
|
+
ThreePhaseTask::Phase2RunnerIgnored::Phase2RunnerIgnored(unique_ptr<ThreePhaseTask> self) : self(std::move(self)) {}
|
|
196
|
+
|
|
197
|
+
void ThreePhaseTask::Phase2RunnerIgnored::Run() {
|
|
198
|
+
TryCatch try_catch{Isolate::GetCurrent()};
|
|
199
|
+
try {
|
|
200
|
+
self->Phase2();
|
|
201
|
+
IsolateEnvironment::GetCurrent().TaskEpilogue();
|
|
202
|
+
} catch (const RuntimeError& cc_error) {}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* RunSync implementation
|
|
207
|
+
*/
|
|
208
|
+
auto ThreePhaseTask::RunSync(IsolateHolder& second_isolate, bool allow_async) -> Local<Value> {
|
|
209
|
+
// Grab a reference to second isolate
|
|
210
|
+
auto second_isolate_ref = second_isolate.GetIsolate();
|
|
211
|
+
if (!second_isolate_ref) {
|
|
212
|
+
throw RuntimeGenericError("Isolated is disposed");
|
|
213
|
+
}
|
|
214
|
+
if (second_isolate_ref->GetIsolate() == Isolate::GetCurrent()) {
|
|
215
|
+
if (allow_async) {
|
|
216
|
+
throw RuntimeGenericError("This function may not be called from the default thread");
|
|
217
|
+
}
|
|
218
|
+
// Shortcut when calling a sync method belonging to the currently entered isolate. This avoids
|
|
219
|
+
// the deadlock protection below
|
|
220
|
+
Phase2();
|
|
221
|
+
second_isolate_ref->CheckMemoryPressure();
|
|
222
|
+
|
|
223
|
+
} else {
|
|
224
|
+
|
|
225
|
+
bool is_recursive = Locker::IsLocked(second_isolate_ref->GetIsolate());
|
|
226
|
+
if (Executor::IsDefaultThread() || is_recursive) {
|
|
227
|
+
if (allow_async) {
|
|
228
|
+
throw RuntimeGenericError("This function may not be called from the default thread");
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Helper function which flushes handle tasks
|
|
232
|
+
auto run_handle_tasks = [](IsolateEnvironment& env) {
|
|
233
|
+
auto handle_tasks = [&]() {
|
|
234
|
+
return ExchangeDefault(env.scheduler->Lock()->handle_tasks);
|
|
235
|
+
}();
|
|
236
|
+
if (handle_tasks.empty()) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
do {
|
|
240
|
+
handle_tasks.front()->Run();
|
|
241
|
+
handle_tasks.pop();
|
|
242
|
+
} while (!handle_tasks.empty());
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
// This is the simple sync runner case
|
|
246
|
+
unique_ptr<ExternalCopy> error;
|
|
247
|
+
{
|
|
248
|
+
Executor::Lock lock(*second_isolate_ref);
|
|
249
|
+
|
|
250
|
+
// Run handle tasks first
|
|
251
|
+
run_handle_tasks(*second_isolate_ref);
|
|
252
|
+
|
|
253
|
+
// Now run the actual work
|
|
254
|
+
FunctorRunners::RunCatchExternal(second_isolate_ref->DefaultContext(), [&]() {
|
|
255
|
+
// Run Phase2 and externalize errors
|
|
256
|
+
Phase2();
|
|
257
|
+
if (!is_recursive) {
|
|
258
|
+
error = second_isolate_ref->TaskEpilogue();
|
|
259
|
+
}
|
|
260
|
+
}, [&](unique_ptr<ExternalCopy> error_inner) {
|
|
261
|
+
|
|
262
|
+
// We need to stash the error in the outer unique_ptr because the executor lock is still up
|
|
263
|
+
error = std::move(error_inner);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Run handle tasks for default isolate now
|
|
268
|
+
auto& current_env = IsolateEnvironment::GetCurrent();
|
|
269
|
+
if (current_env.IsDefault()) {
|
|
270
|
+
run_handle_tasks(current_env);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (error) {
|
|
274
|
+
// Throw to outer isolate
|
|
275
|
+
Isolate* isolate = Isolate::GetCurrent();
|
|
276
|
+
Local<Value> error_copy = error->CopyInto();
|
|
277
|
+
if (error_copy->IsObject()) {
|
|
278
|
+
StackTraceHolder::ChainStack(error_copy.As<Object>(), StackTrace::CurrentStackTrace(isolate, 10));
|
|
279
|
+
}
|
|
280
|
+
isolate->ThrowException(error_copy);
|
|
281
|
+
throw RuntimeError();
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
} else if (second_isolate_ref->IsDefault()) {
|
|
285
|
+
|
|
286
|
+
// In this case we asyncronously call the default thread and suspend this thread
|
|
287
|
+
struct AsyncRunner final : public Runnable {
|
|
288
|
+
bool allow_async = false;
|
|
289
|
+
bool did_run = false;
|
|
290
|
+
ThreePhaseTask& self;
|
|
291
|
+
Scheduler::AsyncWait& wait;
|
|
292
|
+
lockable_t<bool, false, true>& done;
|
|
293
|
+
unique_ptr<ExternalCopy>& error;
|
|
294
|
+
|
|
295
|
+
AsyncRunner(
|
|
296
|
+
ThreePhaseTask& self,
|
|
297
|
+
Scheduler::AsyncWait& wait,
|
|
298
|
+
lockable_t<bool, false, true>& done,
|
|
299
|
+
bool allow_async,
|
|
300
|
+
unique_ptr<ExternalCopy>& error
|
|
301
|
+
) : allow_async{allow_async}, self{self}, wait{wait}, done{done}, error{error} {}
|
|
302
|
+
|
|
303
|
+
AsyncRunner(const AsyncRunner&) = delete;
|
|
304
|
+
auto operator=(const AsyncRunner&) -> AsyncRunner& = delete;
|
|
305
|
+
|
|
306
|
+
~AsyncRunner() final {
|
|
307
|
+
if (!did_run) {
|
|
308
|
+
error = std::make_unique<ExternalCopyError>(ExternalCopyError::ErrorType::Error, "Isolate is disposed");
|
|
309
|
+
}
|
|
310
|
+
// nb: The lock must be held while invoking `notify_one` since the condition variable will
|
|
311
|
+
// be destroyed immediately following the wake.
|
|
312
|
+
auto lock = done.write();
|
|
313
|
+
*lock = true;
|
|
314
|
+
done.notify_one();
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
void Run() final {
|
|
318
|
+
did_run = true;
|
|
319
|
+
FunctorRunners::RunCatchExternal(IsolateEnvironment::GetCurrent().DefaultContext(), [ this ]() {
|
|
320
|
+
// Now in the default thread
|
|
321
|
+
const auto is_async = [&]() {
|
|
322
|
+
if (allow_async) {
|
|
323
|
+
return self.Phase2Async(wait);
|
|
324
|
+
} else {
|
|
325
|
+
self.Phase2();
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
}();
|
|
329
|
+
if (!is_async) {
|
|
330
|
+
wait.Done();
|
|
331
|
+
}
|
|
332
|
+
this->error = IsolateEnvironment::GetCurrent().TaskEpilogue();
|
|
333
|
+
}, [ this ](unique_ptr<ExternalCopy> error) {
|
|
334
|
+
this->error = std::move(error);
|
|
335
|
+
wait.Done();
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
Isolate* isolate = Isolate::GetCurrent();
|
|
341
|
+
unique_ptr<ExternalCopy> error;
|
|
342
|
+
{
|
|
343
|
+
// Setup condition variable to sleep this thread
|
|
344
|
+
IsolateEnvironment& env = IsolateEnvironment::GetCurrent();
|
|
345
|
+
Scheduler::AsyncWait wait(*env.scheduler);
|
|
346
|
+
lockable_t<bool, false, true> done{false};
|
|
347
|
+
// Scope to unlock v8 in this thread and set up the wait
|
|
348
|
+
Executor::Unlock unlocker(env);
|
|
349
|
+
// Run it and sleep
|
|
350
|
+
second_isolate.ScheduleTask(std::make_unique<AsyncRunner>(*this, wait, done, allow_async, error), false, true);
|
|
351
|
+
// Wait for AsyncRunner to finish
|
|
352
|
+
auto lock = done.read<true>();
|
|
353
|
+
while (!*lock) {
|
|
354
|
+
lock.wait();
|
|
355
|
+
}
|
|
356
|
+
// Wait for `applySyncPromise` to finish
|
|
357
|
+
if (wait.Wait() == Scheduler::AsyncWait::canceled) {
|
|
358
|
+
throw RuntimeGenericError("Isolate is disposed");
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// At this point thread synchronization is done and Phase2() has finished
|
|
363
|
+
if (error) {
|
|
364
|
+
Local<Value> error_copy = error->CopyInto();
|
|
365
|
+
if (error_copy->IsObject()) {
|
|
366
|
+
StackTraceHolder::ChainStack(error_copy.As<Object>(), StackTrace::CurrentStackTrace(isolate, 10));
|
|
367
|
+
}
|
|
368
|
+
isolate->ThrowException(error_copy);
|
|
369
|
+
throw RuntimeError();
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
} else {
|
|
373
|
+
|
|
374
|
+
// ~ very specific error message ~
|
|
375
|
+
throw RuntimeGenericError(
|
|
376
|
+
"Calling a synchronous isolated-vm function on a non-default isolate from within an asynchronous isolated-vm function is not allowed."
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Final phase
|
|
382
|
+
return Phase3();
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
} // namespace ivm
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include "node_wrapper.h"
|
|
3
|
+
#include "environment.h"
|
|
4
|
+
#include "holder.h"
|
|
5
|
+
#include "functor_runners.h"
|
|
6
|
+
#include "remote_handle.h"
|
|
7
|
+
#include "stack_trace.h"
|
|
8
|
+
#include "util.h"
|
|
9
|
+
#include <memory>
|
|
10
|
+
|
|
11
|
+
namespace ivm {
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Most operations in this library can be decomposed into three phases.
|
|
15
|
+
*
|
|
16
|
+
* - Phase 1 [Isolate 1]: copy data out of current isolate
|
|
17
|
+
* - Phase 2 [Isolate 2]: copy data into new isolate, run work, copy data out of isolate
|
|
18
|
+
* - Phase 3 [Isolate 1]: copy results from phase 2 into the original isolate
|
|
19
|
+
*
|
|
20
|
+
* This class handles the locking and thread synchronization for either synchronous or
|
|
21
|
+
* asynchronous functions. That way the same code can be used for both versions of each function.
|
|
22
|
+
*
|
|
23
|
+
* These runners are invoked via: ThreePhaseTask::Run<async, T>(isolate, args...);
|
|
24
|
+
*
|
|
25
|
+
* Where:
|
|
26
|
+
* async = 0 -- Synchronous execution
|
|
27
|
+
* async = 1 -- Asynchronous execution, promise returned
|
|
28
|
+
* async = 2 -- Asynchronous execution, result ignored (Phase3() is never called)
|
|
29
|
+
* async = 4 -- Synchronous + asyncronous, original thread waits for async Phase2()
|
|
30
|
+
*/
|
|
31
|
+
class ThreePhaseTask {
|
|
32
|
+
private:
|
|
33
|
+
/**
|
|
34
|
+
* Contains references back to the original isolate which will be used after phase 2 to wake the
|
|
35
|
+
* isolate up and begin phase 3
|
|
36
|
+
*/
|
|
37
|
+
struct CalleeInfo {
|
|
38
|
+
RemoteTuple<v8::Promise::Resolver, v8::Context, v8::StackTrace> remotes;
|
|
39
|
+
node::async_context async {0, 0};
|
|
40
|
+
CalleeInfo(
|
|
41
|
+
v8::Local<v8::Promise::Resolver> resolver,
|
|
42
|
+
v8::Local<v8::Context> context,
|
|
43
|
+
v8::Local<v8::StackTrace> stack_trace
|
|
44
|
+
);
|
|
45
|
+
CalleeInfo(const CalleeInfo&) = delete;
|
|
46
|
+
CalleeInfo(CalleeInfo&& /*that*/) noexcept;
|
|
47
|
+
auto operator= (const CalleeInfo&) = delete;
|
|
48
|
+
auto operator= (CalleeInfo&&) = delete;
|
|
49
|
+
~CalleeInfo();
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Class which manages running async phase 2, then phase 3
|
|
54
|
+
*/
|
|
55
|
+
struct Phase2Runner final : public Runnable {
|
|
56
|
+
std::unique_ptr<ThreePhaseTask> self;
|
|
57
|
+
CalleeInfo info;
|
|
58
|
+
bool did_run = false;
|
|
59
|
+
|
|
60
|
+
Phase2Runner(
|
|
61
|
+
std::unique_ptr<ThreePhaseTask> self,
|
|
62
|
+
CalleeInfo info
|
|
63
|
+
);
|
|
64
|
+
Phase2Runner(const Phase2Runner&) = delete;
|
|
65
|
+
auto operator= (const Phase2Runner&) -> Phase2Runner& = delete;
|
|
66
|
+
~Phase2Runner() final;
|
|
67
|
+
void Run() final;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Class which manages running async phase 2 in ignored mode (ie no phase 3)
|
|
72
|
+
*/
|
|
73
|
+
struct Phase2RunnerIgnored : public Runnable {
|
|
74
|
+
std::unique_ptr<ThreePhaseTask> self;
|
|
75
|
+
explicit Phase2RunnerIgnored(std::unique_ptr<ThreePhaseTask> self);
|
|
76
|
+
void Run() final;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
auto RunSync(IsolateHolder& second_isolate, bool allow_async) -> v8::Local<v8::Value>;
|
|
80
|
+
|
|
81
|
+
public:
|
|
82
|
+
ThreePhaseTask() = default;
|
|
83
|
+
ThreePhaseTask(const ThreePhaseTask&) = delete;
|
|
84
|
+
auto operator= (const ThreePhaseTask&) -> ThreePhaseTask& = delete;
|
|
85
|
+
virtual ~ThreePhaseTask() = default;
|
|
86
|
+
|
|
87
|
+
virtual void Phase2() = 0;
|
|
88
|
+
virtual auto Phase2Async(Scheduler::AsyncWait& /*wait*/) -> bool {
|
|
89
|
+
Phase2();
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
virtual auto Phase3() -> v8::Local<v8::Value> = 0;
|
|
94
|
+
|
|
95
|
+
template <int async, typename T, typename ...Args>
|
|
96
|
+
static auto Run(IsolateHolder& second_isolate, Args&&... args) -> v8::Local<v8::Value> {
|
|
97
|
+
|
|
98
|
+
if (async == 1) { // Full async, promise returned
|
|
99
|
+
// Build a promise for outer isolate
|
|
100
|
+
v8::Isolate* isolate = v8::Isolate::GetCurrent();
|
|
101
|
+
auto context_local = isolate->GetCurrentContext();
|
|
102
|
+
auto promise_local = Unmaybe(v8::Promise::Resolver::New(context_local));
|
|
103
|
+
auto stack_trace = v8::StackTrace::CurrentStackTrace(isolate, 10);
|
|
104
|
+
FunctorRunners::RunCatchValue([&]() {
|
|
105
|
+
// Schedule Phase2 async
|
|
106
|
+
second_isolate.ScheduleTask(
|
|
107
|
+
std::make_unique<Phase2Runner>(
|
|
108
|
+
std::make_unique<T>(std::forward<Args>(args)...), // <-- Phase1 / ctor called here
|
|
109
|
+
CalleeInfo{promise_local, context_local, stack_trace}
|
|
110
|
+
), false, true
|
|
111
|
+
);
|
|
112
|
+
}, [&](v8::Local<v8::Value> error) {
|
|
113
|
+
// A C++ error was caught while running ctor (phase 1)
|
|
114
|
+
if (error->IsObject()) {
|
|
115
|
+
StackTraceHolder::AttachStack(error.As<v8::Object>(), stack_trace);
|
|
116
|
+
}
|
|
117
|
+
Unmaybe(promise_local->Reject(context_local, error));
|
|
118
|
+
});
|
|
119
|
+
return promise_local->GetPromise();
|
|
120
|
+
} else if (async == 2) { // Async, promise ignored
|
|
121
|
+
// Schedule Phase2 async
|
|
122
|
+
second_isolate.ScheduleTask(
|
|
123
|
+
std::make_unique<Phase2RunnerIgnored>(
|
|
124
|
+
std::make_unique<T>(std::forward<Args>(args)...) // <-- Phase1 / ctor called here
|
|
125
|
+
), false, true
|
|
126
|
+
);
|
|
127
|
+
return v8::Undefined(v8::Isolate::GetCurrent());
|
|
128
|
+
} else {
|
|
129
|
+
// Execute synchronously
|
|
130
|
+
T self(std::forward<Args>(args)...);
|
|
131
|
+
return self.RunSync(second_isolate, async == 4);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
} // namespace ivm
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <v8.h>
|
|
3
|
+
|
|
4
|
+
namespace ivm {
|
|
5
|
+
|
|
6
|
+
class Transferable {
|
|
7
|
+
public:
|
|
8
|
+
Transferable() = default;
|
|
9
|
+
Transferable(const Transferable&) = delete;
|
|
10
|
+
auto operator= (const Transferable&) = delete;
|
|
11
|
+
virtual ~Transferable() = default;
|
|
12
|
+
virtual auto TransferIn() -> v8::Local<v8::Value> = 0;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
} // namespace ivm
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <cassert>
|
|
3
|
+
#include <string>
|
|
4
|
+
#include <functional>
|
|
5
|
+
#include <v8.h>
|
|
6
|
+
#include "generic/error.h"
|
|
7
|
+
|
|
8
|
+
namespace ivm {
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Easy strings
|
|
12
|
+
*/
|
|
13
|
+
inline auto v8_string(const char* string) -> v8::Local<v8::String> {
|
|
14
|
+
return Unmaybe(v8::String::NewFromOneByte(v8::Isolate::GetCurrent(), (const uint8_t*)string, v8::NewStringType::kNormal)); // NOLINT
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
inline auto v8_symbol(const char* string) -> v8::Local<v8::String> {
|
|
18
|
+
return Unmaybe(v8::String::NewFromOneByte(v8::Isolate::GetCurrent(), (const uint8_t*)string, v8::NewStringType::kInternalized)); // NOLINT
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Shorthand dereference of Persistent to Local
|
|
23
|
+
*/
|
|
24
|
+
template <typename T>
|
|
25
|
+
auto Deref(const v8::Persistent<T>& handle) -> v8::Local<T> {
|
|
26
|
+
return v8::Local<T>::New(v8::Isolate::GetCurrent(), handle);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
template <typename T>
|
|
30
|
+
auto Deref(const v8::Persistent<T, v8::CopyablePersistentTraits<T>>& handle) -> v8::Local<T> {
|
|
31
|
+
return v8::Local<T>::New(v8::Isolate::GetCurrent(), handle);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#include "remote_handle.h"
|
|
37
|
+
|
|
38
|
+
namespace ivm {
|
|
39
|
+
|
|
40
|
+
template <typename T>
|
|
41
|
+
auto Deref(const RemoteHandle<T>& handle) -> v8::Local<T> {
|
|
42
|
+
return handle.Deref();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
} // namespace ivm
|