GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_contextify.cc Lines: 578 632 91.5 %
Date: 2022-07-31 04:16:25 Branches: 283 444 63.7 %

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_watchdog.h"
32
#include "util-inl.h"
33
34
namespace node {
35
namespace contextify {
36
37
using errors::TryCatchScope;
38
39
using v8::Array;
40
using v8::ArrayBufferView;
41
using v8::Boolean;
42
using v8::Context;
43
using v8::EscapableHandleScope;
44
using v8::External;
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::ScriptOrModule;
74
using v8::String;
75
using v8::Uint32;
76
using v8::UnboundScript;
77
using v8::Value;
78
using v8::WeakCallbackInfo;
79
using v8::WeakCallbackType;
80
81
// The vm module executes code in a sandboxed environment with a different
82
// global object than the rest of the code. This is achieved by applying
83
// every call that changes or queries a property on the global `this` in the
84
// sandboxed code, to the sandbox object.
85
//
86
// The implementation uses V8's interceptors for methods like `set`, `get`,
87
// `delete`, `defineProperty`, and for any query of the property attributes.
88
// Property handlers with interceptors are set on the object template for
89
// the sandboxed code. Handlers for both named properties and for indexed
90
// properties are used. Their functionality is almost identical, the indexed
91
// interceptors mostly just call the named interceptors.
92
//
93
// For every `get` of a global property in the sandboxed context, the
94
// interceptor callback checks the sandbox object for the property.
95
// If the property is defined on the sandbox, that result is returned to
96
// the original call instead of finishing the query on the global object.
97
//
98
// For every `set` of a global property, the interceptor callback defines or
99
// changes the property both on the sandbox and the global proxy.
100
101
namespace {
102
103
// Convert an int to a V8 Name (String or Symbol).
104
3
Local<Name> Uint32ToName(Local<Context> context, uint32_t index) {
105
6
  return Uint32::New(context->GetIsolate(), index)->ToString(context)
106
3
      .ToLocalChecked();
107
}
108
109
}  // anonymous namespace
110
111
616
ContextifyContext::ContextifyContext(
112
    Environment* env,
113
    Local<Object> sandbox_obj,
114
616
    const ContextOptions& options)
115
  : env_(env),
116
1232
    microtask_queue_wrap_(options.microtask_queue_wrap) {
117
616
  MaybeLocal<Context> v8_context = CreateV8Context(env, sandbox_obj, options);
118
119
  // Allocation failure, maximum call stack size reached, termination, etc.
120
616
  if (v8_context.IsEmpty()) return;
121
122
1232
  context_.Reset(env->isolate(), v8_context.ToLocalChecked());
123
616
  context_.SetWeak(this, WeakCallback, WeakCallbackType::kParameter);
124
616
  env->AddCleanupHook(CleanupHook, this);
125
}
126
127
128
504
ContextifyContext::~ContextifyContext() {
129
504
  env()->RemoveCleanupHook(CleanupHook, this);
130
504
  Isolate* isolate = env()->isolate();
131
1008
  HandleScope scope(isolate);
132
133
  env()->async_hooks()
134
504
    ->RemoveContext(PersistentToLocal::Weak(isolate, context_));
135
504
}
136
137
138
441
void ContextifyContext::CleanupHook(void* arg) {
139
441
  ContextifyContext* self = static_cast<ContextifyContext*>(arg);
140
441
  self->context_.Reset();
141
441
  delete self;
142
441
}
143
144
145
// This is an object that just keeps an internal pointer to this
146
// ContextifyContext.  It's passed to the NamedPropertyHandler.  If we
147
// pass the main JavaScript context object we're embedded in, then the
148
// NamedPropertyHandler will store a reference to it forever and keep it
149
// from getting gc'd.
150
616
MaybeLocal<Object> ContextifyContext::CreateDataWrapper(Environment* env) {
151
  Local<Object> wrapper;
152
616
  if (!env->script_data_constructor_function()
153
616
           ->NewInstance(env->context())
154
616
           .ToLocal(&wrapper)) {
155
    return MaybeLocal<Object>();
156
  }
157
158
616
  wrapper->SetAlignedPointerInInternalField(ContextifyContext::kSlot, this);
159
616
  return wrapper;
160
}
161
162
616
MaybeLocal<Context> ContextifyContext::CreateV8Context(
163
    Environment* env,
164
    Local<Object> sandbox_obj,
165
    const ContextOptions& options) {
166
616
  EscapableHandleScope scope(env->isolate());
167
  Local<FunctionTemplate> function_template =
168
616
      FunctionTemplate::New(env->isolate());
169
170
616
  function_template->SetClassName(sandbox_obj->GetConstructorName());
171
172
  Local<ObjectTemplate> object_template =
173
616
      function_template->InstanceTemplate();
174
175
  Local<Object> data_wrapper;
176
1232
  if (!CreateDataWrapper(env).ToLocal(&data_wrapper))
177
    return MaybeLocal<Context>();
178
179
  NamedPropertyHandlerConfiguration config(
180
      PropertyGetterCallback,
181
      PropertySetterCallback,
182
      PropertyDescriptorCallback,
183
      PropertyDeleterCallback,
184
      PropertyEnumeratorCallback,
185
      PropertyDefinerCallback,
186
      data_wrapper,
187
616
      PropertyHandlerFlags::kHasNoSideEffect);
188
189
  IndexedPropertyHandlerConfiguration indexed_config(
190
      IndexedPropertyGetterCallback,
191
      IndexedPropertySetterCallback,
192
      IndexedPropertyDescriptorCallback,
193
      IndexedPropertyDeleterCallback,
194
      PropertyEnumeratorCallback,
195
      IndexedPropertyDefinerCallback,
196
      data_wrapper,
197
616
      PropertyHandlerFlags::kHasNoSideEffect);
198
199
616
  object_template->SetHandler(config);
200
616
  object_template->SetHandler(indexed_config);
201
  Local<Context> ctx = Context::New(
202
      env->isolate(),
203
      nullptr,  // extensions
204
      object_template,
205
      {},       // global object
206
      {},       // deserialization callback
207
1232
      microtask_queue() ?
208
621
          microtask_queue().get() :
209

1848
          env->isolate()->GetCurrentContext()->GetMicrotaskQueue());
210
616
  if (ctx.IsEmpty()) return MaybeLocal<Context>();
211
  // Only partially initialize the context - the primordials are left out
212
  // and only initialized when necessary.
213
1232
  if (InitializeContextRuntime(ctx).IsNothing()) {
214
    return MaybeLocal<Context>();
215
  }
216
217
616
  if (ctx.IsEmpty()) {
218
    return MaybeLocal<Context>();
219
  }
220
221
616
  Local<Context> context = env->context();
222
616
  ctx->SetSecurityToken(context->GetSecurityToken());
223
224
  // We need to tie the lifetime of the sandbox object with the lifetime of
225
  // newly created context. We do this by making them hold references to each
226
  // other. The context can directly hold a reference to the sandbox as an
227
  // embedder data field. However, we cannot hold a reference to a v8::Context
228
  // directly in an Object, we instead hold onto the new context's global
229
  // object instead (which then has a reference to the context).
230
616
  ctx->SetEmbedderData(ContextEmbedderIndex::kSandboxObject, sandbox_obj);
231
  sandbox_obj->SetPrivate(context,
232
                          env->contextify_global_private_symbol(),
233
1232
                          ctx->Global());
234
235
1232
  Utf8Value name_val(env->isolate(), options.name);
236
  // Delegate the code generation validation to
237
  // node::ModifyCodeGenerationFromStrings.
238
616
  ctx->AllowCodeGenerationFromStrings(false);
239
616
  ctx->SetEmbedderData(ContextEmbedderIndex::kAllowCodeGenerationFromStrings,
240
                       options.allow_code_gen_strings);
241
616
  ctx->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
242
                       options.allow_code_gen_wasm);
243
244
1232
  ContextInfo info(*name_val);
245
246
616
  if (!options.origin.IsEmpty()) {
247
4
    Utf8Value origin_val(env->isolate(), options.origin);
248
2
    info.origin = *origin_val;
249
  }
250
251
616
  env->AssignToContext(ctx, info);
252
253
616
  return scope.Escape(ctx);
254
}
255
256
257
1303
void ContextifyContext::Init(Environment* env, Local<Object> target) {
258
  Local<FunctionTemplate> function_template =
259
1303
      FunctionTemplate::New(env->isolate());
260
2606
  function_template->InstanceTemplate()->SetInternalFieldCount(
261
      ContextifyContext::kInternalFieldCount);
262
1303
  env->set_script_data_constructor_function(
263
1303
      function_template->GetFunction(env->context()).ToLocalChecked());
264
265
1303
  env->SetMethod(target, "makeContext", MakeContext);
266
1303
  env->SetMethod(target, "isContext", IsContext);
267
1303
  env->SetMethod(target, "compileFunction", CompileFunction);
268
1303
}
269
270
5288
void ContextifyContext::RegisterExternalReferences(
271
    ExternalReferenceRegistry* registry) {
272
5288
  registry->Register(MakeContext);
273
5288
  registry->Register(IsContext);
274
5288
  registry->Register(CompileFunction);
275
5288
}
276
277
// makeContext(sandbox, name, origin, strings, wasm);
278
616
void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
279
616
  Environment* env = Environment::GetCurrent(args);
280
281
616
  CHECK_EQ(args.Length(), 6);
282
616
  CHECK(args[0]->IsObject());
283
1232
  Local<Object> sandbox = args[0].As<Object>();
284
285
  // Don't allow contextifying a sandbox multiple times.
286
1232
  CHECK(
287
      !sandbox->HasPrivate(
288
          env->context(),
289
          env->contextify_context_private_symbol()).FromJust());
290
291
616
  ContextOptions options;
292
293
1232
  CHECK(args[1]->IsString());
294
1232
  options.name = args[1].As<String>();
295
296

2460
  CHECK(args[2]->IsString() || args[2]->IsUndefined());
297
1232
  if (args[2]->IsString()) {
298
4
    options.origin = args[2].As<String>();
299
  }
300
301
616
  CHECK(args[3]->IsBoolean());
302
1232
  options.allow_code_gen_strings = args[3].As<Boolean>();
303
304
616
  CHECK(args[4]->IsBoolean());
305
1232
  options.allow_code_gen_wasm = args[4].As<Boolean>();
306
307
616
  if (args[5]->IsObject() &&
308

626
      !env->microtask_queue_ctor_template().IsEmpty() &&
309

631
      env->microtask_queue_ctor_template()->HasInstance(args[5])) {
310
5
    options.microtask_queue_wrap.reset(
311
10
        Unwrap<MicrotaskQueueWrap>(args[5].As<Object>()));
312
  }
313
314
616
  TryCatchScope try_catch(env);
315
  std::unique_ptr<ContextifyContext> context_ptr =
316
616
      std::make_unique<ContextifyContext>(env, sandbox, options);
317
318
616
  if (try_catch.HasCaught()) {
319
    if (!try_catch.HasTerminated())
320
      try_catch.ReThrow();
321
    return;
322
  }
323
324
1232
  if (context_ptr->context().IsEmpty())
325
    return;
326
327
  sandbox->SetPrivate(
328
      env->context(),
329
      env->contextify_context_private_symbol(),
330
1232
      External::New(env->isolate(), context_ptr.release()));
331
}
332
333
334
6064
void ContextifyContext::IsContext(const FunctionCallbackInfo<Value>& args) {
335
6064
  Environment* env = Environment::GetCurrent(args);
336
337
6064
  CHECK(args[0]->IsObject());
338
12128
  Local<Object> sandbox = args[0].As<Object>();
339
340
  Maybe<bool> result =
341
      sandbox->HasPrivate(env->context(),
342
6064
                          env->contextify_context_private_symbol());
343
12128
  args.GetReturnValue().Set(result.FromJust());
344
6064
}
345
346
347
63
void ContextifyContext::WeakCallback(
348
    const WeakCallbackInfo<ContextifyContext>& data) {
349
63
  ContextifyContext* context = data.GetParameter();
350
63
  delete context;
351
63
}
352
353
// static
354
5390
ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox(
355
    Environment* env,
356
    const Local<Object>& sandbox) {
357
  MaybeLocal<Value> maybe_value =
358
      sandbox->GetPrivate(env->context(),
359
5390
                          env->contextify_context_private_symbol());
360
  Local<Value> context_external_v;
361

10780
  if (maybe_value.ToLocal(&context_external_v) &&
362
5390
      context_external_v->IsExternal()) {
363
5390
    Local<External> context_external = context_external_v.As<External>();
364
5390
    return static_cast<ContextifyContext*>(context_external->Value());
365
  }
366
  return nullptr;
367
}
368
369
// static
370
template <typename T>
371
2098650
ContextifyContext* ContextifyContext::Get(const PropertyCallbackInfo<T>& args) {
372
2098650
  Local<Value> data = args.Data();
373
  return static_cast<ContextifyContext*>(
374
4197300
      data.As<Object>()->GetAlignedPointerFromInternalField(
375
2098650
          ContextifyContext::kSlot));
376
}
377
378
// static
379
1048842
void ContextifyContext::PropertyGetterCallback(
380
    Local<Name> property,
381
    const PropertyCallbackInfo<Value>& args) {
382
1048842
  ContextifyContext* ctx = ContextifyContext::Get(args);
383
384
  // Still initializing
385
1048842
  if (ctx->context_.IsEmpty())
386
2464
    return;
387
388
1046378
  Local<Context> context = ctx->context();
389
1046378
  Local<Object> sandbox = ctx->sandbox();
390
  MaybeLocal<Value> maybe_rv =
391
1046378
      sandbox->GetRealNamedProperty(context, property);
392
1046378
  if (maybe_rv.IsEmpty()) {
393
    maybe_rv =
394
84488
        ctx->global_proxy()->GetRealNamedProperty(context, property);
395
  }
396
397
  Local<Value> rv;
398
1046378
  if (maybe_rv.ToLocal(&rv)) {
399
1046309
    if (rv == sandbox)
400
10
      rv = ctx->global_proxy();
401
402
2092618
    args.GetReturnValue().Set(rv);
403
  }
404
}
405
406
// static
407
152
void ContextifyContext::PropertySetterCallback(
408
    Local<Name> property,
409
    Local<Value> value,
410
    const PropertyCallbackInfo<Value>& args) {
411
152
  ContextifyContext* ctx = ContextifyContext::Get(args);
412
413
  // Still initializing
414
152
  if (ctx->context_.IsEmpty())
415
14
    return;
416
417
152
  Local<Context> context = ctx->context();
418
152
  PropertyAttribute attributes = PropertyAttribute::None;
419
152
  bool is_declared_on_global_proxy = ctx->global_proxy()
420
152
      ->GetRealNamedPropertyAttributes(context, property)
421
152
      .To(&attributes);
422
152
  bool read_only =
423
152
      static_cast<int>(attributes) &
424
      static_cast<int>(PropertyAttribute::ReadOnly);
425
426
152
  bool is_declared_on_sandbox = ctx->sandbox()
427
152
      ->GetRealNamedPropertyAttributes(context, property)
428
152
      .To(&attributes);
429
300
  read_only = read_only ||
430
148
      (static_cast<int>(attributes) &
431
      static_cast<int>(PropertyAttribute::ReadOnly));
432
433
152
  if (read_only)
434
13
    return;
435
436
  // true for x = 5
437
  // false for this.x = 5
438
  // false for Object.defineProperty(this, 'foo', ...)
439
  // false for vmResult.x = 5 where vmResult = vm.runInContext();
440
278
  bool is_contextual_store = ctx->global_proxy() != args.This();
441
442
  // Indicator to not return before setting (undeclared) function declarations
443
  // on the sandbox in strict mode, i.e. args.ShouldThrowOnError() = true.
444
  // True for 'function f() {}', 'this.f = function() {}',
445
  // 'var f = function()'.
446
  // In effect only for 'function f() {}' because
447
  // var f = function(), is_declared = true
448
  // this.f = function() {}, is_contextual_store = false.
449
139
  bool is_function = value->IsFunction();
450
451

139
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
452


230
  if (!is_declared && args.ShouldThrowOnError() && is_contextual_store &&
453
30
      !is_function)
454
1
    return;
455
456
276
  USE(ctx->sandbox()->Set(context, property, value));
457
276
  args.GetReturnValue().Set(value);
458
}
459
460
// static
461
55
void ContextifyContext::PropertyDescriptorCallback(
462
    Local<Name> property,
463
    const PropertyCallbackInfo<Value>& args) {
464
55
  ContextifyContext* ctx = ContextifyContext::Get(args);
465
466
  // Still initializing
467
55
  if (ctx->context_.IsEmpty())
468
    return;
469
470
55
  Local<Context> context = ctx->context();
471
472
55
  Local<Object> sandbox = ctx->sandbox();
473
474

110
  if (sandbox->HasOwnProperty(context, property).FromMaybe(false)) {
475
    Local<Value> desc;
476
78
    if (sandbox->GetOwnPropertyDescriptor(context, property).ToLocal(&desc)) {
477
78
      args.GetReturnValue().Set(desc);
478
    }
479
  }
480
}
481
482
// static
483
15
void ContextifyContext::PropertyDefinerCallback(
484
    Local<Name> property,
485
    const PropertyDescriptor& desc,
486
    const PropertyCallbackInfo<Value>& args) {
487
15
  ContextifyContext* ctx = ContextifyContext::Get(args);
488
489
  // Still initializing
490
15
  if (ctx->context_.IsEmpty())
491
    return;
492
493
15
  Local<Context> context = ctx->context();
494
15
  Isolate* isolate = context->GetIsolate();
495
496
15
  PropertyAttribute attributes = PropertyAttribute::None;
497
  bool is_declared =
498
15
      ctx->global_proxy()->GetRealNamedPropertyAttributes(context,
499
15
                                                          property)
500
15
          .To(&attributes);
501
15
  bool read_only =
502
15
      static_cast<int>(attributes) &
503
          static_cast<int>(PropertyAttribute::ReadOnly);
504
505
  // If the property is set on the global as read_only, don't change it on
506
  // the global or sandbox.
507

15
  if (is_declared && read_only)
508
    return;
509
510
15
  Local<Object> sandbox = ctx->sandbox();
511
512
  auto define_prop_on_sandbox =
513
15
      [&] (PropertyDescriptor* desc_for_sandbox) {
514
15
        if (desc.has_enumerable()) {
515
2
          desc_for_sandbox->set_enumerable(desc.enumerable());
516
        }
517
15
        if (desc.has_configurable()) {
518
1
          desc_for_sandbox->set_configurable(desc.configurable());
519
        }
520
        // Set the property on the sandbox.
521
15
        USE(sandbox->DefineProperty(context, property, *desc_for_sandbox));
522
30
      };
523
524

15
  if (desc.has_get() || desc.has_set()) {
525
    PropertyDescriptor desc_for_sandbox(
526
15
        desc.has_get() ? desc.get() : Undefined(isolate).As<Value>(),
527

23
        desc.has_set() ? desc.set() : Undefined(isolate).As<Value>());
528
529
5
    define_prop_on_sandbox(&desc_for_sandbox);
530
  } else {
531
    Local<Value> value =
532
12
        desc.has_value() ? desc.value() : Undefined(isolate).As<Value>();
533
534
10
    if (desc.has_writable()) {
535
      PropertyDescriptor desc_for_sandbox(value, desc.writable());
536
      define_prop_on_sandbox(&desc_for_sandbox);
537
    } else {
538
20
      PropertyDescriptor desc_for_sandbox(value);
539
10
      define_prop_on_sandbox(&desc_for_sandbox);
540
    }
541
  }
542
}
543
544
// static
545
2
void ContextifyContext::PropertyDeleterCallback(
546
    Local<Name> property,
547
    const PropertyCallbackInfo<Boolean>& args) {
548
2
  ContextifyContext* ctx = ContextifyContext::Get(args);
549
550
  // Still initializing
551
2
  if (ctx->context_.IsEmpty())
552
1
    return;
553
554
4
  Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), property);
