From 6aaef99f88b3bad8d5a04c4caeb189f4dbaeaecf Mon Sep 17 00:00:00 2001 From: 190n Date: Wed, 23 Apr 2025 12:03:04 -0700 Subject: [PATCH] Use macro to declare and visit garbage-collected GlobalObject members (#18835) --- src/bun.js/bindings/BunProcess.cpp | 11 +- src/bun.js/bindings/JSMockFunction.cpp | 11 + src/bun.js/bindings/JSMockFunction.h | 27 +- src/bun.js/bindings/ZigGlobalObject.cpp | 170 ++------ src/bun.js/bindings/ZigGlobalObject.h | 390 +++++++++--------- src/bun.js/bindings/webcore/DOMConstructors.h | 5 + 6 files changed, 274 insertions(+), 340 deletions(-) diff --git a/src/bun.js/bindings/BunProcess.cpp b/src/bun.js/bindings/BunProcess.cpp index 840ea09dcd..6d53f32f07 100644 --- a/src/bun.js/bindings/BunProcess.cpp +++ b/src/bun.js/bindings/BunProcess.cpp @@ -639,8 +639,8 @@ extern "C" void Process__dispatchOnBeforeExit(Zig::GlobalObject* globalObject, u auto fired = process->wrapped().emit(Identifier::fromString(vm, "beforeExit"_s), arguments); if (fired) { if (globalObject->m_nextTickQueue) { - auto nextTickQueue = jsDynamicCast(globalObject->m_nextTickQueue.get()); - if (nextTickQueue) nextTickQueue->drain(vm, globalObject); + auto nextTickQueue = globalObject->m_nextTickQueue.get(); + nextTickQueue->drain(vm, globalObject); } } } @@ -3183,13 +3183,12 @@ extern "C" void Bun__Process__queueNextTick2(GlobalObject* globalObject, Encoded JSValue Process::constructNextTickFn(JSC::VM& vm, Zig::GlobalObject* globalObject) { - JSValue nextTickQueueObject; + JSNextTickQueue* nextTickQueueObject; if (!globalObject->m_nextTickQueue) { - auto nextTickQueue = Bun::JSNextTickQueue::create(globalObject); - nextTickQueueObject = nextTickQueue; + nextTickQueueObject = JSNextTickQueue::create(globalObject); globalObject->m_nextTickQueue.set(vm, globalObject, nextTickQueueObject); } else { - nextTickQueueObject = jsCast(globalObject->m_nextTickQueue.get()); + nextTickQueueObject = globalObject->m_nextTickQueue.get(); } JSC::JSFunction* initializer = JSC::JSFunction::create(vm, globalObject, processObjectInternalsInitializeNextTickQueueCodeGenerator(vm), globalObject); diff --git a/src/bun.js/bindings/JSMockFunction.cpp b/src/bun.js/bindings/JSMockFunction.cpp index 4940a0f786..39faa9857d 100644 --- a/src/bun.js/bindings/JSMockFunction.cpp +++ b/src/bun.js/bindings/JSMockFunction.cpp @@ -762,6 +762,17 @@ JSMockModule JSMockModule::create(JSC::JSGlobalObject* globalObject) return mock; } +template void JSMockModule::visit(Visitor& visitor) +{ +#define VISIT_JSMOCKMODULE_GC_MEMBER(T, name) \ + name.visit(visitor); + FOR_EACH_JSMOCKMODULE_GC_MEMBER(VISIT_JSMOCKMODULE_GC_MEMBER) +#undef VISIT_JSMOCKMODULE_GC_MEMBER +} + +template void JSMockModule::visit(JSC::AbstractSlotVisitor&); +template void JSMockModule::visit(JSC::SlotVisitor&); + extern Structure* createMockResultStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject) { JSC::Structure* structure = globalObject->structureCache().emptyObjectStructureForPrototype( diff --git a/src/bun.js/bindings/JSMockFunction.h b/src/bun.js/bindings/JSMockFunction.h index a50928014e..2cfc44c89f 100644 --- a/src/bun.js/bindings/JSMockFunction.h +++ b/src/bun.js/bindings/JSMockFunction.h @@ -14,19 +14,26 @@ using namespace WebCore; class JSMockFunction; +// Wrapper to scope a bunch of GlobalObject properties related to mocks class JSMockModule final { public: static uint64_t s_nextInvocationId; static uint64_t nextInvocationId() { return ++s_nextInvocationId; } - LazyProperty mockFunctionStructure; - LazyProperty mockResultStructure; - LazyProperty mockImplementationStructure; - LazyProperty mockObjectStructure; - LazyProperty mockModuleStructure; - LazyProperty activeSpySetStructure; - LazyProperty withImplementationCleanupFunction; - LazyProperty mockWithImplementationCleanupDataStructure; +#define FOR_EACH_JSMOCKMODULE_GC_MEMBER(V) \ + V(Structure, mockFunctionStructure) \ + V(Structure, mockResultStructure) \ + V(Structure, mockImplementationStructure) \ + V(Structure, mockObjectStructure) \ + V(Structure, mockModuleStructure) \ + V(Structure, activeSpySetStructure) \ + V(JSFunction, withImplementationCleanupFunction) \ + V(JSC::Structure, mockWithImplementationCleanupDataStructure) + +#define DECLARE_JSMOCKMODULE_GC_MEMBER(T, name) \ + LazyProperty name; + FOR_EACH_JSMOCKMODULE_GC_MEMBER(DECLARE_JSMOCKMODULE_GC_MEMBER) +#undef DECLARE_JSMOCKMODULE_GC_MEMBER static JSMockModule create(JSC::JSGlobalObject*); @@ -38,6 +45,10 @@ public: // This is useful for iterating through every non-GC'd mock function // This list includes activeSpies JSC::Strong activeMocks; + + // Called by Zig::GlobalObject::visitChildren + template + void visit(Visitor& visitor); }; class MockWithImplementationCleanupData : public JSC::JSInternalFieldObjectImpl<4> { diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 0a69256ca2..d508f592de 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -66,6 +66,7 @@ #include "CallSite.h" #include "CallSitePrototype.h" #include "JSCommonJSModule.h" +#include "JSCommonJSExtensions.h" #include "ConsoleObject.h" #include "DOMWrapperWorld-class.h" #include "ErrorStackTrace.h" @@ -820,8 +821,7 @@ static JSValue computeErrorInfoWrapperToJSValue(JSC::VM& vm, Vector& static void checkIfNextTickWasCalledDuringMicrotask(JSC::VM& vm) { auto* globalObject = defaultGlobalObject(); - if (auto nextTickQueueValue = globalObject->m_nextTickQueue.get()) { - auto* queue = jsCast(nextTickQueueValue); + if (auto queue = globalObject->m_nextTickQueue.get()) { globalObject->resetOnEachMicrotaskTick(); queue->drain(vm, globalObject); } @@ -977,9 +977,8 @@ extern "C" JSC__JSGlobalObject* Zig__GlobalObject__create(void* console_client, vm.setOnComputeErrorInfoJSValue(computeErrorInfoWrapperToJSValue); vm.setOnEachMicrotaskTick([](JSC::VM& vm) -> void { auto* globalObject = defaultGlobalObject(); - if (auto nextTickQueue = globalObject->m_nextTickQueue.get()) { + if (auto queue = globalObject->m_nextTickQueue.get()) { globalObject->resetOnEachMicrotaskTick(); - Bun::JSNextTickQueue* queue = jsCast(nextTickQueue); queue->drain(vm, globalObject); return; } @@ -2863,7 +2862,7 @@ void GlobalObject::finishCreation(VM& vm) ASSERT(inherits(info())); m_commonStrings.initialize(); - m_http2_commongStrings.initialize(); + m_http2CommonStrings.initialize(); Bun::addNodeModuleConstructorProperties(vm, this); m_JSNodeHTTPServerSocketStructure.initLater( @@ -3968,6 +3967,26 @@ extern "C" EncodedJSValue JSC__JSGlobalObject__getHTTP2CommonString(Zig::GlobalO return JSValue::encode(JSValue::JSUndefined); } +template static void visitGlobalObjectMember(Visitor& visitor, T& anything) +{ + anything.visit(visitor); +} + +template static void visitGlobalObjectMember(Visitor& visitor, WriteBarrier& barrier) +{ + visitor.append(barrier); +} + +template static void visitGlobalObjectMember(Visitor& visitor, std::unique_ptr& ptr) +{ + ptr->visit(visitor); +} + +template static void visitGlobalObjectMember(Visitor& visitor, std::array, n>& barriers) +{ + visitor.append(barriers.begin(), barriers.end()); +} + template void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) { @@ -3986,145 +4005,12 @@ void GlobalObject::visitChildrenImpl(JSCell* cell, Visitor& visitor) guarded->visitAggregate(visitor); } - for (auto& constructor : thisObject->constructors().array()) - visitor.append(constructor); +#define VISIT_GLOBALOBJECT_GC_MEMBER(visibility, T, name) \ + visitGlobalObjectMember(visitor, thisObject->name); + FOR_EACH_GLOBALOBJECT_GC_MEMBER(VISIT_GLOBALOBJECT_GC_MEMBER) +#undef VISIT_GLOBALOBJECT_GC_MEMBER - thisObject->m_builtinInternalFunctions.visit(visitor); - thisObject->m_commonStrings.visit(visitor); WebCore::clientData(thisObject->vm())->httpHeaderIdentifiers().visit(visitor); - thisObject->m_http2_commongStrings.visit(visitor); - visitor.append(thisObject->m_assignToStream); - visitor.append(thisObject->m_readableStreamToArrayBuffer); - visitor.append(thisObject->m_readableStreamToArrayBufferResolve); - visitor.append(thisObject->m_readableStreamToBytes); - visitor.append(thisObject->m_readableStreamToBlob); - visitor.append(thisObject->m_readableStreamToJSON); - visitor.append(thisObject->m_readableStreamToText); - visitor.append(thisObject->m_readableStreamToFormData); - - visitor.append(thisObject->m_nextTickQueue); - visitor.append(thisObject->m_errorConstructorPrepareStackTraceValue); - - visitor.append(thisObject->m_pendingNapiModuleAndExports[0]); - visitor.append(thisObject->m_pendingNapiModuleAndExports[1]); - - visitor.append(thisObject->m_currentNapiHandleScopeImpl); - - thisObject->m_moduleResolveFilenameFunction.visit(visitor); - thisObject->m_modulePrototypeUnderscoreCompileFunction.visit(visitor); - thisObject->m_commonJSRequireESMFromHijackedExtensionFunction.visit(visitor); - thisObject->m_moduleRunMainFunction.visit(visitor); - thisObject->m_nodeModuleConstructor.visit(visitor); - thisObject->m_asyncBoundFunctionStructure.visit(visitor); - thisObject->m_bunObject.visit(visitor); - thisObject->m_cachedNodeVMGlobalObjectStructure.visit(visitor); - thisObject->m_cachedGlobalProxyStructure.visit(visitor); - thisObject->m_callSiteStructure.visit(visitor); - thisObject->m_commonJSModuleObjectStructure.visit(visitor); - thisObject->m_JSSocketAddressDTOStructure.visit(visitor); - thisObject->m_cryptoObject.visit(visitor); - thisObject->m_errorConstructorPrepareStackTraceInternalValue.visit(visitor); - thisObject->m_esmRegistryMap.visit(visitor); - thisObject->m_importMetaObjectStructure.visit(visitor); - thisObject->m_internalModuleRegistry.visit(visitor); - thisObject->m_processBindingBuffer.visit(visitor); - thisObject->m_processBindingConstants.visit(visitor); - thisObject->m_processBindingFs.visit(visitor); - thisObject->m_JSArrayBufferControllerPrototype.visit(visitor); - thisObject->m_JSArrayBufferSinkClassStructure.visit(visitor); - thisObject->m_JSBufferClassStructure.visit(visitor); - thisObject->m_JSBufferListClassStructure.visit(visitor); - thisObject->m_JSBufferSubclassStructure.visit(visitor); - thisObject->m_JSNodeHTTPServerSocketStructure.visit(visitor); - thisObject->m_JSResizableOrGrowableSharedBufferSubclassStructure.visit(visitor); - thisObject->m_JSCryptoKey.visit(visitor); - thisObject->m_lazyStackCustomGetterSetter.visit(visitor); - thisObject->m_JSDOMFileConstructor.visit(visitor); - thisObject->m_JSS3FileStructure.visit(visitor); - thisObject->m_S3ErrorStructure.visit(visitor); - thisObject->m_JSFFIFunctionStructure.visit(visitor); - thisObject->m_JSFileSinkClassStructure.visit(visitor); - thisObject->m_JSFileSinkControllerPrototype.visit(visitor); - thisObject->m_JSHTTPResponseController.visit(visitor); - thisObject->m_JSHTTPResponseSinkClassStructure.visit(visitor); - thisObject->m_JSHTTPSResponseControllerPrototype.visit(visitor); - thisObject->m_JSHTTPSResponseSinkClassStructure.visit(visitor); - thisObject->m_JSNetworkSinkClassStructure.visit(visitor); - thisObject->m_JSFetchTaskletChunkedRequestControllerPrototype.visit(visitor); - thisObject->m_JSSQLStatementStructure.visit(visitor); - thisObject->m_V8GlobalInternals.visit(visitor); - thisObject->m_JSStringDecoderClassStructure.visit(visitor); - thisObject->m_lazyPreloadTestModuleObject.visit(visitor); - thisObject->m_lazyReadableStreamPrototypeMap.visit(visitor); - thisObject->m_lazyRequireCacheObject.visit(visitor); - thisObject->m_lazyRequireExtensionsObject.visit(visitor); - thisObject->m_lazyTestModuleObject.visit(visitor); - thisObject->m_memoryFootprintStructure.visit(visitor); - thisObject->m_JSStatsClassStructure.visit(visitor); - thisObject->m_JSStatsBigIntClassStructure.visit(visitor); - thisObject->m_JSStatFSClassStructure.visit(visitor); - thisObject->m_JSStatFSBigIntClassStructure.visit(visitor); - thisObject->m_JSDirentClassStructure.visit(visitor); - thisObject->m_NapiClassStructure.visit(visitor); - thisObject->m_NapiExternalStructure.visit(visitor); - thisObject->m_NapiPrototypeStructure.visit(visitor); - thisObject->m_NapiHandleScopeImplStructure.visit(visitor); - thisObject->m_NapiTypeTagStructure.visit(visitor); - thisObject->m_napiTypeTags.visit(visitor); - thisObject->m_nativeMicrotaskTrampoline.visit(visitor); - thisObject->m_navigatorObject.visit(visitor); - thisObject->m_NodeVMScriptClassStructure.visit(visitor); - thisObject->m_pendingVirtualModuleResultStructure.visit(visitor); - thisObject->m_performanceObject.visit(visitor); - thisObject->m_performMicrotaskFunction.visit(visitor); - thisObject->m_performMicrotaskVariadicFunction.visit(visitor); - thisObject->m_processEnvObject.visit(visitor); - thisObject->m_processObject.visit(visitor); - thisObject->m_requireFunctionUnbound.visit(visitor); - thisObject->m_requireMap.visit(visitor); - thisObject->m_requireResolveFunctionUnbound.visit(visitor); - thisObject->m_subtleCryptoObject.visit(visitor); - thisObject->m_testMatcherUtilsObject.visit(visitor); - thisObject->m_utilInspectFunction.visit(visitor); - thisObject->m_utilInspectOptionsStructure.visit(visitor); - thisObject->m_utilInspectStylizeColorFunction.visit(visitor); - thisObject->m_utilInspectStylizeNoColorFunction.visit(visitor); - thisObject->m_vmModuleContextMap.visit(visitor); - thisObject->m_napiTypeTags.visit(visitor); - thisObject->mockModule.activeSpySetStructure.visit(visitor); - thisObject->mockModule.mockFunctionStructure.visit(visitor); - thisObject->mockModule.mockImplementationStructure.visit(visitor); - thisObject->mockModule.mockModuleStructure.visit(visitor); - thisObject->mockModule.mockObjectStructure.visit(visitor); - thisObject->mockModule.mockResultStructure.visit(visitor); - thisObject->mockModule.mockWithImplementationCleanupDataStructure.visit(visitor); - thisObject->mockModule.withImplementationCleanupFunction.visit(visitor); - thisObject->m_ServerRouteListStructure.visit(visitor); - thisObject->m_JSBunRequestStructure.visit(visitor); - thisObject->m_JSBunRequestParamsPrototype.visit(visitor); - thisObject->m_JSX509CertificateClassStructure.visit(visitor); - thisObject->m_JSSignClassStructure.visit(visitor); - thisObject->m_JSVerifyClassStructure.visit(visitor); - thisObject->m_JSDiffieHellmanClassStructure.visit(visitor); - thisObject->m_JSDiffieHellmanGroupClassStructure.visit(visitor); - thisObject->m_JSECDHClassStructure.visit(visitor); - thisObject->m_JSHmacClassStructure.visit(visitor); - thisObject->m_JSHashClassStructure.visit(visitor); - thisObject->m_JSCipherClassStructure.visit(visitor); - thisObject->m_JSKeyObjectClassStructure.visit(visitor); - thisObject->m_JSSecretKeyObjectClassStructure.visit(visitor); - thisObject->m_JSPublicKeyObjectClassStructure.visit(visitor); - thisObject->m_JSPrivateKeyObjectClassStructure.visit(visitor); - thisObject->m_statValues.visit(visitor); - thisObject->m_bigintStatValues.visit(visitor); - thisObject->m_statFsValues.visit(visitor); - thisObject->m_bigintStatFsValues.visit(visitor); - - thisObject->m_nodeErrorCache.visit(visitor); - - for (auto& barrier : thisObject->m_thenables) { - visitor.append(barrier); - } thisObject->visitGeneratedLazyClasses(thisObject, visitor); thisObject->visitAdditionalChildren(visitor); diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index 9e4c533816..11ee147f8f 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -30,6 +30,7 @@ class Performance; namespace Bun { class InternalModuleRegistry; class NapiHandleScopeImpl; +class JSNextTickQueue; } // namespace Bun namespace v8 { @@ -391,64 +392,220 @@ public: double INSPECT_MAX_BYTES = 50; bool isInsideErrorPrepareStackTraceCallback = false; - /** - * WARNING: You must update visitChildrenImpl() if you add a new field. - * - * That informs the garbage collector that these fields exist. If you don't - * do that, the garbage collector will not know about these fields and will - * not trace them. This will lead to crashes and very strange behavior at runtime. - * - * For example, if you don't add the queueMicrotask functions to visitChildrenImpl(), - * those callbacks will eventually never be called anymore. But it'll work the first time! - */ - // TODO: these should use LazyProperty - mutable WriteBarrier m_assignToStream; - mutable WriteBarrier m_readableStreamToArrayBuffer; - mutable WriteBarrier m_readableStreamToArrayBufferResolve; - mutable WriteBarrier m_readableStreamToBytes; - mutable WriteBarrier m_readableStreamToBlob; - mutable WriteBarrier m_readableStreamToJSON; - mutable WriteBarrier m_readableStreamToText; - mutable WriteBarrier m_readableStreamToFormData; + template + using LazyPropertyOfGlobalObject = LazyProperty; - LazyProperty m_moduleResolveFilenameFunction; - LazyProperty m_moduleRunMainFunction; - LazyProperty m_modulePrototypeUnderscoreCompileFunction; - LazyProperty m_commonJSRequireESMFromHijackedExtensionFunction; - LazyProperty m_nodeModuleConstructor; + using ThenablesArray = std::array, promiseFunctionsSize + 1>; + using NapiModuleAndExports = std::array, 2>; - mutable WriteBarrier m_nextTickQueue; + // Macro for doing something with each member of GlobalObject that has to be visited by the + // garbage collector. To use, define a macro taking three arguments (visibility, type, and + // name), pass it to FOR_EACH_GLOBALOBJECT_GC_MEMBER, and then undefine your macro: + // + // #define DO_SOMETHING_WITH_EACH_MEMBER(visibility, T, name) ... + // FOR_EACH_GLOBALOBJECT_GC_MEMBER(DO_SOMETHING_WITH_EACH_MEMBER) + // #undef DO_SOMETHING_WITH_EACH_MEMBER + // + // To add a new member, write e.g. + // + // /* comment */ \ + // V(private, WriteBarrier, m_thing) \ + // + // If you're adding a member in the middle of existing ones, make sure to put a backslash at the + // end of every line you add (even empty lines). This escapes the newline character, allowing + // the macro to span multiple lines. For comments you will need to use /* */ instead of //; + // otherwise, the backslash will be commented out. clang-format will automatically insert spaces + // so that all the backslashes are vertically aligned. + // + // The most common types for these properties are `LazyPropertyOfGlobalObject`, + // `WriteBarrier`, and `LazyClassStructure`. To use a new type, you'll need to: + // + // - Make sure the type can be written with no commas in its name. This is because a type with + // commas will count as two macro parameters instead of one. You can add a `using` declaration + // like above to create an alias for a complex template type without a comma. + // - Make sure `visitGlobalObjectMember` in `ZigGlobalObject.cpp` can handle your type. + // Currently it has overloads to handle: + // + // - any class with a `visit` method (this covers LazyProperty and LazyClassStructure) + // - `WriteBarrier` of any type + // - `std::unique_ptr` to any class with a `visit` method + // - `std::array` of any number of `WriteBarrier`s of any type + // + // Most members should be WriteBarriers. If your class is a container of GC-owned objects but + // is not itself GC-owned, you can typically just add a `visit` method. This is what's done by + // JSMockModule, for instance. But if you've done something very exotic you might need to add + // a new overload of `visitGlobalObjectMember` so it understands your type. + +#define FOR_EACH_GLOBALOBJECT_GC_MEMBER(V) \ + /* TODO: these should use LazyProperty */ \ + V(private, WriteBarrier, m_assignToStream) \ + V(public, WriteBarrier, m_readableStreamToArrayBuffer) \ + V(public, WriteBarrier, m_readableStreamToBytes) \ + V(public, WriteBarrier, m_readableStreamToBlob) \ + V(public, WriteBarrier, m_readableStreamToJSON) \ + V(public, WriteBarrier, m_readableStreamToText) \ + V(public, WriteBarrier, m_readableStreamToFormData) \ + \ + V(public, LazyPropertyOfGlobalObject, m_moduleResolveFilenameFunction) \ + V(public, LazyPropertyOfGlobalObject, m_moduleRunMainFunction) \ + V(public, LazyPropertyOfGlobalObject, m_modulePrototypeUnderscoreCompileFunction) \ + V(public, LazyPropertyOfGlobalObject, m_commonJSRequireESMFromHijackedExtensionFunction) \ + V(public, LazyPropertyOfGlobalObject, m_nodeModuleConstructor) \ + \ + V(public, WriteBarrier, m_nextTickQueue) \ + \ + /* WriteBarrier m_JSBunDebuggerValue; */ \ + V(private, ThenablesArray, m_thenables) \ + \ + /* Error.prepareStackTrace */ \ + V(public, WriteBarrier, m_errorConstructorPrepareStackTraceValue) \ + \ + /* When a napi module initializes on dlopen, we need to know what the value is */ \ + V(public, NapiModuleAndExports, m_pendingNapiModuleAndExports) \ + \ + /* The handle scope where all new NAPI values will be created. You must not pass any napi_values */ \ + /* back to a NAPI function without putting them in the handle scope, as the NAPI function may */ \ + /* move them off the stack which will cause them to get collected if not in the handle scope. */ \ + V(public, JSC::WriteBarrier, m_currentNapiHandleScopeImpl) \ + \ + /* The original, unmodified Error.prepareStackTrace. */ \ + /* */ \ + /* We set a default value for this to mimic Node.js behavior It is a */ \ + /* separate from the user-facing value so that we can tell if the user */ \ + /* really set it or if it's just the default value. */ \ + V(public, LazyPropertyOfGlobalObject, m_errorConstructorPrepareStackTraceInternalValue) \ + \ + V(private, LazyPropertyOfGlobalObject, m_nodeErrorCache) \ + \ + /* Used by napi_type_tag_object to associate a 128-bit type ID with JS objects. */ \ + /* Should only use JSCell* keys and NapiTypeTag values. */ \ + V(private, LazyPropertyOfGlobalObject, m_napiTypeTags) \ + \ + V(public, Bun::JSMockModule, mockModule) \ + \ + V(public, LazyPropertyOfGlobalObject, m_processEnvObject) \ + \ + V(public, LazyPropertyOfGlobalObject, m_JSS3FileStructure) \ + V(public, LazyPropertyOfGlobalObject, m_S3ErrorStructure) \ + \ + V(public, JSC::LazyClassStructure, m_JSStatsClassStructure) \ + V(public, JSC::LazyClassStructure, m_JSStatsBigIntClassStructure) \ + V(public, JSC::LazyClassStructure, m_JSStatFSClassStructure) \ + V(public, JSC::LazyClassStructure, m_JSStatFSBigIntClassStructure) \ + V(public, JSC::LazyClassStructure, m_JSDirentClassStructure) \ + \ + V(private, WebCore::JSBuiltinInternalFunctions, m_builtinInternalFunctions) \ + V(private, std::unique_ptr, m_constructors) \ + V(private, Bun::CommonStrings, m_commonStrings) \ + V(private, Bun::Http2CommonStrings, m_http2CommonStrings) \ + \ + /* JSC's hashtable code-generator tries to access these properties, so we make them public. */ \ + /* However, we'd like it better if they could be protected. */ \ + V(private, LazyClassStructure, m_JSArrayBufferSinkClassStructure) \ + V(private, LazyClassStructure, m_JSBufferListClassStructure) \ + V(private, LazyClassStructure, m_JSFFIFunctionStructure) \ + V(private, LazyClassStructure, m_JSFileSinkClassStructure) \ + V(private, LazyClassStructure, m_JSHTTPResponseSinkClassStructure) \ + V(private, LazyClassStructure, m_JSHTTPSResponseSinkClassStructure) \ + V(private, LazyClassStructure, m_JSNetworkSinkClassStructure) \ + \ + V(private, LazyClassStructure, m_JSStringDecoderClassStructure) \ + V(private, LazyClassStructure, m_NapiClassStructure) \ + V(private, LazyClassStructure, m_callSiteStructure) \ + V(public, LazyClassStructure, m_JSBufferClassStructure) \ + V(public, LazyClassStructure, m_NodeVMScriptClassStructure) \ + V(public, LazyClassStructure, m_JSX509CertificateClassStructure) \ + V(public, LazyClassStructure, m_JSSignClassStructure) \ + V(public, LazyClassStructure, m_JSVerifyClassStructure) \ + V(public, LazyClassStructure, m_JSDiffieHellmanClassStructure) \ + V(public, LazyClassStructure, m_JSDiffieHellmanGroupClassStructure) \ + V(public, LazyClassStructure, m_JSHmacClassStructure) \ + V(public, LazyClassStructure, m_JSHashClassStructure) \ + V(public, LazyClassStructure, m_JSECDHClassStructure) \ + V(public, LazyClassStructure, m_JSCipherClassStructure) \ + V(public, LazyClassStructure, m_JSKeyObjectClassStructure) \ + V(public, LazyClassStructure, m_JSSecretKeyObjectClassStructure) \ + V(public, LazyClassStructure, m_JSPublicKeyObjectClassStructure) \ + V(public, LazyClassStructure, m_JSPrivateKeyObjectClassStructure) \ + \ + V(private, LazyPropertyOfGlobalObject, m_pendingVirtualModuleResultStructure) \ + V(private, LazyPropertyOfGlobalObject, m_performMicrotaskFunction) \ + V(private, LazyPropertyOfGlobalObject, m_nativeMicrotaskTrampoline) \ + V(private, LazyPropertyOfGlobalObject, m_performMicrotaskVariadicFunction) \ + V(private, LazyPropertyOfGlobalObject, m_utilInspectFunction) \ + V(private, LazyPropertyOfGlobalObject, m_utilInspectOptionsStructure) \ + V(private, LazyPropertyOfGlobalObject, m_utilInspectStylizeColorFunction) \ + V(private, LazyPropertyOfGlobalObject, m_utilInspectStylizeNoColorFunction) \ + V(private, LazyPropertyOfGlobalObject, m_lazyReadableStreamPrototypeMap) \ + V(private, LazyPropertyOfGlobalObject, m_requireMap) \ + V(private, LazyPropertyOfGlobalObject, m_esmRegistryMap) \ + V(private, LazyPropertyOfGlobalObject, m_JSArrayBufferControllerPrototype) \ + V(private, LazyPropertyOfGlobalObject, m_JSHTTPSResponseControllerPrototype) \ + V(private, LazyPropertyOfGlobalObject, m_JSFetchTaskletChunkedRequestControllerPrototype) \ + V(private, LazyPropertyOfGlobalObject, m_JSFileSinkControllerPrototype) \ + V(private, LazyPropertyOfGlobalObject, m_subtleCryptoObject) \ + V(private, LazyPropertyOfGlobalObject, m_JSHTTPResponseController) \ + V(private, LazyPropertyOfGlobalObject, m_JSBufferSubclassStructure) \ + V(private, LazyPropertyOfGlobalObject, m_JSResizableOrGrowableSharedBufferSubclassStructure) \ + V(private, LazyPropertyOfGlobalObject, m_vmModuleContextMap) \ + V(public, LazyPropertyOfGlobalObject, m_lazyRequireCacheObject) \ + V(public, LazyPropertyOfGlobalObject, m_lazyRequireExtensionsObject) \ + V(private, LazyPropertyOfGlobalObject, m_lazyTestModuleObject) \ + V(private, LazyPropertyOfGlobalObject, m_lazyPreloadTestModuleObject) \ + V(public, LazyPropertyOfGlobalObject, m_testMatcherUtilsObject) \ + V(public, LazyPropertyOfGlobalObject, m_cachedNodeVMGlobalObjectStructure) \ + V(private, LazyPropertyOfGlobalObject, m_cachedGlobalProxyStructure) \ + V(private, LazyPropertyOfGlobalObject, m_commonJSModuleObjectStructure) \ + V(private, LazyPropertyOfGlobalObject, m_JSSocketAddressDTOStructure) \ + V(private, LazyPropertyOfGlobalObject, m_memoryFootprintStructure) \ + V(private, LazyPropertyOfGlobalObject, m_requireFunctionUnbound) \ + V(private, LazyPropertyOfGlobalObject, m_requireResolveFunctionUnbound) \ + V(private, LazyPropertyOfGlobalObject, m_internalModuleRegistry) \ + V(private, LazyPropertyOfGlobalObject, m_processBindingBuffer) \ + V(private, LazyPropertyOfGlobalObject, m_processBindingConstants) \ + V(private, LazyPropertyOfGlobalObject, m_processBindingFs) \ + V(private, LazyPropertyOfGlobalObject, m_importMetaObjectStructure) \ + V(private, LazyPropertyOfGlobalObject, m_asyncBoundFunctionStructure) \ + V(public, LazyPropertyOfGlobalObject, m_JSDOMFileConstructor) \ + \ + V(private, LazyPropertyOfGlobalObject, m_JSCryptoKey) \ + V(private, LazyPropertyOfGlobalObject, m_NapiExternalStructure) \ + V(private, LazyPropertyOfGlobalObject, m_NapiPrototypeStructure) \ + V(private, LazyPropertyOfGlobalObject, m_NapiHandleScopeImplStructure) \ + V(private, LazyPropertyOfGlobalObject, m_NapiTypeTagStructure) \ + \ + V(private, LazyPropertyOfGlobalObject, m_JSSQLStatementStructure) \ + V(private, LazyPropertyOfGlobalObject, m_V8GlobalInternals) \ + \ + V(public, LazyPropertyOfGlobalObject, m_bunObject) \ + V(public, LazyPropertyOfGlobalObject, m_cryptoObject) \ + V(public, LazyPropertyOfGlobalObject, m_navigatorObject) \ + V(public, LazyPropertyOfGlobalObject, m_performanceObject) \ + V(public, LazyPropertyOfGlobalObject, m_processObject) \ + V(public, LazyPropertyOfGlobalObject, m_lazyStackCustomGetterSetter) \ + V(public, LazyPropertyOfGlobalObject, m_ServerRouteListStructure) \ + V(public, LazyPropertyOfGlobalObject, m_JSBunRequestStructure) \ + V(public, LazyPropertyOfGlobalObject, m_JSBunRequestParamsPrototype) \ + \ + V(public, LazyPropertyOfGlobalObject, m_JSNodeHTTPServerSocketStructure) \ + V(public, LazyPropertyOfGlobalObject, m_statValues) \ + V(public, LazyPropertyOfGlobalObject, m_bigintStatValues) \ + V(public, LazyPropertyOfGlobalObject, m_statFsValues) \ + V(public, LazyPropertyOfGlobalObject, m_bigintStatFsValues) + +#define DECLARE_GLOBALOBJECT_GC_MEMBER(visibility, T, name) \ + visibility: \ + T name; + FOR_EACH_GLOBALOBJECT_GC_MEMBER(DECLARE_GLOBALOBJECT_GC_MEMBER) +#undef DECLARE_GLOBALOBJECT_GC_MEMBER WTF::String m_moduleWrapperStart; WTF::String m_moduleWrapperEnd; - // mutable WriteBarrier m_JSBunDebuggerValue; - mutable WriteBarrier m_thenables[promiseFunctionsSize + 1]; - - // Error.prepareStackTrace - mutable WriteBarrier m_errorConstructorPrepareStackTraceValue; - - // When a napi module initializes on dlopen, we need to know what the value is - mutable JSC::WriteBarrier m_pendingNapiModuleAndExports[2]; - // This is the result of dlopen()ing a napi module. // We will add it to the resulting napi value. void* m_pendingNapiModuleDlopenHandle = nullptr; - // The handle scope where all new NAPI values will be created. You must not pass any napi_values - // back to a NAPI function without putting them in the handle scope, as the NAPI function may - // move them off the stack which will cause them to get collected if not in the handle scope. - JSC::WriteBarrier m_currentNapiHandleScopeImpl; - - // The original, unmodified Error.prepareStackTrace. - // - // We set a default value for this to mimic Node.js behavior It is a - // separate from the user-facing value so that we can tell if the user - // really set it or if it's just the default value. - // - LazyProperty m_errorConstructorPrepareStackTraceInternalValue; - - LazyProperty m_nodeErrorCache; JSObject* nodeErrorCache() const { return m_nodeErrorCache.getInitializedOnMainThread(this); } Structure* memoryFootprintStructure() @@ -495,30 +652,13 @@ public: // To do that, we count the number of times we register a module. int napiModuleRegisterCallCount = 0; - // Used by napi_type_tag_object to associate a 128-bit type ID with JS objects. - // Should only use JSCell* keys and NapiTypeTag values. - LazyProperty m_napiTypeTags; - JSC::JSWeakMap* napiTypeTags() const { return m_napiTypeTags.getInitializedOnMainThread(this); } - Bun::JSMockModule mockModule; - - LazyProperty m_processEnvObject; - - LazyProperty m_JSS3FileStructure; - LazyProperty m_S3ErrorStructure; - - JSC::LazyClassStructure m_JSStatsClassStructure; - JSC::LazyClassStructure m_JSStatsBigIntClassStructure; - JSC::LazyClassStructure m_JSStatFSClassStructure; - JSC::LazyClassStructure m_JSStatFSBigIntClassStructure; - JSC::LazyClassStructure m_JSDirentClassStructure; - JSObject* cryptoObject() const { return m_cryptoObject.getInitializedOnMainThread(this); } JSObject* JSDOMFileConstructor() const { return m_JSDOMFileConstructor.getInitializedOnMainThread(this); } Bun::CommonStrings& commonStrings() { return m_commonStrings; } - Bun::Http2CommonStrings& http2CommonStrings() { return m_http2_commongStrings; } + Bun::Http2CommonStrings& http2CommonStrings() { return m_http2CommonStrings; } #include "ZigGeneratedClasses+lazyStructureHeader.h" void finishCreation(JSC::VM&); @@ -527,131 +667,13 @@ private: void addBuiltinGlobals(JSC::VM&); friend void WebCore::JSBuiltinInternalFunctions::initialize(Zig::GlobalObject&); - WebCore::JSBuiltinInternalFunctions m_builtinInternalFunctions; - std::unique_ptr m_constructors; uint8_t m_worldIsNormal; JSDOMStructureMap m_structures WTF_GUARDED_BY_LOCK(m_gcLock); Lock m_gcLock; Ref m_world; - Bun::CommonStrings m_commonStrings; - Bun::Http2CommonStrings m_http2_commongStrings; RefPtr m_performance { nullptr }; - // JSC's hashtable code-generator tries to access these properties, so we make them public. - // However, we'd like it better if they could be protected. public: - /** - * WARNING: You must update visitChildrenImpl() if you add a new field. - * - * That informs the garbage collector that these fields exist. If you don't - * do that, the garbage collector will not know about these fields and will - * not trace them. This will lead to crashes and very strange behavior at runtime. - * - * For example, if you don't add the queueMicrotask functions to visitChildrenImpl(), - * those callbacks will eventually never be called anymore. But it'll work the first time! - */ - LazyClassStructure m_JSArrayBufferSinkClassStructure; - LazyClassStructure m_JSBufferListClassStructure; - LazyClassStructure m_JSFFIFunctionStructure; - LazyClassStructure m_JSFileSinkClassStructure; - LazyClassStructure m_JSHTTPResponseSinkClassStructure; - LazyClassStructure m_JSHTTPSResponseSinkClassStructure; - LazyClassStructure m_JSNetworkSinkClassStructure; - - LazyClassStructure m_JSStringDecoderClassStructure; - LazyClassStructure m_NapiClassStructure; - LazyClassStructure m_callSiteStructure; - LazyClassStructure m_JSBufferClassStructure; - LazyClassStructure m_NodeVMScriptClassStructure; - LazyClassStructure m_JSX509CertificateClassStructure; - LazyClassStructure m_JSSignClassStructure; - LazyClassStructure m_JSVerifyClassStructure; - LazyClassStructure m_JSDiffieHellmanClassStructure; - LazyClassStructure m_JSDiffieHellmanGroupClassStructure; - LazyClassStructure m_JSHmacClassStructure; - LazyClassStructure m_JSHashClassStructure; - LazyClassStructure m_JSECDHClassStructure; - LazyClassStructure m_JSCipherClassStructure; - LazyClassStructure m_JSKeyObjectClassStructure; - LazyClassStructure m_JSSecretKeyObjectClassStructure; - LazyClassStructure m_JSPublicKeyObjectClassStructure; - LazyClassStructure m_JSPrivateKeyObjectClassStructure; - - /** - * WARNING: You must update visitChildrenImpl() if you add a new field. - * - * That informs the garbage collector that these fields exist. If you don't - * do that, the garbage collector will not know about these fields and will - * not trace them. This will lead to crashes and very strange behavior at runtime. - * - * For example, if you don't add the queueMicrotask functions to visitChildrenImpl(), - * those callbacks will eventually never be called anymore. But it'll work the first time! - */ - LazyProperty m_pendingVirtualModuleResultStructure; - LazyProperty m_performMicrotaskFunction; - LazyProperty m_nativeMicrotaskTrampoline; - LazyProperty m_performMicrotaskVariadicFunction; - LazyProperty m_utilInspectFunction; - LazyProperty m_utilInspectOptionsStructure; - LazyProperty m_utilInspectStylizeColorFunction; - LazyProperty m_utilInspectStylizeNoColorFunction; - LazyProperty m_lazyReadableStreamPrototypeMap; - LazyProperty m_requireMap; - LazyProperty m_esmRegistryMap; - LazyProperty m_JSArrayBufferControllerPrototype; - LazyProperty m_JSHTTPSResponseControllerPrototype; - LazyProperty m_JSFetchTaskletChunkedRequestControllerPrototype; - LazyProperty m_JSFileSinkControllerPrototype; - LazyProperty m_subtleCryptoObject; - LazyProperty m_JSHTTPResponseController; - LazyProperty m_JSBufferSubclassStructure; - LazyProperty m_JSResizableOrGrowableSharedBufferSubclassStructure; - LazyProperty m_vmModuleContextMap; - LazyProperty m_lazyRequireCacheObject; - LazyProperty m_lazyRequireExtensionsObject; - LazyProperty m_lazyTestModuleObject; - LazyProperty m_lazyPreloadTestModuleObject; - LazyProperty m_testMatcherUtilsObject; - LazyProperty m_cachedNodeVMGlobalObjectStructure; - LazyProperty m_cachedGlobalProxyStructure; - LazyProperty m_commonJSModuleObjectStructure; - LazyProperty m_JSSocketAddressDTOStructure; - LazyProperty m_memoryFootprintStructure; - LazyProperty m_requireFunctionUnbound; - LazyProperty m_requireResolveFunctionUnbound; - LazyProperty m_internalModuleRegistry; - LazyProperty m_processBindingBuffer; - LazyProperty m_processBindingConstants; - LazyProperty m_processBindingFs; - LazyProperty m_importMetaObjectStructure; - LazyProperty m_asyncBoundFunctionStructure; - LazyProperty m_JSDOMFileConstructor; - - LazyProperty m_JSCryptoKey; - LazyProperty m_NapiExternalStructure; - LazyProperty m_NapiPrototypeStructure; - LazyProperty m_NapiHandleScopeImplStructure; - LazyProperty m_NapiTypeTagStructure; - - LazyProperty m_JSSQLStatementStructure; - LazyProperty m_V8GlobalInternals; - - LazyProperty m_bunObject; - LazyProperty m_cryptoObject; - LazyProperty m_navigatorObject; - LazyProperty m_performanceObject; - LazyProperty m_processObject; - LazyProperty m_lazyStackCustomGetterSetter; - LazyProperty m_ServerRouteListStructure; - LazyProperty m_JSBunRequestStructure; - LazyProperty m_JSBunRequestParamsPrototype; - - LazyProperty m_JSNodeHTTPServerSocketStructure; - LazyProperty m_statValues; - LazyProperty m_bigintStatValues; - LazyProperty m_statFsValues; - LazyProperty m_bigintStatFsValues; - // De-optimization once `require("module")._resolveFilename` is written to bool hasOverriddenModuleResolveFilenameFunction = false; // De-optimization once `require("module").wrapper` or `require("module").wrap` is written to diff --git a/src/bun.js/bindings/webcore/DOMConstructors.h b/src/bun.js/bindings/webcore/DOMConstructors.h index 6f3dca538d..e2feb50296 100644 --- a/src/bun.js/bindings/webcore/DOMConstructors.h +++ b/src/bun.js/bindings/webcore/DOMConstructors.h @@ -875,6 +875,11 @@ public: DOMConstructors() = default; ConstructorArray& array() { return m_array; } const ConstructorArray& array() const { return m_array; } + template + void visit(Visitor& visitor) + { + visitor.append(m_array.begin(), m_array.end()); + } private: ConstructorArray m_array {};