GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_contextify.cc Lines: 580 648 89.5 %
Date: 2021-10-04 04:12:38 Branches: 303 478 63.4 %

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
605
ContextifyContext::ContextifyContext(
112
    Environment* env,
113
    Local<Object> sandbox_obj,
114
605
    const ContextOptions& options)
115
  : env_(env),
116
1210
    microtask_queue_wrap_(options.microtask_queue_wrap) {
117
605
  MaybeLocal<Context> v8_context = CreateV8Context(env, sandbox_obj, options);
118
119
  // Allocation failure, maximum call stack size reached, termination, etc.
120
605
  if (v8_context.IsEmpty()) return;
121
122
1210
  context_.Reset(env->isolate(), v8_context.ToLocalChecked());
123
605
  context_.SetWeak(this, WeakCallback, WeakCallbackType::kParameter);
124
605
  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
443
void ContextifyContext::CleanupHook(void* arg) {
139
443
  ContextifyContext* self = static_cast<ContextifyContext*>(arg);
140
443
  self->context_.Reset();
141
443
  delete self;
142
443
}
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
605
MaybeLocal<Object> ContextifyContext::CreateDataWrapper(Environment* env) {
151
  Local<Object> wrapper;
152
605
  if (!env->script_data_constructor_function()
153
605
           ->NewInstance(env->context())
154
605
           .ToLocal(&wrapper)) {
155
    return MaybeLocal<Object>();
156
  }
157
158
605
  wrapper->SetAlignedPointerInInternalField(ContextifyContext::kSlot, this);
159
605
  return wrapper;
160
}
161
162
605
MaybeLocal<Context> ContextifyContext::CreateV8Context(
163
    Environment* env,
164
    Local<Object> sandbox_obj,
165
    const ContextOptions& options) {
166
605
  EscapableHandleScope scope(env->isolate());
167
  Local<FunctionTemplate> function_template =
168
605
      FunctionTemplate::New(env->isolate());
169
170
605
  function_template->SetClassName(sandbox_obj->GetConstructorName());
171
172
  Local<ObjectTemplate> object_template =
173
605
      function_template->InstanceTemplate();
174
175
  Local<Object> data_wrapper;
176
1210
  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
605
      PropertyHandlerFlags::kHasNoSideEffect);
188
189
  IndexedPropertyHandlerConfiguration indexed_config(
190
      IndexedPropertyGetterCallback,
191
      IndexedPropertySetterCallback,
192
      IndexedPropertyDescriptorCallback,
193
      IndexedPropertyDeleterCallback,
194
      PropertyEnumeratorCallback,
195
      IndexedPropertyDefinerCallback,
196
      data_wrapper,
197
605
      PropertyHandlerFlags::kHasNoSideEffect);
198
199
605
  object_template->SetHandler(config);
200
605
  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
1210
      microtask_queue() ?
208
610
          microtask_queue().get() :
209

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

2416
  CHECK(args[2]->IsString() || args[2]->IsUndefined());
293
1210
  if (args[2]->IsString()) {
294
4
    options.origin = args[2].As<String>();
295
  }
296
297
605
  CHECK(args[3]->IsBoolean());
298
1210
  options.allow_code_gen_strings = args[3].As<Boolean>();
299
300
605
  CHECK(args[4]->IsBoolean());
301
1210
  options.allow_code_gen_wasm = args[4].As<Boolean>();
302
303
605
  if (args[5]->IsObject() &&
304

615
      !env->microtask_queue_ctor_template().IsEmpty() &&
305

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

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

136
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
448


227
  if (!is_declared && args.ShouldThrowOnError() && is_contextual_store &&
449
30
      !is_function)
450
1
    return;
451
452
77
  if (!is_declared_on_global_proxy && is_declared_on_sandbox  &&
453


212
      args.ShouldThrowOnError() && is_contextual_store && !is_function) {
454
    // The property exists on the sandbox but not on the global
455
    // proxy. Setting it would throw because we are in strict mode.
456
    // Don't attempt to set it by signaling that the call was
457
    // intercepted. Only change the value on the sandbox.
458
8
    args.GetReturnValue().Set(false);
459
  }
460
461
270
  USE(ctx->sandbox()->Set(context, property, value));
462
}
463
464
// static
465
53
void ContextifyContext::PropertyDescriptorCallback(
466
    Local<Name> property,
467
    const PropertyCallbackInfo<Value>& args) {
468
53
  ContextifyContext* ctx = ContextifyContext::Get(args);
469
470
  // Still initializing
471
53
  if (ctx->context_.IsEmpty())
472
    return;
473
474
53
  Local<Context> context = ctx->context();
475
476
53
  Local<Object> sandbox = ctx->sandbox();
477
478

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

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

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

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

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

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

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

3616
  TRACE_EVENT_NESTABLE_ASYNC_END0(
830
      TRACING_CATEGORY_NODE2(vm, script),
831
      "ContextifyScript::New",
832
      contextify_script);
833
}
834
835
2983
bool ContextifyScript::InstanceOf(Environment* env,
836
                                  const Local<Value>& value) {
837

5966
  return !value.IsEmpty() &&
838
8949
         env->script_context_constructor_template()->HasInstance(value);
839
}
840
841
11
void ContextifyScript::CreateCachedData(
842
    const FunctionCallbackInfo<Value>& args) {
843
11
  Environment* env = Environment::GetCurrent(args);
844
  ContextifyScript* wrapped_script;
845
11
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
846
  Local<UnboundScript> unbound_script =
847
11
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
848
  std::unique_ptr<ScriptCompiler::CachedData> cached_data(
849
22
      ScriptCompiler::CreateCodeCache(unbound_script));
850
11
  if (!cached_data) {
851
    args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked());
852
  } else {
853
    MaybeLocal<Object> buf = Buffer::Copy(
854
        env,
855
22
        reinterpret_cast<const char*>(cached_data->data),
856
11
        cached_data->length);
857
22
    args.GetReturnValue().Set(buf.ToLocalChecked());
858
  }
859
}
860
861
2163
void ContextifyScript::RunInThisContext(
862
    const FunctionCallbackInfo<Value>& args) {
863
2163
  Environment* env = Environment::GetCurrent(args);
864
865
  ContextifyScript* wrapped_script;
866
2163
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
867
868

2607
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
869
      TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script);
