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: 526 591 89.0 %
Date: 2020-06-24 22:13:30 Branches: 257 386 66.6 %

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

3372
  CHECK(args[2]->IsString() || args[2]->IsUndefined());
266
1689
  if (args[2]->IsString()) {
267
4
    options.origin = args[2].As<String>();
268
  }
269
270
1126
  CHECK(args[3]->IsBoolean());
271
1126
  options.allow_code_gen_strings = args[3].As<Boolean>();
272
273
1126
  CHECK(args[4]->IsBoolean());
274
1126
  options.allow_code_gen_wasm = args[4].As<Boolean>();
275
276
1126
  TryCatchScope try_catch(env);
277
1126
  auto context_ptr = std::make_unique<ContextifyContext>(env, sandbox, options);
278
279
563
  if (try_catch.HasCaught()) {
280
    if (!try_catch.HasTerminated())
281
      try_catch.ReThrow();
282
    return;
283
  }
284
285
1126
  if (context_ptr->context().IsEmpty())
286
    return;
287
288
  sandbox->SetPrivate(
289
      env->context(),
290
      env->contextify_context_private_symbol(),
291
1689
      External::New(env->isolate(), context_ptr.release()));
292
}
293
294
295
1871
void ContextifyContext::IsContext(const FunctionCallbackInfo<Value>& args) {
296
1871
  Environment* env = Environment::GetCurrent(args);
297
298
3742
  CHECK(args[0]->IsObject());
299
3742
  Local<Object> sandbox = args[0].As<Object>();
300
301
  Maybe<bool> result =
302
      sandbox->HasPrivate(env->context(),
303
3742
                          env->contextify_context_private_symbol());
304
5613
  args.GetReturnValue().Set(result.FromJust());
305
1871
}
306
307
308
58
void ContextifyContext::WeakCallback(
309
    const WeakCallbackInfo<ContextifyContext>& data) {
310
58
  ContextifyContext* context = data.GetParameter();
311
58
  delete context;
312
58
}
313
314
// static
315
1250
ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox(
316
    Environment* env,
317
    const Local<Object>& sandbox) {
318
  MaybeLocal<Value> maybe_value =
319
      sandbox->GetPrivate(env->context(),
320
2500
                          env->contextify_context_private_symbol());
321
  Local<Value> context_external_v;
322

2500
  if (maybe_value.ToLocal(&context_external_v) &&
323
1250
      context_external_v->IsExternal()) {
324
1250
    Local<External> context_external = context_external_v.As<External>();
325
1250
    return static_cast<ContextifyContext*>(context_external->Value());
326
  }
327
  return nullptr;
328
}
329
330
// static
331
template <typename T>
332
1333289
ContextifyContext* ContextifyContext::Get(const PropertyCallbackInfo<T>& args) {
333
1333289
  Local<Value> data = args.Data();
334
  return static_cast<ContextifyContext*>(
335
3999867
      data.As<Object>()->GetAlignedPointerFromInternalField(
336
2666578
          ContextifyContext::kSlot));
337
}
338
339
// static
340
1330383
void ContextifyContext::PropertyGetterCallback(
341
    Local<Name> property,
342
    const PropertyCallbackInfo<Value>& args) {
343
1330383
  ContextifyContext* ctx = ContextifyContext::Get(args);
344
345
  // Still initializing
346
2660766
  if (ctx->context_.IsEmpty())
347
1689
    return;
348
349
1328694
  Local<Context> context = ctx->context();
350
1328694
  Local<Object> sandbox = ctx->sandbox();
351
  MaybeLocal<Value> maybe_rv =
352
1328694
      sandbox->GetRealNamedProperty(context, property);
353
1328694
  if (maybe_rv.IsEmpty()) {
354
    maybe_rv =
355
558458
        ctx->global_proxy()->GetRealNamedProperty(context, property);
356
  }
357
358
  Local<Value> rv;
359
1328694
  if (maybe_rv.ToLocal(&rv)) {
360
1316622
    if (rv == sandbox)
361
166
      rv = ctx->global_proxy();
362
363
2633244
    args.GetReturnValue().Set(rv);
364
  }
365
}
366
367
// static
368
2701
void ContextifyContext::PropertySetterCallback(
369
    Local<Name> property,
370
    Local<Value> value,
371
    const PropertyCallbackInfo<Value>& args) {
372
2701
  ContextifyContext* ctx = ContextifyContext::Get(args);
373
374
  // Still initializing
375
5402
  if (ctx->context_.IsEmpty())
376
14
    return;
377
378
2701
  auto attributes = PropertyAttribute::None;
379
5402
  bool is_declared_on_global_proxy = ctx->global_proxy()
380
8103
      ->GetRealNamedPropertyAttributes(ctx->context(), property)
381
2701
      .To(&attributes);
382
  bool read_only =
383
2701
      static_cast<int>(attributes) &
384
2701
      static_cast<int>(PropertyAttribute::ReadOnly);
385
386
5402
  bool is_declared_on_sandbox = ctx->sandbox()
387
8103
      ->GetRealNamedPropertyAttributes(ctx->context(), property)
388
2701
      .To(&attributes);
389

5398
  read_only = read_only ||
390
2697
      (static_cast<int>(attributes) &
391
      static_cast<int>(PropertyAttribute::ReadOnly));
392
393
2701
  if (read_only)
394
13
    return;
395
396
  // true for x = 5
397
  // false for this.x = 5
398
  // false for Object.defineProperty(this, 'foo', ...)
399
  // false for vmResult.x = 5 where vmResult = vm.runInContext();
400
5376
  bool is_contextual_store = ctx->global_proxy() != args.This();
401
402
  // Indicator to not return before setting (undeclared) function declarations
403
  // on the sandbox in strict mode, i.e. args.ShouldThrowOnError() = true.
404
  // True for 'function f() {}', 'this.f = function() {}',
405
  // 'var f = function()'.
406
  // In effect only for 'function f() {}' because
407
  // var f = function(), is_declared = true
408
  // this.f = function() {}, is_contextual_store = false.
409
2688
  bool is_function = value->IsFunction();
410
411

2688
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
412


5339
  if (!is_declared && args.ShouldThrowOnError() && is_contextual_store &&
413
65
      !is_function)
414
1
    return;
415
416

7993
  if (!is_declared_on_global_proxy && is_declared_on_sandbox  &&
417

2709
      args.ShouldThrowOnError() && is_contextual_store && !is_function) {
418
    // The property exists on the sandbox but not on the global
419
    // proxy. Setting it would throw because we are in strict mode.
420
    // Don't attempt to set it by signaling that the call was
421
    // intercepted. Only change the value on the sandbox.
422
8
    args.GetReturnValue().Set(false);
423
  }
424
425
5374
  USE(ctx->sandbox()->Set(ctx->context(), property, value));
426
}
427
428
// static
429
29
void ContextifyContext::PropertyDescriptorCallback(
430
    Local<Name> property,
431
    const PropertyCallbackInfo<Value>& args) {
432
29
  ContextifyContext* ctx = ContextifyContext::Get(args);
433
434
  // Still initializing
435
58
  if (ctx->context_.IsEmpty())
436
    return;
437
438
29
  Local<Context> context = ctx->context();
439
440
29
  Local<Object> sandbox = ctx->sandbox();
441
442
87
  if (sandbox->HasOwnProperty(context, property).FromMaybe(false)) {
443
    Local<Value> desc;
444
28
    if (sandbox->GetOwnPropertyDescriptor(context, property).ToLocal(&desc)) {
445
28
      args.GetReturnValue().Set(desc);
446
    }
447
  }
448
}
449
450
// static
451
15
void ContextifyContext::PropertyDefinerCallback(
452
    Local<Name> property,
453
    const PropertyDescriptor& desc,
454
    const PropertyCallbackInfo<Value>& args) {
455
15
  ContextifyContext* ctx = ContextifyContext::Get(args);
456
457
  // Still initializing
458
30
  if (ctx->context_.IsEmpty())
459
    return;
460
461
15
  Local<Context> context = ctx->context();
462
15
  Isolate* isolate = context->GetIsolate();
463
464
15
  auto attributes = PropertyAttribute::None;
465
  bool is_declared =
466
45
      ctx->global_proxy()->GetRealNamedPropertyAttributes(ctx->context(),
467
30
                                                          property)
468
15
          .To(&attributes);
469
  bool read_only =
470
15
      static_cast<int>(attributes) &
471
15
          static_cast<int>(PropertyAttribute::ReadOnly);
472
473
  // If the property is set on the global as read_only, don't change it on
474
  // the global or sandbox.
475

15
  if (is_declared && read_only)
476
    return;
477
478
15
  Local<Object> sandbox = ctx->sandbox();
479
480
  auto define_prop_on_sandbox =
481
15
      [&] (PropertyDescriptor* desc_for_sandbox) {
482
31
        if (desc.has_enumerable()) {
483
2
          desc_for_sandbox->set_enumerable(desc.enumerable());
484
        }
485
15
        if (desc.has_configurable()) {
486
1
          desc_for_sandbox->set_configurable(desc.configurable());
487
        }
488
        // Set the property on the sandbox.
489
30
        USE(sandbox->DefineProperty(context, property, *desc_for_sandbox));
490
30
      };
491
492

15
  if (desc.has_get() || desc.has_set()) {
493
    PropertyDescriptor desc_for_sandbox(
494
10
        desc.has_get() ? desc.get() : Undefined(isolate).As<Value>(),
495

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

14
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
701
        TRACING_CATEGORY_NODE2(vm, script),
702
        "ContextifyScript::New",
703
        contextify_script,
704
        "filename", TRACE_STR_COPY(*fn));
705
  }
706
707
1856
  ScriptCompiler::CachedData* cached_data = nullptr;
708
1856
  if (!cached_data_buf.IsEmpty()) {
709
    uint8_t* data = static_cast<uint8_t*>(
710
46
        cached_data_buf->Buffer()->GetBackingStore()->Data());
711
23
    cached_data = new ScriptCompiler::CachedData(
712
46
        data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
713
  }
714
715
  Local<PrimitiveArray> host_defined_options =
716
1856
      PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
717
5568
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kType,
718
1856
                            Number::New(isolate, loader::ScriptType::kScript));
719
5568
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kID,
720
3712
                            Number::New(isolate, contextify_script->id()));
