GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_contextify.cc Lines: 612 678 90.3 %
Date: 2021-05-30 04:11:56 Branches: 275 412 66.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
12
  return Uint32::New(context->GetIsolate(), index)->ToString(context)
106
6
      .ToLocalChecked();
107
}
108
109
}  // anonymous namespace
110
111
579
ContextifyContext::ContextifyContext(
112
    Environment* env,
113
    Local<Object> sandbox_obj,
114
579
    const ContextOptions& options)
115
  : env_(env),
116
1158
    microtask_queue_wrap_(options.microtask_queue_wrap) {
117
579
  MaybeLocal<Context> v8_context = CreateV8Context(env, sandbox_obj, options);
118
119
  // Allocation failure, maximum call stack size reached, termination, etc.
120
579
  if (v8_context.IsEmpty()) return;
121
122
1158
  context_.Reset(env->isolate(), v8_context.ToLocalChecked());
123
579
  context_.SetWeak(this, WeakCallback, WeakCallbackType::kParameter);
124
579
  env->AddCleanupHook(CleanupHook, this);
125
}
126
127
128
1455
ContextifyContext::~ContextifyContext() {
129
485
  env()->RemoveCleanupHook(CleanupHook, this);
130
485
}
131
132
133
426
void ContextifyContext::CleanupHook(void* arg) {
134
426
  ContextifyContext* self = static_cast<ContextifyContext*>(arg);
135
426
  self->context_.Reset();
136
426
  delete self;
137
426
}
138
139
140
// This is an object that just keeps an internal pointer to this
141
// ContextifyContext.  It's passed to the NamedPropertyHandler.  If we
142
// pass the main JavaScript context object we're embedded in, then the
143
// NamedPropertyHandler will store a reference to it forever and keep it
144
// from getting gc'd.
145
579
MaybeLocal<Object> ContextifyContext::CreateDataWrapper(Environment* env) {
146
  Local<Object> wrapper;
147
1737
  if (!env->script_data_constructor_function()
148
1737
           ->NewInstance(env->context())
149
579
           .ToLocal(&wrapper)) {
150
    return MaybeLocal<Object>();
151
  }
152
153
579
  wrapper->SetAlignedPointerInInternalField(ContextifyContext::kSlot, this);
154
579
  return wrapper;
155
}
156
157
579
MaybeLocal<Context> ContextifyContext::CreateV8Context(
158
    Environment* env,
159
    Local<Object> sandbox_obj,
160
    const ContextOptions& options) {
161
579
  EscapableHandleScope scope(env->isolate());
162
  Local<FunctionTemplate> function_template =
163
579
      FunctionTemplate::New(env->isolate());
164
165
1158
  function_template->SetClassName(sandbox_obj->GetConstructorName());
166
167
  Local<ObjectTemplate> object_template =
168
579
      function_template->InstanceTemplate();
169
170
  Local<Object> data_wrapper;
171
1158
  if (!CreateDataWrapper(env).ToLocal(&data_wrapper))
172
    return MaybeLocal<Context>();
173
174
  NamedPropertyHandlerConfiguration config(
175
      PropertyGetterCallback,
176
      PropertySetterCallback,
177
      PropertyDescriptorCallback,
178
      PropertyDeleterCallback,
179
      PropertyEnumeratorCallback,
180
      PropertyDefinerCallback,
181
      data_wrapper,
182
579
      PropertyHandlerFlags::kHasNoSideEffect);
183
184
  IndexedPropertyHandlerConfiguration indexed_config(
185
      IndexedPropertyGetterCallback,
186
      IndexedPropertySetterCallback,
187
      IndexedPropertyDescriptorCallback,
188
      IndexedPropertyDeleterCallback,
189
      PropertyEnumeratorCallback,
190
      IndexedPropertyDefinerCallback,
191
      data_wrapper,
192
579
      PropertyHandlerFlags::kHasNoSideEffect);
193
194
579
  object_template->SetHandler(config);
195
579
  object_template->SetHandler(indexed_config);
196
  Local<Context> ctx = Context::New(
197
      env->isolate(),
198
      nullptr,  // extensions
199
      object_template,
200
      {},       // global object
201
      {},       // deserialization callback
202
1158
      microtask_queue() ?
203
584
          microtask_queue().get() :
204
1737
          env->isolate()->GetCurrentContext()->GetMicrotaskQueue());
205
579
  if (ctx.IsEmpty()) return MaybeLocal<Context>();
206
  // Only partially initialize the context - the primordials are left out
207
  // and only initialized when necessary.
208
579
  InitializeContextRuntime(ctx);
209
210
579
  if (ctx.IsEmpty()) {
211
    return MaybeLocal<Context>();
212
  }
213
214
579
  Local<Context> context = env->context();
215
1158
  ctx->SetSecurityToken(context->GetSecurityToken());
216
217
  // We need to tie the lifetime of the sandbox object with the lifetime of
218
  // newly created context. We do this by making them hold references to each
219
  // other. The context can directly hold a reference to the sandbox as an
220
  // embedder data field. However, we cannot hold a reference to a v8::Context
221
  // directly in an Object, we instead hold onto the new context's global
222
  // object instead (which then has a reference to the context).
223
579
  ctx->SetEmbedderData(ContextEmbedderIndex::kSandboxObject, sandbox_obj);
224
  sandbox_obj->SetPrivate(context,
225
                          env->contextify_global_private_symbol(),
226
1737
                          ctx->Global());
227
228
1158
  Utf8Value name_val(env->isolate(), options.name);
229
1737
  ctx->AllowCodeGenerationFromStrings(options.allow_code_gen_strings->IsTrue());
230
1158
  ctx->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
231
579
                       options.allow_code_gen_wasm);
