GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_contextify.cc Lines: 621 675 92.0 %
Date: 2022-11-08 04:21:23 Branches: 299 464 64.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 "base_object-inl.h"
25
#include "memory_tracker-inl.h"
26
#include "module_wrap.h"
27
#include "node_context_data.h"
28
#include "node_errors.h"
29
#include "node_external_reference.h"
30
#include "node_internals.h"
31
#include "node_snapshot_builder.h"
32
#include "node_watchdog.h"
33
#include "util-inl.h"
34
35
namespace node {
36
namespace contextify {
37
38
using errors::TryCatchScope;
39
40
using v8::Array;
41
using v8::ArrayBufferView;
42
using v8::Boolean;
43
using v8::Context;
44
using v8::EscapableHandleScope;
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::Isolate;
52
using v8::Local;
53
using v8::Maybe;
54
using v8::MaybeLocal;
55
using v8::MeasureMemoryExecution;
56
using v8::MeasureMemoryMode;
57
using v8::MicrotaskQueue;
58
using v8::MicrotasksPolicy;
59
using v8::Name;
60
using v8::NamedPropertyHandlerConfiguration;
61
using v8::Number;
62
using v8::Object;
63
using v8::ObjectTemplate;
64
using v8::PrimitiveArray;
65
using v8::Promise;
66
using v8::PropertyAttribute;
67
using v8::PropertyCallbackInfo;
68
using v8::PropertyDescriptor;
69
using v8::PropertyHandlerFlags;
70
using v8::Script;
71
using v8::ScriptCompiler;
72
using v8::ScriptOrigin;
73
using v8::String;
74
using v8::Uint32;
75
using v8::UnboundScript;
76
using v8::Value;
77
using v8::WeakCallbackInfo;
78
using v8::WeakCallbackType;
79
80
// The vm module executes code in a sandboxed environment with a different
81
// global object than the rest of the code. This is achieved by applying
82
// every call that changes or queries a property on the global `this` in the
83
// sandboxed code, to the sandbox object.
84
//
85
// The implementation uses V8's interceptors for methods like `set`, `get`,
86
// `delete`, `defineProperty`, and for any query of the property attributes.
87
// Property handlers with interceptors are set on the object template for
88
// the sandboxed code. Handlers for both named properties and for indexed
89
// properties are used. Their functionality is almost identical, the indexed
90
// interceptors mostly just call the named interceptors.
91
//
92
// For every `get` of a global property in the sandboxed context, the
93
// interceptor callback checks the sandbox object for the property.
94
// If the property is defined on the sandbox, that result is returned to
95
// the original call instead of finishing the query on the global object.
96
//
97
// For every `set` of a global property, the interceptor callback defines or
98
// changes the property both on the sandbox and the global proxy.
99
100
namespace {
101
102
// Convert an int to a V8 Name (String or Symbol).
103
3
Local<Name> Uint32ToName(Local<Context> context, uint32_t index) {
104
6
  return Uint32::New(context->GetIsolate(), index)->ToString(context)
105
3
      .ToLocalChecked();
106
}
107
108
}  // anonymous namespace
109
110
631
BaseObjectPtr<ContextifyContext> ContextifyContext::New(
111
    Environment* env,
112
    Local<Object> sandbox_obj,
113
    const ContextOptions& options) {
114
1262
  HandleScope scope(env->isolate());
115
631
  InitializeGlobalTemplates(env->isolate_data());
116
631
  Local<ObjectTemplate> object_template = env->contextify_global_template();
117
  DCHECK(!object_template.IsEmpty());
118
631
  bool use_node_snapshot = per_process::cli_options->node_snapshot;
119
  const SnapshotData* snapshot_data =
120
631
      use_node_snapshot ? SnapshotBuilder::GetEmbeddedSnapshotData() : nullptr;
121
122
  MicrotaskQueue* queue =
123
      options.microtask_queue_wrap
124
631
          ? options.microtask_queue_wrap->microtask_queue().get()
125
1888
          : env->isolate()->GetCurrentContext()->GetMicrotaskQueue();
126
127
  Local<Context> v8_context;
128
631
  if (!(CreateV8Context(env->isolate(), object_template, snapshot_data, queue)
129
631
            .ToLocal(&v8_context))) {
130
    // Allocation failure, maximum call stack size reached, termination, etc.
131
    return BaseObjectPtr<ContextifyContext>();
132
  }
133
631
  return New(v8_context, env, sandbox_obj, options);
134
}
135
136
void ContextifyContext::MemoryInfo(MemoryTracker* tracker) const {
137
  if (microtask_queue_wrap_) {
138
    tracker->TrackField("microtask_queue_wrap",
139
                        microtask_queue_wrap_->object());
140
  }
141
}
142
143
631
ContextifyContext::ContextifyContext(Environment* env,
144
                                     Local<Object> wrapper,
145
                                     Local<Context> v8_context,
146
631
                                     const ContextOptions& options)
147
    : BaseObject(env, wrapper),
148
631
      microtask_queue_wrap_(options.microtask_queue_wrap) {
149
631
  context_.Reset(env->isolate(), v8_context);
150
  // This should only be done after the initial initializations of the context
151
  // global object is finished.
152
  DCHECK_NULL(v8_context->GetAlignedPointerFromEmbedderData(
153
      ContextEmbedderIndex::kContextifyContext));
154
631
  v8_context->SetAlignedPointerInEmbedderData(
155
      ContextEmbedderIndex::kContextifyContext, this);
156
  // It's okay to make this reference weak - V8 would create an internal
157
  // reference to this context via the constructor of the wrapper.
158
  // As long as the wrapper is alive, it's constructor is alive, and so
159
  // is the context.
160
631
  context_.SetWeak();
161
631
}
162
163
3108
ContextifyContext::~ContextifyContext() {
164
1036
  Isolate* isolate = env()->isolate();
165
2072
  HandleScope scope(isolate);
166
167
1036
  env()->UntrackContext(PersistentToLocal::Weak(isolate, context_));
168
1036
  context_.Reset();
169
2072
}
170
171
1430
void ContextifyContext::InitializeGlobalTemplates(IsolateData* isolate_data) {
172
2860
  if (!isolate_data->contextify_global_template().IsEmpty()) {
173
631
    return;
174
  }
175
  DCHECK(isolate_data->contextify_wrapper_template().IsEmpty());
176
  Local<FunctionTemplate> global_func_template =
177
799
      FunctionTemplate::New(isolate_data->isolate());
178
  Local<ObjectTemplate> global_object_template =
179
799
      global_func_template->InstanceTemplate();
180
181
  NamedPropertyHandlerConfiguration config(
182
      PropertyGetterCallback,
183
      PropertySetterCallback,
184
      PropertyDescriptorCallback,
185
      PropertyDeleterCallback,
186
      PropertyEnumeratorCallback,
187
      PropertyDefinerCallback,
188
      {},
189
799
      PropertyHandlerFlags::kHasNoSideEffect);
190
191
  IndexedPropertyHandlerConfiguration indexed_config(
192
      IndexedPropertyGetterCallback,
193
      IndexedPropertySetterCallback,
194
      IndexedPropertyDescriptorCallback,
195
      IndexedPropertyDeleterCallback,
196
      PropertyEnumeratorCallback,
197
      IndexedPropertyDefinerCallback,
198
      {},
199
799
      PropertyHandlerFlags::kHasNoSideEffect);
200
201
799
  global_object_template->SetHandler(config);
202
799
  global_object_template->SetHandler(indexed_config);
203
799
  isolate_data->set_contextify_global_template(global_object_template);
204
205
  Local<FunctionTemplate> wrapper_func_template =
206
799
      BaseObject::MakeLazilyInitializedJSTemplate(isolate_data);
207
  Local<ObjectTemplate> wrapper_object_template =
208
799
      wrapper_func_template->InstanceTemplate();
209
799
  isolate_data->set_contextify_wrapper_template(wrapper_object_template);
210
}
211
212
639
MaybeLocal<Context> ContextifyContext::CreateV8Context(
213
    Isolate* isolate,
214
    Local<ObjectTemplate> object_template,
215
    const SnapshotData* snapshot_data,
216
    MicrotaskQueue* queue) {
217
639
  EscapableHandleScope scope(isolate);
218
219
  Local<Context> ctx;
220
639
  if (snapshot_data == nullptr) {
221
    ctx = Context::New(isolate,
222
                       nullptr,  // extensions
223
                       object_template,
224
                       {},  // global object
225
                       {},  // deserialization callback
226
20
                       queue);
227

20
    if (ctx.IsEmpty() || InitializeBaseContextForSnapshot(ctx).IsNothing()) {
228
      return MaybeLocal<Context>();
229
    }
230
1258
  } else if (!Context::FromSnapshot(isolate,
231
                                    SnapshotData::kNodeVMContextIndex,
232
                                    {},       // deserialization callback
233
                                    nullptr,  // extensions
234
                                    {},       // global object
235
629
                                    queue)
236
629
                  .ToLocal(&ctx)) {
237
    return MaybeLocal<Context>();
238
  }
239
240
639
  return scope.Escape(ctx);
241
}
242
243
631
BaseObjectPtr<ContextifyContext> ContextifyContext::New(
244
    Local<Context> v8_context,
245
    Environment* env,
246
    Local<Object> sandbox_obj,
247
    const ContextOptions& options) {
248
1262
  HandleScope scope(env->isolate());
249
  // This only initializes part of the context. The primordials are
250
  // only initilaized when needed because even deserializing them slows
251
  // things down significantly and they are only needed in rare occasions
252
  // in the vm contexts.
253
1262
  if (InitializeContextRuntime(v8_context).IsNothing()) {
254
    return BaseObjectPtr<ContextifyContext>();
255
  }
256
257
631
  Local<Context> main_context = env->context();
258
631
  Local<Object> new_context_global = v8_context->Global();
259
631
  v8_context->SetSecurityToken(main_context->GetSecurityToken());
260
261
  // We need to tie the lifetime of the sandbox object with the lifetime of
262
  // newly created context. We do this by making them hold references to each
263
  // other. The context can directly hold a reference to the sandbox as an
264
  // embedder data field. The sandbox uses a private symbol to hold a reference
265
  // to the ContextifyContext wrapper which in turn internally references
266
  // the context from its constructor.
267
631
  v8_context->SetEmbedderData(ContextEmbedderIndex::kSandboxObject,
268
                              sandbox_obj);
269
270
  // Delegate the code generation validation to
271
  // node::ModifyCodeGenerationFromStrings.
272
631
  v8_context->AllowCodeGenerationFromStrings(false);
273
631
  v8_context->SetEmbedderData(
274
      ContextEmbedderIndex::kAllowCodeGenerationFromStrings,
275
      options.allow_code_gen_strings);
276
631
  v8_context->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
277
                              options.allow_code_gen_wasm);
278
279
1262
  Utf8Value name_val(env->isolate(), options.name);
280
1893
  ContextInfo info(*name_val);
281
631
  if (!options.origin.IsEmpty()) {
282
4
    Utf8Value origin_val(env->isolate(), options.origin);
283
2
    info.origin = *origin_val;
284
  }
285
286
1262
  BaseObjectPtr<ContextifyContext> result;
287
  Local<Object> wrapper;
288
  {
289
631
    Context::Scope context_scope(v8_context);
290
631
    Local<String> ctor_name = sandbox_obj->GetConstructorName();
291

1897
    if (!ctor_name->Equals(v8_context, env->object_string()).FromMaybe(false) &&
292
        new_context_global
293
631
            ->DefineOwnProperty(
294
                v8_context,
295
                v8::Symbol::GetToStringTag(env->isolate()),
296
                ctor_name,
297
639
                static_cast<v8::PropertyAttribute>(v8::DontEnum))
298
4
            .IsNothing()) {
299
      return BaseObjectPtr<ContextifyContext>();
300
    }
301
631
    env->AssignToContext(v8_context, nullptr, info);
302
303
631
    if (!env->contextify_wrapper_template()
304
631
             ->NewInstance(v8_context)
305
631
             .ToLocal(&wrapper)) {
306
      return BaseObjectPtr<ContextifyContext>();
307
    }
308
309
    result =
310
631
        MakeBaseObject<ContextifyContext>(env, wrapper, v8_context, options);
311
    // The only strong reference to the wrapper will come from the sandbox.
312
631
    result->MakeWeak();
313
  }
314
315
631
  if (sandbox_obj
316
631
          ->SetPrivate(
317
631
              v8_context, env->contextify_context_private_symbol(), wrapper)
318
631
          .IsNothing()) {
319
    return BaseObjectPtr<ContextifyContext>();
320
  }
321
322
631
  return result;
323
}
324
325
788
void ContextifyContext::Init(Environment* env, Local<Object> target) {
326
788
  Local<Context> context = env->context();
327
788
  SetMethod(context, target, "makeContext", MakeContext);
328
788
  SetMethod(context, target, "isContext", IsContext);
329
788
  SetMethod(context, target, "compileFunction", CompileFunction);
330
788
}
331
332
5594
void ContextifyContext::RegisterExternalReferences(
333
    ExternalReferenceRegistry* registry) {
334
5594
  registry->Register(MakeContext);
335
5594
  registry->Register(IsContext);
336
5594
  registry->Register(CompileFunction);
337
5594
  registry->Register(PropertyGetterCallback);
338
5594
  registry->Register(PropertySetterCallback);
339
5594
  registry->Register(PropertyDescriptorCallback);
340
5594
  registry->Register(PropertyDeleterCallback);
341
5594
  registry->Register(PropertyEnumeratorCallback);
342
5594
  registry->Register(PropertyDefinerCallback);
343
5594
  registry->Register(IndexedPropertyGetterCallback);
344
5594
  registry->Register(IndexedPropertySetterCallback);
345
5594
  registry->Register(IndexedPropertyDescriptorCallback);
346
5594
  registry->Register(IndexedPropertyDeleterCallback);
347
5594
  registry->Register(IndexedPropertyDefinerCallback);
348
5594
}
349
350
// makeContext(sandbox, name, origin, strings, wasm);
351
631
void ContextifyContext::MakeContext(const FunctionCallbackInfo<Value>& args) {
352
631
  Environment* env = Environment::GetCurrent(args);
353
354
631
  CHECK_EQ(args.Length(), 6);
355
631
  CHECK(args[0]->IsObject());
356
1262
  Local<Object> sandbox = args[0].As<Object>();
357
358
  // Don't allow contextifying a sandbox multiple times.
359
1262
  CHECK(
360
      !sandbox->HasPrivate(
361
          env->context(),
362
          env->contextify_context_private_symbol()).FromJust());
363
364
631
  ContextOptions options;
365
366
1262
  CHECK(args[1]->IsString());
367
1262
  options.name = args[1].As<String>();
368
369

2520
  CHECK(args[2]->IsString() || args[2]->IsUndefined());
370
1262
  if (args[2]->IsString()) {
371
4
    options.origin = args[2].As<String>();
372
  }
373
374
631
  CHECK(args[3]->IsBoolean());
375
1262
  options.allow_code_gen_strings = args[3].As<Boolean>();
376
377
631
  CHECK(args[4]->IsBoolean());
378
1262
  options.allow_code_gen_wasm = args[4].As<Boolean>();
379
380
631
  if (args[5]->IsObject() &&
381

641
      !env->microtask_queue_ctor_template().IsEmpty() &&
382

646
      env->microtask_queue_ctor_template()->HasInstance(args[5])) {
383
5
    options.microtask_queue_wrap.reset(
384
10
        Unwrap<MicrotaskQueueWrap>(args[5].As<Object>()));
385
  }
386
387
631
  TryCatchScope try_catch(env);
388
  BaseObjectPtr<ContextifyContext> context_ptr =
389
631
      ContextifyContext::New(env, sandbox, options);
390
391
631
  if (try_catch.HasCaught()) {
392
    if (!try_catch.HasTerminated())
393
      try_catch.ReThrow();
394
    return;
395
  }
396
}
397
398
399
6111
void ContextifyContext::IsContext(const FunctionCallbackInfo<Value>& args) {
400
6111
  Environment* env = Environment::GetCurrent(args);
401
402
6111
  CHECK(args[0]->IsObject());
403
12222
  Local<Object> sandbox = args[0].As<Object>();
404
405
  Maybe<bool> result =
406
      sandbox->HasPrivate(env->context(),
407
6111
                          env->contextify_context_private_symbol());
408
12222
  args.GetReturnValue().Set(result.FromJust());
409
6111
}
410
411
412
void ContextifyContext::WeakCallback(
413
    const WeakCallbackInfo<ContextifyContext>& data) {
414
  ContextifyContext* context = data.GetParameter();
415
  delete context;
416
}
417
418
// static
419
5422
ContextifyContext* ContextifyContext::ContextFromContextifiedSandbox(
420
    Environment* env,
421
    const Local<Object>& sandbox) {
422
  Local<Value> context_global;
423
5422
  if (sandbox
424
5422
          ->GetPrivate(env->context(), env->contextify_context_private_symbol())
425

10844
          .ToLocal(&context_global) &&
426
5422
      context_global->IsObject()) {
427
5422
    return Unwrap<ContextifyContext>(context_global.As<Object>());
428
  }
429
  return nullptr;
430
}
431
432
template <typename T>
433
2099006
ContextifyContext* ContextifyContext::Get(const PropertyCallbackInfo<T>& args) {
434
2099006
  return Get(args.This());
435
}
436
437
1049503
ContextifyContext* ContextifyContext::Get(Local<Object> object) {
438
  Local<Context> context;
439
2099006
  if (!object->GetCreationContext().ToLocal(&context)) {
440
    return nullptr;
441
  }
442
1049503
  if (!ContextEmbedderTag::IsNodeContext(context)) {
443
45
    return nullptr;
444
  }
445
  return static_cast<ContextifyContext*>(
446
1049458
      context->GetAlignedPointerFromEmbedderData(
447
1049458
          ContextEmbedderIndex::kContextifyContext));
448
}
449
450
1049503
bool ContextifyContext::IsStillInitializing(const ContextifyContext* ctx) {
451

1049503
  return ctx == nullptr || ctx->context_.IsEmpty();
452
}
453
454
// static
455
1048989
void ContextifyContext::PropertyGetterCallback(
456
    Local<Name> property,
457
    const PropertyCallbackInfo<Value>& args) {
458
1048989
  ContextifyContext* ctx = ContextifyContext::Get(args);
459
460
  // Still initializing
461
1048989
  if (IsStillInitializing(ctx)) return;
462
463
1048344
  Local<Context> context = ctx->context();
464
1048344
  Local<Object> sandbox = ctx->sandbox();
465
  MaybeLocal<Value> maybe_rv =
466
1048344
      sandbox->GetRealNamedProperty(context, property);
467
1048344
  if (maybe_rv.IsEmpty()) {
468
    maybe_rv =
469
88176
        ctx->global_proxy()->GetRealNamedProperty(context, property);
470
  }
471
472
  Local<Value> rv;
473
1048344
  if (maybe_rv.ToLocal(&rv)) {
474
1048275
    if (rv == sandbox)
475
10
      rv = ctx->global_proxy();
476
477
2096550
    args.GetReturnValue().Set(rv);
478
  }
479
}
480
481
// static
482
175
void ContextifyContext::PropertySetterCallback(
483
    Local<Name> property,
484
    Local<Value> value,
485
    const PropertyCallbackInfo<Value>& args) {
486
175
  ContextifyContext* ctx = ContextifyContext::Get(args);
487
488
  // Still initializing
489
189
  if (IsStillInitializing(ctx)) return;
490
491
152
  Local<Context> context = ctx->context();
492
152
  PropertyAttribute attributes = PropertyAttribute::None;
493
152
  bool is_declared_on_global_proxy = ctx->global_proxy()
494
152
      ->GetRealNamedPropertyAttributes(context, property)
495
152
      .To(&attributes);
496
152
  bool read_only =
497
152
      static_cast<int>(attributes) &
498
      static_cast<int>(PropertyAttribute::ReadOnly);
499
500
152
  bool is_declared_on_sandbox = ctx->sandbox()
501
152
      ->GetRealNamedPropertyAttributes(context, property)
502
152
      .To(&attributes);
503
300
  read_only = read_only ||
504
148
      (static_cast<int>(attributes) &
505
      static_cast<int>(PropertyAttribute::ReadOnly));
506
507
152
  if (read_only)
508
13
    return;
509
510
  // true for x = 5
511
  // false for this.x = 5
512
  // false for Object.defineProperty(this, 'foo', ...)
513
  // false for vmResult.x = 5 where vmResult = vm.runInContext();
514
278
  bool is_contextual_store = ctx->global_proxy() != args.This();
515
516
  // Indicator to not return before setting (undeclared) function declarations
517
  // on the sandbox in strict mode, i.e. args.ShouldThrowOnError() = true.
518
  // True for 'function f() {}', 'this.f = function() {}',
519
  // 'var f = function()'.
520
  // In effect only for 'function f() {}' because
521
  // var f = function(), is_declared = true
522
  // this.f = function() {}, is_contextual_store = false.
523
139
  bool is_function = value->IsFunction();
524
525

139
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
526


230
  if (!is_declared && args.ShouldThrowOnError() && is_contextual_store &&
527
30
      !is_function)
528
1
    return;
529
530
276
  USE(ctx->sandbox()->Set(context, property, value));
531
276
  args.GetReturnValue().Set(value);
532
}
533
534
// static
535
59
void ContextifyContext::PropertyDescriptorCallback(
536
    Local<Name> property,
537
    const PropertyCallbackInfo<Value>& args) {
538
59
  ContextifyContext* ctx = ContextifyContext::Get(args);
539
540
  // Still initializing
541
59
  if (IsStillInitializing(ctx)) return;
542
543
55
  Local<Context> context = ctx->context();
544
545
55
  Local<Object> sandbox = ctx->sandbox();
546
547

110
  if (sandbox->HasOwnProperty(context, property).FromMaybe(false)) {
548
    Local<Value> desc;
549
78
    if (sandbox->GetOwnPropertyDescriptor(context, property).ToLocal(&desc)) {
550
78
      args.GetReturnValue().Set(desc);
551
    }
552
  }
553
}
554
555
// static
556
19
void ContextifyContext::PropertyDefinerCallback(
557
    Local<Name> property,
558
    const PropertyDescriptor& desc,
559
    const PropertyCallbackInfo<Value>& args) {
560
19
  ContextifyContext* ctx = ContextifyContext::Get(args);
561
562
  // Still initializing
563
19
  if (IsStillInitializing(ctx)) return;
564
565
15
  Local<Context> context = ctx->context();
566
15
  Isolate* isolate = context->GetIsolate();
567
568
15
  PropertyAttribute attributes = PropertyAttribute::None;
569
  bool is_declared =
570
15
      ctx->global_proxy()->GetRealNamedPropertyAttributes(context,
571
15
                                                          property)
572
15
          .To(&attributes);
573
15
  bool read_only =
574
15
      static_cast<int>(attributes) &
575
          static_cast<int>(PropertyAttribute::ReadOnly);
576
577
  // If the property is set on the global as read_only, don't change it on
578
  // the global or sandbox.
579

15
  if (is_declared && read_only)
580
    return;
581
582
15
  Local<Object> sandbox = ctx->sandbox();
583
584
  auto define_prop_on_sandbox =
585
15
      [&] (PropertyDescriptor* desc_for_sandbox) {
586
15
        if (desc.has_enumerable()) {
587
2
          desc_for_sandbox->set_enumerable(desc.enumerable());
588
        }
589
15
        if (desc.has_configurable()) {
590
1
          desc_for_sandbox->set_configurable(desc.configurable());
591
        }
592
        // Set the property on the sandbox.
593
15
        USE(sandbox->DefineProperty(context, property, *desc_for_sandbox));
594
30
      };
595
596

15
  if (desc.has_get() || desc.has_set()) {
597
    PropertyDescriptor desc_for_sandbox(
598
15
        desc.has_get() ? desc.get() : Undefined(isolate).As<Value>(),
599

23
        desc.has_set() ? desc.set() : Undefined(isolate).As<Value>());
600
601
5
    define_prop_on_sandbox(&desc_for_sandbox);
602
  } else {
603
    Local<Value> value =
604
12
        desc.has_value() ? desc.value() : Undefined(isolate).As<Value>();
605
606
10
    if (desc.has_writable()) {
607
      PropertyDescriptor desc_for_sandbox(value, desc.writable());
608
      define_prop_on_sandbox(&desc_for_sandbox);
609
    } else {
610
20
      PropertyDescriptor desc_for_sandbox(value);
611
10
      define_prop_on_sandbox(&desc_for_sandbox);
612
    }
613
  }
614
}
615
616
// static
617
2
void ContextifyContext::PropertyDeleterCallback(
618
    Local<Name> property,
619
    const PropertyCallbackInfo<Boolean>& args) {
620
2
  ContextifyContext* ctx = ContextifyContext::Get(args);
621
622
  // Still initializing
623
3
  if (IsStillInitializing(ctx)) return;
624
625
4
  Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), property);
