GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
// Copyright Joyent, Inc. and other Node contributors. |
||
2 |
// |
||
3 |
// Permission is hereby granted, free of charge, to any person obtaining a |
||
4 |
// copy of this software and associated documentation files (the |
||
5 |
// "Software"), to deal in the Software without restriction, including |
||
6 |
// without limitation the rights to use, copy, modify, merge, publish, |
||
7 |
// distribute, sublicense, and/or sell copies of the Software, and to permit |
||
8 |
// persons to whom the Software is furnished to do so, subject to the |
||
9 |
// following conditions: |
||
10 |
// |
||
11 |
// The above copyright notice and this permission notice shall be included |
||
12 |
// in all copies or substantial portions of the Software. |
||
13 |
// |
||
14 |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
15 |
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||
16 |
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
||
17 |
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
||
18 |
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
||
19 |
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
||
20 |
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
21 |
|||
22 |
#include "node_contextify.h" |
||
23 |
|||
24 |
#include "base_object-inl.h" |
||
25 |
#include "memory_tracker-inl.h" |
||
26 |
#include "module_wrap.h" |
||
27 |
#include "node_context_data.h" |
||
28 |
#include "node_errors.h" |
||
29 |
#include "node_external_reference.h" |
||
30 |
#include "node_internals.h" |
||
31 |
#include "node_snapshot_builder.h" |
||
32 |
#include "node_watchdog.h" |
||
33 |
#include "util-inl.h" |
||
34 |
|||
35 |
namespace node { |
||
36 |
namespace contextify { |
||
37 |
|||
38 |
using errors::TryCatchScope; |
||
39 |
|||
40 |
using v8::Array; |
||
41 |
using v8::ArrayBufferView; |
||
42 |
using v8::Boolean; |
||
43 |
using v8::Context; |
||
44 |
using v8::EscapableHandleScope; |
||
45 |
using v8::Function; |
||
46 |
using v8::FunctionCallbackInfo; |
||
47 |
using v8::FunctionTemplate; |
||
48 |
using v8::HandleScope; |
||
49 |
using v8::IndexedPropertyHandlerConfiguration; |
||
50 |
using v8::Int32; |
||
51 |
using v8::Isolate; |
||
52 |
using v8::Local; |
||
53 |
using v8::Maybe; |
||
54 |
using v8::MaybeLocal; |
||
55 |
using v8::MeasureMemoryExecution; |
||
56 |
using v8::MeasureMemoryMode; |
||
57 |
using v8::MicrotaskQueue; |
||
58 |
using v8::MicrotasksPolicy; |
||
59 |
using v8::Name; |
||
60 |
using v8::NamedPropertyHandlerConfiguration; |
||
61 |
using v8::Number; |
||
62 |
using v8::Object; |
||
63 |
using v8::ObjectTemplate; |
||
64 |
using v8::PrimitiveArray; |
||
65 |
using v8::Promise; |
||
66 |
using v8::PropertyAttribute; |
||
67 |
using v8::PropertyCallbackInfo; |
||
68 |
using v8::PropertyDescriptor; |
||
69 |
using v8::PropertyHandlerFlags; |
||
70 |
using v8::Script; |
||
71 |
using v8::ScriptCompiler; |
||
72 |
using v8::ScriptOrigin; |
||
73 |
using v8::String; |
||
74 |
using v8::Uint32; |
||
75 |
using v8::UnboundScript; |
||
76 |
using v8::Value; |
||
77 |
using v8::WeakCallbackInfo; |
||
78 |
using v8::WeakCallbackType; |
||
79 |
|||
80 |
// The vm module executes code in a sandboxed environment with a different |
||
81 |
// global object than the rest of the code. This is achieved by applying |
||
82 |
// every call that changes or queries a property on the global `this` in the |
||
83 |
// sandboxed code, to the sandbox object. |
||
84 |
// |
||
85 |
// The implementation uses V8's interceptors for methods like `set`, `get`, |
||
86 |
// `delete`, `defineProperty`, and for any query of the property attributes. |
||
87 |
// Property handlers with interceptors are set on the object template for |
||
88 |
// the sandboxed code. Handlers for both named properties and for indexed |
||
89 |
// properties are used. Their functionality is almost identical, the indexed |
||
90 |
// interceptors mostly just call the named interceptors. |
||
91 |
// |
||
92 |
// For every `get` of a global property in the sandboxed context, the |
||
93 |
// interceptor callback checks the sandbox object for the property. |
||
94 |
// If the property is defined on the sandbox, that result is returned to |
||
95 |
// the original call instead of finishing the query on the global object. |
||
96 |
// |
||
97 |
// For every `set` of a global property, the interceptor callback defines or |
||
98 |
// changes the property both on the sandbox and the global proxy. |
||
99 |
|||
100 |
namespace { |
||
101 |
|||
102 |
// Convert an int to a V8 Name (String or Symbol). |
||
103 |
3 |
Local<Name> Uint32ToName(Local<Context> context, uint32_t index) { |
|
104 |
6 |
return Uint32::New(context->GetIsolate(), index)->ToString(context) |
|
105 |
3 |
.ToLocalChecked(); |
|
106 |
} |
||
107 |
|||
108 |
} // anonymous namespace |
||
109 |
|||
110 |
673 |
BaseObjectPtr<ContextifyContext> ContextifyContext::New( |
|
111 |
Environment* env, |
||
112 |
Local<Object> sandbox_obj, |
||
113 |
const ContextOptions& options) { |
||
114 |
1346 |
HandleScope scope(env->isolate()); |
|
115 |
673 |
InitializeGlobalTemplates(env->isolate_data()); |
|
116 |
673 |
Local<ObjectTemplate> object_template = env->contextify_global_template(); |
|
117 |
DCHECK(!object_template.IsEmpty()); |
||
118 |
673 |
bool use_node_snapshot = per_process::cli_options->node_snapshot; |
|
119 |
const SnapshotData* snapshot_data = |
||
120 |
✓✗ | 673 |
use_node_snapshot ? SnapshotBuilder::GetEmbeddedSnapshotData() : nullptr; |
121 |
|||
122 |
MicrotaskQueue* queue = |
||
123 |
options.microtask_queue_wrap |
||
124 |
✓✓ | 673 |
? options.microtask_queue_wrap->microtask_queue().get() |
125 |
2014 |
: env->isolate()->GetCurrentContext()->GetMicrotaskQueue(); |
|
126 |
|||
127 |
Local<Context> v8_context; |
||
128 |
673 |
if (!(CreateV8Context(env->isolate(), object_template, snapshot_data, queue) |
|
129 |
✗✓ | 673 |
.ToLocal(&v8_context))) { |
130 |
// Allocation failure, maximum call stack size reached, termination, etc. |
||
131 |
return BaseObjectPtr<ContextifyContext>(); |
||
132 |
} |
||
133 |
673 |
return New(v8_context, env, sandbox_obj, options); |
|
134 |
} |
||
135 |
|||
136 |
void ContextifyContext::MemoryInfo(MemoryTracker* tracker) const { |
||
137 |
if (microtask_queue_wrap_) { |
||
138 |
tracker->TrackField("microtask_queue_wrap", |
||
139 |
microtask_queue_wrap_->object()); |
||
140 |
} |
||
141 |
} |
||
142 |
|||
143 |
673 |
ContextifyContext::ContextifyContext(Environment* env, |
|
144 |
Local<Object> wrapper, |
||
145 |
Local<Context> v8_context, |
||
146 |
673 |
const ContextOptions& options) |
|
147 |
: BaseObject(env, wrapper), |
||
148 |
673 |
microtask_queue_wrap_(options.microtask_queue_wrap) { |
|
149 |
673 |
context_.Reset(env->isolate(), v8_context); |
|
150 |
// This should only be done after the initial initializations of the context |
||
151 |
// global object is finished. |
||
152 |
DCHECK_NULL(v8_context->GetAlignedPointerFromEmbedderData( |
||
153 |
ContextEmbedderIndex::kContextifyContext)); |
||
154 |
673 |
v8_context->SetAlignedPointerInEmbedderData( |
|
155 |
ContextEmbedderIndex::kContextifyContext, this); |
||
156 |
// It's okay to make this reference weak - V8 would create an internal |
||
157 |
// reference to this context via the constructor of the wrapper. |
||
158 |
// As long as the wrapper is alive, it's constructor is alive, and so |
||
159 |
// is the context. |
||
160 |
673 |
context_.SetWeak(); |
|
161 |
673 |
} |
|
162 |
|||
163 |
3114 |
ContextifyContext::~ContextifyContext() { |
|
164 |
1038 |
Isolate* isolate = env()->isolate(); |
|
165 |
2076 |
HandleScope scope(isolate); |
|
166 |
|||
167 |
1038 |
env()->UntrackContext(PersistentToLocal::Weak(isolate, context_)); |
|
168 |
1038 |
context_.Reset(); |
|
169 |
2076 |
} |
|
170 |
|||
171 |
1504 |
void ContextifyContext::InitializeGlobalTemplates(IsolateData* isolate_data) { |
|
172 |
✓✓ | 3008 |
if (!isolate_data->contextify_global_template().IsEmpty()) { |
173 |
673 |
return; |
|
174 |
} |
||
175 |
DCHECK(isolate_data->contextify_wrapper_template().IsEmpty()); |
||
176 |
Local<FunctionTemplate> global_func_template = |
||
177 |
831 |
FunctionTemplate::New(isolate_data->isolate()); |
|
178 |
Local<ObjectTemplate> global_object_template = |
||
179 |
831 |
global_func_template->InstanceTemplate(); |
|
180 |
|||
181 |
NamedPropertyHandlerConfiguration config( |
||
182 |
PropertyGetterCallback, |
||
183 |
PropertySetterCallback, |
||
184 |
PropertyDescriptorCallback, |
||
185 |
PropertyDeleterCallback, |
||
186 |
PropertyEnumeratorCallback, |
||
187 |
PropertyDefinerCallback, |
||
188 |
{}, |
||
189 |
831 |
PropertyHandlerFlags::kHasNoSideEffect); |
|
190 |
|||
191 |
IndexedPropertyHandlerConfiguration indexed_config( |
||
192 |
IndexedPropertyGetterCallback, |
||
193 |
IndexedPropertySetterCallback, |
||
194 |
IndexedPropertyDescriptorCallback, |
||
195 |
IndexedPropertyDeleterCallback, |
||
196 |
PropertyEnumeratorCallback, |
||
197 |
IndexedPropertyDefinerCallback, |
||
198 |
{}, |
||
199 |
831 |
PropertyHandlerFlags::kHasNoSideEffect); |
|
200 |
|||
201 |
831 |
global_object_template->SetHandler(config); |
|
202 |
831 |
global_object_template->SetHandler(indexed_config); |
|
203 |
831 |
isolate_data->set_contextify_global_template(global_object_template); |
|
204 |
|||
205 |
Local<FunctionTemplate> wrapper_func_template = |
||
206 |
831 |
BaseObject::MakeLazilyInitializedJSTemplate(isolate_data); |
|
207 |
Local<ObjectTemplate> wrapper_object_template = |
||
208 |
831 |
wrapper_func_template->InstanceTemplate(); |
|
209 |
831 |
isolate_data->set_contextify_wrapper_template(wrapper_object_template); |
|
210 |
} |
||
211 |
|||
212 |
681 |
MaybeLocal<Context> ContextifyContext::CreateV8Context( |
|
213 |
Isolate* isolate, |
||
214 |
Local<ObjectTemplate> object_template, |
||
215 |
const SnapshotData* snapshot_data, |
||
216 |
MicrotaskQueue* queue) { |
||
217 |
681 |
EscapableHandleScope scope(isolate); |
|
218 |
|||
219 |
Local<Context> ctx; |
||
220 |
✓✓ | 681 |
if (snapshot_data == nullptr) { |
221 |
ctx = Context::New(isolate, |
||
222 |
nullptr, // extensions |
||
223 |
object_template, |
||
224 |
{}, // global object |
||
225 |
{}, // deserialization callback |
||
226 |
20 |
queue); |
|
227 |
✓✗✗✓ ✗✓ |
20 |
if (ctx.IsEmpty() || InitializeBaseContextForSnapshot(ctx).IsNothing()) { |
228 |
return MaybeLocal<Context>(); |
||
229 |
} |
||
230 |
1342 |
} else if (!Context::FromSnapshot(isolate, |
|
231 |
SnapshotData::kNodeVMContextIndex, |
||
232 |
{}, // deserialization callback |
||
233 |
nullptr, // extensions |
||
234 |
{}, // global object |
||
235 |
671 |
queue) |
|
236 |
✗✓ | 671 |
.ToLocal(&ctx)) { |
237 |
return MaybeLocal<Context>(); |
||
238 |
} |
||
239 |
|||
240 |
681 |
return scope.Escape(ctx); |
|
241 |
} |
||
242 |
|||
243 |
673 |
BaseObjectPtr<ContextifyContext> ContextifyContext::New( |
|
244 |
Local<Context> v8_context, |
||
245 |
Environment* env, |
||
246 |
Local<Object> sandbox_obj, |
||
247 |
const ContextOptions& options) { |
||
248 |
1346 |
HandleScope scope(env->isolate()); |
|
249 |
// This only initializes part of the context. The primordials are |
||
250 |
// only initilaized when needed because even deserializing them slows |
||
251 |
// things down significantly and they are only needed in rare occasions |
||
252 |
// in the vm contexts. |
||
253 |
✗✓ | 1346 |
if (InitializeContextRuntime(v8_context).IsNothing()) { |
254 |
return BaseObjectPtr<ContextifyContext>(); |
||
255 |
} |
||
256 |
|||
257 |
673 |
Local<Context> main_context = env->context(); |
|
258 |
673 |
Local<Object> new_context_global = v8_context->Global(); |
|
259 |
673 |
v8_context->SetSecurityToken(main_context->GetSecurityToken()); |
|
260 |
|||
261 |
// We need to tie the lifetime of the sandbox object with the lifetime of |
||
262 |
// newly created context. We do this by making them hold references to each |
||
263 |
// other. The context can directly hold a reference to the sandbox as an |
||
264 |
// embedder data field. The sandbox uses a private symbol to hold a reference |
||
265 |
// to the ContextifyContext wrapper which in turn internally references |
||
266 |
// the context from its constructor. |
||
267 |
673 |
v8_context->SetEmbedderData(ContextEmbedderIndex::kSandboxObject, |
|
268 |
sandbox_obj); |
||
269 |
|||
270 |
// Delegate the code generation validation to |
||
271 |
// node::ModifyCodeGenerationFromStrings. |
||
272 |
673 |
v8_context->AllowCodeGenerationFromStrings(false); |
|
273 |
673 |
v8_context->SetEmbedderData( |
|
274 |
ContextEmbedderIndex::kAllowCodeGenerationFromStrings, |
||
275 |
options.allow_code_gen_strings); |
||
276 |
673 |
v8_context->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration, |
|
277 |
options.allow_code_gen_wasm); |
||
278 |
|||
279 |
1346 |
Utf8Value name_val(env->isolate(), options.name); |
|
280 |
2019 |
ContextInfo info(*name_val); |
|
281 |
✓✓ | 673 |
if (!options.origin.IsEmpty()) { |
282 |
4 |
Utf8Value origin_val(env->isolate(), options.origin); |
|
283 |
2 |
info.origin = *origin_val; |
|
284 |
} |
||
285 |
|||
286 |
1346 |
BaseObjectPtr<ContextifyContext> result; |
|
287 |
Local<Object> wrapper; |
||
288 |
{ |
||
289 |
673 |
Context::Scope context_scope(v8_context); |
|
290 |
673 |
Local<String> ctor_name = sandbox_obj->GetConstructorName(); |
|
291 |
✓✗✓✓ |
2023 |
if (!ctor_name->Equals(v8_context, env->object_string()).FromMaybe(false) && |
292 |
new_context_global |
||
293 |
673 |
->DefineOwnProperty( |
|
294 |
v8_context, |
||
295 |
v8::Symbol::GetToStringTag(env->isolate()), |
||
296 |
ctor_name, |
||
297 |
✗✓ | 681 |
static_cast<v8::PropertyAttribute>(v8::DontEnum)) |
298 |
✗✓ | 4 |
.IsNothing()) { |
299 |
return BaseObjectPtr<ContextifyContext>(); |
||
300 |
} |
||
301 |
673 |
env->AssignToContext(v8_context, nullptr, info); |
|
302 |
|||
303 |
673 |
if (!env->contextify_wrapper_template() |
|
304 |
673 |
->NewInstance(v8_context) |
|
305 |
✗✓ | 673 |
.ToLocal(&wrapper)) { |
306 |
return BaseObjectPtr<ContextifyContext>(); |
||
307 |
} |
||
308 |
|||
309 |
result = |
||
310 |
673 |
MakeBaseObject<ContextifyContext>(env, wrapper, v8_context, options); |
|
311 |
// The only strong reference to the wrapper will come from the sandbox. |
||
312 |
673 |
result->MakeWeak(); |
|
313 |
} |
||
314 |
|||
315 |
673 |
if (sandbox_obj |
|
316 |
673 |
->SetPrivate( |
|
317 |
673 |
v8_context, env->contextify_context_private_symbol(), wrapper) |
|
318 |
✗✓ | 673 |
.IsNothing()) { |
319 |
return BaseObjectPtr<ContextifyContext>(); |
||
320 |
} |
||
321 |
|||
322 |
673 |
return result; |
|
323 |
} |
||
324 |
|||
325 |
819 |
void ContextifyContext::Init(Environment* env, Local<Object> target) { |
|
326 |
819 |
Local<Context> context = env->context(); |
|
327 |
819 |
SetMethod(context, target, "makeContext", MakeContext); |
|
328 |
819 |
SetMethod(context, target, "isContext", IsContext); |
|
329 |
819 |
SetMethod(context, target, "compileFunction", CompileFunction); |
|
330 |
819 |
} |
|
331 |
|||
332 |
5717 |
void ContextifyContext::RegisterExternalReferences( |
|
333 |
ExternalReferenceRegistry* registry) { |
||
334 |
5717 |
registry->Register(MakeContext); |
|
335 |
5717 |
registry->Register(IsContext); |
|
336 |
5717 |
registry->Register(CompileFunction); |
|
337 |
5717 |
registry->Register(PropertyGetterCallback); |
|
338 |
5717 |
registry->Register(PropertySetterCallback); |
|
339 |
5717 |
registry->Register(PropertyDescriptorCallback); |
|
340 |
5717 |
registry->Register(PropertyDeleterCallback); |
|
341 |
5717 |
registry->Register(PropertyEnumeratorCallback); |
|
342 |
5717 |
registry->Register(PropertyDefinerCallback); |
|
343 |
5717 |
registry->Register(IndexedPropertyGetterCallback); |
|
344 |
5717 |
registry->Register(IndexedPropertySetterCallback); |
|
345 |
5717 |
registry->Register(IndexedPropertyDescriptorCallback); |
|
346 |
5717 |
registry->Register(IndexedPropertyDeleterCallback); |
|
347 |
5717 |
registry->Register(IndexedPropertyDefinerCallback); |
|
348 |
5717 |
} |
|
349 |
|||
350 |
// makeContext(sandbox, name, origin, strings, wasm); |
||
351 |
673 |
void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) { |
|
352 |
673 |
Environment* env = Environment::GetCurrent(args); |
|
353 |
|||
354 |
✗✓ | 673 |
CHECK_EQ(args.Length(), 6); |
355 |
✗✓ | 673 |
CHECK(args[0]->IsObject()); |
356 |
1346 |
Local<Object> sandbox = args[0].As<Object>(); |
|
357 |
|||
358 |
// Don't allow contextifying a sandbox multiple times. |
||
359 |
✗✓ | 1346 |
CHECK( |
360 |
!sandbox->HasPrivate( |
||
361 |
env->context(), |
||
362 |
env->contextify_context_private_symbol()).FromJust()); |
||
363 |
|||
364 |
673 |
ContextOptions options; |
|
365 |
|||
366 |
✗✓ | 1346 |
CHECK(args[1]->IsString()); |
367 |
✓✗ | 1346 |
options.name = args[1].As<String>(); |
368 |
|||
369 |
✓✓✗✓ ✗✓ |
2688 |
CHECK(args[2]->IsString() || args[2]->IsUndefined()); |
370 |
✓✓ | 1346 |
if (args[2]->IsString()) { |
371 |
4 |
options.origin = args[2].As<String>(); |
|
372 |
} |
||
373 |
|||
374 |
✗✓ | 673 |
CHECK(args[3]->IsBoolean()); |
375 |
✓✗ | 1346 |
options.allow_code_gen_strings = args[3].As<Boolean>(); |
376 |
|||
377 |
✗✓ | 673 |
CHECK(args[4]->IsBoolean()); |
378 |
✓✗ | 1346 |
options.allow_code_gen_wasm = args[4].As<Boolean>(); |
379 |
|||
380 |
673 |
if (args[5]->IsObject() && |
|
381 |
✓✓✓✗ ✓✗ |
683 |
!env->microtask_queue_ctor_template().IsEmpty() && |
382 |
✓✗✓✓ |
688 |
env->microtask_queue_ctor_template()->HasInstance(args[5])) { |
383 |
5 |
options.microtask_queue_wrap.reset( |
|
384 |
10 |
Unwrap<MicrotaskQueueWrap>(args[5].As<Object>())); |
|
385 |
} |
||
386 |
|||
387 |
673 |
TryCatchScope try_catch(env); |
|
388 |
BaseObjectPtr<ContextifyContext> context_ptr = |
||
389 |
673 |
ContextifyContext::New(env, sandbox, options); |
|
390 |
|||
391 |
✗✓ | 673 |
if (try_catch.HasCaught()) { |
392 |
if (!try_catch.HasTerminated()) |
||
393 |
try_catch.ReThrow(); |
||
394 |
return; |
||
395 |
} |
||
396 |
} |
||
397 |
|||
398 |
|||
399 |
6231 |
void ContextifyContext::IsContext(const FunctionCallbackInfo<Value>& args) { |
|
400 |
6231 |
Environment* env = Environment::GetCurrent(args); |
|
401 |
|||
402 |
✗✓ | 6231 |
CHECK(args[0]->IsObject()); |
403 |
12462 |
Local<Object> sandbox = args[0].As<Object>(); |
|
404 |
|||
405 |
Maybe<bool> result = |
||
406 |
sandbox->HasPrivate(env->context(), |
||
407 |
6231 |
env->contextify_context_private_symbol()); |
|
408 |
✓✓ | 12462 |
args.GetReturnValue().Set(result.FromJust()); |
409 |
6231 |
} |
|
410 |
|||
411 |
|||
412 |
void ContextifyContext::WeakCallback( |
||
413 |
const WeakCallbackInfo<ContextifyContext>& data) { |
||
414 |
ContextifyContext* context = data.GetParameter(); |
||
415 |
delete context; |
||
416 |
} |
||
417 |
|||
418 |
// static |
||
419 |
5502 |
ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox( |
|
420 |
Environment* env, |
||
421 |
const Local<Object>& sandbox) { |
||
422 |
Local<Value> context_global; |
||
423 |
5502 |
if (sandbox |
|
424 |
5502 |
->GetPrivate(env->context(), env->contextify_context_private_symbol()) |
|
425 |
✓✗✓✗ ✓✗ |
11004 |
.ToLocal(&context_global) && |
426 |
5502 |
context_global->IsObject()) { |
|
427 |
5502 |
return Unwrap<ContextifyContext>(context_global.As<Object>()); |
|
428 |
} |
||
429 |
return nullptr; |
||
430 |
} |
||
431 |
|||
432 |
template <typename T> |
||
433 |
2105782 |
ContextifyContext* ContextifyContext::Get(const PropertyCallbackInfo<T>& args) { |
|
434 |
2105782 |
return Get(args.This()); |
|
435 |
} |
||
436 |
|||
437 |
1052891 |
ContextifyContext* ContextifyContext::Get(Local<Object> object) { |
|
438 |
Local<Context> context; |
||
439 |
✗✓ | 2105782 |
if (!object->GetCreationContext().ToLocal(&context)) { |
440 |
return nullptr; |
||
441 |
} |
||
442 |
✓✓ | 1052891 |
if (!ContextEmbedderTag::IsNodeContext(context)) { |
443 |
45 |
return nullptr; |
|
444 |
} |
||
445 |
return static_cast<ContextifyContext*>( |
||
446 |
1052846 |
context->GetAlignedPointerFromEmbedderData( |
|
447 |
1052846 |
ContextEmbedderIndex::kContextifyContext)); |
|
448 |
} |
||
449 |
|||
450 |
1052891 |
bool ContextifyContext::IsStillInitializing(const ContextifyContext* ctx) { |
|
451 |
✓✓✗✓ |
1052891 |
return ctx == nullptr || ctx->context_.IsEmpty(); |
452 |
} |
||
453 |
|||
454 |
// static |
||
455 |
1052373 |
void ContextifyContext::PropertyGetterCallback( |
|
456 |
Local<Name> property, |
||
457 |
const PropertyCallbackInfo<Value>& args) { |
||
458 |
1052373 |
ContextifyContext* ctx = ContextifyContext::Get(args); |
|
459 |
|||
460 |
// Still initializing |
||
461 |
✓✓ | 1052373 |
if (IsStillInitializing(ctx)) return; |
462 |
|||
463 |
1051686 |
Local<Context> context = ctx->context(); |
|
464 |
1051686 |
Local<Object> sandbox = ctx->sandbox(); |
|
465 |
MaybeLocal<Value> maybe_rv = |
||
466 |
1051686 |
sandbox->GetRealNamedProperty(context, property); |
|
467 |
✓✓ | 1051686 |
if (maybe_rv.IsEmpty()) { |
468 |
maybe_rv = |
||
469 |
94860 |
ctx->global_proxy()->GetRealNamedProperty(context, property); |
|
470 |
} |
||
471 |
|||
472 |
Local<Value> rv; |
||
473 |
✓✓ | 1051686 |
if (maybe_rv.ToLocal(&rv)) { |
474 |
✓✓ | 1051617 |
if (rv == sandbox) |
475 |
10 |
rv = ctx->global_proxy(); |
|
476 |
|||
477 |
2103234 |
args.GetReturnValue().Set(rv); |
|
478 |
} |
||
479 |
} |
||
480 |
|||
481 |
// static |
||
482 |
175 |
void ContextifyContext::PropertySetterCallback( |
|
483 |
Local<Name> property, |
||
484 |
Local<Value> value, |
||
485 |
const PropertyCallbackInfo<Value>& args) { |
||
486 |
175 |
ContextifyContext* ctx = ContextifyContext::Get(args); |
|
487 |
|||
488 |
// Still initializing |
||
489 |
✓✓ | 189 |
if (IsStillInitializing(ctx)) return; |
490 |
|||
491 |
152 |
Local<Context> context = ctx->context(); |
|
492 |
152 |
PropertyAttribute attributes = PropertyAttribute::None; |
|
493 |
152 |
bool is_declared_on_global_proxy = ctx->global_proxy() |
|
494 |
152 |
->GetRealNamedPropertyAttributes(context, property) |
|
495 |
152 |
.To(&attributes); |
|
496 |
152 |
bool read_only = |
|
497 |
152 |
static_cast<int>(attributes) & |
|
498 |
static_cast<int>(PropertyAttribute::ReadOnly); |
||
499 |
|||
500 |
152 |
bool is_declared_on_sandbox = ctx->sandbox() |
|
501 |
152 |
->GetRealNamedPropertyAttributes(context, property) |
|
502 |
152 |
.To(&attributes); |
|
503 |
✓✓ | 300 |
read_only = read_only || |
504 |
✓✓ | 148 |
(static_cast<int>(attributes) & |
505 |
static_cast<int>(PropertyAttribute::ReadOnly)); |
||
506 |
|||
507 |
✓✓ | 152 |
if (read_only) |
508 |
13 |
return; |
|
509 |
|||
510 |
// true for x = 5 |
||
511 |
// false for this.x = 5 |
||
512 |
// false for Object.defineProperty(this, 'foo', ...) |
||
513 |
// false for vmResult.x = 5 where vmResult = vm.runInContext(); |
||
514 |
278 |
bool is_contextual_store = ctx->global_proxy() != args.This(); |
|
515 |
|||
516 |
// Indicator to not return before setting (undeclared) function declarations |
||
517 |
// on the sandbox in strict mode, i.e. args.ShouldThrowOnError() = true. |
||
518 |
// True for 'function f() {}', 'this.f = function() {}', |
||
519 |
// 'var f = function()'. |
||
520 |
// In effect only for 'function f() {}' because |
||
521 |
// var f = function(), is_declared = true |
||
522 |
// this.f = function() {}, is_contextual_store = false. |
||
523 |
139 |
bool is_function = value->IsFunction(); |
|
524 |
|||
525 |
✓✓✓✓ |
139 |
bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox; |
526 |
✓✓✓✓ ✓✓✓✓ |
230 |
if (!is_declared && args.ShouldThrowOnError() && is_contextual_store && |
527 |
✓✓ | 30 |
!is_function) |
528 |
1 |
return; |
|
529 |
|||
530 |
276 |
USE(ctx->sandbox()->Set(context, property, value)); |
|
531 |
276 |
args.GetReturnValue().Set(value); |
|
532 |
} |
||
533 |
|||
534 |
// static |
||
535 |
59 |
void ContextifyContext::PropertyDescriptorCallback( |
|
536 |
Local<Name> property, |
||
537 |
const PropertyCallbackInfo<Value>& args) { |
||
538 |
59 |
ContextifyContext* ctx = ContextifyContext::Get(args); |
|
539 |
|||
540 |
// Still initializing |
||
541 |
✓✓ | 59 |
if (IsStillInitializing(ctx)) return; |
542 |
|||
543 |
55 |
Local<Context> context = ctx->context(); |
|
544 |
|||
545 |
55 |
Local<Object> sandbox = ctx->sandbox(); |
|
546 |
|||
547 |
✓✗✓✓ |
110 |
if (sandbox->HasOwnProperty(context, property).FromMaybe(false)) { |
548 |
Local<Value> desc; |
||
549 |
✓✗ | 78 |
if (sandbox->GetOwnPropertyDescriptor(context, property).ToLocal(&desc)) { |
550 |
78 |
args.GetReturnValue().Set(desc); |
|
551 |
} |
||
552 |
} |
||
553 |
} |
||
554 |
|||
555 |
// static |
||
556 |
19 |
void ContextifyContext::PropertyDefinerCallback( |
|
557 |
Local<Name> property, |
||
558 |
const PropertyDescriptor& desc, |
||
559 |
const PropertyCallbackInfo<Value>& args) { |
||
560 |
19 |
ContextifyContext* ctx = ContextifyContext::Get(args); |
|
561 |
|||
562 |
// Still initializing |
||
563 |
✓✓ | 19 |
if (IsStillInitializing(ctx)) return; |
564 |
|||
565 |
15 |
Local<Context> context = ctx->context(); |
|
566 |
15 |
Isolate* isolate = context->GetIsolate(); |
|
567 |
|||
568 |
15 |
PropertyAttribute attributes = PropertyAttribute::None; |
|
569 |
bool is_declared = |
||
570 |
15 |
ctx->global_proxy()->GetRealNamedPropertyAttributes(context, |
|
571 |
15 |
property) |
|
572 |
15 |
.To(&attributes); |
|
573 |
15 |
bool read_only = |
|
574 |
15 |
static_cast<int>(attributes) & |
|
575 |
static_cast<int>(PropertyAttribute::ReadOnly); |
||
576 |
|||
577 |
// If the property is set on the global as read_only, don't change it on |
||
578 |
// the global or sandbox. |
||
579 |
✓✓✗✓ |
15 |
if (is_declared && read_only) |
580 |
return; |
||
581 |
|||
582 |
15 |
Local<Object> sandbox = ctx->sandbox(); |
|
583 |
|||
584 |
auto define_prop_on_sandbox = |
||
585 |
15 |
[&] (PropertyDescriptor* desc_for_sandbox) { |
|
586 |
✓✓ | 15 |
if (desc.has_enumerable()) { |
587 |
2 |
desc_for_sandbox->set_enumerable(desc.enumerable()); |
|
588 |
} |
||
589 |
✓✓ | 15 |
if (desc.has_configurable()) { |
590 |
1 |
desc_for_sandbox->set_configurable(desc.configurable()); |
|
591 |
} |
||
592 |
// Set the property on the sandbox. |
||
593 |
15 |
USE(sandbox->DefineProperty(context, property, *desc_for_sandbox)); |
|
594 |
30 |
}; |
|
595 |
|||
596 |
✓✓✗✓ ✓✓ |
15 |
if (desc.has_get() || desc.has_set()) { |
597 |
PropertyDescriptor desc_for_sandbox( |
||
598 |
15 |
desc.has_get() ? desc.get() : Undefined(isolate).As<Value>(), |
|
599 |
✓✓✓✗ |
23 |
desc.has_set() ? desc.set() : Undefined(isolate).As<Value>()); |
600 |
|||
601 |
5 |
define_prop_on_sandbox(&desc_for_sandbox); |
|
602 |
} else { |
||
603 |
Local<Value> value = |
||
604 |
✓✓ | 12 |
desc.has_value() ? desc.value() : Undefined(isolate).As<Value>(); |
605 |
|||
606 |
✗✓ | 10 |
if (desc.has_writable()) { |
607 |
PropertyDescriptor desc_for_sandbox(value, desc.writable()); |
||
608 |
define_prop_on_sandbox(&desc_for_sandbox); |
||
609 |
} else { |
||
610 |
20 |
PropertyDescriptor desc_for_sandbox(value); |
|
611 |
10 |
define_prop_on_sandbox(&desc_for_sandbox); |
|
612 |
} |
||
613 |
} |
||
614 |
} |
||
615 |
|||
616 |
// static |
||
617 |
2 |
void ContextifyContext::PropertyDeleterCallback( |
|
618 |
Local<Name> property, |
||
619 |
const PropertyCallbackInfo<Boolean>& args) { |
||
620 |
2 |
ContextifyContext* ctx = ContextifyContext::Get(args); |
|
621 |
|||
622 |
// Still initializing |
||
623 |
✗✓ | 3 |
if (IsStillInitializing(ctx)) return; |
624 |
|||
625 |
4 |
Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), property); |
|
626 |
|||
627 |
✓✗✓✓ |
4 |
if (success.FromMaybe(false)) |
628 |
1 |
return; |
|
629 |
|||
630 |
// Delete failed on the sandbox, intercept and do not delete on |
||
631 |
// the global object. |
||
632 |
✗✓ | 2 |
args.GetReturnValue().Set(false); |
633 |
} |
||
634 |
|||
635 |
// static |
||
636 |
260 |
void ContextifyContext::PropertyEnumeratorCallback( |
|
637 |
const PropertyCallbackInfo<Array>& args) { |
||
638 |
260 |
ContextifyContext* ctx = ContextifyContext::Get(args); |
|
639 |
|||
640 |
// Still initializing |
||
641 |
✗✓ | 260 |
if (IsStillInitializing(ctx)) return; |
642 |
|||
643 |
Local<Array> properties; |
||
644 |
|||
645 |
✗✓ | 780 |
if (!ctx->sandbox()->GetPropertyNames(ctx->context()).ToLocal(&properties)) |
646 |
return; |
||
647 |
|||
648 |
520 |
args.GetReturnValue().Set(properties); |
|
649 |
} |
||
650 |
|||
651 |
// static |
||
652 |
void ContextifyContext::IndexedPropertyGetterCallback( |
||
653 |
uint32_t index, |
||
654 |
const PropertyCallbackInfo<Value>& args) { |
||
655 |
ContextifyContext* ctx = ContextifyContext::Get(args); |
||
656 |
|||
657 |
// Still initializing |
||
658 |
if (IsStillInitializing(ctx)) return; |
||
659 |
|||
660 |
ContextifyContext::PropertyGetterCallback( |
||
661 |
Uint32ToName(ctx->context(), index), args); |
||
662 |
} |
||
663 |
|||
664 |
|||
665 |
1 |
void ContextifyContext::IndexedPropertySetterCallback( |
|
666 |
uint32_t index, |
||
667 |
Local<Value> value, |
||
668 |
const PropertyCallbackInfo<Value>& args) { |
||
669 |
1 |
ContextifyContext* ctx = ContextifyContext::Get(args); |
|
670 |
|||
671 |
// Still initializing |
||
672 |
✗✓ | 1 |
if (IsStillInitializing(ctx)) return; |
673 |
|||
674 |
1 |
ContextifyContext::PropertySetterCallback( |
|
675 |
Uint32ToName(ctx->context(), index), value, args); |
||
676 |
} |
||
677 |
|||
678 |
// static |
||
679 |
1 |
void ContextifyContext::IndexedPropertyDescriptorCallback( |
|
680 |
uint32_t index, |
||
681 |
const PropertyCallbackInfo<Value>& args) { |
||
682 |
1 |
ContextifyContext* ctx = ContextifyContext::Get(args); |
|
683 |
|||
684 |
// Still initializing |
||
685 |
✗✓ | 1 |
if (IsStillInitializing(ctx)) return; |
686 |
|||
687 |
1 |
ContextifyContext::PropertyDescriptorCallback( |
|
688 |
Uint32ToName(ctx->context(), index), args); |
||
689 |
} |
||
690 |
|||
691 |
|||
692 |
1 |
void ContextifyContext::IndexedPropertyDefinerCallback( |
|
693 |
uint32_t index, |
||
694 |
const PropertyDescriptor& desc, |
||
695 |
const PropertyCallbackInfo<Value>& args) { |
||
696 |
1 |
ContextifyContext* ctx = ContextifyContext::Get(args); |
|
697 |
|||
698 |
// Still initializing |
||
699 |
✗✓ | 1 |
if (IsStillInitializing(ctx)) return; |
700 |
|||
701 |
1 |
ContextifyContext::PropertyDefinerCallback( |
|
702 |
Uint32ToName(ctx->context(), index), desc, args); |
||
703 |
} |
||
704 |
|||
705 |
// static |
||
706 |
void ContextifyContext::IndexedPropertyDeleterCallback( |
||
707 |
uint32_t index, |
||
708 |
const PropertyCallbackInfo<Boolean>& args) { |
||
709 |
ContextifyContext* ctx = ContextifyContext::Get(args); |
||
710 |
|||
711 |
// Still initializing |
||
712 |
if (IsStillInitializing(ctx)) return; |
||
713 |
|||
714 |
Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), index); |
||
715 |
|||
716 |
if (success.FromMaybe(false)) |
||
717 |
return; |
||
718 |
|||
719 |
// Delete failed on the sandbox, intercept and do not delete on |
||
720 |
// the global object. |
||
721 |
args.GetReturnValue().Set(false); |
||
722 |
} |
||
723 |
|||
724 |
819 |
void ContextifyScript::Init(Environment* env, Local<Object> target) { |
|
725 |
819 |
Isolate* isolate = env->isolate(); |
|
726 |
1638 |
HandleScope scope(env->isolate()); |
|
727 |
Local<String> class_name = |
||
728 |
819 |
FIXED_ONE_BYTE_STRING(env->isolate(), "ContextifyScript"); |
|
729 |
|||
730 |
819 |
Local<FunctionTemplate> script_tmpl = NewFunctionTemplate(isolate, New); |
|
731 |
1638 |
script_tmpl->InstanceTemplate()->SetInternalFieldCount( |
|
732 |
ContextifyScript::kInternalFieldCount); |
||
733 |
819 |
script_tmpl->SetClassName(class_name); |
|
734 |
819 |
SetProtoMethod(isolate, script_tmpl, "createCachedData", CreateCachedData); |
|
735 |
819 |
SetProtoMethod(isolate, script_tmpl, "runInContext", RunInContext); |
|
736 |
|||
737 |
819 |
Local<Context> context = env->context(); |
|
738 |
|||
739 |
819 |
target->Set(context, class_name, |
|
740 |
1638 |
script_tmpl->GetFunction(context).ToLocalChecked()).Check(); |
|
741 |
819 |
env->set_script_context_constructor_template(script_tmpl); |
|
742 |
819 |
} |
|
743 |
|||
744 |
5717 |
void ContextifyScript::RegisterExternalReferences( |
|
745 |
ExternalReferenceRegistry* registry) { |
||
746 |
5717 |
registry->Register(New); |
|
747 |
5717 |
registry->Register(CreateCachedData); |
|
748 |
5717 |
registry->Register(RunInContext); |
|
749 |
5717 |
} |
|
750 |
|||
751 |
6155 |
void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) { |
|
752 |
6155 |
Environment* env = Environment::GetCurrent(args); |
|
753 |
6155 |
Isolate* isolate = env->isolate(); |
|
754 |
6155 |
Local<Context> context = env->context(); |
|
755 |
|||
756 |
✗✓ | 6155 |
CHECK(args.IsConstructCall()); |
757 |
|||
758 |
6155 |
const int argc = args.Length(); |
|
759 |
✗✓ | 6155 |
CHECK_GE(argc, 2); |
760 |
|||
761 |
✗✓ | 12310 |
CHECK(args[0]->IsString()); |
762 |
✓✗ | 12310 |
Local<String> code = args[0].As<String>(); |
763 |
|||
764 |
✗✓ | 12310 |
CHECK(args[1]->IsString()); |
765 |
6155 |
Local<String> filename = args[1].As<String>(); |
|
766 |
|||
767 |
6155 |
int line_offset = 0; |
|
768 |
✓✗ | 6155 |
int column_offset = 0; |
769 |
Local<ArrayBufferView> cached_data_buf; |
||
770 |
6155 |
bool produce_cached_data = false; |
|
771 |
6155 |
Local<Context> parsing_context = context; |
|
772 |
|||
773 |
✓✗ | 6155 |
if (argc > 2) { |
774 |
// new ContextifyScript(code, filename, lineOffset, columnOffset, |
||
775 |
// cachedData, produceCachedData, parsingContext) |
||
776 |
✗✓ | 6155 |
CHECK_EQ(argc, 7); |
777 |
✗✓ | 6155 |
CHECK(args[2]->IsNumber()); |
778 |
✓✗ | 12310 |
line_offset = args[2].As<Int32>()->Value(); |
779 |
✗✓ | 6155 |
CHECK(args[3]->IsNumber()); |
780 |
✓✗ | 12310 |
column_offset = args[3].As<Int32>()->Value(); |
781 |
✓✓ | 12310 |
if (!args[4]->IsUndefined()) { |
782 |
✗✓ | 25 |
CHECK(args[4]->IsArrayBufferView()); |
783 |
50 |
cached_data_buf = args[4].As<ArrayBufferView>(); |
|
784 |
} |
||
785 |
✗✓ | 6155 |
CHECK(args[5]->IsBoolean()); |
786 |
✓✗ | 6155 |
produce_cached_data = args[5]->IsTrue(); |
787 |
✓✓ | 12310 |
if (!args[6]->IsUndefined()) { |
788 |
✗✓ | 2561 |
CHECK(args[6]->IsObject()); |
789 |
ContextifyContext* sandbox = |
||
790 |
2561 |
ContextifyContext::ContextFromContextifiedSandbox( |
|
791 |
5122 |
env, args[6].As<Object>()); |
|
792 |
✗✓ | 2561 |
CHECK_NOT_NULL(sandbox); |
793 |
2561 |
parsing_context = sandbox->context(); |
|
794 |
} |
||
795 |
} |
||
796 |
|||
797 |
ContextifyScript* contextify_script = |
||
798 |
6155 |
new ContextifyScript(env, args.This()); |
|
799 |
|||
800 |
6155 |
if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( |
|
801 |
✓✓ | 6155 |
TRACING_CATEGORY_NODE2(vm, script)) != 0) { |
802 |
14 |
Utf8Value fn(isolate, filename); |
|
803 |
✓✗✓✗ |
14 |
TRACE_EVENT_BEGIN1(TRACING_CATEGORY_NODE2(vm, script), |
804 |
"ContextifyScript::New", |
||
805 |
"filename", |
||
806 |
TRACE_STR_COPY(*fn)); |
||
807 |
} |
||
808 |
|||
809 |
6155 |
ScriptCompiler::CachedData* cached_data = nullptr; |
|
810 |
✓✓ | 6155 |
if (!cached_data_buf.IsEmpty()) { |
811 |
50 |
uint8_t* data = static_cast<uint8_t*>(cached_data_buf->Buffer()->Data()); |
|
812 |
25 |
cached_data = new ScriptCompiler::CachedData( |
|
813 |
25 |
data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength()); |
|
814 |
} |
||
815 |
|||
816 |
Local<PrimitiveArray> host_defined_options = |
||
817 |
6155 |
PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength); |
|
818 |
12310 |
host_defined_options->Set(isolate, loader::HostDefinedOptions::kType, |
|
819 |
Number::New(isolate, loader::ScriptType::kScript)); |
||
820 |
12310 |
host_defined_options->Set(isolate, loader::HostDefinedOptions::kID, |
|
821 |
6155 |
Number::New(isolate, contextify_script->id())); |
|
822 |
|||
823 |
ScriptOrigin origin(isolate, |
||
824 |
filename, |
||
825 |
line_offset, // line offset |
||
826 |
column_offset, // column offset |
||
827 |
true, // is cross origin |
||
828 |
-1, // script id |
||
829 |
Local<Value>(), // source map URL |
||
830 |
false, // is opaque (?) |
||
831 |
false, // is WASM |
||
832 |
false, // is ES Module |
||
833 |
✓✗ | 12310 |
host_defined_options); |
834 |
6155 |
ScriptCompiler::Source source(code, origin, cached_data); |
|
835 |
6155 |
ScriptCompiler::CompileOptions compile_options = |
|
836 |
ScriptCompiler::kNoCompileOptions; |
||
837 |
|||
838 |
✓✓ | 6155 |
if (source.GetCachedData() != nullptr) |
839 |
25 |
compile_options = ScriptCompiler::kConsumeCodeCache; |
|
840 |
|||
841 |
6155 |
TryCatchScope try_catch(env); |
|
842 |
6155 |
ShouldNotAbortOnUncaughtScope no_abort_scope(env); |
|
843 |
6155 |
Context::Scope scope(parsing_context); |
|
844 |
|||
845 |
MaybeLocal<UnboundScript> maybe_v8_script = |
||
846 |
6155 |
ScriptCompiler::CompileUnboundScript(isolate, &source, compile_options); |
|
847 |
|||
848 |
Local<UnboundScript> v8_script; |
||
849 |
✓✓ | 6155 |
if (!maybe_v8_script.ToLocal(&v8_script)) { |
850 |
193 |
errors::DecorateErrorStack(env, try_catch); |
|
851 |
193 |
no_abort_scope.Close(); |
|
852 |
✓✗ | 193 |
if (!try_catch.HasTerminated()) |
853 |
193 |
try_catch.ReThrow(); |
|
854 |
✓✓✗✓ |
221 |
TRACE_EVENT_END0(TRACING_CATEGORY_NODE2(vm, script), |
855 |
"ContextifyScript::New"); |
||
856 |
193 |
return; |
|
857 |
} |
||
858 |
5962 |
contextify_script->script_.Reset(isolate, v8_script); |
|
859 |
|||
860 |
5962 |
Local<Context> env_context = env->context(); |
|
861 |
✓✓ | 5962 |
if (compile_options == ScriptCompiler::kConsumeCodeCache) { |
862 |
25 |
args.This()->Set( |
|
863 |
env_context, |
||
864 |
env->cached_data_rejected_string(), |
||
865 |
✓✓ | 100 |
Boolean::New(isolate, source.GetCachedData()->rejected)).Check(); |
866 |
✓✓ | 5937 |
} else if (produce_cached_data) { |
867 |
std::unique_ptr<ScriptCompiler::CachedData> cached_data{ |
||
868 |
6 |
ScriptCompiler::CreateCodeCache(v8_script)}; |
|
869 |
6 |
bool cached_data_produced = cached_data != nullptr; |
|
870 |
✓✗ | 6 |
if (cached_data_produced) { |
871 |
MaybeLocal<Object> buf = Buffer::Copy( |
||
872 |
env, |
||
873 |
12 |
reinterpret_cast<const char*>(cached_data->data), |
|
874 |
6 |
cached_data->length); |
|
875 |
6 |
args.This()->Set(env_context, |
|
876 |
env->cached_data_string(), |
||
877 |
✗✓ | 24 |
buf.ToLocalChecked()).Check(); |
878 |
} |
||
879 |
6 |
args.This()->Set( |
|
880 |
env_context, |
||
881 |
env->cached_data_produced_string(), |
||
882 |
✓✗ | 24 |
Boolean::New(isolate, cached_data_produced)).Check(); |
883 |
} |
||
884 |
|||
885 |
5962 |
args.This() |
|
886 |
5962 |
->Set(env_context, |
|
887 |
env->source_map_url_string(), |
||
888 |
17886 |
v8_script->GetSourceMappingURL()) |
|
889 |
.Check(); |
||
890 |
|||
891 |
✓✓✓✓ |
6778 |
TRACE_EVENT_END0(TRACING_CATEGORY_NODE2(vm, script), "ContextifyScript::New"); |
892 |
} |
||
893 |
|||
894 |
5936 |
bool ContextifyScript::InstanceOf(Environment* env, |
|
895 |
const Local<Value>& value) { |
||
896 |
✓✗✓✗ |
11872 |
return !value.IsEmpty() && |
897 |
17808 |
env->script_context_constructor_template()->HasInstance(value); |
|
898 |
} |
||
899 |
|||
900 |
11 |
void ContextifyScript::CreateCachedData( |
|
901 |
const FunctionCallbackInfo<Value>& args) { |
||
902 |
11 |
Environment* env = Environment::GetCurrent(args); |
|
903 |
ContextifyScript* wrapped_script; |
||
904 |
✗✓ | 11 |
ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder()); |
905 |
Local<UnboundScript> unbound_script = |
||
906 |
11 |
PersistentToLocal::Default(env->isolate(), wrapped_script->script_); |
|
907 |
std::unique_ptr<ScriptCompiler::CachedData> cached_data( |
||
908 |
22 |
ScriptCompiler::CreateCodeCache(unbound_script)); |
|
909 |
✗✓ | 11 |
if (!cached_data) { |
910 |
args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked()); |
||
911 |
} else { |
||
912 |
MaybeLocal<Object> buf = Buffer::Copy( |
||
913 |
env, |
||
914 |
22 |
reinterpret_cast<const char*>(cached_data->data), |
|
915 |
11 |
cached_data->length); |
|
916 |
✗✓ | 22 |
args.GetReturnValue().Set(buf.ToLocalChecked()); |
917 |
} |
||
918 |
} |
||
919 |
|||
920 |
5936 |
void ContextifyScript::RunInContext(const FunctionCallbackInfo<Value>& args) { |
|
921 |
5936 |
Environment* env = Environment::GetCurrent(args); |
|
922 |
|||
923 |
ContextifyScript* wrapped_script; |
||
924 |
✗✓ | 5936 |
ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder()); |
925 |
|||
926 |
✗✓ | 5936 |
CHECK_EQ(args.Length(), 5); |
927 |
✓✓✗✓ ✗✓ |
11986 |
CHECK(args[0]->IsObject() || args[0]->IsNull()); |
928 |
|||
929 |
Local<Context> context; |
||
930 |
✓✗ | 5936 |
std::shared_ptr<MicrotaskQueue> microtask_queue; |
931 |
|||
932 |
✓✓ | 5936 |
if (args[0]->IsObject()) { |
933 |
2911 |
Local<Object> sandbox = args[0].As<Object>(); |
|
934 |
// Get the context from the sandbox |
||
935 |
ContextifyContext* contextify_context = |
||
936 |
2911 |
ContextifyContext::ContextFromContextifiedSandbox(env, sandbox); |
|
937 |
✗✓ | 2911 |
CHECK_NOT_NULL(contextify_context); |
938 |
✗✓ | 2911 |
CHECK_EQ(contextify_context->env(), env); |
939 |
|||
940 |
2911 |
context = contextify_context->context(); |
|
941 |
✗✓ | 2911 |
if (context.IsEmpty()) return; |
942 |
|||
943 |
2911 |
microtask_queue = contextify_context->microtask_queue(); |
|
944 |
} else { |
||
945 |
3025 |
context = env->context(); |
|
946 |
} |
||
947 |
|||
948 |
✓✓✓✓ |
6749 |
TRACE_EVENT0(TRACING_CATEGORY_NODE2(vm, script), "RunInContext"); |
949 |
|||
950 |
✗✓ | 5936 |
CHECK(args[1]->IsNumber()); |
951 |
✓✗ | 11872 |
int64_t timeout = args[1]->IntegerValue(env->context()).FromJust(); |
952 |
|||
953 |
✗✓ | 5936 |
CHECK(args[2]->IsBoolean()); |
954 |
✓✗ | 5936 |
bool display_errors = args[2]->IsTrue(); |
955 |
|||
956 |
✗✓ | 5936 |
CHECK(args[3]->IsBoolean()); |
957 |
✓✗ | 5936 |
bool break_on_sigint = args[3]->IsTrue(); |
958 |
|||
959 |
✗✓ | 5936 |
CHECK(args[4]->IsBoolean()); |
960 |
5936 |
bool break_on_first_line = args[4]->IsTrue(); |
|
961 |
|||
962 |
// Do the eval within the context |
||
963 |
5936 |
EvalMachine(context, |
|
964 |
env, |
||
965 |
timeout, |
||
966 |
display_errors, |
||
967 |
break_on_sigint, |
||
968 |
break_on_first_line, |
||
969 |
microtask_queue, |
||
970 |
args); |
||
971 |
} |
||
972 |
|||
973 |
5936 |
bool ContextifyScript::EvalMachine(Local<Context> context, |
|
974 |
Environment* env, |
||
975 |
const int64_t timeout, |
||
976 |
const bool display_errors, |
||
977 |
const bool break_on_sigint, |
||
978 |
const bool break_on_first_line, |
||
979 |
std::shared_ptr<MicrotaskQueue> mtask_queue, |
||
980 |
const FunctionCallbackInfo<Value>& args) { |
||
981 |
5936 |
Context::Scope context_scope(context); |
|
982 |
|||
983 |
✗✓ | 5936 |
if (!env->can_call_into_js()) |
984 |
return false; |
||
985 |
✗✓ | 5936 |
if (!ContextifyScript::InstanceOf(env, args.Holder())) { |
986 |
THROW_ERR_INVALID_THIS( |
||
987 |
env, |
||
988 |
"Script methods can only be called on script instances."); |
||
989 |
return false; |
||
990 |
} |
||
991 |
|||
992 |
11856 |
TryCatchScope try_catch(env); |
|
993 |
11856 |
Isolate::SafeForTerminationScope safe_for_termination(env->isolate()); |
|
994 |
ContextifyScript* wrapped_script; |
||
995 |
✗✓ | 5936 |
ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder(), false); |
996 |
Local<UnboundScript> unbound_script = |
||
997 |
5936 |
PersistentToLocal::Default(env->isolate(), wrapped_script->script_); |
|
998 |
5936 |
Local<Script> script = unbound_script->BindToCurrentContext(); |
|
999 |
|||
1000 |
#if HAVE_INSPECTOR |
||
1001 |
✓✓ | 5936 |
if (break_on_first_line) { |
1002 |
10 |
env->inspector_agent()->PauseOnNextJavascriptStatement("Break on start"); |
|
1003 |
} |
||
1004 |
#endif |
||
1005 |
|||
1006 |
MaybeLocal<Value> result; |
||
1007 |
5936 |
bool timed_out = false; |
|
1008 |
5936 |
bool received_signal = false; |
|
1009 |
5936 |
auto run = [&]() { |
|
1010 |
5936 |
MaybeLocal<Value> result = script->Run(context); |
|
1011 |
✓✓✓✓ ✓✓ |
5920 |
if (!result.IsEmpty() && mtask_queue) |
1012 |
2 |
mtask_queue->PerformCheckpoint(env->isolate()); |
|
1013 |
5920 |
return result; |
|
1014 |
5936 |
}; |
|
1015 |
✓✓✗✓ |
5936 |
if (break_on_sigint && timeout != -1) { |
1016 |
Watchdog wd(env->isolate(), timeout, &timed_out); |
||
1017 |
SigintWatchdog swd(env->isolate(), &received_signal); |
||
1018 |
result = run(); |
||
1019 |
✓✓ | 5936 |
} else if (break_on_sigint) { |
1020 |
2399 |
SigintWatchdog swd(env->isolate(), &received_signal); |
|
1021 |
1201 |
result = run(); |
|
1022 |
✓✓ | 4735 |
} else if (timeout != -1) { |
1023 |
30 |
Watchdog wd(env->isolate(), timeout, &timed_out); |
|
1024 |
15 |
result = run(); |
|
1025 |
} else { |
||
1026 |
4720 |
result = run(); |
|
1027 |
} |
||
1028 |
|||
1029 |
// Convert the termination exception into a regular exception. |
||
1030 |
✓✓✓✓ |
5920 |
if (timed_out || received_signal) { |
1031 |
✗✓✗✗ ✗✓ |
21 |
if (!env->is_main_thread() && env->is_stopping()) |
1032 |
return false; |
||
1033 |
21 |
env->isolate()->CancelTerminateExecution(); |
|
1034 |
// It is possible that execution was terminated by another timeout in |
||
1035 |
// which this timeout is nested, so check whether one of the watchdogs |
||
1036 |
// from this invocation is responsible for termination. |
||
1037 |
✓✓ | 21 |
if (timed_out) { |
1038 |
10 |
node::THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout); |
|
1039 |
✓✗ | 11 |
} else if (received_signal) { |
1040 |
11 |
node::THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env); |
|
1041 |
} |
||
1042 |
} |
||
1043 |
|||
1044 |
✓✓ | 5920 |
if (try_catch.HasCaught()) { |
1045 |
✓✓✓✓ ✓✓ |
160 |
if (!timed_out && !received_signal && display_errors) { |
1046 |
// We should decorate non-termination exceptions |
||
1047 |
87 |
errors::DecorateErrorStack(env, try_catch); |
|
1048 |
} |
||
1049 |
|||
1050 |
// If there was an exception thrown during script execution, re-throw it. |
||
1051 |
// If one of the above checks threw, re-throw the exception instead of |
||
1052 |
// letting try_catch catch it. |
||
1053 |
// If execution has been terminated, but not by one of the watchdogs from |
||
1054 |
// this invocation, this will re-throw a `null` value. |
||
1055 |
✓✓ | 160 |
if (!try_catch.HasTerminated()) |
1056 |
157 |
try_catch.ReThrow(); |
|
1057 |
|||
1058 |
160 |
return false; |
|
1059 |
} |
||
1060 |
|||
1061 |
✗✓ | 5760 |
args.GetReturnValue().Set(result.ToLocalChecked()); |
1062 |
5760 |
return true; |
|
1063 |
} |
||
1064 |
|||
1065 |
|||
1066 |
6155 |
ContextifyScript::ContextifyScript(Environment* env, Local<Object> object) |
|
1067 |
: BaseObject(env, object), |
||
1068 |
6155 |
id_(env->get_next_script_id()) { |
|
1069 |
6155 |
MakeWeak(); |
|
1070 |
6155 |
env->id_to_script_map.emplace(id_, this); |
|
1071 |
6155 |
} |
|
1072 |
|||
1073 |
|||
1074 |
36072 |
ContextifyScript::~ContextifyScript() { |
|
1075 |
12024 |
env()->id_to_script_map.erase(id_); |
|
1076 |
24048 |
} |
|
1077 |
|||
1078 |
|||
1079 |
36714 |
void ContextifyContext::CompileFunction( |
|
1080 |
const FunctionCallbackInfo<Value>& args) { |
||
1081 |
36714 |
Environment* env = Environment::GetCurrent(args); |
|
1082 |
36714 |
Isolate* isolate = env->isolate(); |
|
1083 |
36714 |
Local<Context> context = env->context(); |
|
1084 |
|||
1085 |
// Argument 1: source code |
||
1086 |
✗✓ | 73428 |
CHECK(args[0]->IsString()); |
1087 |
✓✗ | 73428 |
Local<String> code = args[0].As<String>(); |
1088 |
|||
1089 |
// Argument 2: filename |
||
1090 |
✗✓ | 73428 |
CHECK(args[1]->IsString()); |
1091 |
✓✗ | 73428 |
Local<String> filename = args[1].As<String>(); |
1092 |
|||
1093 |
// Argument 3: line offset |
||
1094 |
✗✓ | 36714 |
CHECK(args[2]->IsNumber()); |
1095 |
✓✗ | 73428 |
int line_offset = args[2].As<Int32>()->Value(); |
1096 |
|||
1097 |
// Argument 4: column offset |
||
1098 |
✗✓ | 36714 |
CHECK(args[3]->IsNumber()); |
1099 |
✓✗ | 73428 |
int column_offset = args[3].As<Int32>()->Value(); |
1100 |
|||
1101 |
// Argument 5: cached data (optional) |
||
1102 |
Local<ArrayBufferView> cached_data_buf; |
||
1103 |
✗✓ | 73428 |
if (!args[4]->IsUndefined()) { |
1104 |
CHECK(args[4]->IsArrayBufferView()); |
||
1105 |
cached_data_buf = args[4].As<ArrayBufferView>(); |
||
1106 |
} |
||
1107 |
|||
1108 |
// Argument 6: produce cache data |
||
1109 |
✗✓ | 36714 |
CHECK(args[5]->IsBoolean()); |
1110 |
✓✗ | 36714 |
bool produce_cached_data = args[5]->IsTrue(); |
1111 |
|||
1112 |
// Argument 7: parsing context (optional) |
||
1113 |
Local<Context> parsing_context; |
||
1114 |
✓✓ | 73428 |
if (!args[6]->IsUndefined()) { |
1115 |
✗✓ | 2 |
CHECK(args[6]->IsObject()); |
1116 |
ContextifyContext* sandbox = |
||
1117 |
2 |
ContextifyContext::ContextFromContextifiedSandbox( |
|
1118 |
4 |
env, args[6].As<Object>()); |
|
1119 |
✗✓ | 2 |
CHECK_NOT_NULL(sandbox); |
1120 |
2 |
parsing_context = sandbox->context(); |
|
1121 |
} else { |
||
1122 |
36712 |
parsing_context = context; |
|
1123 |
} |
||
1124 |
|||
1125 |
// Argument 8: context extensions (optional) |
||
1126 |
Local<Array> context_extensions_buf; |
||
1127 |
✓✗ | 73428 |
if (!args[7]->IsUndefined()) { |
1128 |
✗✓ | 36714 |
CHECK(args[7]->IsArray()); |
1129 |
73428 |
context_extensions_buf = args[7].As<Array>(); |
|
1130 |
} |
||
1131 |
|||
1132 |
// Argument 9: params for the function (optional) |
||
1133 |
Local<Array> params_buf; |
||
1134 |
✓✓ | 73428 |
if (!args[8]->IsUndefined()) { |
1135 |
✗✓ | 36707 |
CHECK(args[8]->IsArray()); |
1136 |
73414 |
params_buf = args[8].As<Array>(); |
|
1137 |
} |
||
1138 |
|||
1139 |
// Read cache from cached data buffer |
||
1140 |
36714 |
ScriptCompiler::CachedData* cached_data = nullptr; |
|
1141 |
✗✓ | 36714 |
if (!cached_data_buf.IsEmpty()) { |
1142 |
uint8_t* data = static_cast<uint8_t*>(cached_data_buf->Buffer()->Data()); |
||
1143 |
cached_data = new ScriptCompiler::CachedData( |
||
1144 |
data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength()); |
||
1145 |
} |
||
1146 |
|||
1147 |
// Get the function id |
||
1148 |
36714 |
uint32_t id = env->get_next_function_id(); |
|
1149 |
|||
1150 |
// Set host_defined_options |
||
1151 |
Local<PrimitiveArray> host_defined_options = |
||
1152 |
36714 |
PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength); |
|
1153 |
73428 |
host_defined_options->Set( |
|
1154 |
isolate, |
||
1155 |
loader::HostDefinedOptions::kType, |
||
1156 |
Number::New(isolate, loader::ScriptType::kFunction)); |
||
1157 |
73428 |
host_defined_options->Set( |
|
1158 |
isolate, loader::HostDefinedOptions::kID, Number::New(isolate, id)); |
||
1159 |
|||
1160 |
ScriptOrigin origin(isolate, |
||
1161 |
filename, |
||
1162 |
line_offset, // line offset |
||
1163 |
column_offset, // column offset |
||
1164 |
true, // is cross origin |
||
1165 |
-1, // script id |
||
1166 |
Local<Value>(), // source map URL |
||
1167 |
false, // is opaque (?) |
||
1168 |
false, // is WASM |
||
1169 |
false, // is ES Module |
||
1170 |
✓✗ | 73428 |
host_defined_options); |
1171 |
|||
1172 |
36714 |
ScriptCompiler::Source source(code, origin, cached_data); |
|
1173 |
ScriptCompiler::CompileOptions options; |
||
1174 |
✓✗ | 36714 |
if (source.GetCachedData() == nullptr) { |
1175 |
36714 |
options = ScriptCompiler::kNoCompileOptions; |
|
1176 |
} else { |
||
1177 |
options = ScriptCompiler::kConsumeCodeCache; |
||
1178 |
} |
||
1179 |
|||
1180 |
36714 |
TryCatchScope try_catch(env); |
|
1181 |
36714 |
Context::Scope scope(parsing_context); |
|
1182 |
|||
1183 |
// Read context extensions from buffer |
||
1184 |
36714 |
std::vector<Local<Object>> context_extensions; |
|
1185 |
✓✗ | 36714 |
if (!context_extensions_buf.IsEmpty()) { |
1186 |
✓✓ | 73429 |
for (uint32_t n = 0; n < context_extensions_buf->Length(); n++) { |
1187 |
Local<Value> val; |
||
1188 |
✗✓ | 2 |
if (!context_extensions_buf->Get(context, n).ToLocal(&val)) return; |
1189 |
✗✓ | 1 |
CHECK(val->IsObject()); |
1190 |
1 |
context_extensions.push_back(val.As<Object>()); |
|
1191 |
} |
||
1192 |
} |
||
1193 |
|||
1194 |
// Read params from params buffer |
||
1195 |
36714 |
std::vector<Local<String>> params; |
|
1196 |
✓✓ | 36714 |
if (!params_buf.IsEmpty()) { |
1197 |
✓✓ | 256899 |
for (uint32_t n = 0; n < params_buf->Length(); n++) { |
1198 |
Local<Value> val; |
||
1199 |
✗✓ | 366970 |
if (!params_buf->Get(context, n).ToLocal(&val)) return; |
1200 |
✗✓ | 366970 |
CHECK(val->IsString()); |
1201 |
183485 |
params.push_back(val.As<String>()); |
|
1202 |
} |
||
1203 |
} |
||
1204 |
|||
1205 |
MaybeLocal<Function> maybe_fn = ScriptCompiler::CompileFunction( |
||
1206 |
parsing_context, |
||
1207 |
&source, |
||
1208 |
params.size(), |
||
1209 |
params.data(), |
||
1210 |
context_extensions.size(), |
||
1211 |
context_extensions.data(), |
||
1212 |
options, |
||
1213 |
36714 |
v8::ScriptCompiler::NoCacheReason::kNoCacheNoReason); |
|
1214 |
|||
1215 |
Local<Function> fn; |
||
1216 |
✓✓ | 36714 |
if (!maybe_fn.ToLocal(&fn)) { |
1217 |
✓✗✓✗ ✓✗ |
29 |
if (try_catch.HasCaught() && !try_catch.HasTerminated()) { |
1218 |
29 |
errors::DecorateErrorStack(env, try_catch); |
|
1219 |
29 |
try_catch.ReThrow(); |
|
1220 |
} |
||
1221 |
29 |
return; |
|
1222 |
} |
||
1223 |
|||
1224 |
Local<Object> cache_key; |
||
1225 |
36685 |
if (!env->compiled_fn_entry_template()->NewInstance( |
|
1226 |
✗✓ | 73370 |
context).ToLocal(&cache_key)) { |
1227 |
return; |
||
1228 |
} |
||
1229 |
36685 |
CompiledFnEntry* entry = new CompiledFnEntry(env, cache_key, id, fn); |
|
1230 |
36685 |
env->id_to_function_map.emplace(id, entry); |
|
1231 |
|||
1232 |
36685 |
Local<Object> result = Object::New(isolate); |
|
1233 |
✗✓ | 110055 |
if (result->Set(parsing_context, env->function_string(), fn).IsNothing()) |
1234 |
return; |
||
1235 |
73370 |
if (result->Set(parsing_context, env->cache_key_string(), cache_key) |
|
1236 |
✗✓ | 36685 |
.IsNothing()) |
1237 |
return; |
||
1238 |
36685 |
if (result |
|
1239 |
36685 |
->Set(parsing_context, |
|
1240 |
env->source_map_url_string(), |
||
1241 |
110055 |
fn->GetScriptOrigin().SourceMapUrl()) |
|
1242 |
✗✓ | 36685 |
.IsNothing()) |
1243 |
return; |
||
1244 |
|||
1245 |
✓✓ | 36685 |
if (produce_cached_data) { |
1246 |
const std::unique_ptr<ScriptCompiler::CachedData> cached_data( |
||
1247 |
1 |
ScriptCompiler::CreateCodeCacheForFunction(fn)); |
|
1248 |
1 |
bool cached_data_produced = cached_data != nullptr; |
|
1249 |
✓✗ | 1 |
if (cached_data_produced) { |
1250 |
MaybeLocal<Object> buf = Buffer::Copy( |
||
1251 |
env, |
||
1252 |
2 |
reinterpret_cast<const char*>(cached_data->data), |
|
1253 |
1 |
cached_data->length); |
|
1254 |
1 |
if (result |
|
1255 |
1 |
->Set(parsing_context, |
|
1256 |
env->cached_data_string(), |
||
1257 |
✗✓ | 3 |
buf.ToLocalChecked()) |
1258 |
✗✓ | 1 |
.IsNothing()) |
1259 |
return; |
||
1260 |
} |
||
1261 |
1 |
if (result |
|
1262 |
1 |
->Set(parsing_context, |
|
1263 |
env->cached_data_produced_string(), |
||
1264 |
✓✗ | 3 |
Boolean::New(isolate, cached_data_produced)) |
1265 |
✗✓ | 1 |
.IsNothing()) |
1266 |
return; |
||
1267 |
} |
||
1268 |
|||
1269 |
73370 |
args.GetReturnValue().Set(result); |
|
1270 |
} |
||
1271 |
|||
1272 |
5 |
void CompiledFnEntry::WeakCallback( |
|
1273 |
const WeakCallbackInfo<CompiledFnEntry>& data) { |
||
1274 |
5 |
CompiledFnEntry* entry = data.GetParameter(); |
|
1275 |
✓✗ | 5 |
delete entry; |
1276 |
5 |
} |
|
1277 |
|||
1278 |
36685 |
CompiledFnEntry::CompiledFnEntry(Environment* env, |
|
1279 |
Local<Object> object, |
||
1280 |
uint32_t id, |
||
1281 |
36685 |
Local<Function> fn) |
|
1282 |
36685 |
: BaseObject(env, object), id_(id), fn_(env->isolate(), fn) { |
|
1283 |
36685 |
fn_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter); |
|
1284 |
36685 |
} |
|
1285 |
|||
1286 |
206652 |
CompiledFnEntry::~CompiledFnEntry() { |
|
1287 |
68884 |
env()->id_to_function_map.erase(id_); |
|
1288 |
68884 |
fn_.ClearWeak(); |
|
1289 |
137768 |
} |
|
1290 |
|||
1291 |
197 |
static void StartSigintWatchdog(const FunctionCallbackInfo<Value>& args) { |
|
1292 |
197 |
int ret = SigintWatchdogHelper::GetInstance()->Start(); |
|
1293 |
✓✗ | 197 |
args.GetReturnValue().Set(ret == 0); |
1294 |
197 |
} |
|
1295 |
|||
1296 |
194 |
static void StopSigintWatchdog(const FunctionCallbackInfo<Value>& args) { |
|
1297 |
194 |
bool had_pending_signals = SigintWatchdogHelper::GetInstance()->Stop(); |
|
1298 |
✓✓ | 194 |
args.GetReturnValue().Set(had_pending_signals); |
1299 |
194 |
} |
|
1300 |
|||
1301 |
3 |
static void WatchdogHasPendingSigint(const FunctionCallbackInfo<Value>& args) { |
|
1302 |
3 |
bool ret = SigintWatchdogHelper::GetInstance()->HasPendingSignal(); |
|
1303 |
✓✗ | 3 |
args.GetReturnValue().Set(ret); |
1304 |
3 |
} |
|
1305 |
|||
1306 |
✓✗ | 8 |
static void MeasureMemory(const FunctionCallbackInfo<Value>& args) { |
1307 |
✗✓ | 8 |
CHECK(args[0]->IsInt32()); |
1308 |
✗✓ | 8 |
CHECK(args[1]->IsInt32()); |
1309 |
✓✗ | 16 |
int32_t mode = args[0].As<v8::Int32>()->Value(); |
1310 |
16 |
int32_t execution = args[1].As<v8::Int32>()->Value(); |
|
1311 |
8 |
Isolate* isolate = args.GetIsolate(); |
|
1312 |
|||
1313 |
8 |
Local<Context> current_context = isolate->GetCurrentContext(); |
|
1314 |
Local<Promise::Resolver> resolver; |
||
1315 |
✗✓ | 16 |
if (!Promise::Resolver::New(current_context).ToLocal(&resolver)) return; |
1316 |
std::unique_ptr<v8::MeasureMemoryDelegate> delegate = |
||
1317 |
v8::MeasureMemoryDelegate::Default( |
||
1318 |
isolate, |
||
1319 |
current_context, |
||
1320 |
resolver, |
||
1321 |
8 |
static_cast<v8::MeasureMemoryMode>(mode)); |
|
1322 |
8 |
isolate->MeasureMemory(std::move(delegate), |
|
1323 |
static_cast<v8::MeasureMemoryExecution>(execution)); |
||
1324 |
8 |
Local<Promise> promise = resolver->GetPromise(); |
|
1325 |
|||
1326 |
16 |
args.GetReturnValue().Set(promise); |
|
1327 |
} |
||
1328 |
|||
1329 |
5 |
MicrotaskQueueWrap::MicrotaskQueueWrap(Environment* env, Local<Object> obj) |
|
1330 |
: BaseObject(env, obj), |
||
1331 |
microtask_queue_( |
||
1332 |
5 |
MicrotaskQueue::New(env->isolate(), MicrotasksPolicy::kExplicit)) { |
|
1333 |
5 |
MakeWeak(); |
|
1334 |
5 |
} |
|
1335 |
|||
1336 |
const std::shared_ptr<MicrotaskQueue>& |
||
1337 |
10 |
MicrotaskQueueWrap::microtask_queue() const { |
|
1338 |
10 |
return microtask_queue_; |
|
1339 |
} |
||
1340 |
|||
1341 |
5 |
void MicrotaskQueueWrap::New(const FunctionCallbackInfo<Value>& args) { |
|
1342 |
✗✓ | 5 |
CHECK(args.IsConstructCall()); |
1343 |
10 |
new MicrotaskQueueWrap(Environment::GetCurrent(args), args.This()); |
|
1344 |
5 |
} |
|
1345 |
|||
1346 |
819 |
void MicrotaskQueueWrap::Init(Environment* env, Local<Object> target) { |
|
1347 |
819 |
Isolate* isolate = env->isolate(); |
|
1348 |
1638 |
HandleScope scope(isolate); |
|
1349 |
819 |
Local<Context> context = env->context(); |
|
1350 |
819 |
Local<FunctionTemplate> tmpl = NewFunctionTemplate(isolate, New); |
|
1351 |
1638 |
tmpl->InstanceTemplate()->SetInternalFieldCount( |
|
1352 |
ContextifyScript::kInternalFieldCount); |
||
1353 |
819 |
env->set_microtask_queue_ctor_template(tmpl); |
|
1354 |
819 |
SetConstructorFunction(context, target, "MicrotaskQueue", tmpl); |
|
1355 |
819 |
} |
|
1356 |
|||
1357 |
5717 |
void MicrotaskQueueWrap::RegisterExternalReferences( |
|
1358 |
ExternalReferenceRegistry* registry) { |
||
1359 |
5717 |
registry->Register(New); |
|
1360 |
5717 |
} |
|
1361 |
|||
1362 |
819 |
void Initialize(Local<Object> target, |
|
1363 |
Local<Value> unused, |
||
1364 |
Local<Context> context, |
||
1365 |
void* priv) { |
||
1366 |
819 |
Environment* env = Environment::GetCurrent(context); |
|
1367 |
819 |
Isolate* isolate = env->isolate(); |
|
1368 |
819 |
ContextifyContext::Init(env, target); |
|
1369 |
819 |
ContextifyScript::Init(env, target); |
|
1370 |
819 |
MicrotaskQueueWrap::Init(env, target); |
|
1371 |
|||
1372 |
819 |
SetMethod(context, target, "startSigintWatchdog", StartSigintWatchdog); |
|
1373 |
819 |
SetMethod(context, target, "stopSigintWatchdog", StopSigintWatchdog); |
|
1374 |
// Used in tests. |
||
1375 |
819 |
SetMethodNoSideEffect( |
|
1376 |
context, target, "watchdogHasPendingSigint", WatchdogHasPendingSigint); |
||
1377 |
|||
1378 |
{ |
||
1379 |
819 |
Local<FunctionTemplate> tpl = FunctionTemplate::New(env->isolate()); |
|
1380 |
819 |
tpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "CompiledFnEntry")); |
|
1381 |
1638 |
tpl->InstanceTemplate()->SetInternalFieldCount( |
|
1382 |
CompiledFnEntry::kInternalFieldCount); |
||
1383 |
|||
1384 |
819 |
env->set_compiled_fn_entry_template(tpl->InstanceTemplate()); |
|
1385 |
} |
||
1386 |
|||
1387 |
819 |
Local<Object> constants = Object::New(env->isolate()); |
|
1388 |
819 |
Local<Object> measure_memory = Object::New(env->isolate()); |
|
1389 |
819 |
Local<Object> memory_execution = Object::New(env->isolate()); |
|
1390 |
|||
1391 |
{ |
||
1392 |
819 |
Local<Object> memory_mode = Object::New(env->isolate()); |
|
1393 |
819 |
MeasureMemoryMode SUMMARY = MeasureMemoryMode::kSummary; |
|
1394 |
819 |
MeasureMemoryMode DETAILED = MeasureMemoryMode::kDetailed; |
|
1395 |
2457 |
NODE_DEFINE_CONSTANT(memory_mode, SUMMARY); |
|
1396 |
2457 |
NODE_DEFINE_CONSTANT(memory_mode, DETAILED); |
|
1397 |
1638 |
READONLY_PROPERTY(measure_memory, "mode", memory_mode); |
|
1398 |
} |
||
1399 |
|||
1400 |
{ |
||
1401 |
819 |
MeasureMemoryExecution DEFAULT = MeasureMemoryExecution::kDefault; |
|
1402 |
819 |
MeasureMemoryExecution EAGER = MeasureMemoryExecution::kEager; |
|
1403 |
2457 |
NODE_DEFINE_CONSTANT(memory_execution, DEFAULT); |
|
1404 |
2457 |
NODE_DEFINE_CONSTANT(memory_execution, EAGER); |
|
1405 |
2457 |
READONLY_PROPERTY(measure_memory, "execution", memory_execution); |
|
1406 |
} |
||
1407 |
|||
1408 |
2457 |
READONLY_PROPERTY(constants, "measureMemory", measure_memory); |
|
1409 |
|||
1410 |
1638 |
target->Set(context, env->constants_string(), constants).Check(); |
|
1411 |
|||
1412 |
819 |
SetMethod(context, target, "measureMemory", MeasureMemory); |
|
1413 |
819 |
} |
|
1414 |
|||
1415 |
5717 |
void RegisterExternalReferences(ExternalReferenceRegistry* registry) { |
|
1416 |
5717 |
ContextifyContext::RegisterExternalReferences(registry); |
|
1417 |
5717 |
ContextifyScript::RegisterExternalReferences(registry); |
|
1418 |
5717 |
MicrotaskQueueWrap::RegisterExternalReferences(registry); |
|
1419 |
|||
1420 |
5717 |
registry->Register(StartSigintWatchdog); |
|
1421 |
5717 |
registry->Register(StopSigintWatchdog); |
|
1422 |
5717 |
registry->Register(WatchdogHasPendingSigint); |
|
1423 |
5717 |
registry->Register(MeasureMemory); |
|
1424 |
5717 |
} |
|
1425 |
} // namespace contextify |
||
1426 |
} // namespace node |
||
1427 |
|||
1428 |
5788 |
NODE_BINDING_CONTEXT_AWARE_INTERNAL(contextify, node::contextify::Initialize) |
|
1429 |
5717 |
NODE_BINDING_EXTERNAL_REFERENCE(contextify, |
|
1430 |
node::contextify::RegisterExternalReferences) |
Generated by: GCOVR (Version 4.2) |