232
233
1158
  ContextInfo info(*name_val);
234
235
1158
  if (!options.origin.IsEmpty()) {
236
4
    Utf8Value origin_val(env->isolate(), options.origin);
237
2
    info.origin = *origin_val;
238
  }
239
240
579
  env->AssignToContext(ctx, info);
241
242
579
  return scope.Escape(ctx);
243
}
244
245
246
468
void ContextifyContext::Init(Environment* env, Local<Object> target) {
247
  Local<FunctionTemplate> function_template =
248
468
      FunctionTemplate::New(env->isolate());
249
1404
  function_template->InstanceTemplate()->SetInternalFieldCount(
250
468
      ContextifyContext::kInternalFieldCount);
251
  env->set_script_data_constructor_function(
252
1404
      function_template->GetFunction(env->context()).ToLocalChecked());
253
254
468
  env->SetMethod(target, "makeContext", MakeContext);
255
468
  env->SetMethod(target, "isContext", IsContext);
256
468
  env->SetMethod(target, "compileFunction", CompileFunction);
257
468
}
258
259
4774
void ContextifyContext::RegisterExternalReferences(
260
    ExternalReferenceRegistry* registry) {
261
4774
  registry->Register(MakeContext);
262
4774
  registry->Register(IsContext);
263
4774
  registry->Register(CompileFunction);
264
4774
}
265
266
// makeContext(sandbox, name, origin, strings, wasm);
267
579
void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
268
579
  Environment* env = Environment::GetCurrent(args);
269
270
579
  CHECK_EQ(args.Length(), 6);
271
1158
  CHECK(args[0]->IsObject());
272
1158
  Local<Object> sandbox = args[0].As<Object>();
273
274
  // Don't allow contextifying a sandbox multiple times.
275
1737
  CHECK(
276
      !sandbox->HasPrivate(
277
          env->context(),
278
          env->contextify_context_private_symbol()).FromJust());
279
280
1158
  ContextOptions options;
281
282
1737
  CHECK(args[1]->IsString());
283
1158
  options.name = args[1].As<String>();
284
285

3468
  CHECK(args[2]->IsString() || args[2]->IsUndefined());
286
1737
  if (args[2]->IsString()) {
287
4
    options.origin = args[2].As<String>();
288
  }
289
290
1158
  CHECK(args[3]->IsBoolean());
291
1158
  options.allow_code_gen_strings = args[3].As<Boolean>();
292
293
1158
  CHECK(args[4]->IsBoolean());
294
1158
  options.allow_code_gen_wasm = args[4].As<Boolean>();
295
296

2321
  if (args[5]->IsObject() &&
297

1168
      !env->microtask_queue_ctor_template().IsEmpty() &&
298
589
      env->microtask_queue_ctor_template()->HasInstance(args[5])) {
299
10
    options.microtask_queue_wrap.reset(
300
15
        Unwrap<MicrotaskQueueWrap>(args[5].As<Object>()));
301
  }
302
303
1158
  TryCatchScope try_catch(env);
304
  std::unique_ptr<ContextifyContext> context_ptr =
305
1158
      std::make_unique<ContextifyContext>(env, sandbox, options);
306
307
579
  if (try_catch.HasCaught()) {
308
    if (!try_catch.HasTerminated())
309
      try_catch.ReThrow();
310
    return;
311
  }
