/src/node/deps/v8/include/v8-script.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_SCRIPT_H_ |
6 | | #define INCLUDE_V8_SCRIPT_H_ |
7 | | |
8 | | #include <stddef.h> |
9 | | #include <stdint.h> |
10 | | |
11 | | #include <memory> |
12 | | #include <tuple> |
13 | | #include <vector> |
14 | | |
15 | | #include "v8-callbacks.h" // NOLINT(build/include_directory) |
16 | | #include "v8-data.h" // NOLINT(build/include_directory) |
17 | | #include "v8-local-handle.h" // NOLINT(build/include_directory) |
18 | | #include "v8-maybe.h" // NOLINT(build/include_directory) |
19 | | #include "v8-memory-span.h" // NOLINT(build/include_directory) |
20 | | #include "v8-message.h" // NOLINT(build/include_directory) |
21 | | #include "v8config.h" // NOLINT(build/include_directory) |
22 | | |
23 | | namespace v8 { |
24 | | |
25 | | class Function; |
26 | | class Message; |
27 | | class Object; |
28 | | class PrimitiveArray; |
29 | | class Script; |
30 | | |
31 | | namespace internal { |
32 | | class BackgroundDeserializeTask; |
33 | | struct ScriptStreamingData; |
34 | | } // namespace internal |
35 | | |
36 | | /** |
37 | | * A container type that holds relevant metadata for module loading. |
38 | | * |
39 | | * This is passed back to the embedder as part of |
40 | | * HostImportModuleDynamicallyCallback for module loading. |
41 | | */ |
42 | | class V8_EXPORT ScriptOrModule { |
43 | | public: |
44 | | /** |
45 | | * The name that was passed by the embedder as ResourceName to the |
46 | | * ScriptOrigin. This can be either a v8::String or v8::Undefined. |
47 | | */ |
48 | | Local<Value> GetResourceName(); |
49 | | |
50 | | /** |
51 | | * The options that were passed by the embedder as HostDefinedOptions to |
52 | | * the ScriptOrigin. |
53 | | */ |
54 | | Local<Data> HostDefinedOptions(); |
55 | | }; |
56 | | |
57 | | /** |
58 | | * A compiled JavaScript script, not yet tied to a Context. |
59 | | */ |
60 | | class V8_EXPORT UnboundScript : public Data { |
61 | | public: |
62 | | /** |
63 | | * Binds the script to the currently entered context. |
64 | | */ |
65 | | Local<Script> BindToCurrentContext(); |
66 | | |
67 | | int GetId() const; |
68 | | Local<Value> GetScriptName(); |
69 | | |
70 | | /** |
71 | | * Data read from magic sourceURL comments. |
72 | | */ |
73 | | Local<Value> GetSourceURL(); |
74 | | /** |
75 | | * Data read from magic sourceMappingURL comments. |
76 | | */ |
77 | | Local<Value> GetSourceMappingURL(); |
78 | | |
79 | | /** |
80 | | * Returns zero based line number of the code_pos location in the script. |
81 | | * -1 will be returned if no information available. |
82 | | */ |
83 | | int GetLineNumber(int code_pos = 0); |
84 | | |
85 | | /** |
86 | | * Returns zero based column number of the code_pos location in the script. |
87 | | * -1 will be returned if no information available. |
88 | | */ |
89 | | int GetColumnNumber(int code_pos = 0); |
90 | | |
91 | | static const int kNoScriptId = 0; |
92 | | }; |
93 | | |
94 | | /** |
95 | | * A compiled JavaScript module, not yet tied to a Context. |
96 | | */ |
97 | | class V8_EXPORT UnboundModuleScript : public Data { |
98 | | public: |
99 | | /** |
100 | | * Data read from magic sourceURL comments. |
101 | | */ |
102 | | Local<Value> GetSourceURL(); |
103 | | /** |
104 | | * Data read from magic sourceMappingURL comments. |
105 | | */ |
106 | | Local<Value> GetSourceMappingURL(); |
107 | | }; |
108 | | |
109 | | /** |
110 | | * A location in JavaScript source. |
111 | | */ |
112 | | class V8_EXPORT Location { |
113 | | public: |
114 | 0 | int GetLineNumber() { return line_number_; } |
115 | 0 | int GetColumnNumber() { return column_number_; } |
116 | | |
117 | | Location(int line_number, int column_number) |
118 | 0 | : line_number_(line_number), column_number_(column_number) {} |
119 | | |
120 | | private: |
121 | | int line_number_; |
122 | | int column_number_; |
123 | | }; |
124 | | |
125 | | class V8_EXPORT ModuleRequest : public Data { |
126 | | public: |
127 | | /** |
128 | | * Returns the module specifier for this ModuleRequest. |
129 | | */ |
130 | | Local<String> GetSpecifier() const; |
131 | | |
132 | | /** |
133 | | * Returns the module import phase for this ModuleRequest. |
134 | | */ |
135 | | ModuleImportPhase GetPhase() const; |
136 | | |
137 | | /** |
138 | | * Returns the source code offset of this module request. |
139 | | * Use Module::SourceOffsetToLocation to convert this to line/column numbers. |
140 | | */ |
141 | | int GetSourceOffset() const; |
142 | | |
143 | | /** |
144 | | * Contains the import attributes for this request in the form: |
145 | | * [key1, value1, source_offset1, key2, value2, source_offset2, ...]. |
146 | | * The keys and values are of type v8::String, and the source offsets are of |
147 | | * type Int32. Use Module::SourceOffsetToLocation to convert the source |
148 | | * offsets to Locations with line/column numbers. |
149 | | * |
150 | | * All attributes present in the module request will be supplied in this |
151 | | * list, regardless of whether they are supported by the host. Per |
152 | | * https://tc39.es/proposal-import-attributes/#sec-hostgetsupportedimportattributes, |
153 | | * hosts are expected to throw for attributes that they do not support (as |
154 | | * opposed to, for example, ignoring them). |
155 | | */ |
156 | | Local<FixedArray> GetImportAttributes() const; |
157 | | |
158 | | V8_DEPRECATED("Use GetImportAttributes instead") |
159 | 0 | Local<FixedArray> GetImportAssertions() const { |
160 | 0 | return GetImportAttributes(); |
161 | 0 | } |
162 | | |
163 | | V8_INLINE static ModuleRequest* Cast(Data* data); |
164 | | |
165 | | private: |
166 | | static void CheckCast(Data* obj); |
167 | | }; |
168 | | |
169 | | /** |
170 | | * A compiled JavaScript module. |
171 | | */ |
172 | | class V8_EXPORT Module : public Data { |
173 | | public: |
174 | | /** |
175 | | * The different states a module can be in. |
176 | | * |
177 | | * This corresponds to the states used in ECMAScript except that "evaluated" |
178 | | * is split into kEvaluated and kErrored, indicating success and failure, |
179 | | * respectively. |
180 | | */ |
181 | | enum Status { |
182 | | kUninstantiated, |
183 | | kInstantiating, |
184 | | kInstantiated, |
185 | | kEvaluating, |
186 | | kEvaluated, |
187 | | kErrored |
188 | | }; |
189 | | |
190 | | /** |
191 | | * Returns the module's current status. |
192 | | */ |
193 | | Status GetStatus() const; |
194 | | |
195 | | /** |
196 | | * For a module in kErrored status, this returns the corresponding exception. |
197 | | */ |
198 | | Local<Value> GetException() const; |
199 | | |
200 | | /** |
201 | | * Returns the ModuleRequests for this module. |
202 | | */ |
203 | | Local<FixedArray> GetModuleRequests() const; |
204 | | |
205 | | /** |
206 | | * For the given source text offset in this module, returns the corresponding |
207 | | * Location with line and column numbers. |
208 | | */ |
209 | | Location SourceOffsetToLocation(int offset) const; |
210 | | |
211 | | /** |
212 | | * Returns the identity hash for this object. |
213 | | */ |
214 | | int GetIdentityHash() const; |
215 | | |
216 | | using ResolveModuleCallback = MaybeLocal<Module> (*)( |
217 | | Local<Context> context, Local<String> specifier, |
218 | | Local<FixedArray> import_attributes, Local<Module> referrer); |
219 | | using ResolveSourceCallback = MaybeLocal<Object> (*)( |
220 | | Local<Context> context, Local<String> specifier, |
221 | | Local<FixedArray> import_attributes, Local<Module> referrer); |
222 | | |
223 | | using ResolveModuleByIndexCallback = MaybeLocal<Module> (*)( |
224 | | Local<Context> context, size_t module_request_index, |
225 | | Local<Module> referrer); |
226 | | using ResolveSourceByIndexCallback = MaybeLocal<Object> (*)( |
227 | | Local<Context> context, size_t module_request_index, |
228 | | Local<Module> referrer); |
229 | | |
230 | | /** |
231 | | * Instantiates the module and its dependencies. |
232 | | * |
233 | | * Returns an empty Maybe<bool> if an exception occurred during |
234 | | * instantiation. (In the case where the callback throws an exception, that |
235 | | * exception is propagated.) |
236 | | */ |
237 | | V8_WARN_UNUSED_RESULT Maybe<bool> InstantiateModule( |
238 | | Local<Context> context, ResolveModuleCallback module_callback, |
239 | | ResolveSourceCallback source_callback = nullptr); |
240 | | |
241 | | /** |
242 | | * Similar to the variant that takes ResolveModuleCallback and |
243 | | * ResolveSourceCallback, but uses the index into the array that is returned |
244 | | * by GetModuleRequests() instead of the specifier and import attributes to |
245 | | * identify the requests. |
246 | | */ |
247 | | V8_WARN_UNUSED_RESULT Maybe<bool> InstantiateModule( |
248 | | Local<Context> context, ResolveModuleByIndexCallback module_callback, |
249 | | ResolveSourceByIndexCallback source_callback = nullptr); |
250 | | |
251 | | /** |
252 | | * Evaluates the module and its dependencies. |
253 | | * |
254 | | * If status is kInstantiated, run the module's code and return a Promise |
255 | | * object. On success, set status to kEvaluated and resolve the Promise with |
256 | | * the completion value; on failure, set status to kErrored and reject the |
257 | | * Promise with the error. |
258 | | * |
259 | | * If IsGraphAsync() is false, the returned Promise is settled. |
260 | | */ |
261 | | V8_WARN_UNUSED_RESULT MaybeLocal<Value> Evaluate(Local<Context> context); |
262 | | |
263 | | /** |
264 | | * Returns the namespace object of this module. |
265 | | * |
266 | | * The module's status must be at least kInstantiated. |
267 | | */ |
268 | | Local<Value> GetModuleNamespace(); |
269 | | |
270 | | /** |
271 | | * Returns the corresponding context-unbound module script. |
272 | | * |
273 | | * The module must be unevaluated, i.e. its status must not be kEvaluating, |
274 | | * kEvaluated or kErrored. |
275 | | */ |
276 | | Local<UnboundModuleScript> GetUnboundModuleScript(); |
277 | | |
278 | | /** |
279 | | * Returns the underlying script's id. |
280 | | * |
281 | | * The module must be a SourceTextModule and must not have a kErrored status. |
282 | | */ |
283 | | int ScriptId() const; |
284 | | |
285 | | /** |
286 | | * Returns whether this module or any of its requested modules is async, |
287 | | * i.e. contains top-level await. |
288 | | * |
289 | | * The module's status must be at least kInstantiated. |
290 | | */ |
291 | | bool IsGraphAsync() const; |
292 | | |
293 | | /** |
294 | | * Returns whether this module is individually asynchronous (for example, |
295 | | * if it's a Source Text Module Record containing a top-level await). |
296 | | * See [[HasTLA]] in https://tc39.es/ecma262/#sec-cyclic-module-records |
297 | | */ |
298 | | bool HasTopLevelAwait() const; |
299 | | |
300 | | /** |
301 | | * Returns whether the module is a SourceTextModule. |
302 | | */ |
303 | | bool IsSourceTextModule() const; |
304 | | |
305 | | /** |
306 | | * Returns whether the module is a SyntheticModule. |
307 | | */ |
308 | | bool IsSyntheticModule() const; |
309 | | |
310 | | /* |
311 | | * Callback defined in the embedder. This is responsible for setting |
312 | | * the module's exported values with calls to SetSyntheticModuleExport(). |
313 | | * The callback must return a resolved Promise to indicate success (where no |
314 | | * exception was thrown) and return an empy MaybeLocal to indicate falure |
315 | | * (where an exception was thrown). |
316 | | */ |
317 | | using SyntheticModuleEvaluationSteps = |
318 | | MaybeLocal<Value> (*)(Local<Context> context, Local<Module> module); |
319 | | |
320 | | /** |
321 | | * Creates a new SyntheticModule with the specified export names, where |
322 | | * evaluation_steps will be executed upon module evaluation. |
323 | | * export_names must not contain duplicates. |
324 | | * module_name is used solely for logging/debugging and doesn't affect module |
325 | | * behavior. |
326 | | */ |
327 | | static Local<Module> CreateSyntheticModule( |
328 | | Isolate* isolate, Local<String> module_name, |
329 | | const MemorySpan<const Local<String>>& export_names, |
330 | | SyntheticModuleEvaluationSteps evaluation_steps); |
331 | | |
332 | | /** |
333 | | * Set this module's exported value for the name export_name to the specified |
334 | | * export_value. This method must be called only on Modules created via |
335 | | * CreateSyntheticModule. An error will be thrown if export_name is not one |
336 | | * of the export_names that were passed in that CreateSyntheticModule call. |
337 | | * Returns Just(true) on success, Nothing<bool>() if an error was thrown. |
338 | | */ |
339 | | V8_WARN_UNUSED_RESULT Maybe<bool> SetSyntheticModuleExport( |
340 | | Isolate* isolate, Local<String> export_name, Local<Value> export_value); |
341 | | |
342 | | /** |
343 | | * Search the modules requested directly or indirectly by the module for |
344 | | * any top-level await that has not yet resolved. If there is any, the |
345 | | * returned pair of vectors (of equal size) contain the unresolved module |
346 | | * and corresponding message with the pending top-level await. |
347 | | * An embedder may call this before exiting to improve error messages. |
348 | | */ |
349 | | std::pair<LocalVector<Module>, LocalVector<Message>> |
350 | | GetStalledTopLevelAwaitMessages(Isolate* isolate); |
351 | | |
352 | | V8_INLINE static Module* Cast(Data* data); |
353 | | |
354 | | private: |
355 | | static void CheckCast(Data* obj); |
356 | | }; |
357 | | |
358 | | class V8_EXPORT CompileHintsCollector : public Data { |
359 | | public: |
360 | | /** |
361 | | * Returns the positions of lazy functions which were compiled and executed. |
362 | | */ |
363 | | std::vector<int> GetCompileHints(Isolate* isolate) const; |
364 | | }; |
365 | | |
366 | | /** |
367 | | * A compiled JavaScript script, tied to a Context which was active when the |
368 | | * script was compiled. |
369 | | */ |
370 | | class V8_EXPORT Script : public Data { |
371 | | public: |
372 | | /** |
373 | | * A shorthand for ScriptCompiler::Compile(). |
374 | | */ |
375 | | static V8_WARN_UNUSED_RESULT MaybeLocal<Script> Compile( |
376 | | Local<Context> context, Local<String> source, |
377 | | ScriptOrigin* origin = nullptr); |
378 | | |
379 | | /** |
380 | | * Runs the script returning the resulting value. It will be run in the |
381 | | * context in which it was created (ScriptCompiler::CompileBound or |
382 | | * UnboundScript::BindToCurrentContext()). |
383 | | */ |
384 | | V8_WARN_UNUSED_RESULT MaybeLocal<Value> Run(Local<Context> context); |
385 | | V8_WARN_UNUSED_RESULT MaybeLocal<Value> Run(Local<Context> context, |
386 | | Local<Data> host_defined_options); |
387 | | |
388 | | /** |
389 | | * Returns the corresponding context-unbound script. |
390 | | */ |
391 | | Local<UnboundScript> GetUnboundScript(); |
392 | | |
393 | | /** |
394 | | * The name that was passed by the embedder as ResourceName to the |
395 | | * ScriptOrigin. This can be either a v8::String or v8::Undefined. |
396 | | */ |
397 | | Local<Value> GetResourceName(); |
398 | | |
399 | | /** |
400 | | * If the script was compiled, returns the positions of lazy functions which |
401 | | * were eventually compiled and executed. |
402 | | */ |
403 | | V8_DEPRECATE_SOON("Use GetCompileHintsCollector instead") |
404 | | std::vector<int> GetProducedCompileHints() const; |
405 | | |
406 | | /** |
407 | | * Get a compile hints collector object which we can use later for retrieving |
408 | | * compile hints (= positions of lazy functions which were compiled and |
409 | | * executed). |
410 | | */ |
411 | | Local<CompileHintsCollector> GetCompileHintsCollector() const; |
412 | | }; |
413 | | |
414 | | enum class ScriptType { kClassic, kModule }; |
415 | | |
416 | | /** |
417 | | * For compiling scripts. |
418 | | */ |
419 | | class V8_EXPORT ScriptCompiler { |
420 | | public: |
421 | | class ConsumeCodeCacheTask; |
422 | | |
423 | | /** |
424 | | * Compilation data that the embedder can cache and pass back to speed up |
425 | | * future compilations. The data is produced if the CompilerOptions passed to |
426 | | * the compilation functions in ScriptCompiler contains produce_data_to_cache |
427 | | * = true. The data to cache can then can be retrieved from |
428 | | * UnboundScript. |
429 | | */ |
430 | | struct V8_EXPORT CachedData { |
431 | | enum BufferPolicy { BufferNotOwned, BufferOwned }; |
432 | | |
433 | | CachedData() |
434 | | : data(nullptr), |
435 | | length(0), |
436 | | rejected(false), |
437 | 0 | buffer_policy(BufferNotOwned) {} |
438 | | |
439 | | // If buffer_policy is BufferNotOwned, the caller keeps the ownership of |
440 | | // data and guarantees that it stays alive until the CachedData object is |
441 | | // destroyed. If the policy is BufferOwned, the given data will be deleted |
442 | | // (with delete[]) when the CachedData object is destroyed. |
443 | | CachedData(const uint8_t* data, int length, |
444 | | BufferPolicy buffer_policy = BufferNotOwned); |
445 | | ~CachedData(); |
446 | | |
447 | | enum CompatibilityCheckResult { |
448 | | // Don't change order/existing values of this enum since it keys into the |
449 | | // `code_cache_reject_reason` histogram. Append-only! |
450 | | kSuccess = 0, |
451 | | kMagicNumberMismatch = 1, |
452 | | kVersionMismatch = 2, |
453 | | kSourceMismatch = 3, |
454 | | kFlagsMismatch = 5, |
455 | | kChecksumMismatch = 6, |
456 | | kInvalidHeader = 7, |
457 | | kLengthMismatch = 8, |
458 | | kReadOnlySnapshotChecksumMismatch = 9, |
459 | | |
460 | | // This should always point at the last real enum value. |
461 | | kLast = kReadOnlySnapshotChecksumMismatch |
462 | | }; |
463 | | |
464 | | // Check if the CachedData can be loaded in the given isolate. |
465 | | CompatibilityCheckResult CompatibilityCheck(Isolate* isolate); |
466 | | |
467 | | // TODO(marja): Async compilation; add constructors which take a callback |
468 | | // which will be called when V8 no longer needs the data. |
469 | | const uint8_t* data; |
470 | | int length; |
471 | | bool rejected; |
472 | | BufferPolicy buffer_policy; |
473 | | |
474 | | // Prevent copying. |
475 | | CachedData(const CachedData&) = delete; |
476 | | CachedData& operator=(const CachedData&) = delete; |
477 | | }; |
478 | | |
479 | | enum class InMemoryCacheResult { |
480 | | // V8 did not attempt to find this script in its in-memory cache. |
481 | | kNotAttempted, |
482 | | |
483 | | // V8 found a previously compiled copy of this script in its in-memory |
484 | | // cache. Any data generated by a streaming compilation or background |
485 | | // deserialization was abandoned. |
486 | | kHit, |
487 | | |
488 | | // V8 didn't have any previously compiled data for this script. |
489 | | kMiss, |
490 | | |
491 | | // V8 had some previously compiled data for an identical script, but the |
492 | | // data was incomplete. |
493 | | kPartial, |
494 | | }; |
495 | | |
496 | | // Details about what happened during a compilation. |
497 | | struct CompilationDetails { |
498 | | InMemoryCacheResult in_memory_cache_result = |
499 | | InMemoryCacheResult::kNotAttempted; |
500 | | |
501 | | static constexpr int64_t kTimeNotMeasured = -1; |
502 | | int64_t foreground_time_in_microseconds = kTimeNotMeasured; |
503 | | int64_t background_time_in_microseconds = kTimeNotMeasured; |
504 | | }; |
505 | | |
506 | | /** |
507 | | * Source code which can be then compiled to a UnboundScript or Script. |
508 | | */ |
509 | | class Source { |
510 | | public: |
511 | | // Source takes ownership of both CachedData and CodeCacheConsumeTask. |
512 | | // The caller *must* ensure that the cached data is from a trusted source. |
513 | | V8_INLINE Source(Local<String> source_string, const ScriptOrigin& origin, |
514 | | CachedData* cached_data = nullptr, |
515 | | ConsumeCodeCacheTask* consume_cache_task = nullptr); |
516 | | // Source takes ownership of both CachedData and CodeCacheConsumeTask. |
517 | | V8_INLINE explicit Source( |
518 | | Local<String> source_string, CachedData* cached_data = nullptr, |
519 | | ConsumeCodeCacheTask* consume_cache_task = nullptr); |
520 | | V8_INLINE Source(Local<String> source_string, const ScriptOrigin& origin, |
521 | | CompileHintCallback callback, void* callback_data); |
522 | 2.59k | V8_INLINE ~Source() = default; |
523 | | |
524 | | // Ownership of the CachedData or its buffers is *not* transferred to the |
525 | | // caller. The CachedData object is alive as long as the Source object is |
526 | | // alive. |
527 | | V8_INLINE const CachedData* GetCachedData() const; |
528 | | |
529 | | V8_INLINE const ScriptOriginOptions& GetResourceOptions() const; |
530 | | |
531 | | V8_INLINE const CompilationDetails& GetCompilationDetails() const; |
532 | | |
533 | | private: |
534 | | friend class ScriptCompiler; |
535 | | |
536 | | Local<String> source_string; |
537 | | |
538 | | // Origin information |
539 | | Local<Value> resource_name; |
540 | | int resource_line_offset = -1; |
541 | | int resource_column_offset = -1; |
542 | | ScriptOriginOptions resource_options; |
543 | | Local<Value> source_map_url; |
544 | | Local<Data> host_defined_options; |
545 | | |
546 | | // Cached data from previous compilation (if a kConsume*Cache flag is |
547 | | // set), or hold newly generated cache data (kProduce*Cache flags) are |
548 | | // set when calling a compile method. |
549 | | std::unique_ptr<CachedData> cached_data; |
550 | | std::unique_ptr<ConsumeCodeCacheTask> consume_cache_task; |
551 | | |
552 | | // For requesting compile hints from the embedder. |
553 | | CompileHintCallback compile_hint_callback = nullptr; |
554 | | void* compile_hint_callback_data = nullptr; |
555 | | |
556 | | // V8 writes this data and never reads it. It exists only to be informative |
557 | | // to the embedder. |
558 | | CompilationDetails compilation_details; |
559 | | }; |
560 | | |
561 | | /** |
562 | | * For streaming incomplete script data to V8. The embedder should implement a |
563 | | * subclass of this class. |
564 | | */ |
565 | | class V8_EXPORT ExternalSourceStream { |
566 | | public: |
567 | | virtual ~ExternalSourceStream() = default; |
568 | | |
569 | | /** |
570 | | * V8 calls this to request the next chunk of data from the embedder. This |
571 | | * function will be called on a background thread, so it's OK to block and |
572 | | * wait for the data, if the embedder doesn't have data yet. Returns the |
573 | | * length of the data returned. When the data ends, GetMoreData should |
574 | | * return 0. Caller takes ownership of the data. |
575 | | * |
576 | | * When streaming UTF-8 data, V8 handles multi-byte characters split between |
577 | | * two data chunks, but doesn't handle multi-byte characters split between |
578 | | * more than two data chunks. The embedder can avoid this problem by always |
579 | | * returning at least 2 bytes of data. |
580 | | * |
581 | | * When streaming UTF-16 data, V8 does not handle characters split between |
582 | | * two data chunks. The embedder has to make sure that chunks have an even |
583 | | * length. |
584 | | * |
585 | | * If the embedder wants to cancel the streaming, they should make the next |
586 | | * GetMoreData call return 0. V8 will interpret it as end of data (and most |
587 | | * probably, parsing will fail). The streaming task will return as soon as |
588 | | * V8 has parsed the data it received so far. |
589 | | */ |
590 | | virtual size_t GetMoreData(const uint8_t** src) = 0; |
591 | | }; |
592 | | |
593 | | /** |
594 | | * Source code which can be streamed into V8 in pieces. It will be parsed |
595 | | * while streaming and compiled after parsing has completed. StreamedSource |
596 | | * must be kept alive while the streaming task is run (see ScriptStreamingTask |
597 | | * below). |
598 | | */ |
599 | | class V8_EXPORT StreamedSource { |
600 | | public: |
601 | | enum Encoding { ONE_BYTE, TWO_BYTE, UTF8, WINDOWS_1252 }; |
602 | | |
603 | | StreamedSource(std::unique_ptr<ExternalSourceStream> source_stream, |
604 | | Encoding encoding); |
605 | | ~StreamedSource(); |
606 | | |
607 | 0 | internal::ScriptStreamingData* impl() const { return impl_.get(); } |
608 | | |
609 | | // Prevent copying. |
610 | | StreamedSource(const StreamedSource&) = delete; |
611 | | StreamedSource& operator=(const StreamedSource&) = delete; |
612 | | |
613 | 0 | CompilationDetails& compilation_details() { return compilation_details_; } |
614 | | |
615 | | private: |
616 | | std::unique_ptr<internal::ScriptStreamingData> impl_; |
617 | | |
618 | | // V8 writes this data and never reads it. It exists only to be informative |
619 | | // to the embedder. |
620 | | CompilationDetails compilation_details_; |
621 | | }; |
622 | | |
623 | | /** |
624 | | * A streaming task which the embedder must run on a background thread to |
625 | | * stream scripts into V8. Returned by ScriptCompiler::StartStreaming. |
626 | | */ |
627 | | class V8_EXPORT ScriptStreamingTask final { |
628 | | public: |
629 | | void Run(); |
630 | | |
631 | | private: |
632 | | friend class ScriptCompiler; |
633 | | |
634 | | explicit ScriptStreamingTask(internal::ScriptStreamingData* data) |
635 | 0 | : data_(data) {} |
636 | | |
637 | | internal::ScriptStreamingData* data_; |
638 | | }; |
639 | | |
640 | | /** |
641 | | * A task which the embedder must run on a background thread to |
642 | | * consume a V8 code cache. Returned by |
643 | | * ScriptCompiler::StartConsumingCodeCache. |
644 | | */ |
645 | | class V8_EXPORT ConsumeCodeCacheTask final { |
646 | | public: |
647 | | ~ConsumeCodeCacheTask(); |
648 | | |
649 | | void Run(); |
650 | | |
651 | | /** |
652 | | * Provides the source text string and origin information to the consumption |
653 | | * task. May be called before, during, or after Run(). This step checks |
654 | | * whether the script matches an existing script in the Isolate's |
655 | | * compilation cache. To check whether such a script was found, call |
656 | | * ShouldMergeWithExistingScript. |
657 | | * |
658 | | * The Isolate provided must be the same one used during |
659 | | * StartConsumingCodeCache and must be currently entered on the thread that |
660 | | * calls this function. The source text and origin provided in this step |
661 | | * must precisely match those used later in the ScriptCompiler::Source that |
662 | | * will contain this ConsumeCodeCacheTask. |
663 | | */ |
664 | | void SourceTextAvailable(Isolate* isolate, Local<String> source_text, |
665 | | const ScriptOrigin& origin); |
666 | | |
667 | | /** |
668 | | * Returns whether the embedder should call MergeWithExistingScript. This |
669 | | * function may be called from any thread, any number of times, but its |
670 | | * return value is only meaningful after SourceTextAvailable has completed. |
671 | | */ |
672 | | bool ShouldMergeWithExistingScript() const; |
673 | | |
674 | | /** |
675 | | * Merges newly deserialized data into an existing script which was found |
676 | | * during SourceTextAvailable. May be called only after Run() has completed. |
677 | | * Can execute on any thread, like Run(). |
678 | | */ |
679 | | void MergeWithExistingScript(); |
680 | | |
681 | | private: |
682 | | friend class ScriptCompiler; |
683 | | |
684 | | explicit ConsumeCodeCacheTask( |
685 | | std::unique_ptr<internal::BackgroundDeserializeTask> impl); |
686 | | |
687 | | std::unique_ptr<internal::BackgroundDeserializeTask> impl_; |
688 | | }; |
689 | | |
690 | | enum CompileOptions { |
691 | | kNoCompileOptions = 0, |
692 | | kConsumeCodeCache = 1 << 0, |
693 | | kEagerCompile = 1 << 1, |
694 | | kProduceCompileHints = 1 << 2, |
695 | | kConsumeCompileHints = 1 << 3, |
696 | | kFollowCompileHintsMagicComment = 1 << 4, |
697 | | kFollowCompileHintsPerFunctionMagicComment = 1 << 5, |
698 | | }; |
699 | | |
700 | 0 | static inline bool CompileOptionsIsValid(CompileOptions compile_options) { |
701 | 0 | // kConsumeCodeCache is mutually exclusive with all other flag bits. |
702 | 0 | if ((compile_options & kConsumeCodeCache) && |
703 | 0 | compile_options != kConsumeCodeCache) { |
704 | 0 | return false; |
705 | 0 | } |
706 | 0 | // kEagerCompile is mutually exclusive with all other flag bits. |
707 | 0 | if ((compile_options & kEagerCompile) && compile_options != kEagerCompile) { |
708 | 0 | return false; |
709 | 0 | } |
710 | 0 | // We don't currently support producing and consuming compile hints at the |
711 | 0 | // same time. |
712 | 0 | constexpr int produce_and_consume = CompileOptions::kProduceCompileHints | |
713 | 0 | CompileOptions::kConsumeCompileHints; |
714 | 0 | if ((compile_options & produce_and_consume) == produce_and_consume) { |
715 | 0 | return false; |
716 | 0 | } |
717 | 0 | return true; |
718 | 0 | } |
719 | | |
720 | | /** |
721 | | * The reason for which we are not requesting or providing a code cache. |
722 | | */ |
723 | | enum NoCacheReason { |
724 | | kNoCacheNoReason = 0, |
725 | | kNoCacheBecauseCachingDisabled, |
726 | | kNoCacheBecauseNoResource, |
727 | | kNoCacheBecauseInlineScript, |
728 | | kNoCacheBecauseModule, |
729 | | kNoCacheBecauseStreamingSource, |
730 | | kNoCacheBecauseInspector, |
731 | | kNoCacheBecauseScriptTooSmall, |
732 | | kNoCacheBecauseCacheTooCold, |
733 | | kNoCacheBecauseV8Extension, |
734 | | kNoCacheBecauseExtensionModule, |
735 | | kNoCacheBecausePacScript, |
736 | | kNoCacheBecauseInDocumentWrite, |
737 | | kNoCacheBecauseResourceWithNoCacheHandler, |
738 | | kNoCacheBecauseDeferredProduceCodeCache, |
739 | | kNoCacheBecauseStaticCodeCache, |
740 | | }; |
741 | | |
742 | | /** |
743 | | * Compiles the specified script (context-independent). |
744 | | * Cached data as part of the source object can be optionally produced to be |
745 | | * consumed later to speed up compilation of identical source scripts. |
746 | | * |
747 | | * Note that when producing cached data, the source must point to NULL for |
748 | | * cached data. When consuming cached data, the cached data must have been |
749 | | * produced by the same version of V8, and the embedder needs to ensure the |
750 | | * cached data is the correct one for the given script. |
751 | | * |
752 | | * \param source Script source code. |
753 | | * \return Compiled script object (context independent; for running it must be |
754 | | * bound to a context). |
755 | | */ |
756 | | static V8_WARN_UNUSED_RESULT MaybeLocal<UnboundScript> CompileUnboundScript( |
757 | | Isolate* isolate, Source* source, |
758 | | CompileOptions options = kNoCompileOptions, |
759 | | NoCacheReason no_cache_reason = kNoCacheNoReason); |
760 | | |
761 | | /** |
762 | | * Compiles the specified script (bound to current context). |
763 | | * |
764 | | * \param source Script source code. |
765 | | * \param pre_data Pre-parsing data, as obtained by ScriptData::PreCompile() |
766 | | * using pre_data speeds compilation if it's done multiple times. |
767 | | * Owned by caller, no references are kept when this function returns. |
768 | | * \return Compiled script object, bound to the context that was active |
769 | | * when this function was called. When run it will always use this |
770 | | * context. |
771 | | */ |
772 | | static V8_WARN_UNUSED_RESULT MaybeLocal<Script> Compile( |
773 | | Local<Context> context, Source* source, |
774 | | CompileOptions options = kNoCompileOptions, |
775 | | NoCacheReason no_cache_reason = kNoCacheNoReason); |
776 | | |
777 | | /** |
778 | | * Returns a task which streams script data into V8, or NULL if the script |
779 | | * cannot be streamed. The user is responsible for running the task on a |
780 | | * background thread and deleting it. When ran, the task starts parsing the |
781 | | * script, and it will request data from the StreamedSource as needed. When |
782 | | * ScriptStreamingTask::Run exits, all data has been streamed and the script |
783 | | * can be compiled (see Compile below). |
784 | | * |
785 | | * This API allows to start the streaming with as little data as possible, and |
786 | | * the remaining data (for example, the ScriptOrigin) is passed to Compile. |
787 | | */ |
788 | | static ScriptStreamingTask* StartStreaming( |
789 | | Isolate* isolate, StreamedSource* source, |
790 | | ScriptType type = ScriptType::kClassic, |
791 | | CompileOptions options = kNoCompileOptions, |
792 | | CompileHintCallback compile_hint_callback = nullptr, |
793 | | void* compile_hint_callback_data = nullptr); |
794 | | |
795 | | static ConsumeCodeCacheTask* StartConsumingCodeCache( |
796 | | Isolate* isolate, std::unique_ptr<CachedData> source); |
797 | | static ConsumeCodeCacheTask* StartConsumingCodeCacheOnBackground( |
798 | | Isolate* isolate, std::unique_ptr<CachedData> source); |
799 | | |
800 | | /** |
801 | | * Compiles a streamed script (bound to current context). |
802 | | * |
803 | | * This can only be called after the streaming has finished |
804 | | * (ScriptStreamingTask has been run). V8 doesn't construct the source string |
805 | | * during streaming, so the embedder needs to pass the full source here. |
806 | | */ |
807 | | static V8_WARN_UNUSED_RESULT MaybeLocal<Script> Compile( |
808 | | Local<Context> context, StreamedSource* source, |
809 | | Local<String> full_source_string, const ScriptOrigin& origin); |
810 | | |
811 | | /** |
812 | | * Return a version tag for CachedData for the current V8 version & flags. |
813 | | * |
814 | | * This value is meant only for determining whether a previously generated |
815 | | * CachedData instance is still valid; the tag has no other meaing. |
816 | | * |
817 | | * Background: The data carried by CachedData may depend on the exact |
818 | | * V8 version number or current compiler flags. This means that when |
819 | | * persisting CachedData, the embedder must take care to not pass in |
820 | | * data from another V8 version, or the same version with different |
821 | | * features enabled. |
822 | | * |
823 | | * The easiest way to do so is to clear the embedder's cache on any |
824 | | * such change. |
825 | | * |
826 | | * Alternatively, this tag can be stored alongside the cached data and |
827 | | * compared when it is being used. |
828 | | */ |
829 | | static uint32_t CachedDataVersionTag(); |
830 | | |
831 | | /** |
832 | | * Compile an ES module, returning a Module that encapsulates |
833 | | * the compiled code. |
834 | | * |
835 | | * Corresponds to the ParseModule abstract operation in the |
836 | | * ECMAScript specification. |
837 | | */ |
838 | | static V8_WARN_UNUSED_RESULT MaybeLocal<Module> CompileModule( |
839 | | Isolate* isolate, Source* source, |
840 | | CompileOptions options = kNoCompileOptions, |
841 | | NoCacheReason no_cache_reason = kNoCacheNoReason); |
842 | | |
843 | | /** |
844 | | * Compiles a streamed module script. |
845 | | * |
846 | | * This can only be called after the streaming has finished |
847 | | * (ScriptStreamingTask has been run). V8 doesn't construct the source string |
848 | | * during streaming, so the embedder needs to pass the full source here. |
849 | | */ |
850 | | static V8_WARN_UNUSED_RESULT MaybeLocal<Module> CompileModule( |
851 | | Local<Context> context, StreamedSource* v8_source, |
852 | | Local<String> full_source_string, const ScriptOrigin& origin); |
853 | | |
854 | | /** |
855 | | * Compile a function for a given context. This is equivalent to running |
856 | | * |
857 | | * with (obj) { |
858 | | * return function(args) { ... } |
859 | | * } |
860 | | * |
861 | | * It is possible to specify multiple context extensions (obj in the above |
862 | | * example). |
863 | | */ |
864 | | static V8_WARN_UNUSED_RESULT MaybeLocal<Function> CompileFunction( |
865 | | Local<Context> context, Source* source, size_t arguments_count = 0, |
866 | | Local<String> arguments[] = nullptr, size_t context_extension_count = 0, |
867 | | Local<Object> context_extensions[] = nullptr, |
868 | | CompileOptions options = kNoCompileOptions, |
869 | | NoCacheReason no_cache_reason = kNoCacheNoReason); |
870 | | |
871 | | /** |
872 | | * Creates and returns code cache for the specified unbound_script. |
873 | | * This will return nullptr if the script cannot be serialized. The |
874 | | * CachedData returned by this function should be owned by the caller. |
875 | | */ |
876 | | static CachedData* CreateCodeCache(Local<UnboundScript> unbound_script); |
877 | | |
878 | | /** |
879 | | * Creates and returns code cache for the specified unbound_module_script. |
880 | | * This will return nullptr if the script cannot be serialized. The |
881 | | * CachedData returned by this function should be owned by the caller. |
882 | | */ |
883 | | static CachedData* CreateCodeCache( |
884 | | Local<UnboundModuleScript> unbound_module_script); |
885 | | |
886 | | /** |
887 | | * Creates and returns code cache for the specified function that was |
888 | | * previously produced by CompileFunction. |
889 | | * This will return nullptr if the script cannot be serialized. The |
890 | | * CachedData returned by this function should be owned by the caller. |
891 | | */ |
892 | | static CachedData* CreateCodeCacheForFunction(Local<Function> function); |
893 | | |
894 | | private: |
895 | | static V8_WARN_UNUSED_RESULT MaybeLocal<UnboundScript> CompileUnboundInternal( |
896 | | Isolate* isolate, Source* source, CompileOptions options, |
897 | | NoCacheReason no_cache_reason); |
898 | | |
899 | | static V8_WARN_UNUSED_RESULT MaybeLocal<Function> CompileFunctionInternal( |
900 | | Local<Context> context, Source* source, size_t arguments_count, |
901 | | Local<String> arguments[], size_t context_extension_count, |
902 | | Local<Object> context_extensions[], CompileOptions options, |
903 | | NoCacheReason no_cache_reason, |
904 | | Local<ScriptOrModule>* script_or_module_out); |
905 | | }; |
906 | | |
907 | | ScriptCompiler::Source::Source(Local<String> string, const ScriptOrigin& origin, |
908 | | CachedData* data, |
909 | | ConsumeCodeCacheTask* consume_cache_task) |
910 | 2.59k | : source_string(string), |
911 | 2.59k | resource_name(origin.ResourceName()), |
912 | 2.59k | resource_line_offset(origin.LineOffset()), |
913 | 2.59k | resource_column_offset(origin.ColumnOffset()), |
914 | 2.59k | resource_options(origin.Options()), |
915 | 2.59k | source_map_url(origin.SourceMapUrl()), |
916 | 2.59k | host_defined_options(origin.GetHostDefinedOptions()), |
917 | 2.59k | cached_data(data), |
918 | 2.59k | consume_cache_task(consume_cache_task) {} |
919 | | |
920 | | ScriptCompiler::Source::Source(Local<String> string, CachedData* data, |
921 | | ConsumeCodeCacheTask* consume_cache_task) |
922 | | : source_string(string), |
923 | | cached_data(data), |
924 | | consume_cache_task(consume_cache_task) {} |
925 | | |
926 | | ScriptCompiler::Source::Source(Local<String> string, const ScriptOrigin& origin, |
927 | | CompileHintCallback callback, |
928 | | void* callback_data) |
929 | | : source_string(string), |
930 | | resource_name(origin.ResourceName()), |
931 | | resource_line_offset(origin.LineOffset()), |
932 | | resource_column_offset(origin.ColumnOffset()), |
933 | | resource_options(origin.Options()), |
934 | | source_map_url(origin.SourceMapUrl()), |
935 | | host_defined_options(origin.GetHostDefinedOptions()), |
936 | | compile_hint_callback(callback), |
937 | | compile_hint_callback_data(callback_data) {} |
938 | | |
939 | | const ScriptCompiler::CachedData* ScriptCompiler::Source::GetCachedData() |
940 | 0 | const { |
941 | 0 | return cached_data.get(); |
942 | 0 | } |
943 | | |
944 | 0 | const ScriptOriginOptions& ScriptCompiler::Source::GetResourceOptions() const { |
945 | 0 | return resource_options; |
946 | 0 | } |
947 | | |
948 | | const ScriptCompiler::CompilationDetails& |
949 | 0 | ScriptCompiler::Source::GetCompilationDetails() const { |
950 | 0 | return compilation_details; |
951 | 0 | } |
952 | | |
953 | 0 | ModuleRequest* ModuleRequest::Cast(Data* data) { |
954 | 0 | #ifdef V8_ENABLE_CHECKS |
955 | 0 | CheckCast(data); |
956 | 0 | #endif |
957 | 0 | return reinterpret_cast<ModuleRequest*>(data); |
958 | 0 | } |
959 | | |
960 | 0 | Module* Module::Cast(Data* data) { |
961 | 0 | #ifdef V8_ENABLE_CHECKS |
962 | 0 | CheckCast(data); |
963 | 0 | #endif |
964 | 0 | return reinterpret_cast<Module*>(data); |
965 | 0 | } |
966 | | |
967 | | } // namespace v8 |
968 | | |
969 | | #endif // INCLUDE_V8_SCRIPT_H_ |