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


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

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

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

3362
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
406


5677
  if (!is_declared && args.ShouldThrowOnError() && is_contextual_store &&
407
54
      !is_function)
408
1
    return;
409
410

9014
  if (!is_declared_on_global_proxy && is_declared_on_sandbox  &&
411

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

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

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

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

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

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

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

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

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

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

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

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

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

2526
  if (break_on_sigint && timeout != -1) {
923
    Watchdog wd(env->isolate(), timeout, &timed_out);
924
    SigintWatchdog swd(env->isolate(), &received_signal);
925
    result = script->Run(env->context());
926
2526
  } else if (break_on_sigint) {
927
95
    SigintWatchdog swd(env->isolate(), &received_signal);
928
190
    result = script->Run(env->context());
929
2431
  } else if (timeout != -1) {
930
1016
    Watchdog wd(env->isolate(), timeout, &timed_out);
931
2032
    result = script->Run(env->context());
932
  } else {
933
2830
    result = script->Run(env->context());
934
  }
935
936
  // Convert the termination exception into a regular exception.
937

2512
  if (timed_out || received_signal) {
938

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

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

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