312
313
1158
  if (context_ptr->context().IsEmpty())
314
    return;
315
316
  sandbox->SetPrivate(
317
      env->context(),
318
      env->contextify_context_private_symbol(),
319
1737
      External::New(env->isolate(), context_ptr.release()));
320
}
321
322
323
1894
void ContextifyContext::IsContext(const FunctionCallbackInfo<Value>& args) {
324
1894
  Environment* env = Environment::GetCurrent(args);
325
326
3788
  CHECK(args[0]->IsObject());
327
3788
  Local<Object> sandbox = args[0].As<Object>();
328
329
  Maybe<bool> result =
330
      sandbox->HasPrivate(env->context(),
331
3788
                          env->contextify_context_private_symbol());
332
5682
  args.GetReturnValue().Set(result.FromJust());
333
1894
}
334
335
336
59
void ContextifyContext::WeakCallback(
337
    const WeakCallbackInfo<ContextifyContext>& data) {
338
59
  ContextifyContext* context = data.GetParameter();
339
59
  delete context;
340
59
}
341
342
// static
343
1257
ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox(
344
    Environment* env,
345
    const Local<Object>& sandbox) {
346
  MaybeLocal<Value> maybe_value =
347
      sandbox->GetPrivate(env->context(),
348
2514
                          env->contextify_context_private_symbol());
349
  Local<Value> context_external_v;
350

2514
  if (maybe_value.ToLocal(&context_external_v) &&
351
1257
      context_external_v->IsExternal()) {
352
1257
    Local<External> context_external = context_external_v.As<External>();
353
1257
    return static_cast<ContextifyContext*>(context_external->Value());
354
  }
355
  return nullptr;
356
}
357
358
// static
359
template <typename T>
360
1043138
ContextifyContext* ContextifyContext::Get(const PropertyCallbackInfo<T>& args) {
361
1043138
  Local<Value> data = args.Data();
362
  return static_cast<ContextifyContext*>(
363
3129414
      data.As<Object>()->GetAlignedPointerFromInternalField(
364
2086276
          ContextifyContext::kSlot));
365
}
366
367
// static
368
1042679
void ContextifyContext::PropertyGetterCallback(
369
    Local<Name> property,
370
    const PropertyCallbackInfo<Value>& args) {
371
1042679
  ContextifyContext* ctx = ContextifyContext::Get(args);
372
373
  // Still initializing
374
2085358
  if (ctx->context_.IsEmpty())
375
1737
    return;
376
377
1040942
  Local<Context> context = ctx->context();
378
1040942
  Local<Object> sandbox = ctx->sandbox();
379
  MaybeLocal<Value> maybe_rv =
380
1040942
      sandbox->GetRealNamedProperty(context, property);
381
1040942
  if (maybe_rv.IsEmpty()) {
382
    maybe_rv =
383
75070
        ctx->global_proxy()->GetRealNamedProperty(context, property);
384
  }
385
386
  Local<Value> rv;
387
1040942
  if (maybe_rv.ToLocal(&rv)) {
388
1040873
    if (rv == sandbox)
389
10
      rv = ctx->global_proxy();
390
391
2081746
    args.GetReturnValue().Set(rv);
392
  }
393
}
394
395
// static
396
158
void ContextifyContext::PropertySetterCallback(
397
    Local<Name> property,
398
    Local<Value> value,
399
    const PropertyCallbackInfo<Value>& args) {
400
158
  ContextifyContext* ctx = ContextifyContext::Get(args);
401
402
  // Still initializing
403
316
  if (ctx->context_.IsEmpty())
404
14
    return;
405
406
158
  Local<Context> context = ctx->context();
407
158
  PropertyAttribute attributes = PropertyAttribute::None;
408
316
  bool is_declared_on_global_proxy = ctx->global_proxy()
409
316
      ->GetRealNamedPropertyAttributes(context, property)
410
158
      .To(&attributes);
411
  bool read_only =
412
158
      static_cast<int>(attributes) &
413
158
      static_cast<int>(PropertyAttribute::ReadOnly);
414
415
316
  bool is_declared_on_sandbox = ctx->sandbox()
416
316
      ->GetRealNamedPropertyAttributes(context, property)
417
158
      .To(&attributes);
418

312
  read_only = read_only ||
419
154
      (static_cast<int>(attributes) &
420
      static_cast<int>(PropertyAttribute::ReadOnly));
421
422
158
  if (read_only)
423
13
    return;
424
425
  // true for x = 5
426
  // false for this.x = 5
427
  // false for Object.defineProperty(this, 'foo', ...)
428
  // false for vmResult.x = 5 where vmResult = vm.runInContext();
429
290
  bool is_contextual_store = ctx->global_proxy() != args.This();
430
431
  // Indicator to not return before setting (undeclared) function declarations
432
  // on the sandbox in strict mode, i.e. args.ShouldThrowOnError() = true.
433
  // True for 'function f() {}', 'this.f = function() {}',
434
  // 'var f = function()'.
435
  // In effect only for 'function f() {}' because
436
  // var f = function(), is_declared = true
437
  // this.f = function() {}, is_contextual_store = false.
438
145
  bool is_function = value->IsFunction();
439
440

145
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
441


249
  if (!is_declared && args.ShouldThrowOnError() && is_contextual_store &&
442
29
      !is_function)
443
1
    return;
444
445

396
  if (!is_declared_on_global_proxy && is_declared_on_sandbox  &&
446

166
      args.ShouldThrowOnError() && is_contextual_store && !is_function) {
447
    // The property exists on the sandbox but not on the global
448
    // proxy. Setting it would throw because we are in strict mode.
449
    // Don't attempt to set it by signaling that the call was
450
    // intercepted. Only change the value on the sandbox.
451
8
    args.GetReturnValue().Set(false);
452
  }
453
454
288
  USE(ctx->sandbox()->Set(context, property, value));
455
}
456
457
// static
458
53
void ContextifyContext::PropertyDescriptorCallback(
459
    Local<Name> property,
460
    const PropertyCallbackInfo<Value>& args) {
461
53
  ContextifyContext* ctx = ContextifyContext::Get(args);
462
463
  // Still initializing
464
106
  if (ctx->context_.IsEmpty())
465
    return;
466
467
53
  Local<Context> context = ctx->context();
468
469
53
  Local<Object> sandbox = ctx->sandbox();
470
471
159
  if (sandbox->HasOwnProperty(context, property).FromMaybe(false)) {
472
    Local<Value> desc;
473
76
    if (sandbox->GetOwnPropertyDescriptor(context, property).ToLocal(&desc)) {
474
76
      args.GetReturnValue().Set(desc);
475
    }
476
  }
477
}
478
479
// static
480
15
void ContextifyContext::PropertyDefinerCallback(
481
    Local<Name> property,
482
    const PropertyDescriptor& desc,
483
    const PropertyCallbackInfo<Value>& args) {
484
15
  ContextifyContext* ctx = ContextifyContext::Get(args);
485
486
  // Still initializing
487
30
  if (ctx->context_.IsEmpty())
488
    return;
489
490
15
  Local<Context> context = ctx->context();
491
15
  Isolate* isolate = context->GetIsolate();
492
493
15
  PropertyAttribute attributes = PropertyAttribute::None;
494
  bool is_declared =
495
45
      ctx->global_proxy()->GetRealNamedPropertyAttributes(context,
496
15
                                                          property)
497
15
          .To(&attributes);
498
  bool read_only =
499
15
      static_cast<int>(attributes) &
500
15
          static_cast<int>(PropertyAttribute::ReadOnly);
501
502
  // If the property is set on the global as read_only, don't change it on
503
  // the global or sandbox.
504

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

15
  if (desc.has_get() || desc.has_set()) {
522
    PropertyDescriptor desc_for_sandbox(
523
10
        desc.has_get() ? desc.get() : Undefined(isolate).As<Value>(),
524

28
        desc.has_set() ? desc.set() : Undefined(isolate).As<Value>());
525
526
5
    define_prop_on_sandbox(&desc_for_sandbox);
527
  } else {
528
    Local<Value> value =
529
12
        desc.has_value() ? desc.value() : Undefined(isolate).As<Value>();
530
531
10
    if (desc.has_writable()) {
532
      PropertyDescriptor desc_for_sandbox(value, desc.writable());
533
      define_prop_on_sandbox(&desc_for_sandbox);
534
    } else {
535
20
      PropertyDescriptor desc_for_sandbox(value);
536
10
      define_prop_on_sandbox(&desc_for_sandbox);
537
    }
538
  }
539
}
540
541
// static
542
2
void ContextifyContext::PropertyDeleterCallback(
543
    Local<Name> property,
544
    const PropertyCallbackInfo<Boolean>& args) {
545
2
  ContextifyContext* ctx = ContextifyContext::Get(args);
546
547
  // Still initializing
548
4
  if (ctx->context_.IsEmpty())
549
1
    return;
550
551
4
  Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), property);
