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: 493 558 88.4 %
Date: 2020-02-19 22:14:06 Branches: 252 378 66.7 %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
#include "node_contextify.h"
23
24
#include "memory_tracker-inl.h"
25
#include "node_internals.h"
26
#include "node_watchdog.h"
27
#include "base_object-inl.h"
28
#include "node_context_data.h"
29
#include "node_errors.h"
30
#include "module_wrap.h"
31
#include "util-inl.h"
32
33
namespace node {
34
namespace contextify {
35
36
using errors::TryCatchScope;
37
38
using v8::Array;
39
using v8::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::Integer;
51
using v8::Isolate;
52
using v8::Local;
53
using v8::Maybe;
54
using v8::MaybeLocal;
55
using v8::Name;
56
using v8::NamedPropertyHandlerConfiguration;
57
using v8::Number;
58
using v8::Object;
59
using v8::ObjectTemplate;
60
using v8::PrimitiveArray;
61
using v8::PropertyAttribute;
62
using v8::PropertyCallbackInfo;
63
using v8::PropertyDescriptor;
64
using v8::PropertyHandlerFlags;
65
using v8::Script;
66
using v8::ScriptCompiler;
67
using v8::ScriptOrigin;
68
using v8::ScriptOrModule;
69
using v8::String;
70
using v8::Uint32;
71
using v8::UnboundScript;
72
using v8::Value;
73
using v8::WeakCallbackInfo;
74
using v8::WeakCallbackType;
75
76
// The vm module executes code in a sandboxed environment with a different
77
// global object than the rest of the code. This is achieved by applying
78
// every call that changes or queries a property on the global `this` in the
79
// sandboxed code, to the sandbox object.
80
//
81
// The implementation uses V8's interceptors for methods like `set`, `get`,
82
// `delete`, `defineProperty`, and for any query of the property attributes.
83
// Property handlers with interceptors are set on the object template for
84
// the sandboxed code. Handlers for both named properties and for indexed
85
// properties are used. Their functionality is almost identical, the indexed
86
// interceptors mostly just call the named interceptors.
87
//
88
// For every `get` of a global property in the sandboxed context, the
89
// interceptor callback checks the sandbox object for the property.
90
// If the property is defined on the sandbox, that result is returned to
91
// the original call instead of finishing the query on the global object.
92
//
93
// For every `set` of a global property, the interceptor callback defines or
94
// changes the property both on the sandbox and the global proxy.
95
96
namespace {
97
98
// Convert an int to a V8 Name (String or Symbol).
99
3
Local<Name> Uint32ToName(Local<Context> context, uint32_t index) {
100
12
  return Uint32::New(context->GetIsolate(), index)->ToString(context)
101
6
      .ToLocalChecked();
102
}
103
104
}  // anonymous namespace
105
106
558
ContextifyContext::ContextifyContext(
107
    Environment* env,
108
558
    Local<Object> sandbox_obj, const ContextOptions& options) : env_(env) {
109
558
  MaybeLocal<Context> v8_context = CreateV8Context(env, sandbox_obj, options);
110
111
  // Allocation failure, maximum call stack size reached, termination, etc.
112
558
  if (v8_context.IsEmpty()) return;
113
114
1116
  context_.Reset(env->isolate(), v8_context.ToLocalChecked());
115
558
  context_.SetWeak(this, WeakCallback, WeakCallbackType::kParameter);
116
558
  env->AddCleanupHook(CleanupHook, this);
117
}
118
119
120
1521
ContextifyContext::~ContextifyContext() {
121
507
  env()->RemoveCleanupHook(CleanupHook, this);
122
507
}
123
124
125
455
void ContextifyContext::CleanupHook(void* arg) {
126
455
  ContextifyContext* self = static_cast<ContextifyContext*>(arg);
127
455
  self->context_.Reset();
128
455
  delete self;
129
455
}
130
131
132
// This is an object that just keeps an internal pointer to this
133
// ContextifyContext.  It's passed to the NamedPropertyHandler.  If we
134
// pass the main JavaScript context object we're embedded in, then the
135
// NamedPropertyHandler will store a reference to it forever and keep it
136
// from getting gc'd.
137
558
MaybeLocal<Object> ContextifyContext::CreateDataWrapper(Environment* env) {
138
  Local<Object> wrapper;
139
1674
  if (!env->script_data_constructor_function()
140
1674
           ->NewInstance(env->context())
141
558
           .ToLocal(&wrapper)) {
142
    return MaybeLocal<Object>();
143
  }
144
145
558
  wrapper->SetAlignedPointerInInternalField(0, this);
146
558
  return wrapper;
147
}
148
149
558
MaybeLocal<Context> ContextifyContext::CreateV8Context(
150
    Environment* env,
151
    Local<Object> sandbox_obj,
152
    const ContextOptions& options) {
153
558
  EscapableHandleScope scope(env->isolate());
154
  Local<FunctionTemplate> function_template =
155
558
      FunctionTemplate::New(env->isolate());
156
157
1116
  function_template->SetClassName(sandbox_obj->GetConstructorName());
158
159
  Local<ObjectTemplate> object_template =
160
558
      function_template->InstanceTemplate();
161
162
  Local<Object> data_wrapper;
163
1116
  if (!CreateDataWrapper(env).ToLocal(&data_wrapper))
164
    return MaybeLocal<Context>();
165
166
  NamedPropertyHandlerConfiguration config(
167
      PropertyGetterCallback,
168
      PropertySetterCallback,
169
      PropertyDescriptorCallback,
170
      PropertyDeleterCallback,
171
      PropertyEnumeratorCallback,
172
      PropertyDefinerCallback,
173
      data_wrapper,
174
558
      PropertyHandlerFlags::kHasNoSideEffect);
175
176
  IndexedPropertyHandlerConfiguration indexed_config(
177
      IndexedPropertyGetterCallback,
178
      IndexedPropertySetterCallback,
179
      IndexedPropertyDescriptorCallback,
180
      IndexedPropertyDeleterCallback,
181
      PropertyEnumeratorCallback,
182
      IndexedPropertyDefinerCallback,
183
      data_wrapper,
184
558
      PropertyHandlerFlags::kHasNoSideEffect);
185
186
558
  object_template->SetHandler(config);
187
558
  object_template->SetHandler(indexed_config);
188
1116
  Local<Context> ctx = Context::New(env->isolate(), nullptr, object_template);
189
558
  if (ctx.IsEmpty()) return MaybeLocal<Context>();
190
  // Only partially initialize the context - the primordials are left out
191
  // and only initialized when necessary.
192
558
  InitializeContextRuntime(ctx);
193
194
558
  if (ctx.IsEmpty()) {
195
    return MaybeLocal<Context>();
196
  }
197
198
1674
  ctx->SetSecurityToken(env->context()->GetSecurityToken());
199
200
  // We need to tie the lifetime of the sandbox object with the lifetime of
201
  // newly created context. We do this by making them hold references to each
202
  // other. The context can directly hold a reference to the sandbox as an
203
  // embedder data field. However, we cannot hold a reference to a v8::Context
204
  // directly in an Object, we instead hold onto the new context's global
205
  // object instead (which then has a reference to the context).
206
558
  ctx->SetEmbedderData(ContextEmbedderIndex::kSandboxObject, sandbox_obj);
207
  sandbox_obj->SetPrivate(env->context(),
208
                          env->contextify_global_private_symbol(),
209
1674
                          ctx->Global());
210
211
1116
  Utf8Value name_val(env->isolate(), options.name);
212
1674
  ctx->AllowCodeGenerationFromStrings(options.allow_code_gen_strings->IsTrue());
213
1116
  ctx->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
214
558
                       options.allow_code_gen_wasm);
215
216
1116
  ContextInfo info(*name_val);
217
218
1116
  if (!options.origin.IsEmpty()) {
219
4
    Utf8Value origin_val(env->isolate(), options.origin);
220
2
    info.origin = *origin_val;
221
  }
222
223
558
  env->AssignToContext(ctx, info);
224
225
558
  return scope.Escape(ctx);
226
}
227
228
229
4369
void ContextifyContext::Init(Environment* env, Local<Object> target) {
230
  Local<FunctionTemplate> function_template =
231
4369
      FunctionTemplate::New(env->isolate());
232
8738
  function_template->InstanceTemplate()->SetInternalFieldCount(1);
233
  env->set_script_data_constructor_function(
234
13107
      function_template->GetFunction(env->context()).ToLocalChecked());
235
236
4369
  env->SetMethod(target, "makeContext", MakeContext);
237
4369
  env->SetMethod(target, "isContext", IsContext);
238
4369
  env->SetMethod(target, "compileFunction", CompileFunction);
239
4369
}
240
241
242
// makeContext(sandbox, name, origin, strings, wasm);
243
558
void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
244
558
  Environment* env = Environment::GetCurrent(args);
245
246
558
  CHECK_EQ(args.Length(), 5);
247
1116
  CHECK(args[0]->IsObject());
248
1116
  Local<Object> sandbox = args[0].As<Object>();
249
250
  // Don't allow contextifying a sandbox multiple times.
251
1674
  CHECK(
252
      !sandbox->HasPrivate(
253
          env->context(),
254
          env->contextify_context_private_symbol()).FromJust());
255
256
558
  ContextOptions options;
257
258
1674
  CHECK(args[1]->IsString());
259
1116
  options.name = args[1].As<String>();
260
261

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

2400
  if (maybe_value.ToLocal(&context_external_v) &&
319
1200
      context_external_v->IsExternal()) {
320
1200
    Local<External> context_external = context_external_v.As<External>();
321
1200
    return static_cast<ContextifyContext*>(context_external->Value());
322
  }
323
  return nullptr;
324
}
325
326
// static
327
template <typename T>
328
1327599
ContextifyContext* ContextifyContext::Get(const PropertyCallbackInfo<T>& args) {
329
1327599
  Local<Value> data = args.Data();
330
  return static_cast<ContextifyContext*>(
331
3982797
      data.As<Object>()->GetAlignedPointerFromInternalField(0));
332
}
333
334
// static
335
1324820
void ContextifyContext::PropertyGetterCallback(
336
    Local<Name> property,
337
    const PropertyCallbackInfo<Value>& args) {
338
1324820
  ContextifyContext* ctx = ContextifyContext::Get(args);
339
340
  // Still initializing
341
2649640
  if (ctx->context_.IsEmpty())
342
1116
    return;
343
344
1323704
  Local<Context> context = ctx->context();
345
1323704
  Local<Object> sandbox = ctx->sandbox();
346
  MaybeLocal<Value> maybe_rv =
347
1323704
      sandbox->GetRealNamedProperty(context, property);
348
1323704
  if (maybe_rv.IsEmpty()) {
349
    maybe_rv =
350
548614
        ctx->global_proxy()->GetRealNamedProperty(context, property);
351
  }
352
353
  Local<Value> rv;
354
1323704
  if (maybe_rv.ToLocal(&rv)) {
355
1311648
    if (rv == sandbox)
356
150
      rv = ctx->global_proxy();
357
358
2623296
    args.GetReturnValue().Set(rv);
359
  }
360
}
361
362
// static
363
2568
void ContextifyContext::PropertySetterCallback(
364
    Local<Name> property,
365
    Local<Value> value,
366
    const PropertyCallbackInfo<Value>& args) {
367
2568
  ContextifyContext* ctx = ContextifyContext::Get(args);
368
369
  // Still initializing
370
5136
  if (ctx->context_.IsEmpty())
371
14
    return;
372
373
2568
  auto attributes = PropertyAttribute::None;
374
5136
  bool is_declared_on_global_proxy = ctx->global_proxy()
375
7704
      ->GetRealNamedPropertyAttributes(ctx->context(), property)
376
2568
      .To(&attributes);
377
  bool read_only =
378
2568
      static_cast<int>(attributes) &
379
2568
      static_cast<int>(PropertyAttribute::ReadOnly);
380
381
5136
  bool is_declared_on_sandbox = ctx->sandbox()
382
7704
      ->GetRealNamedPropertyAttributes(ctx->context(), property)
383
2568
      .To(&attributes);
384

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

2555
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
407


5074
  if (!is_declared && args.ShouldThrowOnError() && is_contextual_store &&
408
65
      !is_function)
409
1
    return;
410
411

7593
  if (!is_declared_on_global_proxy && is_declared_on_sandbox  &&
412

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

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

15
  if (desc.has_get() || desc.has_set()) {
488
    PropertyDescriptor desc_for_sandbox(
489
10
        desc.has_get() ? desc.get() : Undefined(isolate).As<Value>(),
490

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

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

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

3304
  TRACE_EVENT_NESTABLE_ASYNC_END0(
779
      TRACING_CATEGORY_NODE2(vm, script),
780
      "ContextifyScript::New",
781
      contextify_script);
782
}
783
784
1628
bool ContextifyScript::InstanceOf(Environment* env,
785
                                  const Local<Value>& value) {
786

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

1764
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
818
      TRACING_CATEGORY_NODE2(vm, script), "RunInThisContext", wrapped_script);
819
820
  // TODO(addaleax): Use an options object or otherwise merge this with
821
  // RunInContext().
822
882
  CHECK_EQ(args.Length(), 4);
823
824
1764
  CHECK(args[0]->IsNumber());
825
3528
  int64_t timeout = args[0]->IntegerValue(env->context()).FromJust();
826
827
1764
  CHECK(args[1]->IsBoolean());
828
1764
  bool display_errors = args[1]->IsTrue();
829
830
1764
  CHECK(args[2]->IsBoolean());
831
1764
  bool break_on_sigint = args[2]->IsTrue();
832
833
1764
  CHECK(args[3]->IsBoolean());
834
1764
  bool break_on_first_line = args[3]->IsTrue();
835
836
  // Do the eval within this context
837
882
  EvalMachine(env,
838
              timeout,
839
              display_errors,
840
              break_on_sigint,
841
              break_on_first_line,
842
882
              args);
843
844

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

1492
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
867
      TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script);
868
869
1492
  CHECK(args[1]->IsNumber());
870
2984
  int64_t timeout = args[1]->IntegerValue(env->context()).FromJust();
871
872
1492
  CHECK(args[2]->IsBoolean());
873
1492
  bool display_errors = args[2]->IsTrue();
874
875
1492
  CHECK(args[3]->IsBoolean());
876
1492
  bool break_on_sigint = args[3]->IsTrue();
877
878
1492
  CHECK(args[4]->IsBoolean());
879
1492
  bool break_on_first_line = args[4]->IsTrue();
880
881
  // Do the eval within the context
882
746
  Context::Scope context_scope(contextify_context->context());
883
746
  EvalMachine(contextify_context->env(),
884
              timeout,
885
              display_errors,
886
              break_on_sigint,
887
              break_on_first_line,
888
746
              args);
889
890

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

1628
  if (break_on_sigint && timeout != -1) {
924
    Watchdog wd(env->isolate(), timeout, &timed_out);
925
    SigintWatchdog swd(env->isolate(), &received_signal);
926
    result = script->Run(env->context());
927
1628
  } else if (break_on_sigint) {
928
230
    SigintWatchdog swd(env->isolate(), &received_signal);
929
232
    result = script->Run(env->context());
930
1512
  } else if (timeout != -1) {
931
30
    Watchdog wd(env->isolate(), timeout, &timed_out);
932
30
    result = script->Run(env->context());
933
  } else {
934
2994
    result = script->Run(env->context());
935
  }
936
937
  // Convert the termination exception into a regular exception.
938

1614
  if (timed_out || received_signal) {
939

20
    if (!env->is_main_thread() && env->is_stopping())
940
      return false;
941
20
    env->isolate()->CancelTerminateExecution();
942
    // It is possible that execution was terminated by another timeout in
943
    // which this timeout is nested, so check whether one of the watchdogs
944
    // from this invocation is responsible for termination.
945
20
    if (timed_out) {
946
10
      node::THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout);
947
10
    } else if (received_signal) {
948
10
      node::THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env);
949
    }
950
  }
