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: 475 537 88.5 %
Date: 2019-10-05 22:32:21 Branches: 264 392 67.3 %

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
9
      .ToLocalChecked();
102
}
103
104
}  // anonymous namespace
105
106
545
ContextifyContext::ContextifyContext(
107
    Environment* env,
108
545
    Local<Object> sandbox_obj, const ContextOptions& options) : env_(env) {
109
545
  MaybeLocal<Context> v8_context = CreateV8Context(env, sandbox_obj, options);
110
111
  // Allocation failure, maximum call stack size reached, termination, etc.
112
1090
  if (v8_context.IsEmpty()) return;
113
114
922
  context_.Reset(env->isolate(), v8_context.ToLocalChecked());
115
461
  context_.SetWeak(this, WeakCallback, WeakCallbackType::kParameter);
116
461
  env->AddCleanupHook(CleanupHook, this);
117
}
118
119
120
1052
ContextifyContext::~ContextifyContext() {
121
526
  env()->RemoveCleanupHook(CleanupHook, this);
122
526
}
123
124
125
442
void ContextifyContext::CleanupHook(void* arg) {
126
442
  ContextifyContext* self = static_cast<ContextifyContext*>(arg);
127
442
  self->context_.Reset();
128
442
  delete self;
129
442
}
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
545
MaybeLocal<Object> ContextifyContext::CreateDataWrapper(Environment* env) {
138
  Local<Object> wrapper;
139
1090
  if (!env->script_data_constructor_function()
140
1635
           ->NewInstance(env->context())
141
1635
           .ToLocal(&wrapper)) {
142
    return MaybeLocal<Object>();
143
  }
144
145
545
  wrapper->SetAlignedPointerInInternalField(0, this);
146
545
  return wrapper;
147
}
148
149
545
MaybeLocal<Context> ContextifyContext::CreateV8Context(
150
    Environment* env,
151
    Local<Object> sandbox_obj,
152
    const ContextOptions& options) {
153
545
  EscapableHandleScope scope(env->isolate());
154
  Local<FunctionTemplate> function_template =
155
545
      FunctionTemplate::New(env->isolate());
156
157
1090
  function_template->SetClassName(sandbox_obj->GetConstructorName());
158
159
  Local<ObjectTemplate> object_template =
160
545
      function_template->InstanceTemplate();
161
162
  Local<Object> data_wrapper;
163
1090
  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
545
      PropertyHandlerFlags::kHasNoSideEffect);
175
176
  IndexedPropertyHandlerConfiguration indexed_config(
177
      IndexedPropertyGetterCallback,
178
      IndexedPropertySetterCallback,
179
      IndexedPropertyDescriptorCallback,
180
      IndexedPropertyDeleterCallback,
181
      PropertyEnumeratorCallback,
182
      IndexedPropertyDefinerCallback,
183
      data_wrapper,
184
545
      PropertyHandlerFlags::kHasNoSideEffect);
185
186
545
  object_template->SetHandler(config);
187
545
  object_template->SetHandler(indexed_config);
188
189
545
  Local<Context> ctx = NewContext(env->isolate(), object_template);
190
191
545
  if (ctx.IsEmpty()) {
192
84
    return MaybeLocal<Context>();
193
  }
194
195
1383
  ctx->SetSecurityToken(env->context()->GetSecurityToken());
196
197
  // We need to tie the lifetime of the sandbox object with the lifetime of
198
  // newly created context. We do this by making them hold references to each
199
  // other. The context can directly hold a reference to the sandbox as an
200
  // embedder data field. However, we cannot hold a reference to a v8::Context
201
  // directly in an Object, we instead hold onto the new context's global
202
  // object instead (which then has a reference to the context).
203
461
  ctx->SetEmbedderData(ContextEmbedderIndex::kSandboxObject, sandbox_obj);
204
  sandbox_obj->SetPrivate(env->context(),
205
                          env->contextify_global_private_symbol(),
206
1383
                          ctx->Global());
