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: 521 588 88.6 %
Date: 2020-02-27 22:14:15 Branches: 259 390 66.4 %

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

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

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

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

2555
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
410


5074
  if (!is_declared && args.ShouldThrowOnError() && is_contextual_store &&
411
65
      !is_function)
412
1
    return;
413
414

7593
  if (!is_declared_on_global_proxy && is_declared_on_sandbox  &&
415

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

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

15
  if (desc.has_get() || desc.has_set()) {
491
    PropertyDescriptor desc_for_sandbox(
492
10
        desc.has_get() ? desc.get() : Undefined(isolate).As<Value>(),
493

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

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

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

3279
  TRACE_EVENT_NESTABLE_ASYNC_END0(
782
      TRACING_CATEGORY_NODE2(vm, script),
783
      "ContextifyScript::New",
784
      contextify_script);
785
}
786
787
1615
bool ContextifyScript::InstanceOf(Environment* env,
788
                                  const Local<Value>& value) {
789

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

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

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

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

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

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

1604
  if (timed_out || received_signal) {
942

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

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

28
    if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
1124
28
      errors::DecorateErrorStack(env, try_catch);
1125
28
      try_catch.ReThrow();
1126
    }
1127
28
    return;
1128
  }
1129
24334
  Local<Function> fn = maybe_fn.ToLocalChecked();
1130
1131
  Local<Object> cache_key;
1132
73001
  if (!env->compiled_fn_entry_template()->NewInstance(
1133
48667
           context).ToLocal(&cache_key)) {
1134
    return;
1135
  }
1136
24333
  CompiledFnEntry* entry = new CompiledFnEntry(env, cache_key, id, script);
1137
24333
  env->id_to_function_map.emplace(id, entry);
1138
1139
24334
  Local<Object> result = Object::New(isolate);
1140
73000
  if (result->Set(parsing_context, env->function_string(), fn).IsNothing())
1141
    return;
1142
72997
  if (result->Set(parsing_context, env->cache_key_string(), cache_key)
1143
          .IsNothing())
1144
    return;
1145
1146
24332
  if (produce_cached_data) {
1147
    const std::unique_ptr<ScriptCompiler::CachedData> cached_data(
1148
        ScriptCompiler::CreateCodeCacheForFunction(fn));
1149
    bool cached_data_produced = cached_data != nullptr;
1150
    if (cached_data_produced) {
1151
      MaybeLocal<Object> buf = Buffer::Copy(
1152
          env,
1153
          reinterpret_cast<const char*>(cached_data->data),
1154
          cached_data->length);
1155
      if (result
1156
              ->Set(parsing_context,
1157
                    env->cached_data_string(),
1158
                    buf.ToLocalChecked())
1159
              .IsNothing())
1160
        return;
1161
    }
1162
    if (result
1163
            ->Set(parsing_context,
1164
                  env->cached_data_produced_string(),
1165
                  Boolean::New(isolate, cached_data_produced))
1166
            .IsNothing())
1167
      return;
1168
  }
1169
1170
48664
  args.GetReturnValue().Set(result);
1171
}
1172
1173
73
void CompiledFnEntry::WeakCallback(
1174
    const WeakCallbackInfo<CompiledFnEntry>& data) {
1175
73
  CompiledFnEntry* entry = data.GetParameter();
1176
73
  delete entry;
1177
73
}
1178
1179
24334
CompiledFnEntry::CompiledFnEntry(Environment* env,
1180
                                 Local<Object> object,
1181
                                 uint32_t id,
1182
24334
                                 Local<ScriptOrModule> script)
1183
    : BaseObject(env, object),
1184
      id_(id),
1185
24334
      script_(env->isolate(), script) {
1186
24334
  script_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
1187
24334
}
1188
1189
87836
CompiledFnEntry::~CompiledFnEntry() {
1190
21958
  env()->id_to_function_map.erase(id_);
1191
21958
  script_.ClearWeak();
1192
43918
}
1193
1194
113
static void StartSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1195
113
  int ret = SigintWatchdogHelper::GetInstance()->Start();
1196
339
  args.GetReturnValue().Set(ret == 0);
1197
113
}
1198
1199
111
static void StopSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1200
111
  bool had_pending_signals = SigintWatchdogHelper::GetInstance()->Stop();
