GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_contextify.cc Lines: 609 655 93.0 %
Date: 2022-09-07 04:19:57 Branches: 303 468 64.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_snapshot_builder.h"
32
#include "node_watchdog.h"
33
#include "util-inl.h"
34
35
namespace node {
36
namespace contextify {
37
38
using errors::TryCatchScope;
39
40
using v8::Array;
41
using v8::ArrayBufferView;
42
using v8::Boolean;
43
using v8::Context;
44
using v8::EscapableHandleScope;
45
using v8::External;
46
using v8::Function;
47
using v8::FunctionCallbackInfo;
48
using v8::FunctionTemplate;
49
using v8::HandleScope;
50
using v8::IndexedPropertyHandlerConfiguration;
51
using v8::Int32;
52
using v8::Isolate;
53
using v8::Local;
54
using v8::Maybe;
55
using v8::MaybeLocal;
56
using v8::MeasureMemoryExecution;
57
using v8::MeasureMemoryMode;
58
using v8::MicrotaskQueue;
59
using v8::MicrotasksPolicy;
60
using v8::Name;
61
using v8::NamedPropertyHandlerConfiguration;
62
using v8::Number;
63
using v8::Object;
64
using v8::ObjectTemplate;
65
using v8::PrimitiveArray;
66
using v8::Promise;
67
using v8::PropertyAttribute;
68
using v8::PropertyCallbackInfo;
69
using v8::PropertyDescriptor;
70
using v8::PropertyHandlerFlags;
71
using v8::Script;
72
using v8::ScriptCompiler;
73
using v8::ScriptOrigin;
74
using v8::String;
75
using v8::Uint32;
76
using v8::UnboundScript;
77
using v8::Value;
78
using v8::WeakCallbackInfo;
79
using v8::WeakCallbackType;
80
81
// The vm module executes code in a sandboxed environment with a different
82
// global object than the rest of the code. This is achieved by applying
83
// every call that changes or queries a property on the global `this` in the
84
// sandboxed code, to the sandbox object.
85
//
86
// The implementation uses V8's interceptors for methods like `set`, `get`,
87
// `delete`, `defineProperty`, and for any query of the property attributes.
88
// Property handlers with interceptors are set on the object template for
89
// the sandboxed code. Handlers for both named properties and for indexed
90
// properties are used. Their functionality is almost identical, the indexed
91
// interceptors mostly just call the named interceptors.
92
//
93
// For every `get` of a global property in the sandboxed context, the
94
// interceptor callback checks the sandbox object for the property.
95
// If the property is defined on the sandbox, that result is returned to
96
// the original call instead of finishing the query on the global object.
97
//
98
// For every `set` of a global property, the interceptor callback defines or
99
// changes the property both on the sandbox and the global proxy.
100
101
namespace {
102
103
// Convert an int to a V8 Name (String or Symbol).
104
3
Local<Name> Uint32ToName(Local<Context> context, uint32_t index) {
105
6
  return Uint32::New(context->GetIsolate(), index)->ToString(context)
106
3
      .ToLocalChecked();
107
}
108
109
}  // anonymous namespace
110
111
630
ContextifyContext::ContextifyContext(
112
    Environment* env,
113
    Local<Object> sandbox_obj,
114
630
    const ContextOptions& options)
115
  : env_(env),
116
1260
    microtask_queue_wrap_(options.microtask_queue_wrap) {
117
630
  Local<ObjectTemplate> object_template = env->contextify_global_template();
118
630
  if (object_template.IsEmpty()) {
119
    object_template = CreateGlobalTemplate(env->isolate());
120
    env->set_contextify_global_template(object_template);
121
  }
122
630
  bool use_node_snapshot = per_process::cli_options->node_snapshot;
123
  const SnapshotData* snapshot_data =
124
630
      use_node_snapshot ? SnapshotBuilder::GetEmbeddedSnapshotData() : nullptr;
125
126
  MicrotaskQueue* queue =
127
1260
      microtask_queue()
128
1260
          ? microtask_queue().get()
129
1885
          : env->isolate()->GetCurrentContext()->GetMicrotaskQueue();
130
131
  Local<Context> v8_context;
132
630
  if (!(CreateV8Context(env->isolate(), object_template, snapshot_data, queue)
133

1260
            .ToLocal(&v8_context)) ||
134
630
      !InitializeContext(v8_context, env, sandbox_obj, options)) {
135
    // Allocation failure, maximum call stack size reached, termination, etc.
136
    return;
137
  }
138
139
630
  context_.Reset(env->isolate(), v8_context);
140
630
  context_.SetWeak(this, WeakCallback, WeakCallbackType::kParameter);
141
630
  env->AddCleanupHook(CleanupHook, this);
142
}
143
144
145
517
ContextifyContext::~ContextifyContext() {
146
517
  env()->RemoveCleanupHook(CleanupHook, this);
147
517
  Isolate* isolate = env()->isolate();
148
1034
  HandleScope scope(isolate);
149
150
  env()->async_hooks()
151
517
    ->RemoveContext(PersistentToLocal::Weak(isolate, context_));
152
517
}
153
154
155
455
void ContextifyContext::CleanupHook(void* arg) {
156
455
  ContextifyContext* self = static_cast<ContextifyContext*>(arg);
157
455
  self->context_.Reset();
158
455
  delete self;
159
455
}
160
161
791
Local<ObjectTemplate> ContextifyContext::CreateGlobalTemplate(
162
    Isolate* isolate) {
163
791
  Local<FunctionTemplate> function_template = FunctionTemplate::New(isolate);
164
165
  Local<ObjectTemplate> object_template =
166
791
      function_template->InstanceTemplate();
167
168
  NamedPropertyHandlerConfiguration config(
169
      PropertyGetterCallback,
170
      PropertySetterCallback,
171
      PropertyDescriptorCallback,
172
      PropertyDeleterCallback,
173
      PropertyEnumeratorCallback,
174
      PropertyDefinerCallback,
175
      {},
176
791
      PropertyHandlerFlags::kHasNoSideEffect);
177
178
  IndexedPropertyHandlerConfiguration indexed_config(
179
      IndexedPropertyGetterCallback,
180
      IndexedPropertySetterCallback,
181
      IndexedPropertyDescriptorCallback,
182
      IndexedPropertyDeleterCallback,
183
      PropertyEnumeratorCallback,
184
      IndexedPropertyDefinerCallback,
185
      {},
186
791
      PropertyHandlerFlags::kHasNoSideEffect);
187
188
791
  object_template->SetHandler(config);
189
791
  object_template->SetHandler(indexed_config);
190
191
791
  return object_template;
192
}
193
194
637
MaybeLocal<Context> ContextifyContext::CreateV8Context(
195
    Isolate* isolate,
196
    Local<ObjectTemplate> object_template,
197
    const SnapshotData* snapshot_data,
198
    MicrotaskQueue* queue) {
199
637
  EscapableHandleScope scope(isolate);
200
201
  Local<Context> ctx;
202
637
  if (snapshot_data == nullptr) {
203
    ctx = Context::New(isolate,
204
                       nullptr,  // extensions
205
                       object_template,
206
                       {},  // global object
207
                       {},  // deserialization callback
208
18
                       queue);
209

18
    if (ctx.IsEmpty() || InitializeBaseContextForSnapshot(ctx).IsNothing()) {
210
      return MaybeLocal<Context>();
211
    }
212
1256
  } else if (!Context::FromSnapshot(isolate,
213
                                    SnapshotData::kNodeVMContextIndex,
214
                                    {},       // deserialization callback
215
                                    nullptr,  // extensions
216
                                    {},       // global object
217
628
                                    queue)
218
628
                  .ToLocal(&ctx)) {
219
    return MaybeLocal<Context>();
220
  }
221
637
  return scope.Escape(ctx);
222
}
223
224
630
bool ContextifyContext::InitializeContext(Local<Context> ctx,
225
                                          Environment* env,
226
                                          Local<Object> sandbox_obj,
227
                                          const ContextOptions& options) {
228
1260
  HandleScope scope(env->isolate());
229
230
  // This only initializes part of the context. The primordials are
231
  // only initilaized when needed because even deserializing them slows
232
  // things down significantly and they are only needed in rare occasions
233
  // in the vm contexts.
234
1260
  if (InitializeContextRuntime(ctx).IsNothing()) {
235
    return false;
236
  }
237
238
630
  Local<Context> main_context = env->context();
239
630
  ctx->SetSecurityToken(main_context->GetSecurityToken());
240
241
  // We need to tie the lifetime of the sandbox object with the lifetime of
242
  // newly created context. We do this by making them hold references to each
243
  // other. The context can directly hold a reference to the sandbox as an
244
  // embedder data field. However, we cannot hold a reference to a v8::Context
245
  // directly in an Object, we instead hold onto the new context's global
246
  // object instead (which then has a reference to the context).
247
630
  ctx->SetEmbedderData(ContextEmbedderIndex::kSandboxObject, sandbox_obj);
248
  sandbox_obj->SetPrivate(
249
1260
      main_context, env->contextify_global_private_symbol(), ctx->Global());
250
251
  // Delegate the code generation validation to
252
  // node::ModifyCodeGenerationFromStrings.
253
630
  ctx->AllowCodeGenerationFromStrings(false);
254
630
  ctx->SetEmbedderData(ContextEmbedderIndex::kAllowCodeGenerationFromStrings,
255
                       options.allow_code_gen_strings);
256
630
  ctx->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
257
                       options.allow_code_gen_wasm);
258
259
1260
  Utf8Value name_val(env->isolate(), options.name);
260
1890
  ContextInfo info(*name_val);
261
630
  if (!options.origin.IsEmpty()) {
262
4
    Utf8Value origin_val(env->isolate(), options.origin);
263
2
    info.origin = *origin_val;
264
  }
265
266
  {
267
630
    Context::Scope context_scope(ctx);
268
630
    Local<String> ctor_name = sandbox_obj->GetConstructorName();
269

1894
    if (!ctor_name->Equals(ctx, env->object_string()).FromMaybe(false) &&
270
4
        ctx->Global()
271
630
            ->DefineOwnProperty(
272
                ctx,
273
                v8::Symbol::GetToStringTag(env->isolate()),
274
                ctor_name,
275
638
                static_cast<v8::PropertyAttribute>(v8::DontEnum))
276
4
            .IsNothing()) {
277
      return false;
278
    }
279
  }
280
281
630
  env->AssignToContext(ctx, nullptr, info);
282
283
  // This should only be done after the initial initializations of the context
284
  // global object is finished.
285
630
  ctx->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kContextifyContext,
286
                                       this);
287
630
  return true;
288
}
289
290
780
void ContextifyContext::Init(Environment* env, Local<Object> target) {
291
780
  Local<Context> context = env->context();
292
780
  SetMethod(context, target, "makeContext", MakeContext);
293
780
  SetMethod(context, target, "isContext", IsContext);
294
780
  SetMethod(context, target, "compileFunction", CompileFunction);
295
780
}
296
297
5473
void ContextifyContext::RegisterExternalReferences(
298
    ExternalReferenceRegistry* registry) {
299
5473
  registry->Register(MakeContext);
300
5473
  registry->Register(IsContext);
301
5473
  registry->Register(CompileFunction);
302
5473
  registry->Register(PropertyGetterCallback);
303
5473
  registry->Register(PropertySetterCallback);
304
5473
  registry->Register(PropertyDescriptorCallback);
305
5473
  registry->Register(PropertyDeleterCallback);
306
5473
  registry->Register(PropertyEnumeratorCallback);
307
5473
  registry->Register(PropertyDefinerCallback);
308
5473
  registry->Register(IndexedPropertyGetterCallback);
309
5473
  registry->Register(IndexedPropertySetterCallback);
310
5473
  registry->Register(IndexedPropertyDescriptorCallback);
311
5473
  registry->Register(IndexedPropertyDeleterCallback);
312
5473
  registry->Register(IndexedPropertyDefinerCallback);
313
5473
}
314
315
// makeContext(sandbox, name, origin, strings, wasm);
316
630
void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
317
630
  Environment* env = Environment::GetCurrent(args);