555
556

4
  if (success.FromMaybe(false))
557
1
    return;
558
559
  // Delete failed on the sandbox, intercept and do not delete on
560
  // the global object.
561
2
  args.GetReturnValue().Set(false);
562
}
563
564
// static
565
256
void ContextifyContext::PropertyEnumeratorCallback(
566
    const PropertyCallbackInfo<Array>& args) {
567
256
  ContextifyContext* ctx = ContextifyContext::Get(args);
568
569
  // Still initializing
570
256
  if (ctx->context_.IsEmpty())
571
    return;
572
573
  Local<Array> properties;
574
575
768
  if (!ctx->sandbox()->GetPropertyNames(ctx->context()).ToLocal(&properties))
576
    return;
577
578
512
  args.GetReturnValue().Set(properties);
579
}
580
581
// static
582
void ContextifyContext::IndexedPropertyGetterCallback(
583
    uint32_t index,
584
    const PropertyCallbackInfo<Value>& args) {
585
  ContextifyContext* ctx = ContextifyContext::Get(args);
586
587
  // Still initializing
588
  if (ctx->context_.IsEmpty())
589
    return;
590
591
  ContextifyContext::PropertyGetterCallback(
592
      Uint32ToName(ctx->context(), index), args);
593
}
594
595
596
1
void ContextifyContext::IndexedPropertySetterCallback(
597
    uint32_t index,
598
    Local<Value> value,
599
    const PropertyCallbackInfo<Value>& args) {
600
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
601
602
  // Still initializing
603
1
  if (ctx->context_.IsEmpty())
604
    return;
605
606
1
  ContextifyContext::PropertySetterCallback(
607
      Uint32ToName(ctx->context(), index), value, args);
608
}
609
610
// static
611
1
void ContextifyContext::IndexedPropertyDescriptorCallback(
612
    uint32_t index,
613
    const PropertyCallbackInfo<Value>& args) {
614
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
615
616
  // Still initializing
617
1
  if (ctx->context_.IsEmpty())
618
    return;
619
620
1
  ContextifyContext::PropertyDescriptorCallback(
621
      Uint32ToName(ctx->context(), index), args);
622
}
623
624
625
1
void ContextifyContext::IndexedPropertyDefinerCallback(
626
    uint32_t index,
627
    const PropertyDescriptor& desc,
628
    const PropertyCallbackInfo<Value>& args) {
629
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
630
631
  // Still initializing
632
1
  if (ctx->context_.IsEmpty())
633
    return;
634
635
1
  ContextifyContext::PropertyDefinerCallback(
636
      Uint32ToName(ctx->context(), index), desc, args);
637
}
638
639
// static
640
void ContextifyContext::IndexedPropertyDeleterCallback(
641
    uint32_t index,
642
    const PropertyCallbackInfo<Boolean>& args) {
643
  ContextifyContext* ctx = ContextifyContext::Get(args);
644
645
  // Still initializing
646
  if (ctx->context_.IsEmpty())
647
    return;
648
649
  Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), index);