626
627

4
  if (success.FromMaybe(false))
628
1
    return;
629
630
  // Delete failed on the sandbox, intercept and do not delete on
631
  // the global object.
632
2
  args.GetReturnValue().Set(false);
633
}
634
635
// static
636
256
void ContextifyContext::PropertyEnumeratorCallback(
637
    const PropertyCallbackInfo<Array>& args) {
638
256
  ContextifyContext* ctx = ContextifyContext::Get(args);
639
640
  // Still initializing
641
256
  if (IsStillInitializing(ctx)) return;
642
643
  Local<Array> properties;
644
645
768
  if (!ctx->sandbox()->GetPropertyNames(ctx->context()).ToLocal(&properties))
646
    return;
647
648
512
  args.GetReturnValue().Set(properties);
649
}
650
651
// static
652
void ContextifyContext::IndexedPropertyGetterCallback(
653
    uint32_t index,
654
    const PropertyCallbackInfo<Value>& args) {
655
  ContextifyContext* ctx = ContextifyContext::Get(args);
656
657
  // Still initializing
658
  if (IsStillInitializing(ctx)) return;
659
660
  ContextifyContext::PropertyGetterCallback(
661
      Uint32ToName(ctx->context(), index), args);
662
}
663
664
665
1
void ContextifyContext::IndexedPropertySetterCallback(
666
    uint32_t index,
667
    Local<Value> value,
668
    const PropertyCallbackInfo<Value>& args) {
669
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
670
671
  // Still initializing
672
1
  if (IsStillInitializing(ctx)) return;
673
674
1
  ContextifyContext::PropertySetterCallback(
675
      Uint32ToName(ctx->context(), index), value, args);
676
}
677
678
// static
679
1
void ContextifyContext::IndexedPropertyDescriptorCallback(
680
    uint32_t index,
681
    const PropertyCallbackInfo<Value>& args) {
682
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
683
684
  // Still initializing
685
1
  if (IsStillInitializing(ctx)) return;
686
687
1
  ContextifyContext::PropertyDescriptorCallback(
688
      Uint32ToName(ctx->context(), index), args);
689
}
690
691
692
1
void ContextifyContext::IndexedPropertyDefinerCallback(
693
    uint32_t index,
694
    const PropertyDescriptor& desc,
695
    const PropertyCallbackInfo<Value>& args) {
696
1
  ContextifyContext* ctx = ContextifyContext::Get(args);
697
698
  // Still initializing
699
1
  if (IsStillInitializing(ctx)) return;
700
701
1
  ContextifyContext::PropertyDefinerCallback(
702
      Uint32ToName(ctx->context(), index), desc, args);
703
}
704
705
// static
706
void ContextifyContext::IndexedPropertyDeleterCallback(
707
    uint32_t index,
708
    const PropertyCallbackInfo<Boolean>& args) {
709
  ContextifyContext* ctx = ContextifyContext::Get(args);
710
711
  // Still initializing
712
  if (IsStillInitializing(ctx)) return;
713
714
  Maybe<bool> success = ctx->sandbox()->Delete(ctx->context(), index);
715
716
  if (success.FromMaybe(false))
717
    return;
718
719
  // Delete failed on the sandbox, intercept and do not delete on
720
  // the global object.
721
  args.GetReturnValue().Set(false);
722
}
723
724
788
void ContextifyScript::Init(Environment* env, Local<Object> target) {
725
788
  Isolate* isolate = env->isolate();
726
1576
  HandleScope scope(env->isolate());
727
  Local<String> class_name =
728
788
      FIXED_ONE_BYTE_STRING(env->isolate(), "ContextifyScript");
729
730
788
  Local<FunctionTemplate> script_tmpl = NewFunctionTemplate(isolate, New);
731
1576
  script_tmpl->InstanceTemplate()->SetInternalFieldCount(
732
      ContextifyScript::kInternalFieldCount);
733
788
  script_tmpl->SetClassName(class_name);
734
788
  SetProtoMethod(isolate, script_tmpl, "createCachedData", CreateCachedData);
735
788
  SetProtoMethod(isolate, script_tmpl, "runInContext", RunInContext);
736
737
788
  Local<Context> context = env->context();
738
739
788
  target->Set(context, class_name,
740
1576
      script_tmpl->GetFunction(context).ToLocalChecked()).Check();
741
788
  env->set_script_context_constructor_template(script_tmpl);
742
788
}
743
744
5594
void ContextifyScript::RegisterExternalReferences(
745
    ExternalReferenceRegistry* registry) {
746
5594
  registry->Register(New);
747
5594
  registry->Register(CreateCachedData);
748
5594
  registry->Register(RunInContext);
749
5594
}
750
751
5785
void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
752
5785
  Environment* env = Environment::GetCurrent(args);
