@nocobase/plugin-workflow-javascript 2.1.0-beta.11 → 2.1.0-beta.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/externalVersion.js +4 -4
- package/dist/node_modules/isolated-vm/.clang-tidy +13 -0
- package/dist/node_modules/isolated-vm/.dockerignore +9 -0
- package/dist/node_modules/isolated-vm/Dockerfile.alpine +9 -0
- package/dist/node_modules/isolated-vm/Dockerfile.debian +12 -0
- package/dist/node_modules/isolated-vm/LICENSE +13 -0
- package/dist/node_modules/isolated-vm/binding.gyp +120 -0
- package/dist/node_modules/isolated-vm/include.js +3 -0
- package/dist/node_modules/isolated-vm/inspector-example.js +59 -0
- package/dist/node_modules/isolated-vm/isolated-vm.d.ts +820 -0
- package/dist/node_modules/isolated-vm/isolated-vm.js +1 -0
- package/dist/node_modules/isolated-vm/native-example/binding.gyp +23 -0
- package/dist/node_modules/isolated-vm/native-example/example.cc +61 -0
- package/dist/node_modules/isolated-vm/native-example/package.json +13 -0
- package/dist/node_modules/isolated-vm/native-example/usage.js +35 -0
- package/dist/node_modules/isolated-vm/out/isolated_vm.node +0 -0
- package/dist/node_modules/isolated-vm/package.json +1 -0
- package/dist/node_modules/isolated-vm/src/external_copy/error.h +33 -0
- package/dist/node_modules/isolated-vm/src/external_copy/external_copy.cc +509 -0
- package/dist/node_modules/isolated-vm/src/external_copy/external_copy.h +117 -0
- package/dist/node_modules/isolated-vm/src/external_copy/serializer.cc +85 -0
- package/dist/node_modules/isolated-vm/src/external_copy/serializer.h +136 -0
- package/dist/node_modules/isolated-vm/src/external_copy/serializer_nortti.cc +73 -0
- package/dist/node_modules/isolated-vm/src/external_copy/string.cc +124 -0
- package/dist/node_modules/isolated-vm/src/external_copy/string.h +28 -0
- package/dist/node_modules/isolated-vm/src/isolate/allocator.h +32 -0
- package/dist/node_modules/isolated-vm/src/isolate/allocator_nortti.cc +142 -0
- package/dist/node_modules/isolated-vm/src/isolate/class_handle.h +334 -0
- package/dist/node_modules/isolated-vm/src/isolate/cpu_profile_manager.cc +220 -0
- package/dist/node_modules/isolated-vm/src/isolate/cpu_profile_manager.h +100 -0
- package/dist/node_modules/isolated-vm/src/isolate/environment.cc +626 -0
- package/dist/node_modules/isolated-vm/src/isolate/environment.h +381 -0
- package/dist/node_modules/isolated-vm/src/isolate/executor.cc +198 -0
- package/dist/node_modules/isolated-vm/src/isolate/executor.h +183 -0
- package/dist/node_modules/isolated-vm/src/isolate/external.h +64 -0
- package/dist/node_modules/isolated-vm/src/isolate/functor_runners.h +97 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/array.h +145 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/callbacks.h +272 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/error.h +140 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/extract_params.h +145 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/handle_cast.h +257 -0
- package/dist/node_modules/isolated-vm/src/isolate/generic/read_option.h +47 -0
- package/dist/node_modules/isolated-vm/src/isolate/holder.cc +88 -0
- package/dist/node_modules/isolated-vm/src/isolate/holder.h +63 -0
- package/dist/node_modules/isolated-vm/src/isolate/inspector.cc +200 -0
- package/dist/node_modules/isolated-vm/src/isolate/inspector.h +70 -0
- package/dist/node_modules/isolated-vm/src/isolate/node_wrapper.h +15 -0
- package/dist/node_modules/isolated-vm/src/isolate/platform_delegate.cc +22 -0
- package/dist/node_modules/isolated-vm/src/isolate/platform_delegate.h +46 -0
- package/dist/node_modules/isolated-vm/src/isolate/remote_handle.h +164 -0
- package/dist/node_modules/isolated-vm/src/isolate/run_with_timeout.h +171 -0
- package/dist/node_modules/isolated-vm/src/isolate/runnable.h +29 -0
- package/dist/node_modules/isolated-vm/src/isolate/scheduler.cc +191 -0
- package/dist/node_modules/isolated-vm/src/isolate/scheduler.h +165 -0
- package/dist/node_modules/isolated-vm/src/isolate/specific.h +35 -0
- package/dist/node_modules/isolated-vm/src/isolate/stack_trace.cc +219 -0
- package/dist/node_modules/isolated-vm/src/isolate/stack_trace.h +24 -0
- package/dist/node_modules/isolated-vm/src/isolate/strings.h +127 -0
- package/dist/node_modules/isolated-vm/src/isolate/three_phase_task.cc +385 -0
- package/dist/node_modules/isolated-vm/src/isolate/three_phase_task.h +136 -0
- package/dist/node_modules/isolated-vm/src/isolate/transferable.h +15 -0
- package/dist/node_modules/isolated-vm/src/isolate/util.h +45 -0
- package/dist/node_modules/isolated-vm/src/isolate/v8_inspector_wrapper.h +12 -0
- package/dist/node_modules/isolated-vm/src/isolate/v8_version.h +12 -0
- package/dist/node_modules/isolated-vm/src/isolated_vm.h +71 -0
- package/dist/node_modules/isolated-vm/src/lib/covariant.h +50 -0
- package/dist/node_modules/isolated-vm/src/lib/lockable.h +178 -0
- package/dist/node_modules/isolated-vm/src/lib/suspend.h +106 -0
- package/dist/node_modules/isolated-vm/src/lib/thread_pool.cc +98 -0
- package/dist/node_modules/isolated-vm/src/lib/thread_pool.h +45 -0
- package/dist/node_modules/isolated-vm/src/lib/timer.cc +233 -0
- package/dist/node_modules/isolated-vm/src/lib/timer.h +36 -0
- package/dist/node_modules/isolated-vm/src/module/callback.cc +151 -0
- package/dist/node_modules/isolated-vm/src/module/callback.h +64 -0
- package/dist/node_modules/isolated-vm/src/module/context_handle.cc +241 -0
- package/dist/node_modules/isolated-vm/src/module/context_handle.h +35 -0
- package/dist/node_modules/isolated-vm/src/module/evaluation.cc +109 -0
- package/dist/node_modules/isolated-vm/src/module/evaluation.h +99 -0
- package/dist/node_modules/isolated-vm/src/module/external_copy_handle.cc +119 -0
- package/dist/node_modules/isolated-vm/src/module/external_copy_handle.h +64 -0
- package/dist/node_modules/isolated-vm/src/module/isolate.cc +136 -0
- package/dist/node_modules/isolated-vm/src/module/isolate_handle.cc +611 -0
- package/dist/node_modules/isolated-vm/src/module/isolate_handle.h +47 -0
- package/dist/node_modules/isolated-vm/src/module/lib_handle.cc +77 -0
- package/dist/node_modules/isolated-vm/src/module/lib_handle.h +28 -0
- package/dist/node_modules/isolated-vm/src/module/module_handle.cc +475 -0
- package/dist/node_modules/isolated-vm/src/module/module_handle.h +68 -0
- package/dist/node_modules/isolated-vm/src/module/native_module_handle.cc +104 -0
- package/dist/node_modules/isolated-vm/src/module/native_module_handle.h +49 -0
- package/dist/node_modules/isolated-vm/src/module/reference_handle.cc +636 -0
- package/dist/node_modules/isolated-vm/src/module/reference_handle.h +106 -0
- package/dist/node_modules/isolated-vm/src/module/script_handle.cc +107 -0
- package/dist/node_modules/isolated-vm/src/module/script_handle.h +37 -0
- package/dist/node_modules/isolated-vm/src/module/session_handle.cc +173 -0
- package/dist/node_modules/isolated-vm/src/module/session_handle.h +31 -0
- package/dist/node_modules/isolated-vm/src/module/transferable.cc +268 -0
- package/dist/node_modules/isolated-vm/src/module/transferable.h +42 -0
- package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v18.0.0.h +360 -0
- package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v18.3.0.h +376 -0
- package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v20.0.0.h +397 -0
- package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v22.0.0.h +419 -0
- package/dist/node_modules/winston-transport/package.json +1 -1
- package/dist/server/IsolatedVm.js +75 -0
- package/dist/server/ScriptInstruction.d.ts +6 -0
- package/dist/server/ScriptInstruction.js +11 -1
- package/dist/server/Vm.js +42 -27
- package/package.json +3 -2
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <v8.h>
|
|
3
|
+
#include <atomic>
|
|
4
|
+
#include <cstdint>
|
|
5
|
+
#include <cstdlib>
|
|
6
|
+
#include <memory>
|
|
7
|
+
#include <vector>
|
|
8
|
+
|
|
9
|
+
#include "isolate/generic/array.h"
|
|
10
|
+
#include "isolate/allocator.h"
|
|
11
|
+
#include "isolate/transferable.h"
|
|
12
|
+
#include "isolate/util.h"
|
|
13
|
+
#include "lib/lockable.h"
|
|
14
|
+
|
|
15
|
+
namespace ivm {
|
|
16
|
+
|
|
17
|
+
using handle_vector_t = std::vector<v8::Local<v8::Value>>;
|
|
18
|
+
using transferable_vector_t = std::vector<std::unique_ptr<Transferable>>;
|
|
19
|
+
using array_buffer_vector_t = std::vector<std::unique_ptr<class ExternalCopyArrayBuffer>>;
|
|
20
|
+
using shared_buffer_vector_t = std::vector<std::unique_ptr<class ExternalCopySharedArrayBuffer>>;
|
|
21
|
+
|
|
22
|
+
class ExternalCopy : public Transferable {
|
|
23
|
+
public:
|
|
24
|
+
ExternalCopy() = default;
|
|
25
|
+
ExternalCopy(const ExternalCopy&) = delete;
|
|
26
|
+
auto operator= (const ExternalCopy&) = delete;
|
|
27
|
+
~ExternalCopy() override;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* `Copy` may throw a v8 exception if JSON.stringify(value) throws
|
|
31
|
+
*/
|
|
32
|
+
static auto Copy(
|
|
33
|
+
v8::Local<v8::Value> value,
|
|
34
|
+
bool transfer_out = false,
|
|
35
|
+
ArrayRange transfer_list = {}
|
|
36
|
+
) -> std::unique_ptr<ExternalCopy>;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* If you give this a primitive v8::Value (except Symbol) it will return a ExternalCopy for you.
|
|
40
|
+
* Otherwise it returns nullptr. This is used to automatically move simple values between
|
|
41
|
+
* isolates where it is possible to do so perfectly.
|
|
42
|
+
*/
|
|
43
|
+
static auto CopyIfPrimitive(v8::Local<v8::Value> value) -> std::unique_ptr<ExternalCopy>;
|
|
44
|
+
static auto CopyThrownValue(v8::Local<v8::Value> value) -> std::unique_ptr<ExternalCopy>;
|
|
45
|
+
|
|
46
|
+
static auto TotalExternalSize() -> int;
|
|
47
|
+
|
|
48
|
+
auto CopyIntoCheckHeap(bool transfer_in = false) -> v8::Local<v8::Value>;
|
|
49
|
+
virtual auto CopyInto(bool transfer_in = false) -> v8::Local<v8::Value> = 0;
|
|
50
|
+
auto Size() const -> int { return size; }
|
|
51
|
+
auto TransferIn() -> v8::Local<v8::Value> final { return CopyIntoCheckHeap(); }
|
|
52
|
+
|
|
53
|
+
protected:
|
|
54
|
+
explicit ExternalCopy(int size);
|
|
55
|
+
ExternalCopy(ExternalCopy&& that) noexcept;
|
|
56
|
+
auto operator= (ExternalCopy&& that) noexcept -> ExternalCopy&;
|
|
57
|
+
|
|
58
|
+
void UpdateSize(int size);
|
|
59
|
+
|
|
60
|
+
private:
|
|
61
|
+
int size = 0;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Base class for ArrayBuffer and SharedArrayBuffer
|
|
66
|
+
*/
|
|
67
|
+
class ExternalCopyAnyBuffer : public ExternalCopy {
|
|
68
|
+
public:
|
|
69
|
+
explicit ExternalCopyAnyBuffer(std::shared_ptr<v8::BackingStore> backing_store) :
|
|
70
|
+
backing_store{std::move(backing_store)} {}
|
|
71
|
+
auto Acquire() const -> std::shared_ptr<v8::BackingStore> { return *backing_store.read(); }
|
|
72
|
+
|
|
73
|
+
protected:
|
|
74
|
+
lockable_t<std::shared_ptr<v8::BackingStore>> backing_store;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* ArrayBuffer instances
|
|
79
|
+
*/
|
|
80
|
+
class ExternalCopyArrayBuffer : public ExternalCopyAnyBuffer {
|
|
81
|
+
public:
|
|
82
|
+
using ExternalCopyAnyBuffer::ExternalCopyAnyBuffer;
|
|
83
|
+
ExternalCopyArrayBuffer(const void* data, size_t length);
|
|
84
|
+
explicit ExternalCopyArrayBuffer(v8::Local<v8::ArrayBuffer> handle);
|
|
85
|
+
|
|
86
|
+
static auto Transfer(v8::Local<v8::ArrayBuffer> handle) -> std::unique_ptr<ExternalCopyArrayBuffer>;
|
|
87
|
+
auto CopyInto(bool transfer_in = false) -> v8::Local<v8::Value> final;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* SharedArrayBuffer instances
|
|
92
|
+
*/
|
|
93
|
+
class ExternalCopySharedArrayBuffer : public ExternalCopyAnyBuffer {
|
|
94
|
+
public:
|
|
95
|
+
explicit ExternalCopySharedArrayBuffer(v8::Local<v8::SharedArrayBuffer> handle);
|
|
96
|
+
|
|
97
|
+
auto CopyInto(bool transfer_in = false) -> v8::Local<v8::Value> final;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* All types of TypedArray views w/ underlying buffer handle
|
|
102
|
+
*/
|
|
103
|
+
class ExternalCopyArrayBufferView : public ExternalCopy {
|
|
104
|
+
public:
|
|
105
|
+
enum class ViewType { Uint8, Uint8Clamped, Int8, Uint16, Int16, Uint32, Int32, Float32, Float64, BigInt64, BigUint64, DataView };
|
|
106
|
+
|
|
107
|
+
private:
|
|
108
|
+
std::unique_ptr<ExternalCopyAnyBuffer> buffer;
|
|
109
|
+
ViewType type;
|
|
110
|
+
size_t byte_offset, byte_length;
|
|
111
|
+
|
|
112
|
+
public:
|
|
113
|
+
ExternalCopyArrayBufferView(std::unique_ptr<ExternalCopyAnyBuffer> buffer, ViewType type, size_t byte_offset, size_t byte_length);
|
|
114
|
+
auto CopyInto(bool transfer_in = false) -> v8::Local<v8::Value> final;
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
} // namespace ivm
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
#include "serializer.h"
|
|
2
|
+
#include "isolate/allocator.h"
|
|
3
|
+
|
|
4
|
+
using namespace v8;
|
|
5
|
+
namespace ivm {
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* ExternalCopySerialized implementation
|
|
9
|
+
*/
|
|
10
|
+
ExternalCopySerialized::ExternalCopySerialized(Local<Value> value, ArrayRange transfer_list) :
|
|
11
|
+
BaseSerializer{[&](ValueSerializer& serializer, Local<Context> context) {
|
|
12
|
+
// Mark ArrayBuffers as transferred, but don't actually transfer yet otherwise it will invalidate
|
|
13
|
+
// array views before they are transferred
|
|
14
|
+
int ii = 0;
|
|
15
|
+
for (auto handle : transfer_list) {
|
|
16
|
+
if (handle->IsArrayBuffer()) {
|
|
17
|
+
serializer.TransferArrayBuffer(ii++, handle.As<ArrayBuffer>());
|
|
18
|
+
} else {
|
|
19
|
+
throw RuntimeTypeError("Non-ArrayBuffer passed in `transferList`");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Serialize object and save
|
|
24
|
+
serializer.WriteHeader();
|
|
25
|
+
Unmaybe(serializer.WriteValue(context, value));
|
|
26
|
+
}} {
|
|
27
|
+
|
|
28
|
+
// Transfer ArrayBuffers
|
|
29
|
+
for (auto handle : transfer_list) {
|
|
30
|
+
array_buffers.emplace_back(ExternalCopyArrayBuffer::Transfer(handle.As<ArrayBuffer>()));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
auto ExternalCopySerialized::CopyInto(bool transfer_in) -> Local<Value> {
|
|
35
|
+
Local<Value> value;
|
|
36
|
+
|
|
37
|
+
Deserialize([&](ValueDeserializer& deserializer, Local<Context> context) {
|
|
38
|
+
// Transfer ArrayBuffers
|
|
39
|
+
for (unsigned ii = 0; ii < array_buffers.size(); ++ii) {
|
|
40
|
+
deserializer.TransferArrayBuffer(ii, array_buffers[ii]->CopyIntoCheckHeap(transfer_in).As<ArrayBuffer>());
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Deserialize object
|
|
44
|
+
Unmaybe(deserializer.ReadHeader(context));
|
|
45
|
+
return deserializer.ReadValue(context).ToLocal(&value);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return value;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* SerializedVector implementation
|
|
53
|
+
*/
|
|
54
|
+
SerializedVector::SerializedVector(const v8::FunctionCallbackInfo<v8::Value>& info) :
|
|
55
|
+
BaseSerializer([&](ValueSerializer& serializer, Local<Context> context) {
|
|
56
|
+
int length = info.Length();
|
|
57
|
+
serializer.WriteUint32(length);
|
|
58
|
+
for (int ii = 0; ii < length; ++ii) {
|
|
59
|
+
Unmaybe(serializer.WriteValue(context, info[ii]));
|
|
60
|
+
}
|
|
61
|
+
}) {}
|
|
62
|
+
|
|
63
|
+
auto SerializedVector::CopyIntoAsVector() -> std::vector<Local<Value>> {
|
|
64
|
+
std::vector<Local<Value>> result;
|
|
65
|
+
Deserialize([&](ValueDeserializer& deserializer, Local<Context> context) {
|
|
66
|
+
// Read length
|
|
67
|
+
uint32_t length;
|
|
68
|
+
Unmaybe(deserializer.ReadHeader(context));
|
|
69
|
+
if (!deserializer.ReadUint32(&length)) {
|
|
70
|
+
throw RuntimeGenericError("Invalid arguments payload");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Read arguments
|
|
74
|
+
result.resize(length);
|
|
75
|
+
for (unsigned ii = 0; ii < length; ++ii) {
|
|
76
|
+
if (!deserializer.ReadValue(context).ToLocal(&result[ii])) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
});
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
} // namespace ivm
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include "external_copy.h"
|
|
3
|
+
#include "isolate/environment.h"
|
|
4
|
+
#include <deque>
|
|
5
|
+
#include <memory>
|
|
6
|
+
#include <vector>
|
|
7
|
+
|
|
8
|
+
namespace ivm {
|
|
9
|
+
namespace detail {
|
|
10
|
+
|
|
11
|
+
class SerializationDelegateBase {
|
|
12
|
+
public:
|
|
13
|
+
SerializationDelegateBase(
|
|
14
|
+
std::deque<std::unique_ptr<Transferable>>& transferables,
|
|
15
|
+
std::deque<v8::CompiledWasmModule>& wasm_modules
|
|
16
|
+
) : transferables{transferables}, wasm_modules{wasm_modules} {}
|
|
17
|
+
|
|
18
|
+
protected:
|
|
19
|
+
std::deque<std::unique_ptr<Transferable>>& transferables;
|
|
20
|
+
std::deque<v8::CompiledWasmModule>& wasm_modules;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
class SerializerDelegate : public SerializationDelegateBase, public v8::ValueSerializer::Delegate {
|
|
24
|
+
public:
|
|
25
|
+
using SerializationDelegateBase::SerializationDelegateBase;
|
|
26
|
+
|
|
27
|
+
void SetSerializer(v8::ValueSerializer* serializer) { this->serializer = serializer; }
|
|
28
|
+
void ThrowDataCloneError(v8::Local<v8::String> message) final;
|
|
29
|
+
|
|
30
|
+
auto GetSharedArrayBufferId(
|
|
31
|
+
v8::Isolate* isolate, v8::Local<v8::SharedArrayBuffer> shared_array_buffer) -> v8::Maybe<uint32_t> final;
|
|
32
|
+
auto GetWasmModuleTransferId(
|
|
33
|
+
v8::Isolate* isolate, v8::Local<v8::WasmModuleObject> module) -> v8::Maybe<uint32_t> final;
|
|
34
|
+
auto WriteHostObject(v8::Isolate* isolate, v8::Local<v8::Object> object) -> v8::Maybe<bool> final;
|
|
35
|
+
|
|
36
|
+
private:
|
|
37
|
+
v8::ValueSerializer* serializer = nullptr;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
class DeserializerDelegate : public SerializationDelegateBase, public v8::ValueDeserializer::Delegate {
|
|
41
|
+
public:
|
|
42
|
+
using SerializationDelegateBase::SerializationDelegateBase;
|
|
43
|
+
|
|
44
|
+
void SetDeserializer(v8::ValueDeserializer* deserializer) { this->deserializer = deserializer; }
|
|
45
|
+
|
|
46
|
+
auto GetSharedArrayBufferFromId(
|
|
47
|
+
v8::Isolate* isolate, uint32_t clone_id) -> v8::MaybeLocal<v8::SharedArrayBuffer> final;
|
|
48
|
+
auto GetWasmModuleFromId(
|
|
49
|
+
v8::Isolate* isolate, uint32_t transfer_id) -> v8::MaybeLocal<v8::WasmModuleObject> final;
|
|
50
|
+
auto ReadHostObject(v8::Isolate* isolate) -> v8::MaybeLocal<v8::Object> final;
|
|
51
|
+
|
|
52
|
+
private:
|
|
53
|
+
v8::ValueDeserializer* deserializer = nullptr;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
} // namespace detail
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Abstract serializer which manages boilerplate and lifecycle management of the serialized blob
|
|
60
|
+
*/
|
|
61
|
+
class BaseSerializer {
|
|
62
|
+
protected:
|
|
63
|
+
template <class Fn>
|
|
64
|
+
explicit BaseSerializer(Fn fn) {
|
|
65
|
+
// Initialize serializer and delegate
|
|
66
|
+
auto* isolate = v8::Isolate::GetCurrent();
|
|
67
|
+
auto context = isolate->GetCurrentContext();
|
|
68
|
+
detail::SerializerDelegate delegate{transferables, wasm_modules};
|
|
69
|
+
v8::ValueSerializer serializer{isolate, &delegate};
|
|
70
|
+
delegate.SetSerializer(&serializer);
|
|
71
|
+
|
|
72
|
+
// Run serialization
|
|
73
|
+
serializer.WriteHeader();
|
|
74
|
+
fn(serializer, context);
|
|
75
|
+
|
|
76
|
+
// Save to buffer
|
|
77
|
+
auto serialized_data = serializer.Release();
|
|
78
|
+
buffer = {serialized_data.first, std::free};
|
|
79
|
+
size = serialized_data.second;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
template <class Fn>
|
|
83
|
+
auto Deserialize(Fn fn) {
|
|
84
|
+
// Initialize deserializer and delegate
|
|
85
|
+
auto* isolate = v8::Isolate::GetCurrent();
|
|
86
|
+
auto context = isolate->GetCurrentContext();
|
|
87
|
+
detail::DeserializerDelegate delegate{transferables, wasm_modules};
|
|
88
|
+
v8::ValueDeserializer deserializer{isolate, buffer.get(), size, &delegate};
|
|
89
|
+
delegate.SetDeserializer(&deserializer);
|
|
90
|
+
|
|
91
|
+
// Watch for allocation errors
|
|
92
|
+
auto* allocator = IsolateEnvironment::GetCurrent().GetLimitedAllocator();
|
|
93
|
+
int failures = allocator == nullptr ? 0 : allocator->GetFailureCount();
|
|
94
|
+
Unmaybe(deserializer.ReadHeader(context));
|
|
95
|
+
|
|
96
|
+
// Run implementation
|
|
97
|
+
if (!fn(deserializer, context)) {
|
|
98
|
+
// ValueDeserializer throws an unhelpful message when it fails to allocate an ArrayBuffer, so
|
|
99
|
+
// detect that case here and throw an appropriate message.
|
|
100
|
+
if (allocator != nullptr && allocator->GetFailureCount() != failures) {
|
|
101
|
+
throw RuntimeRangeError("Array buffer allocation failed");
|
|
102
|
+
} else {
|
|
103
|
+
throw RuntimeError();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private:
|
|
109
|
+
std::unique_ptr<uint8_t, decltype(std::free)*> buffer = {nullptr, std::free};
|
|
110
|
+
std::deque<std::unique_ptr<Transferable>> transferables;
|
|
111
|
+
std::deque<v8::CompiledWasmModule> wasm_modules;
|
|
112
|
+
size_t size;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Single serialized value compatible with `Transferable`
|
|
117
|
+
*/
|
|
118
|
+
class ExternalCopySerialized : public BaseSerializer, public ExternalCopy {
|
|
119
|
+
public:
|
|
120
|
+
ExternalCopySerialized(v8::Local<v8::Value> value, ArrayRange transfer_list);
|
|
121
|
+
auto CopyInto(bool transfer_in = false) -> v8::Local<v8::Value> final;
|
|
122
|
+
|
|
123
|
+
private:
|
|
124
|
+
std::vector<std::unique_ptr<ExternalCopyArrayBuffer>> array_buffers;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
class SerializedVector : public BaseSerializer {
|
|
128
|
+
public:
|
|
129
|
+
explicit SerializedVector(const v8::FunctionCallbackInfo<v8::Value>& info);
|
|
130
|
+
auto CopyIntoAsVector() -> std::vector<v8::Local<v8::Value>>;
|
|
131
|
+
|
|
132
|
+
private:
|
|
133
|
+
std::vector<std::unique_ptr<ExternalCopyArrayBuffer>> array_buffers;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
} // namespace ivm
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#include "serializer.h"
|
|
2
|
+
#include "isolate/functor_runners.h"
|
|
3
|
+
#include "module/transferable.h"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* This file is compiled *without* runtime type information, which matches the nodejs binary and
|
|
7
|
+
* allows the serializer delegates to resolve correctly.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
using namespace v8;
|
|
11
|
+
|
|
12
|
+
namespace ivm::detail {
|
|
13
|
+
|
|
14
|
+
void SerializerDelegate::ThrowDataCloneError(Local<String> message) {
|
|
15
|
+
Isolate::GetCurrent()->ThrowException(Exception::TypeError(message));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
auto SerializerDelegate::GetSharedArrayBufferId(
|
|
19
|
+
Isolate* /*isolate*/, Local<SharedArrayBuffer> shared_array_buffer) -> Maybe<uint32_t> {
|
|
20
|
+
auto result = Nothing<uint32_t>();
|
|
21
|
+
detail::RunBarrier([&]() {
|
|
22
|
+
transferables.emplace_back(std::make_unique<ExternalCopySharedArrayBuffer>(shared_array_buffer));
|
|
23
|
+
result = Just<uint32_t>(transferables.size() - 1);
|
|
24
|
+
});
|
|
25
|
+
return result;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
auto SerializerDelegate::GetWasmModuleTransferId(
|
|
29
|
+
Isolate* /*isolate*/, Local<WasmModuleObject> module) -> Maybe<uint32_t> {
|
|
30
|
+
auto result = Just<uint32_t>(wasm_modules.size());
|
|
31
|
+
wasm_modules.emplace_back(module->GetCompiledModule());
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
auto SerializerDelegate::WriteHostObject(Isolate* /*isolate*/, Local<Object> object) -> Maybe<bool> {
|
|
36
|
+
auto result = Nothing<bool>();
|
|
37
|
+
detail::RunBarrier([&]() {
|
|
38
|
+
serializer->WriteUint32(transferables.size());
|
|
39
|
+
transferables.emplace_back(TransferOut(object));
|
|
40
|
+
result = Just(true);
|
|
41
|
+
});
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
auto DeserializerDelegate::ReadHostObject(Isolate* /*isolate*/) -> MaybeLocal<Object> {
|
|
46
|
+
MaybeLocal<Object> result;
|
|
47
|
+
detail::RunBarrier([&]() {
|
|
48
|
+
uint32_t ii;
|
|
49
|
+
assert(deserializer->ReadUint32(&ii));
|
|
50
|
+
result = transferables[ii]->TransferIn().As<Object>();
|
|
51
|
+
});
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
auto DeserializerDelegate::GetSharedArrayBufferFromId(
|
|
56
|
+
Isolate* /*isolate*/, uint32_t clone_id) -> MaybeLocal<SharedArrayBuffer> {
|
|
57
|
+
MaybeLocal<SharedArrayBuffer> result;
|
|
58
|
+
detail::RunBarrier([&]() {
|
|
59
|
+
result = transferables[clone_id]->TransferIn().As<SharedArrayBuffer>();
|
|
60
|
+
});
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
auto DeserializerDelegate::GetWasmModuleFromId(
|
|
65
|
+
Isolate* isolate, uint32_t transfer_id) -> MaybeLocal<WasmModuleObject> {
|
|
66
|
+
MaybeLocal<WasmModuleObject> result;
|
|
67
|
+
detail::RunBarrier([&]() {
|
|
68
|
+
result = WasmModuleObject::FromCompiledModule(isolate, wasm_modules[transfer_id]);
|
|
69
|
+
});
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
} // namespace ivm::detail
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
#include "isolate/environment.h"
|
|
2
|
+
#include "./string.h"
|
|
3
|
+
#include <cstring>
|
|
4
|
+
|
|
5
|
+
using namespace v8;
|
|
6
|
+
|
|
7
|
+
namespace ivm {
|
|
8
|
+
namespace {
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Helper classes passed to v8 so we can reuse the same externally allocated memory for strings
|
|
12
|
+
* between different isolates
|
|
13
|
+
*/
|
|
14
|
+
class ExternalString final : public v8::String::ExternalStringResource {
|
|
15
|
+
public:
|
|
16
|
+
explicit ExternalString(std::shared_ptr<std::vector<char>> value) : value{std::move(value)} {
|
|
17
|
+
IsolateEnvironment::GetCurrent().AdjustExtraAllocatedMemory(this->value->size());
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
ExternalString(const ExternalString&) = delete;
|
|
21
|
+
|
|
22
|
+
~ExternalString() final {
|
|
23
|
+
auto* environment = Executor::GetCurrentEnvironment();
|
|
24
|
+
if (environment != nullptr) {
|
|
25
|
+
environment->AdjustExtraAllocatedMemory(-static_cast<int>(this->value->size()));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
auto operator= (const ExternalString&) = delete;
|
|
30
|
+
|
|
31
|
+
auto data() const -> const uint16_t* final {
|
|
32
|
+
return reinterpret_cast<uint16_t*>(value->data());
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
auto length() const -> size_t final {
|
|
36
|
+
return value->size() >> 1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private:
|
|
40
|
+
std::shared_ptr<std::vector<char>> value;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
class ExternalStringOneByte final : public v8::String::ExternalOneByteStringResource {
|
|
44
|
+
public:
|
|
45
|
+
explicit ExternalStringOneByte(std::shared_ptr<std::vector<char>> value) : value{std::move(value)} {
|
|
46
|
+
IsolateEnvironment::GetCurrent().AdjustExtraAllocatedMemory(this->value->size());
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
ExternalStringOneByte(const ExternalStringOneByte&) = delete;
|
|
50
|
+
|
|
51
|
+
~ExternalStringOneByte() final {
|
|
52
|
+
auto* environment = Executor::GetCurrentEnvironment();
|
|
53
|
+
if (environment != nullptr) {
|
|
54
|
+
environment->AdjustExtraAllocatedMemory(-static_cast<int>(this->value->size()));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
auto operator= (const ExternalStringOneByte&) = delete;
|
|
59
|
+
|
|
60
|
+
auto data() const -> const char* final {
|
|
61
|
+
return value->data();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
auto length() const -> size_t final {
|
|
65
|
+
return value->size();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private:
|
|
69
|
+
std::shared_ptr<std::vector<char>> value;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
} // anonymous namespace
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* ExternalCopyString implementation
|
|
76
|
+
*/
|
|
77
|
+
ExternalCopyString::ExternalCopyString(Local<String> string) :
|
|
78
|
+
ExternalCopy{static_cast<int>((string->Length() << (string->IsOneByte() ? 0 : 1)) + sizeof(ExternalCopyString))} {
|
|
79
|
+
if (string->IsOneByte()) {
|
|
80
|
+
one_byte = true;
|
|
81
|
+
value = std::make_shared<std::vector<char>>(string->Length());
|
|
82
|
+
string->WriteOneByte(
|
|
83
|
+
Isolate::GetCurrent(),
|
|
84
|
+
reinterpret_cast<uint8_t*>(value->data()), 0, -1, String::WriteOptions::NO_NULL_TERMINATION
|
|
85
|
+
);
|
|
86
|
+
} else {
|
|
87
|
+
one_byte = false;
|
|
88
|
+
value = std::make_shared<std::vector<char>>(string->Length() << 1);
|
|
89
|
+
string->Write(
|
|
90
|
+
Isolate::GetCurrent(),
|
|
91
|
+
reinterpret_cast<uint16_t*>(value->data()), 0, -1, String::WriteOptions::NO_NULL_TERMINATION
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
ExternalCopyString::ExternalCopyString(const char* string) :
|
|
97
|
+
value{std::make_shared<std::vector<char>>(string, string + strlen(string))}, one_byte{true} {}
|
|
98
|
+
|
|
99
|
+
ExternalCopyString::ExternalCopyString(const std::string& string) :
|
|
100
|
+
value{std::make_shared<std::vector<char>>(string.begin(), string.end())}, one_byte{true} {}
|
|
101
|
+
|
|
102
|
+
auto ExternalCopyString::CopyInto(bool /*transfer_in*/) -> Local<Value> {
|
|
103
|
+
if (value->size() < 1024) {
|
|
104
|
+
// Strings under 1kb will be internal v8 strings. I didn't experiment with this at all, but it
|
|
105
|
+
// seems self-evident that there's some byte length under which it doesn't make sense to create
|
|
106
|
+
// an external string so I picked 1kb.
|
|
107
|
+
if (one_byte) {
|
|
108
|
+
return Unmaybe(String::NewFromOneByte(Isolate::GetCurrent(),
|
|
109
|
+
reinterpret_cast<uint8_t*>(value->data()), NewStringType::kNormal, value->size()));
|
|
110
|
+
} else {
|
|
111
|
+
return Unmaybe(String::NewFromTwoByte(Isolate::GetCurrent(),
|
|
112
|
+
reinterpret_cast<uint16_t*>(value->data()), NewStringType::kNormal, value->size() >> 1));
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
// External strings can save memory and/or copies
|
|
116
|
+
if (one_byte) {
|
|
117
|
+
return Unmaybe(String::NewExternalOneByte(Isolate::GetCurrent(), new ExternalStringOneByte(value)));
|
|
118
|
+
} else {
|
|
119
|
+
return Unmaybe(String::NewExternalTwoByte(Isolate::GetCurrent(), new ExternalString(value)));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
} // namespace ivm
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include "external_copy.h"
|
|
3
|
+
#include <memory>
|
|
4
|
+
#include <vector>
|
|
5
|
+
|
|
6
|
+
namespace ivm {
|
|
7
|
+
|
|
8
|
+
class ExternalCopyString final : public ExternalCopy {
|
|
9
|
+
public:
|
|
10
|
+
ExternalCopyString() = default;
|
|
11
|
+
explicit ExternalCopyString(v8::Local<v8::String> string);
|
|
12
|
+
explicit ExternalCopyString(const char* string);
|
|
13
|
+
explicit ExternalCopyString(const std::string& string);
|
|
14
|
+
ExternalCopyString(const ExternalCopyString&) = delete;
|
|
15
|
+
ExternalCopyString(ExternalCopyString&& that) = default;
|
|
16
|
+
~ExternalCopyString() final = default;
|
|
17
|
+
auto operator= (const ExternalCopyString&) -> ExternalCopyString& = delete;
|
|
18
|
+
auto operator= (ExternalCopyString&& that) noexcept -> ExternalCopyString& = default;
|
|
19
|
+
|
|
20
|
+
explicit operator bool() const { return static_cast<bool>(value); }
|
|
21
|
+
auto CopyInto(bool transfer_in = false) -> v8::Local<v8::Value> final;
|
|
22
|
+
|
|
23
|
+
private:
|
|
24
|
+
std::shared_ptr<std::vector<char>> value;
|
|
25
|
+
bool one_byte = false;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
} // namespace ivm
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#include <v8.h>
|
|
3
|
+
#include <memory>
|
|
4
|
+
#include "v8_version.h"
|
|
5
|
+
|
|
6
|
+
namespace ivm {
|
|
7
|
+
|
|
8
|
+
class LimitedAllocator : public v8::ArrayBuffer::Allocator {
|
|
9
|
+
private:
|
|
10
|
+
class IsolateEnvironment& env;
|
|
11
|
+
size_t limit;
|
|
12
|
+
size_t v8_heap;
|
|
13
|
+
size_t next_check;
|
|
14
|
+
int failures = 0;
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
public:
|
|
18
|
+
auto Check(size_t length) -> bool;
|
|
19
|
+
explicit LimitedAllocator(class IsolateEnvironment& env, size_t limit);
|
|
20
|
+
auto Allocate(size_t length) -> void* final;
|
|
21
|
+
auto AllocateUninitialized(size_t length) -> void* final;
|
|
22
|
+
void Free(void* data, size_t length) final;
|
|
23
|
+
auto Reallocate(void* data, size_t old_length, size_t new_length) -> void* final;
|
|
24
|
+
|
|
25
|
+
// This is used by ExternalCopy when an ArrayBuffer is transferred. The memory is not freed but
|
|
26
|
+
// we should no longer count it against the isolate
|
|
27
|
+
void AdjustAllocatedSize(ptrdiff_t length);
|
|
28
|
+
auto GetFailureCount() const -> int;
|
|
29
|
+
void Track(v8::Local<v8::Object> handle, size_t size);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
} // namespace ivm
|