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: 560 627 89.3 %
Date: 2020-07-19 22:14:24 Branches: 278 416 66.8 %

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::Integer;
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
597
ContextifyContext::ContextifyContext(
112
    Environment* env,
113
    Local<Object> sandbox_obj,
114
597
    const ContextOptions& options)
115
  : env_(env),
116
1194
    microtask_queue_wrap_(options.microtask_queue_wrap) {
117
597
  MaybeLocal<Context> v8_context = CreateV8Context(env, sandbox_obj, options);
118
119
  // Allocation failure, maximum call stack size reached, termination, etc.
120
597
  if (v8_context.IsEmpty()) return;
121
122
1194
  context_.Reset(env->isolate(), v8_context.ToLocalChecked());
123
597
  context_.SetWeak(this, WeakCallback, WeakCallbackType::kParameter);
124
597
  env->AddCleanupHook(CleanupHook, this);
125
}
126
127
128
1629
ContextifyContext::~ContextifyContext() {
129
543
  env()->RemoveCleanupHook(CleanupHook, this);
130
543
}
131
132
133
485
void ContextifyContext::CleanupHook(void* arg) {
134
485
  ContextifyContext* self = static_cast<ContextifyContext*>(arg);
135
485
  self->context_.Reset();
136
485
  delete self;
137
485
}
138
139
140
// This is an object that just keeps an internal pointer to this
141
// ContextifyContext.  It's passed to the NamedPropertyHandler.  If we
142
// pass the main JavaScript context object we're embedded in, then the
143
// NamedPropertyHandler will store a reference to it forever and keep it
144
// from getting gc'd.
145
597
MaybeLocal<Object> ContextifyContext::CreateDataWrapper(Environment* env) {
146
  Local<Object> wrapper;
147
1791
  if (!env->script_data_constructor_function()
148
1791
           ->NewInstance(env->context())
149
597
           .ToLocal(&wrapper)) {
150
    return MaybeLocal<Object>();
151
  }
152
153
597
  wrapper->SetAlignedPointerInInternalField(ContextifyContext::kSlot, this);
154
597
  return wrapper;
155
}
156
157
597
MaybeLocal<Context> ContextifyContext::CreateV8Context(
158
    Environment* env,
159
    Local<Object> sandbox_obj,
160
    const ContextOptions& options) {
161
597
  EscapableHandleScope scope(env->isolate());
162
  Local<FunctionTemplate> function_template =
163
597
      FunctionTemplate::New(env->isolate());
164
165
1194
  function_template->SetClassName(sandbox_obj->GetConstructorName());
166
167
  Local<ObjectTemplate> object_template =
168
597
      function_template->InstanceTemplate();
169
170
  Local<Object> data_wrapper;
171
1194
  if (!CreateDataWrapper(env).ToLocal(&data_wrapper))
172
    return MaybeLocal<Context>();
173
174
  NamedPropertyHandlerConfiguration config(
175
      PropertyGetterCallback,
176
      PropertySetterCallback,
177
      PropertyDescriptorCallback,
178
      PropertyDeleterCallback,
179
      PropertyEnumeratorCallback,
180
      PropertyDefinerCallback,
181
      data_wrapper,
182
597
      PropertyHandlerFlags::kHasNoSideEffect);
183
184
  IndexedPropertyHandlerConfiguration indexed_config(
185
      IndexedPropertyGetterCallback,
186
      IndexedPropertySetterCallback,
187
      IndexedPropertyDescriptorCallback,
188
      IndexedPropertyDeleterCallback,
189
      PropertyEnumeratorCallback,
190
      IndexedPropertyDefinerCallback,
191
      data_wrapper,
192
597
      PropertyHandlerFlags::kHasNoSideEffect);
193
194
597
  object_template->SetHandler(config);
195
597
  object_template->SetHandler(indexed_config);
196
  Local<Context> ctx = Context::New(
197
      env->isolate(),
198
      nullptr,  // extensions
199
      object_template,
200
      {},       // global object
201
      {},       // deserialization callback
202

1194
      microtask_queue() ? microtask_queue().get() : nullptr);
203
597
  if (ctx.IsEmpty()) return MaybeLocal<Context>();
204
  // Only partially initialize the context - the primordials are left out
205
  // and only initialized when necessary.
206
597
  InitializeContextRuntime(ctx);
207
208
597
  if (ctx.IsEmpty()) {
209
    return MaybeLocal<Context>();
210
  }
211
212
1791
  ctx->SetSecurityToken(env->context()->GetSecurityToken());
213
214
  // We need to tie the lifetime of the sandbox object with the lifetime of
215
  // newly created context. We do this by making them hold references to each
216
  // other. The context can directly hold a reference to the sandbox as an
217
  // embedder data field. However, we cannot hold a reference to a v8::Context
218
  // directly in an Object, we instead hold onto the new context's global
219
  // object instead (which then has a reference to the context).
220
597
  ctx->SetEmbedderData(ContextEmbedderIndex::kSandboxObject, sandbox_obj);
221
  sandbox_obj->SetPrivate(env->context(),
222
                          env->contextify_global_private_symbol(),
223
1791
                          ctx->Global());
224
225
1194
  Utf8Value name_val(env->isolate(), options.name);
226
1791
  ctx->AllowCodeGenerationFromStrings(options.allow_code_gen_strings->IsTrue());
227
1194
  ctx->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
228
597
                       options.allow_code_gen_wasm);