870
871
  // TODO(addaleax): Use an options object or otherwise merge this with
872
  // RunInContext().
873
2163
  CHECK_EQ(args.Length(), 4);
874
875
2163
  CHECK(args[0]->IsNumber());
876
4326
  int64_t timeout = args[0]->IntegerValue(env->context()).FromJust();
877
878
2163
  CHECK(args[1]->IsBoolean());
879
2163
  bool display_errors = args[1]->IsTrue();
880
881
2163
  CHECK(args[2]->IsBoolean());
882
2163
  bool break_on_sigint = args[2]->IsTrue();
883
884
2163
  CHECK(args[3]->IsBoolean());
885
2163
  bool break_on_first_line = args[3]->IsTrue();
886
887
  // Do the eval within this context
888
2163
  EvalMachine(env,
889
              timeout,
890
              display_errors,
891
              break_on_sigint,
892
              break_on_first_line,
893
              nullptr,  // microtask_queue
894
              args);
895
896

2578
  TRACE_EVENT_NESTABLE_ASYNC_END0(
897
      TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script);
898
}
899
900
820
void ContextifyScript::RunInContext(const FunctionCallbackInfo<Value>& args) {
901
820
  Environment* env = Environment::GetCurrent(args);
902
903
  ContextifyScript* wrapped_script;
904
820
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
905
906
820
  CHECK_EQ(args.Length(), 5);
907
908
820
  CHECK(args[0]->IsObject());
909
820
  Local<Object> sandbox = args[0].As<Object>();
910
  // Get the context from the sandbox
911
  ContextifyContext* contextify_context =
912
820
      ContextifyContext::ContextFromContextifiedSandbox(env, sandbox);
913
820
  CHECK_NOT_NULL(contextify_context);
914
915
820
  Local<Context> context = contextify_context->context();
916
820
  if (context.IsEmpty())
917
    return;
918
919

1045
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
920
      TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script);
921
922
820
  CHECK(args[1]->IsNumber());
923
1640
  int64_t timeout = args[1]->IntegerValue(env->context()).FromJust();
924
925
820
  CHECK(args[2]->IsBoolean());