951
952
1614
  if (try_catch.HasCaught()) {
953

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

28
    if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
1121
28
      errors::DecorateErrorStack(env, try_catch);
1122
28
      try_catch.ReThrow();
1123
    }
1124
28
    return;
1125
  }
1126
24288
  Local<Function> fn = maybe_fn.ToLocalChecked();
1127
1128
  Local<Object> cache_key;
1129
72864
  if (!env->compiled_fn_entry_template()->NewInstance(
1130
48576
           context).ToLocal(&cache_key)) {
1131
    return;
1132
  }
1133
24288
  CompiledFnEntry* entry = new CompiledFnEntry(env, cache_key, id, script);
1134
24288
  env->id_to_function_map.emplace(id, entry);
1135
1136
24288
  Local<Object> result = Object::New(isolate);
1137
72864
  if (result->Set(parsing_context, env->function_string(), fn).IsNothing())
1138
    return;
1139
72864
  if (result->Set(parsing_context, env->cache_key_string(), cache_key)
1140
          .IsNothing())
1141
    return;
1142
1143
24288
  if (produce_cached_data) {
1144
    const std::unique_ptr<ScriptCompiler::CachedData> cached_data(
1145
        ScriptCompiler::CreateCodeCacheForFunction(fn));
1146
    bool cached_data_produced = cached_data != nullptr;
1147
    if (cached_data_produced) {
1148
      MaybeLocal<Object> buf = Buffer::Copy(
1149
          env,
1150
          reinterpret_cast<const char*>(cached_data->data),
1151
          cached_data->length);
1152
      if (result
1153
              ->Set(parsing_context,
1154
                    env->cached_data_string(),
1155
                    buf.ToLocalChecked())
1156
              .IsNothing())
1157
        return;
1158
    }
1159
    if (result
1160
            ->Set(parsing_context,
1161
                  env->cached_data_produced_string(),
1162
                  Boolean::New(isolate, cached_data_produced))
1163
            .IsNothing())
1164
      return;
1165
  }