318
319
630
  CHECK_EQ(args.Length(), 6);
320
630
  CHECK(args[0]->IsObject());
321
1260
  Local<Object> sandbox = args[0].As<Object>();
322
323
  // Don't allow contextifying a sandbox multiple times.
324
1260
  CHECK(
325
      !sandbox->HasPrivate(
326
          env->context(),
327
          env->contextify_context_private_symbol()).FromJust());
328
329
630
  ContextOptions options;
330
331
1260
  CHECK(args[1]->IsString());
332
1260
  options.name = args[1].As<String>();
333
334

2516
  CHECK(args[2]->IsString() || args[2]->IsUndefined());
335
1260
  if (args[2]->IsString()) {
336
4
    options.origin = args[2].As<String>();
337
  }
338
339
630
  CHECK(args[3]->IsBoolean());
340
1260
  options.allow_code_gen_strings = args[3].As<Boolean>();
341
342
630
  CHECK(args[4]->IsBoolean());
343
1260
  options.allow_code_gen_wasm = args[4].As<Boolean>();
344
345
630
  if (args[5]->IsObject() &&
346

640
      !env->microtask_queue_ctor_template().IsEmpty() &&
347

645
      env->microtask_queue_ctor_template()->HasInstance(args[5])) {
348
5
    options.microtask_queue_wrap.reset(
349
10
        Unwrap<MicrotaskQueueWrap>(args[5].As<Object>()));
350
  }
