GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/node_contextify.cc Lines: 615 681 90.3 %
Date: 2021-06-06 04:11:53 Branches: 275 412 66.7 %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
#include "node_contextify.h"
23
24
#include "base_object-inl.h"
25
#include "memory_tracker-inl.h"
26
#include "module_wrap.h"
27
#include "node_context_data.h"
28
#include "node_errors.h"
29
#include "node_external_reference.h"
30
#include "node_internals.h"
31
#include "node_watchdog.h"
32
#include "util-inl.h"
33
34
namespace node {
35
namespace contextify {
36
37
using errors::TryCatchScope;
38
39
using v8::Array;
40
using v8::ArrayBufferView;
41
using v8::Boolean;
42
using v8::Context;
43
using v8::EscapableHandleScope;
44
using v8::External;
45
using v8::Function;
46
using v8::FunctionCallbackInfo;
47
using v8::FunctionTemplate;
48
using v8::HandleScope;
49
using v8::IndexedPropertyHandlerConfiguration;
50
using v8::Int32;
51
using v8::Isolate;
52
using v8::Local;
53
using v8::Maybe;
54
using v8::MaybeLocal;
55
using v8::MeasureMemoryExecution;
56
using v8::MeasureMemoryMode;
57
using v8::MicrotaskQueue;
58
using v8::MicrotasksPolicy;
59
using v8::Name;
60
using v8::NamedPropertyHandlerConfiguration;
61
using v8::Number;
62
using v8::Object;
63
using v8::ObjectTemplate;
64
using v8::PrimitiveArray;
65
using v8::Promise;
66
using v8::PropertyAttribute;
67
using v8::PropertyCallbackInfo;
68
using v8::PropertyDescriptor;
69
using v8::PropertyHandlerFlags;
70
using v8::Script;
71
using v8::ScriptCompiler;
72
using v8::ScriptOrigin;
73
using v8::ScriptOrModule;
74
using v8::String;
75
using v8::Uint32;
76
using v8::UnboundScript;
77
using v8::Value;
78
using v8::WeakCallbackInfo;
79
using v8::WeakCallbackType;
80
81
// The vm module executes code in a sandboxed environment with a different
82
// global object than the rest of the code. This is achieved by applying
83
// every call that changes or queries a property on the global `this` in the
84
// sandboxed code, to the sandbox object.
85
//
86
// The implementation uses V8's interceptors for methods like `set`, `get`,
87
// `delete`, `defineProperty`, and for any query of the property attributes.
88
// Property handlers with interceptors are set on the object template for
89
// the sandboxed code. Handlers for both named properties and for indexed
90
// properties are used. Their functionality is almost identical, the indexed
91
// interceptors mostly just call the named interceptors.
92
//
93
// For every `get` of a global property in the sandboxed context, the
94
// interceptor callback checks the sandbox object for the property.
95
// If the property is defined on the sandbox, that result is returned to
96
// the original call instead of finishing the query on the global object.
97
//
98
// For every `set` of a global property, the interceptor callback defines or
99
// changes the property both on the sandbox and the global proxy.
100
101
namespace {
102
103
// Convert an int to a V8 Name (String or Symbol).
104
3
Local<Name> Uint32ToName(Local<Context> context, uint32_t index) {
105
12
  return Uint32::New(context->GetIsolate(), index)->ToString(context)
106
6
      .ToLocalChecked();
107
}
108
109
}  // anonymous namespace
110
111
593
ContextifyContext::ContextifyContext(
112
    Environment* env,
113
    Local<Object> sandbox_obj,
114
593
    const ContextOptions& options)
115
  : env_(env),
116
1186
    microtask_queue_wrap_(options.microtask_queue_wrap) {
117
593
  MaybeLocal<Context> v8_context = CreateV8Context(env, sandbox_obj, options);
118
119
  // Allocation failure, maximum call stack size reached, termination, etc.
120
593
  if (v8_context.IsEmpty()) return;
121
122
1186
  context_.Reset(env->isolate(), v8_context.ToLocalChecked());
123
593
  context_.SetWeak(this, WeakCallback, WeakCallbackType::kParameter);
124
593
  env->AddCleanupHook(CleanupHook, this);
125
}
126
127
128
1497
ContextifyContext::~ContextifyContext() {
129
499
  env()->RemoveCleanupHook(CleanupHook, this);
130
499
  Isolate* isolate = env()->isolate();
131
998
  HandleScope scope(isolate);
132
133
  env()->async_hooks()
134
499
    ->RemoveContext(PersistentToLocal::Weak(isolate, context_));
135
499
}
136
137
138
440
void ContextifyContext::CleanupHook(void* arg) {
139
440
  ContextifyContext* self = static_cast<ContextifyContext*>(arg);
140
440
  self->context_.Reset();
141
440
  delete self;
142
440
}
143
144
145
// This is an object that just keeps an internal pointer to this
146
// ContextifyContext.  It's passed to the NamedPropertyHandler.  If we
147
// pass the main JavaScript context object we're embedded in, then the
148
// NamedPropertyHandler will store a reference to it forever and keep it
149
// from getting gc'd.
150
593
MaybeLocal<Object> ContextifyContext::CreateDataWrapper(Environment* env) {
151
  Local<Object> wrapper;
152
1779
  if (!env->script_data_constructor_function()
153
1779
           ->NewInstance(env->context())
154
593
           .ToLocal(&wrapper)) {
155
    return MaybeLocal<Object>();
156
  }
157
158
593
  wrapper->SetAlignedPointerInInternalField(ContextifyContext::kSlot, this);
159
593
  return wrapper;
160
}
161
162
593
MaybeLocal<Context> ContextifyContext::CreateV8Context(
163
    Environment* env,
164
    Local<Object> sandbox_obj,
165
    const ContextOptions& options) {
166
593
  EscapableHandleScope scope(env->isolate());
167
  Local<FunctionTemplate> function_template =
168
593
      FunctionTemplate::New(env->isolate());
169
170
1186
  function_template->SetClassName(sandbox_obj->GetConstructorName());
171
172
  Local<ObjectTemplate> object_template =
173
593
      function_template->InstanceTemplate();
174
175
  Local<Object> data_wrapper;
176
1186
  if (!CreateDataWrapper(env).ToLocal(&data_wrapper))
177
    return MaybeLocal<Context>();
178
179
  NamedPropertyHandlerConfiguration config(
180
      PropertyGetterCallback,
181
      PropertySetterCallback,
182
      PropertyDescriptorCallback,
183
      PropertyDeleterCallback,
184
      PropertyEnumeratorCallback,
185
      PropertyDefinerCallback,
186
      data_wrapper,
187
593
      PropertyHandlerFlags::kHasNoSideEffect);
188
189
  IndexedPropertyHandlerConfiguration indexed_config(
190
      IndexedPropertyGetterCallback,
191
      IndexedPropertySetterCallback,
192
      IndexedPropertyDescriptorCallback,
193
      IndexedPropertyDeleterCallback,
194
      PropertyEnumeratorCallback,
195
      IndexedPropertyDefinerCallback,
196
      data_wrapper,
197
593
      PropertyHandlerFlags::kHasNoSideEffect);
198
199
593
  object_template->SetHandler(config);
200
593
  object_template->SetHandler(indexed_config);
201
  Local<Context> ctx = Context::New(
202
      env->isolate(),
203
      nullptr,  // extensions
204
      object_template,
205
      {},       // global object
206
      {},       // deserialization callback
207
1186
      microtask_queue() ?
208
598
          microtask_queue().get() :
209
1779
          env->isolate()->GetCurrentContext()->GetMicrotaskQueue());
210
593
  if (ctx.IsEmpty()) return MaybeLocal<Context>();
211
  // Only partially initialize the context - the primordials are left out
212
  // and only initialized when necessary.
213
593
  InitializeContextRuntime(ctx);
214
215
593
  if (ctx.IsEmpty()) {
216
    return MaybeLocal<Context>();
217
  }
218
219
593
  Local<Context> context = env->context();
220
1186
  ctx->SetSecurityToken(context->GetSecurityToken());
221
222
  // We need to tie the lifetime of the sandbox object with the lifetime of
223
  // newly created context. We do this by making them hold references to each
224
  // other. The context can directly hold a reference to the sandbox as an
225
  // embedder data field. However, we cannot hold a reference to a v8::Context
226
  // directly in an Object, we instead hold onto the new context's global
227
  // object instead (which then has a reference to the context).
228
593
  ctx->SetEmbedderData(ContextEmbedderIndex::kSandboxObject, sandbox_obj);
229
  sandbox_obj->SetPrivate(context,
230
                          env->contextify_global_private_symbol(),
231
1779
                          ctx->Global());
232
233
1186
  Utf8Value name_val(env->isolate(), options.name);
234
1779
  ctx->AllowCodeGenerationFromStrings(options.allow_code_gen_strings->IsTrue());
235
1186
  ctx->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
236
593
                       options.allow_code_gen_wasm);
237
238
1186
  ContextInfo info(*name_val);
239
240
1186
  if (!options.origin.IsEmpty()) {
241
4
    Utf8Value origin_val(env->isolate(), options.origin);
242
2
    info.origin = *origin_val;
243
  }
244
245
593
  env->AssignToContext(ctx, info);
246
247
593
  return scope.Escape(ctx);
248
}
249
250
251
467
void ContextifyContext::Init(Environment* env, Local<Object> target) {
252
  Local<FunctionTemplate> function_template =
253
467
      FunctionTemplate::New(env->isolate());
254
1401
  function_template->InstanceTemplate()->SetInternalFieldCount(
255
467
      ContextifyContext::kInternalFieldCount);
256
  env->set_script_data_constructor_function(
257
1401
      function_template->GetFunction(env->context()).ToLocalChecked());
258
259
467
  env->SetMethod(target, "makeContext", MakeContext);
260
467
  env->SetMethod(target, "isContext", IsContext);
261
467
  env->SetMethod(target, "compileFunction", CompileFunction);
262
467
}
263
264
4779
void ContextifyContext::RegisterExternalReferences(
265
    ExternalReferenceRegistry* registry) {
266
4779
  registry->Register(MakeContext);
267
4779
  registry->Register(IsContext);
268
4779
  registry->Register(CompileFunction);
269
4779
}
270
271
// makeContext(sandbox, name, origin, strings, wasm);
272
593
void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
273
593
  Environment* env = Environment::GetCurrent(args);
274
275
593
  CHECK_EQ(args.Length(), 6);
276
1186
  CHECK(args[0]->IsObject());
277
1186
  Local<Object> sandbox = args[0].As<Object>();
278
279
  // Don't allow contextifying a sandbox multiple times.
280
1779
  CHECK(
281
      !sandbox->HasPrivate(
282
          env->context(),
283
          env->contextify_context_private_symbol()).FromJust());
284
285
1186
  ContextOptions options;
286
287
1779
  CHECK(args[1]->IsString());
288
1186
  options.name = args[1].As<String>();
289
290

3552
  CHECK(args[2]->IsString() || args[2]->IsUndefined());
291
1779
  if (args[2]->IsString()) {
292
4
    options.origin = args[2].As<String>();
293
  }
294
295
1186
  CHECK(args[3]->IsBoolean());
296
1186
  options.allow_code_gen_strings = args[3].As<Boolean>();
297
298
1186
  CHECK(args[4]->IsBoolean());
299
1186
  options.allow_code_gen_wasm = args[4].As<Boolean>();
300
301

2377
  if (args[5]->IsObject() &&
302

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

2562
  if (maybe_value.ToLocal(&context_external_v) &&
356
1281
      context_external_v->IsExternal()) {
357
1281
    Local<External> context_external = context_external_v.As<External>();
358
1281
    return static_cast<ContextifyContext*>(context_external->Value());
359
  }
360
  return nullptr;
361
}
362
363
// static
364
template <typename T>
365
1043129
ContextifyContext* ContextifyContext::Get(const PropertyCallbackInfo<T>& args) {
366
1043129
  Local<Value> data = args.Data();
367
  return static_cast<ContextifyContext*>(
368
3129387
      data.As<Object>()->GetAlignedPointerFromInternalField(
369
2086258
          ContextifyContext::kSlot));
370
}
371
372
// static
373
1042669
void ContextifyContext::PropertyGetterCallback(
374
    Local<Name> property,
375
    const PropertyCallbackInfo<Value>& args) {
376
1042669
  ContextifyContext* ctx = ContextifyContext::Get(args);
377
378
  // Still initializing
379
2085338
  if (ctx->context_.IsEmpty())
380
1779
    return;
381
382
1040890
  Local<Context> context = ctx->context();
383
1040890
  Local<Object> sandbox = ctx->sandbox();
384
  MaybeLocal<Value> maybe_rv =
385
1040890
      sandbox->GetRealNamedProperty(context, property);
386
1040890
  if (maybe_rv.IsEmpty()) {
387
    maybe_rv =
388
75014
        ctx->global_proxy()->GetRealNamedProperty(context, property);
389
  }
390
391
  Local<Value> rv;
392
1040890
  if (maybe_rv.ToLocal(&rv)) {
393
1040820
    if (rv == sandbox)
394
10
      rv = ctx->global_proxy();
395
396
2081640
    args.GetReturnValue().Set(rv);
397
  }
398
}
399
400
// static
401
159
void ContextifyContext::PropertySetterCallback(
402
    Local<Name> property,
403
    Local<Value> value,
404
    const PropertyCallbackInfo<Value>& args) {
405
159
  ContextifyContext* ctx = ContextifyContext::Get(args);
406
407
  // Still initializing
408
318
  if (ctx->context_.IsEmpty())
409
14
    return;
410
411
159
  Local<Context> context = ctx->context();
412
159
  PropertyAttribute attributes = PropertyAttribute::None;
413
318
  bool is_declared_on_global_proxy = ctx->global_proxy()
414
318
      ->GetRealNamedPropertyAttributes(context, property)
415
159
      .To(&attributes);
416
  bool read_only =
417
159
      static_cast<int>(attributes) &
418
159
      static_cast<int>(PropertyAttribute::ReadOnly);
419
420
318
  bool is_declared_on_sandbox = ctx->sandbox()
421
318
      ->GetRealNamedPropertyAttributes(context, property)
422
159
      .To(&attributes);
423

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

146
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
446


252
  if (!is_declared && args.ShouldThrowOnError() && is_contextual_store &&
447
30
      !is_function)
448
1
    return;
449
450

399
  if (!is_declared_on_global_proxy && is_declared_on_sandbox  &&
451

167
      args.ShouldThrowOnError() && is_contextual_store && !is_function) {
452
    // The property exists on the sandbox but not on the global
453
    // proxy. Setting it would throw because we are in strict mode.
454
    // Don't attempt to set it by signaling that the call was
455
    // intercepted. Only change the value on the sandbox.
456
8
    args.GetReturnValue().Set(false);
457
  }
458
459
290
  USE(ctx->sandbox()->Set(context, property, value));
460
}
461
462
// static
463
53
void ContextifyContext::PropertyDescriptorCallback(
464
    Local<Name> property,
465
    const PropertyCallbackInfo<Value>& args) {
466
53
  ContextifyContext* ctx = ContextifyContext::Get(args);
467
468
  // Still initializing
469
106
  if (ctx->context_.IsEmpty())
470
    return;
471
472
53
  Local<Context> context = ctx->context();
473
474
53
  Local<Object> sandbox = ctx->sandbox();
475
476
159
  if (sandbox->HasOwnProperty(context, property).FromMaybe(false)) {
477
    Local<Value> desc;
478
76
    if (sandbox->GetOwnPropertyDescriptor(context, property).ToLocal(&desc)) {
479
76
      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
30
  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
45
      ctx->global_proxy()->GetRealNamedPropertyAttributes(context,
501
15
                                                          property)
502
15
          .To(&attributes);
503
  bool read_only =
504
15
      static_cast<int>(attributes) &
505
15
          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
31
        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
30
        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
10
        desc.has_get() ? desc.get() : Undefined(isolate).As<Value>(),
529

28
        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
4
  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
228
void ContextifyContext::PropertyEnumeratorCallback(
568
    const PropertyCallbackInfo<Array>& args) {
569
228
  ContextifyContext* ctx = ContextifyContext::Get(args);
570
571
  // Still initializing
572
456
  if (ctx->context_.IsEmpty())
573
    return;
574
575
  Local<Array> properties;
576
577
684
  if (!ctx->sandbox()->GetPropertyNames(ctx->context()).ToLocal(&properties))
578
    return;
579
580
456
  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
2
  if (ctx->context_.IsEmpty())
606
    return;
607
608
1
  ContextifyContext::PropertySetterCallback(
609
1
      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
2
  if (ctx->context_.IsEmpty())
620
    return;
621
622
1
  ContextifyContext::PropertyDescriptorCallback(
623
1
      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
2
  if (ctx->context_.IsEmpty())
635
    return;
636
637
1
  ContextifyContext::PropertyDefinerCallback(
638
1
      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
467
void ContextifyScript::Init(Environment* env, Local<Object> target) {
662
934
  HandleScope scope(env->isolate());
663
  Local<String> class_name =
664
467
      FIXED_ONE_BYTE_STRING(env->isolate(), "ContextifyScript");
665
666
467
  Local<FunctionTemplate> script_tmpl = env->NewFunctionTemplate(New);
667
1401
  script_tmpl->InstanceTemplate()->SetInternalFieldCount(
668
467
      ContextifyScript::kInternalFieldCount);
669
467
  script_tmpl->SetClassName(class_name);
670
467
  env->SetProtoMethod(script_tmpl, "createCachedData", CreateCachedData);
671
467
  env->SetProtoMethod(script_tmpl, "runInContext", RunInContext);
672
467
  env->SetProtoMethod(script_tmpl, "runInThisContext", RunInThisContext);
673
674
467
  Local<Context> context = env->context();
675
676
934
  target->Set(context, class_name,
677
1401
      script_tmpl->GetFunction(context).ToLocalChecked()).Check();
678
467
  env->set_script_context_constructor_template(script_tmpl);
679
467
}
680
681
4779
void ContextifyScript::RegisterExternalReferences(
682
    ExternalReferenceRegistry* registry) {
683
4779
  registry->Register(New);
684
4779
  registry->Register(CreateCachedData);
685
4779
  registry->Register(RunInContext);
686
4779
  registry->Register(RunInThisContext);
687
4779
}
688
689
2171
void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
690
2171
  Environment* env = Environment::GetCurrent(args);
691
2171
  Isolate* isolate = env->isolate();
692
2171
  Local<Context> context = env->context();
693
694
2171
  CHECK(args.IsConstructCall());
695
696
2171
  const int argc = args.Length();
697
2171
  CHECK_GE(argc, 2);
698
699
6513
  CHECK(args[0]->IsString());
700
4342
  Local<String> code = args[0].As<String>();
701
702
6513
  CHECK(args[1]->IsString());
703
4342
  Local<String> filename = args[1].As<String>();
704
705
2171
  int line_offset = 0;
706
2171
  int column_offset = 0;
707
  Local<ArrayBufferView> cached_data_buf;
708
2171
  bool produce_cached_data = false;
709
2171
  Local<Context> parsing_context = context;
710
711
2171
  if (argc > 2) {
712
    // new ContextifyScript(code, filename, lineOffset, columnOffset,
713
    //                      cachedData, produceCachedData, parsingContext)
714
2171
    CHECK_EQ(argc, 7);
715
4342
    CHECK(args[2]->IsNumber());
716
6513
    line_offset = args[2].As<Int32>()->Value();
717
4342
    CHECK(args[3]->IsNumber());
718
6513
    column_offset = args[3].As<Int32>()->Value();
719
6513
    if (!args[4]->IsUndefined()) {
720
46
      CHECK(args[4]->IsArrayBufferView());
721
46
      cached_data_buf = args[4].As<ArrayBufferView>();
722
    }
723
4342
    CHECK(args[5]->IsBoolean());
724
4342
    produce_cached_data = args[5]->IsTrue();
725
6513
    if (!args[6]->IsUndefined()) {
726
920
      CHECK(args[6]->IsObject());
727
      ContextifyContext* sandbox =
728
460
          ContextifyContext::ContextFromContextifiedSandbox(
729
1380
              env, args[6].As<Object>());
730
460
      CHECK_NOT_NULL(sandbox);
731
460
      parsing_context = sandbox->context();
732
    }
733
  }
734
735
  ContextifyScript* contextify_script =
736
2171
      new ContextifyScript(env, args.This());
737
738
2171
  if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
739
          TRACING_CATEGORY_NODE2(vm, script)) != 0) {
740
14
    Utf8Value fn(isolate, filename);
741
7
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
742
        TRACING_CATEGORY_NODE2(vm, script),
743
        "ContextifyScript::New",
744
        contextify_script,
745
14
        "filename", TRACE_STR_COPY(*fn));
746
7
  }
747
7
748
2185
  ScriptCompiler::CachedData* cached_data = nullptr;
749
2171
  if (!cached_data_buf.IsEmpty()) {
750
14
    uint8_t* data = static_cast<uint8_t*>(
751
46
        cached_data_buf->Buffer()->GetBackingStore()->Data());
752
23
    cached_data = new ScriptCompiler::CachedData(
753
46
        data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
754
  }
755
756
  Local<PrimitiveArray> host_defined_options =
757
2171
      PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
758
6513
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kType,
759
2171
                            Number::New(isolate, loader::ScriptType::kScript));
760
6513
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kID,
761
4342
                            Number::New(isolate, contextify_script->id()));
762
763
  ScriptOrigin origin(isolate,
764
                      filename,
765
                      line_offset,                          // line offset
766
                      column_offset,                        // column offset
767
                      true,                                 // is cross origin
768
                      -1,                                   // script id
769
                      Local<Value>(),                       // source map URL
770
                      false,                                // is opaque (?)
771
                      false,                                // is WASM
772
                      false,                                // is ES Module
773
2171
                      host_defined_options);
774
1989
  ScriptCompiler::Source source(code, origin, cached_data);
775
  ScriptCompiler::CompileOptions compile_options =
776
2171
      ScriptCompiler::kNoCompileOptions;
777
778
2171
  if (source.GetCachedData() != nullptr)
779
23
    compile_options = ScriptCompiler::kConsumeCodeCache;
780
781
4160
  TryCatchScope try_catch(env);
782
4160
  ShouldNotAbortOnUncaughtScope no_abort_scope(env);
783
1989
  Context::Scope scope(parsing_context);
784
785
  MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
786
      isolate,
787
      &source,
788
2171
      compile_options);
789
790
2171
  if (v8_script.IsEmpty()) {
791
182
    errors::DecorateErrorStack(env, try_catch);
792
182
    no_abort_scope.Close();
793
182
    if (!try_catch.HasTerminated())
794
182
      try_catch.ReThrow();
795
    TRACE_EVENT_NESTABLE_ASYNC_END0(
796
182
        TRACING_CATEGORY_NODE2(vm, script),
797
        "ContextifyScript::New",
798
28
        contextify_script);
799
546
    return;
800
182
  }
801
3978
  contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
802
803
1989
  Local<Context> env_context = env->context();
804
1989
  if (compile_options == ScriptCompiler::kConsumeCodeCache) {
805
69
    args.This()->Set(
806
        env_context,
807
        env->cached_data_rejected_string(),
808
92
        Boolean::New(isolate, source.GetCachedData()->rejected)).Check();
809
1966
  } else if (produce_cached_data) {
810
    std::unique_ptr<ScriptCompiler::CachedData> cached_data {
811
12
      ScriptCompiler::CreateCodeCache(v8_script.ToLocalChecked()) };
812
6
    bool cached_data_produced = cached_data != nullptr;
813
6
    if (cached_data_produced) {
814
      MaybeLocal<Object> buf = Buffer::Copy(
815
          env,
816
6
          reinterpret_cast<const char*>(cached_data->data),
817
12
          cached_data->length);
818
18
      args.This()->Set(env_context,
819
                       env->cached_data_string(),
820
18
                       buf.ToLocalChecked()).Check();
821
    }
822
18
    args.This()->Set(
823
        env_context,
824
        env->cached_data_produced_string(),
825
24
        Boolean::New(isolate, cached_data_produced)).Check();
826
  }
827
  TRACE_EVENT_NESTABLE_ASYNC_END0(
828
1989
      TRACING_CATEGORY_NODE2(vm, script),
829
      "ContextifyScript::New",
830
605
      contextify_script);
831
1989
}
832
833
1974
bool ContextifyScript::InstanceOf(Environment* env,
834
14
                                  const Local<Value>& value) {
835

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

1951
    if (!result.IsEmpty() && mtask_queue)
981
4
      mtask_queue->PerformCheckpoint(env->isolate());
982
1951
    return result;
983
1967
  };
984

1967
  if (break_on_sigint && timeout != -1) {
985
    Watchdog wd(env->isolate(), timeout, &timed_out);
986
    SigintWatchdog swd(env->isolate(), &received_signal);
987
    result = run();
988
1967
  } else if (break_on_sigint) {
989
367
    SigintWatchdog swd(env->isolate(), &received_signal);
990
185
    result = run();
991
1782
  } else if (timeout != -1) {
992
30
    Watchdog wd(env->isolate(), timeout, &timed_out);
993
15
    result = run();
994
  } else {
995
1767
    result = run();
996
  }
997
998
  // Convert the termination exception into a regular exception.
999

1951
  if (timed_out || received_signal) {
1000

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

166
    if (!timed_out && !received_signal && display_errors) {
1015
      // We should decorate non-termination exceptions
1016
93
      errors::DecorateErrorStack(env, try_catch);
1017
    }
1018
1019
    // If there was an exception thrown during script execution, re-throw it.
1020
    // If one of the above checks threw, re-throw the exception instead of
1021
    // letting try_catch catch it.
1022
    // If execution has been terminated, but not by one of the watchdogs from
1023
    // this invocation, this will re-throw a `null` value.
1024
166
    if (!try_catch.HasTerminated())
1025
163
      try_catch.ReThrow();
1026
1027
166
    return false;
1028
  }
1029
1030
3570
  args.GetReturnValue().Set(result.ToLocalChecked());
1031
1785
  return true;
1032
}
1033
1034
1035
2171
ContextifyScript::ContextifyScript(Environment* env, Local<Object> object)
1036
    : BaseObject(env, object),
1037
4342
      id_(env->get_next_script_id()) {
1038
2171
  MakeWeak();
1039
2171
  env->id_to_script_map.emplace(id_, this);
1040
2171
}
1041
1042
1043
7956
ContextifyScript::~ContextifyScript() {
1044
1988
  env()->id_to_script_map.erase(id_);
1045
3976
}
1046
1047
1048
32149
void ContextifyContext::CompileFunction(
1049
    const FunctionCallbackInfo<Value>& args) {
1050
32149
  Environment* env = Environment::GetCurrent(args);
1051
32149
  Isolate* isolate = env->isolate();
1052
32149
  Local<Context> context = env->context();
1053
1054
  // Argument 1: source code
1055
96447
  CHECK(args[0]->IsString());
1056
64298
  Local<String> code = args[0].As<String>();
1057
1058
  // Argument 2: filename
1059
96447
  CHECK(args[1]->IsString());
1060
64298
  Local<String> filename = args[1].As<String>();
1061
1062
  // Argument 3: line offset
1063
64298
  CHECK(args[2]->IsNumber());
1064
96447
  int line_offset = args[2].As<Int32>()->Value();
1065
1066
  // Argument 4: column offset
1067
64298
  CHECK(args[3]->IsNumber());
1068
96447
  int column_offset = args[3].As<Int32>()->Value();
1069
1070
  // Argument 5: cached data (optional)
1071
  Local<ArrayBufferView> cached_data_buf;
1072
96447
  if (!args[4]->IsUndefined()) {
1073
    CHECK(args[4]->IsArrayBufferView());
1074
    cached_data_buf = args[4].As<ArrayBufferView>();
1075
  }
1076
1077
  // Argument 6: produce cache data
1078
64298
  CHECK(args[5]->IsBoolean());
1079
64298
  bool produce_cached_data = args[5]->IsTrue();
1080
1081
  // Argument 7: parsing context (optional)
1082
  Local<Context> parsing_context;
1083
96447
  if (!args[6]->IsUndefined()) {
1084
4
    CHECK(args[6]->IsObject());
1085
    ContextifyContext* sandbox =
1086
2
        ContextifyContext::ContextFromContextifiedSandbox(
1087
6
            env, args[6].As<Object>());
1088
2
    CHECK_NOT_NULL(sandbox);
1089
2
    parsing_context = sandbox->context();
1090
  } else {
1091
32147
    parsing_context = context;
1092
  }
1093
1094
  // Argument 8: context extensions (optional)
1095
  Local<Array> context_extensions_buf;
1096
96447
  if (!args[7]->IsUndefined()) {
1097
64298
    CHECK(args[7]->IsArray());
1098
64298
    context_extensions_buf = args[7].As<Array>();
1099
  }
1100
1101
  // Argument 9: params for the function (optional)
1102
  Local<Array> params_buf;
1103
96447
  if (!args[8]->IsUndefined()) {
1104
64286
    CHECK(args[8]->IsArray());
1105
64286
    params_buf = args[8].As<Array>();
1106
  }
1107
1108
  // Read cache from cached data buffer
1109
32149
  ScriptCompiler::CachedData* cached_data = nullptr;
1110
32149
  if (!cached_data_buf.IsEmpty()) {
1111
    uint8_t* data = static_cast<uint8_t*>(
1112
        cached_data_buf->Buffer()->GetBackingStore()->Data());
1113
    cached_data = new ScriptCompiler::CachedData(
1114
      data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
1115
  }
1116
1117
  // Get the function id
1118
32149
  uint32_t id = env->get_next_function_id();
1119
1120
  // Set host_defined_options
1121
  Local<PrimitiveArray> host_defined_options =
1122
32149
      PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
1123
96447
  host_defined_options->Set(
1124
      isolate,
1125
      loader::HostDefinedOptions::kType,
1126
32149
      Number::New(isolate, loader::ScriptType::kFunction));
1127
96447
  host_defined_options->Set(
1128
32149
      isolate, loader::HostDefinedOptions::kID, Number::New(isolate, id));
1129
1130
  ScriptOrigin origin(isolate,
1131
                      filename,
1132
                      line_offset,       // line offset
1133
                      column_offset,     // column offset
1134
                      true,              // is cross origin
1135
                      -1,                // script id
1136
                      Local<Value>(),    // source map URL
1137
                      false,             // is opaque (?)
1138
                      false,             // is WASM
1139
                      false,             // is ES Module
1140
32149
                      host_defined_options);
1141
1142
32120
  ScriptCompiler::Source source(code, origin, cached_data);
1143
  ScriptCompiler::CompileOptions options;
1144
32149
  if (source.GetCachedData() == nullptr) {
1145
32149
    options = ScriptCompiler::kNoCompileOptions;
1146
  } else {
1147
    options = ScriptCompiler::kConsumeCodeCache;
1148
  }
1149
1150
64269
  TryCatchScope try_catch(env);
1151
32120
  Context::Scope scope(parsing_context);
1152
1153
  // Read context extensions from buffer
1154
64269
  std::vector<Local<Object>> context_extensions;
1155
32149
  if (!context_extensions_buf.IsEmpty()) {
1156
64300
    for (uint32_t n = 0; n < context_extensions_buf->Length(); n++) {
1157
      Local<Value> val;
1158
2
      if (!context_extensions_buf->Get(context, n).ToLocal(&val)) return;
1159
1
      CHECK(val->IsObject());
1160
1
      context_extensions.push_back(val.As<Object>());
1161
    }
1162
  }
1163
1164
  // Read params from params buffer
1165
64269
  std::vector<Local<String>> params;
1166
32149
  if (!params_buf.IsEmpty()) {
1167
385620
    for (uint32_t n = 0; n < params_buf->Length(); n++) {
1168
      Local<Value> val;
1169
321335
      if (!params_buf->Get(context, n).ToLocal(&val)) return;
1170
321336
      CHECK(val->IsString());
1171
160668
      params.push_back(val.As<String>());
1172
    }
1173
  }
1174
1175
  Local<ScriptOrModule> script;
1176
  MaybeLocal<Function> maybe_fn = ScriptCompiler::CompileFunctionInContext(
1177
      parsing_context, &source, params.size(), params.data(),
1178
      context_extensions.size(), context_extensions.data(), options,
1179
32149
      v8::ScriptCompiler::NoCacheReason::kNoCacheNoReason, &script);
1180
1181
  Local<Function> fn;
1182
32149
  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
96360
  if (!env->compiled_fn_entry_template()->NewInstance(
1192
64240
           context).ToLocal(&cache_key)) {
1193
    return;
1194
  }
1195
32120
  CompiledFnEntry* entry = new CompiledFnEntry(env, cache_key, id, script);
1196
32120
  env->id_to_function_map.emplace(id, entry);
1197
1198
32120
  Local<Object> result = Object::New(isolate);
1199
96360
  if (result->Set(parsing_context, env->function_string(), fn).IsNothing())
1200
    return;
1201
96360
  if (result->Set(parsing_context, env->cache_key_string(), cache_key)
1202
          .IsNothing())
1203
    return;
1204
1205
32120
  if (produce_cached_data) {
1206
    const std::unique_ptr<ScriptCompiler::CachedData> cached_data(
1207
        ScriptCompiler::CreateCodeCacheForFunction(fn));
1208
    bool cached_data_produced = cached_data != nullptr;
1209
    if (cached_data_produced) {
1210
      MaybeLocal<Object> buf = Buffer::Copy(
1211
          env,
1212
          reinterpret_cast<const char*>(cached_data->data),
1213
          cached_data->length);
1214
      if (result
1215
              ->Set(parsing_context,
1216
                    env->cached_data_string(),
1217
                    buf.ToLocalChecked())
1218
              .IsNothing())
1219
        return;
1220
    }
1221
    if (result
1222
            ->Set(parsing_context,
1223
                  env->cached_data_produced_string(),
1224
                  Boolean::New(isolate, cached_data_produced))
1225
            .IsNothing())
1226
      return;
1227
  }
1228
1229
64240
  args.GetReturnValue().Set(result);
1230
}
1231
1232
void CompiledFnEntry::WeakCallback(
1233
    const WeakCallbackInfo<CompiledFnEntry>& data) {
1234
  CompiledFnEntry* entry = data.GetParameter();
1235
  delete entry;
1236
}
1237
1238
32120
CompiledFnEntry::CompiledFnEntry(Environment* env,
1239
                                 Local<Object> object,
1240
                                 uint32_t id,
1241
32120
                                 Local<ScriptOrModule> script)
1242
    : BaseObject(env, object),
1243
      id_(id),
1244
32120
      script_(env->isolate(), script) {
1245
32120
  script_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
1246
32120
}
1247
1248
119607
CompiledFnEntry::~CompiledFnEntry() {
1249
29901
  env()->id_to_function_map.erase(id_);
1250
29903
  script_.ClearWeak();
1251
59801
}
1252
1253
181
static void StartSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1254
181
  int ret = SigintWatchdogHelper::GetInstance()->Start();
1255
543
  args.GetReturnValue().Set(ret == 0);
1256
181
}
1257
1258
178
static void StopSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1259
178
  bool had_pending_signals = SigintWatchdogHelper::GetInstance()->Stop();
1260
534
  args.GetReturnValue().Set(had_pending_signals);
1261
178
}
1262
1263
3
static void WatchdogHasPendingSigint(const FunctionCallbackInfo<Value>& args) {
1264
3
  bool ret = SigintWatchdogHelper::GetInstance()->HasPendingSignal();
1265
9
  args.GetReturnValue().Set(ret);
1266
3
}
1267
1268
8
static void MeasureMemory(const FunctionCallbackInfo<Value>& args) {
1269
16
  CHECK(args[0]->IsInt32());
1270
16
  CHECK(args[1]->IsInt32());
1271
24
  int32_t mode = args[0].As<v8::Int32>()->Value();
1272
24
  int32_t execution = args[1].As<v8::Int32>()->Value();
1273
8
  Isolate* isolate = args.GetIsolate();
1274
1275
8
  Local<Context> current_context = isolate->GetCurrentContext();
1276
  Local<Promise::Resolver> resolver;
1277
16
  if (!Promise::Resolver::New(current_context).ToLocal(&resolver)) return;
1278
  std::unique_ptr<v8::MeasureMemoryDelegate> delegate =
1279
      v8::MeasureMemoryDelegate::Default(
1280
          isolate,
1281
          current_context,
1282
          resolver,
1283
16
          static_cast<v8::MeasureMemoryMode>(mode));
1284
16
  isolate->MeasureMemory(std::move(delegate),
1285
8
                         static_cast<v8::MeasureMemoryExecution>(execution));
1286
8
  v8::Local<v8::Promise> promise = resolver->GetPromise();
1287
1288
16
  args.GetReturnValue().Set(promise);
1289
}
1290
1291
5
MicrotaskQueueWrap::MicrotaskQueueWrap(Environment* env, Local<Object> obj)
1292
  : BaseObject(env, obj),
