| // Copyright 2019 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_OBJECTS_SOURCE_TEXT_MODULE_H_ |
| #define V8_OBJECTS_SOURCE_TEXT_MODULE_H_ |
| |
| #include "src/base/bit-field.h" |
| #include "src/objects/contexts.h" |
| #include "src/objects/module.h" |
| #include "src/objects/promise.h" |
| #include "src/objects/string.h" |
| #include "src/zone/zone-containers.h" |
| |
| // Has to be the last include (doesn't have include guards): |
| #include "src/objects/object-macros.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| class UnorderedModuleSet; |
| class StructBodyDescriptor; |
| |
| // The runtime representation of an ECMAScript Source Text Module Record. |
| // https://tc39.es/ecma262/#sec-source-text-module-records |
| V8_OBJECT class SourceTextModule : public Module { |
| public: |
| DECL_VERIFIER(SourceTextModule) |
| DECL_PRINTER(SourceTextModule) |
| |
| // The shared function info in case {status} is not kEvaluating, kEvaluated or |
| // kErrored. |
| Tagged<SharedFunctionInfo> GetSharedFunctionInfo() const; |
| |
| Tagged<Script> GetScript() const; |
| |
| // Whether or not this module contains a toplevel await. Set during module |
| // creation and does not change afterwards. |
| DECL_BOOLEAN_ACCESSORS(has_toplevel_await) |
| |
| // Get the SourceTextModuleInfo associated with the code. |
| inline Tagged<SourceTextModuleInfo> info() const; |
| |
| Tagged<Cell> GetCell(int cell_index); |
| static Handle<Object> LoadVariable(Isolate* isolate, |
| DirectHandle<SourceTextModule> module, |
| int cell_index); |
| static void StoreVariable(DirectHandle<SourceTextModule> module, |
| int cell_index, DirectHandle<Object> value); |
| |
| static int ImportIndex(int cell_index); |
| static int ExportIndex(int cell_index); |
| |
| // Used by builtins to fulfill or reject the promise associated |
| // with async SourceTextModules. Return Nothing if the execution is |
| // terminated. |
| static Maybe<bool> AsyncModuleExecutionFulfilled( |
| Isolate* isolate, Handle<SourceTextModule> module); |
| static void AsyncModuleExecutionRejected( |
| Isolate* isolate, DirectHandle<SourceTextModule> module, |
| DirectHandle<Object> exception); |
| |
| // Get the namespace object for [module_request] of [module]. If it doesn't |
| // exist yet, it is created. |
| static DirectHandle<JSModuleNamespace> GetModuleNamespace( |
| Isolate* isolate, DirectHandle<SourceTextModule> module, |
| int module_request_index); |
| |
| // Get the import.meta object of [module]. If it doesn't exist yet, it is |
| // created and passed to the embedder callback for initialization. |
| V8_EXPORT_PRIVATE static MaybeHandle<JSObject> GetImportMeta( |
| Isolate* isolate, DirectHandle<SourceTextModule> module); |
| |
| static constexpr unsigned kFirstAsyncEvaluationOrdinal = 2; |
| |
| enum ExecuteAsyncModuleContextSlots { |
| kModule = Context::MIN_CONTEXT_SLOTS, |
| kContextLength, |
| }; |
| |
| V8_EXPORT_PRIVATE |
| std::pair<DirectHandleVector<SourceTextModule>, |
| DirectHandleVector<JSMessageObject>> |
| GetStalledTopLevelAwaitMessages(Isolate* isolate); |
| |
| // https://tc39.es/proposal-defer-import-eval/#sec-IsModuleSCCEvaluated |
| // This function checks if the Strongly Connected Component (SCC) that the |
| // module participates is evaluated. |
| static bool IsModuleSCCEvaluated(Handle<SourceTextModule> module); |
| |
| static void GatherAsynchronousTransitiveDependencies( |
| Isolate* isolate, Handle<Module> module, |
| UnorderedModuleSet* evaluation_set, |
| ZoneVector<Handle<SourceTextModule>>* evaluation_list, |
| UnorderedModuleSet* seen); |
| |
| static bool ReadyForSyncExecution(Isolate* isolate, Handle<Module> module, |
| UnorderedModuleSet* seen); |
| |
| inline Tagged<UnionOf<SharedFunctionInfo, JSFunction, JSGeneratorObject>> |
| code() const; |
| inline void set_code( |
| Tagged<UnionOf<SharedFunctionInfo, JSFunction, JSGeneratorObject>> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<FixedArray> regular_exports() const; |
| inline void set_regular_exports(Tagged<FixedArray> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<FixedArray> regular_imports() const; |
| inline void set_regular_imports(Tagged<FixedArray> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<FixedArray> requested_modules() const; |
| inline void set_requested_modules( |
| Tagged<FixedArray> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<UnionOf<TheHole, JSObject>> import_meta(AcquireLoadTag) const; |
| inline void set_import_meta(Tagged<UnionOf<TheHole, JSObject>> value, |
| ReleaseStoreTag, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<UnionOf<SourceTextModule, TheHole>> cycle_root() const; |
| inline void set_cycle_root(Tagged<UnionOf<SourceTextModule, TheHole>> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<ArrayList> async_parent_modules() const; |
| inline void set_async_parent_modules( |
| Tagged<ArrayList> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline int dfs_index() const; |
| inline void set_dfs_index(int value); |
| |
| inline int dfs_ancestor_index() const; |
| inline void set_dfs_ancestor_index(int value); |
| |
| inline int pending_async_dependencies() const; |
| inline void set_pending_async_dependencies(int value); |
| |
| inline uint32_t flags() const; |
| inline void set_flags(uint32_t value); |
| |
| private: |
| friend class Factory; |
| friend class Module; |
| |
| struct AsyncEvaluationOrdinalCompare; |
| using AvailableAncestorsSet = |
| ZoneSet<Handle<SourceTextModule>, AsyncEvaluationOrdinalCompare>; |
| |
| // Appends a tuple of module and generator to the async parent modules |
| // ArrayList. |
| inline static void AddAsyncParentModule( |
| Isolate* isolate, DirectHandle<SourceTextModule> module, |
| DirectHandle<SourceTextModule> parent); |
| |
| // Get the non-hole cycle root. Only valid when status >= kEvaluated. |
| inline Handle<SourceTextModule> GetCycleRoot(Isolate* isolate) const; |
| |
| // Returns a SourceTextModule, the |
| // ith parent in depth first traversal order of a given async child. |
| inline Handle<SourceTextModule> GetAsyncParentModule(Isolate* isolate, |
| uint32_t index); |
| |
| // Returns the number of async parent modules for a given async child. |
| inline uint32_t AsyncParentModuleCount(); |
| |
| inline bool HasAsyncEvaluationOrdinal() const; |
| |
| inline bool HasPendingAsyncDependencies(); |
| inline void IncrementPendingAsyncDependencies(); |
| inline void DecrementPendingAsyncDependencies(); |
| |
| // Bits for flags. |
| using HasToplevelAwaitBit = base::BitField<bool, 0, 1, uint32_t>; |
| using AsyncEvaluationOrdinalBits = HasToplevelAwaitBit::Next<uint32_t, 30>; |
| friend class TorqueGeneratedBitFieldAsserts; |
| |
| // async_evaluation_ordinal, top_level_capability, pending_async_dependencies, |
| // and async_parent_modules are used exclusively during evaluation of async |
| // modules and the modules which depend on them. |
| // |
| // If >1, this module is async and evaluating or currently evaluating an async |
| // child. The integer is an ordinal for when this module first started async |
| // evaluation and is used for sorting async parent modules when determining |
| // which parent module can start executing after an async evaluation |
| // completes. |
| // |
| // If 1, this module has finished async evaluating. |
| // |
| // If 0, this module is not async or has not been async evaluated. |
| static constexpr unsigned kNotAsyncEvaluated = 0; |
| static constexpr unsigned kAsyncEvaluateDidFinish = 1; |
| static_assert(kNotAsyncEvaluated < kAsyncEvaluateDidFinish); |
| static_assert(kAsyncEvaluateDidFinish < kFirstAsyncEvaluationOrdinal); |
| DECL_PRIMITIVE_ACCESSORS(async_evaluation_ordinal, unsigned) |
| |
| // Helpers for Instantiate and Evaluate. |
| static void CreateExport(Isolate* isolate, |
| DirectHandle<SourceTextModule> module, |
| int cell_index, DirectHandle<FixedArray> names); |
| static void CreateIndirectExport( |
| Isolate* isolate, DirectHandle<SourceTextModule> module, |
| DirectHandle<String> name, DirectHandle<SourceTextModuleInfoEntry> entry); |
| |
| static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveExport( |
| Isolate* isolate, Handle<SourceTextModule> module, |
| DirectHandle<String> module_specifier, Handle<String> export_name, |
| MessageLocation loc, bool must_resolve, ResolveSet* resolve_set); |
| static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveImport( |
| Isolate* isolate, DirectHandle<SourceTextModule> module, |
| MaybeHandle<String> name, int module_request_index, MessageLocation loc, |
| bool must_resolve, ResolveSet* resolve_set); |
| |
| static V8_WARN_UNUSED_RESULT MaybeHandle<Cell> ResolveExportUsingStarExports( |
| Isolate* isolate, DirectHandle<SourceTextModule> module, |
| DirectHandle<String> module_specifier, Handle<String> export_name, |
| MessageLocation loc, bool must_resolve, ResolveSet* resolve_set); |
| |
| static V8_WARN_UNUSED_RESULT bool PrepareInstantiate( |
| Isolate* isolate, DirectHandle<SourceTextModule> module, |
| v8::Local<v8::Context> context, |
| const Module::UserResolveCallbacks& callbacks); |
| static V8_WARN_UNUSED_RESULT bool FinishInstantiate( |
| Isolate* isolate, Handle<SourceTextModule> module, |
| ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index, |
| Zone* zone, unsigned depth, unsigned* max_depth); |
| static V8_WARN_UNUSED_RESULT bool RunInitializationCode( |
| Isolate* isolate, DirectHandle<SourceTextModule> module); |
| |
| static void FetchStarExports(Isolate* isolate, |
| Handle<SourceTextModule> module, Zone* zone, |
| UnorderedModuleSet* visited); |
| |
| static void GatherAvailableAncestors(Isolate* isolate, Zone* zone, |
| Handle<SourceTextModule> start, |
| AvailableAncestorsSet* exec_list); |
| |
| // Implementation of spec concrete method Evaluate. |
| static V8_WARN_UNUSED_RESULT MaybeDirectHandle<JSPromise> Evaluate( |
| Isolate* isolate, Handle<SourceTextModule> module); |
| |
| // Implementation of spec abstract operation InnerModuleEvaluation. |
| static V8_WARN_UNUSED_RESULT MaybeDirectHandle<Object> InnerModuleEvaluation( |
| Isolate* isolate, Handle<SourceTextModule> module, |
| ZoneForwardList<Handle<SourceTextModule>>* stack, unsigned* dfs_index); |
| |
| // Returns true if the evaluation exception was catchable by js, and false |
| // for termination exceptions. |
| bool MaybeHandleEvaluationException( |
| Isolate* isolate, ZoneForwardList<Handle<SourceTextModule>>* stack); |
| |
| static V8_WARN_UNUSED_RESULT bool MaybeTransitionComponent( |
| Isolate* isolate, DirectHandle<SourceTextModule> module, |
| ZoneForwardList<Handle<SourceTextModule>>* stack, Status new_status); |
| |
| // Implementation of spec ExecuteModule is broken up into |
| // InnerExecuteAsyncModule for asynchronous modules and ExecuteModule |
| // for synchronous modules. |
| static V8_WARN_UNUSED_RESULT MaybeDirectHandle<Object> |
| InnerExecuteAsyncModule(Isolate* isolate, |
| DirectHandle<SourceTextModule> module, |
| DirectHandle<JSPromise> capability); |
| |
| static V8_WARN_UNUSED_RESULT MaybeDirectHandle<Object> ExecuteModule( |
| Isolate* isolate, DirectHandle<SourceTextModule> module, |
| MaybeDirectHandle<Object>* exception_out); |
| |
| // Implementation of spec ExecuteAsyncModule. Return Nothing if the execution |
| // is been terminated. |
| static V8_WARN_UNUSED_RESULT Maybe<bool> ExecuteAsyncModule( |
| Isolate* isolate, DirectHandle<SourceTextModule> module); |
| |
| static void Reset(Isolate* isolate, DirectHandle<SourceTextModule> module); |
| |
| V8_EXPORT_PRIVATE void InnerGetStalledTopLevelAwaitModule( |
| Isolate* isolate, UnorderedModuleSet* visited, |
| DirectHandleVector<SourceTextModule>* result); |
| |
| public: |
| TaggedMember<UnionOf<SharedFunctionInfo, JSFunction, JSGeneratorObject>> |
| code_; |
| TaggedMember<FixedArray> regular_exports_; |
| TaggedMember<FixedArray> regular_imports_; |
| TaggedMember<FixedArray> requested_modules_; |
| TaggedMember<UnionOf<TheHole, JSObject>> import_meta_; |
| TaggedMember<UnionOf<SourceTextModule, TheHole>> cycle_root_; |
| TaggedMember<ArrayList> async_parent_modules_; |
| TaggedMember<Smi> dfs_index_; |
| TaggedMember<Smi> dfs_ancestor_index_; |
| TaggedMember<Smi> pending_async_dependencies_; |
| TaggedMember<Smi> flags_; |
| } V8_OBJECT_END; |
| |
| template <> |
| struct ObjectTraits<SourceTextModule> { |
| using BodyDescriptor = SubclassBodyDescriptor< |
| ObjectTraits<Module>::BodyDescriptor, |
| FixedBodyDescriptor<offsetof(SourceTextModule, code_), |
| sizeof(SourceTextModule), sizeof(SourceTextModule)>>; |
| }; |
| |
| // SourceTextModuleInfo is to SourceTextModuleDescriptor what ScopeInfo is to |
| // Scope. |
| class SourceTextModuleInfo : public FixedArray { |
| V8_IT_NO_AUTO_CHECKER; |
| |
| public: |
| template <typename IsolateT> |
| V8_EXPORT_PRIVATE static DirectHandle<SourceTextModuleInfo> New( |
| IsolateT* isolate, Zone* zone, SourceTextModuleDescriptor* descr); |
| |
| inline Tagged<FixedArray> module_requests() const; |
| inline Tagged<FixedArray> special_exports() const; |
| inline Tagged<FixedArray> regular_exports() const; |
| inline Tagged<FixedArray> regular_imports() const; |
| inline Tagged<FixedArray> namespace_imports() const; |
| |
| // Accessors for [regular_exports]. |
| uint32_t RegularExportCount() const; |
| Tagged<String> RegularExportLocalName(int i) const; |
| int RegularExportCellIndex(int i) const; |
| Tagged<FixedArray> RegularExportExportNames(int i) const; |
| |
| inline bool Equals(Tagged<SourceTextModuleInfo> other) const; |
| |
| // Whether the module has at least one `export * from '...'` statement. |
| bool HasStarExports() const; |
| |
| private: |
| template <typename Impl> |
| friend class FactoryBase; |
| friend class SourceTextModuleDescriptor; |
| enum : uint32_t { |
| kModuleRequestsIndex, |
| kSpecialExportsIndex, |
| kRegularExportsIndex, |
| kNamespaceImportsIndex, |
| kRegularImportsIndex, |
| kLength |
| }; |
| enum : uint32_t { |
| kRegularExportLocalNameOffset, |
| kRegularExportCellIndexOffset, |
| kRegularExportExportNamesOffset, |
| kRegularExportLength |
| }; |
| }; |
| |
| V8_OBJECT class ModuleRequest : public Struct { |
| public: |
| inline Tagged<String> specifier() const; |
| inline void set_specifier(Tagged<String> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<FixedArray> import_attributes() const; |
| inline void set_import_attributes( |
| Tagged<FixedArray> value, WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline uint32_t flags() const; |
| inline void set_flags(uint32_t value); |
| |
| DECL_VERIFIER(ModuleRequest) |
| DECL_PRINTER(ModuleRequest) |
| |
| template <typename IsolateT> |
| V8_EXPORT_PRIVATE static Handle<ModuleRequest> New( |
| IsolateT* isolate, DirectHandle<String> specifier, |
| ModuleImportPhase phase, DirectHandle<FixedArray> import_attributes, |
| int position); |
| |
| // The number of entries in the import_attributes FixedArray that are used for |
| // a single attribute. |
| static const size_t kAttributeEntrySize = 3; |
| |
| // Bits for flags. |
| using PhaseBits = base::BitField<ModuleImportPhase, 0, 2, uint32_t>; |
| using PositionBits = PhaseBits::Next<uint32_t, 29>; |
| static_assert(PositionBits::kMax >= String::kMaxLength, |
| "String::kMaxLength should fit in PositionBits::kMax"); |
| DECL_PRIMITIVE_ACCESSORS(position, unsigned) |
| inline void set_phase(ModuleImportPhase phase); |
| inline ModuleImportPhase phase() const; |
| |
| using BodyDescriptor = StructBodyDescriptor; |
| |
| public: |
| TaggedMember<String> specifier_; |
| TaggedMember<FixedArray> import_attributes_; |
| TaggedMember<Smi> flags_; |
| } V8_OBJECT_END; |
| |
| V8_OBJECT class SourceTextModuleInfoEntry : public Struct { |
| public: |
| inline Tagged<UnionOf<String, Undefined>> export_name() const; |
| inline void set_export_name(Tagged<UnionOf<String, Undefined>> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<UnionOf<String, Undefined>> local_name() const; |
| inline void set_local_name(Tagged<UnionOf<String, Undefined>> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline Tagged<UnionOf<String, Undefined>> import_name() const; |
| inline void set_import_name(Tagged<UnionOf<String, Undefined>> value, |
| WriteBarrierMode mode = UPDATE_WRITE_BARRIER); |
| |
| inline int module_request() const; |
| inline void set_module_request(int value); |
| |
| inline int cell_index() const; |
| inline void set_cell_index(int value); |
| |
| inline int beg_pos() const; |
| inline void set_beg_pos(int value); |
| |
| inline int end_pos() const; |
| inline void set_end_pos(int value); |
| |
| DECL_VERIFIER(SourceTextModuleInfoEntry) |
| DECL_PRINTER(SourceTextModuleInfoEntry) |
| |
| template <typename IsolateT> |
| V8_EXPORT_PRIVATE static Handle<SourceTextModuleInfoEntry> New( |
| IsolateT* isolate, DirectHandle<UnionOf<String, Undefined>> export_name, |
| DirectHandle<UnionOf<String, Undefined>> local_name, |
| DirectHandle<UnionOf<String, Undefined>> import_name, int module_request, |
| int cell_index, int beg_pos, int end_pos); |
| |
| using BodyDescriptor = StructBodyDescriptor; |
| |
| public: |
| TaggedMember<UnionOf<String, Undefined>> export_name_; |
| TaggedMember<UnionOf<String, Undefined>> local_name_; |
| TaggedMember<UnionOf<String, Undefined>> import_name_; |
| TaggedMember<Smi> module_request_; |
| TaggedMember<Smi> cell_index_; |
| TaggedMember<Smi> beg_pos_; |
| TaggedMember<Smi> end_pos_; |
| } V8_OBJECT_END; |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #include "src/objects/object-macros-undef.h" |
| |
| #endif // V8_OBJECTS_SOURCE_TEXT_MODULE_H_ |