351
352
630
  TryCatchScope try_catch(env);
353
  std::unique_ptr<ContextifyContext> context_ptr =
354
630
      std::make_unique<ContextifyContext>(env, sandbox, options);
355
356
630
  if (try_catch.HasCaught()) {
357
    if (!try_catch.HasTerminated())
358
      try_catch.ReThrow();
359
    return;
360
  }
361
362
630
  Local<Context> new_context = context_ptr->context();
363
630
  if (new_context.IsEmpty()) return;
364
365
  sandbox->SetPrivate(
366
      env->context(),
367
      env->contextify_context_private_symbol(),
368
1260
      External::New(env->isolate(), context_ptr.release()));
369
}
370
371
372
6107
void ContextifyContext::IsContext(const FunctionCallbackInfo<Value>& args) {
373
6107
  Environment* env = Environment::GetCurrent(args);
374
375
6107
  CHECK(args[0]->IsObject());
376
12214
  Local<Object> sandbox = args[0].As<Object>();
377
378
  Maybe<bool> result =
379
      sandbox->HasPrivate(env->context(),
380
6107
                          env->contextify_context_private_symbol());
381
12214
  args.GetReturnValue().Set(result.FromJust());
382
6107
}
383
384
385
62
void ContextifyContext::WeakCallback(
386
    const WeakCallbackInfo<ContextifyContext>& data) {
387
62
  ContextifyContext* context = data.GetParameter();
388
62
  delete context;
389
62
}
390
391
// static
392
5419
ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox(
393
    Environment* env,
394
    const Local<Object>& sandbox) {
395
  MaybeLocal<Value> maybe_value =
396
      sandbox->GetPrivate(env->context(),
397
5419
                          env->contextify_context_private_symbol());
398
  Local<Value> context_external_v;
399

10838
  if (maybe_value.ToLocal(&context_external_v) &&
400
5419
      context_external_v->IsExternal()) {
401
5419
    Local<External> context_external = context_external_v.As<External>();
402
5419
    return static_cast<ContextifyContext*>(context_external->Value());
403
  }
404
  return nullptr;
405
}
406
407
// static
408
template <typename T>
409
2094690
ContextifyContext* ContextifyContext::Get(const PropertyCallbackInfo<T>& args) {
410
  Local<Context> context;
411
4189380
  if (!args.This()->GetCreationContext().ToLocal(&context)) {
412
    return nullptr;
413
  }
414
2094690
  if (!ContextEmbedderTag::IsNodeContext(context)) {
415
88
    return nullptr;
416
  }
417
  return static_cast<ContextifyContext*>(
418
2094602
      context->GetAlignedPointerFromEmbedderData(
419
2094602
          ContextEmbedderIndex::kContextifyContext));
420
}
421
422
1047345
bool ContextifyContext::IsStillInitializing(const ContextifyContext* ctx) {
423

1047345
  return ctx == nullptr || ctx->context_.IsEmpty();
424
}
425
426
// static
427
1046831
void ContextifyContext::PropertyGetterCallback(
428
    Local<Name> property,
429
    const PropertyCallbackInfo<Value>& args) {
430
1046831
  ContextifyContext* ctx = ContextifyContext::Get(args);
431
432
  // Still initializing
433
1046831
  if (IsStillInitializing(ctx)) return;
434
435
1046188
  Local<Context> context = ctx->context();
436
1046188
  Local<Object> sandbox = ctx->sandbox();
437
  MaybeLocal<Value> maybe_rv =
438
1046188
      sandbox->GetRealNamedProperty(context, property);
439
1046188
  if (maybe_rv.IsEmpty()) {
440
    maybe_rv =
441
84256
        ctx->global_proxy()->GetRealNamedProperty(context, property);
442
  }
443
444
  Local<Value> rv;
445
1046188
  if (maybe_rv.ToLocal(&rv)) {
446
1046119
    if (rv == sandbox)
447
10
      rv = ctx->global_proxy();
448
449
2092238
    args.GetReturnValue().Set(rv);
450
  }
451
}
452
453
// static
454
175
void ContextifyContext::PropertySetterCallback(
455
    Local<Name> property,
456
    Local<Value> value,
457
    const PropertyCallbackInfo<Value>& args) {
458
175
  ContextifyContext* ctx = ContextifyContext::Get(args);
459
460
  // Still initializing
461
189
  if (IsStillInitializing(ctx)) return;
462
463
152
  Local<Context> context = ctx->context();
464
152
  PropertyAttribute attributes = PropertyAttribute::None;
465
152
  bool is_declared_on_global_proxy = ctx->global_proxy()
466
152
      ->GetRealNamedPropertyAttributes(context, property)
467
152
      .To(&attributes);
468
152
  bool read_only =
469
152
      static_cast<int>(attributes) &
470
      static_cast<int>(PropertyAttribute::ReadOnly);
471
472
152
  bool is_declared_on_sandbox = ctx->sandbox()
473
152
      ->GetRealNamedPropertyAttributes(context, property)
474
152
      .To(&attributes);
475
300
  read_only = read_only ||
476
148
      (static_cast<int>(attributes) &
477
      static_cast<int>(PropertyAttribute::ReadOnly));
478
479
152
  if (read_only)
480
13
    return;
481
482
  // true for x = 5
483
  // false for this.x = 5
484
  // false for Object.defineProperty(this, 'foo', ...)
485
  // false for vmResult.x = 5 where vmResult = vm.runInContext();
486
278
  bool is_contextual_store = ctx->global_proxy() != args.This();
487
488
  // Indicator to not return before setting (undeclared) function declarations
489
  // on the sandbox in strict mode, i.e. args.ShouldThrowOnError() = true.
490
  // True for 'function f() {}', 'this.f = function() {}',
491
  // 'var f = function()'.
492
  // In effect only for 'function f() {}' because
493
  // var f = function(), is_declared = true
494
  // this.f = function() {}, is_contextual_store = false.
495
139
  bool is_function = value->IsFunction();
496
497

139
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
498


230
  if (!is_declared && args.ShouldThrowOnError() && is_contextual_store &&
499
30
      !is_function)
500
1
    return;
501
502
276
  USE(ctx->sandbox()->Set(context, property, value));
503
276
  args.GetReturnValue().Set(value);
504
}
505
506
// static
507
59
void ContextifyContext::PropertyDescriptorCallback(
508
    Local<Name> property,
509
    const PropertyCallbackInfo<Value>& args) {
510
59
  ContextifyContext* ctx = ContextifyContext::Get(args);
511
512
  // Still initializing
513
59
  if (IsStillInitializing(ctx)) return;
514
515
55
  Local<Context> context = ctx->context();
516
517
55
  Local<Object> sandbox = ctx->sandbox();
518
519

110
  if (sandbox->HasOwnProperty(context, property).FromMaybe(false)) {
520
    Local<Value> desc;
521
78
    if (sandbox->GetOwnPropertyDescriptor(context, property).ToLocal(&desc)) {
522
78
      args.GetReturnValue().Set(desc);
523
    }
524
  }
525
}
526
527
// static
528
19
void ContextifyContext::PropertyDefinerCallback(
529
    Local<Name> property,
530
    const PropertyDescriptor& desc,
531
    const PropertyCallbackInfo<Value>& args) {
532
19
  ContextifyContext* ctx = ContextifyContext::Get(args);
533
534
  // Still initializing
535
19
  if (IsStillInitializing(ctx)) return;
536
537
15
  Local<Context> context = ctx->context();
538
15
  Isolate* isolate = context->GetIsolate();
539
540
15
  PropertyAttribute attributes = PropertyAttribute::None;
541
  bool is_declared =
542
15
      ctx->global_proxy()->GetRealNamedPropertyAttributes(context,
543
15
                                                          property)
544
15
          .To(&attributes);
545
15
  bool read_only =
546
15
      static_cast<int>(attributes) &
547
          static_cast<int>(PropertyAttribute::ReadOnly);
548
549
  // If the property is set on the global as read_only, don't change it on
550
  // the global or sandbox.
551

15
  if (is_declared && read_only)
552
    return;
553
554
15
  Local<Object> sandbox = ctx->sandbox();
555
556
  auto define_prop_on_sandbox =
557
15
      [&] (PropertyDescriptor* desc_for_sandbox) {
558
15
        if (desc.has_enumerable()) {
559
2
          desc_for_sandbox->set_enumerable(desc.enumerable());
560
        }
561
15
        if (desc.has_configurable()) {
562
1
          desc_for_sandbox->set_configurable(desc.configurable());
563
        }
564
        // Set the property on the sandbox.
565
15
        USE(sandbox->DefineProperty(context, property, *desc_for_sandbox));
566
30
      };
567
568

15
  if (desc.has_get() || desc.has_set()) {
569
    PropertyDescriptor desc_for_sandbox(
570
15
        desc.has_get() ? desc.get() : Undefined(isolate).As<Value>(),
571

23
        desc.has_set() ? desc.set() : Undefined(isolate).As<Value>());
572
573
5
    define_prop_on_sandbox(&desc_for_sandbox);
574
  } else {
575
    Local<Value> value =
576
12
        desc.has_value() ? desc.value() : Undefined(isolate).As<Value>();
577
578
10
    if (desc.has_writable()) {
579
      PropertyDescriptor desc_for_sandbox(value, desc.writable());
580
      define_prop_on_sandbox(&desc_for_sandbox);
581
    } else {
582
20
      PropertyDescriptor desc_for_sandbox(value);
583
10
      define_prop_on_sandbox(&desc_for_sandbox);
584
    }
585
  }
586
}
587
588
// static
589
2
void ContextifyContext::PropertyDeleterCallback(
590
    Local<Name> property,
591
    const PropertyCallbackInfo<Boolean>& args) {
592
2
  ContextifyContext* ctx = ContextifyContext::Get(args);
593
594
  // Still initializing
595
3
  if (IsStillInitializing(ctx)) return;
596
597
4
  Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), property);
