GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_contextify.cc Lines: 583 637 91.5 %
Date: 2022-08-02 04:16:51 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
617
ContextifyContext::ContextifyContext(
112
    Environment* env,
113
    Local<Object> sandbox_obj,
114
617
    const ContextOptions& options)
115
  : env_(env),
116
1234
    microtask_queue_wrap_(options.microtask_queue_wrap) {
117
617
  MaybeLocal<Context> v8_context = CreateV8Context(env, sandbox_obj, options);
118
119
  // Allocation failure, maximum call stack size reached, termination, etc.
120
617
  if (v8_context.IsEmpty()) return;
121
122
1234
  context_.Reset(env->isolate(), v8_context.ToLocalChecked());
123
617
  context_.SetWeak(this, WeakCallback, WeakCallbackType::kParameter);
124
617
  env->AddCleanupHook(CleanupHook, this);
125
}
126
127
128
505
ContextifyContext::~ContextifyContext() {
129
505
  env()->RemoveCleanupHook(CleanupHook, this);
130
505
  Isolate* isolate = env()->isolate();
131
1010
  HandleScope scope(isolate);
132
133
  env()->async_hooks()
134
505
    ->RemoveContext(PersistentToLocal::Weak(isolate, context_));
135
505
}
136
137
138
442
void ContextifyContext::CleanupHook(void* arg) {
139
442
  ContextifyContext* self = static_cast<ContextifyContext*>(arg);
140
442
  self->context_.Reset();
141
442
  delete self;
142
442
}
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
617
MaybeLocal<Object> ContextifyContext::CreateDataWrapper(Environment* env) {
151
  Local<Object> wrapper;
152
617
  if (!env->script_data_constructor_function()
153
617
           ->NewInstance(env->context())
154
617
           .ToLocal(&wrapper)) {
155
    return MaybeLocal<Object>();
156
  }
157
158
617
  wrapper->SetAlignedPointerInInternalField(ContextifyContext::kSlot, this);
159
617
  return wrapper;
160
}
161
162
617
MaybeLocal<Context> ContextifyContext::CreateV8Context(
163
    Environment* env,
164
    Local<Object> sandbox_obj,
165
    const ContextOptions& options) {
166
617
  EscapableHandleScope scope(env->isolate());
167
  Local<FunctionTemplate> function_template =
168
617
      FunctionTemplate::New(env->isolate());
169
170
617
  function_template->SetClassName(sandbox_obj->GetConstructorName());
171
172
  Local<ObjectTemplate> object_template =
173
617
      function_template->InstanceTemplate();
174
175
  Local<Object> data_wrapper;
176
1234
  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
617
      PropertyHandlerFlags::kHasNoSideEffect);
188
189
  IndexedPropertyHandlerConfiguration indexed_config(
190
      IndexedPropertyGetterCallback,
191
      IndexedPropertySetterCallback,
192
      IndexedPropertyDescriptorCallback,
193
      IndexedPropertyDeleterCallback,
194
      PropertyEnumeratorCallback,
195
      IndexedPropertyDefinerCallback,
196
      data_wrapper,
197
617
      PropertyHandlerFlags::kHasNoSideEffect);
198
199
617
  object_template->SetHandler(config);
200
617
  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
1234
      microtask_queue() ?
208
622
          microtask_queue().get() :
209

1851
          env->isolate()->GetCurrentContext()->GetMicrotaskQueue());
210
617
  if (ctx.IsEmpty()) return MaybeLocal<Context>();
211
  // Only partially initialize the context - the primordials are left out
212
  // and only initialized when necessary.
213
1234
  if (InitializeContextRuntime(ctx).IsNothing()) {
214
    return MaybeLocal<Context>();
215
  }
216
217
617
  if (ctx.IsEmpty()) {
218
    return MaybeLocal<Context>();
219
  }
220
221
617
  Local<Context> context = env->context();
222
617
  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
617
  ctx->SetEmbedderData(ContextEmbedderIndex::kSandboxObject, sandbox_obj);
231
  sandbox_obj->SetPrivate(context,
232
                          env->contextify_global_private_symbol(),
233
1234
                          ctx->Global());
234
235
1234
  Utf8Value name_val(env->isolate(), options.name);
236
  // Delegate the code generation validation to
237
  // node::ModifyCodeGenerationFromStrings.
238
617
  ctx->AllowCodeGenerationFromStrings(false);
239
617
  ctx->SetEmbedderData(ContextEmbedderIndex::kAllowCodeGenerationFromStrings,
240
                       options.allow_code_gen_strings);
241
617
  ctx->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
242
                       options.allow_code_gen_wasm);
243
244
1234
  ContextInfo info(*name_val);
245
246
617
  if (!options.origin.IsEmpty()) {
247
4
    Utf8Value origin_val(env->isolate(), options.origin);
248
2
    info.origin = *origin_val;
249
  }