552
553
4
  if (success.FromMaybe(false))
554
1
    return;
555
556
  // Delete failed on the sandbox, intercept and do not delete on
557
  // the global object.
558
2
  args.GetReturnValue().Set(false);
559
}
560
561
// static
562
228
void ContextifyContext::PropertyEnumeratorCallback(
563
    const PropertyCallbackInfo<Array>& args) {
564
228
  ContextifyContext* ctx = ContextifyContext::Get(args);
565
566
  // Still initializing
567
456
  if (ctx->context_.IsEmpty())
568
    return;
569
570
  Local<Array> properties;
571
572
684
  if (!ctx->sandbox()->GetPropertyNames(ctx->context()).ToLocal(&properties))
573
    return;
574
575
456
  args.GetReturnValue().Set(properties);
576
}
577
578
// static
579
void ContextifyContext::IndexedPropertyGetterCallback(
580
    uint32_t index,
581
    const PropertyCallbackInfo<Value>& args) {
582
  ContextifyContext* ctx = ContextifyContext::Get(args);
583
584
  // Still initializing
585
  if (ctx->context_.IsEmpty())
586
    return;
587
588
  ContextifyContext::PropertyGetterCallback(
589
      Uint32ToName(ctx->context(), index), args);
590
}
591
592
593
1
void ContextifyContext::IndexedPropertySetterCallback(
594
    uint32_t index,
595
    Local<Value> value,
596
    const PropertyCallbackInfo<Value>& args) {
597
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
598
599
  // Still initializing
600
2
  if (ctx->context_.IsEmpty())
601
    return;
602
603
1
  ContextifyContext::PropertySetterCallback(
604
1
      Uint32ToName(ctx->context(), index), value, args);
605
}
606
607
// static
608
1
void ContextifyContext::IndexedPropertyDescriptorCallback(
609
    uint32_t index,
610
    const PropertyCallbackInfo<Value>& args) {
611
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
612
613
  // Still initializing
614
2
  if (ctx->context_.IsEmpty())
615
    return;
616
617
1
  ContextifyContext::PropertyDescriptorCallback(
618
1
      Uint32ToName(ctx->context(), index), args);
619
}
620
621
622
1
void ContextifyContext::IndexedPropertyDefinerCallback(
623
    uint32_t index,
624
    const PropertyDescriptor& desc,
625
    const PropertyCallbackInfo<Value>& args) {
626
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
627
628
  // Still initializing
629
2
  if (ctx->context_.IsEmpty())
630
    return;
631
632
1
  ContextifyContext::PropertyDefinerCallback(
633
1
      Uint32ToName(ctx->context(), index), desc, args);
634
}
635
636
// static
637
void ContextifyContext::IndexedPropertyDeleterCallback(
638
    uint32_t index,
639
    const PropertyCallbackInfo<Boolean>& args) {
640
  ContextifyContext* ctx = ContextifyContext::Get(args);
641
642
  // Still initializing
643
  if (ctx->context_.IsEmpty())
644
    return;
645
646
  Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), index);