753
5785
  Isolate* isolate = env->isolate();
754
5785
  Local<Context> context = env->context();
755
756
5785
  CHECK(args.IsConstructCall());
757
758
5785
  const int argc = args.Length();
759
5785
  CHECK_GE(argc, 2);
760
761
11570
  CHECK(args[0]->IsString());
762
11570
  Local<String> code = args[0].As<String>();
763
764
11570
  CHECK(args[1]->IsString());
765
5785
  Local<String> filename = args[1].As<String>();
766
767
5785
  int line_offset = 0;
768
5785
  int column_offset = 0;
769
  Local<ArrayBufferView> cached_data_buf;
770
5785
  bool produce_cached_data = false;
771
5785
  Local<Context> parsing_context = context;
772
773
5785
  if (argc > 2) {
774
    // new ContextifyScript(code, filename, lineOffset, columnOffset,
775
    //                      cachedData, produceCachedData, parsingContext)
776
5785
    CHECK_EQ(argc, 7);
777
5785
    CHECK(args[2]->IsNumber());
778
11570
    line_offset = args[2].As<Int32>()->Value();
779
5785
    CHECK(args[3]->IsNumber());
780
11570
    column_offset = args[3].As<Int32>()->Value();
781
11570
    if (!args[4]->IsUndefined()) {
782
25
      CHECK(args[4]->IsArrayBufferView());
783
50
      cached_data_buf = args[4].As<ArrayBufferView>();
784
    }
785
5785
    CHECK(args[5]->IsBoolean());
786
5785
    produce_cached_data = args[5]->IsTrue();
787
11570
    if (!args[6]->IsUndefined()) {
788
2521
      CHECK(args[6]->IsObject());
789
      ContextifyContext* sandbox =
790
2521
          ContextifyContext::ContextFromContextifiedSandbox(
791
5042
              env, args[6].As<Object>());
792
2521
      CHECK_NOT_NULL(sandbox);
793
2521
      parsing_context = sandbox->context();
794
    }
795
  }