926
820
  bool display_errors = args[2]->IsTrue();
927
928
820
  CHECK(args[3]->IsBoolean());
929
820
  bool break_on_sigint = args[3]->IsTrue();
930
931
820
  CHECK(args[4]->IsBoolean());
932
820
  bool break_on_first_line = args[4]->IsTrue();
933
934
  // Do the eval within the context
935
820
  Context::Scope context_scope(context);
936
820
  EvalMachine(contextify_context->env(),
937
              timeout,
938
              display_errors,
939
              break_on_sigint,
940
              break_on_first_line,
941
1640
              contextify_context->microtask_queue(),
942
              args);
943
944

1045
  TRACE_EVENT_NESTABLE_ASYNC_END0(
945
      TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script);
946
}
947
948
2983
bool ContextifyScript::EvalMachine(Environment* env,
949
                                   const int64_t timeout,
950
                                   const bool display_errors,
951
                                   const bool break_on_sigint,
952
                                   const bool break_on_first_line,
953
                                   std::shared_ptr<MicrotaskQueue> mtask_queue,
954
                                   const FunctionCallbackInfo<Value>& args) {
955
2983
  if (!env->can_call_into_js())
956
    return false;
957
2983
  if (!ContextifyScript::InstanceOf(env, args.Holder())) {
958
    THROW_ERR_INVALID_THIS(
959
        env,
960
        "Script methods can only be called on script instances.");
961
    return false;
962
  }
963
5950
  TryCatchScope try_catch(env);
964
5950
  Isolate::SafeForTerminationScope safe_for_termination(env->isolate());
965
  ContextifyScript* wrapped_script;
966
2983
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder(), false);
967
  Local<UnboundScript> unbound_script =
968
2983
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
969
2983
  Local<Script> script = unbound_script->BindToCurrentContext();
970
971
#if HAVE_INSPECTOR
972
2983
  if (break_on_first_line) {
973
10
    env->inspector_agent()->PauseOnNextJavascriptStatement("Break on start");
974
  }
975
#endif
976
977
  MaybeLocal<Value> result;
978
2983
  bool timed_out = false;
979
2983
  bool received_signal = false;
980
2983
  auto run = [&]() {
981
2983
    MaybeLocal<Value> result = script->Run(env->context());
982

2967
    if (!result.IsEmpty() && mtask_queue)
983
2
      mtask_queue->PerformCheckpoint(env->isolate());
984
2967
    return result;
985
2983
  };
986

2983
  if (break_on_sigint && timeout != -1) {
987
    Watchdog wd(env->isolate(), timeout, &timed_out);
988
    SigintWatchdog swd(env->isolate(), &received_signal);
989
    result = run();
990
2983
  } else if (break_on_sigint) {
991
381
    SigintWatchdog swd(env->isolate(), &received_signal);
992
192
    result = run();
993
2791
  } else if (timeout != -1) {
994
30
    Watchdog wd(env->isolate(), timeout, &timed_out);
995
15
    result = run();
996
  } else {
997
2776
    result = run();
998
  }
999
1000
  // Convert the termination exception into a regular exception.
1001

2967
  if (timed_out || received_signal) {
1002

21
    if (!env->is_main_thread() && env->is_stopping())
1003
      return false;
1004
21
    env->isolate()->CancelTerminateExecution();
1005
    // It is possible that execution was terminated by another timeout in
1006
    // which this timeout is nested, so check whether one of the watchdogs
1007
    // from this invocation is responsible for termination.
1008
21
    if (timed_out) {
1009
10
      node::THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout);
1010
11
    } else if (received_signal) {
1011
11
      node::THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env);
1012
    }
1013
  }
1014
1015
2967
  if (try_catch.HasCaught()) {
1016

170
    if (!timed_out && !received_signal && display_errors) {
1017
      // We should decorate non-termination exceptions
1018
97
      errors::DecorateErrorStack(env, try_catch);
1019
    }
1020
1021
    // If there was an exception thrown during script execution, re-throw it.
1022
    // If one of the above checks threw, re-throw the exception instead of
1023
    // letting try_catch catch it.
1024
    // If execution has been terminated, but not by one of the watchdogs from
1025
    // this invocation, this will re-throw a `null` value.
1026
170
    if (!try_catch.HasTerminated())
1027
167
      try_catch.ReThrow();
1028
1029
170
    return false;
1030
  }
