blob: 4c18eef502b07049e8c2c8d0316cae1ff72d32d9 [file] [log] [blame] [edit]
#ifndef SRC_MODULE_WRAP_H_
#define SRC_MODULE_WRAP_H_
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#include <optional>
#include <string>
#include <unordered_map>
#include <vector>
#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::pair<std::string, std::string>>;
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 <int elements_per_attribute = 3>
static ModuleCacheKey From(v8::Local<v8::Context> context,
v8::Local<v8::String> specifier,
v8::Local<v8::FixedArray> import_attributes);
static ModuleCacheKey From(v8::Local<v8::Context> context,
v8::Local<v8::ModuleRequest> 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<v8::ObjectTemplate> target);
static void CreatePerContextProperties(v8::Local<v8::Object> target,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
void* priv);
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
static void HostInitializeImportMetaObjectCallback(
v8::Local<v8::Context> context,
v8::Local<v8::Module> module,
v8::Local<v8::Object> meta);
v8::Local<v8::Context> context() const;
v8::Maybe<bool> 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<v8::PrimitiveArray> GetHostDefinedOptions(
v8::Isolate* isolate, v8::Local<v8::Symbol> 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<v8::Module> CompileSourceTextModule(
Realm* realm,
v8::Local<v8::String> source_text,
v8::Local<v8::String> url,
int line_offset,
int column_offset,
v8::Local<v8::PrimitiveArray> host_defined_options,
std::optional<v8::ScriptCompiler::CachedData*> user_cached_data,
bool* cache_rejected);
static void CreateRequiredModuleFacade(
const v8::FunctionCallbackInfo<v8::Value>& args);
private:
ModuleWrap(Realm* realm,
v8::Local<v8::Object> object,
v8::Local<v8::Module> module,
v8::Local<v8::String> url,
v8::Local<v8::Object> context_object,
v8::Local<v8::Value> synthetic_evaluation_step);
~ModuleWrap() override;
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetModuleRequests(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetModuleSourceObject(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetModuleSourceObject(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void Link(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Instantiate(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Evaluate(const v8::FunctionCallbackInfo<v8::Value>& args);
static void EvaluateSync(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetNamespace(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetStatus(const v8::FunctionCallbackInfo<v8::Value>& args);
static void GetError(const v8::FunctionCallbackInfo<v8::Value>& args);
static void HasAsyncGraph(v8::Local<v8::Name> property,
const v8::PropertyCallbackInfo<v8::Value>& args);
static void SetImportModuleDynamicallyCallback(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetImportMetaResolveInitializer(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void SetInitializeImportMetaObjectCallback(
const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::MaybeLocal<v8::Value> SyntheticModuleEvaluationStepsCallback(
v8::Local<v8::Context> context, v8::Local<v8::Module> module);
static void SetSyntheticExport(
const v8::FunctionCallbackInfo<v8::Value>& args);
static void CreateCachedData(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::MaybeLocal<v8::Module> ResolveModuleCallback(
v8::Local<v8::Context> context,
size_t module_request_index,
v8::Local<v8::Module> referrer);
static v8::MaybeLocal<v8::Object> ResolveSourceCallback(
v8::Local<v8::Context> context,
size_t module_request_index,
v8::Local<v8::Module> referrer);
static ModuleWrap* GetFromModule(node::Environment*, v8::Local<v8::Module>);
// This method may throw a JavaScript exception, so the return type is
// wrapped in a Maybe.
static v8::Maybe<ModuleWrap*> ResolveModule(v8::Local<v8::Context> context,
size_t module_request_index,
v8::Local<v8::Module> referrer);
std::string url_;
v8::Global<v8::Module> 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<bool> 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<ModuleWrap*> linked_module_wraps_;
};
} // namespace loader
} // namespace node
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#endif // SRC_MODULE_WRAP_H_