1293
    microtask_queue_(
1294
5
        MicrotaskQueue::New(env->isolate(), MicrotasksPolicy::kExplicit)) {
1295
5
  MakeWeak();
1296
5
}
1297
1298
const std::shared_ptr<MicrotaskQueue>&
1299
15
MicrotaskQueueWrap::microtask_queue() const {
1300
15
  return microtask_queue_;
1301
}
1302
1303
5
void MicrotaskQueueWrap::New(const FunctionCallbackInfo<Value>& args) {
1304
5
  CHECK(args.IsConstructCall());
1305
10
  new MicrotaskQueueWrap(Environment::GetCurrent(args), args.This());
1306
5
}
1307
1308
467
void MicrotaskQueueWrap::Init(Environment* env, Local<Object> target) {
1309
934
  HandleScope scope(env->isolate());
1310
467
  Local<FunctionTemplate> tmpl = env->NewFunctionTemplate(New);
1311
1401
  tmpl->InstanceTemplate()->SetInternalFieldCount(
1312
467
      ContextifyScript::kInternalFieldCount);
1313
467
  env->set_microtask_queue_ctor_template(tmpl);
1314
467
  env->SetConstructorFunction(target, "MicrotaskQueue", tmpl);
1315
467
}
1316
1317
4779
void MicrotaskQueueWrap::RegisterExternalReferences(
1318
    ExternalReferenceRegistry* registry) {
1319
4779
  registry->Register(New);
1320
4779
}
1321
1322
467
void Initialize(Local<Object> target,
1323
                Local<Value> unused,
1324
                Local<Context> context,
1325
                void* priv) {
1326
467
  Environment* env = Environment::GetCurrent(context);
1327
467
  Isolate* isolate = env->isolate();
1328
467
  ContextifyContext::Init(env, target);
1329
467
  ContextifyScript::Init(env, target);
1330
467
  MicrotaskQueueWrap::Init(env, target);
1331
1332
467
  env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog);