647
648
  if (success.FromMaybe(false))
649
    return;
650
651
  // Delete failed on the sandbox, intercept and do not delete on
652
  // the global object.
653
  args.GetReturnValue().Set(false);
654
}
655
656
468
void ContextifyScript::Init(Environment* env, Local<Object> target) {
657
936
  HandleScope scope(env->isolate());
658
  Local<String> class_name =
659
468
      FIXED_ONE_BYTE_STRING(env->isolate(), "ContextifyScript");
660
661
468
  Local<FunctionTemplate> script_tmpl = env->NewFunctionTemplate(New);
662
1404
  script_tmpl->InstanceTemplate()->SetInternalFieldCount(
663
468
      ContextifyScript::kInternalFieldCount);
664
468
  script_tmpl->SetClassName(class_name);
665
468
  env->SetProtoMethod(script_tmpl, "createCachedData", CreateCachedData);
666
468
  env->SetProtoMethod(script_tmpl, "runInContext", RunInContext);
667
468
  env->SetProtoMethod(script_tmpl, "runInThisContext", RunInThisContext);
668
669
468
  Local<Context> context = env->context();
670
671
936
  target->Set(context, class_name,
672
1404
      script_tmpl->GetFunction(context).ToLocalChecked()).Check();
673
468
  env->set_script_context_constructor_template(script_tmpl);
674
468
}
675
676
4774
void ContextifyScript::RegisterExternalReferences(
677
    ExternalReferenceRegistry* registry) {
678
4774
  registry->Register(New);
679
4774
  registry->Register(CreateCachedData);
680
4774
  registry->Register(RunInContext);
681
4774
  registry->Register(RunInThisContext);
682
4774
}
683
684
2205
void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
685
2205
  Environment* env = Environment::GetCurrent(args);