796
797
  ContextifyScript* contextify_script =
798
5785
      new ContextifyScript(env, args.This());
799
800
5785
  if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
801
5785
          TRACING_CATEGORY_NODE2(vm, script)) != 0) {
802
14
    Utf8Value fn(isolate, filename);
803

14
    TRACE_EVENT_BEGIN1(TRACING_CATEGORY_NODE2(vm, script),
804
                       "ContextifyScript::New",
805
                       "filename",
806
                       TRACE_STR_COPY(*fn));
807
  }
808
809
5785
  ScriptCompiler::CachedData* cached_data = nullptr;
810
5785
  if (!cached_data_buf.IsEmpty()) {
811
50
    uint8_t* data = static_cast<uint8_t*>(cached_data_buf->Buffer()->Data());
812
25
    cached_data = new ScriptCompiler::CachedData(
813
25
        data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
814
  }
815
816
  Local<PrimitiveArray> host_defined_options =
817
5785
      PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
818
11570
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kType,
819
                            Number::New(isolate, loader::ScriptType::kScript));
820
11570
  host_defined_options->Set(isolate, loader::HostDefinedOptions::kID,
821
5785
                            Number::New(isolate, contextify_script->id()));
822
823
  ScriptOrigin origin(isolate,
824
                      filename,
825
                      line_offset,                          // line offset
826
                      column_offset,                        // column offset
827
                      true,                                 // is cross origin
828
                      -1,                                   // script id
829
                      Local<Value>(),                       // source map URL
830
                      false,                                // is opaque (?)
831
                      false,                                // is WASM
832
                      false,                                // is ES Module
833
11570
                      host_defined_options);