721
722
  ScriptOrigin origin(filename,
723
                      line_offset,                          // line offset
724
                      column_offset,                        // column offset
725
                      True(isolate),                        // is cross origin
726
                      Local<Integer>(),                     // script id
727
                      Local<Value>(),                       // source map URL
728
                      False(isolate),                       // is opaque (?)
729
                      False(isolate),                       // is WASM
730
                      False(isolate),                       // is ES Module
731
1856
                      host_defined_options);
732
1676
  ScriptCompiler::Source source(code, origin, cached_data);
733
  ScriptCompiler::CompileOptions compile_options =
734
1856
      ScriptCompiler::kNoCompileOptions;
735
736
1856
  if (source.GetCachedData() != nullptr)
737
23
    compile_options = ScriptCompiler::kConsumeCodeCache;
738
739
3532
  TryCatchScope try_catch(env);
740
3532
  ShouldNotAbortOnUncaughtScope no_abort_scope(env);
741
1676
  Context::Scope scope(parsing_context);
742
743
  MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
744
      isolate,
745
      &source,
746
1856
      compile_options);
747
748
1856
  if (v8_script.IsEmpty()) {
749
180
    errors::DecorateErrorStack(env, try_catch);
750
180
    no_abort_scope.Close();
751
180
    if (!try_catch.HasTerminated())
752
180
      try_catch.ReThrow();
753

360
    TRACE_EVENT_NESTABLE_ASYNC_END0(
754
        TRACING_CATEGORY_NODE2(vm, script),
755
        "ContextifyScript::New",
756
        contextify_script);
757
180
    return;
758
  }