1166
1167
48576
  args.GetReturnValue().Set(result);
1168
}
1169
1170
73
void CompiledFnEntry::WeakCallback(
1171
    const WeakCallbackInfo<CompiledFnEntry>& data) {
1172
73
  CompiledFnEntry* entry = data.GetParameter();
1173
73
  delete entry;
1174
73
}
1175
1176
24288
CompiledFnEntry::CompiledFnEntry(Environment* env,
1177
                                 Local<Object> object,
1178
                                 uint32_t id,
1179
24288
                                 Local<ScriptOrModule> script)
1180
    : BaseObject(env, object),
1181
      id_(id),
1182
24288
      script_(env->isolate(), script) {
1183
24288
  script_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
1184
24288
}
1185
1186
87654
CompiledFnEntry::~CompiledFnEntry() {
1187
21913
  env()->id_to_function_map.erase(id_);
1188
21914
  script_.ClearWeak();
1189
43827
}
1190
1191
113
static void StartSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1192
113
  int ret = SigintWatchdogHelper::GetInstance()->Start();
1193
339
  args.GetReturnValue().Set(ret == 0);
1194
113
}
1195
1196
111
static void StopSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1197
111
  bool had_pending_signals = SigintWatchdogHelper::GetInstance()->Stop();
1198
333
  args.GetReturnValue().Set(had_pending_signals);