229
230
1194
  ContextInfo info(*name_val);
231
232
1194
  if (!options.origin.IsEmpty()) {
233
4
    Utf8Value origin_val(env->isolate(), options.origin);
234
2
    info.origin = *origin_val;
235
  }
236
237
597
  env->AssignToContext(ctx, info);
238
239
597
  return scope.Escape(ctx);
240
}
241
242
243
5273
void ContextifyContext::Init(Environment* env, Local<Object> target) {
244
  Local<FunctionTemplate> function_template =
245
5273
      FunctionTemplate::New(env->isolate());
246
15819
  function_template->InstanceTemplate()->SetInternalFieldCount(
247
5273
      ContextifyContext::kInternalFieldCount);
248
  env->set_script_data_constructor_function(
249
15819
      function_template->GetFunction(env->context()).ToLocalChecked());
250
251
5273
  env->SetMethod(target, "makeContext", MakeContext);
252
5273
  env->SetMethod(target, "isContext", IsContext);
253
5273
  env->SetMethod(target, "compileFunction", CompileFunction);
254
5273
}
255
256
257
// makeContext(sandbox, name, origin, strings, wasm);
258
597
void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
259
597
  Environment* env = Environment::GetCurrent(args);
260
261
597
  CHECK_EQ(args.Length(), 6);
262
1194
  CHECK(args[0]->IsObject());
263
1194
  Local<Object> sandbox = args[0].As<Object>();
264
265
  // Don't allow contextifying a sandbox multiple times.
266
1791
  CHECK(
267
      !sandbox->HasPrivate(
268
          env->context(),
269
          env->contextify_context_private_symbol()).FromJust());
270
271
1194
  ContextOptions options;
272
273
1791
  CHECK(args[1]->IsString());
274
1194
  options.name = args[1].As<String>();
275
276

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

2392
  if (args[5]->IsObject() &&
288

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

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

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

2690
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
430


5341
  if (!is_declared && args.ShouldThrowOnError() && is_contextual_store &&
431
65
      !is_function)
432
1
    return;
433
434

7997
  if (!is_declared_on_global_proxy && is_declared_on_sandbox  &&
435

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

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

15
  if (desc.has_get() || desc.has_set()) {
511
    PropertyDescriptor desc_for_sandbox(
512
10
        desc.has_get() ? desc.get() : Undefined(isolate).As<Value>(),
513

28
        desc.has_set() ? desc.set() : Undefined(isolate).As<Value>());
514
515
5
    define_prop_on_sandbox(&desc_for_sandbox);
516
  } else {
517
    Local<Value> value =
518
12
        desc.has_value() ? desc.value() : Undefined(isolate).As<Value>();
519
520
10
    if (desc.has_writable()) {
521
      PropertyDescriptor desc_for_sandbox(value, desc.writable());
522
      define_prop_on_sandbox(&desc_for_sandbox);
523
    } else {
524
20
      PropertyDescriptor desc_for_sandbox(value);
525
10
      define_prop_on_sandbox(&desc_for_sandbox);
526
    }
527
  }
528
}
529
530
// static
531
2
void ContextifyContext::PropertyDeleterCallback(
532
    Local<Name> property,
533
    const PropertyCallbackInfo<Boolean>& args) {
534
2
  ContextifyContext* ctx = ContextifyContext::Get(args);
535
536
  // Still initializing
537
4
  if (ctx->context_.IsEmpty())
538
1
    return;
539
540
4
  Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), property);