759
3352
  contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
760
761
1676
  if (compile_options == ScriptCompiler::kConsumeCodeCache) {
762
69
    args.This()->Set(
763
        env->context(),
764
        env->cached_data_rejected_string(),
765
115
        Boolean::New(isolate, source.GetCachedData()->rejected)).Check();
766
1653
  } else if (produce_cached_data) {
767
    std::unique_ptr<ScriptCompiler::CachedData> cached_data {
768
12
      ScriptCompiler::CreateCodeCache(v8_script.ToLocalChecked()) };
769
6
    bool cached_data_produced = cached_data != nullptr;
770
6
    if (cached_data_produced) {
771
      MaybeLocal<Object> buf = Buffer::Copy(
772
          env,
773
6
          reinterpret_cast<const char*>(cached_data->data),
774
12
          cached_data->length);
775
18
      args.This()->Set(env->context(),
776
                       env->cached_data_string(),
777
24
                       buf.ToLocalChecked()).Check();
778
    }
779
18
    args.This()->Set(
780
        env->context(),
781
        env->cached_data_produced_string(),
782
30
        Boolean::New(isolate, cached_data_produced)).Check();
783
  }
784

3352
  TRACE_EVENT_NESTABLE_ASYNC_END0(
785
      TRACING_CATEGORY_NODE2(vm, script),
786
      "ContextifyScript::New",
787
      contextify_script);
