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: 528 593 89.0 %
Date: 2020-05-27 22:15:15 Branches: 255 384 66.4 %

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

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

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

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

2687
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
413


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

7989
  if (!is_declared_on_global_proxy && is_declared_on_sandbox  &&
418

2707
      args.ShouldThrowOnError() && is_contextual_store && !is_function) {
419
    // The property exists on the sandbox but not on the global
420
    // proxy. Setting it would throw because we are in strict mode.
421
    // Don't attempt to set it by signaling that the call was
422
    // intercepted. Only change the value on the sandbox.
423
8
    args.GetReturnValue().Set(false);
424
  }
425
426
8058
  ctx->sandbox()->Set(ctx->context(), property, value).Check();
427
}
428
429
// static
430
29
void ContextifyContext::PropertyDescriptorCallback(
431
    Local<Name> property,
432
    const PropertyCallbackInfo<Value>& args) {
433
29
  ContextifyContext* ctx = ContextifyContext::Get(args);
434
435
  // Still initializing
436
58
  if (ctx->context_.IsEmpty())
437
    return;
438
439
29
  Local<Context> context = ctx->context();
440
441
29
  Local<Object> sandbox = ctx->sandbox();
442
443
87
  if (sandbox->HasOwnProperty(context, property).FromMaybe(false)) {
444
28
    args.GetReturnValue().Set(
445
28
        sandbox->GetOwnPropertyDescriptor(context, property)
446
            .ToLocalChecked());
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
45
        sandbox->DefineProperty(context, property, *desc_for_sandbox)
490
            .Check();
491
30
      };
492
493

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

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

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

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

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

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

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

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

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

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

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

1641
  if (timed_out || received_signal) {
946

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

141
    if (!timed_out && !received_signal && display_errors) {
961
      // We should decorate non-termination exceptions
962
78
      errors::DecorateErrorStack(env, try_catch);
963
    }
964
965
    // If there was an exception thrown during script execution, re-throw it.
966
    // If one of the above checks threw, re-throw the exception instead of
967
    // letting try_catch catch it.
968
    // If execution has been terminated, but not by one of the watchdogs from
969
    // this invocation, this will re-throw a `null` value.
970
141
    if (!try_catch.HasTerminated())
971
137
      try_catch.ReThrow();
972
973
141
    return false;
974
  }
975
976
2998
  args.GetReturnValue().Set(result.ToLocalChecked());
977
1499
  return true;
978
}
979
980
981
1860
ContextifyScript::ContextifyScript(Environment* env, Local<Object> object)
982
    : BaseObject(env, object),