650
651
  if (success.FromMaybe(false))
652
    return;
653
654
  // Delete failed on the sandbox, intercept and do not delete on
655
  // the global object.
656
  args.GetReturnValue().Set(false);
657
}
658
659
1303
void ContextifyScript::Init(Environment* env, Local<Object> target) {
660
2606
  HandleScope scope(env->isolate());
661
  Local<String> class_name =
662
1303
      FIXED_ONE_BYTE_STRING(env->isolate(), "ContextifyScript");
663
664
1303
  Local<FunctionTemplate> script_tmpl = env->NewFunctionTemplate(New);
665
2606
  script_tmpl->InstanceTemplate()->SetInternalFieldCount(
666
      ContextifyScript::kInternalFieldCount);
667
1303
  script_tmpl->SetClassName(class_name);
668
1303
  env->SetProtoMethod(script_tmpl, "createCachedData", CreateCachedData);
669
1303
  env->SetProtoMethod(script_tmpl, "runInContext", RunInContext);
670
671
1303
  Local<Context> context = env->context();
672
673
1303
  target->Set(context, class_name,
674
2606
      script_tmpl->GetFunction(context).ToLocalChecked()).Check();
675
1303
  env->set_script_context_constructor_template(script_tmpl);
676
1303
}
677
678
5288
void ContextifyScript::RegisterExternalReferences(
679
    ExternalReferenceRegistry* registry) {
680
5288
  registry->Register(New);
681
5288
  registry->Register(CreateCachedData);
682
5288
  registry->Register(RunInContext);
683
5288
}
684
685
5844
void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
686
5844
  Environment* env = Environment::GetCurrent(args);