788
}
789
790
1653
bool ContextifyScript::InstanceOf(Environment* env,
791
                                  const Local<Value>& value) {
792

3304
  return !value.IsEmpty() &&
793
4956
         env->script_context_constructor_template()->HasInstance(value);
794
}
795
796
11
void ContextifyScript::CreateCachedData(
797
    const FunctionCallbackInfo<Value>& args) {
798
11
  Environment* env = Environment::GetCurrent(args);
799
  ContextifyScript* wrapped_script;
800
11
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
801
  Local<UnboundScript> unbound_script =
802
11
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
803
  std::unique_ptr<ScriptCompiler::CachedData> cached_data(
804
22
      ScriptCompiler::CreateCodeCache(unbound_script));
805
11
  if (!cached_data) {
806
    args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked());
807
  } else {
808
    MaybeLocal<Object> buf = Buffer::Copy(
809
        env,
810
11
        reinterpret_cast<const char*>(cached_data->data),
811
22
        cached_data->length);
812
22
    args.GetReturnValue().Set(buf.ToLocalChecked());
813
  }
814
}
815
816
876
void ContextifyScript::RunInThisContext(
817
    const FunctionCallbackInfo<Value>& args) {
818
876
  Environment* env = Environment::GetCurrent(args);
819
820
  ContextifyScript* wrapped_script;
821
876
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
822
823

1752
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
824
      TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script);
825
826
  // TODO(addaleax): Use an options object or otherwise merge this with
827
  // RunInContext().
828
876
  CHECK_EQ(args.Length(), 4);
829
830
1752
  CHECK(args[0]->IsNumber());
831
3504
  int64_t timeout = args[0]->IntegerValue(env->context()).FromJust();
832
833
1752
  CHECK(args[1]->IsBoolean());
834
1752
  bool display_errors = args[1]->IsTrue();
835
836
1752
  CHECK(args[2]->IsBoolean());
837
1752
  bool break_on_sigint = args[2]->IsTrue();
838
839
1752
  CHECK(args[3]->IsBoolean());
840
1750
  bool break_on_first_line = args[3]->IsTrue();
841
842
  // Do the eval within this context
843
875
  EvalMachine(env,
844
              timeout,
845
              display_errors,
846
              break_on_sigint,
847
              break_on_first_line,
848
875
              args);
849
850

1720
  TRACE_EVENT_NESTABLE_ASYNC_END0(
851
      TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script);
852
}
853
854
776
void ContextifyScript::RunInContext(const FunctionCallbackInfo<Value>& args) {
855
776
  Environment* env = Environment::GetCurrent(args);
856
857
  ContextifyScript* wrapped_script;
858
776
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
859
860
776
  CHECK_EQ(args.Length(), 5);
861
862
1552
  CHECK(args[0]->IsObject());
863
1552
  Local<Object> sandbox = args[0].As<Object>();
864
  // Get the context from the sandbox
865
  ContextifyContext* contextify_context =
866
776
      ContextifyContext::ContextFromContextifiedSandbox(env, sandbox);
867
776
  CHECK_NOT_NULL(contextify_context);
868
869
1552
  if (contextify_context->context().IsEmpty())
870
    return;
871
872

1552
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
873
      TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script);
874
875
1552
  CHECK(args[1]->IsNumber());
876
3104
  int64_t timeout = args[1]->IntegerValue(env->context()).FromJust();
877
878
1552
  CHECK(args[2]->IsBoolean());
879
1552
  bool display_errors = args[2]->IsTrue();
880
881
1552
  CHECK(args[3]->IsBoolean());
882
1552
  bool break_on_sigint = args[3]->IsTrue();
883
884
1552
  CHECK(args[4]->IsBoolean());
885
1552
  bool break_on_first_line = args[4]->IsTrue();
886
887
  // Do the eval within the context
888
776
  Context::Scope context_scope(contextify_context->context());
889
776
  EvalMachine(contextify_context->env(),
890
              timeout,
891
              display_errors,
892
              break_on_sigint,
893
              break_on_first_line,
894
776
              args);
895
896

1552
  TRACE_EVENT_NESTABLE_ASYNC_END0(
897
      TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script);
