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-28 22:34:34 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
546
ContextifyContext::ContextifyContext(
109
    Environment* env,
110
546
    Local<Object> sandbox_obj, const ContextOptions& options) : env_(env) {
111
546
  MaybeLocal<Context> v8_context = CreateV8Context(env, sandbox_obj, options);
112
113
  // Allocation failure, maximum call stack size reached, termination, etc.
114
1092
  if (v8_context.IsEmpty()) return;
115
116
926
  context_.Reset(env->isolate(), v8_context.ToLocalChecked());
117
463
  context_.SetWeak(this, WeakCallback, WeakCallbackType::kParameter);
118
463
  env->AddCleanupHook(CleanupHook, this);
119
}
120
121
122
1054
ContextifyContext::~ContextifyContext() {
123
527
  env()->RemoveCleanupHook(CleanupHook, this);
124
527
}
125
126
127
444
void ContextifyContext::CleanupHook(void* arg) {
128
444
  ContextifyContext* self = static_cast<ContextifyContext*>(arg);
129
444
  self->context_.Reset();
130
444
  delete self;
131
444
}
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
546
MaybeLocal<Object> ContextifyContext::CreateDataWrapper(Environment* env) {
140
  Local<Object> wrapper;
141
1092
  if (!env->script_data_constructor_function()
142
1638
           ->NewInstance(env->context())
143
1638
           .ToLocal(&wrapper)) {
144
    return MaybeLocal<Object>();
145
  }
146
147
546
  wrapper->SetAlignedPointerInInternalField(0, this);
148
546
  return wrapper;
149
}
150
151
546
MaybeLocal<Context> ContextifyContext::CreateV8Context(
152
    Environment* env,
153
    Local<Object> sandbox_obj,
154
    const ContextOptions& options) {
155
546
  EscapableHandleScope scope(env->isolate());
156
  Local<FunctionTemplate> function_template =
157
546
      FunctionTemplate::New(env->isolate());
158
159
1092
  function_template->SetClassName(sandbox_obj->GetConstructorName());
160
161
  Local<ObjectTemplate> object_template =
162
546
      function_template->InstanceTemplate();
163
164
  Local<Object> data_wrapper;
165
1092
  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
546
      PropertyHandlerFlags::kHasNoSideEffect);
177
178
  IndexedPropertyHandlerConfiguration indexed_config(
179
      IndexedPropertyGetterCallback,
180
      IndexedPropertySetterCallback,
181
      IndexedPropertyDescriptorCallback,
182
      IndexedPropertyDeleterCallback,
183
      PropertyEnumeratorCallback,
184
      IndexedPropertyDefinerCallback,
185
      data_wrapper,
186
546
      PropertyHandlerFlags::kHasNoSideEffect);
187
188
546
  object_template->SetHandler(config);
189
546
  object_template->SetHandler(indexed_config);
190
191
546
  Local<Context> ctx = NewContext(env->isolate(), object_template);
192
193
546
  if (ctx.IsEmpty()) {
194
83
    return MaybeLocal<Context>();
195
  }
196
197
1389
  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
463
  ctx->SetEmbedderData(ContextEmbedderIndex::kSandboxObject, sandbox_obj);
206
  sandbox_obj->SetPrivate(env->context(),
207
                          env->contextify_global_private_symbol(),
208
1389
                          ctx->Global());
209
210
926
  Utf8Value name_val(env->isolate(), options.name);
211
1389
  ctx->AllowCodeGenerationFromStrings(options.allow_code_gen_strings->IsTrue());
212
  ctx->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
213
463
                       options.allow_code_gen_wasm);
214
215
926
  ContextInfo info(*name_val);
216
217
926
  if (!options.origin.IsEmpty()) {
218
    Utf8Value origin_val(env->isolate(), options.origin);
219
    info.origin = *origin_val;
220
  }
221
222
463
  env->AssignToContext(ctx, info);
223
224
463
  return scope.Escape(ctx);