687
5844
  Isolate* isolate = env->isolate();
688
5844
  Local<Context> context = env->context();
689
690
5844
  CHECK(args.IsConstructCall());
691
692
5844
  const int argc = args.Length();
693
5844
  CHECK_GE(argc, 2);
694
695
11688
  CHECK(args[0]->IsString());
696
11688
  Local<String> code = args[0].As<String>();
697
698
11688
  CHECK(args[1]->IsString());
699
5844
  Local<String> filename = args[1].As<String>();
700
701
5844
  int line_offset = 0;
702
5844
  int column_offset = 0;
703
  Local<ArrayBufferView> cached_data_buf;
704
5844
  bool produce_cached_data = false;
705
5844
  Local<Context> parsing_context = context;
706
707
5844
  if (argc > 2) {
708
    // new ContextifyScript(code, filename, lineOffset, columnOffset,
709
    //                      cachedData, produceCachedData, parsingContext)
710
5844
    CHECK_EQ(argc, 7);
711
5844
    CHECK(args[2]->IsNumber());
712
11688
    line_offset = args[2].As<Int32>()->Value();
713
5844
    CHECK(args[3]->IsNumber());
714
11688
    column_offset = args[3].As<Int32>()->Value();
715
11688
    if (!args[4]->IsUndefined()) {
716
25
      CHECK(args[4]->IsArrayBufferView());
717
50
      cached_data_buf = args[4].As<ArrayBufferView>();
718
    }
719
5844
    CHECK(args[5]->IsBoolean());
720
5844
    produce_cached_data = args[5]->IsTrue();
721
11688
    if (!args[6]->IsUndefined()) {
722
2505
      CHECK(args[6]->IsObject());
723
      ContextifyContext* sandbox =
724
2505
          ContextifyContext::ContextFromContextifiedSandbox(
725
5010
              env, args[6].As<Object>());
726
2505
      CHECK_NOT_NULL(sandbox);
727
2505
      parsing_context = sandbox->context();
728
    }
729
  }
730
731
  ContextifyScript* contextify_script =
732
5844
      new ContextifyScript(env, args.This());
733
734
5844
  if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