898
}
899
900
1652
bool ContextifyScript::EvalMachine(Environment* env,
901
                                   const int64_t timeout,
902
                                   const bool display_errors,
903
                                   const bool break_on_sigint,
904
                                   const bool break_on_first_line,
905
                                   const FunctionCallbackInfo<Value>& args) {
906
1652
  if (!env->can_call_into_js())
907
    return false;
908
1652
  if (!ContextifyScript::InstanceOf(env, args.Holder())) {
909
    env->ThrowTypeError(
910
        "Script methods can only be called on script instances.");
911
    return false;
912
  }
913
3288
  TryCatchScope try_catch(env);
914
  ContextifyScript* wrapped_script;
915
1651
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder(), false);
916
  Local<UnboundScript> unbound_script =
917
1651
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
918
1652
  Local<Script> script = unbound_script->BindToCurrentContext();
919
920
#if HAVE_INSPECTOR
921
1651
  if (break_on_first_line) {
922
10
    env->inspector_agent()->PauseOnNextJavascriptStatement("Break on start");
923
  }
924
#endif
925
926
  MaybeLocal<Value> result;
927
1651
  bool timed_out = false;
928
1651
  bool received_signal = false;
929

1651
  if (break_on_sigint && timeout != -1) {
930
    Watchdog wd(env->isolate(), timeout, &timed_out);
931
    SigintWatchdog swd(env->isolate(), &received_signal);
932
    result = script->Run(env->context());
933
1651
  } else if (break_on_sigint) {
934
230
    SigintWatchdog swd(env->isolate(), &received_signal);
935
232
    result = script->Run(env->context());
936
1535
  } else if (timeout != -1) {
937
28
    Watchdog wd(env->isolate(), timeout, &timed_out);
938
28
    result = script->Run(env->context());
939
  } else {
940
3043
    result = script->Run(env->context());
941
  }
942
943
  // Convert the termination exception into a regular exception.
944

1636
  if (timed_out || received_signal) {
945

19
    if (!env->is_main_thread() && env->is_stopping())
946
      return false;
947
19
    env->isolate()->CancelTerminateExecution();
948
    // It is possible that execution was terminated by another timeout in
949
    // which this timeout is nested, so check whether one of the watchdogs
950
    // from this invocation is responsible for termination.
951
19
    if (timed_out) {
952
9
      node::THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout);
953
10
    } else if (received_signal) {
954
10
      node::THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env);
955
    }
956
  }
957
958
1636
  if (try_catch.HasCaught()) {
959

141
    if (!timed_out && !received_signal && display_errors) {
960
      // We should decorate non-termination exceptions
961
78
      errors::DecorateErrorStack(env, try_catch);
962
    }
963
964
    // If there was an exception thrown during script execution, re-throw it.
965
    // If one of the above checks threw, re-throw the exception instead of
966
    // letting try_catch catch it.
967
    // If execution has been terminated, but not by one of the watchdogs from
968
    // this invocation, this will re-throw a `null` value.
969
141
    if (!try_catch.HasTerminated())
970
138
      try_catch.ReThrow();
971
972
141
    return false;
973
  }
974
975
2990
  args.GetReturnValue().Set(result.ToLocalChecked());
976
1495
  return true;
977
}
978
979
980
1856
ContextifyScript::ContextifyScript(Environment* env, Local<Object> object)
981
    : BaseObject(env, object),
