@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.
Files changed (107) hide show
  1. package/dist/externalVersion.js +4 -4
  2. package/dist/node_modules/isolated-vm/.clang-tidy +13 -0
  3. package/dist/node_modules/isolated-vm/.dockerignore +9 -0
  4. package/dist/node_modules/isolated-vm/Dockerfile.alpine +9 -0
  5. package/dist/node_modules/isolated-vm/Dockerfile.debian +12 -0
  6. package/dist/node_modules/isolated-vm/LICENSE +13 -0
  7. package/dist/node_modules/isolated-vm/binding.gyp +120 -0
  8. package/dist/node_modules/isolated-vm/include.js +3 -0
  9. package/dist/node_modules/isolated-vm/inspector-example.js +59 -0
  10. package/dist/node_modules/isolated-vm/isolated-vm.d.ts +820 -0
  11. package/dist/node_modules/isolated-vm/isolated-vm.js +1 -0
  12. package/dist/node_modules/isolated-vm/native-example/binding.gyp +23 -0
  13. package/dist/node_modules/isolated-vm/native-example/example.cc +61 -0
  14. package/dist/node_modules/isolated-vm/native-example/package.json +13 -0
  15. package/dist/node_modules/isolated-vm/native-example/usage.js +35 -0
  16. package/dist/node_modules/isolated-vm/out/isolated_vm.node +0 -0
  17. package/dist/node_modules/isolated-vm/package.json +1 -0
  18. package/dist/node_modules/isolated-vm/src/external_copy/error.h +33 -0
  19. package/dist/node_modules/isolated-vm/src/external_copy/external_copy.cc +509 -0
  20. package/dist/node_modules/isolated-vm/src/external_copy/external_copy.h +117 -0
  21. package/dist/node_modules/isolated-vm/src/external_copy/serializer.cc +85 -0
  22. package/dist/node_modules/isolated-vm/src/external_copy/serializer.h +136 -0
  23. package/dist/node_modules/isolated-vm/src/external_copy/serializer_nortti.cc +73 -0
  24. package/dist/node_modules/isolated-vm/src/external_copy/string.cc +124 -0
  25. package/dist/node_modules/isolated-vm/src/external_copy/string.h +28 -0
  26. package/dist/node_modules/isolated-vm/src/isolate/allocator.h +32 -0
  27. package/dist/node_modules/isolated-vm/src/isolate/allocator_nortti.cc +142 -0
  28. package/dist/node_modules/isolated-vm/src/isolate/class_handle.h +334 -0
  29. package/dist/node_modules/isolated-vm/src/isolate/cpu_profile_manager.cc +220 -0
  30. package/dist/node_modules/isolated-vm/src/isolate/cpu_profile_manager.h +100 -0
  31. package/dist/node_modules/isolated-vm/src/isolate/environment.cc +626 -0
  32. package/dist/node_modules/isolated-vm/src/isolate/environment.h +381 -0
  33. package/dist/node_modules/isolated-vm/src/isolate/executor.cc +198 -0
  34. package/dist/node_modules/isolated-vm/src/isolate/executor.h +183 -0
  35. package/dist/node_modules/isolated-vm/src/isolate/external.h +64 -0
  36. package/dist/node_modules/isolated-vm/src/isolate/functor_runners.h +97 -0
  37. package/dist/node_modules/isolated-vm/src/isolate/generic/array.h +145 -0
  38. package/dist/node_modules/isolated-vm/src/isolate/generic/callbacks.h +272 -0
  39. package/dist/node_modules/isolated-vm/src/isolate/generic/error.h +140 -0
  40. package/dist/node_modules/isolated-vm/src/isolate/generic/extract_params.h +145 -0
  41. package/dist/node_modules/isolated-vm/src/isolate/generic/handle_cast.h +257 -0
  42. package/dist/node_modules/isolated-vm/src/isolate/generic/read_option.h +47 -0
  43. package/dist/node_modules/isolated-vm/src/isolate/holder.cc +88 -0
  44. package/dist/node_modules/isolated-vm/src/isolate/holder.h +63 -0
  45. package/dist/node_modules/isolated-vm/src/isolate/inspector.cc +200 -0
  46. package/dist/node_modules/isolated-vm/src/isolate/inspector.h +70 -0
  47. package/dist/node_modules/isolated-vm/src/isolate/node_wrapper.h +15 -0
  48. package/dist/node_modules/isolated-vm/src/isolate/platform_delegate.cc +22 -0
  49. package/dist/node_modules/isolated-vm/src/isolate/platform_delegate.h +46 -0
  50. package/dist/node_modules/isolated-vm/src/isolate/remote_handle.h +164 -0
  51. package/dist/node_modules/isolated-vm/src/isolate/run_with_timeout.h +171 -0
  52. package/dist/node_modules/isolated-vm/src/isolate/runnable.h +29 -0
  53. package/dist/node_modules/isolated-vm/src/isolate/scheduler.cc +191 -0
  54. package/dist/node_modules/isolated-vm/src/isolate/scheduler.h +165 -0
  55. package/dist/node_modules/isolated-vm/src/isolate/specific.h +35 -0
  56. package/dist/node_modules/isolated-vm/src/isolate/stack_trace.cc +219 -0
  57. package/dist/node_modules/isolated-vm/src/isolate/stack_trace.h +24 -0
  58. package/dist/node_modules/isolated-vm/src/isolate/strings.h +127 -0
  59. package/dist/node_modules/isolated-vm/src/isolate/three_phase_task.cc +385 -0
  60. package/dist/node_modules/isolated-vm/src/isolate/three_phase_task.h +136 -0
  61. package/dist/node_modules/isolated-vm/src/isolate/transferable.h +15 -0
  62. package/dist/node_modules/isolated-vm/src/isolate/util.h +45 -0
  63. package/dist/node_modules/isolated-vm/src/isolate/v8_inspector_wrapper.h +12 -0
  64. package/dist/node_modules/isolated-vm/src/isolate/v8_version.h +12 -0
  65. package/dist/node_modules/isolated-vm/src/isolated_vm.h +71 -0
  66. package/dist/node_modules/isolated-vm/src/lib/covariant.h +50 -0
  67. package/dist/node_modules/isolated-vm/src/lib/lockable.h +178 -0
  68. package/dist/node_modules/isolated-vm/src/lib/suspend.h +106 -0
  69. package/dist/node_modules/isolated-vm/src/lib/thread_pool.cc +98 -0
  70. package/dist/node_modules/isolated-vm/src/lib/thread_pool.h +45 -0
  71. package/dist/node_modules/isolated-vm/src/lib/timer.cc +233 -0
  72. package/dist/node_modules/isolated-vm/src/lib/timer.h +36 -0
  73. package/dist/node_modules/isolated-vm/src/module/callback.cc +151 -0
  74. package/dist/node_modules/isolated-vm/src/module/callback.h +64 -0
  75. package/dist/node_modules/isolated-vm/src/module/context_handle.cc +241 -0
  76. package/dist/node_modules/isolated-vm/src/module/context_handle.h +35 -0
  77. package/dist/node_modules/isolated-vm/src/module/evaluation.cc +109 -0
  78. package/dist/node_modules/isolated-vm/src/module/evaluation.h +99 -0
  79. package/dist/node_modules/isolated-vm/src/module/external_copy_handle.cc +119 -0
  80. package/dist/node_modules/isolated-vm/src/module/external_copy_handle.h +64 -0
  81. package/dist/node_modules/isolated-vm/src/module/isolate.cc +136 -0
  82. package/dist/node_modules/isolated-vm/src/module/isolate_handle.cc +611 -0
  83. package/dist/node_modules/isolated-vm/src/module/isolate_handle.h +47 -0
  84. package/dist/node_modules/isolated-vm/src/module/lib_handle.cc +77 -0
  85. package/dist/node_modules/isolated-vm/src/module/lib_handle.h +28 -0
  86. package/dist/node_modules/isolated-vm/src/module/module_handle.cc +475 -0
  87. package/dist/node_modules/isolated-vm/src/module/module_handle.h +68 -0
  88. package/dist/node_modules/isolated-vm/src/module/native_module_handle.cc +104 -0
  89. package/dist/node_modules/isolated-vm/src/module/native_module_handle.h +49 -0
  90. package/dist/node_modules/isolated-vm/src/module/reference_handle.cc +636 -0
  91. package/dist/node_modules/isolated-vm/src/module/reference_handle.h +106 -0
  92. package/dist/node_modules/isolated-vm/src/module/script_handle.cc +107 -0
  93. package/dist/node_modules/isolated-vm/src/module/script_handle.h +37 -0
  94. package/dist/node_modules/isolated-vm/src/module/session_handle.cc +173 -0
  95. package/dist/node_modules/isolated-vm/src/module/session_handle.h +31 -0
  96. package/dist/node_modules/isolated-vm/src/module/transferable.cc +268 -0
  97. package/dist/node_modules/isolated-vm/src/module/transferable.h +42 -0
  98. package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v18.0.0.h +360 -0
  99. package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v18.3.0.h +376 -0
  100. package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v20.0.0.h +397 -0
  101. package/dist/node_modules/isolated-vm/vendor/v8_inspector/nodejs_v22.0.0.h +419 -0
  102. package/dist/node_modules/winston-transport/package.json +1 -1
  103. package/dist/server/IsolatedVm.js +75 -0
  104. package/dist/server/ScriptInstruction.d.ts +6 -0
  105. package/dist/server/ScriptInstruction.js +11 -1
  106. package/dist/server/Vm.js +42 -27
  107. package/package.json +3 -2