541
542
4
  if (success.FromMaybe(false))
543
1
    return;
544
545
  // Delete failed on the sandbox, intercept and do not delete on
546
  // the global object.
547
2
  args.GetReturnValue().Set(false);
548
}
549
550
// static
551
158
void ContextifyContext::PropertyEnumeratorCallback(
552
    const PropertyCallbackInfo<Array>& args) {
553
158
  ContextifyContext* ctx = ContextifyContext::Get(args);
554
555
  // Still initializing
556
316
  if (ctx->context_.IsEmpty())
557
    return;
558
559
  Local<Array> properties;
560
561
474
  if (!ctx->sandbox()->GetPropertyNames(ctx->context()).ToLocal(&properties))
562
    return;
563
564
316
  args.GetReturnValue().Set(properties);
565
}
566
567
// static
568
void ContextifyContext::IndexedPropertyGetterCallback(
569
    uint32_t index,
570
    const PropertyCallbackInfo<Value>& args) {
571
  ContextifyContext* ctx = ContextifyContext::Get(args);
572
573
  // Still initializing
574
  if (ctx->context_.IsEmpty())
575
    return;
576
577
  ContextifyContext::PropertyGetterCallback(
578
      Uint32ToName(ctx->context(), index), args);
579
}
580
581
582
1
void ContextifyContext::IndexedPropertySetterCallback(
583
    uint32_t index,
584
    Local<Value> value,
585
    const PropertyCallbackInfo<Value>& args) {
586
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
587
588
  // Still initializing
589
2
  if (ctx->context_.IsEmpty())
590
    return;
591
592
1
  ContextifyContext::PropertySetterCallback(
593
1
      Uint32ToName(ctx->context(), index), value, args);
594
}
595
596
// static
597
1
void ContextifyContext::IndexedPropertyDescriptorCallback(
598
    uint32_t index,
599
    const PropertyCallbackInfo<Value>& args) {
600
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
601
602
  // Still initializing
603
2
  if (ctx->context_.IsEmpty())
604
    return;
605
606
1
  ContextifyContext::PropertyDescriptorCallback(
607
1
      Uint32ToName(ctx->context(), index), args);
608
}
609
610
611
1
void ContextifyContext::IndexedPropertyDefinerCallback(
612
    uint32_t index,
613
    const PropertyDescriptor& desc,
614
    const PropertyCallbackInfo<Value>& args) {
615
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
616
617
  // Still initializing
618
2
  if (ctx->context_.IsEmpty())
619
    return;
620
621
1
  ContextifyContext::PropertyDefinerCallback(
622
1
      Uint32ToName(ctx->context(), index), desc, args);
623
}
624
625
// static
626
void ContextifyContext::IndexedPropertyDeleterCallback(
627
    uint32_t index,
628
    const PropertyCallbackInfo<Boolean>& args) {
629
  ContextifyContext* ctx = ContextifyContext::Get(args);
630
631
  // Still initializing
632
  if (ctx->context_.IsEmpty())
633
    return;
634
635
  Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), index);
636
637
  if (success.FromMaybe(false))
638
    return;
639
640
  // Delete failed on the sandbox, intercept and do not delete on
641
  // the global object.
642
  args.GetReturnValue().Set(false);
643
}
644
645
5273
void ContextifyScript::Init(Environment* env, Local<Object> target) {
646
10546
  HandleScope scope(env->isolate());
647
  Local<String> class_name =
648
5273
      FIXED_ONE_BYTE_STRING(env->isolate(), "ContextifyScript");
649
650
5273
  Local<FunctionTemplate> script_tmpl = env->NewFunctionTemplate(New);
651
15819
  script_tmpl->InstanceTemplate()->SetInternalFieldCount(
652
5273
      ContextifyScript::kInternalFieldCount);
653
5273
  script_tmpl->SetClassName(class_name);
654
5273
  env->SetProtoMethod(script_tmpl, "createCachedData", CreateCachedData);
655
5273
  env->SetProtoMethod(script_tmpl, "runInContext", RunInContext);
656
5273
  env->SetProtoMethod(script_tmpl, "runInThisContext", RunInThisContext);
657
658
10546
  target->Set(env->context(), class_name,
659
26365
      script_tmpl->GetFunction(env->context()).ToLocalChecked()).Check();
660
5273
  env->set_script_context_constructor_template(script_tmpl);
661
5273
}
662
663
1915
void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
664
1915
  Environment* env = Environment::GetCurrent(args);