1333
467
  env->SetMethod(target, "stopSigintWatchdog", StopSigintWatchdog);
1334
  // Used in tests.
1335
  env->SetMethodNoSideEffect(
1336
467
      target, "watchdogHasPendingSigint", WatchdogHasPendingSigint);
1337
1338
  {
1339
467
    Local<FunctionTemplate> tpl = FunctionTemplate::New(env->isolate());
1340
934
    tpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "CompiledFnEntry"));
1341
1401
    tpl->InstanceTemplate()->SetInternalFieldCount(
1342
467
        CompiledFnEntry::kInternalFieldCount);
1343
1344
467
    env->set_compiled_fn_entry_template(tpl->InstanceTemplate());
1345
  }
1346
1347
467
  Local<Object> constants = Object::New(env->isolate());
1348
467
  Local<Object> measure_memory = Object::New(env->isolate());
1349
467
  Local<Object> memory_execution = Object::New(env->isolate());
1350
1351
  {
1352
467
    Local<Object> memory_mode = Object::New(env->isolate());
1353
467
    MeasureMemoryMode SUMMARY = MeasureMemoryMode::kSummary;
1354
467
    MeasureMemoryMode DETAILED = MeasureMemoryMode::kDetailed;
1355
1868
    NODE_DEFINE_CONSTANT(memory_mode, SUMMARY);
1356
467
    NODE_DEFINE_CONSTANT(memory_mode, DETAILED);
1357
2335
    READONLY_PROPERTY(measure_memory, "mode", memory_mode);
1358
467
  }