1031
1032
2797
  args.GetReturnValue().Set(result.ToLocalChecked());
1033
2797
  return true;
1034
}
1035
1036
1037
3196
ContextifyScript::ContextifyScript(Environment* env, Local<Object> object)
1038
    : BaseObject(env, object),
1039
3196
      id_(env->get_next_script_id()) {
1040
3196
  MakeWeak();
1041
3196
  env->id_to_script_map.emplace(id_, this);
1042
3196
}
1043
1044
1045
18630
ContextifyScript::~ContextifyScript() {
1046
6210
  env()->id_to_script_map.erase(id_);
1047
12420
}
1048
1049
1050
32382
void ContextifyContext::CompileFunction(
1051
    const FunctionCallbackInfo<Value>& args) {
1052
32382
  Environment* env = Environment::GetCurrent(args);
1053
32382
  Isolate* isolate = env->isolate();
1054
32382
  Local<Context> context = env->context();
1055
1056
  // Argument 1: source code
1057
64764
  CHECK(args[0]->IsString());
1058
64764
  Local<String> code = args[0].As<String>();
1059
1060
  // Argument 2: filename
1061
64764
  CHECK(args[1]->IsString());
1062
64764
  Local<String> filename = args[1].As<String>();
1063
1064
  // Argument 3: line offset
1065
32382
  CHECK(args[2]->IsNumber());
1066
64764
  int line_offset = args[2].As<Int32>()->Value();
1067
1068
  // Argument 4: column offset
1069
32382
  CHECK(args[3]->IsNumber());
1070
64764
  int column_offset = args[3].As<Int32>()->Value();
1071
1072
  // Argument 5: cached data (optional)
1073
  Local<ArrayBufferView> cached_data_buf;
1074
64764
  if (!args[4]->IsUndefined()) {
1075
    CHECK(args[4]->IsArrayBufferView());
1076
    cached_data_buf = args[4].As<ArrayBufferView>();
1077
  }
1078
1079
  // Argument 6: produce cache data
1080
32382
  CHECK(args[5]->IsBoolean());
1081
32382
  bool produce_cached_data = args[5]->IsTrue();
1082
1083
  // Argument 7: parsing context (optional)
1084
  Local<Context> parsing_context;
1085
64764
  if (!args[6]->IsUndefined()) {
1086
2
    CHECK(args[6]->IsObject());
1087
    ContextifyContext* sandbox =
1088
2
        ContextifyContext::ContextFromContextifiedSandbox(
1089
4
            env, args[6].As<Object>());
1090
2
    CHECK_NOT_NULL(sandbox);
1091
2
    parsing_context = sandbox->context();
1092
  } else {
1093
32380
    parsing_context = context;
1094
  }
1095
1096
  // Argument 8: context extensions (optional)
1097
  Local<Array> context_extensions_buf;
1098
64764
  if (!args[7]->IsUndefined()) {
1099
32382
    CHECK(args[7]->IsArray());
1100
64764
    context_extensions_buf = args[7].As<Array>();
1101
  }
1102
1103
  // Argument 9: params for the function (optional)
1104
  Local<Array> params_buf;
1105
64764
  if (!args[8]->IsUndefined()) {
1106
32376
    CHECK(args[8]->IsArray());
1107
64752
    params_buf = args[8].As<Array>();
1108
  }
1109
1110
  // Read cache from cached data buffer
1111
32382
  ScriptCompiler::CachedData* cached_data = nullptr;
1112
32382
  if (!cached_data_buf.IsEmpty()) {
1113
    uint8_t* data = static_cast<uint8_t*>(
1114
        cached_data_buf->Buffer()->GetBackingStore()->Data());
1115
    cached_data = new ScriptCompiler::CachedData(
1116
      data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
1117
  }
1118
1119
  // Get the function id
1120
32382
  uint32_t id = env->get_next_function_id();
1121
1122
  // Set host_defined_options
1123
  Local<PrimitiveArray> host_defined_options =
1124
32382
      PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
1125
64764
  host_defined_options->Set(
1126
      isolate,
1127
      loader::HostDefinedOptions::kType,
1128
      Number::New(isolate, loader::ScriptType::kFunction));
1129
64764
  host_defined_options->Set(
1130
      isolate, loader::HostDefinedOptions::kID, Number::New(isolate, id));
1131
1132
  ScriptOrigin origin(isolate,
1133
                      filename,
1134
                      line_offset,       // line offset
1135
                      column_offset,     // column offset
1136
                      true,              // is cross origin
1137
                      -1,                // script id
1138
                      Local<Value>(),    // source map URL
1139
                      false,             // is opaque (?)
1140
                      false,             // is WASM
1141
                      false,             // is ES Module
1142
64764
                      host_defined_options);
1143
1144
32382
  ScriptCompiler::Source source(code, origin, cached_data);
1145
  ScriptCompiler::CompileOptions options;
1146
32382
  if (source.GetCachedData() == nullptr) {
1147
32382
    options = ScriptCompiler::kNoCompileOptions;
1148
  } else {
1149
    options = ScriptCompiler::kConsumeCodeCache;
1150
  }
1151
1152
32382
  TryCatchScope try_catch(env);
1153
32382
  Context::Scope scope(parsing_context);
1154
1155
  // Read context extensions from buffer
1156
32382
  std::vector<Local<Object>> context_extensions;
1157
32382
  if (!context_extensions_buf.IsEmpty()) {
1158
64765
    for (uint32_t n = 0; n < context_extensions_buf->Length(); n++) {
1159
      Local<Value> val;
1160
2
      if (!context_extensions_buf->Get(context, n).ToLocal(&val)) return;
1161
1
      CHECK(val->IsObject());
1162
1
      context_extensions.push_back(val.As<Object>());
1163
    }
1164
  }
1165
1166
  // Read params from params buffer
1167
32382
  std::vector<Local<String>> params;
1168
32382
  if (!params_buf.IsEmpty()) {
1169
226585
    for (uint32_t n = 0; n < params_buf->Length(); n++) {
1170
      Local<Value> val;
1171
323666
      if (!params_buf->Get(context, n).ToLocal(&val)) return;
1172
323666
      CHECK(val->IsString());
1173
161833
      params.push_back(val.As<String>());
1174
    }
1175
  }
1176
1177
  Local<ScriptOrModule> script;
1178
  MaybeLocal<Function> maybe_fn = ScriptCompiler::CompileFunctionInContext(
1179
      parsing_context, &source, params.size(), params.data(),
1180
      context_extensions.size(), context_extensions.data(), options,
1181
32382
      v8::ScriptCompiler::NoCacheReason::kNoCacheNoReason, &script);
1182
1183
  Local<Function> fn;
1184
32382
  if (!maybe_fn.ToLocal(&fn)) {
1185

29
    if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
1186
29
      errors::DecorateErrorStack(env, try_catch);
1187
29
      try_catch.ReThrow();
1188
    }
1189
29
    return;
1190
  }
1191
1192
  Local<Object> cache_key;
1193
32353
  if (!env->compiled_fn_entry_template()->NewInstance(
1194
64706
           context).ToLocal(&cache_key)) {
1195
    return;
1196
  }
1197
32353
  CompiledFnEntry* entry = new CompiledFnEntry(env, cache_key, id, script);
1198
32353
  env->id_to_function_map.emplace(id, entry);
1199
1200
32353
  Local<Object> result = Object::New(isolate);
1201
97059
  if (result->Set(parsing_context, env->function_string(), fn).IsNothing())
1202
    return;
1203
64706
  if (result->Set(parsing_context, env->cache_key_string(), cache_key)
1204
32353
          .IsNothing())
1205
    return;
1206
1207
32353
  if (produce_cached_data) {
1208
    const std::unique_ptr<ScriptCompiler::CachedData> cached_data(
1209
        ScriptCompiler::CreateCodeCacheForFunction(fn));
1210
    bool cached_data_produced = cached_data != nullptr;
1211
    if (cached_data_produced) {
1212
      MaybeLocal<Object> buf = Buffer::Copy(
1213
          env,
1214
          reinterpret_cast<const char*>(cached_data->data),
1215
          cached_data->length);
1216
      if (result
1217
              ->Set(parsing_context,
1218
                    env->cached_data_string(),
1219
                    buf.ToLocalChecked())
1220
              .IsNothing())
1221
        return;
1222
    }
1223
    if (result
1224
            ->Set(parsing_context,
1225
                  env->cached_data_produced_string(),
1226
                  Boolean::New(isolate, cached_data_produced))
1227
            .IsNothing())
1228
      return;
1229
  }
1230
1231
64706
  args.GetReturnValue().Set(result);
1232
}
1233
1234
void CompiledFnEntry::WeakCallback(
1235
    const WeakCallbackInfo<CompiledFnEntry>& data) {
1236
  CompiledFnEntry* entry = data.GetParameter();
1237
  delete entry;
1238
}
1239
1240
32353
CompiledFnEntry::CompiledFnEntry(Environment* env,
1241
                                 Local<Object> object,
1242
                                 uint32_t id,
1243
32353
                                 Local<ScriptOrModule> script)