665
1915
  Isolate* isolate = env->isolate();
666
1915
  Local<Context> context = env->context();
667
668
1916
  CHECK(args.IsConstructCall());
669
670
1916
  const int argc = args.Length();
671
1916
  CHECK_GE(argc, 2);
672
673
5748
  CHECK(args[0]->IsString());
674
3832
  Local<String> code = args[0].As<String>();
675
676
5748
  CHECK(args[1]->IsString());
677
3832
  Local<String> filename = args[1].As<String>();
678
679
  Local<Integer> line_offset;
680
  Local<Integer> column_offset;
681
  Local<ArrayBufferView> cached_data_buf;
682
1916
  bool produce_cached_data = false;
683
1916
  Local<Context> parsing_context = context;
684
685
1916
  if (argc > 2) {
686
    // new ContextifyScript(code, filename, lineOffset, columnOffset,
687
    //                      cachedData, produceCachedData, parsingContext)
688
1916
    CHECK_EQ(argc, 7);
689
3832
    CHECK(args[2]->IsNumber());
690
3832
    line_offset = args[2].As<Integer>();
691
3832
    CHECK(args[3]->IsNumber());
692
3832
    column_offset = args[3].As<Integer>();
693
5748
    if (!args[4]->IsUndefined()) {
694
46
      CHECK(args[4]->IsArrayBufferView());
695
46
      cached_data_buf = args[4].As<ArrayBufferView>();
696
    }
697
3832
    CHECK(args[5]->IsBoolean());
698
3832
    produce_cached_data = args[5]->IsTrue();
699
5745
    if (!args[6]->IsUndefined()) {
700
984
      CHECK(args[6]->IsObject());
701
      ContextifyContext* sandbox =
702
492
          ContextifyContext::ContextFromContextifiedSandbox(
703
1476
              env, args[6].As<Object>());
704
492
      CHECK_NOT_NULL(sandbox);
705
492
      parsing_context = sandbox->context();
706
    }
707
  } else {
708
    line_offset = Integer::New(isolate, 0);
709
    column_offset = Integer::New(isolate, 0);
710
  }
711
712
  ContextifyScript* contextify_script =
713
1916
      new ContextifyScript(env, args.This());
714
715
1916
  if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
716
          TRACING_CATEGORY_NODE2(vm, script)) != 0) {
717
14
    Utf8Value fn(isolate, filename);
718

14
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
719
        TRACING_CATEGORY_NODE2(vm, script),
720
        "ContextifyScript::New",
721
        contextify_script,
722
        "filename", TRACE_STR_COPY(*fn));
723
  }
724
725
1915
  ScriptCompiler::CachedData* cached_data = nullptr;
726
1915
  if (!cached_data_buf.IsEmpty()) {
727
    uint8_t* data = static_cast<uint8_t*>(
728
46
        cached_data_buf->Buffer()->GetBackingStore()->Data());
729
23
    cached_data = new ScriptCompiler::CachedData(
730
46
        data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
731
  }
732
733
  Local<PrimitiveArray> host_defined_options =
734
1915
      PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
735
5748
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kType,
736
1915
                            Number::New(isolate, loader::ScriptType::kScript));
737
5746
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kID,
738
3833
                            Number::New(isolate, contextify_script->id()));
739
740
  ScriptOrigin origin(filename,
741
                      line_offset,                          // line offset
742
                      column_offset,                        // column offset
743
                      True(isolate),                        // is cross origin
744
                      Local<Integer>(),                     // script id
745
                      Local<Value>(),                       // source map URL
746
                      False(isolate),                       // is opaque (?)
747
                      False(isolate),                       // is WASM
748
                      False(isolate),                       // is ES Module
749
1915
                      host_defined_options);
750
1737
  ScriptCompiler::Source source(code, origin, cached_data);
751
  ScriptCompiler::CompileOptions compile_options =
752
1915
      ScriptCompiler::kNoCompileOptions;
753
754
1915
  if (source.GetCachedData() != nullptr)
755
23
    compile_options = ScriptCompiler::kConsumeCodeCache;
756
757
3652
  TryCatchScope try_catch(env);
758
3654
  ShouldNotAbortOnUncaughtScope no_abort_scope(env);
759
1737
  Context::Scope scope(parsing_context);
760
761
  MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
762
      isolate,
763
      &source,
764
1916
      compile_options);
