@ 261106.3 · fetching
current
// 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)

#if defined(DEBUG) || defined(VERIFY_HEAP)
  void VerifyRequestedModules() const;
#endif

  // 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_