1199
111
}
1200
1201
3
static void WatchdogHasPendingSigint(const FunctionCallbackInfo<Value>& args) {
1202
3
  bool ret = SigintWatchdogHelper::GetInstance()->HasPendingSignal();
1203
9
  args.GetReturnValue().Set(ret);
1204
3
}
1205
1206
4369
void Initialize(Local<Object> target,
1207
                Local<Value> unused,
1208
                Local<Context> context,
1209
                void* priv) {
1210
4369
  Environment* env = Environment::GetCurrent(context);
1211
4369
  ContextifyContext::Init(env, target);
1212
4369
  ContextifyScript::Init(env, target);
1213
1214
4369
  env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog);
1215
4369
  env->SetMethod(target, "stopSigintWatchdog", StopSigintWatchdog);
1216
  // Used in tests.
1217
  env->SetMethodNoSideEffect(
1218
4369
      target, "watchdogHasPendingSigint", WatchdogHasPendingSigint);
1219
1220
  {
1221
4369
    Local<FunctionTemplate> tpl = FunctionTemplate::New(env->isolate());
1222
8738
    tpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "CompiledFnEntry"));
1223
8738
    tpl->InstanceTemplate()->SetInternalFieldCount(1);
1224
1225
4369
    env->set_compiled_fn_entry_template(tpl->InstanceTemplate());
1226
  }
1227
4369
}
1228
1229
}  // namespace contextify
1230
}  // namespace node
1231
1232
4185
NODE_MODULE_CONTEXT_AWARE_INTERNAL(contextify, node::contextify::Initialize)