598
599

4
  if (success.FromMaybe(false))
600
1
    return;
601
602
  // Delete failed on the sandbox, intercept and do not delete on
603
  // the global object.
604
2
  args.GetReturnValue().Set(false);
605
}
606
607
// static
608
256
void ContextifyContext::PropertyEnumeratorCallback(
609
    const PropertyCallbackInfo<Array>& args) {
610
256
  ContextifyContext* ctx = ContextifyContext::Get(args);
611
612
  // Still initializing
613
256
  if (IsStillInitializing(ctx)) return;
614
615
  Local<Array> properties;
616
617
768
  if (!ctx->sandbox()->GetPropertyNames(ctx->context()).ToLocal(&properties))
618
    return;
619
620
512
  args.GetReturnValue().Set(properties);
621
}
622
623
// static
624
void ContextifyContext::IndexedPropertyGetterCallback(
625
    uint32_t index,
626
    const PropertyCallbackInfo<Value>& args) {
627
  ContextifyContext* ctx = ContextifyContext::Get(args);
628
629
  // Still initializing
630
  if (IsStillInitializing(ctx)) return;
631
632
  ContextifyContext::PropertyGetterCallback(
633
      Uint32ToName(ctx->context(), index), args);
634
}
635
636
637
1
void ContextifyContext::IndexedPropertySetterCallback(
638
    uint32_t index,
639
    Local<Value> value,
640
    const PropertyCallbackInfo<Value>& args) {
641
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
642
643
  // Still initializing
644
1
  if (IsStillInitializing(ctx)) return;
645
646
1
  ContextifyContext::PropertySetterCallback(
647
      Uint32ToName(ctx->context(), index), value, args);
648
}
649
650
// static
651
1
void ContextifyContext::IndexedPropertyDescriptorCallback(
652
    uint32_t index,
653
    const PropertyCallbackInfo<Value>& args) {
654
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
655
656
  // Still initializing
657
1
  if (IsStillInitializing(ctx)) return;
658
659
1
  ContextifyContext::PropertyDescriptorCallback(
660
      Uint32ToName(ctx->context(), index), args);
661
}
662
663
664
1
void ContextifyContext::IndexedPropertyDefinerCallback(
665
    uint32_t index,
666
    const PropertyDescriptor& desc,
667
    const PropertyCallbackInfo<Value>& args) {
668
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
669
670
  // Still initializing
671
1
  if (IsStillInitializing(ctx)) return;
672
673
1
  ContextifyContext::PropertyDefinerCallback(
674
      Uint32ToName(ctx->context(), index), desc, args);
675
}
676
677
// static
678
void ContextifyContext::IndexedPropertyDeleterCallback(
679
    uint32_t index,
680
    const PropertyCallbackInfo<Boolean>& args) {
681
  ContextifyContext* ctx = ContextifyContext::Get(args);
682
683
  // Still initializing
684
  if (IsStillInitializing(ctx)) return;
685
686
  Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), index);