983
3721
      id_(env->get_next_script_id()) {
984
1860
  MakeWeak();
985
1861
  env->id_to_script_map.emplace(id_, this);
986
1861
}
987
988
989
7084
ContextifyScript::~ContextifyScript() {
990
1771
  env()->id_to_script_map.erase(id_);
991
3542
}
992
993
994
24854
void ContextifyContext::CompileFunction(
995
    const FunctionCallbackInfo<Value>& args) {
996
24854
  Environment* env = Environment::GetCurrent(args);
997
24855
  Isolate* isolate = env->isolate();
998
24855
  Local<Context> context = env->context();
999
1000
  // Argument 1: source code
1001
74565
  CHECK(args[0]->IsString());
1002
49710
  Local<String> code = args[0].As<String>();
1003
1004
  // Argument 2: filename
1005
74565
  CHECK(args[1]->IsString());
1006
49710
  Local<String> filename = args[1].As<String>();
1007
1008
  // Argument 3: line offset
1009
49710
  CHECK(args[2]->IsNumber());
1010
49710
  Local<Integer> line_offset = args[2].As<Integer>();
1011
1012
  // Argument 4: column offset
1013
49710
  CHECK(args[3]->IsNumber());
1014
49710
  Local<Integer> column_offset = args[3].As<Integer>();
1015
1016
  // Argument 5: cached data (optional)
1017
  Local<ArrayBufferView> cached_data_buf;
1018
74565
  if (!args[4]->IsUndefined()) {
1019
    CHECK(args[4]->IsArrayBufferView());
1020
    cached_data_buf = args[4].As<ArrayBufferView>();
1021
  }
1022
1023
  // Argument 6: produce cache data
1024
49710
  CHECK(args[5]->IsBoolean());
1025
49710
  bool produce_cached_data = args[5]->IsTrue();
1026
1027
  // Argument 7: parsing context (optional)
1028
  Local<Context> parsing_context;
1029
74562
  if (!args[6]->IsUndefined()) {
1030
4
    CHECK(args[6]->IsObject());
1031
    ContextifyContext* sandbox =
1032
2
        ContextifyContext::ContextFromContextifiedSandbox(
1033
6
            env, args[6].As<Object>());
1034
2
    CHECK_NOT_NULL(sandbox);
1035
2
    parsing_context = sandbox->context();
1036
  } else {
1037
24852
    parsing_context = context;
1038
  }
1039
1040
  // Argument 8: context extensions (optional)
1041
  Local<Array> context_extensions_buf;
1042
74562
  if (!args[7]->IsUndefined()) {
1043
49710
    CHECK(args[7]->IsArray());
1044
49710
    context_extensions_buf = args[7].As<Array>();
1045
  }
1046
1047
  // Argument 9: params for the function (optional)
1048
  Local<Array> params_buf;
1049
74562
  if (!args[8]->IsUndefined()) {
1050
49696
    CHECK(args[8]->IsArray());
1051
49698
    params_buf = args[8].As<Array>();
1052
  }
1053
1054
  // Read cache from cached data buffer
1055
24855
  ScriptCompiler::CachedData* cached_data = nullptr;
1056
24855
  if (!cached_data_buf.IsEmpty()) {
1057
    uint8_t* data = static_cast<uint8_t*>(
1058
        cached_data_buf->Buffer()->GetBackingStore()->Data());
1059
    cached_data = new ScriptCompiler::CachedData(
1060
      data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
1061
  }
1062
1063
  // Get the function id
1064
24855
  uint32_t id = env->get_next_function_id();
1065
1066
  // Set host_defined_options
1067
  Local<PrimitiveArray> host_defined_options =
1068
24854
      PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
1069
74564
  host_defined_options->Set(
1070
      isolate,
1071
      loader::HostDefinedOptions::kType,
1072
24855
      Number::New(isolate, loader::ScriptType::kFunction));
1073
74564
  host_defined_options->Set(
1074
24855
      isolate, loader::HostDefinedOptions::kID, Number::New(isolate, id));
1075
1076
  ScriptOrigin origin(filename,
1077
                      line_offset,       // line offset
1078
                      column_offset,     // column offset
1079
                      True(isolate),     // is cross origin
1080
                      Local<Integer>(),  // script id
1081
                      Local<Value>(),    // source map URL
1082
                      False(isolate),    // is opaque (?)
1083
                      False(isolate),    // is WASM
1084
                      False(isolate),    // is ES Module
1085
24855
                      host_defined_options);
1086
1087
24826
  ScriptCompiler::Source source(code, origin, cached_data);
1088
  ScriptCompiler::CompileOptions options;
1089
24855
  if (source.GetCachedData() == nullptr) {
1090
24855
    options = ScriptCompiler::kNoCompileOptions;
1091
  } else {
1092
    options = ScriptCompiler::kConsumeCodeCache;
1093
  }
1094
1095
49682
  TryCatchScope try_catch(env);
1096
24827
  Context::Scope scope(parsing_context);
1097
1098
  // Read context extensions from buffer
1099
49680
  std::vector<Local<Object>> context_extensions;
1100
24854
  if (!context_extensions_buf.IsEmpty()) {
1101
49710
    for (uint32_t n = 0; n < context_extensions_buf->Length(); n++) {
1102
      Local<Value> val;
1103
2
      if (!context_extensions_buf->Get(context, n).ToLocal(&val)) return;
1104
1
      CHECK(val->IsObject());
1105
1
      context_extensions.push_back(val.As<Object>());
1106
    }
1107
  }
1108
1109
  // Read params from params buffer
1110
49680
  std::vector<Local<String>> params;
1111
24854
  if (!params_buf.IsEmpty()) {
1112
298102
    for (uint32_t n = 0; n < params_buf->Length(); n++) {
1113
      Local<Value> val;
1114
248405
      if (!params_buf->Get(context, n).ToLocal(&val)) return;
1115
248406
      CHECK(val->IsString());
1116
124203
      params.push_back(val.As<String>());
1117
    }
1118
  }
1119
1120
  Local<ScriptOrModule> script;
1121
  MaybeLocal<Function> maybe_fn = ScriptCompiler::CompileFunctionInContext(
1122
      parsing_context, &source, params.size(), params.data(),
1123
      context_extensions.size(), context_extensions.data(), options,
1124
24855
      v8::ScriptCompiler::NoCacheReason::kNoCacheNoReason, &script);
1125
1126
24854
  if (maybe_fn.IsEmpty()) {
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
24826
  Local<Function> fn = maybe_fn.ToLocalChecked();
1134
1135
  Local<Object> cache_key;
1136
74479
  if (!env->compiled_fn_entry_template()->NewInstance(
1137
49653
           context).ToLocal(&cache_key)) {
1138
    return;
1139
  }
1140
24826
  CompiledFnEntry* entry = new CompiledFnEntry(env, cache_key, id, script);
1141
24826
  env->id_to_function_map.emplace(id, entry);
1142
1143
24827
  Local<Object> result = Object::New(isolate);
1144
74479
  if (result->Set(parsing_context, env->function_string(), fn).IsNothing())
1145
    return;
1146
74478
  if (result->Set(parsing_context, env->cache_key_string(), cache_key)
1147
          .IsNothing())
1148
    return;
1149
1150
24826
  if (produce_cached_data) {
1151
    const std::unique_ptr<ScriptCompiler::CachedData> cached_data(
1152
        ScriptCompiler::CreateCodeCacheForFunction(fn));
1153
    bool cached_data_produced = cached_data != nullptr;
1154
    if (cached_data_produced) {
1155
      MaybeLocal<Object> buf = Buffer::Copy(
1156
          env,
1157
          reinterpret_cast<const char*>(cached_data->data),
1158
          cached_data->length);
1159
      if (result
1160
              ->Set(parsing_context,
1161
                    env->cached_data_string(),
1162
                    buf.ToLocalChecked())
1163
              .IsNothing())
1164
        return;
1165
    }
1166
    if (result
1167
            ->Set(parsing_context,
1168
                  env->cached_data_produced_string(),
1169
                  Boolean::New(isolate, cached_data_produced))
1170
            .IsNothing())
1171
      return;
1172
  }
1173
1174
49652
  args.GetReturnValue().Set(result);
1175
}
1176
1177
72
void CompiledFnEntry::WeakCallback(
1178
    const WeakCallbackInfo<CompiledFnEntry>& data) {
1179
72
  CompiledFnEntry* entry = data.GetParameter();
1180
72
  delete entry;
1181
72
}
1182
1183
24827
CompiledFnEntry::CompiledFnEntry(Environment* env,
1184
                                 Local<Object> object,
1185
                                 uint32_t id,
1186
24827
                                 Local<ScriptOrModule> script)
1187
    : BaseObject(env, object),
1188
      id_(id),
1189
24827
      script_(env->isolate(), script) {
1190
24827
  script_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
1191
24827
}
1192
1193
89568
CompiledFnEntry::~CompiledFnEntry() {
1194
22392
  env()->id_to_function_map.erase(id_);
1195
22392
  script_.ClearWeak();
1196
44784
}
1197
1198
113
static void StartSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1199
113
  int ret = SigintWatchdogHelper::GetInstance()->Start();
1200
339
  args.GetReturnValue().Set(ret == 0);
1201
113
}
1202
1203
111
static void StopSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1204
111
  bool had_pending_signals = SigintWatchdogHelper::GetInstance()->Stop();
1205
333
  args.GetReturnValue().Set(had_pending_signals);
1206
111
}
1207
1208
3
static void WatchdogHasPendingSigint(const FunctionCallbackInfo<Value>& args) {
1209
3
  bool ret = SigintWatchdogHelper::GetInstance()->HasPendingSignal();
1210
9
  args.GetReturnValue().Set(ret);
1211
3
}
1212
1213
8
static void MeasureMemory(const FunctionCallbackInfo<Value>& args) {
1214
16
  CHECK(args[0]->IsInt32());
1215
16
  CHECK(args[1]->IsInt32());
1216
24
  int32_t mode = args[0].As<v8::Int32>()->Value();
1217
24
  int32_t execution = args[1].As<v8::Int32>()->Value();
1218
8
  Isolate* isolate = args.GetIsolate();
1219
1220
8
  Local<Context> current_context = isolate->GetCurrentContext();
1221
  Local<Promise::Resolver> resolver;
1222
16
  if (!Promise::Resolver::New(current_context).ToLocal(&resolver)) return;
1223
  std::unique_ptr<v8::MeasureMemoryDelegate> delegate =
1224
      v8::MeasureMemoryDelegate::Default(
1225
          isolate,
1226
          current_context,
1227
          resolver,
1228
16
          static_cast<v8::MeasureMemoryMode>(mode));
1229
16
  isolate->MeasureMemory(std::move(delegate),
1230
8
                         static_cast<v8::MeasureMemoryExecution>(execution));
1231
8
  v8::Local<v8::Promise> promise = resolver->GetPromise();
1232
1233
16
  args.GetReturnValue().Set(promise);
1234
}
1235
1236
4559
void Initialize(Local<Object> target,
1237
                Local<Value> unused,
1238
                Local<Context> context,
1239
                void* priv) {
1240
4559
  Environment* env = Environment::GetCurrent(context);
1241
4559
  Isolate* isolate = env->isolate();
1242
4559
  ContextifyContext::Init(env, target);
1243
4559
  ContextifyScript::Init(env, target);
1244
1245
4559
  env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog);