834
5785
  ScriptCompiler::Source source(code, origin, cached_data);
835
5785
  ScriptCompiler::CompileOptions compile_options =
836
      ScriptCompiler::kNoCompileOptions;
837
838
5785
  if (source.GetCachedData() != nullptr)
839
25
    compile_options = ScriptCompiler::kConsumeCodeCache;
840
841
5785
  TryCatchScope try_catch(env);
842
5785
  ShouldNotAbortOnUncaughtScope no_abort_scope(env);
843
5785
  Context::Scope scope(parsing_context);
844
845
  MaybeLocal<UnboundScript> maybe_v8_script =
846
5785
      ScriptCompiler::CompileUnboundScript(isolate, &source, compile_options);
847
848
  Local<UnboundScript> v8_script;
849
5785
  if (!maybe_v8_script.ToLocal(&v8_script)) {
850
193
    errors::DecorateErrorStack(env, try_catch);
851
193
    no_abort_scope.Close();
852
193
    if (!try_catch.HasTerminated())
853
193
      try_catch.ReThrow();
854

221
    TRACE_EVENT_END0(TRACING_CATEGORY_NODE2(vm, script),
855
                     "ContextifyScript::New");
856
193
    return;
857
  }
858
5592
  contextify_script->script_.Reset(isolate, v8_script);
859
860
5592
  Local<Context> env_context = env->context();
861
5592
  if (compile_options == ScriptCompiler::kConsumeCodeCache) {
862
25
    args.This()->Set(
863
        env_context,
864
        env->cached_data_rejected_string(),
865
100
        Boolean::New(isolate, source.GetCachedData()->rejected)).Check();
866
5567
  } else if (produce_cached_data) {
867
    std::unique_ptr<ScriptCompiler::CachedData> cached_data{
868
6
        ScriptCompiler::CreateCodeCache(v8_script)};
869
6
    bool cached_data_produced = cached_data != nullptr;
870
6
    if (cached_data_produced) {
871
      MaybeLocal<Object> buf = Buffer::Copy(
872
          env,
873
12
          reinterpret_cast<const char*>(cached_data->data),
874
6
          cached_data->length);
875
6
      args.This()->Set(env_context,
876
                       env->cached_data_string(),
877
24
                       buf.ToLocalChecked()).Check();
878
    }
879
6
    args.This()->Set(
880
        env_context,
881
        env->cached_data_produced_string(),
882
24
        Boolean::New(isolate, cached_data_produced)).Check();
883
  }
884
885
5592
  args.This()
886
5592
      ->Set(env_context,
887
            env->source_map_url_string(),
888
16776
            v8_script->GetSourceMappingURL())
889
      .Check();
890
891

6398
  TRACE_EVENT_END0(TRACING_CATEGORY_NODE2(vm, script), "ContextifyScript::New");
892
}
893
894
5567
bool ContextifyScript::InstanceOf(Environment* env,
895
                                  const Local<Value>& value) {
896

11134
  return !value.IsEmpty() &&
897
16701
         env->script_context_constructor_template()->HasInstance(value);
898
}
899
900
11
void ContextifyScript::CreateCachedData(
901
    const FunctionCallbackInfo<Value>& args) {
902
11
  Environment* env = Environment::GetCurrent(args);
903
  ContextifyScript* wrapped_script;
904
11
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
905
  Local<UnboundScript> unbound_script =
906
11
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
907
  std::unique_ptr<ScriptCompiler::CachedData> cached_data(
908
22
      ScriptCompiler::CreateCodeCache(unbound_script));
909
11
  if (!cached_data) {
910
    args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked());
911
  } else {
912
    MaybeLocal<Object> buf = Buffer::Copy(
913
        env,
914
22
        reinterpret_cast<const char*>(cached_data->data),
915
11
        cached_data->length);
916
22
    args.GetReturnValue().Set(buf.ToLocalChecked());
917
  }