687
688
  if (success.FromMaybe(false))
689
    return;
690
691
  // Delete failed on the sandbox, intercept and do not delete on
692
  // the global object.
693
  args.GetReturnValue().Set(false);
694
}
695
696
780
void ContextifyScript::Init(Environment* env, Local<Object> target) {
697
780
  Isolate* isolate = env->isolate();
698
1560
  HandleScope scope(env->isolate());
699
  Local<String> class_name =
700
780
      FIXED_ONE_BYTE_STRING(env->isolate(), "ContextifyScript");
701
702
780
  Local<FunctionTemplate> script_tmpl = NewFunctionTemplate(isolate, New);
703
1560
  script_tmpl->InstanceTemplate()->SetInternalFieldCount(
704
      ContextifyScript::kInternalFieldCount);
705
780
  script_tmpl->SetClassName(class_name);
706
780
  SetProtoMethod(isolate, script_tmpl, "createCachedData", CreateCachedData);
707
780
  SetProtoMethod(isolate, script_tmpl, "runInContext", RunInContext);
708
709
780
  Local<Context> context = env->context();
710
711
780
  target->Set(context, class_name,
712
1560
      script_tmpl->GetFunction(context).ToLocalChecked()).Check();
713
780
  env->set_script_context_constructor_template(script_tmpl);
714
780
}
715
716
5473
void ContextifyScript::RegisterExternalReferences(
717
    ExternalReferenceRegistry* registry) {
718
5473
  registry->Register(New);
719
5473
  registry->Register(CreateCachedData);
720
5473
  registry->Register(RunInContext);
721
5473
}
722
723
5673
void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
724
5673
  Environment* env = Environment::GetCurrent(args);