735
5844
          TRACING_CATEGORY_NODE2(vm, script)) != 0) {
736
14
    Utf8Value fn(isolate, filename);
737

14
    TRACE_EVENT_BEGIN1(TRACING_CATEGORY_NODE2(vm, script),
738
                       "ContextifyScript::New",
739
                       "filename",
740
                       TRACE_STR_COPY(*fn));
741
  }
742
743
5844
  ScriptCompiler::CachedData* cached_data = nullptr;
744
5844
  if (!cached_data_buf.IsEmpty()) {
745
    uint8_t* data = static_cast<uint8_t*>(
746
50
        cached_data_buf->Buffer()->GetBackingStore()->Data());
747
25
    cached_data = new ScriptCompiler::CachedData(
748
25
        data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
749
  }
750
751
  Local<PrimitiveArray> host_defined_options =
752
5844
      PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
753
11688
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kType,
754
                            Number::New(isolate, loader::ScriptType::kScript));
755
11688
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kID,
756
5844
                            Number::New(isolate, contextify_script->id()));
757
758
  ScriptOrigin origin(isolate,
759
                      filename,
760
                      line_offset,                          // line offset
761
                      column_offset,                        // column offset
762
                      true,                                 // is cross origin
763
                      -1,                                   // script id
764
                      Local<Value>(),                       // source map URL
765
                      false,                                // is opaque (?)
766
                      false,                                // is WASM
767
                      false,                                // is ES Module
768
11688
                      host_defined_options);
769
5844
  ScriptCompiler::Source source(code, origin, cached_data);
770
5844
  ScriptCompiler::CompileOptions compile_options =
771
      ScriptCompiler::kNoCompileOptions;
772
773
5844
  if (source.GetCachedData() != nullptr)
774
25
    compile_options = ScriptCompiler::kConsumeCodeCache;
775
776
5844
  TryCatchScope try_catch(env);
777
5844
  ShouldNotAbortOnUncaughtScope no_abort_scope(env);
778
5844
  Context::Scope scope(parsing_context);
779
780
  MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
781
      isolate,
782
      &source,
783
5844
      compile_options);
784
785
5844
  if (v8_script.IsEmpty()) {
786
192
    errors::DecorateErrorStack(env, try_catch);
787
192
    no_abort_scope.Close();
788
192
    if (!try_catch.HasTerminated())
789
192
      try_catch.ReThrow();
790

219
    TRACE_EVENT_END0(TRACING_CATEGORY_NODE2(vm, script),
791
                     "ContextifyScript::New");
792
192
    return;
793
  }
794
11304
  contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
795
796
5652
  Local<Context> env_context = env->context();
797
5652
  if (compile_options == ScriptCompiler::kConsumeCodeCache) {
798
25
    args.This()->Set(
799
        env_context,
800
        env->cached_data_rejected_string(),
801
100
        Boolean::New(isolate, source.GetCachedData()->rejected)).Check();
802
5627
  } else if (produce_cached_data) {
803
    std::unique_ptr<ScriptCompiler::CachedData> cached_data {
804
6
      ScriptCompiler::CreateCodeCache(v8_script.ToLocalChecked()) };
805
6
    bool cached_data_produced = cached_data != nullptr;
806
6
    if (cached_data_produced) {
807
      MaybeLocal<Object> buf = Buffer::Copy(
808
          env,
809
12
          reinterpret_cast<const char*>(cached_data->data),
810
6
          cached_data->length);
811
6
      args.This()->Set(env_context,
812
                       env->cached_data_string(),
813
24
                       buf.ToLocalChecked()).Check();
814
    }
815
6
    args.This()->Set(
816
        env_context,
817
        env->cached_data_produced_string(),
818
24
        Boolean::New(isolate, cached_data_produced)).Check();
819
  }
820

6405
  TRACE_EVENT_END0(TRACING_CATEGORY_NODE2(vm, script), "ContextifyScript::New");
821
}
822
823
5630
bool ContextifyScript::InstanceOf(Environment* env,
824
                                  const Local<Value>& value) {
825

11260
  return !value.IsEmpty() &&
826
16890
         env->script_context_constructor_template()->HasInstance(value);
827
}
828
829
11
void ContextifyScript::CreateCachedData(
830
    const FunctionCallbackInfo<Value>& args) {
831
11
  Environment* env = Environment::GetCurrent(args);
832
  ContextifyScript* wrapped_script;
833
11
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
834
  Local<UnboundScript> unbound_script =
835
11
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
836
  std::unique_ptr<ScriptCompiler::CachedData> cached_data(
837
22
      ScriptCompiler::CreateCodeCache(unbound_script));
838
11
  if (!cached_data) {
839
    args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked());
840
  } else {
841
    MaybeLocal<Object> buf = Buffer::Copy(
842
        env,
843
22
        reinterpret_cast<const char*>(cached_data->data),
844
11
        cached_data->length);
845
22
    args.GetReturnValue().Set(buf.ToLocalChecked());
846
  }
847
}
848
849
5630
void ContextifyScript::RunInContext(const FunctionCallbackInfo<Value>& args) {
850
5630
  Environment* env = Environment::GetCurrent(args);
851
852
  ContextifyScript* wrapped_script;
853
5630
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
854
855
5630
  CHECK_EQ(args.Length(), 5);
856

11178
  CHECK(args[0]->IsObject() || args[0]->IsNull());
857
858
  Local<Context> context;
859
5630
  std::shared_ptr<v8::MicrotaskQueue> microtask_queue;
860
861
5630
  if (args[0]->IsObject()) {
862
2856
    Local<Object> sandbox = args[0].As<Object>();
863
    // Get the context from the sandbox
864
    ContextifyContext* contextify_context =
865
2856
        ContextifyContext::ContextFromContextifiedSandbox(env, sandbox);
866
2856
    CHECK_NOT_NULL(contextify_context);
867
2856
    CHECK_EQ(contextify_context->env(), env);
868
869
2856
    context = contextify_context->context();
870
2856
    if (context.IsEmpty()) return;
871
872
2856
    microtask_queue = contextify_context->microtask_queue();
873
  } else {
874
2774
    context = env->context();
875
  }
876
877

11996
  TRACE_EVENT0(TRACING_CATEGORY_NODE2(vm, script), "RunInContext");
878
879
5630
  CHECK(args[1]->IsNumber());
880
11260
  int64_t timeout = args[1]->IntegerValue(env->context()).FromJust();
881
882
5630
  CHECK(args[2]->IsBoolean());
883
5630
  bool display_errors = args[2]->IsTrue();
884
885
5630
  CHECK(args[3]->IsBoolean());
886
5630
  bool break_on_sigint = args[3]->IsTrue();
887
888
5630
  CHECK(args[4]->IsBoolean());
889
5630
  bool break_on_first_line = args[4]->IsTrue();
890
891
  // Do the eval within the context
892
5630
  Context::Scope context_scope(context);
893
5630
  EvalMachine(env,
894
              timeout,
895
              display_errors,
896
              break_on_sigint,
897
              break_on_first_line,
898
              microtask_queue,
899
              args);
900
}
901
902
5630
bool ContextifyScript::EvalMachine(Environment* env,
903
                                   const int64_t timeout,
904
                                   const bool display_errors,
905
                                   const bool break_on_sigint,
906
                                   const bool break_on_first_line,
907
                                   std::shared_ptr<MicrotaskQueue> mtask_queue,
908
                                   const FunctionCallbackInfo<Value>& args) {
909
5630
  if (!env->can_call_into_js())
910
    return false;
911
5630
  if (!ContextifyScript::InstanceOf(env, args.Holder())) {
912
    THROW_ERR_INVALID_THIS(
913
        env,
914
        "Script methods can only be called on script instances.");
915
    return false;
916
  }
917
11244
  TryCatchScope try_catch(env);
918
11244
  Isolate::SafeForTerminationScope safe_for_termination(env->isolate());
919
  ContextifyScript* wrapped_script;
920
5630
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder(), false);
921
  Local<UnboundScript> unbound_script =
