#pragma once #include "root.h" #include "JavaScriptCore/JSGlobalObject.h" #include "JavaScriptCore/JSString.h" #include "headers-handwritten.h" #include "wtf/NakedPtr.h" #include "BunClientData.h" namespace Zig { class GlobalObject; } namespace JSC { class SourceCode; class JSSourceCode; class ProgramExecutable; class AbstractModuleRecord; } namespace Bun { using namespace JSC; JSC_DECLARE_HOST_FUNCTION(jsFunctionCreateCommonJSModule); JSC_DECLARE_HOST_FUNCTION(jsFunctionEvaluateCommonJSModule); JSC_DECLARE_HOST_FUNCTION(functionJSCommonJSModule_compile); void populateESMExports( JSC::JSGlobalObject* globalObject, JSC::JSValue result, WTF::Vector& exportNames, JSC::MarkedArgumentBuffer& exportValues, bool ignoreESModuleAnnotation); class JSCommonJSModule final : public JSC::JSDestructibleObject { public: using Base = JSC::JSDestructibleObject; static constexpr unsigned StructureFlags = Base::StructureFlags; // `module.id` Initialized eagerly; can be overridden. mutable JSC::WriteBarrier m_id; // Initialized eagerly; can be overridden. mutable JSC::WriteBarrier m_filename; // Initialized eagerly; can be overridden. mutable JSC::WriteBarrier m_dirname; // Initialized lazily; can be overridden. mutable JSC::WriteBarrier m_paths; // Children must always be tracked in case the script decides to access // `module.children`. In that case, all children may also need their // children fields to exist, recursively. To avoid allocating a *JSArray for // each module, the children array is constructed internally as a // Vector of pointers. If accessed, deduplication happens and array is // moved into JavaScript. These two fields add 16 bytes to JSCommonJSModule. // `m_childrenValue` can be set to any value via the user-exposed setter, // but Bun does not test that behavior besides ensuring it does not crash. mutable JSC::WriteBarrier m_childrenValue; // This must be WriteBarrier to compile; always JSCommonJSModule WTF::Vector> m_children; // Visited by the GC. When the module is assigned a non-JSCommonJSModule // parent, it is assigned to this field. // // module.parent = parent; // mutable JSC::WriteBarrier m_overriddenParent; // Not visited by the GC. // When the module is assigned a JSCommonJSModule parent, it is assigned to this field. // This is the normal state. JSC::Weak m_parent {}; // If compile is overridden, it is assigned to this field. The default // compile function is not stored here, but in mutable JSC::WriteBarrier m_overriddenCompile; bool ignoreESModuleAnnotation { false }; JSC::SourceCode sourceCode = JSC::SourceCode(); static size_t estimatedSize(JSC::JSCell* cell, JSC::VM& vm); void setSourceCode(JSC::SourceCode&& sourceCode); static void destroy(JSC::JSCell*); ~JSCommonJSModule(); void clearSourceCode() { sourceCode = JSC::SourceCode(); } void finishCreation(JSC::VM& vm, JSC::JSString* id, JSValue filename, JSC::JSString* dirname, const JSC::SourceCode& sourceCode); static JSC::Structure* createStructure(JSC::JSGlobalObject* globalObject); void evaluate(Zig::GlobalObject* globalObject, const WTF::String& sourceURL, ResolvedSource& resolvedSource, bool isBuiltIn); void evaluateWithPotentiallyOverriddenCompile(Zig::GlobalObject* globalObject, const WTF::String& sourceURL, JSValue keyJSString, ResolvedSource& resolvedSource); inline void evaluate(Zig::GlobalObject* globalObject, const WTF::String& sourceURL, ResolvedSource& resolvedSource) { return evaluate(globalObject, sourceURL, resolvedSource, false); } static JSCommonJSModule* create(JSC::VM& vm, JSC::Structure* structure, JSC::JSString* id, JSValue filename, JSC::JSString* dirname, const JSC::SourceCode& sourceCode); static JSCommonJSModule* create( Zig::GlobalObject* globalObject, const WTF::String& key, JSValue exportsObject, bool hasEvaluated, JSValue parent); static JSCommonJSModule* create( Zig::GlobalObject* globalObject, JSC::JSString* key, JSValue exportsObject, bool hasEvaluated, JSValue parent); static JSCommonJSModule* create( Zig::GlobalObject* globalObject, const WTF::String& key, ResolvedSource resolvedSource); static JSObject* createBoundRequireFunction(VM& vm, JSGlobalObject* lexicalGlobalObject, const WTF::String& pathString); void toSyntheticSource(JSC::JSGlobalObject* globalObject, const JSC::Identifier& moduleKey, Vector& exportNames, JSC::MarkedArgumentBuffer& exportValues); JSValue exportsObject() { return this->get(globalObject(), JSC::PropertyName(WebCore::clientData(vm())->builtinNames().exportsPublicName())); } void setExportsObject(JSC::JSValue exportsObject); JSValue idOrDot() { return m_id.get(); } JSValue filename() { return m_filename.get(); } bool load(JSC::VM& vm, Zig::GlobalObject* globalObject); DECLARE_INFO; DECLARE_VISIT_CHILDREN; static void analyzeHeap(JSCell*, JSC::HeapAnalyzer&); template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { if constexpr (mode == JSC::SubspaceAccess::Concurrently) return nullptr; return WebCore::subspaceForImpl( vm, [](auto& spaces) { return spaces.m_clientSubspaceForJSCommonJSModule.get(); }, [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForJSCommonJSModule = std::forward(space); }, [](auto& spaces) { return spaces.m_subspaceForJSCommonJSModule.get(); }, [](auto& spaces, auto&& space) { spaces.m_subspaceForJSCommonJSModule = std::forward(space); }); } bool hasEvaluated = false; JSCommonJSModule(JSC::VM& vm, JSC::Structure* structure) : Base(vm, structure) { } }; JSC::Structure* createCommonJSModuleStructure( Zig::GlobalObject* globalObject); std::optional createCommonJSModule( Zig::GlobalObject* globalObject, JSC::JSString* specifierValue, ResolvedSource& source, bool isBuiltIn); inline std::optional createCommonJSModule( Zig::GlobalObject* globalObject, JSC::JSString* specifierValue, ResolvedSource& source) { return createCommonJSModule(globalObject, specifierValue, source, false); } class RequireResolveFunctionPrototype final : public JSC::JSNonFinalObject { public: using Base = JSC::JSNonFinalObject; static RequireResolveFunctionPrototype* create(JSC::JSGlobalObject* globalObject); static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject); DECLARE_INFO; RequireResolveFunctionPrototype( JSC::VM& vm, JSC::Structure* structure) : Base(vm, structure) { } template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(RequireResolveFunctionPrototype, Base); return &vm.plainObjectSpace(); } void finishCreation(JSC::VM& vm); }; class RequireFunctionPrototype final : public JSC::JSNonFinalObject { public: using Base = JSC::JSNonFinalObject; static RequireFunctionPrototype* create(JSC::JSGlobalObject* globalObject); static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject); DECLARE_INFO; RequireFunctionPrototype( JSC::VM& vm, JSC::Structure* structure) : Base(vm, structure) { } template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) { STATIC_ASSERT_ISO_SUBSPACE_SHARABLE(RequireFunctionPrototype, Base); return &vm.plainObjectSpace(); } void finishCreation(JSC::VM&); }; } // namespace Bun