918
}
919
920
5567
void ContextifyScript::RunInContext(const FunctionCallbackInfo<Value>& args) {
921
5567
  Environment* env = Environment::GetCurrent(args);
922
923
  ContextifyScript* wrapped_script;
924
5567
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
925
926
5567
  CHECK_EQ(args.Length(), 5);
927

10957
  CHECK(args[0]->IsObject() || args[0]->IsNull());
928
929
  Local<Context> context;
930
5567
  std::shared_ptr<MicrotaskQueue> microtask_queue;
931
932
5567
  if (args[0]->IsObject()) {
933
2872
    Local<Object> sandbox = args[0].As<Object>();
934
    // Get the context from the sandbox
935
    ContextifyContext* contextify_context =
936
2872
        ContextifyContext::ContextFromContextifiedSandbox(env, sandbox);
937
2872
    CHECK_NOT_NULL(contextify_context);
938
2872
    CHECK_EQ(contextify_context->env(), env);
939
940
2872
    context = contextify_context->context();
941
2872
    if (context.IsEmpty()) return;
942
943
2872
    microtask_queue = contextify_context->microtask_queue();
944
  } else {
945
2695
    context = env->context();
946
  }
947
948

6371
  TRACE_EVENT0(TRACING_CATEGORY_NODE2(vm, script), "RunInContext");
949
950
5567
  CHECK(args[1]->IsNumber());
951
11134
  int64_t timeout = args[1]->IntegerValue(env->context()).FromJust();
952
953
5567
  CHECK(args[2]->IsBoolean());
954
5567
  bool display_errors = args[2]->IsTrue();
955
956
5567
  CHECK(args[3]->IsBoolean());
957
5567
  bool break_on_sigint = args[3]->IsTrue();
958
959
5567
  CHECK(args[4]->IsBoolean());
960
5567
  bool break_on_first_line = args[4]->IsTrue();
961
962
  // Do the eval within the context
963
5567
  EvalMachine(context,
964
              env,
965
              timeout,
966
              display_errors,
967
              break_on_sigint,
968
              break_on_first_line,
969
              microtask_queue,
970
              args);
971
}
972
973
5567
bool ContextifyScript::EvalMachine(Local<Context> context,
974
                                   Environment* env,
975
                                   const int64_t timeout,
976
                                   const bool display_errors,
977
                                   const bool break_on_sigint,
978
                                   const bool break_on_first_line,
979
                                   std::shared_ptr<MicrotaskQueue> mtask_queue,
980
                                   const FunctionCallbackInfo<Value>& args) {
981
5567
  Context::Scope context_scope(context);
982
983
5567
  if (!env->can_call_into_js())
984
    return false;
985
5567
  if (!ContextifyScript::InstanceOf(env, args.Holder())) {
986
    THROW_ERR_INVALID_THIS(
987
        env,
988
        "Script methods can only be called on script instances.");
989
    return false;
990
  }
991
992
11118
  TryCatchScope try_catch(env);
993
11118
  Isolate::SafeForTerminationScope safe_for_termination(env->isolate());
994
  ContextifyScript* wrapped_script;
995
5567
  ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder(), false);
996
  Local<UnboundScript> unbound_script =
997
5567
      PersistentToLocal::Default(env->isolate(), wrapped_script->script_);
998
5567
  Local<Script> script = unbound_script->BindToCurrentContext();
999
1000
#if HAVE_INSPECTOR
1001
5567
  if (break_on_first_line) {
1002
10
    env->inspector_agent()->PauseOnNextJavascriptStatement("Break on start");
1003
  }
1004
#endif
1005
1006
  MaybeLocal<Value> result;
1007
5567
  bool timed_out = false;
1008
5567
  bool received_signal = false;
1009
5567
  auto run = [&]() {
1010
5567
    MaybeLocal<Value> result = script->Run(context);
1011

5551
    if (!result.IsEmpty() && mtask_queue)
1012
2
      mtask_queue->PerformCheckpoint(env->isolate());
1013
5551
    return result;
1014
5567
  };
1015

5567
  if (break_on_sigint && timeout != -1) {
1016
    Watchdog wd(env->isolate(), timeout, &timed_out);
1017
    SigintWatchdog swd(env->isolate(), &received_signal);
1018
    result = run();
1019
5567
  } else if (break_on_sigint) {
1020
2393
    SigintWatchdog swd(env->isolate(), &received_signal);
1021
1198
    result = run();
1022
4369
  } else if (timeout != -1) {
1023
30
    Watchdog wd(env->isolate(), timeout, &timed_out);
1024
15
    result = run();
1025
  } else {
1026
4354
    result = run();
1027
  }
1028
1029
  // Convert the termination exception into a regular exception.
1030

5551
  if (timed_out || received_signal) {
1031

21
    if (!env->is_main_thread() && env->is_stopping())
1032
      return false;
1033
21
    env->isolate()->CancelTerminateExecution();
1034
    // It is possible that execution was terminated by another timeout in
1035
    // which this timeout is nested, so check whether one of the watchdogs
1036
    // from this invocation is responsible for termination.
1037
21
    if (timed_out) {
1038
10
      node::THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout);
1039
11
    } else if (received_signal) {
1040
11
      node::THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env);
1041
    }
1042
  }
1043
1044
5551
  if (try_catch.HasCaught()) {
1045

159
    if (!timed_out && !received_signal && display_errors) {
1046
      // We should decorate non-termination exceptions
1047
87
      errors::DecorateErrorStack(env, try_catch);
1048
    }
1049
1050
    // If there was an exception thrown during script execution, re-throw it.
1051
    // If one of the above checks threw, re-throw the exception instead of
1052
    // letting try_catch catch it.
1053
    // If execution has been terminated, but not by one of the watchdogs from
1054
    // this invocation, this will re-throw a `null` value.
1055
159
    if (!try_catch.HasTerminated())
1056
156
      try_catch.ReThrow();
1057
1058
159
    return false;
1059
  }
1060
1061
5392
  args.GetReturnValue().Set(result.ToLocalChecked());
1062
5392
  return true;
1063
}
1064
1065
1066
5785
ContextifyScript::ContextifyScript(Environment* env, Local<Object> object)
1067
    : BaseObject(env, object),