225
}
226
227
228
4951
void ContextifyContext::Init(Environment* env, Local<Object> target) {
229
  Local<FunctionTemplate> function_template =
230
4951
      FunctionTemplate::New(env->isolate());
231
9902
  function_template->InstanceTemplate()->SetInternalFieldCount(1);
232
  env->set_script_data_constructor_function(
233
14853
      function_template->GetFunction(env->context()).ToLocalChecked());
234
235
4951
  env->SetMethod(target, "makeContext", MakeContext);
236
4951
  env->SetMethod(target, "isContext", IsContext);
237
4951
  env->SetMethod(target, "compileFunction", CompileFunction);
238
4951
}
239
240
241
// makeContext(sandbox, name, origin, strings, wasm);
242
546
void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
243
546
  Environment* env = Environment::GetCurrent(args);
244
245
546
  CHECK_EQ(args.Length(), 5);
246
1092
  CHECK(args[0]->IsObject());
247
1092
  Local<Object> sandbox = args[0].As<Object>();
248
249
  // Don't allow contextifying a sandbox multiple times.
250
1638
  CHECK(
251
      !sandbox->HasPrivate(
252
          env->context(),
253
          env->contextify_context_private_symbol()).FromJust());
254
255
546
  ContextOptions options;
256
257
1638
  CHECK(args[1]->IsString());
258
1092
  options.name = args[1].As<String>();
259
260


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

3896
  if (maybe_value.ToLocal(&context_external_v) &&
318
1948
      context_external_v->IsExternal()) {
319
1948
    Local<External> context_external = context_external_v.As<External>();
320
1948
    return static_cast<ContextifyContext*>(context_external->Value());
321
  }
322
  return nullptr;