686
2205
  Isolate* isolate = env->isolate();
687
2205
  Local<Context> context = env->context();
688
689
2204
  CHECK(args.IsConstructCall());
690
691
2204
  const int argc = args.Length();
692
2204
  CHECK_GE(argc, 2);
693
694
6612
  CHECK(args[0]->IsString());
695
4408
  Local<String> code = args[0].As<String>();
696
697
6612
  CHECK(args[1]->IsString());
698
4408
  Local<String> filename = args[1].As<String>();
699
700
2204
  int line_offset = 0;
701
2204
  int column_offset = 0;
702
  Local<ArrayBufferView> cached_data_buf;
703
2204
  bool produce_cached_data = false;
704
2204
  Local<Context> parsing_context = context;
705
706
2204
  if (argc > 2) {
707
    // new ContextifyScript(code, filename, lineOffset, columnOffset,
708
    //                      cachedData, produceCachedData, parsingContext)
709
2204
    CHECK_EQ(argc, 7);
710
4408
    CHECK(args[2]->IsNumber());
711
6615
    line_offset = args[2].As<Int32>()->Value();
712
4410
    CHECK(args[3]->IsNumber());
713
6612
    column_offset = args[3].As<Int32>()->Value();
714
6609
    if (!args[4]->IsUndefined()) {
715
46
      CHECK(args[4]->IsArrayBufferView());
716
46
      cached_data_buf = args[4].As<ArrayBufferView>();
717
    }
718
4406
    CHECK(args[5]->IsBoolean());
719
4406
    produce_cached_data = args[5]->IsTrue();
720
6612
    if (!args[6]->IsUndefined()) {
721
896
      CHECK(args[6]->IsObject());
722
      ContextifyContext* sandbox =
723
448
          ContextifyContext::ContextFromContextifiedSandbox(
724
1344
              env, args[6].As<Object>());
725
448
      CHECK_NOT_NULL(sandbox);
726
448
      parsing_context = sandbox->context();
727
    }
728
  }
729
730
  ContextifyScript* contextify_script =
731
2204
      new ContextifyScript(env, args.This());
732
733
2205
  if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
734
          TRACING_CATEGORY_NODE2(vm, script)) != 0) {
735
14
    Utf8Value fn(isolate, filename);
736
7
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
737
        TRACING_CATEGORY_NODE2(vm, script),
738
        "ContextifyScript::New",
739
        contextify_script,
740
14
        "filename", TRACE_STR_COPY(*fn));
741
7
  }
742
7
743
2219
  ScriptCompiler::CachedData* cached_data = nullptr;
744
2205
  if (!cached_data_buf.IsEmpty()) {
745
14
    uint8_t* data = static_cast<uint8_t*>(
746
46
        cached_data_buf->Buffer()->GetBackingStore()->Data());
747
23
    cached_data = new ScriptCompiler::CachedData(
748
46
        data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
749
  }
750
751
  Local<PrimitiveArray> host_defined_options =
752
2205
      PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
753
6615
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kType,
754
2205
                            Number::New(isolate, loader::ScriptType::kScript));
755
6615
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kID,
756
4410
                            Number::New(isolate, contextify_script->id()));
757
758
  ScriptOrigin origin(isolate,
759
                      filename,
760
                      line_offset,                          // line offset
761
                      column_offset,                        // column offset
762
                      true,                                 // is cross origin
763
                      -1,                                   // script id
764
                      Local<Value>(),                       // source map URL
765
                      false,                                // is opaque (?)
766
                      false,                                // is WASM
767
                      false,                                // is ES Module
768
2205
                      host_defined_options);
769
2023
  ScriptCompiler::Source source(code, origin, cached_data);
770
  ScriptCompiler::CompileOptions compile_options =
771
2205
      ScriptCompiler::kNoCompileOptions;
772
773
2205
  if (source.GetCachedData() != nullptr)
774
23
    compile_options = ScriptCompiler::kConsumeCodeCache;
775
776
4227
  TryCatchScope try_catch(env);
777
4228
  ShouldNotAbortOnUncaughtScope no_abort_scope(env);
