GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: node_contextify.cc Lines: 621 675 92.0 %
Date: 2022-11-04 03:21:42 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
616
BaseObjectPtr<ContextifyContext> ContextifyContext::New(
111
    Environment* env,
112
    Local<Object> sandbox_obj,
113
    const ContextOptions& options) {
114
1232
  HandleScope scope(env->isolate());
115
616
  InitializeGlobalTemplates(env->isolate_data());
116
616
  Local<ObjectTemplate> object_template = env->contextify_global_template();
117
  DCHECK(!object_template.IsEmpty());
118
616
  bool use_node_snapshot = per_process::cli_options->node_snapshot;
119
  const SnapshotData* snapshot_data =
120
616
      use_node_snapshot ? SnapshotBuilder::GetEmbeddedSnapshotData() : nullptr;
121
122
  MicrotaskQueue* queue =
123
      options.microtask_queue_wrap
124
616
          ? options.microtask_queue_wrap->microtask_queue().get()
125
1843
          : env->isolate()->GetCurrentContext()->GetMicrotaskQueue();
126
127
  Local<Context> v8_context;
128
616
  if (!(CreateV8Context(env->isolate(), object_template, snapshot_data, queue)
129
616
            .ToLocal(&v8_context))) {
130
    // Allocation failure, maximum call stack size reached, termination, etc.
131
    return BaseObjectPtr<ContextifyContext>();
132
  }
133
616
  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
616
ContextifyContext::ContextifyContext(Environment* env,
144
                                     Local<Object> wrapper,
145
                                     Local<Context> v8_context,
146
616
                                     const ContextOptions& options)
147
    : BaseObject(env, wrapper),
148
616
      microtask_queue_wrap_(options.microtask_queue_wrap) {
149
616
  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
616
  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
616
  context_.SetWeak();
161
616
}
162
163
3018
ContextifyContext::~ContextifyContext() {
164
1006
  Isolate* isolate = env()->isolate();
165
2012
  HandleScope scope(isolate);
166
167
  env()->async_hooks()
168
1006
    ->RemoveContext(PersistentToLocal::Weak(isolate, context_));
169
1006
  context_.Reset();
170
2012
}
171
172
1411
void ContextifyContext::InitializeGlobalTemplates(IsolateData* isolate_data) {
173
2822
  if (!isolate_data->contextify_global_template().IsEmpty()) {
174
616
    return;
175
  }
176
  DCHECK(isolate_data->contextify_wrapper_template().IsEmpty());
177
  Local<FunctionTemplate> global_func_template =
178
795
      FunctionTemplate::New(isolate_data->isolate());
179
  Local<ObjectTemplate> global_object_template =
180
795
      global_func_template->InstanceTemplate();
181
182
  NamedPropertyHandlerConfiguration config(
183
      PropertyGetterCallback,
184
      PropertySetterCallback,
185
      PropertyDescriptorCallback,
186
      PropertyDeleterCallback,
187
      PropertyEnumeratorCallback,
188
      PropertyDefinerCallback,
189
      {},
190
795
      PropertyHandlerFlags::kHasNoSideEffect);
191
192
  IndexedPropertyHandlerConfiguration indexed_config(
193
      IndexedPropertyGetterCallback,
194
      IndexedPropertySetterCallback,
195
      IndexedPropertyDescriptorCallback,
196
      IndexedPropertyDeleterCallback,
197
      PropertyEnumeratorCallback,
198
      IndexedPropertyDefinerCallback,
199
      {},
200
795
      PropertyHandlerFlags::kHasNoSideEffect);
201
202
795
  global_object_template->SetHandler(config);
203
795
  global_object_template->SetHandler(indexed_config);
204
795
  isolate_data->set_contextify_global_template(global_object_template);
205
206
  Local<FunctionTemplate> wrapper_func_template =
207
795
      BaseObject::MakeLazilyInitializedJSTemplate(isolate_data);
208
  Local<ObjectTemplate> wrapper_object_template =
209
795
      wrapper_func_template->InstanceTemplate();
210
795
  isolate_data->set_contextify_wrapper_template(wrapper_object_template);
211
}
212
213
624
MaybeLocal<Context> ContextifyContext::CreateV8Context(
214
    Isolate* isolate,
215
    Local<ObjectTemplate> object_template,
216
    const SnapshotData* snapshot_data,
217
    MicrotaskQueue* queue) {
218
624
  EscapableHandleScope scope(isolate);
219
220
  Local<Context> ctx;
221
624
  if (snapshot_data == nullptr) {
222
    ctx = Context::New(isolate,
223
                       nullptr,  // extensions
224
                       object_template,
225
                       {},  // global object
226
                       {},  // deserialization callback
227
20
                       queue);
228

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

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

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

626
      !env->microtask_queue_ctor_template().IsEmpty() &&
383

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

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

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

139
  bool is_declared = is_declared_on_global_proxy || is_declared_on_sandbox;
527


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

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

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

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

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

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

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

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

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

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

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

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

5525
    if (!result.IsEmpty() && mtask_queue)
1013
2
      mtask_queue->PerformCheckpoint(env->isolate());
1014
5525
    return result;
1015
5541
  };
1016

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

5525
  if (timed_out || received_signal) {
1032

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

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

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