/src/node/deps/v8/include/v8-context.h
Line | Count | Source (jump to first uncovered line) |
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 | | static Local<Context> New( |
89 | | Isolate* isolate, ExtensionConfiguration* extensions = nullptr, |
90 | | MaybeLocal<ObjectTemplate> global_template = MaybeLocal<ObjectTemplate>(), |
91 | | MaybeLocal<Value> global_object = MaybeLocal<Value>(), |
92 | | DeserializeInternalFieldsCallback internal_fields_deserializer = |
93 | | DeserializeInternalFieldsCallback(), |
94 | | MicrotaskQueue* microtask_queue = nullptr); |
95 | | |
96 | | /** |
97 | | * Create a new context from a (non-default) context snapshot. There |
98 | | * is no way to provide a global object template since we do not create |
99 | | * a new global object from template, but we can reuse a global object. |
100 | | * |
101 | | * \param isolate See v8::Context::New. |
102 | | * |
103 | | * \param context_snapshot_index The index of the context snapshot to |
104 | | * deserialize from. Use v8::Context::New for the default snapshot. |
105 | | * |
106 | | * \param embedder_fields_deserializer Optional callback to deserialize |
107 | | * internal fields. It should match the SerializeInternalFieldCallback used |
108 | | * to serialize. |
109 | | * |
110 | | * \param extensions See v8::Context::New. |
111 | | * |
112 | | * \param global_object See v8::Context::New. |
113 | | */ |
114 | | static MaybeLocal<Context> FromSnapshot( |
115 | | Isolate* isolate, size_t context_snapshot_index, |
116 | | DeserializeInternalFieldsCallback embedder_fields_deserializer = |
117 | | DeserializeInternalFieldsCallback(), |
118 | | ExtensionConfiguration* extensions = nullptr, |
119 | | MaybeLocal<Value> global_object = MaybeLocal<Value>(), |
120 | | MicrotaskQueue* microtask_queue = nullptr); |
121 | | |
122 | | /** |
123 | | * Returns an global object that isn't backed by an actual context. |
124 | | * |
125 | | * The global template needs to have access checks with handlers installed. |
126 | | * If an existing global object is passed in, the global object is detached |
127 | | * from its context. |
128 | | * |
129 | | * Note that this is different from a detached context where all accesses to |
130 | | * the global proxy will fail. Instead, the access check handlers are invoked. |
131 | | * |
132 | | * It is also not possible to detach an object returned by this method. |
133 | | * Instead, the access check handlers need to return nothing to achieve the |
134 | | * same effect. |
135 | | * |
136 | | * It is possible, however, to create a new context from the global object |
137 | | * returned by this method. |
138 | | */ |
139 | | static MaybeLocal<Object> NewRemoteContext( |
140 | | Isolate* isolate, Local<ObjectTemplate> global_template, |
141 | | MaybeLocal<Value> global_object = MaybeLocal<Value>()); |
142 | | |
143 | | /** |
144 | | * Sets the security token for the context. To access an object in |
145 | | * another context, the security tokens must match. |
146 | | */ |
147 | | void SetSecurityToken(Local<Value> token); |
148 | | |
149 | | /** Restores the security token to the default value. */ |
150 | | void UseDefaultSecurityToken(); |
151 | | |
152 | | /** Returns the security token of this context.*/ |
153 | | Local<Value> GetSecurityToken(); |
154 | | |
155 | | /** |
156 | | * Enter this context. After entering a context, all code compiled |
157 | | * and run is compiled and run in this context. If another context |
158 | | * is already entered, this old context is saved so it can be |
159 | | * restored when the new context is exited. |
160 | | */ |
161 | | void Enter(); |
162 | | |
163 | | /** |
164 | | * Exit this context. Exiting the current context restores the |
165 | | * context that was in place when entering the current context. |
166 | | */ |
167 | | void Exit(); |
168 | | |
169 | | /** |
170 | | * Delegate to help with Deep freezing embedder-specific objects (such as |
171 | | * JSApiObjects) that can not be frozen natively. |
172 | | */ |
173 | | class DeepFreezeDelegate { |
174 | | public: |
175 | | /** |
176 | | * Performs embedder-specific operations to freeze the provided embedder |
177 | | * object. The provided object *will* be frozen by DeepFreeze after this |
178 | | * function returns, so only embedder-specific objects need to be frozen. |
179 | | * This function *may not* create new JS objects or perform JS allocations. |
180 | | * Any v8 objects reachable from the provided embedder object that should |
181 | | * also be considered for freezing should be added to the children_out |
182 | | * parameter. Returns true if the operation completed successfully. |
183 | | */ |
184 | | V8_DEPRECATED("Please use the version that takes a LocalVector&") |
185 | | virtual bool FreezeEmbedderObjectAndGetChildren( |
186 | 0 | Local<Object> obj, std::vector<Local<Object>>& children_out) { |
187 | 0 | // TODO(chromium:1454114): This method is temporarily defined in order to |
188 | 0 | // smoothen the transition to the version that follows. |
189 | 0 | return true; |
190 | 0 | } |
191 | | virtual bool FreezeEmbedderObjectAndGetChildren( |
192 | 0 | Local<Object> obj, LocalVector<Object>& children_out) { |
193 | 0 | // TODO(chromium:1454114): This method is temporarily defined and |
194 | 0 | // calls the previous version, soon to be deprecated, in order to |
195 | 0 | // smoothen the transition. When deprecation is completed, this |
196 | 0 | // will become an abstract method. |
197 | 0 | std::vector<Local<Object>> children; |
198 | 0 | START_ALLOW_USE_DEPRECATED() |
199 | 0 | // Temporarily use the old callback. |
200 | 0 | bool result = FreezeEmbedderObjectAndGetChildren(obj, children); |
201 | 0 | END_ALLOW_USE_DEPRECATED() |
202 | 0 | children_out.insert(children_out.end(), children.begin(), children.end()); |
203 | 0 | return result; |
204 | 0 | } |
205 | | }; |
206 | | |
207 | | /** |
208 | | * Attempts to recursively freeze all objects reachable from this context. |
209 | | * Some objects (generators, iterators, non-const closures) can not be frozen |
210 | | * and will cause this method to throw an error. An optional delegate can be |
211 | | * provided to help freeze embedder-specific objects. |
212 | | * |
213 | | * Freezing occurs in two steps: |
214 | | * 1. "Marking" where we iterate through all objects reachable by this |
215 | | * context, accumulating a list of objects that need to be frozen and |
216 | | * looking for objects that can't be frozen. This step is separated because |
217 | | * it is more efficient when we can assume there is no garbage collection. |
218 | | * 2. "Freezing" where we go through the list of objects and freezing them. |
219 | | * This effectively requires copying them so it may trigger garbage |
220 | | * collection. |
221 | | */ |
222 | | Maybe<void> DeepFreeze(DeepFreezeDelegate* delegate = nullptr); |
223 | | |
224 | | /** Returns the isolate associated with a current context. */ |
225 | | Isolate* GetIsolate(); |
226 | | |
227 | | /** Returns the microtask queue associated with a current context. */ |
228 | | MicrotaskQueue* GetMicrotaskQueue(); |
229 | | |
230 | | /** Sets the microtask queue associated with the current context. */ |
231 | | void SetMicrotaskQueue(MicrotaskQueue* queue); |
232 | | |
233 | | /** |
234 | | * The field at kDebugIdIndex used to be reserved for the inspector. |
235 | | * It now serves no purpose. |
236 | | */ |
237 | | enum EmbedderDataFields { kDebugIdIndex = 0 }; |
238 | | |
239 | | /** |
240 | | * Return the number of fields allocated for embedder data. |
241 | | */ |
242 | | uint32_t GetNumberOfEmbedderDataFields(); |
243 | | |
244 | | /** |
245 | | * Gets the embedder data with the given index, which must have been set by a |
246 | | * previous call to SetEmbedderData with the same index. |
247 | | */ |
248 | | V8_INLINE Local<Value> GetEmbedderData(int index); |
249 | | |
250 | | /** |
251 | | * Gets the binding object used by V8 extras. Extra natives get a reference |
252 | | * to this object and can use it to "export" functionality by adding |
253 | | * properties. Extra natives can also "import" functionality by accessing |
254 | | * properties added by the embedder using the V8 API. |
255 | | */ |
256 | | Local<Object> GetExtrasBindingObject(); |
257 | | |
258 | | /** |
259 | | * Sets the embedder data with the given index, growing the data as |
260 | | * needed. Note that index 0 currently has a special meaning for Chrome's |
261 | | * debugger. |
262 | | */ |
263 | | void SetEmbedderData(int index, Local<Value> value); |
264 | | |
265 | | /** |
266 | | * Gets a 2-byte-aligned native pointer from the embedder data with the given |
267 | | * index, which must have been set by a previous call to |
268 | | * SetAlignedPointerInEmbedderData with the same index. Note that index 0 |
269 | | * currently has a special meaning for Chrome's debugger. |
270 | | */ |
271 | | V8_INLINE void* GetAlignedPointerFromEmbedderData(int index); |
272 | | |
273 | | /** |
274 | | * Sets a 2-byte-aligned native pointer in the embedder data with the given |
275 | | * index, growing the data as needed. Note that index 0 currently has a |
276 | | * special meaning for Chrome's debugger. |
277 | | */ |
278 | | void SetAlignedPointerInEmbedderData(int index, void* value); |
279 | | |
280 | | /** |
281 | | * Control whether code generation from strings is allowed. Calling |
282 | | * this method with false will disable 'eval' and the 'Function' |
283 | | * constructor for code running in this context. If 'eval' or the |
284 | | * 'Function' constructor are used an exception will be thrown. |
285 | | * |
286 | | * If code generation from strings is not allowed the |
287 | | * V8::AllowCodeGenerationFromStrings callback will be invoked if |
288 | | * set before blocking the call to 'eval' or the 'Function' |
289 | | * constructor. If that callback returns true, the call will be |
290 | | * allowed, otherwise an exception will be thrown. If no callback is |
291 | | * set an exception will be thrown. |
292 | | */ |
293 | | void AllowCodeGenerationFromStrings(bool allow); |
294 | | |
295 | | /** |
296 | | * Returns true if code generation from strings is allowed for the context. |
297 | | * For more details see AllowCodeGenerationFromStrings(bool) documentation. |
298 | | */ |
299 | | bool IsCodeGenerationFromStringsAllowed() const; |
300 | | |
301 | | /** |
302 | | * Sets the error description for the exception that is thrown when |
303 | | * code generation from strings is not allowed and 'eval' or the 'Function' |
304 | | * constructor are called. |
305 | | */ |
306 | | void SetErrorMessageForCodeGenerationFromStrings(Local<String> message); |
307 | | |
308 | | /** |
309 | | * Sets the error description for the exception that is thrown when |
310 | | * wasm code generation is not allowed. |
311 | | */ |
312 | | void SetErrorMessageForWasmCodeGeneration(Local<String> message); |
313 | | |
314 | | /** |
315 | | * Return data that was previously attached to the context snapshot via |
316 | | * SnapshotCreator, and removes the reference to it. |
317 | | * Repeated call with the same index returns an empty MaybeLocal. |
318 | | */ |
319 | | template <class T> |
320 | | V8_INLINE MaybeLocal<T> GetDataFromSnapshotOnce(size_t index); |
321 | | |
322 | | /** |
323 | | * If callback is set, abort any attempt to execute JavaScript in this |
324 | | * context, call the specified callback, and throw an exception. |
325 | | * To unset abort, pass nullptr as callback. |
326 | | */ |
327 | | using AbortScriptExecutionCallback = void (*)(Isolate* isolate, |
328 | | Local<Context> context); |
329 | | void SetAbortScriptExecution(AbortScriptExecutionCallback callback); |
330 | | |
331 | | /** |
332 | | * Returns the value that was set or restored by |
333 | | * SetContinuationPreservedEmbedderData(), if any. |
334 | | */ |
335 | | V8_DEPRECATE_SOON( |
336 | | "Use v8::Isolate::GetContinuationPreservedEmbedderData instead") |
337 | | Local<Value> GetContinuationPreservedEmbedderData() const; |
338 | | |
339 | | /** |
340 | | * Sets a value that will be stored on continuations and reset while the |
341 | | * continuation runs. |
342 | | */ |
343 | | V8_DEPRECATE_SOON( |
344 | | "Use v8::Isolate::SetContinuationPreservedEmbedderData instead") |
345 | | void SetContinuationPreservedEmbedderData(Local<Value> context); |
346 | | |
347 | | /** |
348 | | * Set or clear hooks to be invoked for promise lifecycle operations. |
349 | | * To clear a hook, set it to an empty v8::Function. Each function will |
350 | | * receive the observed promise as the first argument. If a chaining |
351 | | * operation is used on a promise, the init will additionally receive |
352 | | * the parent promise as the second argument. |
353 | | */ |
354 | | void SetPromiseHooks(Local<Function> init_hook, Local<Function> before_hook, |
355 | | Local<Function> after_hook, |
356 | | Local<Function> resolve_hook); |
357 | | |
358 | | bool HasTemplateLiteralObject(Local<Value> object); |
359 | | /** |
360 | | * Stack-allocated class which sets the execution context for all |
361 | | * operations executed within a local scope. |
362 | | */ |
363 | | class V8_NODISCARD Scope { |
364 | | public: |
365 | 915k | explicit V8_INLINE Scope(Local<Context> context) : context_(context) { |
366 | 915k | context_->Enter(); |
367 | 915k | } |
368 | 915k | V8_INLINE ~Scope() { context_->Exit(); } |
369 | | |
370 | | private: |
371 | | Local<Context> context_; |
372 | | }; |
373 | | |
374 | | /** |
375 | | * Stack-allocated class to support the backup incumbent settings object |
376 | | * stack. |
377 | | * https://html.spec.whatwg.org/multipage/webappapis.html#backup-incumbent-settings-object-stack |
378 | | */ |
379 | | class V8_EXPORT V8_NODISCARD BackupIncumbentScope final { |
380 | | public: |
381 | | /** |
382 | | * |backup_incumbent_context| is pushed onto the backup incumbent settings |
383 | | * object stack. |
384 | | */ |
385 | | explicit BackupIncumbentScope(Local<Context> backup_incumbent_context); |
386 | | ~BackupIncumbentScope(); |
387 | | |
388 | | private: |
389 | | friend class internal::Isolate; |
390 | | |
391 | 0 | uintptr_t JSStackComparableAddressPrivate() const { |
392 | 0 | return js_stack_comparable_address_; |
393 | 0 | } |
394 | | |
395 | | Local<Context> backup_incumbent_context_; |
396 | | uintptr_t js_stack_comparable_address_ = 0; |
397 | | const BackupIncumbentScope* prev_ = nullptr; |
398 | | }; |
399 | | |
400 | | V8_INLINE static Context* Cast(Data* data); |
401 | | |
402 | | private: |
403 | | friend class Value; |
404 | | friend class Script; |
405 | | friend class Object; |
406 | | friend class Function; |
407 | | |
408 | | static void CheckCast(Data* obj); |
409 | | |
410 | | internal::Address* GetDataFromSnapshotOnce(size_t index); |
411 | | Local<Value> SlowGetEmbedderData(int index); |
412 | | void* SlowGetAlignedPointerFromEmbedderData(int index); |
413 | | }; |
414 | | |
415 | | // --- Implementation --- |
416 | | |
417 | 4.55k | Local<Value> Context::GetEmbedderData(int index) { |
418 | 4.55k | #ifndef V8_ENABLE_CHECKS |
419 | 4.55k | using A = internal::Address; |
420 | 4.55k | using I = internal::Internals; |
421 | 4.55k | A ctx = internal::ValueHelper::ValueAsAddress(this); |
422 | 4.55k | A embedder_data = |
423 | 4.55k | I::ReadTaggedPointerField(ctx, I::kNativeContextEmbedderDataOffset); |
424 | 4.55k | int value_offset = |
425 | 4.55k | I::kEmbedderDataArrayHeaderSize + (I::kEmbedderDataSlotSize * index); |
426 | 4.55k | A value = I::ReadRawField<A>(embedder_data, value_offset); |
427 | | #ifdef V8_COMPRESS_POINTERS |
428 | | // We read the full pointer value and then decompress it in order to avoid |
429 | | // dealing with potential endiannes issues. |
430 | | value = I::DecompressTaggedField(embedder_data, static_cast<uint32_t>(value)); |
431 | | #endif |
432 | | |
433 | 4.55k | auto isolate = reinterpret_cast<v8::Isolate*>( |
434 | 4.55k | internal::IsolateFromNeverReadOnlySpaceObject(ctx)); |
435 | 4.55k | return Local<Value>::New(isolate, value); |
436 | | #else |
437 | | return SlowGetEmbedderData(index); |
438 | | #endif |
439 | 4.55k | } |
440 | | |
441 | 51.6M | void* Context::GetAlignedPointerFromEmbedderData(int index) { |
442 | 51.6M | #if !defined(V8_ENABLE_CHECKS) |
443 | 51.6M | using A = internal::Address; |
444 | 51.6M | using I = internal::Internals; |
445 | 51.6M | A ctx = internal::ValueHelper::ValueAsAddress(this); |
446 | 51.6M | A embedder_data = |
447 | 51.6M | I::ReadTaggedPointerField(ctx, I::kNativeContextEmbedderDataOffset); |
448 | 51.6M | int value_offset = I::kEmbedderDataArrayHeaderSize + |
449 | 51.6M | (I::kEmbedderDataSlotSize * index) + |
450 | 51.6M | I::kEmbedderDataSlotExternalPointerOffset; |
451 | 51.6M | Isolate* isolate = I::GetIsolateForSandbox(ctx); |
452 | 51.6M | return reinterpret_cast<void*>( |
453 | 51.6M | I::ReadExternalPointerField<internal::kEmbedderDataSlotPayloadTag>( |
454 | 51.6M | isolate, embedder_data, value_offset)); |
455 | | #else |
456 | | return SlowGetAlignedPointerFromEmbedderData(index); |
457 | | #endif |
458 | 51.6M | } |
459 | | |
460 | | template <class T> |
461 | 0 | MaybeLocal<T> Context::GetDataFromSnapshotOnce(size_t index) { |
462 | 0 | auto slot = GetDataFromSnapshotOnce(index); |
463 | 0 | if (slot) { |
464 | 0 | internal::PerformCastCheck( |
465 | 0 | internal::ValueHelper::SlotAsValue<T, false>(slot)); |
466 | 0 | } |
467 | 0 | return Local<T>::FromSlot(slot); |
468 | 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) |
469 | | |
470 | 0 | Context* Context::Cast(v8::Data* data) { |
471 | | #ifdef V8_ENABLE_CHECKS |
472 | | CheckCast(data); |
473 | | #endif |
474 | 0 | return static_cast<Context*>(data); |
475 | 0 | } |
476 | | |
477 | | } // namespace v8 |
478 | | |
479 | | #endif // INCLUDE_V8_CONTEXT_H_ |