725
5673
  Isolate* isolate = env->isolate();
726
5673
  Local<Context> context = env->context();
727
728
5673
  CHECK(args.IsConstructCall());
729
730
5673
  const int argc = args.Length();
731
5673
  CHECK_GE(argc, 2);
732
733
11346
  CHECK(args[0]->IsString());
734
11346
  Local<String> code = args[0].As<String>();
735
736
11346
  CHECK(args[1]->IsString());
737
5673
  Local<String> filename = args[1].As<String>();
738
739
5673
  int line_offset = 0;
740
5673
  int column_offset = 0;
741
  Local<ArrayBufferView> cached_data_buf;
742
5673
  bool produce_cached_data = false;
743
5673
  Local<Context> parsing_context = context;
744
745
5673
  if (argc > 2) {
746
    // new ContextifyScript(code, filename, lineOffset, columnOffset,
747
    //                      cachedData, produceCachedData, parsingContext)
748
5673
    CHECK_EQ(argc, 7);
749
5673
    CHECK(args[2]->IsNumber());
750
11346
    line_offset = args[2].As<Int32>()->Value();
751
5673
    CHECK(args[3]->IsNumber());
752
11346
    column_offset = args[3].As<Int32>()->Value();
753
11346
    if (!args[4]->IsUndefined()) {
754
25
      CHECK(args[4]->IsArrayBufferView());
755
50
      cached_data_buf = args[4].As<ArrayBufferView>();
756
    }
757
5673
    CHECK(args[5]->IsBoolean());
758
5673
    produce_cached_data = args[5]->IsTrue();
759
11346
    if (!args[6]->IsUndefined()) {
760
2519
      CHECK(args[6]->IsObject());
761
      ContextifyContext* sandbox =
762
2519
          ContextifyContext::ContextFromContextifiedSandbox(
763
5038
              env, args[6].As<Object>());
764
2519
      CHECK_NOT_NULL(sandbox);
765
2519
      parsing_context = sandbox->context();
766
    }
767
  }