323
}
324
325
// static
326
template <typename T>
327
13052354
ContextifyContext* ContextifyContext::Get(const PropertyCallbackInfo<T>& args) {
328
13052354
  Local<Value> data = args.Data();
329
  return static_cast<ContextifyContext*>(
330
39157062
      data.As<Object>()->GetAlignedPointerFromInternalField(0));
331
}
332
333
// static
334
13048920
void ContextifyContext::PropertyGetterCallback(
335
    Local<Name> property,
336
    const PropertyCallbackInfo<Value>& args) {
337
13048920
  ContextifyContext* ctx = ContextifyContext::Get(args);
338
339
  // Still initializing
340
26097840
  if (ctx->context_.IsEmpty())
341
13736392
    return;
342
343
12361448
  Local<Context> context = ctx->context();
344
12361448
  Local<Object> sandbox = ctx->sandbox();
345
  MaybeLocal<Value> maybe_rv =
346
12361448
      sandbox->GetRealNamedProperty(context, property);
347
12361448
  if (maybe_rv.IsEmpty()) {
348
    maybe_rv =
349
11592662
        ctx->global_proxy()->GetRealNamedProperty(context, property);
350
  }
351
352
  Local<Value> rv;
353
12361448
  if (maybe_rv.ToLocal(&rv)) {
354
12356942
    if (rv == sandbox)
355
150
      rv = ctx->global_proxy();
356
357
24713884
    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
4951
void ContextifyScript::Init(Environment* env, Local<Object> target) {
622
4951
  HandleScope scope(env->isolate());
623
  Local<String> class_name =
624
4951
      FIXED_ONE_BYTE_STRING(env->isolate(), "ContextifyScript");
625
626
4951
  Local<FunctionTemplate> script_tmpl = env->NewFunctionTemplate(New);
627
9902
  script_tmpl->InstanceTemplate()->SetInternalFieldCount(1);
628
4951
  script_tmpl->SetClassName(class_name);
629
4951
  env->SetProtoMethod(script_tmpl, "createCachedData", CreateCachedData);
630
4951
  env->SetProtoMethod(script_tmpl, "runInContext", RunInContext);
631
4951
  env->SetProtoMethod(script_tmpl, "runInThisContext", RunInThisContext);
632
633
  target->Set(env->context(), class_name,
634
24755
      script_tmpl->GetFunction(env->context()).ToLocalChecked()).Check();
635
4951
  env->set_script_context_constructor_template(script_tmpl);
636
4951
}
637
638
1749
void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
639
1749
  Environment* env = Environment::GetCurrent(args);
640
1749
  Isolate* isolate = env->isolate();
641
1749
  Local<Context> context = env->context();
642
643
1749
  CHECK(args.IsConstructCall());
644
645
1749
  const int argc = args.Length();
646
1749
  CHECK_GE(argc, 2);
647
648
5247
  CHECK(args[0]->IsString());
649
3498
  Local<String> code = args[0].As<String>();
650
651
5247
  CHECK(args[1]->IsString());
652
3498
  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
1749
  bool produce_cached_data = false;
658
1749
  Local<Context> parsing_context = context;
659
660
1749
  if (argc > 2) {
661
    // new ContextifyScript(code, filename, lineOffset, columnOffset,
662
    //                      cachedData, produceCachedData, parsingContext)
663
1749
    CHECK_EQ(argc, 7);
664
3498
    CHECK(args[2]->IsNumber());
665
3498
    line_offset = args[2].As<Integer>();
666
3498
    CHECK(args[3]->IsNumber());
667
3498
    column_offset = args[3].As<Integer>();
668
5247
    if (!args[4]->IsUndefined()) {
669
46
      CHECK(args[4]->IsArrayBufferView());
670
46
      cached_data_buf = args[4].As<ArrayBufferView>();
671
    }
672
3498
    CHECK(args[5]->IsBoolean());
673
3498
    produce_cached_data = args[5]->IsTrue();
674
5244
    if (!args[6]->IsUndefined()) {
675
662
      CHECK(args[6]->IsObject());
676
      ContextifyContext* sandbox =
677
          ContextifyContext::ContextFromContextifiedSandbox(
678
662
              env, args[6].As<Object>());
679
331
      CHECK_NOT_NULL(sandbox);
680
331
      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
1749
      new ContextifyScript(env, args.This());
689
690
3498
  if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
691
1749
          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
1749
  ScriptCompiler::CachedData* cached_data = nullptr;
701
1749
  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
1749
      PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
710
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kType,
711
3498
                            Number::New(isolate, loader::ScriptType::kScript));
712
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kID,
713
3498
                            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
1749
                      host_defined_options);
725
  ScriptCompiler::Source source(code, origin, cached_data);
726
  ScriptCompiler::CompileOptions compile_options =
727
1749
      ScriptCompiler::kNoCompileOptions;
728
729
1749
  if (source.GetCachedData() != nullptr)
730
23
    compile_options = ScriptCompiler::kConsumeCodeCache;
731
732
3300
  TryCatchScope try_catch(env);
733
3300
  ShouldNotAbortOnUncaughtScope no_abort_scope(env);
734
1551
  Context::Scope scope(parsing_context);
735
736
  MaybeLocal<UnboundScript> v8_script = ScriptCompiler::CompileUnboundScript(
737
      isolate,
738
      &source,
739
1749
      compile_options);
740
741
1749
  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
1947
    return;
751
  }
752
3102
  contextify_script->script_.Reset(isolate, v8_script.ToLocalChecked());
753
754
1551
  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
1528
  } 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

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

10116
  return !value.IsEmpty() &&
786
7587
         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
1844
  CHECK(args[2]->IsBoolean());
830
1844
  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
1607
void ContextifyScript::RunInContext(const FunctionCallbackInfo<Value>& args) {
848
1607
  Environment* env = Environment::GetCurrent(args);
849
850
  ContextifyScript* wrapped_script;
851
1607
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
852
853
1607
  CHECK_EQ(args.Length(), 5);
854
855
3214
  CHECK(args[0]->IsObject());
856
3214
  Local<Object> sandbox = args[0].As<Object>();
857
  // Get the context from the sandbox
858
  ContextifyContext* contextify_context =
859
1607
      ContextifyContext::ContextFromContextifiedSandbox(env, sandbox);
860
1607
  CHECK_NOT_NULL(contextify_context);
861
862
3214
  if (contextify_context->context().IsEmpty())
863
    return;
864
865

3214
  TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(
866
      TRACING_CATEGORY_NODE2(vm, script), "RunInContext", wrapped_script);
867
868
3214
  CHECK(args[1]->IsNumber());
869
6428
  int64_t timeout = args[1]->IntegerValue(env->context()).FromJust();
870
871
3214
  CHECK(args[2]->IsBoolean());
872
3214
  bool display_errors = args[2]->IsTrue();
873
874
3214
  CHECK(args[3]->IsBoolean());
875
3214
  bool break_on_sigint = args[3]->IsTrue();
876
877
3214
  CHECK(args[4]->IsBoolean());
878
3214
  bool break_on_first_line = args[4]->IsTrue();
879
880
  // Do the eval within the context
881
1607
  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
1607
              args);