1246
4559
  env->SetMethod(target, "stopSigintWatchdog", StopSigintWatchdog);
1247
  // Used in tests.
1248
  env->SetMethodNoSideEffect(
1249
4559
      target, "watchdogHasPendingSigint", WatchdogHasPendingSigint);
1250
1251
  {
1252
4559
    Local<FunctionTemplate> tpl = FunctionTemplate::New(env->isolate());
1253
9118
    tpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "CompiledFnEntry"));
1254
13677
    tpl->InstanceTemplate()->SetInternalFieldCount(
1255
4559
        CompiledFnEntry::kInternalFieldCount);
1256
1257
4559
    env->set_compiled_fn_entry_template(tpl->InstanceTemplate());
1258
  }
1259
1260
4559
  Local<Object> constants = Object::New(env->isolate());
1261
4559
  Local<Object> measure_memory = Object::New(env->isolate());
1262
4559
  Local<Object> memory_execution = Object::New(env->isolate());
1263
1264
  {
1265
4559
    Local<Object> memory_mode = Object::New(env->isolate());
1266
4559
    MeasureMemoryMode SUMMARY = MeasureMemoryMode::kSummary;
1267
4559
    MeasureMemoryMode DETAILED = MeasureMemoryMode::kDetailed;
1268
18236
    NODE_DEFINE_CONSTANT(memory_mode, SUMMARY);
1269
18236
    NODE_DEFINE_CONSTANT(memory_mode, DETAILED);
1270
13677
    READONLY_PROPERTY(measure_memory, "mode", memory_mode);
1271
  }
1272
1273
  {
1274
4559
    MeasureMemoryExecution DEFAULT = MeasureMemoryExecution::kDefault;
1275
4559
    MeasureMemoryExecution EAGER = MeasureMemoryExecution::kEager;
1276
18236
    NODE_DEFINE_CONSTANT(memory_execution, DEFAULT);
1277
18236
    NODE_DEFINE_CONSTANT(memory_execution, EAGER);
1278
13677
    READONLY_PROPERTY(measure_memory, "execution", memory_execution);
1279
  }
1280
1281
13677
  READONLY_PROPERTY(constants, "measureMemory", measure_memory);
1282
1283
13677
  target->Set(context, env->constants_string(), constants).Check();
1284
1285
4559
  env->SetMethod(target, "measureMemory", MeasureMemory);
1286
4559
}
1287
1288
}  // namespace contextify
1289
}  // namespace node
1290
1291
4325
NODE_MODULE_CONTEXT_AWARE_INTERNAL(contextify, node::contextify::Initialize)