1244
    : BaseObject(env, object),
1245
      id_(id),
1246
32353
      script_(env->isolate(), script) {
1247
32353
  script_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
1248
32353
}
1249
1250
182766
CompiledFnEntry::~CompiledFnEntry() {
1251
60922
  env()->id_to_function_map.erase(id_);
1252
60922
  script_.ClearWeak();
1253
121844
}
1254
1255
189
static void StartSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1256
189
  int ret = SigintWatchdogHelper::GetInstance()->Start();
1257
189
  args.GetReturnValue().Set(ret == 0);
1258
189
}
1259
1260
186
static void StopSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1261
186
  bool had_pending_signals = SigintWatchdogHelper::GetInstance()->Stop();
1262
186
  args.GetReturnValue().Set(had_pending_signals);
1263
186
}
1264
1265
3
static void WatchdogHasPendingSigint(const FunctionCallbackInfo<Value>& args) {
1266
3
  bool ret = SigintWatchdogHelper::GetInstance()->HasPendingSignal();
1267
3
  args.GetReturnValue().Set(ret);
1268
3
}
1269
1270
8
static void MeasureMemory(const FunctionCallbackInfo<Value>& args) {
1271
8
  CHECK(args[0]->IsInt32());
1272
8
  CHECK(args[1]->IsInt32());
1273
16
  int32_t mode = args[0].As<v8::Int32>()->Value();
1274
16
  int32_t execution = args[1].As<v8::Int32>()->Value();
1275
8
  Isolate* isolate = args.GetIsolate();
1276
1277
8
  Local<Context> current_context = isolate->GetCurrentContext();
1278
  Local<Promise::Resolver> resolver;
1279
16
  if (!Promise::Resolver::New(current_context).ToLocal(&resolver)) return;
1280
  std::unique_ptr<v8::MeasureMemoryDelegate> delegate =
1281
      v8::MeasureMemoryDelegate::Default(
1282
          isolate,
1283
          current_context,
1284
          resolver,
1285
8
          static_cast<v8::MeasureMemoryMode>(mode));
1286
8
  isolate->MeasureMemory(std::move(delegate),
1287
                         static_cast<v8::MeasureMemoryExecution>(execution));
1288
8
  v8::Local<v8::Promise> promise = resolver->GetPromise();
1289
1290
16
  args.GetReturnValue().Set(promise);
1291
}
1292
1293
5
MicrotaskQueueWrap::MicrotaskQueueWrap(Environment* env, Local<Object> obj)
1294
  : BaseObject(env, obj),