765
766
1915
  if (v8_script.IsEmpty()) {
767
180
    errors::DecorateErrorStack(env, try_catch);
768
180
    no_abort_scope.Close();
769
180
    if (!try_catch.HasTerminated())
770
180
      try_catch.ReThrow();
771

360
    TRACE_EVENT_NESTABLE_ASYNC_END0(
772
        TRACING_CATEGORY_NODE2(vm, script),
773
        "ContextifyScript::New",
774
        contextify_script);
775
180
    return;
776
  }
777
3468
  contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
778
779
1735
  if (compile_options == ScriptCompiler::kConsumeCodeCache) {
780
69
    args.This()->Set(
781
        env->context(),
782
        env->cached_data_rejected_string(),
783
115
        Boolean::New(isolate, source.GetCachedData()->rejected)).Check();
784
1712
  } else if (produce_cached_data) {
785
    std::unique_ptr<ScriptCompiler::CachedData> cached_data {
786
12
      ScriptCompiler::CreateCodeCache(v8_script.ToLocalChecked()) };
787
6
    bool cached_data_produced = cached_data != nullptr;
788
6
    if (cached_data_produced) {
789
      MaybeLocal<Object> buf = Buffer::Copy(
790
          env,
791
6
          reinterpret_cast<const char*>(cached_data->data),
792
12
          cached_data->length);
793
18
      args.This()->Set(env->context(),
794
                       env->cached_data_string(),
795
24
                       buf.ToLocalChecked()).Check();
796
    }
797
18
    args.This()->Set(
798
        env->context(),
799
        env->cached_data_produced_string(),
800
30
        Boolean::New(isolate, cached_data_produced)).Check();
801
  }
802

3472
  TRACE_EVENT_NESTABLE_ASYNC_END0(
803
      TRACING_CATEGORY_NODE2(vm, script),
804
      "ContextifyScript::New",
805
      contextify_script);
806
}
807
808
1710
bool ContextifyScript::InstanceOf(Environment* env,
809
                                  const Local<Value>& value) {
810

3422
  return !value.IsEmpty() &&
811
5132
         env->script_context_constructor_template()->HasInstance(value);
812
}
813
814
11
void ContextifyScript::CreateCachedData(
815
    const FunctionCallbackInfo<Value>& args) {
816
11
  Environment* env = Environment::GetCurrent(args);
817
  ContextifyScript* wrapped_script;
818
11
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
819
  Local<UnboundScript> unbound_script =
820
11
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
821
  std::unique_ptr<ScriptCompiler::CachedData> cached_data(
822
22
      ScriptCompiler::CreateCodeCache(unbound_script));
823
11
  if (!cached_data) {
824
    args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked());
825
  } else {
826
    MaybeLocal<Object> buf = Buffer::Copy(
827
        env,
828
11
        reinterpret_cast<const char*>(cached_data->data),
829
22
        cached_data->length);
830
22
    args.GetReturnValue().Set(buf.ToLocalChecked());
831
  }
832
}
833
834
902
void ContextifyScript::RunInThisContext(
835
    const FunctionCallbackInfo<Value>& args) {
836
902
  Environment* env = Environment::GetCurrent(args);
837
838
  ContextifyScript* wrapped_script;
839
903
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
840
841

1804
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
842
      TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script);
843
844
  // TODO(addaleax): Use an options object or otherwise merge this with
845
  // RunInContext().
846
902
  CHECK_EQ(args.Length(), 4);
847
848
1804
  CHECK(args[0]->IsNumber());
849
3610
  int64_t timeout = args[0]->IntegerValue(env->context()).FromJust();
850
851
1804
  CHECK(args[1]->IsBoolean());
852
1806
  bool display_errors = args[1]->IsTrue();
853
854
1804
  CHECK(args[2]->IsBoolean());
855
1806
  bool break_on_sigint = args[2]->IsTrue();
856
857
1806
  CHECK(args[3]->IsBoolean());
858
1804
  bool break_on_first_line = args[3]->IsTrue();
859
860
  // Do the eval within this context
861
1788
  EvalMachine(env,
862
              timeout,
863
              display_errors,
864
              break_on_sigint,
865
              break_on_first_line,
866
              nullptr,  // microtask_queue
867
903
              args);
868
869

1774
  TRACE_EVENT_NESTABLE_ASYNC_END0(
870
      TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script);