@@ -0,0 +1,142 @@
1
+ #include "allocator.h"
2
+ #include "environment.h"
3
+ #include <cstdlib>
4
+
5
+ using namespace v8;
6
+
7
+ namespace ivm {
8
+ namespace {
9
+
10
+ class ExternalMemoryHandle {
11
+ public:
12
+ ExternalMemoryHandle(Local<Object> local_handle, size_t size) :
13
+ handle{Isolate::GetCurrent(), local_handle}, size{size} {
14
+ handle.SetWeak(reinterpret_cast<void*>(this), &WeakCallbackV8, WeakCallbackType::kParameter);
15
+ IsolateEnvironment::GetCurrent().AddWeakCallback(&handle, WeakCallback, this);
16
+ }
17
+
18
+ ExternalMemoryHandle(const ExternalMemoryHandle&) = delete;
19
+ auto operator=(const ExternalMemoryHandle&) = delete;
20
+
21
+ ~ExternalMemoryHandle() {
22
+ auto* allocator = IsolateEnvironment::GetCurrent().GetLimitedAllocator();
23
+ if (allocator != nullptr) {
24
+ allocator->AdjustAllocatedSize(-static_cast<ptrdiff_t>(size));
25
+ }
26
+ };
27
+
28
+ private:
29
+ static void WeakCallbackV8(const WeakCallbackInfo<void>& info) {
30
+ WeakCallback(info.GetParameter());
31
+ }
32
+
33
+ static void WeakCallback(void* param) {
34
+ auto* that = reinterpret_cast<ExternalMemoryHandle*>(param);
35
+ IsolateEnvironment::GetCurrent().RemoveWeakCallback(&that->handle);
36
+ that->handle.Reset();
37
+ delete that;
38
+ }
39
+
40
+ v8::Persistent<v8::Value> handle;
41
+ size_t size;
42
+ };
43
+
44
+ } // anonymous namespace
45
+
46
+ /**
47
+ * ArrayBuffer::Allocator that enforces memory limits. The v8 documentation specifically says
48
+ * that it's unsafe to call back into v8 from this class but I took a look at
49
+ * GetHeapStatistics() and I think it'll be ok.
50
+ */
51
+ auto LimitedAllocator::Check(const size_t length) -> bool {
52
+ if (v8_heap + env.extra_allocated_memory + length > next_check) {
53
+ HeapStatistics heap_statistics;
54
+ Isolate* isolate = Isolate::GetCurrent();
55
+ isolate->GetHeapStatistics(&heap_statistics);
56
+ v8_heap = heap_statistics.used_heap_size();
57
+ if (v8_heap + env.extra_allocated_memory + length > limit + env.misc_memory_size) {
58
+ // This is might be dangerous but the tests pass soooo..
59
+ isolate->LowMemoryNotification();
60
+ isolate->GetHeapStatistics(&heap_statistics);
61
+ v8_heap = heap_statistics.used_heap_size();
62
+ if (v8_heap + env.extra_allocated_memory + length > limit + env.misc_memory_size) {
63
+ return false;
64
+ }
65
+ }
66
+ next_check = v8_heap + env.extra_allocated_memory + length + 1024 * 1024;
67
+ }
68
+ return v8_heap + env.extra_allocated_memory + length <= limit + env.misc_memory_size;
69
+ }
70
+
71
+ LimitedAllocator::LimitedAllocator(IsolateEnvironment& env, size_t limit) : env(env), limit(limit), v8_heap(1024 * 1024 * 4), next_check(1024 * 1024) {}
72
+
73
+ auto LimitedAllocator::Allocate(size_t length) -> void* {
74
+ if (Check(length)) {
75
+ env.extra_allocated_memory += length;
76
+ return std::calloc(length, 1);
77
+ } else {
78
+ ++failures;
79
+ if (length <= 64) { // kMinAddedElementsCapacity * sizeof(uint32_t)
80
+ // When a tiny TypedArray is created v8 will avoid calling the allocator and instead just use
81
+ // the internal heap. This is all fine until someone wants a pointer to the underlying buffer,
82
+ // in that case v8 will "materialize" an ArrayBuffer which does invoke this allocator. If the
83
+ // allocator refuses to return a valid pointer it will result in a hard crash so we have no
84
+ // choice but to let this allocation succeed. Luckily the amount of memory allocated is tiny
85
+ // and will soon be freed because at the same time we terminate the isolate.
86
+ env.extra_allocated_memory += length;
87
+ env.Terminate();
88
+ return std::calloc(length, 1);
89
+ } else {
90
+ // The places end up here are more graceful and will throw a RangeError
91
+ return nullptr;
92
+ }
93
+ }
94
+ }
95
+
96
+ auto LimitedAllocator::AllocateUninitialized(size_t length) -> void* {
97
+ if (Check(length)) {
98
+ env.extra_allocated_memory += length;
99
+ return std::malloc(length);
100
+ } else {
101
+ ++failures;
102
+ if (length <= 64) {
103
+ env.extra_allocated_memory += length;
104
+ env.Terminate();
105
+ return std::malloc(length);
106
+ } else {
107
+ return nullptr;
108
+ }
109
+ }
110
+ }
111
+
112
+ void LimitedAllocator::Free(void* data, size_t length) {
113
+ env.extra_allocated_memory -= length;
114
+ next_check -= length;
115
+ std::free(data);
116
+ }
117
+
118
+ auto LimitedAllocator::Reallocate(void* data, size_t old_length, size_t new_length) -> void* {
119
+ auto delta = static_cast<ssize_t>(new_length) - static_cast<ssize_t>(old_length);
120
+ if (delta > 0) {
121
+ if (!Check(delta)) {
122
+ return nullptr;
123
+ }
124
+ }
125
+ env.extra_allocated_memory += delta;
126
+ return ArrayBuffer::Allocator::Reallocate(data, old_length, new_length);
127
+ }
128
+
129
+ void LimitedAllocator::AdjustAllocatedSize(ptrdiff_t length) {
130
+ env.extra_allocated_memory += length;
131
+ }
132
+
133
+ auto LimitedAllocator::GetFailureCount() const -> int {
134
+ return failures;
135
+ }
136
+
137
+ void LimitedAllocator::Track(Local<Object> handle, size_t size) {
138
+ new ExternalMemoryHandle{handle, size};
139
+ AdjustAllocatedSize(size);
140
+ }
141
+
142
+ } // namespace ivm
@@ -0,0 +1,334 @@
1
+ #pragma once
2
+ #include <v8.h>
3
+ #include "environment.h"
4
+ #include "functor_runners.h"
5
+ #include "util.h"
6
+ #include "generic/callbacks.h"
7
+ #include "generic/extract_params.h"
8
+ #include "generic/handle_cast.h"
9
+ #include "generic/read_option.h"
10
+ #include "v8-function-callback.h"
11
+
12
+ #include <cassert>
13
+ #include <cstddef>
14
+ #include <type_traits>
15
+ #include <stdexcept>
16
+
17
+ namespace ivm {
18
+
19
+ namespace detail {
20
+ struct ConstructorFunctionHolder : detail::FreeFunctionHolder {
21
+ using FreeFunctionHolder::FreeFunctionHolder;
22
+ };
23
+
24
+ template <class Signature>
25
+ struct ConstructorFunctionImpl;
26
+
27
+ template <class Type>
28
+ struct TemplateHolder {
29
+ static IsolateSpecific<v8::FunctionTemplate> specific;
30
+ };
31
+
32
+ template <class Type>
33
+ IsolateSpecific<v8::FunctionTemplate> TemplateHolder<Type>::specific;
34
+
35
+ template <class Type, class = void>
36
+ struct DontFreezePrototype : std::false_type{};
37
+
38
+ template <class Type>
39
+ struct DontFreezePrototype<Type, typename Type::DontFreezePrototype> : std::true_type {};
40
+
41
+ template <class Type, class = void>
42
+ struct DontFreezeInstance : std::false_type{};
43
+
44
+ template <class Type>
45
+ struct DontFreezeInstance<Type, typename Type::DontFreezeInstance> : std::true_type {};
46
+
47
+ }
48
+
49
+ /**
50
+ * Analogous to node::ObjectWrap but Isolate-aware. Also has a bunch of unnecessary template stuff.
51
+ */
52
+ class ClassHandle {
53
+ template <class Signature>
54
+ friend struct detail::ConstructorFunctionImpl;
55
+ private:
56
+ v8::Persistent<v8::Value> handle;
57
+
58
+ /**
59
+ * Utility methods to set up object prototype
60
+ */
61
+ struct TemplateDefinition {
62
+ v8::Isolate* isolate;
63
+ v8::Local<v8::FunctionTemplate>& tmpl;
64
+ v8::Local<v8::ObjectTemplate>& proto;
65
+ v8::Local<v8::Signature>& sig;
66
+
67
+ // This add regular methods
68
+ template <typename... Args>
69
+ void Add(const char* name, detail::MemberFunctionHolder impl, Args... args) {
70
+ v8::Local<v8::String> name_handle = v8_symbol(name);
71
+ proto->Set(name_handle, v8::FunctionTemplate::New(isolate, impl.callback, {}, sig, impl.length));
72
+ Add(args...);
73
+ }
74
+
75
+ // This adds function templates to the prototype
76
+ template <typename... Args>
77
+ void Add(const char* name, v8::Local<v8::FunctionTemplate>& value, Args... args) {
78
+ v8::Local<v8::String> name_handle = v8_symbol(name);
79
+ proto->Set(name_handle, value);
80
+ Add(args...);
81
+ }
82
+
83
+ // This adds static functions on the object constructor
84
+ template <typename... Args>
85
+ void Add(const char* name, detail::FreeFunctionHolder impl, Args... args) {
86
+ v8::Local<v8::String> name_handle = v8_symbol(name);
87
+ tmpl->Set(name_handle, v8::FunctionTemplate::New(isolate, impl.callback, {}, v8::Local<v8::Signature>(), impl.length));
88
+ Add(args...);
89
+ }
90
+
91
+ // This adds accessors
92
+ template <typename... Args>
93
+ void Add(const char* name, detail::MemberAccessorHolder impl, Args... args) {
94
+ v8::Local<v8::String> name_handle = v8_symbol(name);
95
+ proto->SetAccessor(name_handle, impl.getter.callback, impl.setter.callback);
96
+ Add(args...);
97
+ }
98
+
99
+ // This adds static accessors
100
+ template <typename... Args>
101
+ void Add(const char* name, detail::StaticAccessorHolder impl, Args... args) {
102
+ v8::Local<v8::String> name_handle = v8_symbol(name);
103
+ v8::Local<v8::FunctionTemplate> setter;
104
+ if (impl.setter.callback != nullptr) {
105
+ setter = v8::FunctionTemplate::New(isolate, impl.setter.callback, name_handle);
106
+ }
107
+ tmpl->SetAccessorProperty(name_handle, v8::FunctionTemplate::New(isolate, impl.getter.callback, {}), setter);
108
+ Add(args...);
109
+ }
110
+
111
+ void Add() {} // NOLINT
112
+ };
113
+
114
+ /**
115
+ * Convenience wrapper for the obtuse SetWeak function signature. When the callback is called
116
+ * the handle will already be gone.
117
+ */
118
+ template <typename P, void (*F)(P*)>
119
+ void SetWeak(P* param) {
120
+ auto& isolate = IsolateEnvironment::GetCurrent();
121
+ isolate.AddWeakCallback(&this->handle, (void(*)(void*))F, param);
122
+ handle.SetWeak(param, WeakCallback<P, F>, v8::WeakCallbackType::kParameter);
123
+ }
124
+ template <typename P, void (*F)(P*)>
125
+ static void WeakCallback(const v8::WeakCallbackInfo<P>& info) {
126
+ F(info.GetParameter());
127
+ }
128
+
129
+ /**
130
+ * Invoked once JS loses all references to this object
131
+ */
132
+ static void WeakCallback(void* param) {
133
+ auto& isolate = IsolateEnvironment::GetCurrent();
134
+ auto* that = reinterpret_cast<ClassHandle*>(param);
135
+ isolate.RemoveWeakCallback(&that->handle);
136
+ delete that; // NOLINT
137
+ }
138
+
139
+ /**
140
+ * Transfer ownership of this C++ pointer to the v8 handle lifetime.
141
+ */
142
+ static void Wrap(std::unique_ptr<ClassHandle> ptr, v8::Local<v8::Object> handle) {
143
+ handle->SetAlignedPointerInInternalField(0, ptr.get());
144
+ ptr->handle.Reset(v8::Isolate::GetCurrent(), handle);
145
+ ClassHandle* ptr_raw = ptr.release();
146
+ ptr_raw->SetWeak<void, WeakCallback>(ptr_raw);
147
+ }
148
+
149
+ /**
150
+ * It just throws when you call it; used when `nullptr` is passed as constructor
151
+ */
152
+ static void PrivateConstructor(const v8::FunctionCallbackInfo<v8::Value>& info) {
153
+ throw RuntimeTypeError(detail::CalleeName(info)+ " constructor is private");
154
+ }
155
+
156
+ protected:
157
+ /**
158
+ * Sets up this object's FunctionTemplate inside the current isolate
159
+ */
160
+ template <typename... Args>
161
+ static auto MakeClass(const char* class_name, detail::ConstructorFunctionHolder New, Args... args) -> v8::Local<v8::FunctionTemplate> {
162
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
163
+ v8::Local<v8::String> name_handle = v8_symbol(class_name);
164
+ v8::Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(
165
+ isolate, New.callback == nullptr ? PrivateConstructor : New.callback,
166
+ name_handle, {}, New.length
167
+ );
168
+ tmpl->SetClassName(name_handle);
169
+
170
+ auto instance_tmpl = tmpl->InstanceTemplate();
171
+ instance_tmpl->SetImmutableProto();
172
+ instance_tmpl->SetInternalFieldCount(1);
173
+
174
+ auto proto = tmpl->PrototypeTemplate();
175
+ proto->SetImmutableProto();
176
+ v8::Local<v8::Signature> sig = v8::Signature::New(isolate, tmpl);
177
+ TemplateDefinition def{isolate, tmpl, proto, sig};
178
+ def.Add(args...);
179
+
180
+ return tmpl;
181
+ }
182
+
183
+ /**
184
+ * Inherit from another class's FunctionTemplate
185
+ */
186
+ template <typename T>
187
+ static auto Inherit(v8::Local<v8::FunctionTemplate> definition) -> v8::Local<v8::FunctionTemplate> {
188
+ v8::Local<v8::FunctionTemplate> parent = GetFunctionTemplate<T>();
189
+ definition->Inherit(parent);
190
+ return definition;
191
+ }
192
+
193
+ public:
194
+ ClassHandle() = default;
195
+ ClassHandle(const ClassHandle&) = delete;
196
+ auto operator= (const ClassHandle&) -> ClassHandle& = delete;
197
+ virtual ~ClassHandle() {
198
+ if (!handle.IsEmpty()) {
199
+ handle.ClearWeak();
200
+ handle.Reset();
201
+ }
202
+ }
203
+
204
+ /**
205
+ * Returns instance of this class for this context.
206
+ */
207
+ template <typename T>
208
+ static auto Init() -> v8::Local<v8::Function> {
209
+ return GetFunctionTemplate<T>()->GetFunction();
210
+ }
211
+
212
+ /**
213
+ * Returns the FunctionTemplate for this isolate, generating it if needed.
214
+ */
215
+ template <class Type>
216
+ static auto GetFunctionTemplate() -> v8::Local<v8::FunctionTemplate> {
217
+ return detail::TemplateHolder<Type>::specific.Deref([&]() {
218
+ return Type::Definition();
219
+ });
220
+ }
221
+
222
+ /**
223
+ * Freeze the handle and prototype unless `DontFreezeInstance` is set on the class handle
224
+ */
225
+ template <class Type>
226
+ static auto MaybeFreeze(v8::Local<v8::Object> handle) {
227
+ auto context = handle->GetIsolate()->GetCurrentContext();
228
+ if (!detail::DontFreezePrototype<Type>::value) {
229
+ handle->GetPrototype().As<v8::Object>()->SetIntegrityLevel(context, v8::IntegrityLevel::kFrozen);
230
+ }
231
+ if (!detail::DontFreezeInstance<Type>::value) {
232
+ handle->SetIntegrityLevel(context, v8::IntegrityLevel::kFrozen);
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Builds a new instance of T from scratch, used in factory functions.
238
+ */
239
+ template <typename T, typename ...Args>
240
+ static auto NewInstance(Args&&... args) -> v8::Local<v8::Object> {
241
+ auto context = v8::Isolate::GetCurrent()->GetCurrentContext();
242
+ v8::Local<v8::Object> instance = Unmaybe(GetFunctionTemplate<T>()->InstanceTemplate()->NewInstance(context));
243
+ MaybeFreeze<T>(instance);
244
+ Wrap(std::make_unique<T>(std::forward<Args>(args)...), instance);
245
+ return instance;
246
+ }
247
+
248
+ /**
249
+ * Pull out native pointer from v8 handle
250
+ */
251
+ template <typename T>
252
+ static auto Unwrap(v8::Local<v8::Object> handle) -> T* {
253
+ assert(!handle.IsEmpty());
254
+ if (!ClassHandle::GetFunctionTemplate<T>()->HasInstance(handle)) {
255
+ return nullptr;
256
+ }
257
+ assert(handle->InternalFieldCount() > 0);
258
+ return dynamic_cast<T*>(static_cast<ClassHandle*>(handle->GetAlignedPointerFromInternalField(0)));
259
+ }
260
+
261
+ /**
262
+ * Returns the JS value that this ClassHandle points to
263
+ */
264
+ auto This() -> v8::Local<v8::Object> {
265
+ return Deref(handle).As<v8::Object>();
266
+ }
267
+ };
268
+
269
+ // Conversions from v8::Value -> Type&
270
+ template <class Type>
271
+ inline auto HandleCastImpl(v8::Local<v8::Value> value, const HandleCastArguments& /*arguments*/, HandleCastTag<Type&> /*tag*/) -> Type& {
272
+ if (!value->IsObject()) {
273
+ throw ParamIncorrect("an object");
274
+ }
275
+ v8::Local<v8::Object> handle = value.As<v8::Object>();
276
+ if (handle->InternalFieldCount() != 1) {
277
+ throw ParamIncorrect("something else");
278
+ }
279
+ auto* ptr = ClassHandle::Unwrap<Type>(handle);
280
+ if (ptr == nullptr) {
281
+ throw ParamIncorrect("something else");
282
+ } else {
283
+ return *ptr;
284
+ }
285
+ }
286
+
287
+ namespace detail {
288
+
289
+ template <class Signature>
290
+ struct ConstructorFunctionImpl;
291
+
292
+ template <class Signature>
293
+ struct ConstructorFunctionImpl<Signature*> : ConstructorFunctionImpl<Signature> {};
294
+
295
+ template <class Return, class ...Args>
296
+ struct ConstructorFunctionImpl<Return(Args...)> {
297
+ using Type = v8::Local<v8::Value>(*)(v8::Local<v8::Value> This, Args... args);
298
+
299
+ template <Return(*Function)(Args...)>
300
+ static inline auto Invoke(v8::Local<v8::Value> This, Args... args) -> v8::Local<v8::Value> {
301
+ auto instance = Function(args...);
302
+ if (instance) {
303
+ v8::Local<v8::Object> handle = This.As<v8::Object>();
304
+ ClassHandle::MaybeFreeze<typename decltype(instance)::element_type>(handle);
305
+ ClassHandle::Wrap(std::move(instance), handle);
306
+ return handle;
307
+ } else {
308
+ return Undefined(v8::Isolate::GetCurrent());
309
+ }
310
+ }
311
+ };
312
+
313
+ } // namespace detail
314
+
315
+ template <class Signature, Signature Function>
316
+ struct ConstructorFunction : detail::ConstructorFunctionHolder {
317
+ using ConstructorFunctionHolder::ConstructorFunctionHolder;
318
+ ConstructorFunction() : ConstructorFunctionHolder{
319
+ Entry,
320
+ std::tuple_size<typename detail::extract_arguments<Signature>::arguments>::value} {}
321
+
322
+ static void Entry(const v8::FunctionCallbackInfo<v8::Value>& info) {
323
+ detail::RunBarrier([&]() {
324
+ if (!info.IsConstructCall()) {
325
+ throw RuntimeTypeError(detail::CalleeName(info)+ " must be called with `new`");
326
+ }
327
+ ToCallback<-1, typename Impl::Type, &Impl::template Invoke<Function>>()(info);
328
+ });
329
+ }
330
+
331
+ using Impl = detail::ConstructorFunctionImpl<Signature>;
332
+ };
333
+
334
+ } // namespace ivm
@@ -0,0 +1,220 @@
1
+ #include "cpu_profile_manager.h"
2
+ #include "environment.h"
3
+ #include <algorithm>
4
+ #include <climits>
5
+ #include <cmath>
6
+ #include <cstdio>
7
+ #include <cstring>
8
+ #include <memory>
9
+ #include <mutex>
10
+ #include <thread>
11
+ #include <vector>
12
+ #include "isolate/strings.h"
13
+ #include "v8-platform.h"
14
+ #include "v8.h"
15
+
16
+ using namespace v8;
17
+
18
+ namespace ivm {
19
+
20
+ /**
21
+ * CpuProfileManagerImpl
22
+ */
23
+ IVMCpuProfile::IVMCpuProfile(const std::shared_ptr<v8::CpuProfile>& cpuProfile):
24
+ profile_thread(std::this_thread::get_id()),
25
+ start_time(cpuProfile->GetStartTime()),
26
+ end_time(cpuProfile->GetEndTime()),
27
+ samples_count(cpuProfile->GetSamplesCount()) {
28
+
29
+ samples.reserve(samples_count);
30
+ timestamps.reserve(samples_count);
31
+ for (int64_t i = 0; i < samples_count; i++) {
32
+ const int idx = static_cast<int>(i);
33
+ samples.push_back(cpuProfile->GetSample(idx)->GetNodeId());
34
+ timestamps.push_back(cpuProfile->GetSampleTimestamp(idx));
35
+ }
36
+
37
+ // handle nodes
38
+ FlatNodes(cpuProfile->GetTopDownRoot(), &profileNodes);
39
+ }
40
+
41
+ auto IVMCpuProfile::GetTidValue(Isolate *iso) -> Local<Value>{
42
+ const auto tid = std::hash<std::thread::id>{}(profile_thread);
43
+ return Number::New(iso, static_cast<double>(tid));
44
+ }
45
+
46
+ auto IVMCpuProfile::BuildCpuProfile(Isolate *iso) -> Local<Value> {
47
+ auto& strings = StringTable::Get();
48
+ auto context = iso->GetCurrentContext();
49
+ auto profileObject = Object::New(iso);
50
+
51
+ Unmaybe(profileObject->Set(context, strings.startTime, Number::New(iso, static_cast<double>(start_time))));
52
+ Unmaybe(profileObject->Set(context, strings.endTime, Number::New(iso, static_cast<double>(end_time))));
53
+
54
+ const Local<Array> samplesArr = Array::New(iso);
55
+ const Local<Array> timeDeltasArr = Array::New(iso);
56
+
57
+ for (int64_t i = 0; i < samples_count; i++) {
58
+ Unmaybe(samplesArr->Set(context, i, Number::New(iso, static_cast<double>(samples[i]))));
59
+ Unmaybe(timeDeltasArr->Set(context, i, Number::New(iso, static_cast<double>(timestamps[i] - start_time))));
60
+ }
61
+ Unmaybe(profileObject->Set(context, strings.samples, samplesArr));
62
+ Unmaybe(profileObject->Set(context, strings.timeDeltas, timeDeltasArr));
63
+
64
+ const Local<Array> nodeArr = Array::New(iso, static_cast<int>(profileNodes.size()));
65
+ Unmaybe(profileObject->Set(context, strings.nodes, nodeArr));
66
+
67
+ const size_t count = profileNodes.size();
68
+ for (size_t i = 0; i < count; i++) {
69
+ ProfileNode node = profileNodes[i];
70
+ Unmaybe(nodeArr->Set(context, i, node.ToJSObject(iso)));
71
+ }
72
+
73
+ return profileObject;
74
+ }
75
+
76
+ auto IVMCpuProfile::ToJSObject(Isolate *iso) -> Local<Value> {
77
+ auto& strings = StringTable::Get();
78
+ auto context = iso->GetCurrentContext();
79
+ auto result = Object::New(iso);
80
+
81
+ Unmaybe(result->Set(context, (v8::Local<v8::Value>)strings.threadId, GetTidValue(iso)));
82
+ Unmaybe(result->Set(context, strings.profile, BuildCpuProfile(iso)));
83
+
84
+ return result;
85
+ }
86
+
87
+ IVMCpuProfile::CallFrame::CallFrame(const v8::CpuProfileNode* node):
88
+ function_name(node->GetFunctionNameStr()),
89
+ url(node->GetScriptResourceNameStr()),
90
+ script_id(node->GetScriptId()),
91
+ line_number(node->GetLineNumber()),
92
+ column_number(node->GetColumnNumber()) {}
93
+
94
+
95
+ auto IVMCpuProfile::CallFrame::ToJSObject(v8::Isolate *iso) -> Local<Value> {
96
+ auto& strings = StringTable::Get();
97
+ Local<Object> callFrame = Object::New(iso);
98
+ const Local<Context> context = iso->GetCurrentContext();
99
+ Unmaybe(callFrame->Set(context, strings.functionName, String::NewFromUtf8(iso, function_name).ToLocalChecked()));
100
+ Unmaybe(callFrame->Set(context, strings.url, String::NewFromUtf8(iso, url).ToLocalChecked()));
101
+ Unmaybe(callFrame->Set(context, strings.scriptId, Number::New(iso, script_id)));
102
+ Unmaybe(callFrame->Set(context, strings.lineNumber, Number::New(iso, line_number)));
103
+ Unmaybe(callFrame->Set(context, strings.columnNumber, Number::New(iso, column_number)));
104
+ return callFrame;
105
+ }
106
+
107
+ IVMCpuProfile::ProfileNode::ProfileNode(const v8::CpuProfileNode* node):
108
+ hit_count(node->GetHitCount()),
109
+ node_id(node->GetNodeId()),
110
+ bailout_reason(node->GetBailoutReason()),
111
+ call_frame(node) {
112
+ const int childrenCount = node->GetChildrenCount();
113
+ children.reserve(childrenCount);
114
+ for (int i = 0; i < childrenCount; i++) {
115
+ children.push_back(node->GetChild(i)->GetNodeId());
116
+ }
117
+ }
118
+
119
+ auto IVMCpuProfile::ProfileNode::ToJSObject(Isolate *iso) -> Local<Value> {
120
+ auto& strings = StringTable::Get();
121
+ auto context = iso->GetCurrentContext();
122
+
123
+ Local<Object> nodeObj = Object::New(iso);
124
+
125
+ Unmaybe(nodeObj->Set(context, strings.hitCount, Number::New(iso, hit_count)));
126
+ Unmaybe(nodeObj->Set(context, strings.id, Number::New(iso, node_id)));
127
+
128
+ if (strlen(bailout_reason) > 0) {
129
+ Unmaybe(nodeObj->Set(context, strings.bailoutReason, String::NewFromUtf8(iso, bailout_reason).ToLocalChecked()));
130
+ }
131
+
132
+ const int children_count = static_cast<int>(children.size());
133
+ const Local<Array> childrenArr = Array::New(iso, children_count);
134
+ Unmaybe(nodeObj->Set(context, strings.children, childrenArr));
135
+
136
+ for (int j = 0; j < children_count; j++) {
137
+ Unmaybe(childrenArr->Set(context, j, Number::New(iso, static_cast<double>(children[j]))));
138
+ }
139
+
140
+ const Local<Value> callFrame = call_frame.ToJSObject(iso);
141
+ Unmaybe(nodeObj->Set(context, strings.callFrame, callFrame));
142
+
143
+ return nodeObj;
144
+ }
145
+
146
+ CpuProfileManager::CpuProfileManager() = default;
147
+
148
+ void CpuProfileManager::StartProfiling(const char* title) {
149
+ const std::lock_guard<std::mutex> lock(mutex);
150
+ std::string str(title);
151
+ profile_titles.insert(str);
152
+ }
153
+
154
+ auto CpuProfileManager::StopProfiling(const char* title) -> std::vector<IVMCpuProfile> {
155
+ const std::lock_guard<std::mutex> lock(mutex);
156
+ const std::string str_title(title);
157
+
158
+ std::vector<IVMCpuProfile> currently_collected;
159
+
160
+ if (profile_begin_ptrs.find(str_title) == profile_begin_ptrs.end()) {
161
+ return currently_collected;
162
+ }
163
+
164
+ auto iter = profile_begin_ptrs[str_title];
165
+
166
+ // Iterate using an iterator
167
+ for (auto it = iter; it != profile_items.end(); ++it) {
168
+ currently_collected.push_back(*it);
169
+ }
170
+
171
+ // remove the titles
172
+ profile_titles.erase(str_title);
173
+ // remove the profile ptr from map
174
+ profile_begin_ptrs.erase(str_title);
175
+
176
+ // TODO clean up old profiles, extract private method
177
+ CleanProfiles();
178
+
179
+ return currently_collected;
180
+ }
181
+
182
+ auto CpuProfileManager::IsProfiling() -> bool {
183
+ return !profile_titles.empty();
184
+ }
185
+
186
+ auto CpuProfileManager::InjestCpuProfile(const std::shared_ptr<v8::CpuProfile>& cpuProfile) -> void {
187
+ const std::lock_guard<std::mutex> lock(mutex);
188
+ profile_items.emplace_back(cpuProfile);
189
+
190
+ for(const std::string &title : profile_titles) {
191
+ if (profile_begin_ptrs.find(title) == profile_begin_ptrs.end()) {
192
+ profile_begin_ptrs[title] = std::prev(profile_items.end());
193
+ }
194
+ }
195
+ }
196
+
197
+ void CpuProfileManager::CleanProfiles() {
198
+ if (profile_titles.empty()) {
199
+ profile_items.clear();
200
+ profile_begin_ptrs.clear();
201
+ }
202
+
203
+ int64_t min_start_time = INT_MAX;
204
+
205
+ for (const auto& profile_item: profile_begin_ptrs) {
206
+ if (profile_item.second->GetStartTime() < min_start_time) {
207
+ min_start_time = profile_item.second->GetStartTime();
208
+ }
209
+ }
210
+
211
+ for (auto it = profile_items.begin(); it != profile_items.end(); ) {
212
+ if (it->GetStartTime() < min_start_time) {
213
+ it = profile_items.erase(it);
214
+ } else {
215
+ ++it;
216
+ }
217
+ }
218
+ }
219
+
220
+ }