Add support for dumping GC heap snapshots, and a viewer
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Aug 2018 04:10:31 +0000 (04:10 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 24 Aug 2018 04:10:31 +0000 (04:10 +0000)
https://bugs.webkit.org/show_bug.cgi?id=186416

Reviewed by Joseph Pecoraro.

Source/JavaScriptCore:

Make a way to dump information about the GC heap that is useful for looking for leaked
or abandoned objects. This dump is obtained (on Apple platforms) via:
    notifyutil -p com.apple.WebKit.dumpGCHeap
which writes a JSON file to /tmp which can then be loaded into the viewer in Tools/GCHeapInspector.

This leverages the heap snapshot used by Web Inspector, adding an alternate format for
the snapshot JSON that adds additional data about objects and why they are GC roots.

SlotVisitor maintains a RootMarkReason (via SetRootMarkReasonScope) that allows
the HeapSnapshotBuilder to keep track of why a JSCell was treated as a GC root. For
objects visited via opaque roots, we record the reason why via a new out param to
isReachableFromOpaqueRoots().

HeapSnapshotBuilder is enhanced to produce GCDebuggingSnapshot JSON output. This contains
additional information including the address of the JSCell* and the wrapped object (for
JSDOMWrappers), the root reasons, and for some objects like JSDocument a label which can
be the document URL.

GCDebuggingSnapshots are always full snapshots (previous snapshots are not kept around).

* API/JSAPIWrapperObject.mm:
(JSAPIWrapperObjectHandleOwner::isReachableFromOpaqueRoots):
* API/JSManagedValue.mm:
(JSManagedValueHandleOwner::isReachableFromOpaqueRoots):
* API/glib/JSAPIWrapperObjectGLib.cpp:
(JSAPIWrapperObjectHandleOwner::isReachableFromOpaqueRoots):
* CMakeLists.txt:
* heap/ConservativeRoots.h:
(JSC::ConservativeRoots::size const):
(JSC::ConservativeRoots::size): Deleted.
* heap/Heap.cpp:
(JSC::Heap::addCoreConstraints):
* heap/HeapSnapshotBuilder.cpp:
(JSC::HeapSnapshotBuilder::getNextObjectIdentifier):
(JSC::HeapSnapshotBuilder::HeapSnapshotBuilder):
(JSC::HeapSnapshotBuilder::~HeapSnapshotBuilder):
(JSC::HeapSnapshotBuilder::buildSnapshot):
(JSC::HeapSnapshotBuilder::appendNode):
(JSC::HeapSnapshotBuilder::appendEdge):
(JSC::HeapSnapshotBuilder::setOpaqueRootReachabilityReasonForCell):
(JSC::HeapSnapshotBuilder::setWrappedObjectForCell):
(JSC::HeapSnapshotBuilder::previousSnapshotHasNodeForCell):
(JSC::snapshotTypeToString):
(JSC::rootTypeToString):
(JSC::HeapSnapshotBuilder::setLabelForCell):
(JSC::HeapSnapshotBuilder::descriptionForCell const):
(JSC::HeapSnapshotBuilder::json):
(JSC::HeapSnapshotBuilder::hasExistingNodeForCell): Deleted.
* heap/HeapSnapshotBuilder.h:
* heap/SlotVisitor.cpp:
(JSC::SlotVisitor::appendSlow):
* heap/SlotVisitor.h:
(JSC::SlotVisitor::heapSnapshotBuilder const):
(JSC::SlotVisitor::rootMarkReason const):
(JSC::SlotVisitor::setRootMarkReason):
(JSC::SetRootMarkReasonScope::SetRootMarkReasonScope):
(JSC::SetRootMarkReasonScope::~SetRootMarkReasonScope):
* heap/WeakBlock.cpp:
(JSC::WeakBlock::specializedVisit):
* heap/WeakHandleOwner.cpp:
(JSC::WeakHandleOwner::isReachableFromOpaqueRoots):
* heap/WeakHandleOwner.h:
* runtime/SimpleTypedArrayController.cpp:
(JSC::SimpleTypedArrayController::JSArrayBufferOwner::isReachableFromOpaqueRoots):
* runtime/SimpleTypedArrayController.h:
* tools/JSDollarVM.cpp:

Source/WebCore:

Make a way to dump information about the GC heap that is useful for looking for leaked
or abandoned objects. This dump is obtained (on Apple platforms) via:
    notifyutil -p com.apple.WebKit.dumpGCHeap
which writes a JSON file to /tmp which can then be loaded into the viewer in Tools/GCHeapInspector.

This leverages the heap snapshot used by Web Inspector, adding an alternate format for
the snapshot JSON that adds additional data about objects and why they are GC roots.

The generated bindings code is changed to include the output root reason from isReachableFromOpaqueRoots(),
and to implement heapSnapshot() which provides the address of the wrapped object. A new IDL attribute,
CustomHeapSnapshot, is used to allow custom heapSnapshot() implementations for classes like JSDocument
that need to decorate the heap snapshot cell data with things like the document URL.

GCController registers a notifyutil callback which gathers the debug heap snapshot, and dumps it
to a file in /tmp. The file path is printed out to the system log.

* bindings/js/DOMGCOutputConstraint.cpp:
(WebCore::DOMGCOutputConstraint::executeImpl):
* bindings/js/GCController.cpp:
(WebCore::GCController::GCController):
(WebCore::GCController::dumpHeap):
* bindings/js/GCController.h:
* bindings/js/JSCSSRuleListCustom.cpp:
(WebCore::JSCSSRuleListOwner::isReachableFromOpaqueRoots):
* bindings/js/JSCallbackData.cpp:
(WebCore::JSCallbackDataWeak::WeakOwner::isReachableFromOpaqueRoots):
* bindings/js/JSCallbackData.h:
* bindings/js/JSCanvasRenderingContext2DCustom.cpp:
(WebCore::JSCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots):
* bindings/js/JSDOMWindowCustom.cpp:
(WebCore::JSDOMWindow::getOwnPropertySlot):
(WebCore::JSDOMWindow::heapSnapshot):
* bindings/js/JSDeprecatedCSSOMValueCustom.cpp:
(WebCore::JSDeprecatedCSSOMValueOwner::isReachableFromOpaqueRoots):
* bindings/js/JSDocumentCustom.cpp:
(WebCore::JSDocument::heapSnapshot):
* bindings/js/JSMicrotaskCallback.h:
(WebCore::JSMicrotaskCallback::call):
* bindings/js/JSMutationObserverCustom.cpp:
(WebCore::JSMutationObserverOwner::isReachableFromOpaqueRoots):
* bindings/js/JSNavigatorCustom.cpp:
(WebCore::JSNavigator::visitAdditionalChildren):
* bindings/js/JSNodeCustom.cpp:
(WebCore::isReachableFromDOM):
(WebCore::JSNodeOwner::isReachableFromOpaqueRoots):
* bindings/js/JSNodeListCustom.cpp:
(WebCore::JSNodeListOwner::isReachableFromOpaqueRoots):
* bindings/js/JSOffscreenCanvasRenderingContext2DCustom.cpp:
(WebCore::JSOffscreenCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots):
* bindings/js/JSPerformanceObserverCustom.cpp:
(WebCore::JSPerformanceObserverOwner::isReachableFromOpaqueRoots):
* bindings/js/JSPopStateEventCustom.cpp:
* bindings/js/JSTextTrackCueCustom.cpp:
(WebCore::JSTextTrackCueOwner::isReachableFromOpaqueRoots):
* bindings/js/WebCoreTypedArrayController.cpp:
(WebCore::WebCoreTypedArrayController::JSArrayBufferOwner::isReachableFromOpaqueRoots):
* bindings/js/WebCoreTypedArrayController.h:
* bindings/scripts/CodeGeneratorJS.pm:
(GenerateHeader):
(GenerateImplementation):
* bindings/scripts/IDLAttributes.json:
* bindings/scripts/test/JS/JSInterfaceName.cpp:
(WebCore::JSInterfaceName::heapSnapshot):
(WebCore::JSInterfaceNameOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSInterfaceName.h:
* bindings/scripts/test/JS/JSMapLike.cpp:
(WebCore::JSMapLike::heapSnapshot):
(WebCore::JSMapLikeOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSMapLike.h:
* bindings/scripts/test/JS/JSReadOnlyMapLike.cpp:
(WebCore::JSReadOnlyMapLike::heapSnapshot):
(WebCore::JSReadOnlyMapLikeOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSReadOnlyMapLike.h:
* bindings/scripts/test/JS/JSTestActiveDOMObject.cpp:
(WebCore::JSTestActiveDOMObject::heapSnapshot):
(WebCore::JSTestActiveDOMObjectOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestActiveDOMObject.h:
* bindings/scripts/test/JS/JSTestCEReactions.cpp:
(WebCore::JSTestCEReactions::heapSnapshot):
(WebCore::JSTestCEReactionsOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestCEReactions.h:
* bindings/scripts/test/JS/JSTestCEReactionsStringifier.cpp:
(WebCore::JSTestCEReactionsStringifier::heapSnapshot):
(WebCore::JSTestCEReactionsStringifierOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestCEReactionsStringifier.h:
* bindings/scripts/test/JS/JSTestCallTracer.cpp:
(WebCore::JSTestCallTracer::heapSnapshot):
(WebCore::JSTestCallTracerOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestCallTracer.h:
* bindings/scripts/test/JS/JSTestClassWithJSBuiltinConstructor.cpp:
(WebCore::JSTestClassWithJSBuiltinConstructor::heapSnapshot):
(WebCore::JSTestClassWithJSBuiltinConstructorOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestClassWithJSBuiltinConstructor.h:
* bindings/scripts/test/JS/JSTestCustomConstructorWithNoInterfaceObject.cpp:
(WebCore::JSTestCustomConstructorWithNoInterfaceObject::heapSnapshot):
(WebCore::JSTestCustomConstructorWithNoInterfaceObjectOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestCustomConstructorWithNoInterfaceObject.h:
* bindings/scripts/test/JS/JSTestDOMJIT.cpp:
(WebCore::JSTestDOMJIT::heapSnapshot):
* bindings/scripts/test/JS/JSTestDOMJIT.h:
* bindings/scripts/test/JS/JSTestEnabledBySetting.cpp:
(WebCore::JSTestEnabledBySetting::heapSnapshot):
(WebCore::JSTestEnabledBySettingOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestEnabledBySetting.h:
* bindings/scripts/test/JS/JSTestEventConstructor.cpp:
(WebCore::JSTestEventConstructor::heapSnapshot):
* bindings/scripts/test/JS/JSTestEventConstructor.h:
* bindings/scripts/test/JS/JSTestEventTarget.cpp:
(WebCore::JSTestEventTarget::heapSnapshot):
* bindings/scripts/test/JS/JSTestEventTarget.h:
* bindings/scripts/test/JS/JSTestException.cpp:
(WebCore::JSTestException::heapSnapshot):
(WebCore::JSTestExceptionOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestException.h:
* bindings/scripts/test/JS/JSTestGenerateIsReachable.cpp:
(WebCore::JSTestGenerateIsReachable::heapSnapshot):
(WebCore::JSTestGenerateIsReachableOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestGenerateIsReachable.h:
* bindings/scripts/test/JS/JSTestGlobalObject.cpp:
(WebCore::JSTestGlobalObject::heapSnapshot):
(WebCore::JSTestGlobalObjectOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestGlobalObject.h:
* bindings/scripts/test/JS/JSTestIndexedSetterNoIdentifier.cpp:
(WebCore::JSTestIndexedSetterNoIdentifier::heapSnapshot):
(WebCore::JSTestIndexedSetterNoIdentifierOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestIndexedSetterNoIdentifier.h:
* bindings/scripts/test/JS/JSTestIndexedSetterThrowingException.cpp:
(WebCore::JSTestIndexedSetterThrowingException::heapSnapshot):
(WebCore::JSTestIndexedSetterThrowingExceptionOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestIndexedSetterThrowingException.h:
* bindings/scripts/test/JS/JSTestIndexedSetterWithIdentifier.cpp:
(WebCore::JSTestIndexedSetterWithIdentifier::heapSnapshot):
(WebCore::JSTestIndexedSetterWithIdentifierOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestIndexedSetterWithIdentifier.h:
* bindings/scripts/test/JS/JSTestInterface.cpp:
(WebCore::JSTestInterface::heapSnapshot):
(WebCore::JSTestInterfaceOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestInterface.h:
* bindings/scripts/test/JS/JSTestInterfaceLeadingUnderscore.cpp:
(WebCore::JSTestInterfaceLeadingUnderscore::heapSnapshot):
(WebCore::JSTestInterfaceLeadingUnderscoreOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestInterfaceLeadingUnderscore.h:
* bindings/scripts/test/JS/JSTestIterable.cpp:
(WebCore::JSTestIterable::heapSnapshot):
(WebCore::JSTestIterableOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestIterable.h:
* bindings/scripts/test/JS/JSTestMediaQueryListListener.cpp:
(WebCore::JSTestMediaQueryListListener::heapSnapshot):
(WebCore::JSTestMediaQueryListListenerOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestMediaQueryListListener.h:
* bindings/scripts/test/JS/JSTestNamedAndIndexedSetterNoIdentifier.cpp:
(WebCore::JSTestNamedAndIndexedSetterNoIdentifier::heapSnapshot):
(WebCore::JSTestNamedAndIndexedSetterNoIdentifierOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedAndIndexedSetterNoIdentifier.h:
* bindings/scripts/test/JS/JSTestNamedAndIndexedSetterThrowingException.cpp:
(WebCore::JSTestNamedAndIndexedSetterThrowingException::heapSnapshot):
(WebCore::JSTestNamedAndIndexedSetterThrowingExceptionOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedAndIndexedSetterThrowingException.h:
* bindings/scripts/test/JS/JSTestNamedAndIndexedSetterWithIdentifier.cpp:
(WebCore::JSTestNamedAndIndexedSetterWithIdentifier::heapSnapshot):
(WebCore::JSTestNamedAndIndexedSetterWithIdentifierOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedAndIndexedSetterWithIdentifier.h:
* bindings/scripts/test/JS/JSTestNamedConstructor.cpp:
(WebCore::JSTestNamedConstructor::heapSnapshot):
(WebCore::JSTestNamedConstructorOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedConstructor.h:
* bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.cpp:
(WebCore::JSTestNamedDeleterNoIdentifier::heapSnapshot):
(WebCore::JSTestNamedDeleterNoIdentifierOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.h:
* bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.cpp:
(WebCore::JSTestNamedDeleterThrowingException::heapSnapshot):
(WebCore::JSTestNamedDeleterThrowingExceptionOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.h:
* bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.cpp:
(WebCore::JSTestNamedDeleterWithIdentifier::heapSnapshot):
(WebCore::JSTestNamedDeleterWithIdentifierOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.h:
* bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.cpp:
(WebCore::JSTestNamedDeleterWithIndexedGetter::heapSnapshot):
(WebCore::JSTestNamedDeleterWithIndexedGetterOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.h:
* bindings/scripts/test/JS/JSTestNamedGetterCallWith.cpp:
(WebCore::JSTestNamedGetterCallWith::heapSnapshot):
(WebCore::JSTestNamedGetterCallWithOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedGetterCallWith.h:
* bindings/scripts/test/JS/JSTestNamedGetterNoIdentifier.cpp:
(WebCore::JSTestNamedGetterNoIdentifier::heapSnapshot):
(WebCore::JSTestNamedGetterNoIdentifierOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedGetterNoIdentifier.h:
* bindings/scripts/test/JS/JSTestNamedGetterWithIdentifier.cpp:
(WebCore::JSTestNamedGetterWithIdentifier::heapSnapshot):
(WebCore::JSTestNamedGetterWithIdentifierOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedGetterWithIdentifier.h:
* bindings/scripts/test/JS/JSTestNamedSetterNoIdentifier.cpp:
(WebCore::JSTestNamedSetterNoIdentifier::heapSnapshot):
(WebCore::JSTestNamedSetterNoIdentifierOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedSetterNoIdentifier.h:
* bindings/scripts/test/JS/JSTestNamedSetterThrowingException.cpp:
(WebCore::JSTestNamedSetterThrowingException::heapSnapshot):
(WebCore::JSTestNamedSetterThrowingExceptionOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedSetterThrowingException.h:
* bindings/scripts/test/JS/JSTestNamedSetterWithIdentifier.cpp:
(WebCore::JSTestNamedSetterWithIdentifier::heapSnapshot):
(WebCore::JSTestNamedSetterWithIdentifierOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedSetterWithIdentifier.h:
* bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetter.cpp:
(WebCore::JSTestNamedSetterWithIndexedGetter::heapSnapshot):
(WebCore::JSTestNamedSetterWithIndexedGetterOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetter.h:
* bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetterAndSetter.cpp:
(WebCore::JSTestNamedSetterWithIndexedGetterAndSetter::heapSnapshot):
(WebCore::JSTestNamedSetterWithIndexedGetterAndSetterOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetterAndSetter.h:
* bindings/scripts/test/JS/JSTestNamedSetterWithOverrideBuiltins.cpp:
(WebCore::JSTestNamedSetterWithOverrideBuiltins::heapSnapshot):
(WebCore::JSTestNamedSetterWithOverrideBuiltinsOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedSetterWithOverrideBuiltins.h:
* bindings/scripts/test/JS/JSTestNamedSetterWithUnforgableProperties.cpp:
(WebCore::JSTestNamedSetterWithUnforgableProperties::heapSnapshot):
(WebCore::JSTestNamedSetterWithUnforgablePropertiesOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedSetterWithUnforgableProperties.h:
* bindings/scripts/test/JS/JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins.cpp:
(WebCore::JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins::heapSnapshot):
(WebCore::JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltinsOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins.h:
* bindings/scripts/test/JS/JSTestNode.cpp:
(WebCore::JSTestNode::heapSnapshot):
* bindings/scripts/test/JS/JSTestNode.h:
* bindings/scripts/test/JS/JSTestObj.cpp:
(WebCore::JSTestObj::heapSnapshot):
(WebCore::JSTestObjOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestObj.h:
* bindings/scripts/test/JS/JSTestOverloadedConstructors.cpp:
(WebCore::JSTestOverloadedConstructors::heapSnapshot):
(WebCore::JSTestOverloadedConstructorsOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestOverloadedConstructors.h:
* bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.cpp:
(WebCore::JSTestOverloadedConstructorsWithSequence::heapSnapshot):
(WebCore::JSTestOverloadedConstructorsWithSequenceOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.h:
* bindings/scripts/test/JS/JSTestOverrideBuiltins.cpp:
(WebCore::JSTestOverrideBuiltins::heapSnapshot):
(WebCore::JSTestOverrideBuiltinsOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestOverrideBuiltins.h:
* bindings/scripts/test/JS/JSTestPluginInterface.cpp:
(WebCore::JSTestPluginInterface::heapSnapshot):
(WebCore::JSTestPluginInterfaceOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestPluginInterface.h:
* bindings/scripts/test/JS/JSTestPromiseRejectionEvent.cpp:
(WebCore::JSTestPromiseRejectionEvent::heapSnapshot):
* bindings/scripts/test/JS/JSTestPromiseRejectionEvent.h:
* bindings/scripts/test/JS/JSTestSerialization.cpp:
(WebCore::JSTestSerialization::heapSnapshot):
(WebCore::JSTestSerializationOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestSerialization.h:
* bindings/scripts/test/JS/JSTestSerializationIndirectInheritance.cpp:
(WebCore::JSTestSerializationIndirectInheritance::heapSnapshot):
* bindings/scripts/test/JS/JSTestSerializationIndirectInheritance.h:
* bindings/scripts/test/JS/JSTestSerializationInherit.cpp:
(WebCore::JSTestSerializationInherit::heapSnapshot):
* bindings/scripts/test/JS/JSTestSerializationInherit.h:
* bindings/scripts/test/JS/JSTestSerializationInheritFinal.cpp:
(WebCore::JSTestSerializationInheritFinal::heapSnapshot):
* bindings/scripts/test/JS/JSTestSerializationInheritFinal.h:
* bindings/scripts/test/JS/JSTestSerializedScriptValueInterface.cpp:
(WebCore::JSTestSerializedScriptValueInterface::heapSnapshot):
(WebCore::JSTestSerializedScriptValueInterfaceOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestSerializedScriptValueInterface.h:
* bindings/scripts/test/JS/JSTestStringifier.cpp:
(WebCore::JSTestStringifier::heapSnapshot):
(WebCore::JSTestStringifierOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestStringifier.h:
* bindings/scripts/test/JS/JSTestStringifierAnonymousOperation.cpp:
(WebCore::JSTestStringifierAnonymousOperation::heapSnapshot):
(WebCore::JSTestStringifierAnonymousOperationOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestStringifierAnonymousOperation.h:
* bindings/scripts/test/JS/JSTestStringifierNamedOperation.cpp:
(WebCore::JSTestStringifierNamedOperation::heapSnapshot):
(WebCore::JSTestStringifierNamedOperationOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestStringifierNamedOperation.h:
* bindings/scripts/test/JS/JSTestStringifierOperationImplementedAs.cpp:
(WebCore::JSTestStringifierOperationImplementedAs::heapSnapshot):
(WebCore::JSTestStringifierOperationImplementedAsOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestStringifierOperationImplementedAs.h:
* bindings/scripts/test/JS/JSTestStringifierOperationNamedToString.cpp:
(WebCore::JSTestStringifierOperationNamedToString::heapSnapshot):
(WebCore::JSTestStringifierOperationNamedToStringOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestStringifierOperationNamedToString.h:
* bindings/scripts/test/JS/JSTestStringifierReadOnlyAttribute.cpp:
(WebCore::JSTestStringifierReadOnlyAttribute::heapSnapshot):
(WebCore::JSTestStringifierReadOnlyAttributeOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestStringifierReadOnlyAttribute.h:
* bindings/scripts/test/JS/JSTestStringifierReadWriteAttribute.cpp:
(WebCore::JSTestStringifierReadWriteAttribute::heapSnapshot):
(WebCore::JSTestStringifierReadWriteAttributeOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestStringifierReadWriteAttribute.h:
* bindings/scripts/test/JS/JSTestTypedefs.cpp:
(WebCore::JSTestTypedefs::heapSnapshot):
(WebCore::JSTestTypedefsOwner::isReachableFromOpaqueRoots):
* bindings/scripts/test/JS/JSTestTypedefs.h:
* dom/Document.idl:
* page/DOMWindow.idl:

Source/WebInspectorUI:

Make a way to dump information about the GC heap that is useful for looking for leaked
or abandoned objects. This dump is obtained (on Apple platforms) via:
    notifyutil -p com.apple.WebKit.dumpGCHeap
which writes a JSON file to /tmp which can then be loaded into the viewer in Tools/GCHeapInspector.

This leverages the heap snapshot used by Web Inspector, adding an alternate format for
the snapshot JSON that adds additional data about objects and why they are GC roots.

The generated bindings code is changed to include the output root reason from isReachableFromOpaqueRoots(),
and to implement heapSnapshot() which provides the address of the wrapped object. A new IDL attribute,
CustomHeapSnapshot, is used to allow custom heapSnapshot() implementations for classes like JSDocument
that need to decorate the heap snapshot cell data with things like the document URL.

GCController registers a notifyutil callback which gathers the debug heap snapshot, and dumps it
to a file in /tmp. The file path is printed out to the system log.

* UserInterface/Workers/HeapSnapshot/HeapSnapshot.js:
(HeapSnapshot):

Tools:

Add a viewer for GC heap snapshots. A snapshot JSON file can be dragged into this
page for inspection (or set via the 'filename' URL parameter).

For now, this page shows all objects, all roots, and the shortest path from a root
to all HTMLDocuments and Windows.

* GCHeapInspector/gc-heap-inspector.html: Added.
* GCHeapInspector/heap-analysis/HeapSnapshot.js: Copied from Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js.
* GCHeapInspector/script/interface.js: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@235271 268f45cc-cd09-0410-ab3c-d52691b4dbfc

173 files changed:
Source/JavaScriptCore/API/JSAPIWrapperObject.mm
Source/JavaScriptCore/API/JSManagedValue.mm
Source/JavaScriptCore/API/glib/JSAPIWrapperObjectGLib.cpp
Source/JavaScriptCore/CMakeLists.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/heap/ConservativeRoots.h
Source/JavaScriptCore/heap/Heap.cpp
Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp
Source/JavaScriptCore/heap/HeapSnapshotBuilder.h
Source/JavaScriptCore/heap/SlotVisitor.cpp
Source/JavaScriptCore/heap/SlotVisitor.h
Source/JavaScriptCore/heap/WeakBlock.cpp
Source/JavaScriptCore/heap/WeakHandleOwner.cpp
Source/JavaScriptCore/heap/WeakHandleOwner.h
Source/JavaScriptCore/runtime/SimpleTypedArrayController.cpp
Source/JavaScriptCore/runtime/SimpleTypedArrayController.h
Source/JavaScriptCore/tools/JSDollarVM.cpp
Source/WebCore/ChangeLog
Source/WebCore/bindings/js/DOMGCOutputConstraint.cpp
Source/WebCore/bindings/js/GCController.cpp
Source/WebCore/bindings/js/GCController.h
Source/WebCore/bindings/js/JSCSSRuleListCustom.cpp
Source/WebCore/bindings/js/JSCallbackData.cpp
Source/WebCore/bindings/js/JSCallbackData.h
Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp
Source/WebCore/bindings/js/JSDOMWindowCustom.cpp
Source/WebCore/bindings/js/JSDeprecatedCSSOMValueCustom.cpp
Source/WebCore/bindings/js/JSDocumentCustom.cpp
Source/WebCore/bindings/js/JSMicrotaskCallback.h
Source/WebCore/bindings/js/JSMutationObserverCustom.cpp
Source/WebCore/bindings/js/JSNavigatorCustom.cpp
Source/WebCore/bindings/js/JSNodeCustom.cpp
Source/WebCore/bindings/js/JSNodeListCustom.cpp
Source/WebCore/bindings/js/JSOffscreenCanvasRenderingContext2DCustom.cpp
Source/WebCore/bindings/js/JSPerformanceObserverCustom.cpp
Source/WebCore/bindings/js/JSPopStateEventCustom.cpp
Source/WebCore/bindings/js/JSTextTrackCueCustom.cpp
Source/WebCore/bindings/js/WebCoreTypedArrayController.cpp
Source/WebCore/bindings/js/WebCoreTypedArrayController.h
Source/WebCore/bindings/scripts/CodeGeneratorJS.pm
Source/WebCore/bindings/scripts/IDLAttributes.json
Source/WebCore/bindings/scripts/test/JS/JSInterfaceName.cpp
Source/WebCore/bindings/scripts/test/JS/JSInterfaceName.h
Source/WebCore/bindings/scripts/test/JS/JSMapLike.cpp
Source/WebCore/bindings/scripts/test/JS/JSMapLike.h
Source/WebCore/bindings/scripts/test/JS/JSReadOnlyMapLike.cpp
Source/WebCore/bindings/scripts/test/JS/JSReadOnlyMapLike.h
Source/WebCore/bindings/scripts/test/JS/JSTestActiveDOMObject.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestActiveDOMObject.h
Source/WebCore/bindings/scripts/test/JS/JSTestCEReactions.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestCEReactions.h
Source/WebCore/bindings/scripts/test/JS/JSTestCEReactionsStringifier.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestCEReactionsStringifier.h
Source/WebCore/bindings/scripts/test/JS/JSTestCallTracer.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestCallTracer.h
Source/WebCore/bindings/scripts/test/JS/JSTestClassWithJSBuiltinConstructor.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestClassWithJSBuiltinConstructor.h
Source/WebCore/bindings/scripts/test/JS/JSTestCustomConstructorWithNoInterfaceObject.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestCustomConstructorWithNoInterfaceObject.h
Source/WebCore/bindings/scripts/test/JS/JSTestDOMJIT.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestDOMJIT.h
Source/WebCore/bindings/scripts/test/JS/JSTestEnabledBySetting.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestEnabledBySetting.h
Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.h
Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.h
Source/WebCore/bindings/scripts/test/JS/JSTestException.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestException.h
Source/WebCore/bindings/scripts/test/JS/JSTestGenerateIsReachable.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestGenerateIsReachable.h
Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.h
Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterNoIdentifier.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterNoIdentifier.h
Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterThrowingException.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterThrowingException.h
Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterWithIdentifier.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterWithIdentifier.h
Source/WebCore/bindings/scripts/test/JS/JSTestInterface.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestInterface.h
Source/WebCore/bindings/scripts/test/JS/JSTestInterfaceLeadingUnderscore.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestInterfaceLeadingUnderscore.h
Source/WebCore/bindings/scripts/test/JS/JSTestIterable.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestIterable.h
Source/WebCore/bindings/scripts/test/JS/JSTestMediaQueryListListener.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestMediaQueryListListener.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterNoIdentifier.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterNoIdentifier.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterThrowingException.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterThrowingException.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterWithIdentifier.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterWithIdentifier.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedConstructor.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedConstructor.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterCallWith.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterCallWith.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterNoIdentifier.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterNoIdentifier.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterWithIdentifier.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterWithIdentifier.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterNoIdentifier.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterNoIdentifier.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterThrowingException.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterThrowingException.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIdentifier.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIdentifier.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetter.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetter.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetterAndSetter.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetterAndSetter.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithOverrideBuiltins.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithOverrideBuiltins.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgableProperties.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgableProperties.h
Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins.h
Source/WebCore/bindings/scripts/test/JS/JSTestNode.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestNode.h
Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestObj.h
Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructors.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructors.h
Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.h
Source/WebCore/bindings/scripts/test/JS/JSTestOverrideBuiltins.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestOverrideBuiltins.h
Source/WebCore/bindings/scripts/test/JS/JSTestPluginInterface.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestPluginInterface.h
Source/WebCore/bindings/scripts/test/JS/JSTestPromiseRejectionEvent.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestPromiseRejectionEvent.h
Source/WebCore/bindings/scripts/test/JS/JSTestSerialization.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestSerialization.h
Source/WebCore/bindings/scripts/test/JS/JSTestSerializationIndirectInheritance.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestSerializationIndirectInheritance.h
Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInherit.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInherit.h
Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInheritFinal.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInheritFinal.h
Source/WebCore/bindings/scripts/test/JS/JSTestSerializedScriptValueInterface.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestSerializedScriptValueInterface.h
Source/WebCore/bindings/scripts/test/JS/JSTestStringifier.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestStringifier.h
Source/WebCore/bindings/scripts/test/JS/JSTestStringifierAnonymousOperation.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestStringifierAnonymousOperation.h
Source/WebCore/bindings/scripts/test/JS/JSTestStringifierNamedOperation.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestStringifierNamedOperation.h
Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationImplementedAs.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationImplementedAs.h
Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationNamedToString.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationNamedToString.h
Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadOnlyAttribute.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadOnlyAttribute.h
Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadWriteAttribute.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadWriteAttribute.h
Source/WebCore/bindings/scripts/test/JS/JSTestTypedefs.cpp
Source/WebCore/bindings/scripts/test/JS/JSTestTypedefs.h
Source/WebCore/dom/Document.idl
Source/WebCore/page/DOMWindow.idl
Source/WebInspectorUI/ChangeLog
Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js
Tools/ChangeLog
Tools/GCHeapInspector/gc-heap-inspector.html [new file with mode: 0644]
Tools/GCHeapInspector/heap-analysis/HeapSnapshot.js [new file with mode: 0644]
Tools/GCHeapInspector/script/interface.js [new file with mode: 0644]

index 979ff9b..8a84bf7 100644 (file)
@@ -37,7 +37,7 @@
 class JSAPIWrapperObjectHandleOwner : public JSC::WeakHandleOwner {
 public:
     void finalize(JSC::Handle<JSC::Unknown>, void*) override;
-    bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&) override;
+    bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**) override;
 };
 
 static JSAPIWrapperObjectHandleOwner* jsAPIWrapperObjectHandleOwner()
@@ -56,7 +56,7 @@ void JSAPIWrapperObjectHandleOwner::finalize(JSC::Handle<JSC::Unknown> handle, v
     JSC::WeakSet::deallocate(JSC::WeakImpl::asWeakImpl(handle.slot()));
 }
 
-bool JSAPIWrapperObjectHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor)
+bool JSAPIWrapperObjectHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor, const char**)
 {
     JSC::JSAPIWrapperObject* wrapperObject = JSC::jsCast<JSC::JSAPIWrapperObject*>(handle.get().asCell());
     // We use the JSGlobalObject when processing weak handles to prevent the situation where using
index 29c717d..c545fad 100644 (file)
@@ -43,7 +43,7 @@
 class JSManagedValueHandleOwner : public JSC::WeakHandleOwner {
 public:
     void finalize(JSC::Handle<JSC::Unknown>, void* context) override;
-    bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&) override;
+    bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**) override;
 };
 
 static JSManagedValueHandleOwner& managedValueHandleOwner()
@@ -182,8 +182,10 @@ static JSManagedValueHandleOwner& managedValueHandleOwner()
 - (void)disconnectValue;
 @end
 
-bool JSManagedValueHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor& visitor)
+bool JSManagedValueHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor& visitor, const char** reason)
 {
+    if (UNLIKELY(reason))
+        *reason = "JSManagedValue is opaque root";
     JSManagedValue *managedValue = (__bridge JSManagedValue *)context;
     return visitor.containsOpaqueRoot((__bridge void*)managedValue);
 }
index 18dd13e..87d198c 100644 (file)
@@ -36,7 +36,7 @@
 class JSAPIWrapperObjectHandleOwner : public JSC::WeakHandleOwner {
 public:
     void finalize(JSC::Handle<JSC::Unknown>, void*) override;
-    bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&) override;
+    bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**) override;
 };
 
 static JSAPIWrapperObjectHandleOwner* jsAPIWrapperObjectHandleOwner()
@@ -55,7 +55,7 @@ void JSAPIWrapperObjectHandleOwner::finalize(JSC::Handle<JSC::Unknown> handle, v
     JSC::WeakSet::deallocate(JSC::WeakImpl::asWeakImpl(handle.slot()));
 }
 
-bool JSAPIWrapperObjectHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor)
+bool JSAPIWrapperObjectHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor, const char**)
 {
     JSC::JSAPIWrapperObject* wrapperObject = JSC::jsCast<JSC::JSAPIWrapperObject*>(handle.get().asCell());
     // We use the JSGlobalObject when processing weak handles to prevent the situation where using
index f610d72..fb1d0cc 100644 (file)
@@ -534,6 +534,7 @@ set(JavaScriptCore_PRIVATE_FRAMEWORK_HEADERS
     heap/HeapFinalizerCallback.h
     heap/HeapInlines.h
     heap/HeapObserver.h
+    heap/HeapSnapshotBuilder.h
     heap/IncrementalSweeper.h
     heap/IsoCellSet.h
     heap/IsoSubspace.h
index 5fa2c2a..4a26d37 100644 (file)
@@ -1,3 +1,77 @@
+2018-08-23  Simon Fraser  <simon.fraser@apple.com>
+
+        Add support for dumping GC heap snapshots, and a viewer
+        https://bugs.webkit.org/show_bug.cgi?id=186416
+
+        Reviewed by Joseph Pecoraro.
+
+        Make a way to dump information about the GC heap that is useful for looking for leaked
+        or abandoned objects. This dump is obtained (on Apple platforms) via:
+            notifyutil -p com.apple.WebKit.dumpGCHeap
+        which writes a JSON file to /tmp which can then be loaded into the viewer in Tools/GCHeapInspector.
+        
+        This leverages the heap snapshot used by Web Inspector, adding an alternate format for
+        the snapshot JSON that adds additional data about objects and why they are GC roots.
+
+        SlotVisitor maintains a RootMarkReason (via SetRootMarkReasonScope) that allows
+        the HeapSnapshotBuilder to keep track of why a JSCell was treated as a GC root. For
+        objects visited via opaque roots, we record the reason why via a new out param to
+        isReachableFromOpaqueRoots().
+
+        HeapSnapshotBuilder is enhanced to produce GCDebuggingSnapshot JSON output. This contains
+        additional information including the address of the JSCell* and the wrapped object (for
+        JSDOMWrappers), the root reasons, and for some objects like JSDocument a label which can
+        be the document URL.
+
+        GCDebuggingSnapshots are always full snapshots (previous snapshots are not kept around).
+
+        * API/JSAPIWrapperObject.mm:
+        (JSAPIWrapperObjectHandleOwner::isReachableFromOpaqueRoots):
+        * API/JSManagedValue.mm:
+        (JSManagedValueHandleOwner::isReachableFromOpaqueRoots):
+        * API/glib/JSAPIWrapperObjectGLib.cpp:
+        (JSAPIWrapperObjectHandleOwner::isReachableFromOpaqueRoots):
+        * CMakeLists.txt:
+        * heap/ConservativeRoots.h:
+        (JSC::ConservativeRoots::size const):
+        (JSC::ConservativeRoots::size): Deleted.
+        * heap/Heap.cpp:
+        (JSC::Heap::addCoreConstraints):
+        * heap/HeapSnapshotBuilder.cpp:
+        (JSC::HeapSnapshotBuilder::getNextObjectIdentifier):
+        (JSC::HeapSnapshotBuilder::HeapSnapshotBuilder):
+        (JSC::HeapSnapshotBuilder::~HeapSnapshotBuilder):
+        (JSC::HeapSnapshotBuilder::buildSnapshot):
+        (JSC::HeapSnapshotBuilder::appendNode):
+        (JSC::HeapSnapshotBuilder::appendEdge):
+        (JSC::HeapSnapshotBuilder::setOpaqueRootReachabilityReasonForCell):
+        (JSC::HeapSnapshotBuilder::setWrappedObjectForCell):
+        (JSC::HeapSnapshotBuilder::previousSnapshotHasNodeForCell):
+        (JSC::snapshotTypeToString):
+        (JSC::rootTypeToString):
+        (JSC::HeapSnapshotBuilder::setLabelForCell):
+        (JSC::HeapSnapshotBuilder::descriptionForCell const):
+        (JSC::HeapSnapshotBuilder::json):
+        (JSC::HeapSnapshotBuilder::hasExistingNodeForCell): Deleted.
+        * heap/HeapSnapshotBuilder.h:
+        * heap/SlotVisitor.cpp:
+        (JSC::SlotVisitor::appendSlow):
+        * heap/SlotVisitor.h:
+        (JSC::SlotVisitor::heapSnapshotBuilder const):
+        (JSC::SlotVisitor::rootMarkReason const):
+        (JSC::SlotVisitor::setRootMarkReason):
+        (JSC::SetRootMarkReasonScope::SetRootMarkReasonScope):
+        (JSC::SetRootMarkReasonScope::~SetRootMarkReasonScope):
+        * heap/WeakBlock.cpp:
+        (JSC::WeakBlock::specializedVisit):
+        * heap/WeakHandleOwner.cpp:
+        (JSC::WeakHandleOwner::isReachableFromOpaqueRoots):
+        * heap/WeakHandleOwner.h:
+        * runtime/SimpleTypedArrayController.cpp:
+        (JSC::SimpleTypedArrayController::JSArrayBufferOwner::isReachableFromOpaqueRoots):
+        * runtime/SimpleTypedArrayController.h:
+        * tools/JSDollarVM.cpp:
+
 2018-08-23  Saam barati  <sbarati@apple.com>
 
         JSRunLoopTimer may run part of a member function after it's destroyed
index 0f9a42a..83e5ce4 100644 (file)
@@ -41,7 +41,7 @@ public:
     void add(void* begin, void* end);
     void add(void* begin, void* end, JITStubRoutineSet&, CodeBlockSet&);
     
-    size_t size();
+    size_t size() const;
     HeapCell** roots();
 
 private:
@@ -63,7 +63,7 @@ private:
     HeapCell* m_inlineRoots[inlineCapacity];
 };
 
-inline size_t ConservativeRoots::size()
+inline size_t ConservativeRoots::size() const
 {
     return m_size;
 }
index f84f7e6..7a46a52 100644 (file)
@@ -2641,11 +2641,15 @@ void Heap::addCoreConstraints()
             
             TimingScope preConvergenceTimingScope(*this, "Constraint: conservative scan");
             m_objectSpace.prepareForConservativeScan();
+
             ConservativeRoots conservativeRoots(*this);
             SuperSamplerScope superSamplerScope(false);
+
             gatherStackRoots(conservativeRoots);
             gatherJSStackRoots(conservativeRoots);
             gatherScratchBufferRoots(conservativeRoots);
+
+            SetRootMarkReasonScope rootScope(slotVisitor, SlotVisitor::RootMarkReason::ConservativeScan);
             slotVisitor.append(conservativeRoots);
             
             lastVersion = m_phaseVersion;
@@ -2655,27 +2659,38 @@ void Heap::addCoreConstraints()
     m_constraintSet->add(
         "Msr", "Misc Small Roots",
         [this] (SlotVisitor& slotVisitor) {
+
 #if JSC_OBJC_API_ENABLED
             scanExternalRememberedSet(*m_vm, slotVisitor);
 #endif
-
-            if (m_vm->smallStrings.needsToBeVisited(*m_collectionScope))
+            if (m_vm->smallStrings.needsToBeVisited(*m_collectionScope)) {
+                SetRootMarkReasonScope rootScope(slotVisitor, SlotVisitor::RootMarkReason::StrongReferences);
                 m_vm->smallStrings.visitStrongReferences(slotVisitor);
+            }
             
-            for (auto& pair : m_protectedValues)
-                slotVisitor.appendUnbarriered(pair.key);
+            {
+                SetRootMarkReasonScope rootScope(slotVisitor, SlotVisitor::RootMarkReason::ProtectedValues);
+                for (auto& pair : m_protectedValues)
+                    slotVisitor.appendUnbarriered(pair.key);
+            }
             
-            if (m_markListSet && m_markListSet->size())
+            if (m_markListSet && m_markListSet->size()) {
+                SetRootMarkReasonScope rootScope(slotVisitor, SlotVisitor::RootMarkReason::ConservativeScan);
                 MarkedArgumentBuffer::markLists(slotVisitor, *m_markListSet);
-            
-            slotVisitor.appendUnbarriered(m_vm->exception());
-            slotVisitor.appendUnbarriered(m_vm->lastException());
+            }
+
+            {
+                SetRootMarkReasonScope rootScope(slotVisitor, SlotVisitor::RootMarkReason::VMExceptions);
+                slotVisitor.appendUnbarriered(m_vm->exception());
+                slotVisitor.appendUnbarriered(m_vm->lastException());
+            }
         },
         ConstraintVolatility::GreyedByExecution);
     
     m_constraintSet->add(
         "Sh", "Strong Handles",
         [this] (SlotVisitor& slotVisitor) {
+            SetRootMarkReasonScope rootScope(slotVisitor, SlotVisitor::RootMarkReason::StrongHandles);
             m_handleSet.visitStrongHandles(slotVisitor);
         },
         ConstraintVolatility::GreyedByExecution);
@@ -2683,6 +2698,8 @@ void Heap::addCoreConstraints()
     m_constraintSet->add(
         "D", "Debugger",
         [this] (SlotVisitor& slotVisitor) {
+            SetRootMarkReasonScope rootScope(slotVisitor, SlotVisitor::RootMarkReason::Debugger);
+
 #if ENABLE(SAMPLING_PROFILER)
             if (SamplingProfiler* samplingProfiler = m_vm->samplingProfiler()) {
                 LockHolder locker(samplingProfiler->getLock());
@@ -2692,7 +2709,7 @@ void Heap::addCoreConstraints()
                     dataLog("Sampling Profiler data:\n", slotVisitor);
             }
 #endif // ENABLE(SAMPLING_PROFILER)
-            
+
             if (m_vm->typeProfiler())
                 m_vm->typeProfilerLog()->visit(slotVisitor);
             
@@ -2703,6 +2720,7 @@ void Heap::addCoreConstraints()
     m_constraintSet->add(
         "Jsr", "JIT Stub Routines",
         [this] (SlotVisitor& slotVisitor) {
+            SetRootMarkReasonScope rootScope(slotVisitor, SlotVisitor::RootMarkReason::JITStubRoutines);
             m_jitStubRoutines->traceMarkedStubRoutines(slotVisitor);
         },
         ConstraintVolatility::GreyedByExecution);
@@ -2710,6 +2728,7 @@ void Heap::addCoreConstraints()
     m_constraintSet->add(
         "Ws", "Weak Sets",
         [this] (SlotVisitor& slotVisitor) {
+            SetRootMarkReasonScope rootScope(slotVisitor, SlotVisitor::RootMarkReason::WeakSets);
             m_objectSpace.visitWeakSets(slotVisitor);
         },
         ConstraintVolatility::GreyedByMarking);
@@ -2718,8 +2737,9 @@ void Heap::addCoreConstraints()
         "O", "Output",
         [] (SlotVisitor& slotVisitor) {
             VM& vm = slotVisitor.vm();
-            
+
             auto callOutputConstraint = [] (SlotVisitor& slotVisitor, HeapCell* heapCell, HeapCell::Kind) {
+                SetRootMarkReasonScope rootScope(slotVisitor, SlotVisitor::RootMarkReason::Output);
                 VM& vm = slotVisitor.vm();
                 JSCell* cell = static_cast<JSCell*>(heapCell);
                 cell->methodTable(vm)->visitOutputConstraints(cell, slotVisitor);
@@ -2739,6 +2759,8 @@ void Heap::addCoreConstraints()
     m_constraintSet->add(
         "Dw", "DFG Worklists",
         [this] (SlotVisitor& slotVisitor) {
+            SetRootMarkReasonScope rootScope(slotVisitor, SlotVisitor::RootMarkReason::DFGWorkLists);
+
             for (unsigned i = DFG::numberOfWorklists(); i--;)
                 DFG::existingWorklistForIndex(i).visitWeakReferences(slotVisitor);
             
@@ -2759,6 +2781,7 @@ void Heap::addCoreConstraints()
     m_constraintSet->add(
         "Cb", "CodeBlocks",
         [this] (SlotVisitor& slotVisitor) {
+            SetRootMarkReasonScope rootScope(slotVisitor, SlotVisitor::RootMarkReason::CodeBlocks);
             iterateExecutingAndCompilingCodeBlocksWithoutHoldingLocks(
                 [&] (CodeBlock* codeBlock) {
                     // Visit the CodeBlock as a constraint only if it's black.
index 624935a..303a1f7 100644 (file)
 #include <wtf/text/StringBuilder.h>
 
 namespace JSC {
-    
-unsigned HeapSnapshotBuilder::nextAvailableObjectIdentifier = 1;
-unsigned HeapSnapshotBuilder::getNextObjectIdentifier() { return nextAvailableObjectIdentifier++; }
+
+static const char* rootTypeToString(SlotVisitor::RootMarkReason);
+
+NodeIdentifier HeapSnapshotBuilder::nextAvailableObjectIdentifier = 1;
+NodeIdentifier HeapSnapshotBuilder::getNextObjectIdentifier() { return nextAvailableObjectIdentifier++; }
 void HeapSnapshotBuilder::resetNextAvailableObjectIdentifier() { HeapSnapshotBuilder::nextAvailableObjectIdentifier = 1; }
 
-HeapSnapshotBuilder::HeapSnapshotBuilder(HeapProfiler& profiler)
+HeapSnapshotBuilder::HeapSnapshotBuilder(HeapProfiler& profiler, SnapshotType type)
     : m_profiler(profiler)
+    , m_snapshotType(type)
 {
 }
 
 HeapSnapshotBuilder::~HeapSnapshotBuilder()
 {
+    if (m_snapshotType == SnapshotType::GCDebuggingSnapshot)
+        m_profiler.clearSnapshots();
 }
 
 void HeapSnapshotBuilder::buildSnapshot()
 {
+    // GCDebuggingSnapshot are always full snapshots, so clear any existing snapshots.
+    if (m_snapshotType == SnapshotType::GCDebuggingSnapshot)
+        m_profiler.clearSnapshots();
+
     PreventCollectionScope preventCollectionScope(m_profiler.vm().heap);
-    
+
     m_snapshot = std::make_unique<HeapSnapshot>(m_profiler.mostRecentSnapshot());
     {
         m_profiler.setActiveSnapshotBuilder(this);
@@ -69,17 +78,18 @@ void HeapSnapshotBuilder::buildSnapshot()
 void HeapSnapshotBuilder::appendNode(JSCell* cell)
 {
     ASSERT(m_profiler.activeSnapshotBuilder() == this);
+    
     ASSERT(Heap::isMarked(cell));
 
-    if (hasExistingNodeForCell(cell))
+    NodeIdentifier identifier;
+    if (previousSnapshotHasNodeForCell(cell, identifier))
         return;
 
     std::lock_guard<Lock> lock(m_buildingNodeMutex);
-
     m_snapshot->appendNode(HeapSnapshotNode(cell, getNextObjectIdentifier()));
 }
 
-void HeapSnapshotBuilder::appendEdge(JSCell* from, JSCell* to)
+void HeapSnapshotBuilder::appendEdge(JSCell* from, JSCell* to, SlotVisitor::RootMarkReason rootMarkReason)
 {
     ASSERT(m_profiler.activeSnapshotBuilder() == this);
     ASSERT(to);
@@ -90,6 +100,15 @@ void HeapSnapshotBuilder::appendEdge(JSCell* from, JSCell* to)
 
     std::lock_guard<Lock> lock(m_buildingEdgeMutex);
 
+    if (m_snapshotType == SnapshotType::GCDebuggingSnapshot && !from) {
+        if (rootMarkReason == SlotVisitor::RootMarkReason::None && m_snapshotType == SnapshotType::GCDebuggingSnapshot)
+            WTFLogAlways("Cell %p is a root but no root marking reason was supplied", to);
+
+        m_rootData.ensure(to, [] () -> RootData {
+            return { };
+        }).iterator->value.markReason = rootMarkReason;
+    }
+
     m_edges.append(HeapSnapshotEdge(from, to));
 }
 
@@ -123,22 +142,46 @@ void HeapSnapshotBuilder::appendIndexEdge(JSCell* from, JSCell* to, uint32_t ind
     m_edges.append(HeapSnapshotEdge(from, to, index));
 }
 
-bool HeapSnapshotBuilder::hasExistingNodeForCell(JSCell* cell)
+void HeapSnapshotBuilder::setOpaqueRootReachabilityReasonForCell(JSCell* cell, const char* reason)
+{
+    if (!reason || !*reason || m_snapshotType != SnapshotType::GCDebuggingSnapshot)
+        return;
+
+    m_rootData.ensure(cell, [] () -> RootData {
+        return { };
+    }).iterator->value.reachabilityFromOpaqueRootReasons = reason;
+}
+
+void HeapSnapshotBuilder::setWrappedObjectForCell(JSCell* cell, void* wrappedPtr)
+{
+    m_wrappedObjectPointers.set(cell, wrappedPtr);
+}
+
+bool HeapSnapshotBuilder::previousSnapshotHasNodeForCell(JSCell* cell, NodeIdentifier& identifier)
 {
     if (!m_snapshot->previous())
         return false;
 
-    return !!m_snapshot->previous()->nodeForCell(cell);
-}
+    auto existingNode = m_snapshot->previous()->nodeForCell(cell);
+    if (existingNode) {
+        identifier = existingNode.value().identifier;
+        return true;
+    }
 
+    return false;
+}
 
 // Heap Snapshot JSON Format:
 //
+//  Inspector snapshots:
+//
 //   {
 //      "version": 1.0,
+//      "type": "Inspector",
+//      // [<address>, <labelIndex>, <wrappedEddress>] only present in GCDebuggingSnapshot-type snapshots
 //      "nodes": [
-//          <nodeId>, <sizeInBytes>, <nodeClassNameIndex>, <internal>,
-//          <nodeId>, <sizeInBytes>, <nodeClassNameIndex>, <internal>,
+//          <nodeId>, <sizeInBytes>, <nodeClassNameIndex>, <internal>
+//          <nodeId>, <sizeInBytes>, <nodeClassNameIndex>, <internal>
 //          ...
 //      ],
 //      "nodeClassNames": [
@@ -157,6 +200,40 @@ bool HeapSnapshotBuilder::hasExistingNodeForCell(JSCell* cell)
 //      ]
 //   }
 //
+//  GC heap debugger snapshots:
+//
+//   {
+//      "version": 1.0,
+//      "type": "GCDebugging",
+//      "nodes": [
+//          <nodeId>, <sizeInBytes>, <nodeClassNameIndex>, <internal>, <labelIndex>, <cellEddress>, <wrappedEddress>,
+//          <nodeId>, <sizeInBytes>, <nodeClassNameIndex>, <internal>, <labelIndex>, <cellEddress>, <wrappedEddress>,
+//          ...
+//      ],
+//      "nodeClassNames": [
+//          "string", "Structure", "Object", ...
+//      ],
+//      "edges": [
+//          <fromNodeId>, <toNodeId>, <edgeTypeIndex>, <edgeExtraData>,
+//          <fromNodeId>, <toNodeId>, <edgeTypeIndex>, <edgeExtraData>,
+//          ...
+//      ],
+//      "edgeTypes": [
+//          "Internal", "Property", "Index", "Variable"
+//      ],
+//      "edgeNames": [
+//          "propertyName", "variableName", ...
+//      ],
+//      "roots" : [
+//          <nodeId>, <rootReasonIndex>, <reachabilityReasonIndex>,
+//          <nodeId>, <rootReasonIndex>, <reachabilityReasonIndex>,
+//          ... // <nodeId> may be repeated
+//      ],
+//      "labels" : [
+//          "foo", "bar", ...
+//      ]
+//   }
+//
 // Notes:
 //
 //     <nodeClassNameIndex>
@@ -172,6 +249,9 @@ bool HeapSnapshotBuilder::hasExistingNodeForCell(JSCell* cell)
 //       - for Internal edges this should be ignored (0).
 //       - for Index edges this is the index value.
 //       - for Property or Variable edges this is an index into the "edgeNames" list.
+//
+//      <rootReasonIndex>
+//       - index into the "labels" list.
 
 static uint8_t edgeTypeToNumber(EdgeType type)
 {
@@ -194,24 +274,98 @@ static const char* edgeTypeToString(EdgeType type)
     return "Internal";
 }
 
+static const char* snapshotTypeToString(HeapSnapshotBuilder::SnapshotType type)
+{
+    switch (type) {
+    case HeapSnapshotBuilder::SnapshotType::InspectorSnapshot:
+        return "Inspector";
+    case HeapSnapshotBuilder::SnapshotType::GCDebuggingSnapshot:
+        return "GCDebugging";
+    }
+    ASSERT_NOT_REACHED();
+    return "Inspector";
+}
+
+static const char* rootTypeToString(SlotVisitor::RootMarkReason type)
+{
+    switch (type) {
+    case SlotVisitor::RootMarkReason::None:
+        return "None";
+    case SlotVisitor::RootMarkReason::ConservativeScan:
+        return "Conservative scan";
+    case SlotVisitor::RootMarkReason::StrongReferences:
+        return "Strong references";
+    case SlotVisitor::RootMarkReason::ProtectedValues:
+        return "Protected values";
+    case SlotVisitor::RootMarkReason::MarkListSet:
+        return "Mark list set";
+    case SlotVisitor::RootMarkReason::VMExceptions:
+        return "VM exceptions";
+    case SlotVisitor::RootMarkReason::StrongHandles:
+        return "Strong handles";
+    case SlotVisitor::RootMarkReason::Debugger:
+        return "Debugger";
+    case SlotVisitor::RootMarkReason::JITStubRoutines:
+        return "JIT stub routines";
+    case SlotVisitor::RootMarkReason::WeakSets:
+        return "Weak sets";
+    case SlotVisitor::RootMarkReason::Output:
+        return "Output";
+    case SlotVisitor::RootMarkReason::DFGWorkLists:
+        return "DFG work lists";
+    case SlotVisitor::RootMarkReason::CodeBlocks:
+        return "Code blocks";
+    case SlotVisitor::RootMarkReason::DOMGCOutput:
+        return "DOM GC output";
+    }
+    ASSERT_NOT_REACHED();
+    return "None";
+}
+
 String HeapSnapshotBuilder::json()
 {
     return json([] (const HeapSnapshotNode&) { return true; });
 }
 
+void HeapSnapshotBuilder::setLabelForCell(JSCell* cell, const String& label)
+{
+    m_cellLabels.set(cell, label);
+}
+
+String HeapSnapshotBuilder::descriptionForCell(JSCell *cell) const
+{
+    if (cell->isString())
+        return emptyString(); // FIXME: get part of string.
+
+    VM& vm = m_profiler.vm();
+    Structure* structure = cell->structure(vm);
+
+    if (structure->classInfo()->isSubClassOf(Structure::info())) {
+        Structure* cellAsStructure = jsCast<Structure*>(cell);
+        return cellAsStructure->classInfo()->className;
+    }
+
+    return emptyString();
+}
+
 String HeapSnapshotBuilder::json(Function<bool (const HeapSnapshotNode&)> allowNodeCallback)
 {
     VM& vm = m_profiler.vm();
     DeferGCForAWhile deferGC(vm.heap);
 
     // Build a node to identifier map of allowed nodes to use when serializing edges.
-    HashMap<JSCell*, unsigned> allowedNodeIdentifiers;
+    HashMap<JSCell*, NodeIdentifier> allowedNodeIdentifiers;
 
     // Build a list of used class names.
     HashMap<const char*, unsigned> classNameIndexes;
     classNameIndexes.set("<root>", 0);
     unsigned nextClassNameIndex = 1;
 
+    // Build a list of labels (this is just a string table).
+    HashMap<String, unsigned> labelIndexes;
+    labelIndexes.set(emptyString(), 0);
+    unsigned nextLabelIndex = 1;
+
     // Build a list of used edge names.
     HashMap<UniquedStringImpl*, unsigned> edgeNameIndexes;
     unsigned nextEdgeNameIndex = 0;
@@ -231,12 +385,44 @@ String HeapSnapshotBuilder::json(Function<bool (const HeapSnapshotNode&)> allowN
         unsigned classNameIndex = result.iterator->value;
 
         bool isInternal = false;
+        void* wrappedAddress = 0;
+        unsigned labelIndex = 0;
         if (!node.cell->isString()) {
             Structure* structure = node.cell->structure(vm);
             isInternal = !structure || !structure->globalObject();
+
+            if (m_snapshotType == SnapshotType::GCDebuggingSnapshot) {
+                String nodeLabel;
+                auto it = m_cellLabels.find(node.cell);
+                if (it != m_cellLabels.end())
+                    nodeLabel = it->value;
+
+                if (nodeLabel.isEmpty()) {
+                    if (auto* object = jsDynamicCast<JSObject*>(vm, node.cell)) {
+                        if (auto* function = jsDynamicCast<JSFunction*>(vm, object))
+                            nodeLabel = function->calculatedDisplayName(vm);
+                    }
+                }
+                
+                String description = descriptionForCell(node.cell);
+                if (description.length()) {
+                    if (nodeLabel.length())
+                        nodeLabel.append(' ');
+                    nodeLabel.append(description);
+                }
+
+                if (!nodeLabel.isEmpty() && m_snapshotType == SnapshotType::GCDebuggingSnapshot) {
+                    auto result = labelIndexes.add(nodeLabel, nextLabelIndex);
+                    if (result.isNewEntry)
+                        nextLabelIndex++;
+                    labelIndex = result.iterator->value;
+                }
+                
+                wrappedAddress = m_wrappedObjectPointers.get(node.cell);
+            }
         }
 
-        // <nodeId>, <sizeInBytes>, <className>, <optionalInternalBoolean>
+        // <nodeId>, <sizeInBytes>, <nodeClassNameIndex>, <internal>, [<labelIndex>, <cellEddress>, <wrappedEddress>]
         json.append(',');
         json.appendNumber(node.identifier);
         json.append(',');
@@ -245,6 +431,14 @@ String HeapSnapshotBuilder::json(Function<bool (const HeapSnapshotNode&)> allowN
         json.appendNumber(classNameIndex);
         json.append(',');
         json.append(isInternal ? '1' : '0');
+        if (m_snapshotType == SnapshotType::GCDebuggingSnapshot) {
+            json.append(',');
+            json.appendNumber(labelIndex);
+            json.append(',');
+            json.append(String::format("\"%p\"", node.cell)); // FIXME: Should add StringBuilder::appendAddress(void*).
+            json.append(',');
+            json.append(String::format("\"%p\"", wrappedAddress));
+        }
     };
 
     bool firstEdge = true;
@@ -285,11 +479,21 @@ String HeapSnapshotBuilder::json(Function<bool (const HeapSnapshotNode&)> allowN
     // version
     json.appendLiteral("\"version\":1");
 
+    // type
+    json.append(',');
+    json.appendLiteral("\"type\":");
+    json.appendQuotedJSONString(snapshotTypeToString(m_snapshotType));
+
     // nodes
     json.append(',');
     json.appendLiteral("\"nodes\":");
     json.append('[');
-    json.appendLiteral("0,0,0,0"); // <root>
+    // <root>
+    if (m_snapshotType == SnapshotType::GCDebuggingSnapshot)
+        json.appendLiteral("0,0,0,0,0,\"0x0\",\"0x0\"");
+    else
+        json.appendLiteral("0,0,0,0");
+
     for (HeapSnapshot* snapshot = m_profiler.mostRecentSnapshot(); snapshot; snapshot = snapshot->previous()) {
         for (auto& node : snapshot->m_nodes)
             appendNodeJSON(node);
@@ -323,8 +527,11 @@ String HeapSnapshotBuilder::json(Function<bool (const HeapSnapshotNode&)> allowN
             edge.from.identifier = 0;
         else {
             auto fromLookup = allowedNodeIdentifiers.find(edge.from.cell);
-            if (fromLookup == allowedNodeIdentifiers.end())
+            if (fromLookup == allowedNodeIdentifiers.end()) {
+                if (m_snapshotType == SnapshotType::GCDebuggingSnapshot)
+                    WTFLogAlways("Failed to find node for from-edge cell %p", edge.from.cell);
                 return true;
+            }
             edge.from.identifier = fromLookup->value;
         }
 
@@ -332,13 +539,17 @@ String HeapSnapshotBuilder::json(Function<bool (const HeapSnapshotNode&)> allowN
             edge.to.identifier = 0;
         else {
             auto toLookup = allowedNodeIdentifiers.find(edge.to.cell);
-            if (toLookup == allowedNodeIdentifiers.end())
+            if (toLookup == allowedNodeIdentifiers.end()) {
+                if (m_snapshotType == SnapshotType::GCDebuggingSnapshot)
+                    WTFLogAlways("Failed to find node for to-edge cell %p", edge.to.cell);
                 return true;
+            }
             edge.to.identifier = toLookup->value;
         }
 
         return false;
     });
+
     allowedNodeIdentifiers.clear();
     m_edges.shrinkToFit();
 
@@ -386,6 +597,73 @@ String HeapSnapshotBuilder::json(Function<bool (const HeapSnapshotNode&)> allowN
     orderedEdgeNames.clear();
     json.append(']');
 
+    if (m_snapshotType == SnapshotType::GCDebuggingSnapshot) {
+        json.append(',');
+        json.appendLiteral("\"roots\":");
+        json.append('[');
+        
+        HeapSnapshot* snapshot = m_profiler.mostRecentSnapshot();
+
+        bool firstNode = true;
+        for (auto it : m_rootData) {
+            auto snapshotNode = snapshot->nodeForCell(it.key);
+            if (!snapshotNode) {
+                WTFLogAlways("Failed to find snapshot node for cell %p", it.key);
+                continue;
+            }
+
+            if (!firstNode)
+                json.append(',');
+
+            firstNode = false;
+            json.appendNumber(snapshotNode.value().identifier);
+            
+            // Maybe we should just always encode the root names.
+            const char* rootName = rootTypeToString(it.value.markReason);
+            auto result = labelIndexes.add(rootName, nextLabelIndex);
+            if (result.isNewEntry)
+                nextLabelIndex++;
+            unsigned labelIndex = result.iterator->value;
+            json.append(',');
+            json.appendNumber(labelIndex);
+
+            unsigned reachabilityReasonIndex = 0;
+            if (it.value.reachabilityFromOpaqueRootReasons) {
+                auto result = labelIndexes.add(it.value.reachabilityFromOpaqueRootReasons, nextLabelIndex);
+                if (result.isNewEntry)
+                    nextLabelIndex++;
+                reachabilityReasonIndex = result.iterator->value;
+            }
+            json.append(',');
+            json.appendNumber(reachabilityReasonIndex);
+        }
+
+        json.append(']');
+    }
+
+    if (m_snapshotType == SnapshotType::GCDebuggingSnapshot) {
+        // internal node descriptions
+        json.append(',');
+        json.appendLiteral("\"labels\":");
+        json.append('[');
+
+        Vector<String> orderedLabels(labelIndexes.size());
+        for (auto& entry : labelIndexes)
+            orderedLabels[entry.value] = entry.key;
+        labelIndexes.clear();
+        bool firstLabel = true;
+        for (auto& label : orderedLabels) {
+            if (!firstLabel)
+                json.append(',');
+
+            firstLabel = false;
+            json.appendQuotedJSONString(label);
+        }
+        orderedLabels.clear();
+
+        json.append(']');
+    }
+
     json.append('}');
     return json.toString();
 }
index ae7f0bd..d698692 100644 (file)
@@ -25,6 +25,7 @@
 
 #pragma once
 
+#include "SlotVisitor.h"
 #include <functional>
 #include <wtf/Lock.h>
 #include <wtf/Vector.h>
 
 namespace JSC {
 
+class ConservativeRoots;
 class HeapProfiler;
 class HeapSnapshot;
 class JSCell;
 
+typedef unsigned NodeIdentifier;
+
 struct HeapSnapshotNode {
     HeapSnapshotNode(JSCell* cell, unsigned identifier)
         : cell(cell)
@@ -44,7 +48,7 @@ struct HeapSnapshotNode {
     { }
 
     JSCell* cell;
-    unsigned identifier;
+    NodeIdentifier identifier;
 };
 
 enum class EdgeType : uint8_t {
@@ -82,12 +86,12 @@ struct HeapSnapshotEdge {
 
     union {
         JSCell *cell;
-        unsigned identifier;
+        NodeIdentifier identifier;
     } from;
 
     union {
         JSCell *cell;
-        unsigned identifier;
+        NodeIdentifier identifier;
     } to;
 
     union {
@@ -101,33 +105,47 @@ struct HeapSnapshotEdge {
 class JS_EXPORT_PRIVATE HeapSnapshotBuilder {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    HeapSnapshotBuilder(HeapProfiler&);
+    enum SnapshotType { InspectorSnapshot, GCDebuggingSnapshot };
+
+    HeapSnapshotBuilder(HeapProfiler&, SnapshotType = SnapshotType::InspectorSnapshot);
     ~HeapSnapshotBuilder();
 
-    static unsigned nextAvailableObjectIdentifier;
-    static unsigned getNextObjectIdentifier();
     static void resetNextAvailableObjectIdentifier();
 
     // Performs a garbage collection that builds a snapshot of all live cells.
     void buildSnapshot();
 
-    // A marked cell.
+    // A root or marked cell.
     void appendNode(JSCell*);
 
     // A reference from one cell to another.
-    void appendEdge(JSCell* from, JSCell* to);
+    void appendEdge(JSCell* from, JSCell* to, SlotVisitor::RootMarkReason);
     void appendPropertyNameEdge(JSCell* from, JSCell* to, UniquedStringImpl* propertyName);
     void appendVariableNameEdge(JSCell* from, JSCell* to, UniquedStringImpl* variableName);
     void appendIndexEdge(JSCell* from, JSCell* to, uint32_t index);
 
+    void setOpaqueRootReachabilityReasonForCell(JSCell*, const char*);
+    void setWrappedObjectForCell(JSCell*, void*);
+    void setLabelForCell(JSCell*, const String&);
+
     String json();
     String json(Function<bool (const HeapSnapshotNode&)> allowNodeCallback);
 
 private:
+    static NodeIdentifier nextAvailableObjectIdentifier;
+    static NodeIdentifier getNextObjectIdentifier();
+
     // Finalized snapshots are not modified during building. So searching them
     // for an existing node can be done concurrently without a lock.
-    bool hasExistingNodeForCell(JSCell*);
-
+    bool previousSnapshotHasNodeForCell(JSCell*, NodeIdentifier&);
+    
+    String descriptionForCell(JSCell*) const;
+    
+    struct RootData {
+        const char* reachabilityFromOpaqueRootReasons { nullptr };
+        SlotVisitor::RootMarkReason markReason { SlotVisitor::RootMarkReason::None };
+    };
+    
     HeapProfiler& m_profiler;
 
     // SlotVisitors run in parallel.
@@ -135,6 +153,10 @@ private:
     std::unique_ptr<HeapSnapshot> m_snapshot;
     Lock m_buildingEdgeMutex;
     Vector<HeapSnapshotEdge> m_edges;
+    HashMap<JSCell*, RootData> m_rootData;
+    HashMap<JSCell*, void*> m_wrappedObjectPointers;
+    HashMap<JSCell*, String> m_cellLabels;
+    SnapshotType m_snapshotType;
 };
 
 } // namespace JSC
index e737f39..33c37fc 100644 (file)
@@ -225,7 +225,7 @@ void SlotVisitor::appendJSCellOrAuxiliary(HeapCell* heapCell)
 void SlotVisitor::appendSlow(JSCell* cell, Dependency dependency)
 {
     if (UNLIKELY(m_heapSnapshotBuilder))
-        m_heapSnapshotBuilder->appendEdge(m_currentCell, cell);
+        m_heapSnapshotBuilder->appendEdge(m_currentCell, cell, m_rootMarkReason);
     
     appendHiddenSlowImpl(cell, dependency);
 }
index e8a2774..ee590ef 100644 (file)
@@ -57,6 +57,23 @@ class SlotVisitor {
     friend class Heap;
 
 public:
+    enum RootMarkReason {
+        None,
+        ConservativeScan,
+        StrongReferences,
+        ProtectedValues,
+        MarkListSet,
+        VMExceptions,
+        StrongHandles,
+        Debugger,
+        JITStubRoutines,
+        WeakSets,
+        Output,
+        DFGWorkLists,
+        CodeBlocks,
+        DOMGCOutput,
+    };
+
     SlotVisitor(Heap&, CString codeName);
     ~SlotVisitor();
 
@@ -142,7 +159,11 @@ public:
     void dump(PrintStream&) const;
 
     bool isBuildingHeapSnapshot() const { return !!m_heapSnapshotBuilder; }
+    HeapSnapshotBuilder* heapSnapshotBuilder() const { return m_heapSnapshotBuilder; }
     
+    RootMarkReason rootMarkReason() const { return m_rootMarkReason; }
+    void setRootMarkReason(RootMarkReason reason) { m_rootMarkReason = reason; }
+
     HeapVersion markingVersion() const { return m_markingVersion; }
 
     bool mutatorIsStopped() const { return m_mutatorIsStopped; }
@@ -224,6 +245,7 @@ private:
 
     HeapSnapshotBuilder* m_heapSnapshotBuilder { nullptr };
     JSCell* m_currentCell { nullptr };
+    RootMarkReason m_rootMarkReason { RootMarkReason::None };
     bool m_isFirstVisit { false };
     bool m_mutatorIsStopped { false };
     bool m_canOptimizeForStoppedMutator { false };
@@ -262,4 +284,23 @@ private:
     SlotVisitor& m_stack;
 };
 
+class SetRootMarkReasonScope {
+public:
+    SetRootMarkReasonScope(SlotVisitor& visitor, SlotVisitor::RootMarkReason reason)
+        : m_visitor(visitor)
+        , m_previousReason(visitor.rootMarkReason())
+    {
+        m_visitor.setRootMarkReason(reason);
+    }
+
+    ~SetRootMarkReasonScope()
+    {
+        m_visitor.setRootMarkReason(m_previousReason);
+    }
+
+private:
+    SlotVisitor& m_visitor;
+    SlotVisitor::RootMarkReason m_previousReason;
+};
+
 } // namespace JSC
index f328f96..323ce6f 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "CellContainerInlines.h"
 #include "Heap.h"
+#include "HeapSnapshotBuilder.h"
 #include "JSCInlines.h"
 #include "JSObject.h"
 #include "WeakHandleOwner.h"
@@ -114,10 +115,20 @@ void WeakBlock::specializedVisit(ContainerType& container, SlotVisitor& visitor)
         if (container.isMarked(markingVersion, jsValue.asCell()))
             continue;
         
-        if (!weakHandleOwner->isReachableFromOpaqueRoots(Handle<Unknown>::wrapSlot(&const_cast<JSValue&>(jsValue)), weakImpl->context(), visitor))
+        const char* reason = "";
+        const char** reasonPtr = nullptr;
+        if (UNLIKELY(visitor.isBuildingHeapSnapshot()))
+            reasonPtr = &reason;
+
+        if (!weakHandleOwner->isReachableFromOpaqueRoots(Handle<Unknown>::wrapSlot(&const_cast<JSValue&>(jsValue)), weakImpl->context(), visitor, reasonPtr))
             continue;
 
         visitor.appendUnbarriered(jsValue);
+
+        if (UNLIKELY(visitor.isBuildingHeapSnapshot())) {
+            if (jsValue.isCell())
+                visitor.heapSnapshotBuilder()->setOpaqueRootReachabilityReasonForCell(jsValue.asCell(), *reasonPtr);
+        }
     }
 }
 
index 044518f..4572405 100644 (file)
@@ -37,7 +37,7 @@ WeakHandleOwner::~WeakHandleOwner()
 {
 }
 
-bool WeakHandleOwner::isReachableFromOpaqueRoots(Handle<Unknown>, void*, SlotVisitor&)
+bool WeakHandleOwner::isReachableFromOpaqueRoots(Handle<Unknown>, void*, SlotVisitor&, const char**)
 {
     return false;
 }
index 219a9c5..450456f 100644 (file)
@@ -34,7 +34,8 @@ class SlotVisitor;
 class JS_EXPORT_PRIVATE WeakHandleOwner {
 public:
     virtual ~WeakHandleOwner();
-    virtual bool isReachableFromOpaqueRoots(Handle<Unknown>, void* context, SlotVisitor&);
+    // reason will only be non-null when generating a debug GC heap snapshot.
+    virtual bool isReachableFromOpaqueRoots(Handle<Unknown>, void* context, SlotVisitor&, char const** reason = nullptr);
     virtual void finalize(Handle<Unknown>, void* context);
 };
 
index a25028c..6afe230 100644 (file)
@@ -58,8 +58,10 @@ bool SimpleTypedArrayController::isAtomicsWaitAllowedOnCurrentThread()
     return true;
 }
 
-bool SimpleTypedArrayController::JSArrayBufferOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor)
+bool SimpleTypedArrayController::JSArrayBufferOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor, const char** reason)
 {
+    if (UNLIKELY(reason))
+        *reason = "JSArrayBuffer is opaque root";
     auto& wrapper = *JSC::jsCast<JSC::JSArrayBuffer*>(handle.slot()->asCell());
     return visitor.containsOpaqueRoot(wrapper.impl());
 }
index d2b03c2..33d089f 100644 (file)
@@ -58,7 +58,7 @@ public:
 private:
     class JSArrayBufferOwner : public WeakHandleOwner {
     public:
-        bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, SlotVisitor&) override;
+        bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, SlotVisitor&, const char** reason) override;
         void finalize(JSC::Handle<JSC::Unknown>, void* context) override;
     };
 
index dde3109..eb57c78 100644 (file)
@@ -172,8 +172,10 @@ private:
 
 class ElementHandleOwner : public WeakHandleOwner {
 public:
-    bool isReachableFromOpaqueRoots(Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor) override
+    bool isReachableFromOpaqueRoots(Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason) override
     {
+        if (UNLIKELY(reason))
+            *reason = "JSC::Element is opaque root";
         Element* element = jsCast<Element*>(handle.slot()->asCell());
         return visitor.containsOpaqueRoot(element->root());
     }
index 506c99e..50081f9 100644 (file)
@@ -1,3 +1,314 @@
+2018-08-23  Simon Fraser  <simon.fraser@apple.com>
+
+        Add support for dumping GC heap snapshots, and a viewer
+        https://bugs.webkit.org/show_bug.cgi?id=186416
+
+        Reviewed by Joseph Pecoraro.
+
+        Make a way to dump information about the GC heap that is useful for looking for leaked
+        or abandoned objects. This dump is obtained (on Apple platforms) via:
+            notifyutil -p com.apple.WebKit.dumpGCHeap
+        which writes a JSON file to /tmp which can then be loaded into the viewer in Tools/GCHeapInspector.
+
+        This leverages the heap snapshot used by Web Inspector, adding an alternate format for
+        the snapshot JSON that adds additional data about objects and why they are GC roots.
+        
+        The generated bindings code is changed to include the output root reason from isReachableFromOpaqueRoots(),
+        and to implement heapSnapshot() which provides the address of the wrapped object. A new IDL attribute,
+        CustomHeapSnapshot, is used to allow custom heapSnapshot() implementations for classes like JSDocument
+        that need to decorate the heap snapshot cell data with things like the document URL.
+
+        GCController registers a notifyutil callback which gathers the debug heap snapshot, and dumps it
+        to a file in /tmp. The file path is printed out to the system log.
+
+        * bindings/js/DOMGCOutputConstraint.cpp:
+        (WebCore::DOMGCOutputConstraint::executeImpl):
+        * bindings/js/GCController.cpp:
+        (WebCore::GCController::GCController):
+        (WebCore::GCController::dumpHeap):
+        * bindings/js/GCController.h:
+        * bindings/js/JSCSSRuleListCustom.cpp:
+        (WebCore::JSCSSRuleListOwner::isReachableFromOpaqueRoots):
+        * bindings/js/JSCallbackData.cpp:
+        (WebCore::JSCallbackDataWeak::WeakOwner::isReachableFromOpaqueRoots):
+        * bindings/js/JSCallbackData.h:
+        * bindings/js/JSCanvasRenderingContext2DCustom.cpp:
+        (WebCore::JSCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots):
+        * bindings/js/JSDOMWindowCustom.cpp:
+        (WebCore::JSDOMWindow::getOwnPropertySlot):
+        (WebCore::JSDOMWindow::heapSnapshot):
+        * bindings/js/JSDeprecatedCSSOMValueCustom.cpp:
+        (WebCore::JSDeprecatedCSSOMValueOwner::isReachableFromOpaqueRoots):
+        * bindings/js/JSDocumentCustom.cpp:
+        (WebCore::JSDocument::heapSnapshot):
+        * bindings/js/JSMicrotaskCallback.h:
+        (WebCore::JSMicrotaskCallback::call):
+        * bindings/js/JSMutationObserverCustom.cpp:
+        (WebCore::JSMutationObserverOwner::isReachableFromOpaqueRoots):
+        * bindings/js/JSNavigatorCustom.cpp:
+        (WebCore::JSNavigator::visitAdditionalChildren):
+        * bindings/js/JSNodeCustom.cpp:
+        (WebCore::isReachableFromDOM):
+        (WebCore::JSNodeOwner::isReachableFromOpaqueRoots):
+        * bindings/js/JSNodeListCustom.cpp:
+        (WebCore::JSNodeListOwner::isReachableFromOpaqueRoots):
+        * bindings/js/JSOffscreenCanvasRenderingContext2DCustom.cpp:
+        (WebCore::JSOffscreenCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots):
+        * bindings/js/JSPerformanceObserverCustom.cpp:
+        (WebCore::JSPerformanceObserverOwner::isReachableFromOpaqueRoots):
+        * bindings/js/JSPopStateEventCustom.cpp:
+        * bindings/js/JSTextTrackCueCustom.cpp:
+        (WebCore::JSTextTrackCueOwner::isReachableFromOpaqueRoots):
+        * bindings/js/WebCoreTypedArrayController.cpp:
+        (WebCore::WebCoreTypedArrayController::JSArrayBufferOwner::isReachableFromOpaqueRoots):
+        * bindings/js/WebCoreTypedArrayController.h:
+        * bindings/scripts/CodeGeneratorJS.pm:
+        (GenerateHeader):
+        (GenerateImplementation):
+        * bindings/scripts/IDLAttributes.json:
+        * bindings/scripts/test/JS/JSInterfaceName.cpp:
+        (WebCore::JSInterfaceName::heapSnapshot):
+        (WebCore::JSInterfaceNameOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSInterfaceName.h:
+        * bindings/scripts/test/JS/JSMapLike.cpp:
+        (WebCore::JSMapLike::heapSnapshot):
+        (WebCore::JSMapLikeOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSMapLike.h:
+        * bindings/scripts/test/JS/JSReadOnlyMapLike.cpp:
+        (WebCore::JSReadOnlyMapLike::heapSnapshot):
+        (WebCore::JSReadOnlyMapLikeOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSReadOnlyMapLike.h:
+        * bindings/scripts/test/JS/JSTestActiveDOMObject.cpp:
+        (WebCore::JSTestActiveDOMObject::heapSnapshot):
+        (WebCore::JSTestActiveDOMObjectOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestActiveDOMObject.h:
+        * bindings/scripts/test/JS/JSTestCEReactions.cpp:
+        (WebCore::JSTestCEReactions::heapSnapshot):
+        (WebCore::JSTestCEReactionsOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestCEReactions.h:
+        * bindings/scripts/test/JS/JSTestCEReactionsStringifier.cpp:
+        (WebCore::JSTestCEReactionsStringifier::heapSnapshot):
+        (WebCore::JSTestCEReactionsStringifierOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestCEReactionsStringifier.h:
+        * bindings/scripts/test/JS/JSTestCallTracer.cpp:
+        (WebCore::JSTestCallTracer::heapSnapshot):
+        (WebCore::JSTestCallTracerOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestCallTracer.h:
+        * bindings/scripts/test/JS/JSTestClassWithJSBuiltinConstructor.cpp:
+        (WebCore::JSTestClassWithJSBuiltinConstructor::heapSnapshot):
+        (WebCore::JSTestClassWithJSBuiltinConstructorOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestClassWithJSBuiltinConstructor.h:
+        * bindings/scripts/test/JS/JSTestCustomConstructorWithNoInterfaceObject.cpp:
+        (WebCore::JSTestCustomConstructorWithNoInterfaceObject::heapSnapshot):
+        (WebCore::JSTestCustomConstructorWithNoInterfaceObjectOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestCustomConstructorWithNoInterfaceObject.h:
+        * bindings/scripts/test/JS/JSTestDOMJIT.cpp:
+        (WebCore::JSTestDOMJIT::heapSnapshot):
+        * bindings/scripts/test/JS/JSTestDOMJIT.h:
+        * bindings/scripts/test/JS/JSTestEnabledBySetting.cpp:
+        (WebCore::JSTestEnabledBySetting::heapSnapshot):
+        (WebCore::JSTestEnabledBySettingOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestEnabledBySetting.h:
+        * bindings/scripts/test/JS/JSTestEventConstructor.cpp:
+        (WebCore::JSTestEventConstructor::heapSnapshot):
+        * bindings/scripts/test/JS/JSTestEventConstructor.h:
+        * bindings/scripts/test/JS/JSTestEventTarget.cpp:
+        (WebCore::JSTestEventTarget::heapSnapshot):
+        * bindings/scripts/test/JS/JSTestEventTarget.h:
+        * bindings/scripts/test/JS/JSTestException.cpp:
+        (WebCore::JSTestException::heapSnapshot):
+        (WebCore::JSTestExceptionOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestException.h:
+        * bindings/scripts/test/JS/JSTestGenerateIsReachable.cpp:
+        (WebCore::JSTestGenerateIsReachable::heapSnapshot):
+        (WebCore::JSTestGenerateIsReachableOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestGenerateIsReachable.h:
+        * bindings/scripts/test/JS/JSTestGlobalObject.cpp:
+        (WebCore::JSTestGlobalObject::heapSnapshot):
+        (WebCore::JSTestGlobalObjectOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestGlobalObject.h:
+        * bindings/scripts/test/JS/JSTestIndexedSetterNoIdentifier.cpp:
+        (WebCore::JSTestIndexedSetterNoIdentifier::heapSnapshot):
+        (WebCore::JSTestIndexedSetterNoIdentifierOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestIndexedSetterNoIdentifier.h:
+        * bindings/scripts/test/JS/JSTestIndexedSetterThrowingException.cpp:
+        (WebCore::JSTestIndexedSetterThrowingException::heapSnapshot):
+        (WebCore::JSTestIndexedSetterThrowingExceptionOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestIndexedSetterThrowingException.h:
+        * bindings/scripts/test/JS/JSTestIndexedSetterWithIdentifier.cpp:
+        (WebCore::JSTestIndexedSetterWithIdentifier::heapSnapshot):
+        (WebCore::JSTestIndexedSetterWithIdentifierOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestIndexedSetterWithIdentifier.h:
+        * bindings/scripts/test/JS/JSTestInterface.cpp:
+        (WebCore::JSTestInterface::heapSnapshot):
+        (WebCore::JSTestInterfaceOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestInterface.h:
+        * bindings/scripts/test/JS/JSTestInterfaceLeadingUnderscore.cpp:
+        (WebCore::JSTestInterfaceLeadingUnderscore::heapSnapshot):
+        (WebCore::JSTestInterfaceLeadingUnderscoreOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestInterfaceLeadingUnderscore.h:
+        * bindings/scripts/test/JS/JSTestIterable.cpp:
+        (WebCore::JSTestIterable::heapSnapshot):
+        (WebCore::JSTestIterableOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestIterable.h:
+        * bindings/scripts/test/JS/JSTestMediaQueryListListener.cpp:
+        (WebCore::JSTestMediaQueryListListener::heapSnapshot):
+        (WebCore::JSTestMediaQueryListListenerOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestMediaQueryListListener.h:
+        * bindings/scripts/test/JS/JSTestNamedAndIndexedSetterNoIdentifier.cpp:
+        (WebCore::JSTestNamedAndIndexedSetterNoIdentifier::heapSnapshot):
+        (WebCore::JSTestNamedAndIndexedSetterNoIdentifierOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedAndIndexedSetterNoIdentifier.h:
+        * bindings/scripts/test/JS/JSTestNamedAndIndexedSetterThrowingException.cpp:
+        (WebCore::JSTestNamedAndIndexedSetterThrowingException::heapSnapshot):
+        (WebCore::JSTestNamedAndIndexedSetterThrowingExceptionOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedAndIndexedSetterThrowingException.h:
+        * bindings/scripts/test/JS/JSTestNamedAndIndexedSetterWithIdentifier.cpp:
+        (WebCore::JSTestNamedAndIndexedSetterWithIdentifier::heapSnapshot):
+        (WebCore::JSTestNamedAndIndexedSetterWithIdentifierOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedAndIndexedSetterWithIdentifier.h:
+        * bindings/scripts/test/JS/JSTestNamedConstructor.cpp:
+        (WebCore::JSTestNamedConstructor::heapSnapshot):
+        (WebCore::JSTestNamedConstructorOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedConstructor.h:
+        * bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.cpp:
+        (WebCore::JSTestNamedDeleterNoIdentifier::heapSnapshot):
+        (WebCore::JSTestNamedDeleterNoIdentifierOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.h:
+        * bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.cpp:
+        (WebCore::JSTestNamedDeleterThrowingException::heapSnapshot):
+        (WebCore::JSTestNamedDeleterThrowingExceptionOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.h:
+        * bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.cpp:
+        (WebCore::JSTestNamedDeleterWithIdentifier::heapSnapshot):
+        (WebCore::JSTestNamedDeleterWithIdentifierOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.h:
+        * bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.cpp:
+        (WebCore::JSTestNamedDeleterWithIndexedGetter::heapSnapshot):
+        (WebCore::JSTestNamedDeleterWithIndexedGetterOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.h:
+        * bindings/scripts/test/JS/JSTestNamedGetterCallWith.cpp:
+        (WebCore::JSTestNamedGetterCallWith::heapSnapshot):
+        (WebCore::JSTestNamedGetterCallWithOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedGetterCallWith.h:
+        * bindings/scripts/test/JS/JSTestNamedGetterNoIdentifier.cpp:
+        (WebCore::JSTestNamedGetterNoIdentifier::heapSnapshot):
+        (WebCore::JSTestNamedGetterNoIdentifierOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedGetterNoIdentifier.h:
+        * bindings/scripts/test/JS/JSTestNamedGetterWithIdentifier.cpp:
+        (WebCore::JSTestNamedGetterWithIdentifier::heapSnapshot):
+        (WebCore::JSTestNamedGetterWithIdentifierOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedGetterWithIdentifier.h:
+        * bindings/scripts/test/JS/JSTestNamedSetterNoIdentifier.cpp:
+        (WebCore::JSTestNamedSetterNoIdentifier::heapSnapshot):
+        (WebCore::JSTestNamedSetterNoIdentifierOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedSetterNoIdentifier.h:
+        * bindings/scripts/test/JS/JSTestNamedSetterThrowingException.cpp:
+        (WebCore::JSTestNamedSetterThrowingException::heapSnapshot):
+        (WebCore::JSTestNamedSetterThrowingExceptionOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedSetterThrowingException.h:
+        * bindings/scripts/test/JS/JSTestNamedSetterWithIdentifier.cpp:
+        (WebCore::JSTestNamedSetterWithIdentifier::heapSnapshot):
+        (WebCore::JSTestNamedSetterWithIdentifierOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedSetterWithIdentifier.h:
+        * bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetter.cpp:
+        (WebCore::JSTestNamedSetterWithIndexedGetter::heapSnapshot):
+        (WebCore::JSTestNamedSetterWithIndexedGetterOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetter.h:
+        * bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetterAndSetter.cpp:
+        (WebCore::JSTestNamedSetterWithIndexedGetterAndSetter::heapSnapshot):
+        (WebCore::JSTestNamedSetterWithIndexedGetterAndSetterOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetterAndSetter.h:
+        * bindings/scripts/test/JS/JSTestNamedSetterWithOverrideBuiltins.cpp:
+        (WebCore::JSTestNamedSetterWithOverrideBuiltins::heapSnapshot):
+        (WebCore::JSTestNamedSetterWithOverrideBuiltinsOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedSetterWithOverrideBuiltins.h:
+        * bindings/scripts/test/JS/JSTestNamedSetterWithUnforgableProperties.cpp:
+        (WebCore::JSTestNamedSetterWithUnforgableProperties::heapSnapshot):
+        (WebCore::JSTestNamedSetterWithUnforgablePropertiesOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedSetterWithUnforgableProperties.h:
+        * bindings/scripts/test/JS/JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins.cpp:
+        (WebCore::JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins::heapSnapshot):
+        (WebCore::JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltinsOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins.h:
+        * bindings/scripts/test/JS/JSTestNode.cpp:
+        (WebCore::JSTestNode::heapSnapshot):
+        * bindings/scripts/test/JS/JSTestNode.h:
+        * bindings/scripts/test/JS/JSTestObj.cpp:
+        (WebCore::JSTestObj::heapSnapshot):
+        (WebCore::JSTestObjOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestObj.h:
+        * bindings/scripts/test/JS/JSTestOverloadedConstructors.cpp:
+        (WebCore::JSTestOverloadedConstructors::heapSnapshot):
+        (WebCore::JSTestOverloadedConstructorsOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestOverloadedConstructors.h:
+        * bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.cpp:
+        (WebCore::JSTestOverloadedConstructorsWithSequence::heapSnapshot):
+        (WebCore::JSTestOverloadedConstructorsWithSequenceOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.h:
+        * bindings/scripts/test/JS/JSTestOverrideBuiltins.cpp:
+        (WebCore::JSTestOverrideBuiltins::heapSnapshot):
+        (WebCore::JSTestOverrideBuiltinsOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestOverrideBuiltins.h:
+        * bindings/scripts/test/JS/JSTestPluginInterface.cpp:
+        (WebCore::JSTestPluginInterface::heapSnapshot):
+        (WebCore::JSTestPluginInterfaceOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestPluginInterface.h:
+        * bindings/scripts/test/JS/JSTestPromiseRejectionEvent.cpp:
+        (WebCore::JSTestPromiseRejectionEvent::heapSnapshot):
+        * bindings/scripts/test/JS/JSTestPromiseRejectionEvent.h:
+        * bindings/scripts/test/JS/JSTestSerialization.cpp:
+        (WebCore::JSTestSerialization::heapSnapshot):
+        (WebCore::JSTestSerializationOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestSerialization.h:
+        * bindings/scripts/test/JS/JSTestSerializationIndirectInheritance.cpp:
+        (WebCore::JSTestSerializationIndirectInheritance::heapSnapshot):
+        * bindings/scripts/test/JS/JSTestSerializationIndirectInheritance.h:
+        * bindings/scripts/test/JS/JSTestSerializationInherit.cpp:
+        (WebCore::JSTestSerializationInherit::heapSnapshot):
+        * bindings/scripts/test/JS/JSTestSerializationInherit.h:
+        * bindings/scripts/test/JS/JSTestSerializationInheritFinal.cpp:
+        (WebCore::JSTestSerializationInheritFinal::heapSnapshot):
+        * bindings/scripts/test/JS/JSTestSerializationInheritFinal.h:
+        * bindings/scripts/test/JS/JSTestSerializedScriptValueInterface.cpp:
+        (WebCore::JSTestSerializedScriptValueInterface::heapSnapshot):
+        (WebCore::JSTestSerializedScriptValueInterfaceOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestSerializedScriptValueInterface.h:
+        * bindings/scripts/test/JS/JSTestStringifier.cpp:
+        (WebCore::JSTestStringifier::heapSnapshot):
+        (WebCore::JSTestStringifierOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestStringifier.h:
+        * bindings/scripts/test/JS/JSTestStringifierAnonymousOperation.cpp:
+        (WebCore::JSTestStringifierAnonymousOperation::heapSnapshot):
+        (WebCore::JSTestStringifierAnonymousOperationOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestStringifierAnonymousOperation.h:
+        * bindings/scripts/test/JS/JSTestStringifierNamedOperation.cpp:
+        (WebCore::JSTestStringifierNamedOperation::heapSnapshot):
+        (WebCore::JSTestStringifierNamedOperationOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestStringifierNamedOperation.h:
+        * bindings/scripts/test/JS/JSTestStringifierOperationImplementedAs.cpp:
+        (WebCore::JSTestStringifierOperationImplementedAs::heapSnapshot):
+        (WebCore::JSTestStringifierOperationImplementedAsOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestStringifierOperationImplementedAs.h:
+        * bindings/scripts/test/JS/JSTestStringifierOperationNamedToString.cpp:
+        (WebCore::JSTestStringifierOperationNamedToString::heapSnapshot):
+        (WebCore::JSTestStringifierOperationNamedToStringOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestStringifierOperationNamedToString.h:
+        * bindings/scripts/test/JS/JSTestStringifierReadOnlyAttribute.cpp:
+        (WebCore::JSTestStringifierReadOnlyAttribute::heapSnapshot):
+        (WebCore::JSTestStringifierReadOnlyAttributeOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestStringifierReadOnlyAttribute.h:
+        * bindings/scripts/test/JS/JSTestStringifierReadWriteAttribute.cpp:
+        (WebCore::JSTestStringifierReadWriteAttribute::heapSnapshot):
+        (WebCore::JSTestStringifierReadWriteAttributeOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestStringifierReadWriteAttribute.h:
+        * bindings/scripts/test/JS/JSTestTypedefs.cpp:
+        (WebCore::JSTestTypedefs::heapSnapshot):
+        (WebCore::JSTestTypedefsOwner::isReachableFromOpaqueRoots):
+        * bindings/scripts/test/JS/JSTestTypedefs.h:
+        * dom/Document.idl:
+        * page/DOMWindow.idl:
+
 2018-08-23  Ryosuke Niwa  <rniwa@webkit.org>
 
         initKeyboardEvent doesn't clear CapsLock state
index 6886343..7d27da4 100644 (file)
@@ -29,6 +29,7 @@
 #include "WebCoreJSClientData.h"
 #include <JavaScriptCore/BlockDirectoryInlines.h>
 #include <JavaScriptCore/HeapInlines.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/MarkedBlockInlines.h>
 #include <JavaScriptCore/SubspaceInlines.h>
 #include <JavaScriptCore/VM.h>
@@ -61,6 +62,7 @@ void DOMGCOutputConstraint::executeImpl(SlotVisitor& visitor)
     m_clientData.forEachOutputConstraintSpace(
         [&] (Subspace& subspace) {
             auto func = [] (SlotVisitor& visitor, HeapCell* heapCell, HeapCell::Kind) {
+                SetRootMarkReasonScope rootScope(visitor, SlotVisitor::RootMarkReason::DOMGCOutput);
                 JSCell* cell = static_cast<JSCell*>(heapCell);
                 cell->methodTable(visitor.vm())->visitOutputConstraints(cell, visitor);
             };
index 43856f5..d251d2e 100644 (file)
 #include "GCController.h"
 
 #include "CommonVM.h"
+#include "FileSystem.h"
+#include "JSHTMLDocument.h"
+#include "Location.h"
 #include <JavaScriptCore/Heap.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSLock.h>
 #include <JavaScriptCore/VM.h>
+#include <pal/Logging.h>
 #include <wtf/FastMalloc.h>
 #include <wtf/NeverDestroyed.h>
 #include <wtf/StdLibExtras.h>
@@ -52,6 +57,12 @@ GCController& GCController::singleton()
 GCController::GCController()
     : m_GCTimer(*this, &GCController::gcTimerFired)
 {
+    static std::once_flag onceFlag;
+    std::call_once(onceFlag, [] {
+        PAL::registerNotifyCallback("com.apple.WebKit.dumpGCHeap", [] {
+            GCController::singleton().dumpHeap();
+        });
+    });
 }
 
 void GCController::garbageCollectSoon()
@@ -127,4 +138,36 @@ void GCController::deleteAllLinkedCode(DeleteAllCodeEffort effort)
     commonVM().deleteAllLinkedCode(effort);
 }
 
+void GCController::dumpHeap()
+{
+    FileSystem::PlatformFileHandle fileHandle;
+    String tempFilePath = FileSystem::openTemporaryFile("GCHeap"_s, fileHandle);
+    if (!FileSystem::isHandleValid(fileHandle)) {
+        WTFLogAlways("Dumping GC heap failed to open temporary file");
+        return;
+    }
+
+    VM& vm = commonVM();
+    JSLockHolder lock(vm);
+
+    sanitizeStackForVM(&vm);
+
+    String jsonData;
+    {
+        DeferGCForAWhile deferGC(vm.heap); // Prevent concurrent GC from interfering with the full GC that the snapshot does.
+
+        HeapSnapshotBuilder snapshotBuilder(vm.ensureHeapProfiler(), HeapSnapshotBuilder::SnapshotType::GCDebuggingSnapshot);
+        snapshotBuilder.buildSnapshot();
+
+        jsonData = snapshotBuilder.json();
+    }
+
+    CString utf8String = jsonData.utf8();
+
+    FileSystem::writeToFile(fileHandle, utf8String.data(), utf8String.length());
+    FileSystem::closeFile(fileHandle);
+    
+    WTFLogAlways("Dumped GC heap to %s", tempFilePath.utf8().data());
+}
+
 } // namespace WebCore
index ef6d138..0ce4595 100644 (file)
@@ -51,6 +51,8 @@ public:
 private:
     GCController(); // Use singleton() instead.
 
+    void dumpHeap();
+
     void gcTimerFired();
     Timer m_GCTimer;
 };
index f0550aa..020e458 100644 (file)
 namespace WebCore {
 using namespace JSC;
 
-bool JSCSSRuleListOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+bool JSCSSRuleListOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     JSCSSRuleList* jsCSSRuleList = jsCast<JSCSSRuleList*>(handle.slot()->asCell());
     if (!jsCSSRuleList->hasCustomProperties(*jsCSSRuleList->vm()))
         return false;
-    if (CSSStyleSheet* styleSheet = jsCSSRuleList->wrapped().styleSheet())
+
+    if (CSSStyleSheet* styleSheet = jsCSSRuleList->wrapped().styleSheet()) {
+        if (UNLIKELY(reason))
+            *reason = "CSSStyleSheet is opaque root";
+
         return visitor.containsOpaqueRoot(root(styleSheet));
-    if (CSSRule* cssRule = jsCSSRuleList->wrapped().item(0))
+    }
+    
+    if (CSSRule* cssRule = jsCSSRuleList->wrapped().item(0)) {
+        if (UNLIKELY(reason))
+            *reason = "CSSRule is opaque root";
+
         return visitor.containsOpaqueRoot(root(cssRule));
+    }
     return false;
 }
 
index 9ba0eaf..186762a 100644 (file)
@@ -90,8 +90,10 @@ void JSCallbackDataWeak::visitJSFunction(JSC::SlotVisitor& vistor)
     vistor.append(m_callback);
 }
 
-bool JSCallbackDataWeak::WeakOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, SlotVisitor& visitor)
+bool JSCallbackDataWeak::WeakOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, SlotVisitor& visitor, const char** reason)
 {
+    if (UNLIKELY(reason))
+        *reason = "Context is opaque root"; // FIXME: what is the context.
     return visitor.containsOpaqueRoot(context);
 }
 
index 60192e6..a5bc954 100644 (file)
@@ -116,7 +116,7 @@ public:
 
 private:
     class WeakOwner : public JSC::WeakHandleOwner {
-        bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&) override;
+        bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**) override;
     };
     WeakOwner m_weakOwner;
     JSC::Weak<JSC::JSObject> m_callback;
index f1018f4..4d50042 100644 (file)
 
 namespace WebCore {
 
-bool JSCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor)
+bool JSCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor, const char** reason)
 {
+    if (UNLIKELY(reason))
+        *reason = "Canvas is opaque root";
+
     JSCanvasRenderingContext2D* jsCanvasRenderingContext = jsCast<JSCanvasRenderingContext2D*>(handle.slot()->asCell());
     void* root = WebCore::root(jsCanvasRenderingContext->wrapped().canvas());
     return visitor.containsOpaqueRoot(root);
index a761db1..496d2e7 100644 (file)
@@ -45,6 +45,7 @@
 #include "ScheduledAction.h"
 #include "Settings.h"
 #include "WebCoreJSClientData.h"
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <JavaScriptCore/JSMicrotask.h>
 #include <JavaScriptCore/Lookup.h>
@@ -202,7 +203,7 @@ bool JSDOMWindow::getOwnPropertySlot(JSObject* object, ExecState* state, Propert
     if (!BindingSecurity::shouldAllowAccessToDOMWindow(*state, thisObject->wrapped(), errorMessage))
         return jsDOMWindowGetOwnPropertySlotRestrictedAccess<DOMWindowType::Local>(thisObject, thisObject->wrapped(), *state, propertyName, slot, errorMessage);
 
-    // FIXME: this need more explanation.
+    // FIXME: this needs more explanation.
     // (Particularly, is it correct that this exists here but not in getOwnPropertySlotByIndex?)
     slot.setWatchpointSet(thisObject->m_windowCloseWatchpoints);
 
@@ -328,6 +329,15 @@ bool JSDOMWindow::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned
     return Base::deletePropertyByIndex(thisObject, exec, propertyName);
 }
 
+void JSDOMWindow::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(cell);
+    if (auto* location = thisObject->wrapped().location())
+        builder.setLabelForCell(cell, location->href());
+
+    Base::heapSnapshot(cell, builder);
+}
+
 // https://html.spec.whatwg.org/#crossoriginproperties-(-o-)
 static void addCrossOriginWindowPropertyNames(ExecState& state, AbstractDOMWindow& window, PropertyNameArray& propertyNames)
 {
index 35c75fe..f86fee6 100644 (file)
 namespace WebCore {
 using namespace JSC;
 
-bool JSDeprecatedCSSOMValueOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+bool JSDeprecatedCSSOMValueOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     JSDeprecatedCSSOMValue* jsCSSValue = jsCast<JSDeprecatedCSSOMValue*>(handle.slot()->asCell());
     if (!jsCSSValue->hasCustomProperties(*jsCSSValue->vm()))
         return false;
+
+    if (UNLIKELY(reason))
+        *reason = "CSSStyleDeclaration is opaque root";
+
     return visitor.containsOpaqueRoot(root(&jsCSSValue->wrapped().owner()));
 }
 
index 6605f1e..5687e4d 100644 (file)
@@ -26,6 +26,7 @@
 #include "JSXMLDocument.h"
 #include "NodeTraversal.h"
 #include "SVGDocument.h"
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 
 
 namespace WebCore {
@@ -93,4 +94,11 @@ void JSDocument::visitAdditionalChildren(SlotVisitor& visitor)
     visitor.addOpaqueRoot(static_cast<ScriptExecutionContext*>(&wrapped()));
 }
 
+void JSDocument::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    Base::heapSnapshot(cell, builder);
+    auto* thisObject = jsCast<JSDocument*>(cell);
+    builder.setLabelForCell(cell, thisObject->wrapped().url().string());
+}
+
 } // namespace WebCore
index c9b8e64..1a0b53f 100644 (file)
@@ -40,8 +40,8 @@ public:
     void call()
     {
         auto protectedThis { makeRef(*this) };
-        VM& vm = m_globalObject->vm();
-        JSLockHolder lock(vm);
+        JSC::VM& vm = m_globalObject->vm();
+        JSC::JSLockHolder lock(vm);
         auto scope = DECLARE_THROW_SCOPE(vm);
         JSExecState::runTask(m_globalObject->globalExec(), m_task);
         scope.assertNoException();
@@ -54,7 +54,7 @@ private:
     {
     }
 
-    Strong<JSDOMGlobalObject> m_globalObject;
+    JSC::Strong<JSDOMGlobalObject> m_globalObject;
     Ref<JSC::Microtask> m_task;
 };
 
index 4ddef8a..195ad01 100644 (file)
@@ -44,11 +44,14 @@ void JSMutationObserver::visitAdditionalChildren(JSC::SlotVisitor& visitor)
     wrapped().callback().visitJSFunction(visitor);
 }
 
-bool JSMutationObserverOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+bool JSMutationObserverOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char**reason)
 {
     for (auto* node : jsCast<JSMutationObserver*>(handle.slot()->asCell())->wrapped().observedNodes()) {
-        if (visitor.containsOpaqueRoot(root(node)))
+        if (visitor.containsOpaqueRoot(root(node))) {
+            if (UNLIKELY(reason))
+                *reason = "Reachable from observed nodes";
             return true;
+        }
     }
     return false;
 }
index 49cda06..2169900 100644 (file)
@@ -28,7 +28,7 @@
 
 namespace WebCore {
 
-void JSNavigator::visitAdditionalChildren(SlotVisitor& visitor)
+void JSNavigator::visitAdditionalChildren(JSC::SlotVisitor& visitor)
 {
 #if ENABLE(SERVICE_WORKER)
     visitor.addOpaqueRoot(&wrapped().serviceWorker());
index 09a70f2..c485e30 100644 (file)
@@ -71,7 +71,7 @@ using namespace JSC;
 
 using namespace HTMLNames;
 
-static inline bool isReachableFromDOM(Node* node, SlotVisitor& visitor)
+static inline bool isReachableFromDOM(Node* node, SlotVisitor& visitor, const char** reason)
 {
     if (!node->isConnected()) {
         if (is<Element>(*node)) {
@@ -83,30 +83,42 @@ static inline bool isReachableFromDOM(Node* node, SlotVisitor& visitor)
             // the element is destroyed, its load event will not fire.
             // FIXME: The DOM should manage this issue without the help of JavaScript wrappers.
             if (is<HTMLImageElement>(element)) {
-                if (downcast<HTMLImageElement>(element).hasPendingActivity())
+                if (downcast<HTMLImageElement>(element).hasPendingActivity()) {
+                    if (UNLIKELY(reason))
+                        *reason = "Image element with pending activity";
                     return true;
+                }
             }
 #if ENABLE(VIDEO)
             else if (is<HTMLAudioElement>(element)) {
-                if (!downcast<HTMLAudioElement>(element).paused())
+                if (!downcast<HTMLAudioElement>(element).paused()) {
+                    if (UNLIKELY(reason))
+                        *reason = "Audio element which is not paused";
                     return true;
+                }
             }
 #endif
         }
 
         // If a node is firing event listeners, its wrapper is observable because
         // its wrapper is responsible for marking those event listeners.
-        if (node->isFiringEventListeners())
+        if (node->isFiringEventListeners()) {
+            if (UNLIKELY(reason))
+                *reason = "Node which is firing event listeners";
             return true;
+        }
     }
 
+    if (UNLIKELY(reason))
+        *reason = "Connected node";
+
     return visitor.containsOpaqueRoot(root(node));
 }
 
-bool JSNodeOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+bool JSNodeOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     JSNode* jsNode = jsCast<JSNode*>(handle.slot()->asCell());
-    return isReachableFromDOM(&jsNode->wrapped(), visitor);
+    return isReachableFromDOM(&jsNode->wrapped(), visitor, reason);
 }
 
 JSScope* JSNode::pushEventHandlerScope(ExecState* exec, JSScope* node) const
index 9a1c873..7f6d9e7 100644 (file)
 namespace WebCore {
 using namespace JSC;
 
-bool JSNodeListOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+bool JSNodeListOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     JSNodeList* jsNodeList = jsCast<JSNodeList*>(handle.slot()->asCell());
     if (!jsNodeList->hasCustomProperties(*jsNodeList->vm()))
         return false;
-    if (jsNodeList->wrapped().isLiveNodeList())
+
+    if (jsNodeList->wrapped().isLiveNodeList()) {
+        if (UNLIKELY(reason))
+            *reason = "LiveNodeList owner is opaque root";
+
         return visitor.containsOpaqueRoot(root(static_cast<LiveNodeList&>(jsNodeList->wrapped()).ownerNode()));
-    if (jsNodeList->wrapped().isChildNodeList())
+    }
+
+    if (jsNodeList->wrapped().isChildNodeList()) {
+        if (UNLIKELY(reason))
+            *reason = "ChildNodeList owner is opaque root";
+
         return visitor.containsOpaqueRoot(root(static_cast<ChildNodeList&>(jsNodeList->wrapped()).ownerNode()));
-    if (jsNodeList->wrapped().isEmptyNodeList())
+    }
+
+    if (jsNodeList->wrapped().isEmptyNodeList()) {
+        if (UNLIKELY(reason))
+            *reason = "EmptyNodeList owner is opaque root";
+
         return visitor.containsOpaqueRoot(root(static_cast<EmptyNodeList&>(jsNodeList->wrapped()).ownerNode()));
+    }
     return false;
 }
 
index 33b08e7..34d7a09 100644 (file)
@@ -28,8 +28,11 @@ inline void* root(OffscreenCanvas* canvas)
     return canvas;
 }
 
-bool JSOffscreenCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+bool JSOffscreenCanvasRenderingContext2DOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
+    if (UNLIKELY(reason))
+        *reason = "Canvas is opaque root";
+
     JSOffscreenCanvasRenderingContext2D* jsOffscreenCanvasRenderingContext = jsCast<JSOffscreenCanvasRenderingContext2D*>(handle.slot()->asCell());
     void* root = WebCore::root(&jsOffscreenCanvasRenderingContext->wrapped().canvas());
     return visitor.containsOpaqueRoot(root);
index 37e9517..6efa3dc 100644 (file)
@@ -35,8 +35,11 @@ void JSPerformanceObserver::visitAdditionalChildren(JSC::SlotVisitor& visitor)
     wrapped().callback().visitJSFunction(visitor);
 }
 
-bool JSPerformanceObserverOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor&)
+bool JSPerformanceObserverOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor&, const char** reason)
 {
+    if (UNLIKELY(reason))
+        *reason = "Registered PerformanceObserver callback";
+
     return jsCast<JSPerformanceObserver*>(handle.slot()->asCell())->wrapped().isRegistered();
 }
 
index 722dd9e..d31bdc7 100644 (file)
@@ -37,6 +37,7 @@
 #include <JavaScriptCore/JSCJSValueInlines.h>
 
 namespace WebCore {
+using namespace JSC;
 
 JSValue JSPopStateEvent::state(ExecState& state) const
 {
index c294451..3c48795 100644 (file)
 namespace WebCore {
 using namespace JSC;
 
-bool JSTextTrackCueOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+bool JSTextTrackCueOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     JSTextTrackCue* jsTextTrackCue = jsCast<JSTextTrackCue*>(handle.slot()->asCell());
     TextTrackCue& textTrackCue = jsTextTrackCue->wrapped();
 
     // If the cue is firing event listeners, its wrapper is reachable because
     // the wrapper is responsible for marking those event listeners.
-    if (textTrackCue.isFiringEventListeners())
+    if (textTrackCue.isFiringEventListeners()) {
+        if (UNLIKELY(reason))
+            *reason = "TextTrackCue is firing event listeners";
         return true;
+    }
 
     // If the cue is not associated with a track, it is not reachable.
     if (!textTrackCue.track())
         return false;
 
+    if (UNLIKELY(reason))
+        *reason = "TextTrack is an opaque root";
+
     return visitor.containsOpaqueRoot(root(textTrackCue.track()));
 }
 
index 84fb3c4..20b5f98 100644 (file)
@@ -53,8 +53,10 @@ bool WebCoreTypedArrayController::isAtomicsWaitAllowedOnCurrentThread()
     return !isMainThread();
 }
 
-bool WebCoreTypedArrayController::JSArrayBufferOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor)
+bool WebCoreTypedArrayController::JSArrayBufferOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor, const char** reason)
 {
+    if (UNLIKELY(reason))
+        *reason = "ArrayBuffer is opaque root";
     auto& wrapper = *JSC::jsCast<JSC::JSArrayBuffer*>(handle.slot()->asCell());
     return visitor.containsOpaqueRoot(wrapper.impl());
 }
index 2526012..e0bb956 100644 (file)
@@ -48,7 +48,7 @@ public:
 private:
     class JSArrayBufferOwner : public JSC::WeakHandleOwner {
     public:
-        bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&) override;
+        bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**) override;
         void finalize(JSC::Handle<JSC::Unknown>, void* context) override;
     };
 
index 873ed6b..7f4ac10 100644 (file)
@@ -2657,7 +2657,7 @@ sub GenerateHeader
     if ($interface->extendedAttributes->{CustomPreventExtensions}) {
         push(@headerContent, "    static bool preventExtensions(JSC::JSObject*, JSC::ExecState*);\n");
     }
-    
+
     if (InstanceNeedsEstimatedSize($interface)) {
         push(@headerContent, "    static size_t estimatedSize(JSCell*, JSC::VM&);\n");
     }
@@ -2758,6 +2758,10 @@ sub GenerateHeader
             push(@headerContent, "    template<typename> static JSC::CompleteSubspace* subspaceFor(JSC::VM& vm) { return $subspaceFunc(vm); }\n");
         }
     }
+
+    if (NeedsImplementationClass($interface)) {
+        push(@headerContent, "    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);\n");
+    }
     
     if ($numCustomAttributes > 0) {
         push(@headerContent, "\n    // Custom attributes\n");
@@ -2867,7 +2871,7 @@ sub GenerateHeader
         }
         $headerIncludes{"<wtf/NeverDestroyed.h>"} = 1;
         push(@headerContent, "public:\n");
-        push(@headerContent, "    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);\n");
+        push(@headerContent, "    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);\n");
         push(@headerContent, "    virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);\n");
         push(@headerContent, "};\n");
         push(@headerContent, "\n");
@@ -4521,6 +4525,20 @@ sub GenerateImplementation
         push(@implContent, "}\n\n");
     }
 
+    if (NeedsImplementationClass($interface) && !$interface->extendedAttributes->{CustomHeapSnapshot}) {
+        AddToImplIncludes("<JavaScriptCore/HeapSnapshotBuilder.h>");
+        AddToImplIncludes("ScriptExecutionContext.h");
+        AddToImplIncludes("URL.h");
+        push(@implContent, "void ${className}::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)\n");
+        push(@implContent, "{\n");
+        push(@implContent, "    auto* thisObject = jsCast<${className}*>(cell);\n");
+        push(@implContent, "    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());\n");
+        push(@implContent, "    if (thisObject->scriptExecutionContext())\n");
+        push(@implContent, "        builder.setLabelForCell(cell, String::format(\"url %s\", thisObject->scriptExecutionContext()->url().string().utf8().data()));\n");
+        push(@implContent, "    Base::heapSnapshot(cell, builder);\n");
+        push(@implContent, "}\n\n");
+    }
+
     if ($indexedGetterOperation) {
         $implIncludes{"URL.h"} = 1 if $indexedGetterOperation->type->name eq "DOMString";
         if ($interfaceName =~ /^HTML\w*Collection$/ or $interfaceName eq "RadioNodeList") {
@@ -4530,7 +4548,7 @@ sub GenerateImplementation
     }
 
     if (ShouldGenerateWrapperOwnerCode($hasParent, $interface) && !GetCustomIsReachable($interface)) {
-        push(@implContent, "bool JS${interfaceName}Owner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)\n");
+        push(@implContent, "bool JS${interfaceName}Owner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)\n");
         push(@implContent, "{\n");
         # All ActiveDOMObjects implement hasPendingActivity(), but not all of them
         # increment their C++ reference counts when hasPendingActivity() becomes
@@ -4543,23 +4561,29 @@ sub GenerateImplementation
         if ($codeGenerator->InheritsExtendedAttribute($interface, "ActiveDOMObject")) {
             push(@implContent, "    auto* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.slot()->asCell());\n");
             $emittedJSCast = 1;
-            push(@implContent, "    if (js${interfaceName}->wrapped().hasPendingActivity())\n");
+            push(@implContent, "    if (js${interfaceName}->wrapped().hasPendingActivity()) {\n");
+            push(@implContent, "        if (UNLIKELY(reason))\n");
+            push(@implContent, "            *reason = \"ActiveDOMObject with pending activity\";\n");
             push(@implContent, "        return true;\n");
+            push(@implContent, "     }\n");
         }
         if ($codeGenerator->InheritsInterface($interface, "EventTarget")) {
             if (!$emittedJSCast) {
                 push(@implContent, "    auto* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.slot()->asCell());\n");
                 $emittedJSCast = 1;
             }
-            push(@implContent, "    if (js${interfaceName}->wrapped().isFiringEventListeners())\n");
+            push(@implContent, "    if (js${interfaceName}->wrapped().isFiringEventListeners()) {\n");
+            push(@implContent, "        if (UNLIKELY(reason))\n");
+            push(@implContent, "            *reason = \"EventTarget firing event listeners\";\n");
             push(@implContent, "        return true;\n");
+            push(@implContent, "    }\n");
         }
         if ($codeGenerator->InheritsInterface($interface, "Node")) {
             if (!$emittedJSCast) {
                 push(@implContent, "    auto* js${interfaceName} = jsCast<JS${interfaceName}*>(handle.slot()->asCell());\n");
                 $emittedJSCast = 1;
             }
-            push(@implContent, "    if (JSNodeOwner::isReachableFromOpaqueRoots(handle, 0, visitor))\n");
+            push(@implContent, "    if (JSNodeOwner::isReachableFromOpaqueRoots(handle, 0, visitor, reason))\n");
             push(@implContent, "        return true;\n");
         }
         if (GetGenerateIsReachable($interface)) {
@@ -4571,33 +4595,49 @@ sub GenerateImplementation
             my $rootString;
             if (GetGenerateIsReachable($interface) eq "Impl") {
                 $rootString  = "    ${implType}* root = &js${interfaceName}->wrapped();\n";
+                $rootString .= "    if (UNLIKELY(reason))\n";
+                $rootString .= "        *reason = \"Reachable from ${interfaceName}\";\n";
             } elsif (GetGenerateIsReachable($interface) eq "ImplWebGLRenderingContext") {
                 $rootString  = "    WebGLRenderingContextBase* root = WTF::getPtr(js${interfaceName}->wrapped().context());\n";
+                $rootString .= "    if (UNLIKELY(reason))\n";
+                $rootString .= "        *reason = \"Reachable from ${interfaceName}\";\n";
             } elsif (GetGenerateIsReachable($interface) eq "ImplFrame") {
                 $rootString  = "    Frame* root = WTF::getPtr(js${interfaceName}->wrapped().frame());\n";
                 $rootString .= "    if (!root)\n";
                 $rootString .= "        return false;\n";
+                $rootString .= "    if (UNLIKELY(reason))\n";
+                $rootString .= "        *reason = \"Reachable from Frame\";\n";
             } elsif (GetGenerateIsReachable($interface) eq "ImplDocument") {
                 $rootString  = "    Document* root = WTF::getPtr(js${interfaceName}->wrapped().document());\n";
                 $rootString .= "    if (!root)\n";
                 $rootString .= "        return false;\n";
+                $rootString .= "    if (UNLIKELY(reason))\n";
+                $rootString .= "        *reason = \"Reachable from Document\";\n";
             } elsif (GetGenerateIsReachable($interface) eq "ImplElementRoot") {
                 $implIncludes{"Element.h"} = 1;
                 $implIncludes{"JSNodeCustom.h"} = 1;
                 $rootString  = "    Element* element = WTF::getPtr(js${interfaceName}->wrapped().element());\n";
                 $rootString .= "    if (!element)\n";
                 $rootString .= "        return false;\n";
+                $rootString .= "    if (UNLIKELY(reason))\n";
+                $rootString .= "        *reason = \"Reachable from ${interfaceName}Owner\";\n";
                 $rootString .= "    void* root = WebCore::root(element);\n";
             } elsif (GetGenerateIsReachable($interface) eq "ImplOwnerNodeRoot") {
                 $implIncludes{"Element.h"} = 1;
                 $implIncludes{"JSNodeCustom.h"} = 1;
                 $rootString  = "    void* root = WebCore::root(js${interfaceName}->wrapped().ownerNode());\n";
+                $rootString .= "    if (UNLIKELY(reason))\n";
+                $rootString .= "        *reason = \"Reachable from ${interfaceName} ownerNode\";\n";
             } elsif (GetGenerateIsReachable($interface) eq "ImplScriptExecutionContext") {
                 $rootString  = "    ScriptExecutionContext* root = WTF::getPtr(js${interfaceName}->wrapped().scriptExecutionContext());\n";
                 $rootString .= "    if (!root)\n";
                 $rootString .= "        return false;\n";
+                $rootString .= "    if (UNLIKELY(reason))\n";
+                $rootString .= "        *reason = \"Reachable from ScriptExecutionContext\";\n";
             } else {
                 $rootString  = "    void* root = WebCore::root(&js${interfaceName}->wrapped());\n";
+                $rootString .= "    if (UNLIKELY(reason))\n";
+                $rootString .= "        *reason = \"Reachable from js${interfaceName}\";\n";
             }
 
             push(@implContent, $rootString);
@@ -4607,6 +4647,7 @@ sub GenerateImplementation
                 push(@implContent, "    UNUSED_PARAM(handle);\n");
             }
             push(@implContent, "    UNUSED_PARAM(visitor);\n");
+            push(@implContent, "    UNUSED_PARAM(reason);\n");
             push(@implContent, "    return false;\n");
         }
         push(@implContent, "}\n\n");
index a9991c2..73fe7a2 100644 (file)
         "CustomGetter": {
             "contextsAllowed": ["attribute"]
         },
+        "CustomHeapSnapshot": {
+            "contextsAllowed": ["interface"]
+        },
         "CustomIndexedSetter": {
             "contextsAllowed": ["interface"]
         },
index d8c10a2..1179587 100644 (file)
 #include "JSDOMConstructorNotConstructable.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -168,10 +171,20 @@ size_t JSInterfaceName::estimatedSize(JSCell* cell, VM& vm)
     return Base::estimatedSize(thisObject, vm) + thisObject->wrapped().memoryCost();
 }
 
-bool JSInterfaceNameOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSInterfaceName::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSInterfaceName*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSInterfaceNameOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 9ddbbc3..c60a917 100644 (file)
@@ -52,6 +52,7 @@ public:
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
     static void visitChildren(JSCell*, JSC::SlotVisitor&);
 
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSInterfaceName(JSC::Structure*, JSDOMGlobalObject&, Ref<InterfaceName>&&);
 
@@ -60,7 +61,7 @@ protected:
 
 class JSInterfaceNameOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 761bbf4..6d7faa2 100644 (file)
 #include "JSDOMMapLike.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/BuiltinNames.h>
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -337,10 +340,20 @@ EncodedJSValue JSC_HOST_CALL jsMapLikePrototypeFunctionDelete(ExecState* state)
     return IDLOperation<JSMapLike>::call<jsMapLikePrototypeFunctionDeleteBody>(*state, "delete");
 }
 
-bool JSMapLikeOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSMapLike::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSMapLike*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSMapLikeOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index d80402d..206cd2e 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSMapLike(JSC::Structure*, JSDOMGlobalObject&, Ref<MapLike>&&);
 
@@ -57,7 +58,7 @@ protected:
 
 class JSMapLikeOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index c52d101..008dceb 100644 (file)
 #include "JSDOMMapLike.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/BuiltinNames.h>
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -286,10 +289,20 @@ EncodedJSValue JSC_HOST_CALL jsReadOnlyMapLikePrototypeFunctionForEach(ExecState
     return IDLOperation<JSReadOnlyMapLike>::call<jsReadOnlyMapLikePrototypeFunctionForEachBody>(*state, "forEach");
 }
 
-bool JSReadOnlyMapLikeOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSReadOnlyMapLike::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSReadOnlyMapLike*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSReadOnlyMapLikeOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index e2dc79f..b6fbb20 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSReadOnlyMapLike(JSC::Structure*, JSDOMGlobalObject&, Ref<ReadOnlyMapLike>&&);
 
@@ -57,7 +58,7 @@ protected:
 
 class JSReadOnlyMapLikeOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 7d4907d..62916d3 100644 (file)
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
 #include "JSNode.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -247,10 +250,20 @@ EncodedJSValue JSC_HOST_CALL jsTestActiveDOMObjectPrototypeFunctionPostMessage(E
     return IDLOperation<JSTestActiveDOMObject>::call<jsTestActiveDOMObjectPrototypeFunctionPostMessageBody>(*state, "postMessage");
 }
 
-bool JSTestActiveDOMObjectOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestActiveDOMObject::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestActiveDOMObject*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestActiveDOMObjectOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 0dd833f..f224633 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::HasStaticPropertyTable | Base::StructureFlags;
 protected:
@@ -59,7 +60,7 @@ protected:
 
 class JSTestActiveDOMObjectOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 83740bf..6406be9 100644 (file)
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
 #include "JSTestCEReactionsStringifier.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -427,10 +430,20 @@ EncodedJSValue JSC_HOST_CALL jsTestCEReactionsPrototypeFunctionMethodWithCEReact
     return IDLOperation<JSTestCEReactions>::call<jsTestCEReactionsPrototypeFunctionMethodWithCEReactionsNotNeededBody>(*state, "methodWithCEReactionsNotNeeded");
 }
 
-bool JSTestCEReactionsOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestCEReactions::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestCEReactions*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestCEReactionsOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index e7f801f..8ac99c9 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSTestCEReactions(JSC::Structure*, JSDOMGlobalObject&, Ref<TestCEReactions>&&);
 
@@ -57,7 +58,7 @@ protected:
 
 class JSTestCEReactionsOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 8ef20f3..adad049 100644 (file)
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -256,10 +259,20 @@ EncodedJSValue JSC_HOST_CALL jsTestCEReactionsStringifierPrototypeFunctionToStri
     return IDLOperation<JSTestCEReactionsStringifier>::call<jsTestCEReactionsStringifierPrototypeFunctionToStringBody>(*state, "toString");
 }
 
-bool JSTestCEReactionsStringifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestCEReactionsStringifier::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestCEReactionsStringifier*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestCEReactionsStringifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 63b3e16..05c1edb 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSTestCEReactionsStringifier(JSC::Structure*, JSDOMGlobalObject&, Ref<TestCEReactionsStringifier>&&);
 
@@ -57,7 +58,7 @@ protected:
 
 class JSTestCEReactionsStringifierOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 330a2ce..461c4d9 100644 (file)
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
 #include "JSNode.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -520,10 +523,20 @@ EncodedJSValue JSC_HOST_CALL jsTestCallTracerPrototypeFunctionTestOperationWithD
     return IDLOperation<JSTestCallTracer>::call<jsTestCallTracerPrototypeFunctionTestOperationWithDefaultVariantArgumentBody>(*state, "testOperationWithDefaultVariantArgument");
 }
 
-bool JSTestCallTracerOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestCallTracer::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestCallTracer*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestCallTracerOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index dd75a17..c7bca1f 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSTestCallTracer(JSC::Structure*, JSDOMGlobalObject&, Ref<TestCallTracer>&&);
 
@@ -57,7 +58,7 @@ protected:
 
 class JSTestCallTracerOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index b8b3101..1db0a32 100644 (file)
 #include "JSDOMBuiltinConstructor.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
 #include "TestClassWithJSBuiltinConstructorBuiltins.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -160,10 +163,20 @@ bool setJSTestClassWithJSBuiltinConstructorConstructor(ExecState* state, Encoded
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestClassWithJSBuiltinConstructorOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestClassWithJSBuiltinConstructor::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestClassWithJSBuiltinConstructor*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestClassWithJSBuiltinConstructorOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 061b23a..166ee73 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSTestClassWithJSBuiltinConstructor(JSC::Structure*, JSDOMGlobalObject&, Ref<TestClassWithJSBuiltinConstructor>&&);
 
@@ -57,7 +58,7 @@ protected:
 
 class JSTestClassWithJSBuiltinConstructorOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 84f8df2..e1f9f17 100644 (file)
 #include "JSDOMConstructor.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -158,10 +161,20 @@ bool setJSTestCustomConstructorWithNoInterfaceObjectConstructor(ExecState* state
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestCustomConstructorWithNoInterfaceObjectOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestCustomConstructorWithNoInterfaceObject::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestCustomConstructorWithNoInterfaceObject*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestCustomConstructorWithNoInterfaceObjectOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index d3b2b05..4cde2e9 100644 (file)
@@ -48,6 +48,7 @@ public:
         return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
     }
 
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSTestCustomConstructorWithNoInterfaceObject(JSC::Structure*, JSDOMGlobalObject&, Ref<TestCustomConstructorWithNoInterfaceObject>&&);
 
@@ -56,7 +57,7 @@ protected:
 
 class JSTestCustomConstructorWithNoInterfaceObjectOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 93872a6..76c40fb 100644 (file)
 #include "JSDOMWrapperCache.h"
 #include "JSElement.h"
 #include "JSNodeList.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FrameTracers.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -1258,5 +1261,14 @@ JSC::EncodedJSValue JIT_OPERATION unsafeJsTestDOMJITPrototypeFunctionGetElements
     return JSValue::encode(toJS<IDLInterface<NodeList>>(*state, *castedThis->globalObject(), impl.getElementsByName(WTFMove(elementName))));
 }
 
+void JSTestDOMJIT::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestDOMJIT*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
 
 }
index 0b781e6..35fb126 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
     TestDOMJIT& wrapped() const
     {
         return static_cast<TestDOMJIT&>(Base::wrapped());
index d999032..87b353c 100644 (file)
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
 #include "JSTestSubObj.h"
+#include "ScriptExecutionContext.h"
 #include "Settings.h"
+#include "URL.h"
 #include "WebCoreJSClientData.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -294,10 +297,20 @@ EncodedJSValue JSC_HOST_CALL jsTestEnabledBySettingPrototypeFunctionEnabledBySet
 
 #endif
 
-bool JSTestEnabledBySettingOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestEnabledBySetting::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestEnabledBySetting*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestEnabledBySettingOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 9ff3705..ca1ebb6 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::HasStaticPropertyTable | Base::StructureFlags;
 protected:
@@ -59,7 +60,7 @@ protected:
 
 class JSTestEnabledBySettingOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 8f1f9b4..55dea8e 100644 (file)
@@ -29,6 +29,9 @@
 #include "JSDOMConvertStrings.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -303,6 +306,15 @@ EncodedJSValue jsTestEventConstructorAttr3(ExecState* state, EncodedJSValue this
 
 #endif
 
+void JSTestEventConstructor::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestEventConstructor*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
 #if ENABLE(BINDING_INTEGRITY)
 #if PLATFORM(WIN)
 #pragma warning(disable: 4483)
index e104ced..9755360 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
     TestEventConstructor& wrapped() const
     {
         return static_cast<TestEventConstructor&>(Base::wrapped());
index 17f3d03..308e34f 100644 (file)
@@ -31,6 +31,9 @@
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
 #include "JSNode.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <JavaScriptCore/PropertyNameArray.h>
 #include <wtf/GetPtr.h>
@@ -246,6 +249,15 @@ EncodedJSValue JSC_HOST_CALL jsTestEventTargetPrototypeFunctionItem(ExecState* s
     return IDLOperation<JSTestEventTarget>::call<jsTestEventTargetPrototypeFunctionItemBody>(*state, "item");
 }
 
+void JSTestEventTarget::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestEventTarget*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
 #if ENABLE(BINDING_INTEGRITY)
 #if PLATFORM(WIN)
 #pragma warning(disable: 4483)
index 9ac2220..eb86395 100644 (file)
@@ -53,6 +53,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
     TestEventTarget& wrapped() const
     {
         return static_cast<TestEventTarget&>(Base::wrapped());
index 348190e..238a48f 100644 (file)
 #include "JSDOMConvertStrings.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -177,10 +180,20 @@ EncodedJSValue jsTestExceptionName(ExecState* state, EncodedJSValue thisValue, P
     return IDLAttribute<JSTestException>::get<jsTestExceptionNameGetter, CastedThisErrorBehavior::Assert>(*state, thisValue, "name");
 }
 
-bool JSTestExceptionOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestException::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestException*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestExceptionOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 59c8d4c..ab25de7 100644 (file)
@@ -50,6 +50,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSTestException(JSC::Structure*, JSDOMGlobalObject&, Ref<TestException>&&);
 
@@ -58,7 +59,7 @@ protected:
 
 class JSTestExceptionOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 708ef66..34238bc 100644 (file)
@@ -28,7 +28,9 @@
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
 #include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -183,10 +185,21 @@ EncodedJSValue jsTestGenerateIsReachableASecretAttribute(ExecState* state, Encod
     return IDLAttribute<JSTestGenerateIsReachable>::get<jsTestGenerateIsReachableASecretAttributeGetter, CastedThisErrorBehavior::Assert>(*state, thisValue, "aSecretAttribute");
 }
 
-bool JSTestGenerateIsReachableOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestGenerateIsReachable::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestGenerateIsReachable*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestGenerateIsReachableOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     auto* jsTestGenerateIsReachable = jsCast<JSTestGenerateIsReachable*>(handle.slot()->asCell());
     TestGenerateIsReachable* root = &jsTestGenerateIsReachable->wrapped();
+    if (UNLIKELY(reason))
+        *reason = "Reachable from TestGenerateIsReachable";
     return visitor.containsOpaqueRoot(root);
 }
 
index c788ce1..0065023 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSTestGenerateIsReachable(JSC::Structure*, JSDOMGlobalObject&, Ref<TestGenerateIsReachable>&&);
 
@@ -57,7 +58,7 @@ protected:
 
 class JSTestGenerateIsReachableOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 561d514..bda32c3 100644 (file)
 #include "JSDOMWrapperCache.h"
 #include "RuntimeEnabledFeatures.h"
 #include "ScriptExecutionContext.h"
+#include "URL.h"
 #include "WebCoreJSClientData.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -568,10 +570,20 @@ EncodedJSValue JSC_HOST_CALL jsTestGlobalObjectInstanceFunctionTestFeatureGetSec
 
 #endif
 
-bool JSTestGlobalObjectOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestGlobalObject::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestGlobalObject*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestGlobalObjectOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index fe261f5..7fd4875 100644 (file)
@@ -51,6 +51,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::HasStaticPropertyTable | Base::StructureFlags;
 protected:
@@ -61,7 +62,7 @@ protected:
 
 class JSTestGlobalObjectOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index efd18c9..66078bd 100644 (file)
 #include "JSDOMConvertStrings.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
 #include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <JavaScriptCore/PropertyNameArray.h>
 #include <wtf/GetPtr.h>
@@ -246,10 +248,20 @@ bool setJSTestIndexedSetterNoIdentifierConstructor(ExecState* state, EncodedJSVa
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestIndexedSetterNoIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestIndexedSetterNoIdentifier::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestIndexedSetterNoIdentifier*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestIndexedSetterNoIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 866c415..b7aa998 100644 (file)
@@ -55,6 +55,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -65,7 +66,7 @@ protected:
 
 class JSTestIndexedSetterNoIdentifierOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 0119e6b..6203cc0 100644 (file)
 #include "JSDOMConvertStrings.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
 #include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <JavaScriptCore/PropertyNameArray.h>
 #include <wtf/GetPtr.h>
@@ -246,10 +248,20 @@ bool setJSTestIndexedSetterThrowingExceptionConstructor(ExecState* state, Encode
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestIndexedSetterThrowingExceptionOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestIndexedSetterThrowingException::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestIndexedSetterThrowingException*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestIndexedSetterThrowingExceptionOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 088c4bb..29ad2be 100644 (file)
@@ -55,6 +55,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -65,7 +66,7 @@ protected:
 
 class JSTestIndexedSetterThrowingExceptionOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 8c2974e..3fdc560 100644 (file)
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
 #include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <JavaScriptCore/PropertyNameArray.h>
 #include <wtf/GetPtr.h>
@@ -278,10 +280,20 @@ EncodedJSValue JSC_HOST_CALL jsTestIndexedSetterWithIdentifierPrototypeFunctionI
     return IDLOperation<JSTestIndexedSetterWithIdentifier>::call<jsTestIndexedSetterWithIdentifierPrototypeFunctionIndexedSetterBody>(*state, "indexedSetter");
 }
 
-bool JSTestIndexedSetterWithIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestIndexedSetterWithIdentifier::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestIndexedSetterWithIdentifier*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestIndexedSetterWithIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 83ebf52..040dfaa 100644 (file)
@@ -55,6 +55,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -65,7 +66,7 @@ protected:
 
 class JSTestIndexedSetterWithIdentifierOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index b7dee1a..4c64c19 100644 (file)
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
 #include "TestSupplemental.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -984,12 +987,25 @@ EncodedJSValue JSC_HOST_CALL jsTestInterfaceConstructorFunctionSupplementalMetho
 
 #endif
 
-bool JSTestInterfaceOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestInterface::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestInterface*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestInterfaceOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     auto* jsTestInterface = jsCast<JSTestInterface*>(handle.slot()->asCell());
-    if (jsTestInterface->wrapped().hasPendingActivity())
+    if (jsTestInterface->wrapped().hasPendingActivity()) {
+        if (UNLIKELY(reason))
+            *reason = "ActiveDOMObject with pending activity";
         return true;
+     }
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index be94dc5..a55a4e1 100644 (file)
@@ -53,6 +53,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 
     // Custom attributes
 #if ENABLE(Condition22) || ENABLE(Condition23)
@@ -83,7 +84,7 @@ protected:
 
 class JSTestInterfaceOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 11a78d7..55ffd67 100644 (file)
 #include "JSDOMConvertStrings.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -177,10 +180,20 @@ EncodedJSValue jsTestInterfaceLeadingUnderscoreReadonly(ExecState* state, Encode
     return IDLAttribute<JSTestInterfaceLeadingUnderscore>::get<jsTestInterfaceLeadingUnderscoreReadonlyGetter, CastedThisErrorBehavior::Assert>(*state, thisValue, "readonly");
 }
 
-bool JSTestInterfaceLeadingUnderscoreOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestInterfaceLeadingUnderscore::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestInterfaceLeadingUnderscore*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestInterfaceLeadingUnderscoreOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index cd206ca..4cc8d8c 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSTestInterfaceLeadingUnderscore(JSC::Structure*, JSDOMGlobalObject&, Ref<TestInterfaceLeadingUnderscore>&&);
 
@@ -57,7 +58,7 @@ protected:
 
 class JSTestInterfaceLeadingUnderscoreOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 78c3ff9..979c0f8 100644 (file)
 #include "JSDOMIterator.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/BuiltinNames.h>
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -230,10 +233,20 @@ JSC::EncodedJSValue JSC_HOST_CALL jsTestIterablePrototypeFunctionForEach(JSC::Ex
     return IDLOperation<JSTestIterable>::call<jsTestIterablePrototypeFunctionForEachCaller>(*state, "forEach");
 }
 
-bool JSTestIterableOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestIterable::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestIterable*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestIterableOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 4630d7e..6489f26 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSTestIterable(JSC::Structure*, JSDOMGlobalObject&, Ref<TestIterable>&&);
 
@@ -57,7 +58,7 @@ protected:
 
 class JSTestIterableOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index e0d8389..50ada8c 100644 (file)
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
 #include "JSMediaQueryListListener.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -186,10 +189,20 @@ EncodedJSValue JSC_HOST_CALL jsTestMediaQueryListListenerPrototypeFunctionMethod
     return IDLOperation<JSTestMediaQueryListListener>::call<jsTestMediaQueryListListenerPrototypeFunctionMethodBody>(*state, "method");
 }
 
-bool JSTestMediaQueryListListenerOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestMediaQueryListListener::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestMediaQueryListListener*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestMediaQueryListListenerOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index d34bbde..d0375e3 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSTestMediaQueryListListener(JSC::Structure*, JSDOMGlobalObject&, Ref<TestMediaQueryListListener>&&);
 
@@ -57,7 +58,7 @@ protected:
 
 class JSTestMediaQueryListListenerOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 17cf7e5..3187d2d 100644 (file)
 #include "JSDOMConvertStrings.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
 #include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <JavaScriptCore/PropertyNameArray.h>
 #include <wtf/GetPtr.h>
@@ -312,10 +314,20 @@ bool setJSTestNamedAndIndexedSetterNoIdentifierConstructor(ExecState* state, Enc
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestNamedAndIndexedSetterNoIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedAndIndexedSetterNoIdentifier::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedAndIndexedSetterNoIdentifier*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedAndIndexedSetterNoIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 2b82b09..10390d9 100644 (file)
@@ -55,6 +55,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -65,7 +66,7 @@ protected:
 
 class JSTestNamedAndIndexedSetterNoIdentifierOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index d3c324a..d27194e 100644 (file)
 #include "JSDOMConvertStrings.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
 #include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <JavaScriptCore/PropertyNameArray.h>
 #include <wtf/GetPtr.h>
@@ -312,10 +314,20 @@ bool setJSTestNamedAndIndexedSetterThrowingExceptionConstructor(ExecState* state
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestNamedAndIndexedSetterThrowingExceptionOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedAndIndexedSetterThrowingException::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedAndIndexedSetterThrowingException*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedAndIndexedSetterThrowingExceptionOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 3cdb6dc..1bfd74c 100644 (file)
@@ -55,6 +55,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -65,7 +66,7 @@ protected:
 
 class JSTestNamedAndIndexedSetterThrowingExceptionOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 99574b2..b1f36d7 100644 (file)
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
 #include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <JavaScriptCore/PropertyNameArray.h>
 #include <wtf/GetPtr.h>
@@ -366,10 +368,20 @@ EncodedJSValue JSC_HOST_CALL jsTestNamedAndIndexedSetterWithIdentifierPrototypeF
     return IDLOperation<JSTestNamedAndIndexedSetterWithIdentifier>::call<jsTestNamedAndIndexedSetterWithIdentifierPrototypeFunctionIndexedSetterBody>(*state, "indexedSetter");
 }
 
-bool JSTestNamedAndIndexedSetterWithIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedAndIndexedSetterWithIdentifier::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedAndIndexedSetterWithIdentifier*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedAndIndexedSetterWithIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index ddcb655..7e88cf4 100644 (file)
@@ -55,6 +55,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -65,7 +66,7 @@ protected:
 
 class JSTestNamedAndIndexedSetterWithIdentifierOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index e3ce421..9298a17 100644 (file)
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMNamedConstructor.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -197,12 +200,25 @@ bool setJSTestNamedConstructorConstructor(ExecState* state, EncodedJSValue thisV
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestNamedConstructorOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedConstructor::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedConstructor*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedConstructorOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     auto* jsTestNamedConstructor = jsCast<JSTestNamedConstructor*>(handle.slot()->asCell());
-    if (jsTestNamedConstructor->wrapped().hasPendingActivity())
+    if (jsTestNamedConstructor->wrapped().hasPendingActivity()) {
+        if (UNLIKELY(reason))
+            *reason = "ActiveDOMObject with pending activity";
         return true;
+     }
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 5732bc0..25c51bd 100644 (file)
@@ -50,6 +50,7 @@ public:
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
     static JSC::JSValue getNamedConstructor(JSC::VM&, JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSTestNamedConstructor(JSC::Structure*, JSDOMGlobalObject&, Ref<TestNamedConstructor>&&);
 
@@ -58,7 +59,7 @@ protected:
 
 class JSTestNamedConstructorOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 524a603..57d67c2 100644 (file)
 #include "JSDOMConvertStrings.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -225,10 +228,20 @@ bool setJSTestNamedDeleterNoIdentifierConstructor(ExecState* state, EncodedJSVal
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestNamedDeleterNoIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedDeleterNoIdentifier::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedDeleterNoIdentifier*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedDeleterNoIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index fc93e80..2479f4f 100644 (file)
@@ -54,6 +54,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -64,7 +65,7 @@ protected:
 
 class JSTestNamedDeleterNoIdentifierOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index e07c9a1..d0fcd2f 100644 (file)
 #include "JSDOMConvertStrings.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -239,10 +242,20 @@ bool setJSTestNamedDeleterThrowingExceptionConstructor(ExecState* state, Encoded
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestNamedDeleterThrowingExceptionOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedDeleterThrowingException::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedDeleterThrowingException*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedDeleterThrowingExceptionOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index cde11c6..7bde9b1 100644 (file)
@@ -54,6 +54,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -64,7 +65,7 @@ protected:
 
 class JSTestNamedDeleterThrowingExceptionOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 6a59741..251410b 100644 (file)
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -256,10 +259,20 @@ EncodedJSValue JSC_HOST_CALL jsTestNamedDeleterWithIdentifierPrototypeFunctionNa
     return IDLOperation<JSTestNamedDeleterWithIdentifier>::call<jsTestNamedDeleterWithIdentifierPrototypeFunctionNamedDeleterBody>(*state, "namedDeleter");
 }
 
-bool JSTestNamedDeleterWithIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedDeleterWithIdentifier::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedDeleterWithIdentifier*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedDeleterWithIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 0141708..4ef3ec1 100644 (file)
@@ -54,6 +54,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -64,7 +65,7 @@ protected:
 
 class JSTestNamedDeleterWithIdentifierOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 1f83a9a..2758ca1 100644 (file)
 #include "JSDOMConvertStrings.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
 #include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <JavaScriptCore/PropertyNameArray.h>
 #include <wtf/GetPtr.h>
@@ -243,10 +245,20 @@ bool setJSTestNamedDeleterWithIndexedGetterConstructor(ExecState* state, Encoded
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestNamedDeleterWithIndexedGetterOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedDeleterWithIndexedGetter::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedDeleterWithIndexedGetter*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedDeleterWithIndexedGetterOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 153db7e..b3d5017 100644 (file)
@@ -54,6 +54,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -64,7 +65,7 @@ protected:
 
 class JSTestNamedDeleterWithIndexedGetterOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 5d34b7b..ca2bf61 100644 (file)
 #include "JSDOMConvertStrings.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -204,10 +207,20 @@ bool setJSTestNamedGetterCallWithConstructor(ExecState* state, EncodedJSValue th
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestNamedGetterCallWithOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedGetterCallWith::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedGetterCallWith*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedGetterCallWithOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 6bd2e8d..36db017 100644 (file)
@@ -52,6 +52,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -62,7 +63,7 @@ protected:
 
 class JSTestNamedGetterCallWithOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 9b0c4b7..9120f4b 100644 (file)
 #include "JSDOMConvertStrings.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -204,10 +207,20 @@ bool setJSTestNamedGetterNoIdentifierConstructor(ExecState* state, EncodedJSValu
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestNamedGetterNoIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedGetterNoIdentifier::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedGetterNoIdentifier*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedGetterNoIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 73180d5..d37c83f 100644 (file)
@@ -52,6 +52,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -62,7 +63,7 @@ protected:
 
 class JSTestNamedGetterNoIdentifierOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index c752fd0..3bb7d3b 100644 (file)
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -232,10 +235,20 @@ EncodedJSValue JSC_HOST_CALL jsTestNamedGetterWithIdentifierPrototypeFunctionGet
     return IDLOperation<JSTestNamedGetterWithIdentifier>::call<jsTestNamedGetterWithIdentifierPrototypeFunctionGetterNameBody>(*state, "getterName");
 }
 
-bool JSTestNamedGetterWithIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedGetterWithIdentifier::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedGetterWithIdentifier*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedGetterWithIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index f57b9d5..0d55fef 100644 (file)
@@ -52,6 +52,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -62,7 +63,7 @@ protected:
 
 class JSTestNamedGetterWithIdentifierOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 48c0711..cbd5d31 100644 (file)
 #include "JSDOMConvertStrings.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -266,10 +269,20 @@ bool setJSTestNamedSetterNoIdentifierConstructor(ExecState* state, EncodedJSValu
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestNamedSetterNoIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedSetterNoIdentifier::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedSetterNoIdentifier*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedSetterNoIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 4544c51..637570f 100644 (file)
@@ -55,6 +55,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -65,7 +66,7 @@ protected:
 
 class JSTestNamedSetterNoIdentifierOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 2b7dc95..9fcbf69 100644 (file)
 #include "JSDOMConvertStrings.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -266,10 +269,20 @@ bool setJSTestNamedSetterThrowingExceptionConstructor(ExecState* state, EncodedJ
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestNamedSetterThrowingExceptionOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedSetterThrowingException::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedSetterThrowingException*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedSetterThrowingExceptionOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index ef4a26d..5b1713c 100644 (file)
@@ -55,6 +55,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -65,7 +66,7 @@ protected:
 
 class JSTestNamedSetterThrowingExceptionOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index e659eb3..b8a9fad 100644 (file)
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -297,10 +300,20 @@ EncodedJSValue JSC_HOST_CALL jsTestNamedSetterWithIdentifierPrototypeFunctionNam
     return IDLOperation<JSTestNamedSetterWithIdentifier>::call<jsTestNamedSetterWithIdentifierPrototypeFunctionNamedSetterBody>(*state, "namedSetter");
 }
 
-bool JSTestNamedSetterWithIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedSetterWithIdentifier::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedSetterWithIdentifier*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedSetterWithIdentifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index bc885b3..0ec45f4 100644 (file)
@@ -55,6 +55,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -65,7 +66,7 @@ protected:
 
 class JSTestNamedSetterWithIdentifierOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 64a5ca6..1714775 100644 (file)
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
 #include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <JavaScriptCore/PropertyNameArray.h>
 #include <wtf/GetPtr.h>
@@ -340,10 +342,20 @@ EncodedJSValue JSC_HOST_CALL jsTestNamedSetterWithIndexedGetterPrototypeFunction
     return IDLOperation<JSTestNamedSetterWithIndexedGetter>::call<jsTestNamedSetterWithIndexedGetterPrototypeFunctionIndexedSetterBody>(*state, "indexedSetter");
 }
 
-bool JSTestNamedSetterWithIndexedGetterOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedSetterWithIndexedGetter::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedSetterWithIndexedGetter*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedSetterWithIndexedGetterOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 2f24520..dbebe4c 100644 (file)
@@ -55,6 +55,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -65,7 +66,7 @@ protected:
 
 class JSTestNamedSetterWithIndexedGetterOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index cccdeb1..103f91c 100644 (file)
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
 #include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <JavaScriptCore/PropertyNameArray.h>
 #include <wtf/GetPtr.h>
@@ -390,10 +392,20 @@ EncodedJSValue JSC_HOST_CALL jsTestNamedSetterWithIndexedGetterAndSetterPrototyp
     return IDLOperation<JSTestNamedSetterWithIndexedGetterAndSetter>::call<jsTestNamedSetterWithIndexedGetterAndSetterPrototypeFunctionIndexedSetterOverloadDispatcher>(*state, "indexedSetter");
 }
 
-bool JSTestNamedSetterWithIndexedGetterAndSetterOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedSetterWithIndexedGetterAndSetter::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedSetterWithIndexedGetterAndSetter*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedSetterWithIndexedGetterAndSetterOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 45060c7..c160d68 100644 (file)
@@ -55,6 +55,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -65,7 +66,7 @@ protected:
 
 class JSTestNamedSetterWithIndexedGetterAndSetterOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index fb2514c..fc122a2 100644 (file)
 #include "JSDOMConvertStrings.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -253,10 +256,20 @@ bool setJSTestNamedSetterWithOverrideBuiltinsConstructor(ExecState* state, Encod
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestNamedSetterWithOverrideBuiltinsOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedSetterWithOverrideBuiltins::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedSetterWithOverrideBuiltins*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedSetterWithOverrideBuiltinsOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index d084ca5..fe037c3 100644 (file)
@@ -55,6 +55,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpure | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -65,7 +66,7 @@ protected:
 
 class JSTestNamedSetterWithOverrideBuiltinsOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index c54943a..4807b36 100644 (file)
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -335,10 +338,20 @@ EncodedJSValue JSC_HOST_CALL jsTestNamedSetterWithUnforgablePropertiesInstanceFu
     return IDLOperation<JSTestNamedSetterWithUnforgableProperties>::call<jsTestNamedSetterWithUnforgablePropertiesInstanceFunctionUnforgeableOperationBody>(*state, "unforgeableOperation");
 }
 
-bool JSTestNamedSetterWithUnforgablePropertiesOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedSetterWithUnforgableProperties::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedSetterWithUnforgableProperties*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedSetterWithUnforgablePropertiesOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 964a17d..a16868f 100644 (file)
@@ -55,6 +55,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpureForPropertyAbsence | JSC::HasStaticPropertyTable | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -65,7 +66,7 @@ protected:
 
 class JSTestNamedSetterWithUnforgablePropertiesOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 4982e17..dd51930 100644 (file)
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -322,10 +325,20 @@ EncodedJSValue JSC_HOST_CALL jsTestNamedSetterWithUnforgablePropertiesAndOverrid
     return IDLOperation<JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins>::call<jsTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltinsInstanceFunctionUnforgeableOperationBody>(*state, "unforgeableOperation");
 }
 
-bool JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltinsOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltinsOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 385b0a5..9e4267c 100644 (file)
@@ -55,6 +55,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpure | JSC::HasStaticPropertyTable | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -65,7 +66,7 @@ protected:
 
 class JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltinsOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 246b17a..de96d3b 100644 (file)
@@ -34,7 +34,9 @@
 #include "JSDOMWrapperCache.h"
 #include "RuntimeEnabledFeatures.h"
 #include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/BuiltinNames.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <JavaScriptCore/ObjectConstructor.h>
 #include <wtf/GetPtr.h>
@@ -412,6 +414,15 @@ EncodedJSValue JSC_HOST_CALL jsTestNodePrototypeFunctionToJSON(ExecState* state)
     return IDLOperation<JSTestNode>::call<jsTestNodePrototypeFunctionToJSONBody>(*state, "toJSON");
 }
 
+void JSTestNode::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestNode*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
 #if ENABLE(BINDING_INTEGRITY)
 #if PLATFORM(WIN)
 #pragma warning(disable: 4483)
index 8f8d2c3..e7c25d5 100644 (file)
@@ -49,6 +49,7 @@ public:
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
     static JSC::JSObject* serialize(JSC::ExecState&, JSTestNode& thisObject, JSDOMGlobalObject&, JSC::ThrowScope&);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
     TestNode& wrapped() const
     {
         return static_cast<TestNode&>(Base::wrapped());
index 5deebbb..e4d9885 100644 (file)
@@ -82,6 +82,7 @@
 #include <JavaScriptCore/ArrayPrototype.h>
 #include <JavaScriptCore/BuiltinNames.h>
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/IteratorOperations.h>
 #include <JavaScriptCore/JSArray.h>
 #include <JavaScriptCore/JSCInlines.h>
@@ -8389,10 +8390,20 @@ void JSTestObj::visitChildren(JSCell* cell, SlotVisitor& visitor)
     visitor.append(thisObject->m_cachedAttribute2);
 }
 
-bool JSTestObjOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestObj::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestObj*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestObjOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 8542443..1e1b467 100644 (file)
@@ -62,6 +62,7 @@ public:
     mutable JSC::WriteBarrier<JSC::Unknown> m_cachedAttribute2;
     static void visitChildren(JSCell*, JSC::SlotVisitor&);
 
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 
     // Custom attributes
     JSC::JSValue customAttr(JSC::ExecState&) const;
@@ -84,7 +85,7 @@ protected:
 
 class JSTestObjOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 38aa4ab..eaf092a 100644 (file)
 #include "JSDOMConvertVariadic.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -249,10 +252,20 @@ bool setJSTestOverloadedConstructorsConstructor(ExecState* state, EncodedJSValue
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestOverloadedConstructorsOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestOverloadedConstructors::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestOverloadedConstructors*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestOverloadedConstructorsOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index b78d83a..289a635 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSTestOverloadedConstructors(JSC::Structure*, JSDOMGlobalObject&, Ref<TestOverloadedConstructors>&&);
 
@@ -57,7 +58,7 @@ protected:
 
 class JSTestOverloadedConstructorsOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 1dc8bc9..058143b 100644 (file)
 #include "JSDOMConvertStrings.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/IteratorOperations.h>
 #include <JavaScriptCore/JSArray.h>
 #include <JavaScriptCore/JSCInlines.h>
@@ -205,10 +208,20 @@ bool setJSTestOverloadedConstructorsWithSequenceConstructor(ExecState* state, En
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestOverloadedConstructorsWithSequenceOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestOverloadedConstructorsWithSequence::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestOverloadedConstructorsWithSequence*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestOverloadedConstructorsWithSequenceOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index e358daa..e0f54eb 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSTestOverloadedConstructorsWithSequence(JSC::Structure*, JSDOMGlobalObject&, Ref<TestOverloadedConstructorsWithSequence>&&);
 
@@ -57,7 +58,7 @@ protected:
 
 class JSTestOverloadedConstructorsWithSequenceOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index d890d3e..0db774a 100644 (file)
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
 #include "JSNode.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -235,10 +238,20 @@ EncodedJSValue JSC_HOST_CALL jsTestOverrideBuiltinsPrototypeFunctionNamedItem(Ex
     return IDLOperation<JSTestOverrideBuiltins>::call<jsTestOverrideBuiltinsPrototypeFunctionNamedItemBody>(*state, "namedItem");
 }
 
-bool JSTestOverrideBuiltinsOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestOverrideBuiltins::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestOverrideBuiltins*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestOverrideBuiltinsOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index f5be072..f2a26af 100644 (file)
@@ -52,6 +52,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::GetOwnPropertySlotIsImpure | JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetOwnPropertySlot | JSC::OverridesGetPropertyNames | Base::StructureFlags;
 protected:
@@ -62,7 +63,7 @@ protected:
 
 class JSTestOverrideBuiltinsOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index de490c5..2836247 100644 (file)
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
 #include "JSPluginElementFunctions.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -208,10 +211,20 @@ bool setJSTestPluginInterfaceConstructor(ExecState* state, EncodedJSValue thisVa
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
-bool JSTestPluginInterfaceOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestPluginInterface::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestPluginInterface*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestPluginInterfaceOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 37a30ec..6ddb79c 100644 (file)
@@ -56,6 +56,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 public:
     static const unsigned StructureFlags = JSC::InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | JSC::OverridesGetCallData | JSC::OverridesGetOwnPropertySlot | Base::StructureFlags;
 protected:
@@ -66,7 +67,7 @@ protected:
 
 class JSTestPluginInterfaceOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 07a93b3..8b0f51e 100644 (file)
@@ -33,6 +33,9 @@
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMGlobalObject.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -285,6 +288,15 @@ EncodedJSValue jsTestPromiseRejectionEventReason(ExecState* state, EncodedJSValu
     return IDLAttribute<JSTestPromiseRejectionEvent>::get<jsTestPromiseRejectionEventReasonGetter, CastedThisErrorBehavior::Assert>(*state, thisValue, "reason");
 }
 
+void JSTestPromiseRejectionEvent::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestPromiseRejectionEvent*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
 #if ENABLE(BINDING_INTEGRITY)
 #if PLATFORM(WIN)
 #pragma warning(disable: 4483)
index 4426824..f4695fa 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
     TestPromiseRejectionEvent& wrapped() const
     {
         return static_cast<TestPromiseRejectionEvent&>(Base::wrapped());
index 2b2cc62..e3c1cc2 100644 (file)
 #include "JSTestException.h"
 #include "JSTestSerializationIndirectInheritance.h"
 #include "JSTestSerializationInheritFinal.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <JavaScriptCore/ObjectConstructor.h>
 #include <wtf/GetPtr.h>
@@ -542,10 +545,20 @@ EncodedJSValue JSC_HOST_CALL jsTestSerializationPrototypeFunctionToJSON(ExecStat
     return IDLOperation<JSTestSerialization>::call<jsTestSerializationPrototypeFunctionToJSONBody>(*state, "toJSON");
 }
 
-bool JSTestSerializationOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestSerialization::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestSerialization*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestSerializationOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 009d66f..d272847 100644 (file)
@@ -50,6 +50,7 @@ public:
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
     static JSC::JSObject* serialize(JSC::ExecState&, JSTestSerialization& thisObject, JSDOMGlobalObject&, JSC::ThrowScope&);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSTestSerialization(JSC::Structure*, JSDOMGlobalObject&, Ref<TestSerialization>&&);
 
@@ -58,7 +59,7 @@ protected:
 
 class JSTestSerializationOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 86e1cd9..96368f3 100644 (file)
@@ -25,6 +25,9 @@
 #include "JSDOMConstructorNotConstructable.h"
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -146,5 +149,14 @@ bool setJSTestSerializationIndirectInheritanceConstructor(ExecState* state, Enco
     return prototype->putDirect(vm, vm.propertyNames->constructor, JSValue::decode(encodedValue));
 }
 
+void JSTestSerializationIndirectInheritance::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestSerializationIndirectInheritance*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
 
 }
index a1335fa..0dd045a 100644 (file)
@@ -48,6 +48,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
     TestSerializationIndirectInheritance& wrapped() const
     {
         return static_cast<TestSerializationIndirectInheritance&>(Base::wrapped());
index a77a588..37f654d 100644 (file)
@@ -28,6 +28,9 @@
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <JavaScriptCore/ObjectConstructor.h>
 #include <wtf/GetPtr.h>
@@ -221,5 +224,14 @@ EncodedJSValue JSC_HOST_CALL jsTestSerializationInheritPrototypeFunctionToJSON(E
     return IDLOperation<JSTestSerializationInherit>::call<jsTestSerializationInheritPrototypeFunctionToJSONBody>(*state, "toJSON");
 }
 
+void JSTestSerializationInherit::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestSerializationInherit*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
 
 }
index 0673854..02873a2 100644 (file)
@@ -49,6 +49,7 @@ public:
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
     static JSC::JSObject* serialize(JSC::ExecState&, JSTestSerializationInherit& thisObject, JSDOMGlobalObject&, JSC::ThrowScope&);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
     TestSerializationInherit& wrapped() const
     {
         return static_cast<TestSerializationInherit&>(Base::wrapped());
index 52504f1..5e86910 100644 (file)
@@ -28,6 +28,9 @@
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <JavaScriptCore/ObjectConstructor.h>
 #include <wtf/GetPtr.h>
@@ -255,5 +258,14 @@ EncodedJSValue JSC_HOST_CALL jsTestSerializationInheritFinalPrototypeFunctionToJ
     return IDLOperation<JSTestSerializationInheritFinal>::call<jsTestSerializationInheritFinalPrototypeFunctionToJSONBody>(*state, "toJSON");
 }
 
+void JSTestSerializationInheritFinal::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestSerializationInheritFinal*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
 
 }
index d16f85f..7c47575 100644 (file)
@@ -49,6 +49,7 @@ public:
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
     static JSC::JSObject* serialize(JSC::ExecState&, JSTestSerializationInheritFinal& thisObject, JSDOMGlobalObject&, JSC::ThrowScope&);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
     TestSerializationInheritFinal& wrapped() const
     {
         return static_cast<TestSerializationInheritFinal&>(Base::wrapped());
index 32af693..342ed1a 100644 (file)
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
 #include "JSMessagePort.h"
+#include "ScriptExecutionContext.h"
 #include "SerializedScriptValue.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSArray.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
@@ -345,10 +348,20 @@ void JSTestSerializedScriptValueInterface::visitChildren(JSCell* cell, SlotVisit
     visitor.append(thisObject->m_cachedReadonlyValue);
 }
 
-bool JSTestSerializedScriptValueInterfaceOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestSerializedScriptValueInterface::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestSerializedScriptValueInterface*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestSerializedScriptValueInterfaceOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index 069a1d5..feaec89 100644 (file)
@@ -55,6 +55,7 @@ public:
     mutable JSC::WriteBarrier<JSC::Unknown> m_cachedReadonlyValue;
     static void visitChildren(JSCell*, JSC::SlotVisitor&);
 
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSTestSerializedScriptValueInterface(JSC::Structure*, JSDOMGlobalObject&, Ref<TestSerializedScriptValueInterface>&&);
 
@@ -63,7 +64,7 @@ protected:
 
 class JSTestSerializedScriptValueInterfaceOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index ac39bc8..ff2cad2 100644 (file)
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -179,10 +182,20 @@ EncodedJSValue JSC_HOST_CALL jsTestStringifierPrototypeFunctionToString(ExecStat
     return IDLOperation<JSTestStringifier>::call<jsTestStringifierPrototypeFunctionToStringBody>(*state, "toString");
 }
 
-bool JSTestStringifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestStringifier::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestStringifier*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestStringifierOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index f432bee..55381f7 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSTestStringifier(JSC::Structure*, JSDOMGlobalObject&, Ref<TestStringifier>&&);
 
@@ -57,7 +58,7 @@ protected:
 
 class JSTestStringifierOwner : public JSC::WeakHandleOwner {
 public:
-    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
+    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&, const char**);
     virtual void finalize(JSC::Handle<JSC::Unknown>, void* context);
 };
 
index 1e4730e..89edfb4 100644 (file)
 #include "JSDOMExceptionHandling.h"
 #include "JSDOMOperation.h"
 #include "JSDOMWrapperCache.h"
+#include "ScriptExecutionContext.h"
+#include "URL.h"
 #include <JavaScriptCore/FunctionPrototype.h>
+#include <JavaScriptCore/HeapSnapshotBuilder.h>
 #include <JavaScriptCore/JSCInlines.h>
 #include <wtf/GetPtr.h>
 #include <wtf/PointerPreparations.h>
@@ -179,10 +182,20 @@ EncodedJSValue JSC_HOST_CALL jsTestStringifierAnonymousOperationPrototypeFunctio
     return IDLOperation<JSTestStringifierAnonymousOperation>::call<jsTestStringifierAnonymousOperationPrototypeFunctionToStringBody>(*state, "toString");
 }
 
-bool JSTestStringifierAnonymousOperationOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor)
+void JSTestStringifierAnonymousOperation::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder)
+{
+    auto* thisObject = jsCast<JSTestStringifierAnonymousOperation*>(cell);
+    builder.setWrappedObjectForCell(cell, &thisObject->wrapped());
+    if (thisObject->scriptExecutionContext())
+        builder.setLabelForCell(cell, String::format("url %s", thisObject->scriptExecutionContext()->url().string().utf8().data()));
+    Base::heapSnapshot(cell, builder);
+}
+
+bool JSTestStringifierAnonymousOperationOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason)
 {
     UNUSED_PARAM(handle);
     UNUSED_PARAM(visitor);
+    UNUSED_PARAM(reason);
     return false;
 }
 
index f29d3e0..14aa0ed 100644 (file)
@@ -49,6 +49,7 @@ public:
     }
 
     static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*);
+    static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&);
 protected:
     JSTestStringifierAnonymousOperation(JSC::Structure*, JSDOMGlobalObject&, Ref<TestStringifierAnonymousOperation>&&);
 
@@