1295
    microtask_queue_(
1296
5
        MicrotaskQueue::New(env->isolate(), MicrotasksPolicy::kExplicit)) {
1297
5
  MakeWeak();
1298
5
}
1299
1300
const std::shared_ptr<MicrotaskQueue>&
1301
15
MicrotaskQueueWrap::microtask_queue() const {
1302
15
  return microtask_queue_;
1303
}
1304
1305
5
void MicrotaskQueueWrap::New(const FunctionCallbackInfo<Value>& args) {
1306
5
  CHECK(args.IsConstructCall());
1307
10
  new MicrotaskQueueWrap(Environment::GetCurrent(args), args.This());
1308
5
}
1309
1310
617
void MicrotaskQueueWrap::Init(Environment* env, Local<Object> target) {
1311
1234
  HandleScope scope(env->isolate());
1312
617
  Local<FunctionTemplate> tmpl = env->NewFunctionTemplate(New);
1313
1234
  tmpl->InstanceTemplate()->SetInternalFieldCount(
1314
      ContextifyScript::kInternalFieldCount);
1315
617
  env->set_microtask_queue_ctor_template(tmpl);
1316
617
  env->SetConstructorFunction(target, "MicrotaskQueue", tmpl);
1317
617
}
1318
1319
4853
void MicrotaskQueueWrap::RegisterExternalReferences(
1320
    ExternalReferenceRegistry* registry) {
1321
4853
  registry->Register(New);
1322
4853
}
1323
1324
617
void Initialize(Local<Object> target,
1325
                Local<Value> unused,
1326
                Local<Context> context,
1327
                void* priv) {
1328
617
  Environment* env = Environment::GetCurrent(context);
1329
617
  Isolate* isolate = env->isolate();
1330
617
  ContextifyContext::Init(env, target);
1331
617
  ContextifyScript::Init(env, target);
1332
617
  MicrotaskQueueWrap::Init(env, target);
1333
1334
617
  env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog);