207
208
922
  Utf8Value name_val(env->isolate(), options.name);
209
1383
  ctx->AllowCodeGenerationFromStrings(options.allow_code_gen_strings->IsTrue());
210
  ctx->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
211
461
                       options.allow_code_gen_wasm);
212
213
922
  ContextInfo info(*name_val);
214
215
922
  if (!options.origin.IsEmpty()) {
216
    Utf8Value origin_val(env->isolate(), options.origin);
217
    info.origin = *origin_val;
218
  }
219
220
461
  env->AssignToContext(ctx, info);
221
222
461
  return scope.Escape(ctx);
223
}
224
225
226
5092
void ContextifyContext::Init(Environment* env, Local<Object> target) {
227
  Local<FunctionTemplate> function_template =
228
5092
      FunctionTemplate::New(env->isolate());
229
10184
  function_template->InstanceTemplate()->SetInternalFieldCount(1);
230
  env->set_script_data_constructor_function(
231
15276
      function_template->GetFunction(env->context()).ToLocalChecked());
232
233
5092
  env->SetMethod(target, "makeContext", MakeContext);
234
5092
  env->SetMethod(target, "isContext", IsContext);
235
5092
  env->SetMethod(target, "compileFunction", CompileFunction);
236
5092
}
237
238
239
// makeContext(sandbox, name, origin, strings, wasm);
240
545
void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
241
545
  Environment* env = Environment::GetCurrent(args);
242
243
545
  CHECK_EQ(args.Length(), 5);
244
1090
  CHECK(args[0]->IsObject());
245
1090
  Local<Object> sandbox = args[0].As<Object>();
246
247
  // Don't allow contextifying a sandbox multiple times.
248
1635
  CHECK(
249
      !sandbox->HasPrivate(
250
          env->context(),
251
          env->contextify_context_private_symbol()).FromJust());
252
253
545
  ContextOptions options;
254
255
1635
  CHECK(args[1]->IsString());
256
1090
  options.name = args[1].As<String>();
257
258


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

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

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

3545
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
404


6038
  if (!is_declared && args.ShouldThrowOnError() && is_contextual_store &&
405
55
      !is_function)
406
1
    return;
407
408

9557
  if (!is_declared_on_global_proxy && is_declared_on_sandbox  &&
409

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

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

15
  if (desc.has_get() || desc.has_set()) {
485
    PropertyDescriptor desc_for_sandbox(
486
10
        desc.has_get() ? desc.get() : Undefined(isolate).As<Value>(),
487

23
        desc.has_set() ? desc.set() : Undefined(isolate).As<Value>());
488
489
5
    define_prop_on_sandbox(&desc_for_sandbox);
490
  } else {
491
    Local<Value> value =
492

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

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

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

3460
  TRACE_EVENT_NESTABLE_ASYNC_END0(
776
      TRACING_CATEGORY_NODE2(vm, script),
777
      "ContextifyScript::New",
778
1730
      contextify_script);
779
}
780
781
2708
bool ContextifyScript::InstanceOf(Environment* env,
782
                                  const Local<Value>& value) {
783

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

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

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

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

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

2708
  if (break_on_sigint && timeout != -1) {
921
    Watchdog wd(env->isolate(), timeout, &timed_out);
922
    SigintWatchdog swd(env->isolate(), &received_signal);
923
    result = script->Run(env->context());
924
2708
  } else if (break_on_sigint) {
925
96
    SigintWatchdog swd(env->isolate(), &received_signal);
926
192
    result = script->Run(env->context());
927
2612
  } else if (timeout != -1) {
928
1016
    Watchdog wd(env->isolate(), timeout, &timed_out);
929
2032
    result = script->Run(env->context());
930
  } else {
931
3192
    result = script->Run(env->context());
932
  }
933
934
  // Convert the termination exception into a regular exception.
935

2693
  if (timed_out || received_signal) {
936

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

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

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