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: 588 654 89.9 %
Date: 2021-05-01 04:12:26 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 "memory_tracker-inl.h"
25
#include "node_internals.h"
26
#include "node_watchdog.h"
27
#include "base_object-inl.h"
28
#include "node_context_data.h"
29
#include "node_errors.h"
30
#include "module_wrap.h"
31
#include "util-inl.h"
32
33
namespace node {
34
namespace contextify {
35
36
using errors::TryCatchScope;
37
38
using v8::Array;
39
using v8::ArrayBufferView;
40
using v8::Boolean;
41
using v8::Context;
42
using v8::EscapableHandleScope;
43
using v8::External;
44
using v8::Function;
45
using v8::FunctionCallbackInfo;
46
using v8::FunctionTemplate;
47
using v8::HandleScope;
48
using v8::IndexedPropertyHandlerConfiguration;
49
using v8::Int32;
50
using v8::Isolate;
51
using v8::Local;
52
using v8::Maybe;
53
using v8::MaybeLocal;
54
using v8::MeasureMemoryExecution;
55
using v8::MeasureMemoryMode;
56
using v8::MicrotaskQueue;
57
using v8::MicrotasksPolicy;
58
using v8::Name;
59
using v8::NamedPropertyHandlerConfiguration;
60
using v8::Number;
61
using v8::Object;
62
using v8::ObjectTemplate;
63
using v8::PrimitiveArray;
64
using v8::Promise;
65
using v8::PropertyAttribute;
66
using v8::PropertyCallbackInfo;
67
using v8::PropertyDescriptor;
68
using v8::PropertyHandlerFlags;
69
using v8::Script;
70
using v8::ScriptCompiler;
71
using v8::ScriptOrigin;
72
using v8::ScriptOrModule;
73
using v8::String;
74
using v8::Uint32;
75
using v8::UnboundScript;
76
using v8::Value;
77
using v8::WeakCallbackInfo;
78
using v8::WeakCallbackType;
79
80
// The vm module executes code in a sandboxed environment with a different
81
// global object than the rest of the code. This is achieved by applying
82
// every call that changes or queries a property on the global `this` in the
83
// sandboxed code, to the sandbox object.
84
//
85
// The implementation uses V8's interceptors for methods like `set`, `get`,
86
// `delete`, `defineProperty`, and for any query of the property attributes.
87
// Property handlers with interceptors are set on the object template for
88
// the sandboxed code. Handlers for both named properties and for indexed
89
// properties are used. Their functionality is almost identical, the indexed
90
// interceptors mostly just call the named interceptors.
91
//
92
// For every `get` of a global property in the sandboxed context, the
93
// interceptor callback checks the sandbox object for the property.
94
// If the property is defined on the sandbox, that result is returned to
95
// the original call instead of finishing the query on the global object.
96
//
97
// For every `set` of a global property, the interceptor callback defines or
98
// changes the property both on the sandbox and the global proxy.
99
100
namespace {
101
102
// Convert an int to a V8 Name (String or Symbol).
103
3
Local<Name> Uint32ToName(Local<Context> context, uint32_t index) {
104
12
  return Uint32::New(context->GetIsolate(), index)->ToString(context)
105
6
      .ToLocalChecked();
106
}
107
108
}  // anonymous namespace
109
110
597
ContextifyContext::ContextifyContext(
111
    Environment* env,
112
    Local<Object> sandbox_obj,
113
597
    const ContextOptions& options)
114
  : env_(env),
115
1194
    microtask_queue_wrap_(options.microtask_queue_wrap) {
116
597
  MaybeLocal<Context> v8_context = CreateV8Context(env, sandbox_obj, options);
117
118
  // Allocation failure, maximum call stack size reached, termination, etc.
119
597
  if (v8_context.IsEmpty()) return;
120
121
1194
  context_.Reset(env->isolate(), v8_context.ToLocalChecked());
122
597
  context_.SetWeak(this, WeakCallback, WeakCallbackType::kParameter);
123
597
  env->AddCleanupHook(CleanupHook, this);
124
}
125
126
127
1509
ContextifyContext::~ContextifyContext() {
128
503
  env()->RemoveCleanupHook(CleanupHook, this);
129
503
}
130
131
132
444
void ContextifyContext::CleanupHook(void* arg) {
133
444
  ContextifyContext* self = static_cast<ContextifyContext*>(arg);
134
444
  self->context_.Reset();
135
444
  delete self;
136
444
}
137
138
139
// This is an object that just keeps an internal pointer to this
140
// ContextifyContext.  It's passed to the NamedPropertyHandler.  If we
141
// pass the main JavaScript context object we're embedded in, then the
142
// NamedPropertyHandler will store a reference to it forever and keep it
143
// from getting gc'd.
144
597
MaybeLocal<Object> ContextifyContext::CreateDataWrapper(Environment* env) {
145
  Local<Object> wrapper;
146
1791
  if (!env->script_data_constructor_function()
147
1791
           ->NewInstance(env->context())
148
597
           .ToLocal(&wrapper)) {
149
    return MaybeLocal<Object>();
150
  }
151
152
597
  wrapper->SetAlignedPointerInInternalField(ContextifyContext::kSlot, this);
153
597
  return wrapper;
154
}
155
156
597
MaybeLocal<Context> ContextifyContext::CreateV8Context(
157
    Environment* env,
158
    Local<Object> sandbox_obj,
159
    const ContextOptions& options) {
160
597
  EscapableHandleScope scope(env->isolate());
161
  Local<FunctionTemplate> function_template =
162
597
      FunctionTemplate::New(env->isolate());
163
164
1194
  function_template->SetClassName(sandbox_obj->GetConstructorName());
165
166
  Local<ObjectTemplate> object_template =
167
597
      function_template->InstanceTemplate();
168
169
  Local<Object> data_wrapper;
170
1194
  if (!CreateDataWrapper(env).ToLocal(&data_wrapper))
171
    return MaybeLocal<Context>();
172
173
  NamedPropertyHandlerConfiguration config(
174
      PropertyGetterCallback,
175
      PropertySetterCallback,
176
      PropertyDescriptorCallback,
177
      PropertyDeleterCallback,
178
      PropertyEnumeratorCallback,
179
      PropertyDefinerCallback,
180
      data_wrapper,
181
597
      PropertyHandlerFlags::kHasNoSideEffect);
182
183
  IndexedPropertyHandlerConfiguration indexed_config(
184
      IndexedPropertyGetterCallback,
185
      IndexedPropertySetterCallback,
186
      IndexedPropertyDescriptorCallback,
187
      IndexedPropertyDeleterCallback,
188
      PropertyEnumeratorCallback,
189
      IndexedPropertyDefinerCallback,
190
      data_wrapper,
191
597
      PropertyHandlerFlags::kHasNoSideEffect);
192
193
597
  object_template->SetHandler(config);
194
597
  object_template->SetHandler(indexed_config);
195
  Local<Context> ctx = Context::New(
196
      env->isolate(),
197
      nullptr,  // extensions
198
      object_template,
199
      {},       // global object
200
      {},       // deserialization callback
201
1194
      microtask_queue() ?
202
602
          microtask_queue().get() :
203
1791
          env->isolate()->GetCurrentContext()->GetMicrotaskQueue());
204
597
  if (ctx.IsEmpty()) return MaybeLocal<Context>();
205
  // Only partially initialize the context - the primordials are left out
206
  // and only initialized when necessary.
207
597
  InitializeContextRuntime(ctx);
208
209
597
  if (ctx.IsEmpty()) {
210
    return MaybeLocal<Context>();
211
  }
212
213
597
  Local<Context> context = env->context();
214
1194
  ctx->SetSecurityToken(context->GetSecurityToken());
215
216
  // We need to tie the lifetime of the sandbox object with the lifetime of
217
  // newly created context. We do this by making them hold references to each
218
  // other. The context can directly hold a reference to the sandbox as an
219
  // embedder data field. However, we cannot hold a reference to a v8::Context
220
  // directly in an Object, we instead hold onto the new context's global
221
  // object instead (which then has a reference to the context).
222
597
  ctx->SetEmbedderData(ContextEmbedderIndex::kSandboxObject, sandbox_obj);
223
  sandbox_obj->SetPrivate(context,
224
                          env->contextify_global_private_symbol(),
225
1791
                          ctx->Global());
226
227
1194
  Utf8Value name_val(env->isolate(), options.name);
228
1791
  ctx->AllowCodeGenerationFromStrings(options.allow_code_gen_strings->IsTrue());
229
1194
  ctx->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
230
597
                       options.allow_code_gen_wasm);
231
232
1194
  ContextInfo info(*name_val);
233
234
1194
  if (!options.origin.IsEmpty()) {
235
4
    Utf8Value origin_val(env->isolate(), options.origin);
236
2
    info.origin = *origin_val;
237
  }
238
239
597
  env->AssignToContext(ctx, info);
240
241
597
  return scope.Escape(ctx);
242
}
243
244
245
5191
void ContextifyContext::Init(Environment* env, Local<Object> target) {
246
  Local<FunctionTemplate> function_template =
247
5191
      FunctionTemplate::New(env->isolate());
248
15573
  function_template->InstanceTemplate()->SetInternalFieldCount(
249
5191
      ContextifyContext::kInternalFieldCount);
250
  env->set_script_data_constructor_function(
251
15573
      function_template->GetFunction(env->context()).ToLocalChecked());
252
253
5191
  env->SetMethod(target, "makeContext", MakeContext);
254
5191
  env->SetMethod(target, "isContext", IsContext);
255
5191
  env->SetMethod(target, "compileFunction", CompileFunction);
256
5191
}
257
258
259
// makeContext(sandbox, name, origin, strings, wasm);
260
597
void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
261
597
  Environment* env = Environment::GetCurrent(args);
262
263
597
  CHECK_EQ(args.Length(), 6);
264
1194
  CHECK(args[0]->IsObject());
265
1194
  Local<Object> sandbox = args[0].As<Object>();
266
267
  // Don't allow contextifying a sandbox multiple times.
268
1791
  CHECK(
269
      !sandbox->HasPrivate(
270
          env->context(),
271
          env->contextify_context_private_symbol()).FromJust());
272
273
1194
  ContextOptions options;
274
275
1791
  CHECK(args[1]->IsString());
276
1194
  options.name = args[1].As<String>();
277
278

3576
  CHECK(args[2]->IsString() || args[2]->IsUndefined());
279
1791
  if (args[2]->IsString()) {
280
4
    options.origin = args[2].As<String>();
281
  }
282
283
1194
  CHECK(args[3]->IsBoolean());
284
1194
  options.allow_code_gen_strings = args[3].As<Boolean>();
285
286
1194
  CHECK(args[4]->IsBoolean());
287
1194
  options.allow_code_gen_wasm = args[4].As<Boolean>();
288
289

2393
  if (args[5]->IsObject() &&
290

1204
      !env->microtask_queue_ctor_template().IsEmpty() &&
291
607
      env->microtask_queue_ctor_template()->HasInstance(args[5])) {
292
10
    options.microtask_queue_wrap.reset(
293
15
        Unwrap<MicrotaskQueueWrap>(args[5].As<Object>()));
294
  }
295
296
1194
  TryCatchScope try_catch(env);
297
1194
  auto context_ptr = std::make_unique<ContextifyContext>(env, sandbox, options);
298
299
597
  if (try_catch.HasCaught()) {
300
    if (!try_catch.HasTerminated())
301
      try_catch.ReThrow();
302
    return;
303
  }
304
305
1194
  if (context_ptr->context().IsEmpty())
306
    return;
307
308
  sandbox->SetPrivate(
309
      env->context(),
310
      env->contextify_context_private_symbol(),
311
1791
      External::New(env->isolate(), context_ptr.release()));
312
}
313
314
315
1943
void ContextifyContext::IsContext(const FunctionCallbackInfo<Value>& args) {
316
1943
  Environment* env = Environment::GetCurrent(args);
317
318
3886
  CHECK(args[0]->IsObject());
319
3886
  Local<Object> sandbox = args[0].As<Object>();
320
321
  Maybe<bool> result =
322
      sandbox->HasPrivate(env->context(),
323
3886
                          env->contextify_context_private_symbol());
324
5829
  args.GetReturnValue().Set(result.FromJust());
325
1943
}
326
327
328
59
void ContextifyContext::WeakCallback(
329
    const WeakCallbackInfo<ContextifyContext>& data) {
330
59
  ContextifyContext* context = data.GetParameter();
331
59
  delete context;
332
59
}
333
334
// static
335
1288
ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox(
336
    Environment* env,
337
    const Local<Object>& sandbox) {
338
  MaybeLocal<Value> maybe_value =
339
      sandbox->GetPrivate(env->context(),
340
2576
                          env->contextify_context_private_symbol());
341
  Local<Value> context_external_v;
342

2576
  if (maybe_value.ToLocal(&context_external_v) &&
343
1288
      context_external_v->IsExternal()) {
344
1288
    Local<External> context_external = context_external_v.As<External>();
345
1288
    return static_cast<ContextifyContext*>(context_external->Value());
346
  }
347
  return nullptr;
348
}
349
350
// static
351
template <typename T>
352
1043170
ContextifyContext* ContextifyContext::Get(const PropertyCallbackInfo<T>& args) {
353
1043170
  Local<Value> data = args.Data();
354
  return static_cast<ContextifyContext*>(
355
3129510
      data.As<Object>()->GetAlignedPointerFromInternalField(
356
2086340
          ContextifyContext::kSlot));
357
}
358
359
// static
360
1042711
void ContextifyContext::PropertyGetterCallback(
361
    Local<Name> property,
362
    const PropertyCallbackInfo<Value>& args) {
363
1042711
  ContextifyContext* ctx = ContextifyContext::Get(args);
364
365
  // Still initializing
366
2085422
  if (ctx->context_.IsEmpty())
367
1791
    return;
368
369
1040920
  Local<Context> context = ctx->context();
370
1040920
  Local<Object> sandbox = ctx->sandbox();
371
  MaybeLocal<Value> maybe_rv =
372
1040920
      sandbox->GetRealNamedProperty(context, property);
373
1040920
  if (maybe_rv.IsEmpty()) {
374
    maybe_rv =
375
75016
        ctx->global_proxy()->GetRealNamedProperty(context, property);
376
  }
377
378
  Local<Value> rv;
379
1040920
  if (maybe_rv.ToLocal(&rv)) {
380
1040851
    if (rv == sandbox)
381
10
      rv = ctx->global_proxy();
382
383
2081702
    args.GetReturnValue().Set(rv);
384
  }
385
}
386
387
// static
388
158
void ContextifyContext::PropertySetterCallback(
389
    Local<Name> property,
390
    Local<Value> value,
391
    const PropertyCallbackInfo<Value>& args) {
392
158
  ContextifyContext* ctx = ContextifyContext::Get(args);
393
394
  // Still initializing
395
316
  if (ctx->context_.IsEmpty())
396
14
    return;
397
398
158
  Local<Context> context = ctx->context();
399
158
  auto attributes = PropertyAttribute::None;
400
316
  bool is_declared_on_global_proxy = ctx->global_proxy()
401
316
      ->GetRealNamedPropertyAttributes(context, property)
402
158
      .To(&attributes);
403
  bool read_only =
404
158
      static_cast<int>(attributes) &
405
158
      static_cast<int>(PropertyAttribute::ReadOnly);
406
407
316
  bool is_declared_on_sandbox = ctx->sandbox()
408
316
      ->GetRealNamedPropertyAttributes(context, property)
409
158
      .To(&attributes);
410

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

145
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
433


249
  if (!is_declared && args.ShouldThrowOnError() && is_contextual_store &&
434
29
      !is_function)
435
1
    return;
436
437

396
  if (!is_declared_on_global_proxy && is_declared_on_sandbox  &&
438

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

15
  if (is_declared && read_only)
497
    return;
498
499
15
  Local<Object> sandbox = ctx->sandbox();
500
501
  auto define_prop_on_sandbox =
502
15
      [&] (PropertyDescriptor* desc_for_sandbox) {
503
31
        if (desc.has_enumerable()) {
504
2
          desc_for_sandbox->set_enumerable(desc.enumerable());
505
        }
506
15
        if (desc.has_configurable()) {
507
1
          desc_for_sandbox->set_configurable(desc.configurable());
508
        }
509
        // Set the property on the sandbox.
510
30
        USE(sandbox->DefineProperty(context, property, *desc_for_sandbox));
511
30
      };
512
513

15
  if (desc.has_get() || desc.has_set()) {
514
    PropertyDescriptor desc_for_sandbox(
515
10
        desc.has_get() ? desc.get() : Undefined(isolate).As<Value>(),
516

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

3910
  return !value.IsEmpty() &&
815
5844
         env->script_context_constructor_template()->HasInstance(value);
816
}
817
818
11
void ContextifyScript::CreateCachedData(
819
    const FunctionCallbackInfo<Value>& args) {
820
11
  Environment* env = Environment::GetCurrent(args);
821
  ContextifyScript* wrapped_script;
822
11
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
823
  Local<UnboundScript> unbound_script =
824
11
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
825
  std::unique_ptr<ScriptCompiler::CachedData> cached_data(
826
22
      ScriptCompiler::CreateCodeCache(unbound_script));
827
11
  if (!cached_data) {
828
    args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked());
829
  } else {
830
    MaybeLocal<Object> buf = Buffer::Copy(
831
        env,
832
11
        reinterpret_cast<const char*>(cached_data->data),
833
22
        cached_data->length);
834
22
    args.GetReturnValue().Set(buf.ToLocalChecked());
835
  }
836
}
837
838
1151
void ContextifyScript::RunInThisContext(
839
    const FunctionCallbackInfo<Value>& args) {
840
1151
  Environment* env = Environment::GetCurrent(args);
841
842
  ContextifyScript* wrapped_script;
843
1151
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
844
845
1151
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
846
      TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script);
847
848
442
  // TODO(addaleax): Use an options object or otherwise merge this with
849
1151
  // RunInContext().
850
1151
  CHECK_EQ(args.Length(), 4);
851
6
852
2314
  CHECK(args[0]->IsNumber());
853
4616
  int64_t timeout = args[0]->IntegerValue(env->context()).FromJust();
854
855
2302
  CHECK(args[1]->IsBoolean());
856
2302
  bool display_errors = args[1]->IsTrue();
857
858
2302
  CHECK(args[2]->IsBoolean());
859
2302
  bool break_on_sigint = args[2]->IsTrue();
860
861
2302
  CHECK(args[3]->IsBoolean());
862
2302
  bool break_on_first_line = args[3]->IsTrue();
863
864
  // Do the eval within this context
865
2286
  EvalMachine(env,
866
              timeout,
867
              display_errors,
868
              break_on_sigint,
869
              break_on_first_line,
870
              nullptr,  // microtask_queue
871
1151
              args);
872
873
1135
  TRACE_EVENT_NESTABLE_ASYNC_END0(
874
      TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script);
875
}
876
429
877
1932
void ContextifyScript::RunInContext(const FunctionCallbackInfo<Value>& args) {
878
797
  Environment* env = Environment::GetCurrent(args);
879
5
880
10
  ContextifyScript* wrapped_script;
881
807
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
882
883
797
  CHECK_EQ(args.Length(), 5);
884
885
1594
  CHECK(args[0]->IsObject());
886
1594
  Local<Object> sandbox = args[0].As<Object>();
887
  // Get the context from the sandbox
888
  ContextifyContext* contextify_context =
889
797
      ContextifyContext::ContextFromContextifiedSandbox(env, sandbox);
890
797
  CHECK_NOT_NULL(contextify_context);
891
892
797
  Local<Context> context = contextify_context->context();
893
797
  if (context.IsEmpty())
894
    return;
895
896
797
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
897
      TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script);
898
899
1594
  CHECK(args[1]->IsNumber());
900
3985
  int64_t timeout = args[1]->IntegerValue(env->context()).FromJust();
901
902
1595
  CHECK(args[2]->IsBoolean());
903
1596
  bool display_errors = args[2]->IsTrue();
904
2
905
1594
  CHECK(args[3]->IsBoolean());
906
1594
  bool break_on_sigint = args[3]->IsTrue();
907
908
1594
  CHECK(args[4]->IsBoolean());
909
1594
  bool break_on_first_line = args[4]->IsTrue();
910
911
  // Do the eval within the context
912
  Context::Scope context_scope(context);
913
797
  EvalMachine(contextify_context->env(),
914
              timeout,
915
              display_errors,
916
              break_on_sigint,
917
              break_on_first_line,
918
1594
              contextify_context->microtask_queue(),
919
797
              args);
920
921
797
  TRACE_EVENT_NESTABLE_ASYNC_END0(
922
      TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script);
923
}
924
213
925
2745
bool ContextifyScript::EvalMachine(Environment* env,
926
                                   const int64_t timeout,
927
1
                                   const bool display_errors,
928
2
                                   const bool break_on_sigint,
929
2
                                   const bool break_on_first_line,
930
                                   std::shared_ptr<MicrotaskQueue> mtask_queue,
931
                                   const FunctionCallbackInfo<Value>& args) {
932
1948
  if (!env->can_call_into_js())
933
    return false;
934
1948
  if (!ContextifyScript::InstanceOf(env, args.Holder())) {
935
    THROW_ERR_INVALID_THIS(
936
        env,
937
        "Script methods can only be called on script instances.");
938
    return false;
939
  }
940
3880
  TryCatchScope try_catch(env);
941
3880
  Isolate::SafeForTerminationScope safe_for_termination(env->isolate());
942
  ContextifyScript* wrapped_script;
943
1948
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder(), false);
944
  Local<UnboundScript> unbound_script =