1335
617
  env->SetMethod(target, "stopSigintWatchdog", StopSigintWatchdog);
1336
  // Used in tests.
1337
617
  env->SetMethodNoSideEffect(
1338
      target, "watchdogHasPendingSigint", WatchdogHasPendingSigint);
1339
1340
  {
1341
617
    Local<FunctionTemplate> tpl = FunctionTemplate::New(env->isolate());
1342
617
    tpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "CompiledFnEntry"));
1343
1234
    tpl->InstanceTemplate()->SetInternalFieldCount(
1344
        CompiledFnEntry::kInternalFieldCount);
1345
1346
617
    env->set_compiled_fn_entry_template(tpl->InstanceTemplate());
1347
  }
1348
1349
617
  Local<Object> constants = Object::New(env->isolate());
1350
617
  Local<Object> measure_memory = Object::New(env->isolate());
1351
617
  Local<Object> memory_execution = Object::New(env->isolate());
1352
1353
  {
1354
617
    Local<Object> memory_mode = Object::New(env->isolate());
1355
617
    MeasureMemoryMode SUMMARY = MeasureMemoryMode::kSummary;
1356
617
    MeasureMemoryMode DETAILED = MeasureMemoryMode::kDetailed;
1357
1851
    NODE_DEFINE_CONSTANT(memory_mode, SUMMARY);
1358
1851
    NODE_DEFINE_CONSTANT(memory_mode, DETAILED);
1359
1234
    READONLY_PROPERTY(measure_memory, "mode", memory_mode);
1360
  }
1361
1362
  {
1363
617
    MeasureMemoryExecution DEFAULT = MeasureMemoryExecution::kDefault;
1364
617
    MeasureMemoryExecution EAGER = MeasureMemoryExecution::kEager;
1365
1851
    NODE_DEFINE_CONSTANT(memory_execution, DEFAULT);
1366
1851
    NODE_DEFINE_CONSTANT(memory_execution, EAGER);
1367
1851
    READONLY_PROPERTY(measure_memory, "execution", memory_execution);
1368
  }
1369
1370
1851
  READONLY_PROPERTY(constants, "measureMemory", measure_memory);
1371
1372
1234
  target->Set(context, env->constants_string(), constants).Check();
1373
1374
617
  env->SetMethod(target, "measureMemory", MeasureMemory);
1375
617
}
1376
1377
4853
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1378
4853
  ContextifyContext::RegisterExternalReferences(registry);
1379
4853
  ContextifyScript::RegisterExternalReferences(registry);
1380
4853
  MicrotaskQueueWrap::RegisterExternalReferences(registry);
1381
1382
4853
  registry->Register(StartSigintWatchdog);
1383
4853
  registry->Register(StopSigintWatchdog);
1384
4853
  registry->Register(WatchdogHasPendingSigint);
1385
4853
  registry->Register(MeasureMemory);
1386
4853
}
1387
}  // namespace contextify
1388
}  // namespace node
1389
1390
4926
NODE_MODULE_CONTEXT_AWARE_INTERNAL(contextify, node::contextify::Initialize)
1391
4853
NODE_MODULE_EXTERNAL_REFERENCE(contextify,
1392
                               node::contextify::RegisterExternalReferences)