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

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

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

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

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

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

140
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
432


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

381
  if (!is_declared_on_global_proxy && is_declared_on_sandbox  &&
437

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

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

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

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

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

1724
    if (!result.IsEmpty() && mtask_queue)
957
4
      mtask_queue->PerformCheckpoint(env->isolate());
958
1724
    return result;
959
1740
  };
960

1740
  if (break_on_sigint && timeout != -1) {
961
    Watchdog wd(env->isolate(), timeout, &timed_out);
962
    SigintWatchdog swd(env->isolate(), &received_signal);
963
    result = run();
964
1740
  } else if (break_on_sigint) {
965
295
    SigintWatchdog swd(env->isolate(), &received_signal);
966
149
    result = run();
967
1591
  } else if (timeout != -1) {
968
30
    Watchdog wd(env->isolate(), timeout, &timed_out);
969
15
    result = run();
970
  } else {
971
1576
    result = run();
972
  }
973
974
  // Convert the termination exception into a regular exception.
975

1724
  if (timed_out || received_signal) {
976

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

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

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

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