945
1948
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
946
1948
  Local<Script> script = unbound_script->BindToCurrentContext();
947
948
#if HAVE_INSPECTOR
949
1948
  if (break_on_first_line) {
950
10
    env->inspector_agent()->PauseOnNextJavascriptStatement("Break on start");
951
  }
952
#endif
953
954
  MaybeLocal<Value> result;
955
1948
  bool timed_out = false;
956
1948
  bool received_signal = false;
957
1948
  auto run = [&]() {
958
3898
    MaybeLocal<Value> result = script->Run(env->context());
959

1932
    if (!result.IsEmpty() && mtask_queue)
960
4
      mtask_queue->PerformCheckpoint(env->isolate());
961
1932
    return result;
962
1948
  };
963

1948
  if (break_on_sigint && timeout != -1) {
964
    Watchdog wd(env->isolate(), timeout, &timed_out);
965
    SigintWatchdog swd(env->isolate(), &received_signal);
966
    result = run();
967
1948
  } else if (break_on_sigint) {
968
369
    SigintWatchdog swd(env->isolate(), &received_signal);
969
186
    result = run();
970
1762
  } else if (timeout != -1) {
971
30
    Watchdog wd(env->isolate(), timeout, &timed_out);
972
15
    result = run();
973
  } else {
974
1747
    result = run();
975
  }
976
977
  // Convert the termination exception into a regular exception.
978

1932
  if (timed_out || received_signal) {
979

21
    if (!env->is_main_thread() && env->is_stopping())
980
      return false;
981
21
    env->isolate()->CancelTerminateExecution();
982
    // It is possible that execution was terminated by another timeout in
983
    // which this timeout is nested, so check whether one of the watchdogs
984
    // from this invocation is responsible for termination.
985
21
    if (timed_out) {
986
10
      node::THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout);
987
11
    } else if (received_signal) {
988
11
      node::THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env);
989
    }
990
  }
991
992
1932
  if (try_catch.HasCaught()) {
993

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

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

19308
NODE_MODULE_CONTEXT_AWARE_INTERNAL(contextify, node::contextify::Initialize)