#ifndef SRC_MODULE_WRAP_H_ #define SRC_MODULE_WRAP_H_ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include #include #include #include #include "base_object.h" #include "v8-script.h" namespace node { class IsolateData; class Environment; class ExternalReferenceRegistry; namespace contextify { class ContextifyContext; } namespace loader { enum ScriptType : int { kScript, kModule, kFunction, }; enum HostDefinedOptions : int { kID = 8, kLength = 9, }; enum ModulePhase : int { kSourcePhase = 1, kEvaluationPhase = 2, }; /** * ModuleCacheKey is used to uniquely identify a module request * in the module cache. It is a composition of the module specifier * and the import attributes. ModuleImportPhase is not included * in the key. */ struct ModuleCacheKey : public MemoryRetainer { using ImportAttributeVector = std::vector>; std::string specifier; ImportAttributeVector import_attributes; // A hash of the specifier, and import attributes. // This does not guarantee uniqueness, but is used to reduce // the number of comparisons needed when checking for equality. std::size_t hash; SET_MEMORY_INFO_NAME(ModuleCacheKey) SET_SELF_SIZE(ModuleCacheKey) void MemoryInfo(MemoryTracker* tracker) const override; // Returns a string representation of the ModuleCacheKey. std::string ToString() const; template static ModuleCacheKey From(v8::Local specifier, v8::Local import_attributes); static ModuleCacheKey From(v8::Local v8_request); struct Hash { std::size_t operator()(const ModuleCacheKey& request) const { return request.hash; } }; // Equality operator for ModuleCacheKey. bool operator==(const ModuleCacheKey& other) const { // Hash does not provide uniqueness guarantee, so ignore it. return specifier == other.specifier && import_attributes == other.import_attributes; } private: // Use public ModuleCacheKey::From to create instances. ModuleCacheKey(std::string specifier, ImportAttributeVector import_attributes, std::size_t hash) : specifier(specifier), import_attributes(import_attributes), hash(hash) {} }; class ModuleWrap : public BaseObject { public: enum InternalFields { kModuleSlot = BaseObject::kInternalFieldCount, kModuleSourceObjectSlot, kSyntheticEvaluationStepsSlot, kContextObjectSlot, // Object whose creation context is the target Context kLinkedRequestsSlot, // Array of linked requests, each is a ModuleWrap JS // wrapper object. kInternalFieldCount }; static void CreatePerIsolateProperties(IsolateData* isolate_data, v8::Local target); static void CreatePerContextProperties(v8::Local target, v8::Local unused, v8::Local context, void* priv); static void RegisterExternalReferences(ExternalReferenceRegistry* registry); static void HostInitializeImportMetaObjectCallback( v8::Local context, v8::Local module, v8::Local meta); v8::Local context() const; v8::Maybe CheckUnsettledTopLevelAwait(); bool HasAsyncGraph(); SET_MEMORY_INFO_NAME(ModuleWrap) SET_SELF_SIZE(ModuleWrap) SET_NO_MEMORY_INFO() bool IsNotIndicativeOfMemoryLeakAtExit() const override { // XXX: The garbage collection rules for ModuleWrap are *super* unclear. // Do these objects ever get GC'd? Are we just okay with leaking them? return true; } bool IsLinked() const { return linked_; } static v8::Local GetHostDefinedOptions( v8::Isolate* isolate, v8::Local symbol); // When user_cached_data is not std::nullopt, use the code cache if it's not // nullptr, otherwise don't use code cache. // TODO(joyeecheung): when it is std::nullopt, use on-disk cache // See: https://github.com/nodejs/node/issues/47472 static v8::MaybeLocal CompileSourceTextModule( Realm* realm, v8::Local source_text, v8::Local url, int line_offset, int column_offset, v8::Local host_defined_options, std::optional user_cached_data, bool* cache_rejected); static void CreateRequiredModuleFacade( const v8::FunctionCallbackInfo& args); private: ModuleWrap(Realm* realm, v8::Local object, v8::Local module, v8::Local url, v8::Local context_object, v8::Local synthetic_evaluation_step); ~ModuleWrap() override; static void New(const v8::FunctionCallbackInfo& args); static void GetModuleRequests( const v8::FunctionCallbackInfo& args); static void SetModuleSourceObject( const v8::FunctionCallbackInfo& args); static void GetModuleSourceObject( const v8::FunctionCallbackInfo& args); static void Link(const v8::FunctionCallbackInfo& args); static void Instantiate(const v8::FunctionCallbackInfo& args); static void Evaluate(const v8::FunctionCallbackInfo& args); static void EvaluateSync(const v8::FunctionCallbackInfo& args); static void GetNamespace(const v8::FunctionCallbackInfo& args); static void GetStatus(const v8::FunctionCallbackInfo& args); static void GetError(const v8::FunctionCallbackInfo& args); static void HasAsyncGraph(v8::Local property, const v8::PropertyCallbackInfo& args); static void SetImportModuleDynamicallyCallback( const v8::FunctionCallbackInfo& args); static void SetImportMetaResolveInitializer( const v8::FunctionCallbackInfo& args); static void SetInitializeImportMetaObjectCallback( const v8::FunctionCallbackInfo& args); static v8::MaybeLocal SyntheticModuleEvaluationStepsCallback( v8::Local context, v8::Local module); static void SetSyntheticExport( const v8::FunctionCallbackInfo& args); static void CreateCachedData(const v8::FunctionCallbackInfo& args); static v8::MaybeLocal ResolveModuleCallback( v8::Local context, size_t module_request_index, v8::Local referrer); static v8::MaybeLocal ResolveSourceCallback( v8::Local context, size_t module_request_index, v8::Local referrer); static ModuleWrap* GetFromModule(node::Environment*, v8::Local); // This method may throw a JavaScript exception, so the return type is // wrapped in a Maybe. static v8::Maybe ResolveModule(v8::Local context, size_t module_request_index, v8::Local referrer); std::string url_; v8::Global module_; contextify::ContextifyContext* contextify_context_ = nullptr; bool synthetic_ = false; bool linked_ = false; // This depends on the module to be instantiated so it begins with a // nullopt value. std::optional has_async_graph_ = std::nullopt; int module_hash_; // Corresponds to the ModuleWrap* of the wrappers in kLinkedRequestsSlot. // These are populated during Link(), and are only valid after that as // convenient shortcuts, but do not hold the ModuleWraps alive. The actual // strong references come from the array in kLinkedRequestsSlot. std::vector linked_module_wraps_; }; } // namespace loader } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #endif // SRC_MODULE_WRAP_H_