922
5630
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
923
5630
  Local<Script> script = unbound_script->BindToCurrentContext();
924
925
#if HAVE_INSPECTOR
926
5630
  if (break_on_first_line) {
927
10
    env->inspector_agent()->PauseOnNextJavascriptStatement("Break on start");
928
  }
929
#endif
930
931
  MaybeLocal<Value> result;
932
5630
  bool timed_out = false;
933
5630
  bool received_signal = false;
934
5630
  auto run = [&]() {
935
5630
    MaybeLocal<Value> result = script->Run(env->context());
936

5614
    if (!result.IsEmpty() && mtask_queue)
937
2
      mtask_queue->PerformCheckpoint(env->isolate());
938
5614
    return result;
939
5630
  };
940

5630
  if (break_on_sigint && timeout != -1) {
941
    Watchdog wd(env->isolate(), timeout, &timed_out);
942
    SigintWatchdog swd(env->isolate(), &received_signal);
943
    result = run();
944
5630
  } else if (break_on_sigint) {
945
2393
    SigintWatchdog swd(env->isolate(), &received_signal);
946
1198
    result = run();
947
4432
  } else if (timeout != -1) {
948
30
    Watchdog wd(env->isolate(), timeout, &timed_out);
949
15
    result = run();
950
  } else {
951
4417
    result = run();
952
  }
953
954
  // Convert the termination exception into a regular exception.
955

5614
  if (timed_out || received_signal) {
956

21
    if (!env->is_main_thread() && env->is_stopping())
957
      return false;
958
21
    env->isolate()->CancelTerminateExecution();
959
    // It is possible that execution was terminated by another timeout in
960
    // which this timeout is nested, so check whether one of the watchdogs
961
    // from this invocation is responsible for termination.
962
21
    if (timed_out) {
963
10
      node::THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout);
964
11
    } else if (received_signal) {
965
11
      node::THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env);
966
    }
967
  }
968
969
5614
  if (try_catch.HasCaught()) {
970

173
    if (!timed_out && !received_signal && display_errors) {
971
      // We should decorate non-termination exceptions
972
101
      errors::DecorateErrorStack(env, try_catch);
973
    }
974
975
    // If there was an exception thrown during script execution, re-throw it.
976
    // If one of the above checks threw, re-throw the exception instead of
977
    // letting try_catch catch it.
978
    // If execution has been terminated, but not by one of the watchdogs from
979
    // this invocation, this will re-throw a `null` value.
980
173
    if (!try_catch.HasTerminated())
981
170
      try_catch.ReThrow();
982
983
173
    return false;
984
  }
985
986
5441
  args.GetReturnValue().Set(result.ToLocalChecked());
987
5441
  return true;
988
}
989
990
991
5844
ContextifyScript::ContextifyScript(Environment* env, Local<Object> object)
992
    : BaseObject(env, object),