778
2023
  Context::Scope scope(parsing_context);
779
780
  MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
781
      isolate,
782
      &source,
783
2205
      compile_options);
784
785
2204
  if (v8_script.IsEmpty()) {
786
182
    errors::DecorateErrorStack(env, try_catch);
787
182
    no_abort_scope.Close();
788
182
    if (!try_catch.HasTerminated())
789
182
      try_catch.ReThrow();
790
    TRACE_EVENT_NESTABLE_ASYNC_END0(
791
181
        TRACING_CATEGORY_NODE2(vm, script),
792
        "ContextifyScript::New",
793
28
        contextify_script);
794
543
    return;
795
181
  }
796
4045
  contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
797
798
2023
  Local<Context> env_context = env->context();
799
2022
  if (compile_options == ScriptCompiler::kConsumeCodeCache) {
800
69
    args.This()->Set(
801
        env_context,
802
        env->cached_data_rejected_string(),
803
92
        Boolean::New(isolate, source.GetCachedData()->rejected)).Check();
804
1999
  } else if (produce_cached_data) {
805
    std::unique_ptr<ScriptCompiler::CachedData> cached_data {
806
12
      ScriptCompiler::CreateCodeCache(v8_script.ToLocalChecked()) };
807
6
    bool cached_data_produced = cached_data != nullptr;
808
6
    if (cached_data_produced) {
809
      MaybeLocal<Object> buf = Buffer::Copy(
810
          env,
811
6
          reinterpret_cast<const char*>(cached_data->data),
812
12
          cached_data->length);
813
18
      args.This()->Set(env_context,
814
                       env->cached_data_string(),
815
18
                       buf.ToLocalChecked()).Check();
816
    }
817
18
    args.This()->Set(
818
        env_context,
819
        env->cached_data_produced_string(),
820
24
        Boolean::New(isolate, cached_data_produced)).Check();
821
  }
822
  TRACE_EVENT_NESTABLE_ASYNC_END0(
823
2023
      TRACING_CATEGORY_NODE2(vm, script),
824
      "ContextifyScript::New",
825
604
      contextify_script);
826
2023
}
827
828
2007
bool ContextifyScript::InstanceOf(Environment* env,
829
14
                                  const Local<Value>& value) {
830

4015
  return !value.IsEmpty() &&
831
6001
         env->script_context_constructor_template()->HasInstance(value);
832
}
833
834
11
void ContextifyScript::CreateCachedData(
835
    const FunctionCallbackInfo<Value>& args) {
836
11
  Environment* env = Environment::GetCurrent(args);
837
  ContextifyScript* wrapped_script;
838
11
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
839
  Local<UnboundScript> unbound_script =
840
11
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
841
  std::unique_ptr<ScriptCompiler::CachedData> cached_data(
842
22
      ScriptCompiler::CreateCodeCache(unbound_script));
843
11
  if (!cached_data) {
844
    args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked());
845
  } else {
846
    MaybeLocal<Object> buf = Buffer::Copy(
847
        env,
848
11
        reinterpret_cast<const char*>(cached_data->data),
849
22
        cached_data->length);
850
22
    args.GetReturnValue().Set(buf.ToLocalChecked());
851
  }
852
}
853
854
1220
void ContextifyScript::RunInThisContext(
855
    const FunctionCallbackInfo<Value>& args) {
856
1220
  Environment* env = Environment::GetCurrent(args);
857
858
  ContextifyScript* wrapped_script;
859
1220
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
860
861
1220
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
862
      TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script);
863
864
443
  // TODO(addaleax): Use an options object or otherwise merge this with
865
1220
  // RunInContext().
866
1220
  CHECK_EQ(args.Length(), 4);
867
6
868
2452
  CHECK(args[0]->IsNumber());
869
4888
  int64_t timeout = args[0]->IntegerValue(env->context()).FromJust();
870
871
2436
  CHECK(args[1]->IsBoolean());
872
2436
  bool display_errors = args[1]->IsTrue();
873
874
2440
  CHECK(args[2]->IsBoolean());
875
2438
  bool break_on_sigint = args[2]->IsTrue();
876
877
2438
  CHECK(args[3]->IsBoolean());
878
2440
  bool break_on_first_line = args[3]->IsTrue();
879
880
  // Do the eval within this context
881
2423
  EvalMachine(env,
882
              timeout,
883
              display_errors,
884
              break_on_sigint,
885
              break_on_first_line,
886
              nullptr,  // microtask_queue
887
1220
              args);