1201
333
  args.GetReturnValue().Set(had_pending_signals);
1202
111
}
1203
1204
3
static void WatchdogHasPendingSigint(const FunctionCallbackInfo<Value>& args) {
1205
3
  bool ret = SigintWatchdogHelper::GetInstance()->HasPendingSignal();
1206
9
  args.GetReturnValue().Set(ret);
1207
3
}
1208
1209
7
static void MeasureMemory(const FunctionCallbackInfo<Value>& args) {
1210
14
  CHECK(args[0]->IsInt32());
1211
21
  int32_t mode = args[0].As<v8::Int32>()->Value();
1212
7
  Isolate* isolate = args.GetIsolate();
1213
7
  Environment* env = Environment::GetCurrent(args);
1214
  Local<Context> context;
1215
21
  if (args[1]->IsUndefined()) {
1216
4
    context = isolate->GetCurrentContext();
1217
  } else {
1218
6
    CHECK(args[1]->IsObject());
1219
    ContextifyContext* sandbox =
1220
3
        ContextifyContext::ContextFromContextifiedSandbox(env,
1221
9
                                                          args[1].As<Object>());
1222
3
    CHECK_NOT_NULL(sandbox);
1223
3
    context = sandbox->context();
1224
3
    if (context.IsEmpty()) {  // Not yet fully initilaized
1225
      return;
1226
    }
1227
  }
1228
  v8::Local<v8::Promise> promise;
1229
14
  if (!isolate->MeasureMemory(context, static_cast<v8::MeasureMemoryMode>(mode))
1230
7
           .ToLocal(&promise)) {
1231
    return;
1232
  }
1233
14
  args.GetReturnValue().Set(promise);
1234
}
1235
1236
4359
void Initialize(Local<Object> target,
1237
                Local<Value> unused,
1238
                Local<Context> context,
1239
                void* priv) {
1240
4359
  Environment* env = Environment::GetCurrent(context);
1241
4359
  Isolate* isolate = env->isolate();
1242
4359
  ContextifyContext::Init(env, target);
1243
4359
  ContextifyScript::Init(env, target);
1244
1245
4359
  env->SetMethod(target, "startSigintWatchdog", StartSigintWatchdog);
1246
4359
  env->SetMethod(target, "stopSigintWatchdog", StopSigintWatchdog);
1247
  // Used in tests.
1248
  env->SetMethodNoSideEffect(
1249
4359
      target, "watchdogHasPendingSigint", WatchdogHasPendingSigint);
1250
1251
  {
1252
4359
    Local<FunctionTemplate> tpl = FunctionTemplate::New(env->isolate());
1253
8718
    tpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "CompiledFnEntry"));
1254
8718
    tpl->InstanceTemplate()->SetInternalFieldCount(1);
1255
1256
4359
    env->set_compiled_fn_entry_template(tpl->InstanceTemplate());
1257
  }
1258
1259
4359
  Local<Object> constants = Object::New(env->isolate());
1260
4359
  Local<Object> measure_memory = Object::New(env->isolate());
1261
4359
  Local<Object> memory_mode = Object::New(env->isolate());
1262
4359
  MeasureMemoryMode SUMMARY = MeasureMemoryMode::kSummary;
1263
4359
  MeasureMemoryMode DETAILED = MeasureMemoryMode::kDetailed;
1264
17436
  NODE_DEFINE_CONSTANT(memory_mode, SUMMARY);
1265
17436
  NODE_DEFINE_CONSTANT(memory_mode, DETAILED);
1266
13077
  READONLY_PROPERTY(measure_memory, "mode", memory_mode);
1267
13077
  READONLY_PROPERTY(constants, "measureMemory", measure_memory);
1268
13077
  target->Set(context, env->constants_string(), constants).Check();
1269
1270
4359
  env->SetMethod(target, "measureMemory", MeasureMemory);
1271
4359
}
1272
1273
}  // namespace contextify
1274
}  // namespace node
1275
1276
4201
NODE_MODULE_CONTEXT_AWARE_INTERNAL(contextify, node::contextify::Initialize)