Use macro to declare and visit garbage-collected GlobalObject members (#18835)

This commit is contained in:
190n
2025-04-23 12:03:04 -07:00
committed by GitHub
parent acc2925bbb
commit 6aaef99f88
6 changed files with 274 additions and 340 deletions

View File

@@ -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<JSNextTickQueue*>(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<Bun::JSNextTickQueue*>(globalObject->m_nextTickQueue.get());
nextTickQueueObject = globalObject->m_nextTickQueue.get();
}
JSC::JSFunction* initializer = JSC::JSFunction::create(vm, globalObject, processObjectInternalsInitializeNextTickQueueCodeGenerator(vm), globalObject);

View File

@@ -762,6 +762,17 @@ JSMockModule JSMockModule::create(JSC::JSGlobalObject* globalObject)
return mock;
}
template<typename Visitor> 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(

View File

@@ -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<JSC::JSGlobalObject, Structure> mockFunctionStructure;
LazyProperty<JSC::JSGlobalObject, Structure> mockResultStructure;
LazyProperty<JSC::JSGlobalObject, Structure> mockImplementationStructure;
LazyProperty<JSC::JSGlobalObject, Structure> mockObjectStructure;
LazyProperty<JSC::JSGlobalObject, Structure> mockModuleStructure;
LazyProperty<JSC::JSGlobalObject, Structure> activeSpySetStructure;
LazyProperty<JSC::JSGlobalObject, JSFunction> withImplementationCleanupFunction;
LazyProperty<JSC::JSGlobalObject, JSC::Structure> 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<JSGlobalObject, T> 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<JSC::Unknown> activeMocks;
// Called by Zig::GlobalObject::visitChildren
template<typename Visitor>
void visit(Visitor& visitor);
};
class MockWithImplementationCleanupData : public JSC::JSInternalFieldObjectImpl<4> {

View File

@@ -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<StackFrame>&
static void checkIfNextTickWasCalledDuringMicrotask(JSC::VM& vm)
{
auto* globalObject = defaultGlobalObject();
if (auto nextTickQueueValue = globalObject->m_nextTickQueue.get()) {
auto* queue = jsCast<Bun::JSNextTickQueue*>(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<Bun::JSNextTickQueue*>(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<class Visitor, class T> static void visitGlobalObjectMember(Visitor& visitor, T& anything)
{
anything.visit(visitor);
}
template<class Visitor, class T> static void visitGlobalObjectMember(Visitor& visitor, WriteBarrier<T>& barrier)
{
visitor.append(barrier);
}
template<class Visitor, class T> static void visitGlobalObjectMember(Visitor& visitor, std::unique_ptr<T>& ptr)
{
ptr->visit(visitor);
}
template<class Visitor, class T, size_t n> static void visitGlobalObjectMember(Visitor& visitor, std::array<WriteBarrier<T>, n>& barriers)
{
visitor.append(barriers.begin(), barriers.end());
}
template<typename Visitor>
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>(visitor);
WebCore::clientData(thisObject->vm())->httpHeaderIdentifiers().visit<Visitor>(visitor);
thisObject->m_http2_commongStrings.visit<Visitor>(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<Visitor>(thisObject, visitor);
thisObject->visitAdditionalChildren<Visitor>(visitor);

View File

@@ -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<JSFunction> m_assignToStream;
mutable WriteBarrier<JSFunction> m_readableStreamToArrayBuffer;
mutable WriteBarrier<JSFunction> m_readableStreamToArrayBufferResolve;
mutable WriteBarrier<JSFunction> m_readableStreamToBytes;
mutable WriteBarrier<JSFunction> m_readableStreamToBlob;
mutable WriteBarrier<JSFunction> m_readableStreamToJSON;
mutable WriteBarrier<JSFunction> m_readableStreamToText;
mutable WriteBarrier<JSFunction> m_readableStreamToFormData;
template<typename T>
using LazyPropertyOfGlobalObject = LazyProperty<JSGlobalObject, T>;
LazyProperty<JSGlobalObject, JSCell> m_moduleResolveFilenameFunction;
LazyProperty<JSGlobalObject, JSCell> m_moduleRunMainFunction;
LazyProperty<JSGlobalObject, JSFunction> m_modulePrototypeUnderscoreCompileFunction;
LazyProperty<JSGlobalObject, JSFunction> m_commonJSRequireESMFromHijackedExtensionFunction;
LazyProperty<JSGlobalObject, JSObject> m_nodeModuleConstructor;
using ThenablesArray = std::array<WriteBarrier<JSFunction>, promiseFunctionsSize + 1>;
using NapiModuleAndExports = std::array<WriteBarrier<Unknown>, 2>;
mutable WriteBarrier<Unknown> 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<Thing>, 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<T>`,
// `WriteBarrier<T>`, 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<JSFunction>, m_assignToStream) \
V(public, WriteBarrier<JSFunction>, m_readableStreamToArrayBuffer) \
V(public, WriteBarrier<JSFunction>, m_readableStreamToBytes) \
V(public, WriteBarrier<JSFunction>, m_readableStreamToBlob) \
V(public, WriteBarrier<JSFunction>, m_readableStreamToJSON) \
V(public, WriteBarrier<JSFunction>, m_readableStreamToText) \
V(public, WriteBarrier<JSFunction>, m_readableStreamToFormData) \
\
V(public, LazyPropertyOfGlobalObject<JSCell>, m_moduleResolveFilenameFunction) \
V(public, LazyPropertyOfGlobalObject<JSCell>, m_moduleRunMainFunction) \
V(public, LazyPropertyOfGlobalObject<JSFunction>, m_modulePrototypeUnderscoreCompileFunction) \
V(public, LazyPropertyOfGlobalObject<JSFunction>, m_commonJSRequireESMFromHijackedExtensionFunction) \
V(public, LazyPropertyOfGlobalObject<JSObject>, m_nodeModuleConstructor) \
\
V(public, WriteBarrier<Bun::JSNextTickQueue>, m_nextTickQueue) \
\
/* WriteBarrier<Unknown> m_JSBunDebuggerValue; */ \
V(private, ThenablesArray, m_thenables) \
\
/* Error.prepareStackTrace */ \
V(public, WriteBarrier<JSC::Unknown>, 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<Bun::NapiHandleScopeImpl>, 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<JSC::JSFunction>, m_errorConstructorPrepareStackTraceInternalValue) \
\
V(private, LazyPropertyOfGlobalObject<JSObject>, 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<JSC::JSWeakMap>, m_napiTypeTags) \
\
V(public, Bun::JSMockModule, mockModule) \
\
V(public, LazyPropertyOfGlobalObject<JSObject>, m_processEnvObject) \
\
V(public, LazyPropertyOfGlobalObject<Structure>, m_JSS3FileStructure) \
V(public, LazyPropertyOfGlobalObject<Structure>, 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<WebCore::DOMConstructors>, 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<Structure>, m_pendingVirtualModuleResultStructure) \
V(private, LazyPropertyOfGlobalObject<JSFunction>, m_performMicrotaskFunction) \
V(private, LazyPropertyOfGlobalObject<JSFunction>, m_nativeMicrotaskTrampoline) \
V(private, LazyPropertyOfGlobalObject<JSFunction>, m_performMicrotaskVariadicFunction) \
V(private, LazyPropertyOfGlobalObject<JSFunction>, m_utilInspectFunction) \
V(private, LazyPropertyOfGlobalObject<Structure>, m_utilInspectOptionsStructure) \
V(private, LazyPropertyOfGlobalObject<JSFunction>, m_utilInspectStylizeColorFunction) \
V(private, LazyPropertyOfGlobalObject<JSFunction>, m_utilInspectStylizeNoColorFunction) \
V(private, LazyPropertyOfGlobalObject<JSMap>, m_lazyReadableStreamPrototypeMap) \
V(private, LazyPropertyOfGlobalObject<JSMap>, m_requireMap) \
V(private, LazyPropertyOfGlobalObject<JSMap>, m_esmRegistryMap) \
V(private, LazyPropertyOfGlobalObject<JSObject>, m_JSArrayBufferControllerPrototype) \
V(private, LazyPropertyOfGlobalObject<JSObject>, m_JSHTTPSResponseControllerPrototype) \
V(private, LazyPropertyOfGlobalObject<JSObject>, m_JSFetchTaskletChunkedRequestControllerPrototype) \
V(private, LazyPropertyOfGlobalObject<JSObject>, m_JSFileSinkControllerPrototype) \
V(private, LazyPropertyOfGlobalObject<JSObject>, m_subtleCryptoObject) \
V(private, LazyPropertyOfGlobalObject<Structure>, m_JSHTTPResponseController) \
V(private, LazyPropertyOfGlobalObject<Structure>, m_JSBufferSubclassStructure) \
V(private, LazyPropertyOfGlobalObject<Structure>, m_JSResizableOrGrowableSharedBufferSubclassStructure) \
V(private, LazyPropertyOfGlobalObject<JSWeakMap>, m_vmModuleContextMap) \
V(public, LazyPropertyOfGlobalObject<JSObject>, m_lazyRequireCacheObject) \
V(public, LazyPropertyOfGlobalObject<Bun::JSCommonJSExtensions>, m_lazyRequireExtensionsObject) \
V(private, LazyPropertyOfGlobalObject<JSObject>, m_lazyTestModuleObject) \
V(private, LazyPropertyOfGlobalObject<JSObject>, m_lazyPreloadTestModuleObject) \
V(public, LazyPropertyOfGlobalObject<JSObject>, m_testMatcherUtilsObject) \
V(public, LazyPropertyOfGlobalObject<Structure>, m_cachedNodeVMGlobalObjectStructure) \
V(private, LazyPropertyOfGlobalObject<Structure>, m_cachedGlobalProxyStructure) \
V(private, LazyPropertyOfGlobalObject<Structure>, m_commonJSModuleObjectStructure) \
V(private, LazyPropertyOfGlobalObject<Structure>, m_JSSocketAddressDTOStructure) \
V(private, LazyPropertyOfGlobalObject<Structure>, m_memoryFootprintStructure) \
V(private, LazyPropertyOfGlobalObject<JSObject>, m_requireFunctionUnbound) \
V(private, LazyPropertyOfGlobalObject<JSObject>, m_requireResolveFunctionUnbound) \
V(private, LazyPropertyOfGlobalObject<Bun::InternalModuleRegistry>, m_internalModuleRegistry) \
V(private, LazyPropertyOfGlobalObject<JSObject>, m_processBindingBuffer) \
V(private, LazyPropertyOfGlobalObject<JSObject>, m_processBindingConstants) \
V(private, LazyPropertyOfGlobalObject<JSObject>, m_processBindingFs) \
V(private, LazyPropertyOfGlobalObject<Structure>, m_importMetaObjectStructure) \
V(private, LazyPropertyOfGlobalObject<Structure>, m_asyncBoundFunctionStructure) \
V(public, LazyPropertyOfGlobalObject<JSC::JSObject>, m_JSDOMFileConstructor) \
\
V(private, LazyPropertyOfGlobalObject<Structure>, m_JSCryptoKey) \
V(private, LazyPropertyOfGlobalObject<Structure>, m_NapiExternalStructure) \
V(private, LazyPropertyOfGlobalObject<Structure>, m_NapiPrototypeStructure) \
V(private, LazyPropertyOfGlobalObject<Structure>, m_NapiHandleScopeImplStructure) \
V(private, LazyPropertyOfGlobalObject<Structure>, m_NapiTypeTagStructure) \
\
V(private, LazyPropertyOfGlobalObject<Structure>, m_JSSQLStatementStructure) \
V(private, LazyPropertyOfGlobalObject<v8::shim::GlobalInternals>, m_V8GlobalInternals) \
\
V(public, LazyPropertyOfGlobalObject<JSObject>, m_bunObject) \
V(public, LazyPropertyOfGlobalObject<JSObject>, m_cryptoObject) \
V(public, LazyPropertyOfGlobalObject<JSObject>, m_navigatorObject) \
V(public, LazyPropertyOfGlobalObject<JSObject>, m_performanceObject) \
V(public, LazyPropertyOfGlobalObject<JSObject>, m_processObject) \
V(public, LazyPropertyOfGlobalObject<CustomGetterSetter>, m_lazyStackCustomGetterSetter) \
V(public, LazyPropertyOfGlobalObject<Structure>, m_ServerRouteListStructure) \
V(public, LazyPropertyOfGlobalObject<Structure>, m_JSBunRequestStructure) \
V(public, LazyPropertyOfGlobalObject<JSObject>, m_JSBunRequestParamsPrototype) \
\
V(public, LazyPropertyOfGlobalObject<Structure>, m_JSNodeHTTPServerSocketStructure) \
V(public, LazyPropertyOfGlobalObject<JSFloat64Array>, m_statValues) \
V(public, LazyPropertyOfGlobalObject<JSBigInt64Array>, m_bigintStatValues) \
V(public, LazyPropertyOfGlobalObject<JSFloat64Array>, m_statFsValues) \
V(public, LazyPropertyOfGlobalObject<JSBigInt64Array>, 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<Unknown> m_JSBunDebuggerValue;
mutable WriteBarrier<JSFunction> m_thenables[promiseFunctionsSize + 1];
// Error.prepareStackTrace
mutable WriteBarrier<JSC::Unknown> m_errorConstructorPrepareStackTraceValue;
// When a napi module initializes on dlopen, we need to know what the value is
mutable JSC::WriteBarrier<Unknown> 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<Bun::NapiHandleScopeImpl> 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<JSGlobalObject, JSC::JSFunction> m_errorConstructorPrepareStackTraceInternalValue;
LazyProperty<JSGlobalObject, JSObject> 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<JSGlobalObject, JSC::JSWeakMap> m_napiTypeTags;
JSC::JSWeakMap* napiTypeTags() const { return m_napiTypeTags.getInitializedOnMainThread(this); }
Bun::JSMockModule mockModule;
LazyProperty<JSGlobalObject, JSObject> m_processEnvObject;
LazyProperty<JSGlobalObject, Structure> m_JSS3FileStructure;
LazyProperty<JSGlobalObject, Structure> 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<WebCore::DOMConstructors> m_constructors;
uint8_t m_worldIsNormal;
JSDOMStructureMap m_structures WTF_GUARDED_BY_LOCK(m_gcLock);
Lock m_gcLock;
Ref<WebCore::DOMWrapperWorld> m_world;
Bun::CommonStrings m_commonStrings;
Bun::Http2CommonStrings m_http2_commongStrings;
RefPtr<WebCore::Performance> 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<JSGlobalObject, Structure> m_pendingVirtualModuleResultStructure;
LazyProperty<JSGlobalObject, JSFunction> m_performMicrotaskFunction;
LazyProperty<JSGlobalObject, JSFunction> m_nativeMicrotaskTrampoline;
LazyProperty<JSGlobalObject, JSFunction> m_performMicrotaskVariadicFunction;
LazyProperty<JSGlobalObject, JSFunction> m_utilInspectFunction;
LazyProperty<JSGlobalObject, Structure> m_utilInspectOptionsStructure;
LazyProperty<JSGlobalObject, JSFunction> m_utilInspectStylizeColorFunction;
LazyProperty<JSGlobalObject, JSFunction> m_utilInspectStylizeNoColorFunction;
LazyProperty<JSGlobalObject, JSMap> m_lazyReadableStreamPrototypeMap;
LazyProperty<JSGlobalObject, JSMap> m_requireMap;
LazyProperty<JSGlobalObject, JSMap> m_esmRegistryMap;
LazyProperty<JSGlobalObject, JSObject> m_JSArrayBufferControllerPrototype;
LazyProperty<JSGlobalObject, JSObject> m_JSHTTPSResponseControllerPrototype;
LazyProperty<JSGlobalObject, JSObject> m_JSFetchTaskletChunkedRequestControllerPrototype;
LazyProperty<JSGlobalObject, JSObject> m_JSFileSinkControllerPrototype;
LazyProperty<JSGlobalObject, JSObject> m_subtleCryptoObject;
LazyProperty<JSGlobalObject, Structure> m_JSHTTPResponseController;
LazyProperty<JSGlobalObject, Structure> m_JSBufferSubclassStructure;
LazyProperty<JSGlobalObject, Structure> m_JSResizableOrGrowableSharedBufferSubclassStructure;
LazyProperty<JSGlobalObject, JSWeakMap> m_vmModuleContextMap;
LazyProperty<JSGlobalObject, JSObject> m_lazyRequireCacheObject;
LazyProperty<JSGlobalObject, Bun::JSCommonJSExtensions> m_lazyRequireExtensionsObject;
LazyProperty<JSGlobalObject, JSObject> m_lazyTestModuleObject;
LazyProperty<JSGlobalObject, JSObject> m_lazyPreloadTestModuleObject;
LazyProperty<JSGlobalObject, JSObject> m_testMatcherUtilsObject;
LazyProperty<JSGlobalObject, Structure> m_cachedNodeVMGlobalObjectStructure;
LazyProperty<JSGlobalObject, Structure> m_cachedGlobalProxyStructure;
LazyProperty<JSGlobalObject, Structure> m_commonJSModuleObjectStructure;
LazyProperty<JSGlobalObject, Structure> m_JSSocketAddressDTOStructure;
LazyProperty<JSGlobalObject, Structure> m_memoryFootprintStructure;
LazyProperty<JSGlobalObject, JSObject> m_requireFunctionUnbound;
LazyProperty<JSGlobalObject, JSObject> m_requireResolveFunctionUnbound;
LazyProperty<JSGlobalObject, Bun::InternalModuleRegistry> m_internalModuleRegistry;
LazyProperty<JSGlobalObject, JSObject> m_processBindingBuffer;
LazyProperty<JSGlobalObject, JSObject> m_processBindingConstants;
LazyProperty<JSGlobalObject, JSObject> m_processBindingFs;
LazyProperty<JSGlobalObject, Structure> m_importMetaObjectStructure;
LazyProperty<JSGlobalObject, Structure> m_asyncBoundFunctionStructure;
LazyProperty<JSGlobalObject, JSC::JSObject> m_JSDOMFileConstructor;
LazyProperty<JSGlobalObject, Structure> m_JSCryptoKey;
LazyProperty<JSGlobalObject, Structure> m_NapiExternalStructure;
LazyProperty<JSGlobalObject, Structure> m_NapiPrototypeStructure;
LazyProperty<JSGlobalObject, Structure> m_NapiHandleScopeImplStructure;
LazyProperty<JSGlobalObject, Structure> m_NapiTypeTagStructure;
LazyProperty<JSGlobalObject, Structure> m_JSSQLStatementStructure;
LazyProperty<JSGlobalObject, v8::shim::GlobalInternals> m_V8GlobalInternals;
LazyProperty<JSGlobalObject, JSObject> m_bunObject;
LazyProperty<JSGlobalObject, JSObject> m_cryptoObject;
LazyProperty<JSGlobalObject, JSObject> m_navigatorObject;
LazyProperty<JSGlobalObject, JSObject> m_performanceObject;
LazyProperty<JSGlobalObject, JSObject> m_processObject;
LazyProperty<JSGlobalObject, CustomGetterSetter> m_lazyStackCustomGetterSetter;
LazyProperty<JSGlobalObject, Structure> m_ServerRouteListStructure;
LazyProperty<JSGlobalObject, Structure> m_JSBunRequestStructure;
LazyProperty<JSGlobalObject, JSObject> m_JSBunRequestParamsPrototype;
LazyProperty<JSGlobalObject, Structure> m_JSNodeHTTPServerSocketStructure;
LazyProperty<JSGlobalObject, JSFloat64Array> m_statValues;
LazyProperty<JSGlobalObject, JSBigInt64Array> m_bigintStatValues;
LazyProperty<JSGlobalObject, JSFloat64Array> m_statFsValues;
LazyProperty<JSGlobalObject, JSBigInt64Array> 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

View File

@@ -875,6 +875,11 @@ public:
DOMConstructors() = default;
ConstructorArray& array() { return m_array; }
const ConstructorArray& array() const { return m_array; }
template<typename Visitor>
void visit(Visitor& visitor)
{
visitor.append(m_array.begin(), m_array.end());
}
private:
ConstructorArray m_array {};