768
769
  ContextifyScript* contextify_script =
770
5673
      new ContextifyScript(env, args.This());
771
772
5673
  if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
773
5673
          TRACING_CATEGORY_NODE2(vm, script)) != 0) {
774
14
    Utf8Value fn(isolate, filename);
775

14
    TRACE_EVENT_BEGIN1(TRACING_CATEGORY_NODE2(vm, script),
776
                       "ContextifyScript::New",
777
                       "filename",
778
                       TRACE_STR_COPY(*fn));
779
  }
780
781
5673
  ScriptCompiler::CachedData* cached_data = nullptr;
782
5673
  if (!cached_data_buf.IsEmpty()) {
783
50
    uint8_t* data = static_cast<uint8_t*>(cached_data_buf->Buffer()->Data());
784
25
    cached_data = new ScriptCompiler::CachedData(
785
25
        data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
786
  }
787
788
  Local<PrimitiveArray> host_defined_options =
789
5673
      PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
790
11346
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kType,
791
                            Number::New(isolate, loader::ScriptType::kScript));
792
11346
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kID,
793
5673
                            Number::New(isolate, contextify_script->id()));
794
795
  ScriptOrigin origin(isolate,
796
                      filename,
797
                      line_offset,                          // line offset
798
                      column_offset,                        // column offset
799
                      true,                                 // is cross origin
800
                      -1,                                   // script id
801
                      Local<Value>(),                       // source map URL
802
                      false,                                // is opaque (?)
803
                      false,                                // is WASM
804
                      false,                                // is ES Module
805
11346
                      host_defined_options);
806
5673
  ScriptCompiler::Source source(code, origin, cached_data);
807
5673
  ScriptCompiler::CompileOptions compile_options =
808
      ScriptCompiler::kNoCompileOptions;
809
810
5673
  if (source.GetCachedData() != nullptr)
811
25
    compile_options = ScriptCompiler::kConsumeCodeCache;
812
813
5673
  TryCatchScope try_catch(env);
814
5673
  ShouldNotAbortOnUncaughtScope no_abort_scope(env);
815
5673
  Context::Scope scope(parsing_context);
816
817
  MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
818
      isolate,
819
      &source,
820
5673
      compile_options);
821
822
5673
  if (v8_script.IsEmpty()) {
823
192
    errors::DecorateErrorStack(env, try_catch);
824
192
    no_abort_scope.Close();
825
192
    if (!try_catch.HasTerminated())
826
192
      try_catch.ReThrow();
827

219
    TRACE_EVENT_END0(TRACING_CATEGORY_NODE2(vm, script),
828
                     "ContextifyScript::New");
829
192
    return;
830
  }
831
10962
  contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
832
833
5481
  Local<Context> env_context = env->context();
834
5481
  if (compile_options == ScriptCompiler::kConsumeCodeCache) {
835
25
    args.This()->Set(
836
        env_context,
837
        env->cached_data_rejected_string(),
838
100
        Boolean::New(isolate, source.GetCachedData()->rejected)).Check();
839
5456
  } else if (produce_cached_data) {
840
    std::unique_ptr<ScriptCompiler::CachedData> cached_data {
841
6
      ScriptCompiler::CreateCodeCache(v8_script.ToLocalChecked()) };
842
6
    bool cached_data_produced = cached_data != nullptr;
843
6
    if (cached_data_produced) {
844
      MaybeLocal<Object> buf = Buffer::Copy(
845
          env,
846
12
          reinterpret_cast<const char*>(cached_data->data),
847
6
          cached_data->length);
848
6
      args.This()->Set(env_context,
849
                       env->cached_data_string(),
850
24
                       buf.ToLocalChecked()).Check();
851
    }
852
6
    args.This()->Set(
853
        env_context,
854
        env->cached_data_produced_string(),
855
24
        Boolean::New(isolate, cached_data_produced)).Check();
856
  }
857

6274
  TRACE_EVENT_END0(TRACING_CATEGORY_NODE2(vm, script), "ContextifyScript::New");
858
}
859
860
5460
bool ContextifyScript::InstanceOf(Environment* env,
861
                                  const Local<Value>& value) {
862

10920
  return !value.IsEmpty() &&
863
16380
         env->script_context_constructor_template()->HasInstance(value);
864
}
865
866
11
void ContextifyScript::CreateCachedData(
867
    const FunctionCallbackInfo<Value>& args) {
868
11
  Environment* env = Environment::GetCurrent(args);
869
  ContextifyScript* wrapped_script;
870
11
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
871
  Local<UnboundScript> unbound_script =
872
11
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
873
  std::unique_ptr<ScriptCompiler::CachedData> cached_data(
874
22
      ScriptCompiler::CreateCodeCache(unbound_script));
875
11
  if (!cached_data) {
876
    args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked());
877
  } else {
878
    MaybeLocal<Object> buf = Buffer::Copy(
879
        env,
880
22
        reinterpret_cast<const char*>(cached_data->data),
881
11
        cached_data->length);
882
22
    args.GetReturnValue().Set(buf.ToLocalChecked());
883
  }