982
3712
      id_(env->get_next_script_id()) {
983
1856
  MakeWeak();
984
1856
  env->id_to_script_map.emplace(id_, this);
985
1856
}
986
987
988
7173
ContextifyScript::~ContextifyScript() {
989
1793
  env()->id_to_script_map.erase(id_);
990
3587
}
991
992
993
25220
void ContextifyContext::CompileFunction(
994
    const FunctionCallbackInfo<Value>& args) {
995
25220
  Environment* env = Environment::GetCurrent(args);
996
25220
  Isolate* isolate = env->isolate();
997
25220
  Local<Context> context = env->context();
998
999
  // Argument 1: source code
1000
75660
  CHECK(args[0]->IsString());
1001
50440
  Local<String> code = args[0].As<String>();
1002
1003
  // Argument 2: filename
1004
75660
  CHECK(args[1]->IsString());
1005
50440
  Local<String> filename = args[1].As<String>();
1006
1007
  // Argument 3: line offset
1008
50440
  CHECK(args[2]->IsNumber());
1009
50440
  Local<Integer> line_offset = args[2].As<Integer>();
1010
1011
  // Argument 4: column offset
1012
50440
  CHECK(args[3]->IsNumber());
1013
50440
  Local<Integer> column_offset = args[3].As<Integer>();
1014
1015
  // Argument 5: cached data (optional)
1016
  Local<ArrayBufferView> cached_data_buf;
1017
75660
  if (!args[4]->IsUndefined()) {
1018
    CHECK(args[4]->IsArrayBufferView());
1019
    cached_data_buf = args[4].As<ArrayBufferView>();
1020
  }
1021
1022
  // Argument 6: produce cache data
1023
50440
  CHECK(args[5]->IsBoolean());
1024
50440
  bool produce_cached_data = args[5]->IsTrue();
1025
1026
  // Argument 7: parsing context (optional)
1027
  Local<Context> parsing_context;
1028
75660
  if (!args[6]->IsUndefined()) {
1029
4
    CHECK(args[6]->IsObject());
1030
    ContextifyContext* sandbox =
1031
2
        ContextifyContext::ContextFromContextifiedSandbox(
1032
6
            env, args[6].As<Object>());
1033
2
    CHECK_NOT_NULL(sandbox);
1034
2
    parsing_context = sandbox->context();
1035
  } else {
1036
25218
    parsing_context = context;
1037
  }
1038
1039
  // Argument 8: context extensions (optional)
1040
  Local<Array> context_extensions_buf;
1041
75660
  if (!args[7]->IsUndefined()) {
1042
50440
    CHECK(args[7]->IsArray());
1043
50440
    context_extensions_buf = args[7].As<Array>();
1044
  }
1045
1046
  // Argument 9: params for the function (optional)
1047
  Local<Array> params_buf;
1048
75660
  if (!args[8]->IsUndefined()) {
1049
50428
    CHECK(args[8]->IsArray());
1050
50428
    params_buf = args[8].As<Array>();
1051
  }
1052
1053
  // Read cache from cached data buffer
1054
25220
  ScriptCompiler::CachedData* cached_data = nullptr;
1055
25220
  if (!cached_data_buf.IsEmpty()) {
1056
    uint8_t* data = static_cast<uint8_t*>(
1057
        cached_data_buf->Buffer()->GetBackingStore()->Data());
1058
    cached_data = new ScriptCompiler::CachedData(
1059
      data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
1060
  }
1061
1062
  // Get the function id
1063
25220
  uint32_t id = env->get_next_function_id();
1064
1065
  // Set host_defined_options
1066
  Local<PrimitiveArray> host_defined_options =
1067
25220
      PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
1068
75660
  host_defined_options->Set(
1069
      isolate,
1070
      loader::HostDefinedOptions::kType,
1071
25220
      Number::New(isolate, loader::ScriptType::kFunction));
1072
75660
  host_defined_options->Set(
1073
25220
      isolate, loader::HostDefinedOptions::kID, Number::New(isolate, id));
1074
1075
  ScriptOrigin origin(filename,
1076
                      line_offset,       // line offset
1077
                      column_offset,     // column offset
1078
                      True(isolate),     // is cross origin
1079
                      Local<Integer>(),  // script id
1080
                      Local<Value>(),    // source map URL
1081
                      False(isolate),    // is opaque (?)
1082
                      False(isolate),    // is WASM
1083
                      False(isolate),    // is ES Module
1084
25220
                      host_defined_options);
1085
1086
25192
  ScriptCompiler::Source source(code, origin, cached_data);
1087
  ScriptCompiler::CompileOptions options;
1088
25220
  if (source.GetCachedData() == nullptr) {
1089
25220
    options = ScriptCompiler::kNoCompileOptions;
1090
  } else {
1091
    options = ScriptCompiler::kConsumeCodeCache;
1092
  }
1093
1094
50412
  TryCatchScope try_catch(env);
1095
25192
  Context::Scope scope(parsing_context);
1096
1097
  // Read context extensions from buffer
1098
50412
  std::vector<Local<Object>> context_extensions;
1099
25220
  if (!context_extensions_buf.IsEmpty()) {
1100
50442
    for (uint32_t n = 0; n < context_extensions_buf->Length(); n++) {
1101
      Local<Value> val;
1102
2
      if (!context_extensions_buf->Get(context, n).ToLocal(&val)) return;
1103
1
      CHECK(val->IsObject());
1104
1
      context_extensions.push_back(val.As<Object>());
1105
    }
1106
  }
1107
1108
  // Read params from params buffer
1109
50412
  std::vector<Local<String>> params;
1110
25220
  if (!params_buf.IsEmpty()) {
1111
302484
    for (uint32_t n = 0; n < params_buf->Length(); n++) {
1112
      Local<Value> val;
1113
252056
      if (!params_buf->Get(context, n).ToLocal(&val)) return;
1114
252056
      CHECK(val->IsString());
1115
126028
      params.push_back(val.As<String>());
1116
    }
1117
  }
1118
1119
  Local<ScriptOrModule> script;
1120
  MaybeLocal<Function> maybe_fn = ScriptCompiler::CompileFunctionInContext(
1121
      parsing_context, &source, params.size(), params.data(),
1122
      context_extensions.size(), context_extensions.data(), options,
1123
25220
      v8::ScriptCompiler::NoCacheReason::kNoCacheNoReason, &script);
1124
1125
  Local<Function> fn;
1126
25220
  if (!maybe_fn.ToLocal(&fn)) {
1127

28
    if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
1128
28
      errors::DecorateErrorStack(env, try_catch);
1129
28
      try_catch.ReThrow();
1130
    }
1131
28
    return;
1132
  }
1133
1134
  Local<Object> cache_key;
1135
75576
  if (!env->compiled_fn_entry_template()->NewInstance(
1136
50384
           context).ToLocal(&cache_key)) {
1137
    return;
1138
  }
1139
25192
  CompiledFnEntry* entry = new CompiledFnEntry(env, cache_key, id, script);
1140
25192
  env->id_to_function_map.emplace(id, entry);
1141
1142
25192
  Local<Object> result = Object::New(isolate);
1143
75576
  if (result->Set(parsing_context, env->function_string(), fn).IsNothing())
1144
    return;
1145
75576
  if (result->Set(parsing_context, env->cache_key_string(), cache_key)
1146
          .IsNothing())
1147
    return;
1148
1149
25192
  if (produce_cached_data) {
1150
    const std::unique_ptr<ScriptCompiler::CachedData> cached_data(
1151
        ScriptCompiler::CreateCodeCacheForFunction(fn));
1152
    bool cached_data_produced = cached_data != nullptr;
1153
    if (cached_data_produced) {
1154
      MaybeLocal<Object> buf = Buffer::Copy(
1155
          env,
1156
          reinterpret_cast<const char*>(cached_data->data),
1157
          cached_data->length);
1158
      if (result
1159
              ->Set(parsing_context,
1160
                    env->cached_data_string(),
1161
                    buf.ToLocalChecked())
1162
              .IsNothing())
1163
        return;
1164
    }
1165
    if (result
1166
            ->Set(parsing_context,
1167
                  env->cached_data_produced_string(),
1168
                  Boolean::New(isolate, cached_data_produced))
1169
            .IsNothing())
1170
      return;
1171
  }
1172
1173
50384
  args.GetReturnValue().Set(result);
1174
}
1175
1176
72
void CompiledFnEntry::WeakCallback(
1177
    const WeakCallbackInfo<CompiledFnEntry>& data) {
1178
72
  CompiledFnEntry* entry = data.GetParameter();
1179
72
  delete entry;
1180
72
}
1181
1182
25192
CompiledFnEntry::CompiledFnEntry(Environment* env,
1183
                                 Local<Object> object,
1184
                                 uint32_t id,
1185
25192
                                 Local<ScriptOrModule> script)