888
889

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

2529
  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
2529
  } else if (break_on_sigint) {
927
95
    SigintWatchdog swd(env->isolate(), &received_signal);
928
190
    result = script->Run(env->context());
929
2434
  } else if (timeout != -1) {
930
1016
    Watchdog wd(env->isolate(), timeout, &timed_out);
931
2032
    result = script->Run(env->context());
932
  } else {
933
2836
    result = script->Run(env->context());
934
  }
935
936
  // Convert the termination exception into a regular exception.
937

2515
  if (timed_out || received_signal) {
938

521
    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
2515
  if (try_catch.HasCaught()) {
952

625
    if (!timed_out && !received_signal && display_errors) {
953
      // We should decorate non-termination exceptions
954
63
      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
625
    if (!try_catch.HasTerminated())
963
623
      try_catch.ReThrow();
964
965
625
    return false;
966
  }
967
968
3780
  args.GetReturnValue().Set(result.ToLocalChecked());
969
1890
  return true;
970
}
971
972
973
1749
ContextifyScript::ContextifyScript(Environment* env, Local<Object> object)
974
    : BaseObject(env, object),
975
3498
      id_(env->get_next_script_id()) {
976
1749
  MakeWeak();
977
1749
  env->id_to_script_map.emplace(id_, this);
978
1749
}
979
980
981
6448
ContextifyScript::~ContextifyScript() {
982
1612
  env()->id_to_script_map.erase(id_);
983
3224
}
984
985
986
39793
void ContextifyContext::CompileFunction(
987
    const FunctionCallbackInfo<Value>& args) {
988
39793
  Environment* env = Environment::GetCurrent(args);
989
39793
  Isolate* isolate = env->isolate();
990
39793
  Local<Context> context = env->context();
991
992
  // Argument 1: source code
993
119379
  CHECK(args[0]->IsString());
994
79586
  Local<String> code = args[0].As<String>();
995
996
  // Argument 2: filename
997
119379
  CHECK(args[1]->IsString());
998
79586
  Local<String> filename = args[1].As<String>();
999
1000
  // Argument 3: line offset
1001
79586
  CHECK(args[2]->IsNumber());
1002
79586
  Local<Integer> line_offset = args[2].As<Integer>();
1003
1004
  // Argument 4: column offset
1005
79586
  CHECK(args[3]->IsNumber());
1006
79586
  Local<Integer> column_offset = args[3].As<Integer>();
1007
1008
  // Argument 5: cached data (optional)
1009
  Local<ArrayBufferView> cached_data_buf;
1010
119379
  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
79586
  CHECK(args[5]->IsBoolean());
1017
79586
  bool produce_cached_data = args[5]->IsTrue();
1018
1019
  // Argument 7: parsing context (optional)
1020
  Local<Context> parsing_context;
1021
119379
  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
39791
    parsing_context = context;
1030
  }
1031
1032
  // Argument 8: context extensions (optional)
1033
  Local<Array> context_extensions_buf;
1034
119379
  if (!args[7]->IsUndefined()) {
1035
79586
    CHECK(args[7]->IsArray());
1036
79586
    context_extensions_buf = args[7].As<Array>();
1037
  }
1038
1039
  // Argument 9: params for the function (optional)
1040
  Local<Array> params_buf;
1041
119379
  if (!args[8]->IsUndefined()) {
1042
79574
    CHECK(args[8]->IsArray());
1043
79574
    params_buf = args[8].As<Array>();
1044
  }
1045
1046
  // Read cache from cached data buffer
1047
39793
  ScriptCompiler::CachedData* cached_data = nullptr;
1048
39793
  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
39793
  uint32_t id = env->get_next_function_id();
1057
1058
  // Set host_defined_options
1059
  Local<PrimitiveArray> host_defined_options =
1060
39793
      PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
1061
  host_defined_options->Set(
1062
      isolate,
1063
      loader::HostDefinedOptions::kType,
1064
79586
      Number::New(isolate, loader::ScriptType::kFunction));
1065
  host_defined_options->Set(
1066
79586
      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
39793
                      host_defined_options);
1078
1079
  ScriptCompiler::Source source(code, origin, cached_data);
1080
  ScriptCompiler::CompileOptions options;
1081
39793
  if (source.GetCachedData() == nullptr) {
1082
39793
    options = ScriptCompiler::kNoCompileOptions;
1083
  } else {
1084
    options = ScriptCompiler::kConsumeCodeCache;
1085
  }
1086
1087
79563
  TryCatchScope try_catch(env);
1088
39770
  Context::Scope scope(parsing_context);
1089
1090
  // Read context extensions from buffer
1091
79563
  std::vector<Local<Object>> context_extensions;
1092
39793
  if (!context_extensions_buf.IsEmpty()) {
1093
79588
    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
79563
  std::vector<Local<String>> params;
1103
39793
  if (!params_buf.IsEmpty()) {
1104
477384
    for (uint32_t n = 0; n < params_buf->Length(); n++) {
1105
      Local<Value> val;
1106
397810
      if (!params_buf->Get(context, n).ToLocal(&val)) return;
1107
397810
      CHECK(val->IsString());
1108
198905
      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
39793
      v8::ScriptCompiler::NoCacheReason::kNoCacheNoReason, &script);
1117
1118
39793
  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
39770
  Local<Function> fn = maybe_fn.ToLocalChecked();
1126
1127
  Local<Object> cache_key;
1128
79540
  if (!env->compiled_fn_entry_template()->NewInstance(
1129
159080
           context).ToLocal(&cache_key)) {
1130
    return;
1131
  }
1132
39770
  CompiledFnEntry* entry = new CompiledFnEntry(env, cache_key, id, script);
1133
39770
  env->id_to_function_map.emplace(id, entry);
1134
1135
39770
  Local<Object> result = Object::New(isolate);
1136
119310
  if (result->Set(parsing_context, env->function_string(), fn).IsNothing())
1137
    return;
1138
159080
  if (result->Set(parsing_context, env->cache_key_string(), cache_key)
1139
79540
          .IsNothing())
1140
    return;
1141
1142
39770
  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
119310
  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
39770
CompiledFnEntry::CompiledFnEntry(Environment* env,
1176
                                 Local<Object> object,
1177
                                 uint32_t id,
1178
                                 Local<ScriptOrModule> script)
1179
    : BaseObject(env, object),
1180
      id_(id),
1181
39770
      script_(env->isolate(), script) {
1182
39770
  script_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
1183
39770
}
1184
1185
149436
CompiledFnEntry::~CompiledFnEntry() {
1186
37359
  env()->id_to_function_map.erase(id_);
1187
37359
  script_.ClearWeak();
1188
74718
}
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
4951
void Initialize(Local<Object> target,
1206
                Local<Value> unused,
1207
                Local<Context> context,
1208
                void* priv) {
1209
4951
  Environment* env = Environment::GetCurrent(context);
1210
4951
  ContextifyContext::Init(env, target);
1211
4951
  ContextifyScript::Init(env, target);
1212
1213
4951
  env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog);
1214
4951
  env->SetMethod(target, "stopSigintWatchdog", StopSigintWatchdog);
1215
  // Used in tests.
1216
  env->SetMethodNoSideEffect(
1217
4951
      target, "watchdogHasPendingSigint", WatchdogHasPendingSigint);
1218
1219
  {
1220
4951
    Local<FunctionTemplate> tpl = FunctionTemplate::New(env->isolate());
1221
9902
    tpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "CompiledFnEntry"));
1222
9902
    tpl->InstanceTemplate()->SetInternalFieldCount(1);
1223
1224
4951
    env->set_compiled_fn_entry_template(tpl->InstanceTemplate());
1225
  }
1226
4951
}
1227
1228
}  // namespace contextify
1229
}  // namespace node
1230
1231
4827
NODE_MODULE_CONTEXT_AWARE_INTERNAL(contextify, node::contextify::Initialize)