1068
5785
      id_(env->get_next_script_id()) {
1069
5785
  MakeWeak();
1070
5785
  env->id_to_script_map.emplace(id_, this);
1071
5785
}
1072
1073
1074
34338
ContextifyScript::~ContextifyScript() {
1075
11446
  env()->id_to_script_map.erase(id_);
1076
22892
}
1077
1078
1079
36238
void ContextifyContext::CompileFunction(
1080
    const FunctionCallbackInfo<Value>& args) {
1081
36238
  Environment* env = Environment::GetCurrent(args);
1082
36238
  Isolate* isolate = env->isolate();
1083
36238
  Local<Context> context = env->context();
1084
1085
  // Argument 1: source code
1086
72476
  CHECK(args[0]->IsString());
1087
72476
  Local<String> code = args[0].As<String>();
1088
1089
  // Argument 2: filename
1090
72476
  CHECK(args[1]->IsString());
1091
72476
  Local<String> filename = args[1].As<String>();
1092
1093
  // Argument 3: line offset
1094
36238
  CHECK(args[2]->IsNumber());
1095
72476
  int line_offset = args[2].As<Int32>()->Value();
1096
1097
  // Argument 4: column offset
1098
36238
  CHECK(args[3]->IsNumber());
1099
72476
  int column_offset = args[3].As<Int32>()->Value();
1100
1101
  // Argument 5: cached data (optional)
1102
  Local<ArrayBufferView> cached_data_buf;
1103
72476
  if (!args[4]->IsUndefined()) {
1104
    CHECK(args[4]->IsArrayBufferView());
1105
    cached_data_buf = args[4].As<ArrayBufferView>();
1106
  }
1107
1108
  // Argument 6: produce cache data
1109
36238
  CHECK(args[5]->IsBoolean());
1110
36238
  bool produce_cached_data = args[5]->IsTrue();
1111
1112
  // Argument 7: parsing context (optional)
1113
  Local<Context> parsing_context;
1114
72476
  if (!args[6]->IsUndefined()) {
1115
2
    CHECK(args[6]->IsObject());
1116
    ContextifyContext* sandbox =
1117
2
        ContextifyContext::ContextFromContextifiedSandbox(
1118
4
            env, args[6].As<Object>());
1119
2
    CHECK_NOT_NULL(sandbox);
1120
2
    parsing_context = sandbox->context();
1121
  } else {
1122
36236
    parsing_context = context;
1123
  }
1124
1125
  // Argument 8: context extensions (optional)
1126
  Local<Array> context_extensions_buf;
1127
72476
  if (!args[7]->IsUndefined()) {
1128
36238
    CHECK(args[7]->IsArray());
1129
72476
    context_extensions_buf = args[7].As<Array>();
1130
  }
1131
1132
  // Argument 9: params for the function (optional)
1133
  Local<Array> params_buf;
1134
72476
  if (!args[8]->IsUndefined()) {
1135
36231
    CHECK(args[8]->IsArray());
1136
72462
    params_buf = args[8].As<Array>();
1137
  }
1138
1139
  // Read cache from cached data buffer
1140
36238
  ScriptCompiler::CachedData* cached_data = nullptr;
1141
36238
  if (!cached_data_buf.IsEmpty()) {
1142
    uint8_t* data = static_cast<uint8_t*>(cached_data_buf->Buffer()->Data());
1143
    cached_data = new ScriptCompiler::CachedData(
1144
      data + cached_data_buf->ByteOffset(), cached_data_buf->ByteLength());
1145
  }
1146
1147
  // Get the function id
1148
36238
  uint32_t id = env->get_next_function_id();
1149
1150
  // Set host_defined_options
1151
  Local<PrimitiveArray> host_defined_options =
1152
36238
      PrimitiveArray::New(isolate, loader::HostDefinedOptions::kLength);
1153
72476
  host_defined_options->Set(
1154
      isolate,
1155
      loader::HostDefinedOptions::kType,
1156
      Number::New(isolate, loader::ScriptType::kFunction));
1157
72476
  host_defined_options->Set(
1158
      isolate, loader::HostDefinedOptions::kID, Number::New(isolate, id));
1159
1160
  ScriptOrigin origin(isolate,
1161
                      filename,
1162
                      line_offset,       // line offset
1163
                      column_offset,     // column offset
1164
                      true,              // is cross origin
1165
                      -1,                // script id
1166
                      Local<Value>(),    // source map URL
1167
                      false,             // is opaque (?)
1168
                      false,             // is WASM
1169
                      false,             // is ES Module
1170
72476
                      host_defined_options);
1171
1172
36238
  ScriptCompiler::Source source(code, origin, cached_data);
1173
  ScriptCompiler::CompileOptions options;
1174
36238
  if (source.GetCachedData() == nullptr) {
1175
36238
    options = ScriptCompiler::kNoCompileOptions;
1176
  } else {
1177
    options = ScriptCompiler::kConsumeCodeCache;
1178
  }
1179
1180
36238
  TryCatchScope try_catch(env);
1181
36238
  Context::Scope scope(parsing_context);
1182
1183
  // Read context extensions from buffer
1184
36238
  std::vector<Local<Object>> context_extensions;
1185
36238
  if (!context_extensions_buf.IsEmpty()) {
1186
72477
    for (uint32_t n = 0; n < context_extensions_buf->Length(); n++) {
1187
      Local<Value> val;
1188
2
      if (!context_extensions_buf->Get(context, n).ToLocal(&val)) return;
1189
1
      CHECK(val->IsObject());
1190
1
      context_extensions.push_back(val.As<Object>());
1191
    }
1192
  }
1193
1194
  // Read params from params buffer
1195
36238
  std::vector<Local<String>> params;
1196
36238
  if (!params_buf.IsEmpty()) {
1197
253567
    for (uint32_t n = 0; n < params_buf->Length(); n++) {
1198
      Local<Value> val;
1199
362210
      if (!params_buf->Get(context, n).ToLocal(&val)) return;
1200
362210
      CHECK(val->IsString());
1201
181105
      params.push_back(val.As<String>());
1202
    }
1203
  }
1204
1205
  MaybeLocal<Function> maybe_fn = ScriptCompiler::CompileFunction(
1206
      parsing_context,
1207
      &source,
1208
      params.size(),
1209
      params.data(),
1210
      context_extensions.size(),
1211
      context_extensions.data(),
1212
      options,
1213
36238
      v8::ScriptCompiler::NoCacheReason::kNoCacheNoReason);
1214
1215
  Local<Function> fn;
1216
36238
  if (!maybe_fn.ToLocal(&fn)) {
1217

29
    if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
1218
29
      errors::DecorateErrorStack(env, try_catch);
1219
29
      try_catch.ReThrow();
1220
    }
1221
29
    return;
1222
  }
1223
1224
  Local<Object> cache_key;
1225
36209
  if (!env->compiled_fn_entry_template()->NewInstance(
1226
72418
           context).ToLocal(&cache_key)) {
1227
    return;
1228
  }
1229
36209
  CompiledFnEntry* entry = new CompiledFnEntry(env, cache_key, id, fn);
1230
36209
  env->id_to_function_map.emplace(id, entry);
1231
1232
36209
  Local<Object> result = Object::New(isolate);
1233
108627
  if (result->Set(parsing_context, env->function_string(), fn).IsNothing())
1234
    return;
1235
72418
  if (result->Set(parsing_context, env->cache_key_string(), cache_key)
1236
36209
          .IsNothing())
1237
    return;
1238
36209
  if (result
1239
36209
          ->Set(parsing_context,
1240
                env->source_map_url_string(),
1241
108627
                fn->GetScriptOrigin().SourceMapUrl())
1242
36209
          .IsNothing())
1243
    return;
1244
1245
36209
  if (produce_cached_data) {
1246
    const std::unique_ptr<ScriptCompiler::CachedData> cached_data(
1247
1
        ScriptCompiler::CreateCodeCacheForFunction(fn));
1248
1
    bool cached_data_produced = cached_data != nullptr;
1249
1
    if (cached_data_produced) {
1250
      MaybeLocal<Object> buf = Buffer::Copy(
1251
          env,
1252
2
          reinterpret_cast<const char*>(cached_data->data),
1253
1
          cached_data->length);
1254
1
      if (result
1255
1
              ->Set(parsing_context,
1256
                    env->cached_data_string(),
1257
3
                    buf.ToLocalChecked())
1258
1
              .IsNothing())
1259
        return;
1260
    }
1261
1
    if (result
1262
1
            ->Set(parsing_context,
1263
                  env->cached_data_produced_string(),
1264
3
                  Boolean::New(isolate, cached_data_produced))
1265
1
            .IsNothing())
1266
      return;
1267
  }
1268
1269
72418
  args.GetReturnValue().Set(result);
1270
}
1271
1272
7
void CompiledFnEntry::WeakCallback(
1273
    const WeakCallbackInfo<CompiledFnEntry>& data) {
1274
7
  CompiledFnEntry* entry = data.GetParameter();
1275
7
  delete entry;
1276
7
}
1277
1278
36209
CompiledFnEntry::CompiledFnEntry(Environment* env,
1279
                                 Local<Object> object,
1280
                                 uint32_t id,
1281
36209
                                 Local<Function> fn)