1186
    : BaseObject(env, object),
1187
      id_(id),
1188
25192
      script_(env->isolate(), script) {
1189
25192
  script_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
1190
25192
}
1191
1192
90547
CompiledFnEntry::~CompiledFnEntry() {
1193
22637
  env()->id_to_function_map.erase(id_);
1194
22637
  script_.ClearWeak();
1195
45273
}
1196
1197
113
static void StartSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1198
113
  int ret = SigintWatchdogHelper::GetInstance()->Start();
1199
339
  args.GetReturnValue().Set(ret == 0);
1200
113
}
1201
1202
111
static void StopSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1203
111
  bool had_pending_signals = SigintWatchdogHelper::GetInstance()->Stop();
1204
333
  args.GetReturnValue().Set(had_pending_signals);
1205
111
}
1206
1207
3
static void WatchdogHasPendingSigint(const FunctionCallbackInfo<Value>& args) {
1208
3
  bool ret = SigintWatchdogHelper::GetInstance()->HasPendingSignal();
1209
9
  args.GetReturnValue().Set(ret);
1210
3
}
1211
1212
8
static void MeasureMemory(const FunctionCallbackInfo<Value>& args) {
1213
16
  CHECK(args[0]->IsInt32());
1214
16
  CHECK(args[1]->IsInt32());
1215
24
  int32_t mode = args[0].As<v8::Int32>()->Value();
1216
24
  int32_t execution = args[1].As<v8::Int32>()->Value();
1217
8
  Isolate* isolate = args.GetIsolate();
1218
1219
8
  Local<Context> current_context = isolate->GetCurrentContext();
1220
  Local<Promise::Resolver> resolver;
1221
16
  if (!Promise::Resolver::New(current_context).ToLocal(&resolver)) return;
1222
  std::unique_ptr<v8::MeasureMemoryDelegate> delegate =
1223
      v8::MeasureMemoryDelegate::Default(
1224
          isolate,
1225
          current_context,
1226
          resolver,
1227
16
          static_cast<v8::MeasureMemoryMode>(mode));
1228
16
  isolate->MeasureMemory(std::move(delegate),
1229
8
                         static_cast<v8::MeasureMemoryExecution>(execution));
1230
8
  v8::Local<v8::Promise> promise = resolver->GetPromise();
1231
1232
16
  args.GetReturnValue().Set(promise);
1233
}
1234
1235
4670
void Initialize(Local<Object> target,
1236
                Local<Value> unused,
1237
                Local<Context> context,
1238
                void* priv) {
1239
4670
  Environment* env = Environment::GetCurrent(context);
1240
4670
  Isolate* isolate = env->isolate();
1241
4670
  ContextifyContext::Init(env, target);
1242
4670
  ContextifyScript::Init(env, target);
1243
1244
4670
  env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog);