871
}
872
873
809
void ContextifyScript::RunInContext(const FunctionCallbackInfo<Value>& args) {
874
809
  Environment* env = Environment::GetCurrent(args);
875
876
  ContextifyScript* wrapped_script;
877
809
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
878
879
809
  CHECK_EQ(args.Length(), 5);
880
881
1618
  CHECK(args[0]->IsObject());
882
1618
  Local<Object> sandbox = args[0].As<Object>();
883
  // Get the context from the sandbox
884
  ContextifyContext* contextify_context =
885
809
      ContextifyContext::ContextFromContextifiedSandbox(env, sandbox);
886
809
  CHECK_NOT_NULL(contextify_context);
887
888
1618
  if (contextify_context->context().IsEmpty())
889
    return;
890
891

1618
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
892
      TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script);
893
894
1618
  CHECK(args[1]->IsNumber());
895
3236
  int64_t timeout = args[1]->IntegerValue(env->context()).FromJust();
896
897
1618
  CHECK(args[2]->IsBoolean());
898
1618
  bool display_errors = args[2]->IsTrue();
899
900
1618
  CHECK(args[3]->IsBoolean());
901
1618
  bool break_on_sigint = args[3]->IsTrue();
902
903
1618
  CHECK(args[4]->IsBoolean());
904
1618
  bool break_on_first_line = args[4]->IsTrue();
905
906
  // Do the eval within the context
907
809
  Context::Scope context_scope(contextify_context->context());
908
809
  EvalMachine(contextify_context->env(),
909
              timeout,
910
              display_errors,
911
              break_on_sigint,
912
              break_on_first_line,
913
1618
              contextify_context->microtask_queue(),
914
809
              args);
915
916

1618
  TRACE_EVENT_NESTABLE_ASYNC_END0(
917
      TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script);
918
}
919
920
1710
bool ContextifyScript::EvalMachine(Environment* env,
921
                                   const int64_t timeout,
922
                                   const bool display_errors,
923
                                   const bool break_on_sigint,
924
                                   const bool break_on_first_line,
925
                                   std::shared_ptr<MicrotaskQueue> mtask_queue,
926
                                   const FunctionCallbackInfo<Value>& args) {
927
1710
  if (!env->can_call_into_js())
928
    return false;
929
1710
  if (!ContextifyScript::InstanceOf(env, args.Holder())) {
930
    env->ThrowTypeError(
931
        "Script methods can only be called on script instances.");
932
    return false;
933
  }
934
3407
  TryCatchScope try_catch(env);
935
  ContextifyScript* wrapped_script;
936
1710
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder(), false);
937
  Local<UnboundScript> unbound_script =
938
1712
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
939
1712
  Local<Script> script = unbound_script->BindToCurrentContext();
940
941
#if HAVE_INSPECTOR
942
1710
  if (break_on_first_line) {
943
10
    env->inspector_agent()->PauseOnNextJavascriptStatement("Break on start");
944
  }
945
#endif
946
947
  MaybeLocal<Value> result;
948
1710
  bool timed_out = false;
949
1710
  bool received_signal = false;
950
1710
  auto run = [&]() {
951
3423
    MaybeLocal<Value> result = script->Run(env->context());
952

1696
    if (!result.IsEmpty() && mtask_queue)
953
2
      mtask_queue->PerformCheckpoint(env->isolate());
954
1695
    return result;
955
1710
  };
956

1710
  if (break_on_sigint && timeout != -1) {
957
    Watchdog wd(env->isolate(), timeout, &timed_out);
958
    SigintWatchdog swd(env->isolate(), &received_signal);
959
    result = run();
960
1710
  } else if (break_on_sigint) {
961
230
    SigintWatchdog swd(env->isolate(), &received_signal);
962
116
    result = run();
963
1594
  } else if (timeout != -1) {
964
30
    Watchdog wd(env->isolate(), timeout, &timed_out);
965
15
    result = run();
966
  } else {
967
1579
    result = run();
968
  }
969
970
  // Convert the termination exception into a regular exception.
971

1695
  if (timed_out || received_signal) {
972

20
    if (!env->is_main_thread() && env->is_stopping())
973
      return false;
974
20
    env->isolate()->CancelTerminateExecution();
975
    // It is possible that execution was terminated by another timeout in
976
    // which this timeout is nested, so check whether one of the watchdogs
977
    // from this invocation is responsible for termination.
978
20
    if (timed_out) {
979
10
      node::THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout);
980
10
    } else if (received_signal) {
981
10
      node::THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env);
982
    }
983
  }
984
985
1695
  if (try_catch.HasCaught()) {
986

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

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

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