GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_contextify.cc Lines: 587 638 92.0 %
Date: 2022-08-21 04:19:51 Branches: 284 444 64.0 %

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

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

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

636
      !env->microtask_queue_ctor_template().IsEmpty() &&
311

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

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

139
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
454


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

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

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

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

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

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

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

219
    TRACE_EVENT_END0(TRACING_CATEGORY_NODE2(vm, script),
793
                     "ContextifyScript::New");
794
192
    return;
795
  }
796
14404
  contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
797
798
7202
  Local<Context> env_context = env->context();
799
7202
  if (compile_options == ScriptCompiler::kConsumeCodeCache) {
800
25
    args.This()->Set(
801
        env_context,
802
        env->cached_data_rejected_string(),
803
100
        Boolean::New(isolate, source.GetCachedData()->rejected)).Check();
804
7177
  } else if (produce_cached_data) {
805
    std::unique_ptr<ScriptCompiler::CachedData> cached_data {
806
6
      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
12
          reinterpret_cast<const char*>(cached_data->data),
812
6
          cached_data->length);
813
6
      args.This()->Set(env_context,
814
                       env->cached_data_string(),
815
24
                       buf.ToLocalChecked()).Check();
816
    }
817
6
    args.This()->Set(
818
        env_context,
819
        env->cached_data_produced_string(),
820
24
        Boolean::New(isolate, cached_data_produced)).Check();
821
  }
822

7963
  TRACE_EVENT_END0(TRACING_CATEGORY_NODE2(vm, script), "ContextifyScript::New");
823
}
824
825
7180
bool ContextifyScript::InstanceOf(Environment* env,
826
                                  const Local<Value>& value) {
827

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

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

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

7164
    if (!result.IsEmpty() && mtask_queue)
939
2
      mtask_queue->PerformCheckpoint(env->isolate());
940
7164
    return result;
941
7180
  };
942

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

7164
  if (timed_out || received_signal) {
958

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

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

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