1282
36209
    : BaseObject(env, object), id_(id), fn_(env->isolate(), fn) {
1283
36209
  fn_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
1284
36209
}
1285
1286
202212
CompiledFnEntry::~CompiledFnEntry() {
1287
67404
  env()->id_to_function_map.erase(id_);
1288
67404
  fn_.ClearWeak();
1289
134808
}
1290
1291
195
static void StartSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1292
195
  int ret = SigintWatchdogHelper::GetInstance()->Start();
1293
195
  args.GetReturnValue().Set(ret == 0);
1294
195
}
1295
1296
192
static void StopSigintWatchdog(const FunctionCallbackInfo<Value>& args) {
1297
192
  bool had_pending_signals = SigintWatchdogHelper::GetInstance()->Stop();
1298
192
  args.GetReturnValue().Set(had_pending_signals);
1299
192
}
1300
1301
3
static void WatchdogHasPendingSigint(const FunctionCallbackInfo<Value>& args) {
1302
3
  bool ret = SigintWatchdogHelper::GetInstance()->HasPendingSignal();
1303
3
  args.GetReturnValue().Set(ret);
1304
3
}
1305
1306
8
static void MeasureMemory(const FunctionCallbackInfo<Value>& args) {
1307
8
  CHECK(args[0]->IsInt32());
1308
8
  CHECK(args[1]->IsInt32());
1309
16
  int32_t mode = args[0].As<v8::Int32>()->Value();
1310
16
  int32_t execution = args[1].As<v8::Int32>()->Value();
1311
8
  Isolate* isolate = args.GetIsolate();
1312
1313
8
  Local<Context> current_context = isolate->GetCurrentContext();
1314
  Local<Promise::Resolver> resolver;
1315
16
  if (!Promise::Resolver::New(current_context).ToLocal(&resolver)) return;
1316
  std::unique_ptr<v8::MeasureMemoryDelegate> delegate =
1317
      v8::MeasureMemoryDelegate::Default(
1318
          isolate,
1319
          current_context,
1320
          resolver,
1321
8
          static_cast<v8::MeasureMemoryMode>(mode));
1322
8
  isolate->MeasureMemory(std::move(delegate),
1323
                         static_cast<v8::MeasureMemoryExecution>(execution));
1324
8
  Local<Promise> promise = resolver->GetPromise();
1325
1326
16
  args.GetReturnValue().Set(promise);
1327
}
1328
1329
5
MicrotaskQueueWrap::MicrotaskQueueWrap(Environment* env, Local<Object> obj)
1330
  : BaseObject(env, obj),
1331
    microtask_queue_(
1332
5
        MicrotaskQueue::New(env->isolate(), MicrotasksPolicy::kExplicit)) {
1333
5
  MakeWeak();
1334
5
}
1335
1336
const std::shared_ptr<MicrotaskQueue>&
1337
10
MicrotaskQueueWrap::microtask_queue() const {
1338
10
  return microtask_queue_;
1339
}
1340
1341
5
void MicrotaskQueueWrap::New(const FunctionCallbackInfo<Value>& args) {
1342
5
  CHECK(args.IsConstructCall());
1343
10
  new MicrotaskQueueWrap(Environment::GetCurrent(args), args.This());
1344
5
}
1345
1346
788
void MicrotaskQueueWrap::Init(Environment* env, Local<Object> target) {
1347
788
  Isolate* isolate = env->isolate();
1348
1576
  HandleScope scope(isolate);
1349
788
  Local<Context> context = env->context();
1350
788
  Local<FunctionTemplate> tmpl = NewFunctionTemplate(isolate, New);
1351
1576
  tmpl->InstanceTemplate()->SetInternalFieldCount(
1352
      ContextifyScript::kInternalFieldCount);
1353
788
  env->set_microtask_queue_ctor_template(tmpl);
1354
788
  SetConstructorFunction(context, target, "MicrotaskQueue", tmpl);
1355
788
}
1356
1357
5594
void MicrotaskQueueWrap::RegisterExternalReferences(
1358
    ExternalReferenceRegistry* registry) {
1359
5594
  registry->Register(New);
1360
5594
}
1361
1362
788
void Initialize(Local<Object> target,
1363
                Local<Value> unused,
1364
                Local<Context> context,
1365
                void* priv) {
1366
788
  Environment* env = Environment::GetCurrent(context);
1367
788
  Isolate* isolate = env->isolate();
1368
788
  ContextifyContext::Init(env, target);
1369
788
  ContextifyScript::Init(env, target);
1370
788
  MicrotaskQueueWrap::Init(env, target);
1371
1372
788
  SetMethod(context, target, "startSigintWatchdog", StartSigintWatchdog);
1373
788
  SetMethod(context, target, "stopSigintWatchdog", StopSigintWatchdog);
1374
  // Used in tests.
1375
788
  SetMethodNoSideEffect(
1376
      context, target, "watchdogHasPendingSigint", WatchdogHasPendingSigint);
1377
1378
  {
1379
788
    Local<FunctionTemplate> tpl = FunctionTemplate::New(env->isolate());
1380
788
    tpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "CompiledFnEntry"));
1381
1576
    tpl->InstanceTemplate()->SetInternalFieldCount(
1382
        CompiledFnEntry::kInternalFieldCount);
1383
1384
788
    env->set_compiled_fn_entry_template(tpl->InstanceTemplate());
1385
  }
1386
1387
788
  Local<Object> constants = Object::New(env->isolate());
1388
788
  Local<Object> measure_memory = Object::New(env->isolate());
1389
788
  Local<Object> memory_execution = Object::New(env->isolate());
1390
1391
  {
1392
788
    Local<Object> memory_mode = Object::New(env->isolate());
1393
788
    MeasureMemoryMode SUMMARY = MeasureMemoryMode::kSummary;
1394
788
    MeasureMemoryMode DETAILED = MeasureMemoryMode::kDetailed;
1395
2364
    NODE_DEFINE_CONSTANT(memory_mode, SUMMARY);
1396
2364
    NODE_DEFINE_CONSTANT(memory_mode, DETAILED);
1397
1576
    READONLY_PROPERTY(measure_memory, "mode", memory_mode);
1398
  }
1399
1400
  {
1401
788
    MeasureMemoryExecution DEFAULT = MeasureMemoryExecution::kDefault;
1402
788
    MeasureMemoryExecution EAGER = MeasureMemoryExecution::kEager;
1403
2364
    NODE_DEFINE_CONSTANT(memory_execution, DEFAULT);
1404
2364
    NODE_DEFINE_CONSTANT(memory_execution, EAGER);
1405
2364
    READONLY_PROPERTY(measure_memory, "execution", memory_execution);
1406
  }
1407
1408
2364
  READONLY_PROPERTY(constants, "measureMemory", measure_memory);
1409
1410
1576
  target->Set(context, env->constants_string(), constants).Check();
1411
1412
788
  SetMethod(context, target, "measureMemory", MeasureMemory);
1413
788
}
1414
1415
5594
void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
1416
5594
  ContextifyContext::RegisterExternalReferences(registry);
1417
5594
  ContextifyScript::RegisterExternalReferences(registry);
1418
5594
  MicrotaskQueueWrap::RegisterExternalReferences(registry);
1419
1420
5594
  registry->Register(StartSigintWatchdog);
1421
5594
  registry->Register(StopSigintWatchdog);
1422
5594
  registry->Register(WatchdogHasPendingSigint);
1423
5594
  registry->Register(MeasureMemory);
1424
5594
}
1425
}  // namespace contextify
1426
}  // namespace node
1427
1428
5665
NODE_MODULE_CONTEXT_AWARE_INTERNAL(contextify, node::contextify::Initialize)
1429
5594
NODE_MODULE_EXTERNAL_REFERENCE(contextify,
1430
                               node::contextify::RegisterExternalReferences)