1245
4670
  env->SetMethod(target, "stopSigintWatchdog", StopSigintWatchdog);
1246
  // Used in tests.
1247
  env->SetMethodNoSideEffect(
1248
4670
      target, "watchdogHasPendingSigint", WatchdogHasPendingSigint);
1249
1250
  {
1251
4670
    Local<FunctionTemplate> tpl = FunctionTemplate::New(env->isolate());
1252
9340
    tpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "CompiledFnEntry"));
1253
14010
    tpl->InstanceTemplate()->SetInternalFieldCount(
1254
4670
        CompiledFnEntry::kInternalFieldCount);
1255
1256
4670
    env->set_compiled_fn_entry_template(tpl->InstanceTemplate());
1257
  }
1258
1259
4670
  Local<Object> constants = Object::New(env->isolate());
1260
4670
  Local<Object> measure_memory = Object::New(env->isolate());
1261
4670
  Local<Object> memory_execution = Object::New(env->isolate());
1262
1263
  {
1264
4670
    Local<Object> memory_mode = Object::New(env->isolate());
1265
4670
    MeasureMemoryMode SUMMARY = MeasureMemoryMode::kSummary;
1266
4670
    MeasureMemoryMode DETAILED = MeasureMemoryMode::kDetailed;
1267
18680
    NODE_DEFINE_CONSTANT(memory_mode, SUMMARY);
1268
18680
    NODE_DEFINE_CONSTANT(memory_mode, DETAILED);
1269
14010
    READONLY_PROPERTY(measure_memory, "mode", memory_mode);
1270
  }
1271
1272
  {
1273
4670
    MeasureMemoryExecution DEFAULT = MeasureMemoryExecution::kDefault;
1274
4670
    MeasureMemoryExecution EAGER = MeasureMemoryExecution::kEager;
1275
18680
    NODE_DEFINE_CONSTANT(memory_execution, DEFAULT);
1276
18680
    NODE_DEFINE_CONSTANT(memory_execution, EAGER);
1277
14010
    READONLY_PROPERTY(measure_memory, "execution", memory_execution);
1278
  }
1279
1280
14010
  READONLY_PROPERTY(constants, "measureMemory", measure_memory);
1281
1282
14010
  target->Set(context, env->constants_string(), constants).Check();
1283
1284
4670
  env->SetMethod(target, "measureMemory", MeasureMemory);
1285
4670
}
1286
1287
}  // namespace contextify
1288
}  // namespace node
1289
1290
4398
NODE_MODULE_CONTEXT_AWARE_INTERNAL(contextify, node::contextify::Initialize)