Coverage Report

Created: 2025-10-31 09:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/node/deps/v8/include/v8-context.h
Line
Count
Source
1
// Copyright 2021 the V8 project authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
#ifndef INCLUDE_V8_CONTEXT_H_
6
#define INCLUDE_V8_CONTEXT_H_
7
8
#include <stdint.h>
9
10
#include <vector>
11
12
#include "v8-data.h"          // NOLINT(build/include_directory)
13
#include "v8-local-handle.h"  // NOLINT(build/include_directory)
14
#include "v8-maybe.h"         // NOLINT(build/include_directory)
15
#include "v8-snapshot.h"      // NOLINT(build/include_directory)
16
#include "v8config.h"         // NOLINT(build/include_directory)
17
18
namespace v8 {
19
20
class Function;
21
class MicrotaskQueue;
22
class Object;
23
class ObjectTemplate;
24
class Value;
25
class String;
26
27
/**
28
 * A container for extension names.
29
 */
30
class V8_EXPORT ExtensionConfiguration {
31
 public:
32
0
  ExtensionConfiguration() : name_count_(0), names_(nullptr) {}
33
  ExtensionConfiguration(int name_count, const char* names[])
34
0
      : name_count_(name_count), names_(names) {}
35
36
0
  const char** begin() const { return &names_[0]; }
37
0
  const char** end() const { return &names_[name_count_]; }
38
39
 private:
40
  const int name_count_;
41
  const char** names_;
42
};
43
44
/**
45
 * A sandboxed execution context with its own set of built-in objects
46
 * and functions.
47
 */
48
class V8_EXPORT Context : public Data {
49
 public:
50
  /**
51
   * Returns the global proxy object.
52
   *
53
   * Global proxy object is a thin wrapper whose prototype points to actual
54
   * context's global object with the properties like Object, etc. This is done
55
   * that way for security reasons (for more details see
56
   * https://wiki.mozilla.org/Gecko:SplitWindow).
57
   *
58
   * Please note that changes to global proxy object prototype most probably
59
   * would break VM---v8 expects only global object as a prototype of global
60
   * proxy object.
61
   */
62
  Local<Object> Global();
63
64
  /**
65
   * Detaches the global object from its context before
66
   * the global object can be reused to create a new context.
67
   */
68
  void DetachGlobal();
69
70
  /**
71
   * Creates a new context and returns a handle to the newly allocated
72
   * context.
73
   *
74
   * \param isolate The isolate in which to create the context.
75
   *
76
   * \param extensions An optional extension configuration containing
77
   * the extensions to be installed in the newly created context.
78
   *
79
   * \param global_template An optional object template from which the
80
   * global object for the newly created context will be created.
81
   *
82
   * \param global_object An optional global object to be reused for
83
   * the newly created context. This global object must have been
84
   * created by a previous call to Context::New with the same global
85
   * template. The state of the global object will be completely reset
86
   * and only object identify will remain.
87
   *
88
   * \param internal_fields_deserializer An optional callback used
89
   * to deserialize fields set by
90
   * v8::Object::SetAlignedPointerInInternalField() in wrapper objects
91
   * from the default context snapshot. It should match the
92
   * SerializeInternalFieldsCallback() used by
93
   * v8::SnapshotCreator::SetDefaultContext() when the default context
94
   * snapshot is created. It does not need to be configured if the default
95
   * context snapshot contains no wrapper objects with pointer internal
96
   * fields, or if no custom startup snapshot is configured
97
   * in the v8::CreateParams used to create the isolate.
98
   *
99
   * \param microtask_queue An optional microtask queue used to manage
100
   * the microtasks created in this context. If not set the per-isolate
101
   * default microtask queue would be used.
102
   *
103
   * \param context_data_deserializer An optional callback used
104
   * to deserialize embedder data set by
105
   * v8::Context::SetAlignedPointerInEmbedderData() in the default
106
   * context from the default context snapshot. It does not need to be
107
   * configured if the default context snapshot contains no pointer embedder
108
   * data, or if no custom startup snapshot is configured in the
109
   * v8::CreateParams used to create the isolate.
110
   *
111
   * \param api_wrapper_deserializer An optional callback used to deserialize
112
   * API wrapper objects that was initially set with v8::Object::Wrap() and then
113
   * serialized using SerializeAPIWrapperCallback.
114
   */
115
  static Local<Context> New(
116
      Isolate* isolate, ExtensionConfiguration* extensions = nullptr,
117
      MaybeLocal<ObjectTemplate> global_template = MaybeLocal<ObjectTemplate>(),
118
      MaybeLocal<Value> global_object = MaybeLocal<Value>(),
119
      DeserializeInternalFieldsCallback internal_fields_deserializer =
120
          DeserializeInternalFieldsCallback(),
121
      MicrotaskQueue* microtask_queue = nullptr,
122
      DeserializeContextDataCallback context_data_deserializer =
123
          DeserializeContextDataCallback(),
124
      DeserializeAPIWrapperCallback api_wrapper_deserializer =
125
          DeserializeAPIWrapperCallback());
126
127
  /**
128
   * Create a new context from a (non-default) context snapshot. There
129
   * is no way to provide a global object template since we do not create
130
   * a new global object from template, but we can reuse a global object.
131
   *
132
   * \param isolate See v8::Context::New().
133
   *
134
   * \param context_snapshot_index The index of the context snapshot to
135
   * deserialize from. Use v8::Context::New() for the default snapshot.
136
   *
137
   * \param internal_fields_deserializer An optional callback used
138
   * to deserialize fields set by
139
   * v8::Object::SetAlignedPointerInInternalField() in wrapper objects
140
   * from the default context snapshot. It does not need to be
141
   * configured if there are no wrapper objects with no internal
142
   * pointer fields in the default context snapshot or if no startup
143
   * snapshot is configured when the isolate is created.
144
   *
145
   * \param extensions See v8::Context::New().
146
   *
147
   * \param global_object See v8::Context::New().
148
   *
149
   * \param internal_fields_deserializer Similar to
150
   * internal_fields_deserializer in v8::Context::New() but applies to
151
   * the context specified by the context_snapshot_index.
152
   *
153
   * \param microtask_queue  See v8::Context::New().
154
   *
155
   * \param context_data_deserializer  Similar to
156
   * context_data_deserializer in v8::Context::New() but applies to
157
   * the context specified by the context_snapshot_index.
158
   *
159
   *\param api_wrapper_deserializer Similar to api_wrapper_deserializer in
160
   * v8::Context::New() but applies to the context specified by the
161
   * context_snapshot_index.
162
   */
163
  static MaybeLocal<Context> FromSnapshot(
164
      Isolate* isolate, size_t context_snapshot_index,
165
      DeserializeInternalFieldsCallback internal_fields_deserializer =
166
          DeserializeInternalFieldsCallback(),
167
      ExtensionConfiguration* extensions = nullptr,
168
      MaybeLocal<Value> global_object = MaybeLocal<Value>(),
169
      MicrotaskQueue* microtask_queue = nullptr,
170
      DeserializeContextDataCallback context_data_deserializer =
171
          DeserializeContextDataCallback(),
172
      DeserializeAPIWrapperCallback api_wrapper_deserializer =
173
          DeserializeAPIWrapperCallback());
174
175
  /**
176
   * Returns an global object that isn't backed by an actual context.
177
   *
178
   * The global template needs to have access checks with handlers installed.
179
   * If an existing global object is passed in, the global object is detached
180
   * from its context.
181
   *
182
   * Note that this is different from a detached context where all accesses to
183
   * the global proxy will fail. Instead, the access check handlers are invoked.
184
   *
185
   * It is also not possible to detach an object returned by this method.
186
   * Instead, the access check handlers need to return nothing to achieve the
187
   * same effect.
188
   *
189
   * It is possible, however, to create a new context from the global object
190
   * returned by this method.
191
   */
192
  static MaybeLocal<Object> NewRemoteContext(
193
      Isolate* isolate, Local<ObjectTemplate> global_template,
194
      MaybeLocal<Value> global_object = MaybeLocal<Value>());
195
196
  /**
197
   * Sets the security token for the context.  To access an object in
198
   * another context, the security tokens must match.
199
   */
200
  void SetSecurityToken(Local<Value> token);
201
202
  /** Restores the security token to the default value. */
203
  void UseDefaultSecurityToken();
204
205
  /** Returns the security token of this context.*/
206
  Local<Value> GetSecurityToken();
207
208
  /**
209
   * Enter this context.  After entering a context, all code compiled
210
   * and run is compiled and run in this context.  If another context
211
   * is already entered, this old context is saved so it can be
212
   * restored when the new context is exited.
213
   */
214
  void Enter();
215
216
  /**
217
   * Exit this context.  Exiting the current context restores the
218
   * context that was in place when entering the current context.
219
   */
220
  void Exit();
221
222
  /**
223
   * Delegate to help with Deep freezing embedder-specific objects (such as
224
   * JSApiObjects) that can not be frozen natively.
225
   */
226
  class DeepFreezeDelegate {
227
   public:
228
    /**
229
     * Performs embedder-specific operations to freeze the provided embedder
230
     * object. The provided object *will* be frozen by DeepFreeze after this
231
     * function returns, so only embedder-specific objects need to be frozen.
232
     * This function *may not* create new JS objects or perform JS allocations.
233
     * Any v8 objects reachable from the provided embedder object that should
234
     * also be considered for freezing should be added to the children_out
235
     * parameter. Returns true if the operation completed successfully.
236
     */
237
    virtual bool FreezeEmbedderObjectAndGetChildren(
238
        Local<Object> obj, LocalVector<Object>& children_out) = 0;
239
  };
240
241
  /**
242
   * Attempts to recursively freeze all objects reachable from this context.
243
   * Some objects (generators, iterators, non-const closures) can not be frozen
244
   * and will cause this method to throw an error. An optional delegate can be
245
   * provided to help freeze embedder-specific objects.
246
   *
247
   * Freezing occurs in two steps:
248
   * 1. "Marking" where we iterate through all objects reachable by this
249
   *    context, accumulating a list of objects that need to be frozen and
250
   *    looking for objects that can't be frozen. This step is separated because
251
   *    it is more efficient when we can assume there is no garbage collection.
252
   * 2. "Freezing" where we go through the list of objects and freezing them.
253
   *    This effectively requires copying them so it may trigger garbage
254
   *    collection.
255
   */
256
  Maybe<void> DeepFreeze(DeepFreezeDelegate* delegate = nullptr);
257
258
  /** Returns the microtask queue associated with a current context. */
259
  MicrotaskQueue* GetMicrotaskQueue();
260
261
  /** Sets the microtask queue associated with the current context. */
262
  void SetMicrotaskQueue(MicrotaskQueue* queue);
263
264
  /**
265
   * The field at kDebugIdIndex used to be reserved for the inspector.
266
   * It now serves no purpose.
267
   */
268
  enum EmbedderDataFields { kDebugIdIndex = 0 };
269
270
  /**
271
   * Return the number of fields allocated for embedder data.
272
   */
273
  uint32_t GetNumberOfEmbedderDataFields();
274
275
  /**
276
   * Gets the embedder data with the given index, which must have been set by a
277
   * previous call to SetEmbedderData with the same index.
278
   */
279
  V8_INLINE Local<Value> GetEmbedderData(int index);
280
281
  /**
282
   * Gets the binding object used by V8 extras. Extra natives get a reference
283
   * to this object and can use it to "export" functionality by adding
284
   * properties. Extra natives can also "import" functionality by accessing
285
   * properties added by the embedder using the V8 API.
286
   */
287
  Local<Object> GetExtrasBindingObject();
288
289
  /**
290
   * Sets the embedder data with the given index, growing the data as
291
   * needed. Note that index 0 currently has a special meaning for Chrome's
292
   * debugger.
293
   */
294
  void SetEmbedderData(int index, Local<Value> value);
295
296
  /**
297
   * Gets a 2-byte-aligned native pointer from the embedder data with the given
298
   * index, which must have been set by a previous call to
299
   * SetAlignedPointerInEmbedderData with the same index. Note that index 0
300
   * currently has a special meaning for Chrome's debugger.
301
   */
302
  V8_INLINE void* GetAlignedPointerFromEmbedderData(Isolate* isolate, int index,
303
                                                    EmbedderDataTypeTag tag);
304
  V8_INLINE void* GetAlignedPointerFromEmbedderData(int index,
305
                                                    EmbedderDataTypeTag tag);
306
307
  V8_DEPRECATE_SOON(
308
      "Use GetAlignedPointerFromEmbedderData with EmbedderDataTypeTag "
309
      "parameter instead.")
310
  V8_INLINE void* GetAlignedPointerFromEmbedderData(Isolate* isolate,
311
0
                                                    int index) {
312
0
    return GetAlignedPointerFromEmbedderData(isolate, index,
313
0
                                             kEmbedderDataTypeTagDefault);
314
0
  }
315
316
  V8_DEPRECATE_SOON(
317
      "Use GetAlignedPointerFromEmbedderData with EmbedderDataTypeTag "
318
      "parameter instead.")
319
5.05M
  V8_INLINE void* GetAlignedPointerFromEmbedderData(int index) {
320
5.05M
    return GetAlignedPointerFromEmbedderData(index,
321
5.05M
                                             kEmbedderDataTypeTagDefault);
322
5.05M
  }
323
324
  void SetAlignedPointerInEmbedderData(int index, void* value,
325
                                       EmbedderDataTypeTag tag);
326
327
  /**
328
   * Sets a 2-byte-aligned native pointer in the embedder data with the given
329
   * index, growing the data as needed. Note that index 0 currently has a
330
   * special meaning for Chrome's debugger.
331
   */
332
  V8_DEPRECATE_SOON(
333
      "Use SetAlignedPointerInEmbedderData with EmbedderDataTypeTag parameter "
334
      "instead.")
335
245
  void SetAlignedPointerInEmbedderData(int index, void* value) {
336
245
    SetAlignedPointerInEmbedderData(index, value, kEmbedderDataTypeTagDefault);
337
245
  }
338
339
  /**
340
   * Control whether code generation from strings is allowed. Calling
341
   * this method with false will disable 'eval' and the 'Function'
342
   * constructor for code running in this context. If 'eval' or the
343
   * 'Function' constructor are used an exception will be thrown.
344
   *
345
   * If code generation from strings is not allowed the
346
   * V8::ModifyCodeGenerationFromStringsCallback callback will be invoked if
347
   * set before blocking the call to 'eval' or the 'Function'
348
   * constructor. If that callback returns true, the call will be
349
   * allowed, otherwise an exception will be thrown. If no callback is
350
   * set an exception will be thrown.
351
   */
352
  void AllowCodeGenerationFromStrings(bool allow);
353
354
  /**
355
   * Returns true if code generation from strings is allowed for the context.
356
   * For more details see AllowCodeGenerationFromStrings(bool) documentation.
357
   */
358
  bool IsCodeGenerationFromStringsAllowed() const;
359
360
  /**
361
   * Sets the error description for the exception that is thrown when
362
   * code generation from strings is not allowed and 'eval' or the 'Function'
363
   * constructor are called.
364
   */
365
  void SetErrorMessageForCodeGenerationFromStrings(Local<String> message);
366
367
  /**
368
   * Sets the error description for the exception that is thrown when
369
   * wasm code generation is not allowed.
370
   */
371
  void SetErrorMessageForWasmCodeGeneration(Local<String> message);
372
373
  /**
374
   * Return data that was previously attached to the context snapshot via
375
   * SnapshotCreator, and removes the reference to it.
376
   * Repeated call with the same index returns an empty MaybeLocal.
377
   */
378
  template <class T>
379
  V8_INLINE MaybeLocal<T> GetDataFromSnapshotOnce(size_t index);
380
381
  /**
382
   * If callback is set, abort any attempt to execute JavaScript in this
383
   * context, call the specified callback, and throw an exception.
384
   * To unset abort, pass nullptr as callback.
385
   */
386
  using AbortScriptExecutionCallback = void (*)(Isolate* isolate,
387
                                                Local<Context> context);
388
  void SetAbortScriptExecution(AbortScriptExecutionCallback callback);
389
390
  /**
391
   * Set or clear hooks to be invoked for promise lifecycle operations.
392
   * To clear a hook, set it to an empty v8::Function. Each function will
393
   * receive the observed promise as the first argument. If a chaining
394
   * operation is used on a promise, the init will additionally receive
395
   * the parent promise as the second argument.
396
   */
397
  void SetPromiseHooks(Local<Function> init_hook, Local<Function> before_hook,
398
                       Local<Function> after_hook,
399
                       Local<Function> resolve_hook);
400
401
  bool HasTemplateLiteralObject(Local<Value> object);
402
  /**
403
   * Stack-allocated class which sets the execution context for all
404
   * operations executed within a local scope.
405
   */
406
  class V8_NODISCARD Scope {
407
   public:
408
49.3k
    explicit V8_INLINE Scope(Local<Context> context) : context_(context) {
409
49.3k
      context_->Enter();
410
49.3k
    }
411
49.3k
    V8_INLINE ~Scope() { context_->Exit(); }
412
413
   private:
414
    Local<Context> context_;
415
  };
416
417
  /**
418
   * Stack-allocated class to support the backup incumbent settings object
419
   * stack.
420
   * https://html.spec.whatwg.org/multipage/webappapis.html#backup-incumbent-settings-object-stack
421
   */
422
  class V8_EXPORT V8_NODISCARD BackupIncumbentScope final {
423
   public:
424
    /**
425
     * |backup_incumbent_context| is pushed onto the backup incumbent settings
426
     * object stack.
427
     */
428
    explicit BackupIncumbentScope(Local<Context> backup_incumbent_context);
429
    ~BackupIncumbentScope();
430
431
   private:
432
    friend class internal::Isolate;
433
434
0
    uintptr_t JSStackComparableAddressPrivate() const {
435
0
      return js_stack_comparable_address_;
436
0
    }
437
438
    Local<Context> backup_incumbent_context_;
439
    uintptr_t js_stack_comparable_address_ = 0;
440
    const BackupIncumbentScope* prev_ = nullptr;
441
  };
442
443
  V8_INLINE static Context* Cast(Data* data);
444
445
 private:
446
  friend class Value;
447
  friend class Script;
448
  friend class Object;
449
  friend class Function;
450
451
  static void CheckCast(Data* obj);
452
453
  internal::ValueHelper::InternalRepresentationType GetDataFromSnapshotOnce(
454
      size_t index);
455
  Local<Value> SlowGetEmbedderData(int index);
456
  void* SlowGetAlignedPointerFromEmbedderData(int index,
457
                                              EmbedderDataTypeTag tag);
458
};
459
460
// --- Implementation ---
461
462
4
Local<Value> Context::GetEmbedderData(int index) {
463
4
#ifndef V8_ENABLE_CHECKS
464
4
  using A = internal::Address;
465
4
  using I = internal::Internals;
466
4
  A ctx = internal::ValueHelper::ValueAsAddress(this);
467
4
  A embedder_data =
468
4
      I::ReadTaggedPointerField(ctx, I::kNativeContextEmbedderDataOffset);
469
4
  int value_offset =
470
4
      I::kEmbedderDataArrayHeaderSize + (I::kEmbedderDataSlotSize * index);
471
4
  A value = I::ReadRawField<A>(embedder_data, value_offset);
472
#ifdef V8_COMPRESS_POINTERS
473
  // We read the full pointer value and then decompress it in order to avoid
474
  // dealing with potential endiannes issues.
475
  value = I::DecompressTaggedField(embedder_data, static_cast<uint32_t>(value));
476
#endif
477
478
4
  auto* isolate = I::GetCurrentIsolate();
479
4
  return Local<Value>::New(isolate, value);
480
#else
481
  return SlowGetEmbedderData(index);
482
#endif
483
4
}
484
485
void* Context::GetAlignedPointerFromEmbedderData(Isolate* isolate, int index,
486
0
                                                 EmbedderDataTypeTag tag) {
487
0
#if !defined(V8_ENABLE_CHECKS)
488
0
  using A = internal::Address;
489
0
  using I = internal::Internals;
490
0
  A ctx = internal::ValueHelper::ValueAsAddress(this);
491
0
  A embedder_data =
492
0
      I::ReadTaggedPointerField(ctx, I::kNativeContextEmbedderDataOffset);
493
0
  int value_offset = I::kEmbedderDataArrayHeaderSize +
494
0
                     (I::kEmbedderDataSlotSize * index) +
495
0
                     I::kEmbedderDataSlotExternalPointerOffset;
496
0
  return reinterpret_cast<void*>(I::ReadExternalPointerField(
497
0
      isolate, embedder_data, value_offset, ToExternalPointerTag(tag)));
498
0
#else
499
0
  return SlowGetAlignedPointerFromEmbedderData(index, tag);
500
0
#endif
501
0
}
502
503
void* Context::GetAlignedPointerFromEmbedderData(int index,
504
5.05M
                                                 EmbedderDataTypeTag tag) {
505
5.05M
#if !defined(V8_ENABLE_CHECKS)
506
5.05M
  using A = internal::Address;
507
5.05M
  using I = internal::Internals;
508
5.05M
  A ctx = internal::ValueHelper::ValueAsAddress(this);
509
5.05M
  A embedder_data =
510
5.05M
      I::ReadTaggedPointerField(ctx, I::kNativeContextEmbedderDataOffset);
511
5.05M
  int value_offset = I::kEmbedderDataArrayHeaderSize +
512
5.05M
                     (I::kEmbedderDataSlotSize * index) +
513
5.05M
                     I::kEmbedderDataSlotExternalPointerOffset;
514
5.05M
  Isolate* isolate = I::GetCurrentIsolateForSandbox();
515
5.05M
  return reinterpret_cast<void*>(I::ReadExternalPointerField(
516
5.05M
      isolate, embedder_data, value_offset, ToExternalPointerTag(tag)));
517
#else
518
  return SlowGetAlignedPointerFromEmbedderData(index, tag);
519
#endif
520
5.05M
}
521
522
template <class T>
523
0
MaybeLocal<T> Context::GetDataFromSnapshotOnce(size_t index) {
524
0
  if (auto repr = GetDataFromSnapshotOnce(index);
525
0
      repr != internal::ValueHelper::kEmpty) {
526
0
    internal::PerformCastCheck(internal::ValueHelper::ReprAsValue<T>(repr));
527
0
    return Local<T>::FromRepr(repr);
528
0
  }
529
0
  return {};
530
0
}
Unexecuted instantiation: v8::MaybeLocal<v8::Uint32Array> v8::Context::GetDataFromSnapshotOnce<v8::Uint32Array>(unsigned long)
Unexecuted instantiation: v8::MaybeLocal<v8::Uint8Array> v8::Context::GetDataFromSnapshotOnce<v8::Uint8Array>(unsigned long)
Unexecuted instantiation: v8::MaybeLocal<v8::Float64Array> v8::Context::GetDataFromSnapshotOnce<v8::Float64Array>(unsigned long)
Unexecuted instantiation: v8::MaybeLocal<v8::Array> v8::Context::GetDataFromSnapshotOnce<v8::Array>(unsigned long)
Unexecuted instantiation: v8::MaybeLocal<v8::Object> v8::Context::GetDataFromSnapshotOnce<v8::Object>(unsigned long)
Unexecuted instantiation: v8::MaybeLocal<v8::Int32Array> v8::Context::GetDataFromSnapshotOnce<v8::Int32Array>(unsigned long)
Unexecuted instantiation: v8::MaybeLocal<v8::BigInt64Array> v8::Context::GetDataFromSnapshotOnce<v8::BigInt64Array>(unsigned long)
Unexecuted instantiation: v8::MaybeLocal<v8::Function> v8::Context::GetDataFromSnapshotOnce<v8::Function>(unsigned long)
Unexecuted instantiation: v8::MaybeLocal<v8::Context> v8::Context::GetDataFromSnapshotOnce<v8::Context>(unsigned long)
531
532
0
Context* Context::Cast(v8::Data* data) {
533
#ifdef V8_ENABLE_CHECKS
534
  CheckCast(data);
535
#endif
536
0
  return static_cast<Context*>(data);
537
0
}
538
539
}  // namespace v8
540
541
#endif  // INCLUDE_V8_CONTEXT_H_