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: 584 650 89.8 %
Date: 2021-04-19 04:11:46 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
543
ContextifyContext::ContextifyContext(
111
    Environment* env,
112
    Local<Object> sandbox_obj,
113
543
    const ContextOptions& options)
114
  : env_(env),
115
1086
    microtask_queue_wrap_(options.microtask_queue_wrap) {
116
543
  MaybeLocal<Context> v8_context = CreateV8Context(env, sandbox_obj, options);
117
118
  // Allocation failure, maximum call stack size reached, termination, etc.
119
543
  if (v8_context.IsEmpty()) return;
120
121
1086
  context_.Reset(env->isolate(), v8_context.ToLocalChecked());
122
543
  context_.SetWeak(this, WeakCallback, WeakCallbackType::kParameter);
123
543
  env->AddCleanupHook(CleanupHook, this);
124
}
125
126
127
1491
ContextifyContext::~ContextifyContext() {
128
497
  env()->RemoveCleanupHook(CleanupHook, this);
129
497
}
130
131
132
439
void ContextifyContext::CleanupHook(void* arg) {
133
439
  ContextifyContext* self = static_cast<ContextifyContext*>(arg);
134
439
  self->context_.Reset();
135
439
  delete self;
136
439
}
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
543
MaybeLocal<Object> ContextifyContext::CreateDataWrapper(Environment* env) {
145
  Local<Object> wrapper;
146
1629
  if (!env->script_data_constructor_function()
147
1629
           ->NewInstance(env->context())
148
543
           .ToLocal(&wrapper)) {
149
    return MaybeLocal<Object>();
150
  }
151
152
543
  wrapper->SetAlignedPointerInInternalField(ContextifyContext::kSlot, this);
153
543
  return wrapper;
154
}
155
156
543
MaybeLocal<Context> ContextifyContext::CreateV8Context(
157
    Environment* env,
158
    Local<Object> sandbox_obj,
159
    const ContextOptions& options) {
160
543
  EscapableHandleScope scope(env->isolate());
161
  Local<FunctionTemplate> function_template =
162
543
      FunctionTemplate::New(env->isolate());
163
164
1086
  function_template->SetClassName(sandbox_obj->GetConstructorName());
165
166
  Local<ObjectTemplate> object_template =
167
543
      function_template->InstanceTemplate();
168
169
  Local<Object> data_wrapper;
170
1086
  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
543
      PropertyHandlerFlags::kHasNoSideEffect);
182
183
  IndexedPropertyHandlerConfiguration indexed_config(
184
      IndexedPropertyGetterCallback,
185
      IndexedPropertySetterCallback,
186
      IndexedPropertyDescriptorCallback,
187
      IndexedPropertyDeleterCallback,
188
      PropertyEnumeratorCallback,
189
      IndexedPropertyDefinerCallback,
190
      data_wrapper,
191
543
      PropertyHandlerFlags::kHasNoSideEffect);
192
193
543
  object_template->SetHandler(config);
194
543
  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
1086
      microtask_queue() ?
202
548
          microtask_queue().get() :
203
1629
          env->isolate()->GetCurrentContext()->GetMicrotaskQueue());
204
543
  if (ctx.IsEmpty()) return MaybeLocal<Context>();
205
  // Only partially initialize the context - the primordials are left out
206
  // and only initialized when necessary.
207
543
  InitializeContextRuntime(ctx);
208
209
543
  if (ctx.IsEmpty()) {
210
    return MaybeLocal<Context>();
211
  }
212
213
1629
  ctx->SetSecurityToken(env->context()->GetSecurityToken());
214
215
  // We need to tie the lifetime of the sandbox object with the lifetime of
216
  // newly created context. We do this by making them hold references to each
217
  // other. The context can directly hold a reference to the sandbox as an
218
  // embedder data field. However, we cannot hold a reference to a v8::Context
219
  // directly in an Object, we instead hold onto the new context's global
220
  // object instead (which then has a reference to the context).
221
543
  ctx->SetEmbedderData(ContextEmbedderIndex::kSandboxObject, sandbox_obj);
222
  sandbox_obj->SetPrivate(env->context(),
223
                          env->contextify_global_private_symbol(),
224
1629
                          ctx->Global());
225
226
1086
  Utf8Value name_val(env->isolate(), options.name);
227
1629
  ctx->AllowCodeGenerationFromStrings(options.allow_code_gen_strings->IsTrue());
228
1086
  ctx->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
229
543
                       options.allow_code_gen_wasm);
230
231
1086
  ContextInfo info(*name_val);
232
233
1086
  if (!options.origin.IsEmpty()) {
234
4
    Utf8Value origin_val(env->isolate(), options.origin);
235
2
    info.origin = *origin_val;
236
  }
237
238
543
  env->AssignToContext(ctx, info);
239
240
543
  return scope.Escape(ctx);
241
}
242
243
244
5122
void ContextifyContext::Init(Environment* env, Local<Object> target) {
245
  Local<FunctionTemplate> function_template =
246
5122
      FunctionTemplate::New(env->isolate());
247
15366
  function_template->InstanceTemplate()->SetInternalFieldCount(
248
5122
      ContextifyContext::kInternalFieldCount);
249
  env->set_script_data_constructor_function(
250
15366
      function_template->GetFunction(env->context()).ToLocalChecked());
251
252
5122
  env->SetMethod(target, "makeContext", MakeContext);
253
5122
  env->SetMethod(target, "isContext", IsContext);
254
5122
  env->SetMethod(target, "compileFunction", CompileFunction);
255
5122
}
256
257
258
// makeContext(sandbox, name, origin, strings, wasm);
259
543
void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
260
543
  Environment* env = Environment::GetCurrent(args);
261
262
543
  CHECK_EQ(args.Length(), 6);
263
1086
  CHECK(args[0]->IsObject());
264
1086
  Local<Object> sandbox = args[0].As<Object>();
265
266
  // Don't allow contextifying a sandbox multiple times.
267
1629
  CHECK(
268
      !sandbox->HasPrivate(
269
          env->context(),
270
          env->contextify_context_private_symbol()).FromJust());
271
272
1086
  ContextOptions options;
273
274
1629
  CHECK(args[1]->IsString());
275
1086
  options.name = args[1].As<String>();
276
277

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

2177
  if (args[5]->IsObject() &&
289

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

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

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

145
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
431


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

396
  if (!is_declared_on_global_proxy && is_declared_on_sandbox  &&
436

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

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

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

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

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

1849
    if (!result.IsEmpty() && mtask_queue)
954
4
      mtask_queue->PerformCheckpoint(env->isolate());
955
1849
    return result;
956
1865
  };
957

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

1849
  if (timed_out || received_signal) {
973

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

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

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

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