993
5844
      id_(env->get_next_script_id()) {
994
5844
  MakeWeak();
995
5844
  env->id_to_script_map.emplace(id_, this);
996
5844
}
997
998
999
34662
ContextifyScript::~ContextifyScript() {
1000
11554
  env()->id_to_script_map.erase(id_);
1001
23108
}
1002
1003
1004
35863
void ContextifyContext::CompileFunction(
1005
    const FunctionCallbackInfo<Value>& args) {
1006
35863
  Environment* env = Environment::GetCurrent(args);
1007
35863
  Isolate* isolate = env->isolate();
1008
35863
  Local<Context> context = env->context();
1009
1010
  // Argument 1: source code
1011
71726
  CHECK(args[0]->IsString());
1012
71726
  Local<String> code = args[0].As<String>();
1013
1014
  // Argument 2: filename
1015
71726
  CHECK(args[1]->IsString());
1016
71726
  Local<String> filename = args[1].As<String>();
1017
1018
  // Argument 3: line offset
1019
35863
  CHECK(args[2]->IsNumber());
1020
71726
  int line_offset = args[2].As<Int32>()->Value();
1021
1022
  // Argument 4: column offset
1023
35863
  CHECK(args[3]->IsNumber());
1024
71726
  int column_offset = args[3].As<Int32>()->Value();
1025
1026
  // Argument 5: cached data (optional)
1027
  Local<ArrayBufferView> cached_data_buf;
1028
71726
  if (!args[4]->IsUndefined()) {
1029
    CHECK(args[4]->IsArrayBufferView());
1030
    cached_data_buf = args[4].As<ArrayBufferView>();
1031
  }
1032
1033
  // Argument 6: produce cache data
1034
35863
  CHECK(args[5]->IsBoolean());
1035
35863
  bool produce_cached_data = args[5]->IsTrue();
1036
1037
  // Argument 7: parsing context (optional)
1038
  Local<Context> parsing_context;
1039
71726
  if (!args[6]->IsUndefined()) {
1040
2
    CHECK(args[6]->IsObject());
1041
    ContextifyContext* sandbox =
1042
2
        ContextifyContext::ContextFromContextifiedSandbox(
1043
4
            env, args[6].As<Object>());
1044
2
    CHECK_NOT_NULL(sandbox);
1045
2
    parsing_context = sandbox->context();
1046
  } else {
1047
35861
    parsing_context = context;
1048
  }
1049
1050
  // Argument 8: context extensions (optional)
1051
  Local<Array> context_extensions_buf;
1052
71726
  if (!args[7]->IsUndefined()) {
1053
35863
    CHECK(args[7]->IsArray());
1054
71726
    context_extensions_buf = args[7].As<Array>();
1055
  }
1056
1057
  // Argument 9: params for the function (optional)
1058
  Local<Array> params_buf;
1059
71726
  if (!args[8]->IsUndefined()) {
1060
35856
    CHECK(args[8]->IsArray());
1061
71712
    params_buf = args[8].As<Array>();
1062
  }
1063
1064
  // Read cache from cached data buffer
1065
35863
  ScriptCompiler::CachedData* cached_data = nullptr;
1066
35863
  if (!cached_data_buf.IsEmpty()) {
1067
    uint8_t* data = static_cast<uint8_t*>(
1068
        cached_data_buf->Buffer()->GetBackingStore()->Data());
1069
    cached_data = new ScriptCompiler::CachedData(
1070
      data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
1071
  }
1072
1073
  // Get the function id
1074
35863
  uint32_t id = env->get_next_function_id();
1075
1076
  // Set host_defined_options
1077
  Local<PrimitiveArray> host_defined_options =
1078
35863
      PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
1079
71726
  host_defined_options->Set(
1080
      isolate,
1081
      loader::HostDefinedOptions::kType,
1082
      Number::New(isolate, loader::ScriptType::kFunction));
1083
71726
  host_defined_options->Set(
1084
      isolate, loader::HostDefinedOptions::kID, Number::New(isolate, id));
1085
1086
  ScriptOrigin origin(isolate,
1087
                      filename,
1088
                      line_offset,       // line offset
1089
                      column_offset,     // column offset
1090
                      true,              // is cross origin
1091
                      -1,                // script id
1092
                      Local<Value>(),    // source map URL
1093
                      false,             // is opaque (?)
1094
                      false,             // is WASM
1095
                      false,             // is ES Module
1096
71726
                      host_defined_options);
1097
1098
35863
  ScriptCompiler::Source source(code, origin, cached_data);
1099
  ScriptCompiler::CompileOptions options;
1100
35863
  if (source.GetCachedData() == nullptr) {
1101
35863
    options = ScriptCompiler::kNoCompileOptions;
1102
  } else {
1103
    options = ScriptCompiler::kConsumeCodeCache;
1104
  }
1105
1106
35863
  TryCatchScope try_catch(env);
1107
35863
  Context::Scope scope(parsing_context);
1108
1109
  // Read context extensions from buffer
1110
35863
  std::vector<Local<Object>> context_extensions;
1111
35863
  if (!context_extensions_buf.IsEmpty()) {
1112
71727
    for (uint32_t n = 0; n < context_extensions_buf->Length(); n++) {
1113
      Local<Value> val;
1114
2
      if (!context_extensions_buf->Get(context, n).ToLocal(&val)) return;
1115
1
      CHECK(val->IsObject());
1116
1
      context_extensions.push_back(val.As<Object>());
1117
    }
1118
  }
1119
1120
  // Read params from params buffer
1121
35863
  std::vector<Local<String>> params;
1122
35863
  if (!params_buf.IsEmpty()) {
1123
250944
    for (uint32_t n = 0; n < params_buf->Length(); n++) {
1124
      Local<Value> val;
1125
358464
      if (!params_buf->Get(context, n).ToLocal(&val)) return;
1126
358464
      CHECK(val->IsString());
1127
179232
      params.push_back(val.As<String>());
1128
    }
1129
  }
1130
1131
  Local<ScriptOrModule> script;
1132
  MaybeLocal<Function> maybe_fn = ScriptCompiler::CompileFunctionInContext(
1133
      parsing_context, &source, params.size(), params.data(),
1134
      context_extensions.size(), context_extensions.data(), options,
1135
35863
      v8::ScriptCompiler::NoCacheReason::kNoCacheNoReason, &script);
1136
1137
  Local<Function> fn;
1138
35863
  if (!maybe_fn.ToLocal(&fn)) {
1139

28
    if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
1140
28
      errors::DecorateErrorStack(env, try_catch);
1141
28
      try_catch.ReThrow();
1142
    }
1143
28
    return;
1144
  }
1145
1146
  Local<Object> cache_key;
1147
35835
  if (!env->compiled_fn_entry_template()->NewInstance(
1148
71670
           context).ToLocal(&cache_key)) {
1149
    return;
1150
  }
1151
35835
  CompiledFnEntry* entry = new CompiledFnEntry(env, cache_key, id, script);
1152
35835
  env->id_to_function_map.emplace(id, entry);
1153
1154
35835
  Local<Object> result = Object::New(isolate);
1155
107505
  if (result->Set(parsing_context, env->function_string(), fn).IsNothing())
1156
    return;
1157
71670
  if (result->Set(parsing_context, env->cache_key_string(), cache_key)
1158
35835
          .IsNothing())
1159
    return;
1160
1161
35835
  if (produce_cached_data) {
1162
    const std::unique_ptr<ScriptCompiler::CachedData> cached_data(
1163
1
        ScriptCompiler::CreateCodeCacheForFunction(fn));
1164
1
    bool cached_data_produced = cached_data != nullptr;
1165
1
    if (cached_data_produced) {
1166
      MaybeLocal<Object> buf = Buffer::Copy(
1167
          env,
1168
2
          reinterpret_cast<const char*>(cached_data->data),
1169
1
          cached_data->length);
1170
1
      if (result
1171
1
              ->Set(parsing_context,
1172
                    env->cached_data_string(),
1173
3
                    buf.ToLocalChecked())
1174
1
              .IsNothing())
1175
        return;
1176
    }
1177
1
    if (result
1178
1
            ->Set(parsing_context,
1179
                  env->cached_data_produced_string(),
1180
3
                  Boolean::New(isolate, cached_data_produced))
1181
1
            .IsNothing())
1182
      return;
1183
  }
1184
1185
71670
  args.GetReturnValue().Set(result);
1186
}
1187
1188
void CompiledFnEntry::WeakCallback(
1189
    const WeakCallbackInfo<CompiledFnEntry>& data) {
1190
  CompiledFnEntry* entry = data.GetParameter();
1191
  delete entry;
1192
}
1193
1194
35835
CompiledFnEntry::CompiledFnEntry(Environment* env,
1195
                                 Local<Object> object,
1196
                                 uint32_t id,
1197
35835
                                 Local<ScriptOrModule> script)
1198
    : BaseObject(env, object),
1199
      id_(id),
1200
35835
      script_(env->isolate(), script) {
1201
35835
  script_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
1202
35835
}
1203
1204
203274
CompiledFnEntry::~CompiledFnEntry() {
1205
67758
  env()->id_to_function_map.erase(id_);
1206
67758
  script_.ClearWeak();
1207
135516
}
1208
1209
195
static void StartSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1210
195
  int ret = SigintWatchdogHelper::GetInstance()->Start();
1211
195
  args.GetReturnValue().Set(ret == 0);
1212
195
}
1213
1214
192
static void StopSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1215
192
  bool had_pending_signals = SigintWatchdogHelper::GetInstance()->Stop();
1216
192
  args.GetReturnValue().Set(had_pending_signals);