884
}
885
886
5460
void ContextifyScript::RunInContext(const FunctionCallbackInfo<Value>& args) {
887
5460
  Environment* env = Environment::GetCurrent(args);
888
889
  ContextifyScript* wrapped_script;
890
5460
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
891
892
5460
  CHECK_EQ(args.Length(), 5);
893

10638
  CHECK(args[0]->IsObject() || args[0]->IsNull());
894
895
  Local<Context> context;
896
5460
  std::shared_ptr<MicrotaskQueue> microtask_queue;
897
898
5460
  if (args[0]->IsObject()) {
899
2871
    Local<Object> sandbox = args[0].As<Object>();
900
    // Get the context from the sandbox
901
    ContextifyContext* contextify_context =
902
2871
        ContextifyContext::ContextFromContextifiedSandbox(env, sandbox);
903
2871
    CHECK_NOT_NULL(contextify_context);
904
2871
    CHECK_EQ(contextify_context->env(), env);
905
906
2871
    context = contextify_context->context();
907
2871
    if (context.IsEmpty()) return;
908
909
2871
    microtask_queue = contextify_context->microtask_queue();
910
  } else {
911
2589
    context = env->context();
912
  }
913
914

6252
  TRACE_EVENT0(TRACING_CATEGORY_NODE2(vm, script), "RunInContext");
915
916
5460
  CHECK(args[1]->IsNumber());
917
10920
  int64_t timeout = args[1]->IntegerValue(env->context()).FromJust();
918
919
5460
  CHECK(args[2]->IsBoolean());
920
5460
  bool display_errors = args[2]->IsTrue();
921
922
5460
  CHECK(args[3]->IsBoolean());
923
5460
  bool break_on_sigint = args[3]->IsTrue();
924
925
5460
  CHECK(args[4]->IsBoolean());
926
5460
  bool break_on_first_line = args[4]->IsTrue();
927
928
  // Do the eval within the context
929
5460
  EvalMachine(context,
930
              env,
931
              timeout,
932
              display_errors,
933
              break_on_sigint,
934
              break_on_first_line,
935
              microtask_queue,
936
              args);
937
}
938
939
5460
bool ContextifyScript::EvalMachine(Local<Context> context,
940
                                   Environment* env,
941
                                   const int64_t timeout,
942
                                   const bool display_errors,
943
                                   const bool break_on_sigint,
944
                                   const bool break_on_first_line,
945
                                   std::shared_ptr<MicrotaskQueue> mtask_queue,
946
                                   const FunctionCallbackInfo<Value>& args) {
947
5460
  Context::Scope context_scope(context);
948
949
5460
  if (!env->can_call_into_js())
950
    return false;
951
5460
  if (!ContextifyScript::InstanceOf(env, args.Holder())) {
952
    THROW_ERR_INVALID_THIS(
953
        env,
954
        "Script methods can only be called on script instances.");
955
    return false;
956
  }
957
958
10904
  TryCatchScope try_catch(env);
959
10904
  Isolate::SafeForTerminationScope safe_for_termination(env->isolate());
960
  ContextifyScript* wrapped_script;
961
5460
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder(), false);
962
  Local<UnboundScript> unbound_script =
963
5460
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
964
5460
  Local<Script> script = unbound_script->BindToCurrentContext();
965
966
#if HAVE_INSPECTOR
967
5460
  if (break_on_first_line) {
968
10
    env->inspector_agent()->PauseOnNextJavascriptStatement("Break on start");
969
  }
970
#endif
971
972
  MaybeLocal<Value> result;
973
5460
  bool timed_out = false;
974
5460
  bool received_signal = false;
975
5460
  auto run = [&]() {
976
5460
    MaybeLocal<Value> result = script->Run(context);
977

5444
    if (!result.IsEmpty() && mtask_queue)
978
2
      mtask_queue->PerformCheckpoint(env->isolate());
979
5444
    return result;
980
5460
  };
981

5460
  if (break_on_sigint && timeout != -1) {
982
    Watchdog wd(env->isolate(), timeout, &timed_out);
983
    SigintWatchdog swd(env->isolate(), &received_signal);
984
    result = run();
985
5460
  } else if (break_on_sigint) {
986
2393
    SigintWatchdog swd(env->isolate(), &received_signal);
987
1198
    result = run();
988
4262
  } else if (timeout != -1) {
989
30
    Watchdog wd(env->isolate(), timeout, &timed_out);
990
15
    result = run();
991
  } else {
992
4247
    result = run();
993
  }
994
995
  // Convert the termination exception into a regular exception.
996

5444
  if (timed_out || received_signal) {
997

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

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

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