888
889
1203
  TRACE_EVENT_NESTABLE_ASYNC_END0(
890
      TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script);
891
}
892
430
893
1984
void ContextifyScript::RunInContext(const FunctionCallbackInfo<Value>& args) {
894
781
  Environment* env = Environment::GetCurrent(args);
895
5
896
10
  ContextifyScript* wrapped_script;
897
791
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
898
899
781
  CHECK_EQ(args.Length(), 5);
900
901
1562
  CHECK(args[0]->IsObject());
902
1562
  Local<Object> sandbox = args[0].As<Object>();
903
  // Get the context from the sandbox
904
  ContextifyContext* contextify_context =
905
781
      ContextifyContext::ContextFromContextifiedSandbox(env, sandbox);
906
781
  CHECK_NOT_NULL(contextify_context);
907
908
781
  Local<Context> context = contextify_context->context();
909
781
  if (context.IsEmpty())
910
    return;
911
912
781
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
913
      TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script);
914
915
1562
  CHECK(args[1]->IsNumber());
916
3905
  int64_t timeout = args[1]->IntegerValue(env->context()).FromJust();
917
918
1563
  CHECK(args[2]->IsBoolean());
919
1564
  bool display_errors = args[2]->IsTrue();
920
2
921
1562
  CHECK(args[3]->IsBoolean());
922
1562
  bool break_on_sigint = args[3]->IsTrue();
923
924
1562
  CHECK(args[4]->IsBoolean());
925
1562
  bool break_on_first_line = args[4]->IsTrue();
926
927
  // Do the eval within the context
928
  Context::Scope context_scope(context);
929
781
  EvalMachine(contextify_context->env(),
930
              timeout,
931
              display_errors,
932
              break_on_sigint,
933
              break_on_first_line,
934
1562
              contextify_context->microtask_queue(),
935
781
              args);
936
937
781
  TRACE_EVENT_NESTABLE_ASYNC_END0(
938
      TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script);
939
}
940
213
941
2780
bool ContextifyScript::EvalMachine(Environment* env,
942
                                   const int64_t timeout,
943
1
                                   const bool display_errors,
944
2
                                   const bool break_on_sigint,
945
2
                                   const bool break_on_first_line,
946
                                   std::shared_ptr<MicrotaskQueue> mtask_queue,
947
                                   const FunctionCallbackInfo<Value>& args) {
948
1999
  if (!env->can_call_into_js())
949
    return false;
950
2000
  if (!ContextifyScript::InstanceOf(env, args.Holder())) {
951
    THROW_ERR_INVALID_THIS(
952
        env,
953
        "Script methods can only be called on script instances.");
954
    return false;
955
  }
956
3986
  TryCatchScope try_catch(env);
957
3986
  Isolate::SafeForTerminationScope safe_for_termination(env->isolate());
958
  ContextifyScript* wrapped_script;
959
2001
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder(), false);
960
  Local<UnboundScript> unbound_script =
961
2001
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
962
2001
  Local<Script> script = unbound_script->BindToCurrentContext();
963
964
#if HAVE_INSPECTOR
965
2000
  if (break_on_first_line) {
966
10
    env->inspector_agent()->PauseOnNextJavascriptStatement("Break on start");
967
  }
968
#endif
969
970
  MaybeLocal<Value> result;
971
2000
  bool timed_out = false;
972
2000
  bool received_signal = false;
973
2001
  auto run = [&]() {
974
4004
    MaybeLocal<Value> result = script->Run(env->context());
975

1985
    if (!result.IsEmpty() && mtask_queue)
976
4
      mtask_queue->PerformCheckpoint(env->isolate());
977
1984
    return result;
978
2000
  };
979

2000
  if (break_on_sigint && timeout != -1) {
980
    Watchdog wd(env->isolate(), timeout, &timed_out);
981
    SigintWatchdog swd(env->isolate(), &received_signal);
982
    result = run();
983
2000
  } else if (break_on_sigint) {
984
367
    SigintWatchdog swd(env->isolate(), &received_signal);
985
185
    result = run();
986
1815
  } else if (timeout != -1) {
987
30
    Watchdog wd(env->isolate(), timeout, &timed_out);
988
15
    result = run();
989
  } else {
990
1800
    result = run();
991
  }
992
993
  // Convert the termination exception into a regular exception.
994

1984
  if (timed_out || received_signal) {
995

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

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

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

19294
NODE_MODULE_EXTERNAL_REFERENCE(contextify,
1385
                               node::contextify::RegisterExternalReferences)