1217
192
}
1218
1219
3
static void WatchdogHasPendingSigint(const FunctionCallbackInfo<Value>& args) {
1220
3
  bool ret = SigintWatchdogHelper::GetInstance()->HasPendingSignal();
1221
3
  args.GetReturnValue().Set(ret);
1222
3
}
1223
1224
8
static void MeasureMemory(const FunctionCallbackInfo<Value>& args) {
1225
8
  CHECK(args[0]->IsInt32());
1226
8
  CHECK(args[1]->IsInt32());
1227
16
  int32_t mode = args[0].As<v8::Int32>()->Value();
1228
16
  int32_t execution = args[1].As<v8::Int32>()->Value();
1229
8
  Isolate* isolate = args.GetIsolate();
1230
1231
8
  Local<Context> current_context = isolate->GetCurrentContext();
1232
  Local<Promise::Resolver> resolver;
1233
16
  if (!Promise::Resolver::New(current_context).ToLocal(&resolver)) return;
1234
  std::unique_ptr<v8::MeasureMemoryDelegate> delegate =
1235
      v8::MeasureMemoryDelegate::Default(
1236
          isolate,
1237
          current_context,
1238
          resolver,
1239
8
          static_cast<v8::MeasureMemoryMode>(mode));
1240
8
  isolate->MeasureMemory(std::move(delegate),
1241
                         static_cast<v8::MeasureMemoryExecution>(execution));
1242
8
  v8::Local<v8::Promise> promise = resolver->GetPromise();
1243
1244
16
  args.GetReturnValue().Set(promise);
1245
}
1246
1247
5
MicrotaskQueueWrap::MicrotaskQueueWrap(Environment* env, Local<Object> obj)
1248
  : BaseObject(env, obj),
1249
    microtask_queue_(
1250
5
        MicrotaskQueue::New(env->isolate(), MicrotasksPolicy::kExplicit)) {
1251
5
  MakeWeak();
1252
5
}
1253
1254
const std::shared_ptr<MicrotaskQueue>&
1255
15
MicrotaskQueueWrap::microtask_queue() const {
1256
15
  return microtask_queue_;
1257
}
1258
1259
5
void MicrotaskQueueWrap::New(const FunctionCallbackInfo<Value>& args) {
1260
5
  CHECK(args.IsConstructCall());
1261
10
  new MicrotaskQueueWrap(Environment::GetCurrent(args), args.This());
1262
5
}
1263
1264
1303
void MicrotaskQueueWrap::Init(Environment* env, Local<Object> target) {
1265
2606
  HandleScope scope(env->isolate());
1266
1303
  Local<FunctionTemplate> tmpl = env->NewFunctionTemplate(New);
1267
2606
  tmpl->InstanceTemplate()->SetInternalFieldCount(
1268
      ContextifyScript::kInternalFieldCount);
1269
1303
  env->set_microtask_queue_ctor_template(tmpl);
1270
1303
  env->SetConstructorFunction(target, "MicrotaskQueue", tmpl);
1271
1303
}
1272
1273
5288
void MicrotaskQueueWrap::RegisterExternalReferences(
1274
    ExternalReferenceRegistry* registry) {
1275
5288
  registry->Register(New);
1276
5288
}
1277
1278
1303
void Initialize(Local<Object> target,
1279
                Local<Value> unused,
1280
                Local<Context> context,
1281
                void* priv) {
1282
1303
  Environment* env = Environment::GetCurrent(context);
1283
1303
  Isolate* isolate = env->isolate();
1284
1303
  ContextifyContext::Init(env, target);
1285
1303
  ContextifyScript::Init(env, target);
1286
1303
  MicrotaskQueueWrap::Init(env, target);
1287
1288
1303
  env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog);
1289
1303
  env->SetMethod(target, "stopSigintWatchdog", StopSigintWatchdog);
1290
  // Used in tests.
1291
1303
  env->SetMethodNoSideEffect(
1292
      target, "watchdogHasPendingSigint", WatchdogHasPendingSigint);
1293
1294
  {
1295
1303
    Local<FunctionTemplate> tpl = FunctionTemplate::New(env->isolate());
1296
1303
    tpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "CompiledFnEntry"));
1297
2606
    tpl->InstanceTemplate()->SetInternalFieldCount(
1298
        CompiledFnEntry::kInternalFieldCount);
1299
1300
1303
    env->set_compiled_fn_entry_template(tpl->InstanceTemplate());
1301
  }
1302
1303
1303
  Local<Object> constants = Object::New(env->isolate());
1304
1303
  Local<Object> measure_memory = Object::New(env->isolate());
1305
1303
  Local<Object> memory_execution = Object::New(env->isolate());
1306
1307
  {
1308
1303
    Local<Object> memory_mode = Object::New(env->isolate());
1309
1303
    MeasureMemoryMode SUMMARY = MeasureMemoryMode::kSummary;
1310
1303
    MeasureMemoryMode DETAILED = MeasureMemoryMode::kDetailed;
1311
3909
    NODE_DEFINE_CONSTANT(memory_mode, SUMMARY);
1312
3909
    NODE_DEFINE_CONSTANT(memory_mode, DETAILED);
1313
2606
    READONLY_PROPERTY(measure_memory, "mode", memory_mode);
1314
  }
1315
1316
  {
1317
1303
    MeasureMemoryExecution DEFAULT = MeasureMemoryExecution::kDefault;
1318
1303
    MeasureMemoryExecution EAGER = MeasureMemoryExecution::kEager;
1319
3909
    NODE_DEFINE_CONSTANT(memory_execution, DEFAULT);
1320
3909
    NODE_DEFINE_CONSTANT(memory_execution, EAGER);
1321
3909
    READONLY_PROPERTY(measure_memory, "execution", memory_execution);
1322
  }
1323
1324
3909
  READONLY_PROPERTY(constants, "measureMemory", measure_memory);
1325
1326
2606
  target->Set(context, env->constants_string(), constants).Check();
1327
1328
1303
  env->SetMethod(target, "measureMemory", MeasureMemory);
1329
1303
}
1330
1331
5288
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1332
5288
  ContextifyContext::RegisterExternalReferences(registry);
1333
5288
  ContextifyScript::RegisterExternalReferences(registry);
1334
5288
  MicrotaskQueueWrap::RegisterExternalReferences(registry);
1335
1336
5288
  registry->Register(StartSigintWatchdog);
1337
5288
  registry->Register(StopSigintWatchdog);
1338
5288
  registry->Register(WatchdogHasPendingSigint);
1339
5288
  registry->Register(MeasureMemory);
1340
5288
}
1341
}  // namespace contextify
1342
}  // namespace node
1343
1344
5356
NODE_MODULE_CONTEXT_AWARE_INTERNAL(contextify, node::contextify::Initialize)
1345
5288
NODE_MODULE_EXTERNAL_REFERENCE(contextify,
1346
                               node::contextify::RegisterExternalReferences)