1359
2335
1360
934
  {
1361
467
    MeasureMemoryExecution DEFAULT = MeasureMemoryExecution::kDefault;
1362
467
    MeasureMemoryExecution EAGER = MeasureMemoryExecution::kEager;
1363
934
    NODE_DEFINE_CONSTANT(memory_execution, DEFAULT);
1364
467
    NODE_DEFINE_CONSTANT(memory_execution, EAGER);
1365
3269
    READONLY_PROPERTY(measure_memory, "execution", memory_execution);
1366
2335
  }
1367
2335
1368
2335
  READONLY_PROPERTY(constants, "measureMemory", measure_memory);
1369
1370
1401
  target->Set(context, env->constants_string(), constants).Check();
1371
1372
467
  env->SetMethod(target, "measureMemory", MeasureMemory);
1373
467
}
1374
1375
4779
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1376
4779
  ContextifyContext::RegisterExternalReferences(registry);
1377
4779
  ContextifyScript::RegisterExternalReferences(registry);
1378
4779
  MicrotaskQueueWrap::RegisterExternalReferences(registry);
1379
1380
4779
  registry->Register(StartSigintWatchdog);
1381
4779
  registry->Register(StopSigintWatchdog);
1382
4779
  registry->Register(WatchdogHasPendingSigint);
1383
4779
  registry->Register(MeasureMemory);
1384
4779
}
1385
}  // namespace contextify
1386
}  // namespace node
1387
1388
4837
NODE_MODULE_CONTEXT_AWARE_INTERNAL(contextify, node::contextify::Initialize)
1389

19314
NODE_MODULE_EXTERNAL_REFERENCE(contextify,
1390
                               node::contextify::RegisterExternalReferences)