250
251
617
  env->AssignToContext(ctx, info);
252
253
617
  return scope.Escape(ctx);
254
}
255
256
257
1303
void ContextifyContext::Init(Environment* env, Local<Object> target) {
258
1303
  Isolate* isolate = env->isolate();
259
1303
  Local<Context> context = env->context();
260
261
  Local<FunctionTemplate> function_template =
262
1303
      NewFunctionTemplate(isolate, nullptr);
263
2606
  function_template->InstanceTemplate()->SetInternalFieldCount(
264
      ContextifyContext::kInternalFieldCount);
265
1303
  env->set_script_data_constructor_function(
266
1303
      function_template->GetFunction(env->context()).ToLocalChecked());
267
268
1303
  SetMethod(context, target, "makeContext", MakeContext);
269
1303
  SetMethod(context, target, "isContext", IsContext);
270
1303
  SetMethod(context, target, "compileFunction", CompileFunction);
271
1303
}
272
273
5300
void ContextifyContext::RegisterExternalReferences(
274
    ExternalReferenceRegistry* registry) {
275
5300
  registry->Register(MakeContext);
276
5300
  registry->Register(IsContext);
277
5300
  registry->Register(CompileFunction);
278
5300
}
279
280
// makeContext(sandbox, name, origin, strings, wasm);
281
617
void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
282
617
  Environment* env = Environment::GetCurrent(args);
283
284
617
  CHECK_EQ(args.Length(), 6);
285
617
  CHECK(args[0]->IsObject());
286
1234
  Local<Object> sandbox = args[0].As<Object>();
287
288
  // Don't allow contextifying a sandbox multiple times.
289
1234
  CHECK(
290
      !sandbox->HasPrivate(
291
          env->context(),
292
          env->contextify_context_private_symbol()).FromJust());
293
294
617
  ContextOptions options;
295
296
1234
  CHECK(args[1]->IsString());
297
1234
  options.name = args[1].As<String>();
298
299

2464
  CHECK(args[2]->IsString() || args[2]->IsUndefined());
300
1234
  if (args[2]->IsString()) {
301
4
    options.origin = args[2].As<String>();
302
  }
303
304
617
  CHECK(args[3]->IsBoolean());
305
1234
  options.allow_code_gen_strings = args[3].As<Boolean>();
306
307
617
  CHECK(args[4]->IsBoolean());
308
1234
  options.allow_code_gen_wasm = args[4].As<Boolean>();
309
310
617
  if (args[5]->IsObject() &&
311

627
      !env->microtask_queue_ctor_template().IsEmpty() &&
312

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

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

139
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
455


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

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

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

15
  if (desc.has_get() || desc.has_set()) {
528
    PropertyDescriptor desc_for_sandbox(
529
15
        desc.has_get() ? desc.get() : Undefined(isolate).As<Value>(),
530

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

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

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

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

7579
  TRACE_EVENT_END0(TRACING_CATEGORY_NODE2(vm, script), "ContextifyScript::New");
825
}
826
827
6801
bool ContextifyScript::InstanceOf(Environment* env,
828
                                  const Local<Value>& value) {
829

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

14689
  CHECK(args[0]->IsObject() || args[0]->IsNull());
861
862
  Local<Context> context;
863
6801
  std::shared_ptr<v8::MicrotaskQueue> microtask_queue;
864
865
6801
  if (args[0]->IsObject()) {
866
2857
    Local<Object> sandbox = args[0].As<Object>();
867
    // Get the context from the sandbox
868
    ContextifyContext* contextify_context =
869
2857
        ContextifyContext::ContextFromContextifiedSandbox(env, sandbox);
870
2857
    CHECK_NOT_NULL(contextify_context);
871
2857
    CHECK_EQ(contextify_context->env(), env);
872
873
2857
    context = contextify_context->context();
874
2857
    if (context.IsEmpty()) return;
875
876
2857
    microtask_queue = contextify_context->microtask_queue();
877
  } else {
878
3944
    context = env->context();
879
  }
880
881

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

6785
    if (!result.IsEmpty() && mtask_queue)
941
2
      mtask_queue->PerformCheckpoint(env->isolate());
942
6785
    return result;
943
6801
  };
944

6801
  if (break_on_sigint && timeout != -1) {
945
    Watchdog wd(env->isolate(), timeout, &timed_out);
946
    SigintWatchdog swd(env->isolate(), &received_signal);
947
    result = run();
948
6801
  } else if (break_on_sigint) {
949
2393
    SigintWatchdog swd(env->isolate(), &received_signal);
950
1198
    result = run();
951
5603
  } else if (timeout != -1) {
952
30
    Watchdog wd(env->isolate(), timeout, &timed_out);
953
15
    result = run();
954
  } else {
955
5588
    result = run();
956
  }
957
958
  // Convert the termination exception into a regular exception.
959

6785
  if (timed_out || received_signal) {
960

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

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

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