WebKit Bugzilla
Attachment 347982 Details for
Bug 186416
: Add support for dumping GC heap snapshots, and a viewer
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-186416-20180823180632.patch (text/plain), 343.56 KB, created by
Simon Fraser (smfr)
on 2018-08-23 18:06:32 PDT
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Simon Fraser (smfr)
Created:
2018-08-23 18:06:32 PDT
Size:
343.56 KB
patch
obsolete
>Subversion Revision: 235242 >diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog >index a53407616ebf05a2fa792bb0bf22a9221d526e74..1b64432979a32d850a78c490842b6d1c6499f422 100644 >--- a/Source/JavaScriptCore/ChangeLog >+++ b/Source/JavaScriptCore/ChangeLog >@@ -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 Michael Saboff <msaboff@apple.com> > > YARR: Need to JIT compile a RegExp before using containsNestedSubpatterns flag >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index d300016200038a04943585e6946c1e04e75f85e3..4619a9b204707eb7a1a84d0608c64e1769be37ad 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -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 Eric Carlson <eric.carlson@apple.com> > > [MediaStream] Store video preset sizes in a map >diff --git a/Source/WebInspectorUI/ChangeLog b/Source/WebInspectorUI/ChangeLog >index 646875d092b90aa0e42766367cb2cc6e38535713..f971fadfe2e6e98a42eff70590839426e7fb75e6 100644 >--- a/Source/WebInspectorUI/ChangeLog >+++ b/Source/WebInspectorUI/ChangeLog >@@ -1,3 +1,29 @@ >+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. >+ >+ * UserInterface/Workers/HeapSnapshot/HeapSnapshot.js: >+ (HeapSnapshot): >+ > 2018-08-23 Devin Rousso <drousso@apple.com> > > Web Inspector: `console.inspect(sessionStorage)` first time does not show Session Storage content view if Storage tab was previously unvisited >diff --git a/Source/JavaScriptCore/API/JSAPIWrapperObject.mm b/Source/JavaScriptCore/API/JSAPIWrapperObject.mm >index 979ff9b9ed0af2170423ccf9452d1a9a6d0fefbd..8a84bf77b3e2dee1060696ba3717f5d6418cb0ac 100644 >--- a/Source/JavaScriptCore/API/JSAPIWrapperObject.mm >+++ b/Source/JavaScriptCore/API/JSAPIWrapperObject.mm >@@ -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 >diff --git a/Source/JavaScriptCore/API/JSManagedValue.mm b/Source/JavaScriptCore/API/JSManagedValue.mm >index 29c717db3b3d1d18571855b8e13e67e58a44cbde..c545fad6d58c5651749f5c91d1c119f933a40295 100644 >--- a/Source/JavaScriptCore/API/JSManagedValue.mm >+++ b/Source/JavaScriptCore/API/JSManagedValue.mm >@@ -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 @@ @interface JSManagedValue (PrivateMethods) > - (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); > } >diff --git a/Source/JavaScriptCore/API/glib/JSAPIWrapperObjectGLib.cpp b/Source/JavaScriptCore/API/glib/JSAPIWrapperObjectGLib.cpp >index 18dd13eb70f6d1057eba63f23fceebdc2ff3012c..87d198ccb2f8f80650369632fe5cd0decc4dee1d 100644 >--- a/Source/JavaScriptCore/API/glib/JSAPIWrapperObjectGLib.cpp >+++ b/Source/JavaScriptCore/API/glib/JSAPIWrapperObjectGLib.cpp >@@ -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 >diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt >index f610d720486be1781fc2ca1aa08783f1b8124201..fb1d0cc6b246a7a6a5d7ec0921927327e195994b 100644 >--- a/Source/JavaScriptCore/CMakeLists.txt >+++ b/Source/JavaScriptCore/CMakeLists.txt >@@ -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 >diff --git a/Source/JavaScriptCore/heap/ConservativeRoots.h b/Source/JavaScriptCore/heap/ConservativeRoots.h >index 0f9a42a6fcd694f0a9efeb10f32062246f96410d..83e5ce4694267c3143f08b44b0a861df450ce1a6 100644 >--- a/Source/JavaScriptCore/heap/ConservativeRoots.h >+++ b/Source/JavaScriptCore/heap/ConservativeRoots.h >@@ -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; > } >diff --git a/Source/JavaScriptCore/heap/Heap.cpp b/Source/JavaScriptCore/heap/Heap.cpp >index c782fcbb7051dbd65b13dedfa526626b67c73c5f..e0baee52fd4c92ea723f4751b872e01f5013b1f7 100644 >--- a/Source/JavaScriptCore/heap/Heap.cpp >+++ b/Source/JavaScriptCore/heap/Heap.cpp >@@ -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. >diff --git a/Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp b/Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp >index 624935a7b33f2c9f5e638df649e0dbb17695effd..aa7fce2fca476ad2128b23f33740c14c7f50557c 100644 >--- a/Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp >+++ b/Source/JavaScriptCore/heap/HeapSnapshotBuilder.cpp >@@ -37,24 +37,33 @@ > #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) { >+ 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(); > } >diff --git a/Source/JavaScriptCore/heap/HeapSnapshotBuilder.h b/Source/JavaScriptCore/heap/HeapSnapshotBuilder.h >index ae7f0bd0c3e423145643d73dd22ff5c8048ec18a..d69869298b36eb0e10e606c0a55421350a03caa7 100644 >--- a/Source/JavaScriptCore/heap/HeapSnapshotBuilder.h >+++ b/Source/JavaScriptCore/heap/HeapSnapshotBuilder.h >@@ -25,6 +25,7 @@ > > #pragma once > >+#include "SlotVisitor.h" > #include <functional> > #include <wtf/Lock.h> > #include <wtf/Vector.h> >@@ -33,10 +34,13 @@ > > 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 >diff --git a/Source/JavaScriptCore/heap/SlotVisitor.cpp b/Source/JavaScriptCore/heap/SlotVisitor.cpp >index e737f39450e90c5425eb3a146c39245d8e96554e..33c37fc6e89b28b6347869dbe0dac77db1eab357 100644 >--- a/Source/JavaScriptCore/heap/SlotVisitor.cpp >+++ b/Source/JavaScriptCore/heap/SlotVisitor.cpp >@@ -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); > } >diff --git a/Source/JavaScriptCore/heap/SlotVisitor.h b/Source/JavaScriptCore/heap/SlotVisitor.h >index e8a27743a6c63b12ad99773abd260d839ad31731..ee590efa057957a5998be1dc69aa3d051b73137c 100644 >--- a/Source/JavaScriptCore/heap/SlotVisitor.h >+++ b/Source/JavaScriptCore/heap/SlotVisitor.h >@@ -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 >diff --git a/Source/JavaScriptCore/heap/WeakBlock.cpp b/Source/JavaScriptCore/heap/WeakBlock.cpp >index f328f96c451a5153b89d5b3c4ae424880675f0c3..323ce6ffac688ae14b10dc84c85d122df021fba8 100644 >--- a/Source/JavaScriptCore/heap/WeakBlock.cpp >+++ b/Source/JavaScriptCore/heap/WeakBlock.cpp >@@ -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); >+ } > } > } > >diff --git a/Source/JavaScriptCore/heap/WeakHandleOwner.cpp b/Source/JavaScriptCore/heap/WeakHandleOwner.cpp >index 044518f7a31307cf366c18fa3b2e67fde805fe1c..4572405977f5971a17775de4b9e41ad6c4e27ad1 100644 >--- a/Source/JavaScriptCore/heap/WeakHandleOwner.cpp >+++ b/Source/JavaScriptCore/heap/WeakHandleOwner.cpp >@@ -37,7 +37,7 @@ WeakHandleOwner::~WeakHandleOwner() > { > } > >-bool WeakHandleOwner::isReachableFromOpaqueRoots(Handle<Unknown>, void*, SlotVisitor&) >+bool WeakHandleOwner::isReachableFromOpaqueRoots(Handle<Unknown>, void*, SlotVisitor&, const char**) > { > return false; > } >diff --git a/Source/JavaScriptCore/heap/WeakHandleOwner.h b/Source/JavaScriptCore/heap/WeakHandleOwner.h >index 219a9c59189dd1413e4ea6e724d7da1a36505db1..450456f40169a7a45640b5e6554768edd415e92f 100644 >--- a/Source/JavaScriptCore/heap/WeakHandleOwner.h >+++ b/Source/JavaScriptCore/heap/WeakHandleOwner.h >@@ -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); > }; > >diff --git a/Source/JavaScriptCore/runtime/SimpleTypedArrayController.cpp b/Source/JavaScriptCore/runtime/SimpleTypedArrayController.cpp >index a25028cd752f83f7ad666783fe62bc9a510c7a36..6afe2309f14a21f38d33e31219bb5709322b9c0e 100644 >--- a/Source/JavaScriptCore/runtime/SimpleTypedArrayController.cpp >+++ b/Source/JavaScriptCore/runtime/SimpleTypedArrayController.cpp >@@ -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()); > } >diff --git a/Source/JavaScriptCore/runtime/SimpleTypedArrayController.h b/Source/JavaScriptCore/runtime/SimpleTypedArrayController.h >index d2b03c2639590d37ecd12c6a998d3569bae279a6..33d089f617bd88cbe4df81c411bdf4e40c77d510 100644 >--- a/Source/JavaScriptCore/runtime/SimpleTypedArrayController.h >+++ b/Source/JavaScriptCore/runtime/SimpleTypedArrayController.h >@@ -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; > }; > >diff --git a/Source/JavaScriptCore/tools/JSDollarVM.cpp b/Source/JavaScriptCore/tools/JSDollarVM.cpp >index dde310911c0dc43c1b67c35292d108677fbd2295..eb57c784c98180462d4a8e43c86b50baaae8493b 100644 >--- a/Source/JavaScriptCore/tools/JSDollarVM.cpp >+++ b/Source/JavaScriptCore/tools/JSDollarVM.cpp >@@ -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()); > } >diff --git a/Source/WebCore/bindings/js/DOMGCOutputConstraint.cpp b/Source/WebCore/bindings/js/DOMGCOutputConstraint.cpp >index 6886343a77534848d4b59c34eff65bfed7c7cf25..7d27da466b85c5d5c9a15b7391c13f9652c7c8d4 100644 >--- a/Source/WebCore/bindings/js/DOMGCOutputConstraint.cpp >+++ b/Source/WebCore/bindings/js/DOMGCOutputConstraint.cpp >@@ -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); > }; >diff --git a/Source/WebCore/bindings/js/GCController.cpp b/Source/WebCore/bindings/js/GCController.cpp >index 43856f5ee5cafc23f563d5fc765499a6f6ac21e5..d251d2ece1f18b240a88bbfb3a22c2c24f80f6cd 100644 >--- a/Source/WebCore/bindings/js/GCController.cpp >+++ b/Source/WebCore/bindings/js/GCController.cpp >@@ -27,9 +27,14 @@ > #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 >diff --git a/Source/WebCore/bindings/js/GCController.h b/Source/WebCore/bindings/js/GCController.h >index ef6d1386f72d50819031a6c1d32438afde90f8f1..0ce45950c5391f60696fd40d89d927da386a87d3 100644 >--- a/Source/WebCore/bindings/js/GCController.h >+++ b/Source/WebCore/bindings/js/GCController.h >@@ -51,6 +51,8 @@ public: > private: > GCController(); // Use singleton() instead. > >+ void dumpHeap(); >+ > void gcTimerFired(); > Timer m_GCTimer; > }; >diff --git a/Source/WebCore/bindings/js/JSCSSRuleListCustom.cpp b/Source/WebCore/bindings/js/JSCSSRuleListCustom.cpp >index f0550aa6443ee9d44655b95c09720e462dcd7bfe..020e458c05fb350d0351d04dc175e11935067cba 100644 >--- a/Source/WebCore/bindings/js/JSCSSRuleListCustom.cpp >+++ b/Source/WebCore/bindings/js/JSCSSRuleListCustom.cpp >@@ -36,15 +36,25 @@ > 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; > } > >diff --git a/Source/WebCore/bindings/js/JSCallbackData.cpp b/Source/WebCore/bindings/js/JSCallbackData.cpp >index 9ba0eaf19faddc1c4be1a530aeb447dcb39eef1f..186762a90d2853547462318c25caea46856fd9ca 100644 >--- a/Source/WebCore/bindings/js/JSCallbackData.cpp >+++ b/Source/WebCore/bindings/js/JSCallbackData.cpp >@@ -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); > } > >diff --git a/Source/WebCore/bindings/js/JSCallbackData.h b/Source/WebCore/bindings/js/JSCallbackData.h >index 60192e61422d123a2297927b5bdaff03d447d765..a5bc9542e54752334af0d790305263e94fe5bdda 100644 >--- a/Source/WebCore/bindings/js/JSCallbackData.h >+++ b/Source/WebCore/bindings/js/JSCallbackData.h >@@ -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; >diff --git a/Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp b/Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp >index f1018f4d57dfb3b4256d171edb68fda183c480a8..4d500429807753580491facec170e6ba7770250f 100644 >--- a/Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp >+++ b/Source/WebCore/bindings/js/JSCanvasRenderingContext2DCustom.cpp >@@ -22,8 +22,11 @@ > > 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); >diff --git a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp b/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp >index a761db123e62c8bd97f0e78172c16e06a227b427..496d2e7d6f2468feb6d81a2d84ed26d837a36eca 100644 >--- a/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp >+++ b/Source/WebCore/bindings/js/JSDOMWindowCustom.cpp >@@ -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) > { >diff --git a/Source/WebCore/bindings/js/JSDeprecatedCSSOMValueCustom.cpp b/Source/WebCore/bindings/js/JSDeprecatedCSSOMValueCustom.cpp >index 35c75fe347126421775609c4428cacf0a3cdf103..f86fee63c76b956b3f3c2bcc1d265fa87769559c 100644 >--- a/Source/WebCore/bindings/js/JSDeprecatedCSSOMValueCustom.cpp >+++ b/Source/WebCore/bindings/js/JSDeprecatedCSSOMValueCustom.cpp >@@ -35,11 +35,15 @@ > 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())); > } > >diff --git a/Source/WebCore/bindings/js/JSDocumentCustom.cpp b/Source/WebCore/bindings/js/JSDocumentCustom.cpp >index 6605f1e7ff2f9576ff89fe70f1a348ee4c8bdf3c..5687e4d78c62d08f194b93824646979699c17f8d 100644 >--- a/Source/WebCore/bindings/js/JSDocumentCustom.cpp >+++ b/Source/WebCore/bindings/js/JSDocumentCustom.cpp >@@ -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 >diff --git a/Source/WebCore/bindings/js/JSMicrotaskCallback.h b/Source/WebCore/bindings/js/JSMicrotaskCallback.h >index c9b8e64b854b443ffd3f97bc23e25c8d1664c26a..1a0b53fc343d5c5b14f737e258b37a64d8244e4c 100644 >--- a/Source/WebCore/bindings/js/JSMicrotaskCallback.h >+++ b/Source/WebCore/bindings/js/JSMicrotaskCallback.h >@@ -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; > }; > >diff --git a/Source/WebCore/bindings/js/JSMutationObserverCustom.cpp b/Source/WebCore/bindings/js/JSMutationObserverCustom.cpp >index 4ddef8afc87b01dc6a551d1b92dd2ff19430dbe3..195ad015cd599b4561ae5ea10fc09346674bf557 100644 >--- a/Source/WebCore/bindings/js/JSMutationObserverCustom.cpp >+++ b/Source/WebCore/bindings/js/JSMutationObserverCustom.cpp >@@ -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; > } >diff --git a/Source/WebCore/bindings/js/JSNavigatorCustom.cpp b/Source/WebCore/bindings/js/JSNavigatorCustom.cpp >index 49cda064dc66f2bb38901a2e3e6e3195739c0f81..21699004aa751edbb46f190d57f4308c04087fda 100644 >--- a/Source/WebCore/bindings/js/JSNavigatorCustom.cpp >+++ b/Source/WebCore/bindings/js/JSNavigatorCustom.cpp >@@ -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()); >diff --git a/Source/WebCore/bindings/js/JSNodeCustom.cpp b/Source/WebCore/bindings/js/JSNodeCustom.cpp >index 09a70f22e88cf1cb987ae7d7181cfe2595359422..c485e303d5a36e31105f83fd574d5c3117ab2490 100644 >--- a/Source/WebCore/bindings/js/JSNodeCustom.cpp >+++ b/Source/WebCore/bindings/js/JSNodeCustom.cpp >@@ -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 >diff --git a/Source/WebCore/bindings/js/JSNodeListCustom.cpp b/Source/WebCore/bindings/js/JSNodeListCustom.cpp >index 9a1c873446953e321fb8e5569c94f3481ccef8f8..7f6d9e72da50795fef35ffd62bd2688c5a10eaf2 100644 >--- a/Source/WebCore/bindings/js/JSNodeListCustom.cpp >+++ b/Source/WebCore/bindings/js/JSNodeListCustom.cpp >@@ -37,17 +37,32 @@ > 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; > } > >diff --git a/Source/WebCore/bindings/js/JSOffscreenCanvasRenderingContext2DCustom.cpp b/Source/WebCore/bindings/js/JSOffscreenCanvasRenderingContext2DCustom.cpp >index 33b08e78a2c2f76574ad8c52d230f6ca0774a529..34d7a099b36678753f54f5ddfc648974b27d4a7f 100644 >--- a/Source/WebCore/bindings/js/JSOffscreenCanvasRenderingContext2DCustom.cpp >+++ b/Source/WebCore/bindings/js/JSOffscreenCanvasRenderingContext2DCustom.cpp >@@ -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); >diff --git a/Source/WebCore/bindings/js/JSPerformanceObserverCustom.cpp b/Source/WebCore/bindings/js/JSPerformanceObserverCustom.cpp >index 37e95171122ddda05dd376b61eea1f8e1d3c729f..6efa3dcd2e7ebd35ac1b8627bc2bdb8080a1ca35 100644 >--- a/Source/WebCore/bindings/js/JSPerformanceObserverCustom.cpp >+++ b/Source/WebCore/bindings/js/JSPerformanceObserverCustom.cpp >@@ -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(); > } > >diff --git a/Source/WebCore/bindings/js/JSPopStateEventCustom.cpp b/Source/WebCore/bindings/js/JSPopStateEventCustom.cpp >index 722dd9e43403f9dc3432960cf737f4c8f1ad601e..d31bdc779b917ec5e5821f6f89f40bbfe02ada88 100644 >--- a/Source/WebCore/bindings/js/JSPopStateEventCustom.cpp >+++ b/Source/WebCore/bindings/js/JSPopStateEventCustom.cpp >@@ -37,6 +37,7 @@ > #include <JavaScriptCore/JSCJSValueInlines.h> > > namespace WebCore { >+using namespace JSC; > > JSValue JSPopStateEvent::state(ExecState& state) const > { >diff --git a/Source/WebCore/bindings/js/JSTextTrackCueCustom.cpp b/Source/WebCore/bindings/js/JSTextTrackCueCustom.cpp >index c2944513f95e93d0b1aae2a7b50673d813e3a4e3..3c487952c3865a0770a47dabfcd5ce8fab5fd4dd 100644 >--- a/Source/WebCore/bindings/js/JSTextTrackCueCustom.cpp >+++ b/Source/WebCore/bindings/js/JSTextTrackCueCustom.cpp >@@ -38,20 +38,26 @@ > 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())); > } > >diff --git a/Source/WebCore/bindings/js/WebCoreTypedArrayController.cpp b/Source/WebCore/bindings/js/WebCoreTypedArrayController.cpp >index 84fb3c4f15a8c8380be35b15e61f8e76f5a972a2..20b5f98168dbde3a7f19069319335fa9a54adf5b 100644 >--- a/Source/WebCore/bindings/js/WebCoreTypedArrayController.cpp >+++ b/Source/WebCore/bindings/js/WebCoreTypedArrayController.cpp >@@ -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()); > } >diff --git a/Source/WebCore/bindings/js/WebCoreTypedArrayController.h b/Source/WebCore/bindings/js/WebCoreTypedArrayController.h >index 25260122ebf1197edcf1274971961ef229344736..e0bb956b9944ba22bce97a29676cf81dd0a2b841 100644 >--- a/Source/WebCore/bindings/js/WebCoreTypedArrayController.h >+++ b/Source/WebCore/bindings/js/WebCoreTypedArrayController.h >@@ -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; > }; > >diff --git a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm >index 873ed6b02de17f182bcd6ec3022d0d5a7310c784..7f4ac10c9e8af8bdc6dbc865cc7bbfe4a642f3dc 100644 >--- a/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm >+++ b/Source/WebCore/bindings/scripts/CodeGeneratorJS.pm >@@ -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"); >diff --git a/Source/WebCore/bindings/scripts/IDLAttributes.json b/Source/WebCore/bindings/scripts/IDLAttributes.json >index a9991c284bfdfe1809e70bdd3781aa070fd1c42b..73fe7a25f9cd19dcac7e35743fe6ff5fffae21c8 100644 >--- a/Source/WebCore/bindings/scripts/IDLAttributes.json >+++ b/Source/WebCore/bindings/scripts/IDLAttributes.json >@@ -118,6 +118,9 @@ > "CustomGetter": { > "contextsAllowed": ["attribute"] > }, >+ "CustomHeapSnapshot": { >+ "contextsAllowed": ["interface"] >+ }, > "CustomIndexedSetter": { > "contextsAllowed": ["interface"] > }, >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSInterfaceName.cpp b/Source/WebCore/bindings/scripts/test/JS/JSInterfaceName.cpp >index d8c10a2a9b89af090f8fa2edfd134e41f169d060..11795875351bf2e363c914edd741351b742a29ac 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSInterfaceName.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSInterfaceName.cpp >@@ -25,7 +25,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSInterfaceName.h b/Source/WebCore/bindings/scripts/test/JS/JSInterfaceName.h >index 9ddbbc3e8dd8a6903bc6fd23fe94d93a8c436bf4..c60a9177586c63b802b283e58a3c0fa0784a6094 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSInterfaceName.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSInterfaceName.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSMapLike.cpp b/Source/WebCore/bindings/scripts/test/JS/JSMapLike.cpp >index 761bbf46d9a6e4160b567214fa956295857b649e..6d7faa2b77dad6a473d09ca6ff29b3896c5c4a2b 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSMapLike.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSMapLike.cpp >@@ -30,8 +30,11 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSMapLike.h b/Source/WebCore/bindings/scripts/test/JS/JSMapLike.h >index d80402d84f6ccc98e4ee2d0f1e2c39842ee878f9..206cd2ef23f51ff266dd948f86b0104b8709c213 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSMapLike.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSMapLike.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSReadOnlyMapLike.cpp b/Source/WebCore/bindings/scripts/test/JS/JSReadOnlyMapLike.cpp >index c52d101f4b0100e773fe67b52d9611ac83e06579..008dceba42c6d4c6fb2c9a913ffb6d33fd0f1c83 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSReadOnlyMapLike.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSReadOnlyMapLike.cpp >@@ -30,8 +30,11 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSReadOnlyMapLike.h b/Source/WebCore/bindings/scripts/test/JS/JSReadOnlyMapLike.h >index e2dc79f3e43558e93e56a3503509321ffd25bb1d..b6fbb20bc7e71cfcd8518f4e5509678795a5e4d7 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSReadOnlyMapLike.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSReadOnlyMapLike.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestActiveDOMObject.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestActiveDOMObject.cpp >index 7d4907d15fd2ddb6c7bc3887b0df5cfd4d84bf8b..62916d36bb55a6932262ffa55dc24ce6ee3be863 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestActiveDOMObject.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestActiveDOMObject.cpp >@@ -32,7 +32,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestActiveDOMObject.h b/Source/WebCore/bindings/scripts/test/JS/JSTestActiveDOMObject.h >index 0dd833f749e050ac3ed85affb5baeba6dbd1ebe8..f224633ead1801b470da1bf05b29f02431f2abd2 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestActiveDOMObject.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestActiveDOMObject.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestCEReactions.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestCEReactions.cpp >index 83740bf795107af42c036168d61075cd504302fb..6406be99903d14c1b17108b8fa3d1292e1fc9070 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestCEReactions.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestCEReactions.cpp >@@ -33,7 +33,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestCEReactions.h b/Source/WebCore/bindings/scripts/test/JS/JSTestCEReactions.h >index e7f801fcdc482ebc2ffebba8fd33c4a6f8f7b4bb..8ac99c9e8a54284e54fd285aec90cd385d9060c3 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestCEReactions.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestCEReactions.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestCEReactionsStringifier.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestCEReactionsStringifier.cpp >index 8ef20f352e70cd6bec275379e8bc5c6fdd707dcf..adad049b14c4aa5f25aead9460b1c2bfa619224e 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestCEReactionsStringifier.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestCEReactionsStringifier.cpp >@@ -29,7 +29,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestCEReactionsStringifier.h b/Source/WebCore/bindings/scripts/test/JS/JSTestCEReactionsStringifier.h >index 63b3e163139a6d8c6d6787ca5c85e1b0302daa4c..05c1edb3eb8873491d68fca571e2b8e4d3dd25d1 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestCEReactionsStringifier.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestCEReactionsStringifier.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestCallTracer.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestCallTracer.cpp >index 330a2cec7e031ecabf35e692f4337f2b1551a85a..461c4d96a5f390dc8f190095cb74564a7107a722 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestCallTracer.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestCallTracer.cpp >@@ -36,7 +36,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestCallTracer.h b/Source/WebCore/bindings/scripts/test/JS/JSTestCallTracer.h >index dd75a17258aa3b8b339f6849e5fbc17c34195607..c7bca1f19f13dbdb9ee6c92d3971cb559f1ba41c 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestCallTracer.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestCallTracer.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestClassWithJSBuiltinConstructor.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestClassWithJSBuiltinConstructor.cpp >index b8b3101c99b173dcd35746724754a160f43a6e4f..1db0a32d55e5cb7c0f94c85f2afc9c982b2eb00d 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestClassWithJSBuiltinConstructor.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestClassWithJSBuiltinConstructor.cpp >@@ -25,8 +25,11 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestClassWithJSBuiltinConstructor.h b/Source/WebCore/bindings/scripts/test/JS/JSTestClassWithJSBuiltinConstructor.h >index 061b23af23dac061bde16f509824061336512a79..166ee73b0fc8f83ca65f8dd34f23c0cdb27bb73f 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestClassWithJSBuiltinConstructor.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestClassWithJSBuiltinConstructor.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestCustomConstructorWithNoInterfaceObject.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestCustomConstructorWithNoInterfaceObject.cpp >index 84f8df209e115ce83d88453239f3217866f8b958..e1f9f170a6cd723dbe95584dcf5fad04242cee88 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestCustomConstructorWithNoInterfaceObject.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestCustomConstructorWithNoInterfaceObject.cpp >@@ -25,7 +25,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestCustomConstructorWithNoInterfaceObject.h b/Source/WebCore/bindings/scripts/test/JS/JSTestCustomConstructorWithNoInterfaceObject.h >index d3b2b05211ca482136839f6f36f5068687446e1d..4cde2e9bd02f385b6562a64574105376f6503451 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestCustomConstructorWithNoInterfaceObject.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestCustomConstructorWithNoInterfaceObject.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestDOMJIT.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestDOMJIT.cpp >index 93872a6a01d7deebf8db37549cbbd0f088349e9c..76c40fb04579503ea5b52c47e04960db21999f3a 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestDOMJIT.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestDOMJIT.cpp >@@ -40,7 +40,10 @@ > #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); >+} >+ > > } >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestDOMJIT.h b/Source/WebCore/bindings/scripts/test/JS/JSTestDOMJIT.h >index 0b781e62e3be2f21b389170dadf2ecd31ef01e20..35fb126ec4c6e9a518f8c8f41972016d484130ee 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestDOMJIT.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestDOMJIT.h >@@ -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()); >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledBySetting.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledBySetting.cpp >index d999032ef2e7a2c31148c187a9c95a7de9a8b826..87b353c5b598589d5902b70e64f390721fa92c93 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledBySetting.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledBySetting.cpp >@@ -29,9 +29,12 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledBySetting.h b/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledBySetting.h >index 9ff37051e0a115f6b816dd6227a1e3409fe83ace..ca1ebb63eea784882233ae5a65e470260f9cf2a3 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledBySetting.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestEnabledBySetting.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.cpp >index 8f1f9b4fc9454248d791ff9d07fa3595a052d7cd..55dea8eeab07f7505f1a6bdfcc241b671cbdea56 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.cpp >@@ -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) >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.h b/Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.h >index e104cedd7f9818acee1990f0a70b4a7817d6fb43..9755360e26a8c1748ef8de0a95ca1f0dc7858832 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestEventConstructor.h >@@ -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()); >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.cpp >index 17f3d03f0bd4a770f1e9e86299a051efc08d41ec..308e34f001ac2d8b353e8051d8ec51bbadd6ee0a 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.cpp >@@ -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) >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.h b/Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.h >index 9ac22200d88b39e04256f24479c5f777f18eebda..eb863955e5c49ff99a0451050f74d46f1124992f 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestEventTarget.h >@@ -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()); >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestException.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestException.cpp >index 348190e93b1fd58cac0dbb5e50a6061ab6351c16..238a48f7c65f0d3cb6f1e03f7a29e9e829ebcbcf 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestException.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestException.cpp >@@ -27,7 +27,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestException.h b/Source/WebCore/bindings/scripts/test/JS/JSTestException.h >index 59c8d4c2af7d19a61972bb7b1c59175bcb8c9715..ab25de750382978a00c5e094b8463b5d731f7da1 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestException.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestException.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestGenerateIsReachable.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestGenerateIsReachable.cpp >index 708ef66d69120b9978dcc998454d0c432dcc2525..34238bc5d213ec499fbe5a255c5618f30685b2dc 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestGenerateIsReachable.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestGenerateIsReachable.cpp >@@ -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); > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestGenerateIsReachable.h b/Source/WebCore/bindings/scripts/test/JS/JSTestGenerateIsReachable.h >index c788ce1ccb7a63aca8adf4b304a6c4b6dc86a937..0065023501d3e8368482cb8ea6a8b7b2dd882e99 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestGenerateIsReachable.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestGenerateIsReachable.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.cpp >index 561d51471bdef373f2ef1a6f83f618320607b476..bda32c37b044bfbd7346b7270a6cab4488c84ea5 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.cpp >@@ -34,8 +34,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.h b/Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.h >index fe261f5ae10a6d05d85835c93603f1d4fde32281..7fd48750c1df4cc275aa56dee7a423906148545d 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestGlobalObject.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterNoIdentifier.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterNoIdentifier.cpp >index efd18c9b6098cbd825f4208dd2064efe07cadef5..66078bd6cb511e1d2f468882582a7f91fbc06bc9 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterNoIdentifier.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterNoIdentifier.cpp >@@ -26,8 +26,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterNoIdentifier.h b/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterNoIdentifier.h >index 866c415953a0e8a3cde28c9466ecb2bfa0e8bea0..b7aa998c868bb6dda46ae300acfdfa534fb19c4f 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterNoIdentifier.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterNoIdentifier.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterThrowingException.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterThrowingException.cpp >index 0119e6bea7a937d5a2615a92f95c71ee848e7f82..6203cc0b987392477a1d9bf7b570cbe37c10e34f 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterThrowingException.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterThrowingException.cpp >@@ -26,8 +26,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterThrowingException.h b/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterThrowingException.h >index 088c4bbf03d88f62be60ff5691c2dd49ccee3c3c..29ad2be67c157c9bbc5391054dc5d465588f76e1 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterThrowingException.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterThrowingException.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterWithIdentifier.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterWithIdentifier.cpp >index 8c2974e8edb448eac6f97892b8e75f47ba4434fe..3fdc56040350e1321db24697b7272557dd1a908d 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterWithIdentifier.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterWithIdentifier.cpp >@@ -28,8 +28,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterWithIdentifier.h b/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterWithIdentifier.h >index 83ebf5299e98ef94f7f9fd8c4cf7191481cc28d0..040dfaaae0c54555c25a004fe7f91f28b490a124 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterWithIdentifier.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestIndexedSetterWithIdentifier.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestInterface.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestInterface.cpp >index b7dee1a8eafa4d94c9a18898fe12947024c5e202..4c64c19eb85826029f60b925b319e11a703d94f7 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestInterface.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestInterface.cpp >@@ -32,8 +32,11 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestInterface.h b/Source/WebCore/bindings/scripts/test/JS/JSTestInterface.h >index be94dc5c3b6c1899b854e6797f838e31b221c19a..a55a4e1aea426de16a7b8acb2276169c8d4b5cc0 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestInterface.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestInterface.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestInterfaceLeadingUnderscore.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestInterfaceLeadingUnderscore.cpp >index 11a78d7943ace14c58c98c7f05a2ab120056fbb7..55ffd67a150fe32c5eda35e32d246f6932e8ebaa 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestInterfaceLeadingUnderscore.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestInterfaceLeadingUnderscore.cpp >@@ -27,7 +27,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestInterfaceLeadingUnderscore.h b/Source/WebCore/bindings/scripts/test/JS/JSTestInterfaceLeadingUnderscore.h >index cd206ca31b003000156aece6d8913958c3325cb3..4cc8d8c728cdd898934c2e0a5ccf8c211ba176f4 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestInterfaceLeadingUnderscore.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestInterfaceLeadingUnderscore.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestIterable.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestIterable.cpp >index 78c3ff921791d15bf00ad1ffa4f0ac8101beb008..979c0f8cc5bad846f0961cbda264e0cb76c1830c 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestIterable.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestIterable.cpp >@@ -27,8 +27,11 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestIterable.h b/Source/WebCore/bindings/scripts/test/JS/JSTestIterable.h >index 4630d7e286a0781e56e1216816c7ae011436cec1..6489f26100c7cf67ed58c8a36e29a540de9a006b 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestIterable.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestIterable.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestMediaQueryListListener.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestMediaQueryListListener.cpp >index e0d83898cc9925d439a6624a9347d50d95a78735..50ada8caf0ee6d02bada801b0b698aee959d9360 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestMediaQueryListListener.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestMediaQueryListListener.cpp >@@ -29,7 +29,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestMediaQueryListListener.h b/Source/WebCore/bindings/scripts/test/JS/JSTestMediaQueryListListener.h >index d34bbde576732e43f4b6633fc7711b9105adf361..d0375e3af77feb133d74d48e21d84da29f15e9ab 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestMediaQueryListListener.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestMediaQueryListListener.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterNoIdentifier.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterNoIdentifier.cpp >index 17cf7e5034d2262b580f3025083bd2e2120aab81..3187d2daf3d6e721e7e0085f27ccb22f2b41daf9 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterNoIdentifier.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterNoIdentifier.cpp >@@ -27,8 +27,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterNoIdentifier.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterNoIdentifier.h >index 2b82b0927eec1194f6115136af0e49af9e7547a8..10390d972626a944b3910070bd4a16bcad213c1e 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterNoIdentifier.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterNoIdentifier.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterThrowingException.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterThrowingException.cpp >index d3c324a2d0b90f6aa7978c39275955a2a2aac3ed..d27194e83e6ac776531a9db7730f0574c2dfae1d 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterThrowingException.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterThrowingException.cpp >@@ -27,8 +27,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterThrowingException.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterThrowingException.h >index 3cdb6dc7cf0af377deec11f0ddce8e2202d48042..1bfd74c486cfe217490e31f1e736ff4ba12a4437 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterThrowingException.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterThrowingException.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterWithIdentifier.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterWithIdentifier.cpp >index 99574b20547a301f3b274249bb312b9bf5bbe9b7..b1f36d73e035afe78efe932b14df93ceffba4df2 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterWithIdentifier.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterWithIdentifier.cpp >@@ -29,8 +29,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterWithIdentifier.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterWithIdentifier.h >index ddcb655da9b90b2350156ea0292f0398a9f2293c..7e88cf4d41d725d40b9ff9d1951fef51b1887269 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterWithIdentifier.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedAndIndexedSetterWithIdentifier.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedConstructor.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedConstructor.cpp >index e3ce42191733972e02bcf6404cce6f39fcd5663d..9298a1760c0835266c42eb664864bf64482c7b30 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedConstructor.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedConstructor.cpp >@@ -28,7 +28,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedConstructor.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedConstructor.h >index 5732bc0e447de180bf0800ba2f23329df97e26be..25c51bd7af3fbf8aa6434bed6c533ecdfd30b2ad 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedConstructor.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedConstructor.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.cpp >index 524a60348e2998a4cae7a7048a60a758e16f23aa..57d67c234e26b4ddd0947e402ef89b4502b6dd43 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.cpp >@@ -27,7 +27,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.h >index fc93e802a011ed0492eefffc23abd1b4f0c34c2d..2479f4f8c8b1dc5479db1093c7297105c5a5b493 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterNoIdentifier.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.cpp >index e07c9a1aac87397a7221fe0d696e7359aae0b600..d0fcd2f2b9032495b4b658be9b31b7fe55a0886a 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.cpp >@@ -27,7 +27,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.h >index cde11c68195087221eee36dd51e6535dad286184..7bde9b18964ac2a72fd0e39819432f7df69a7e23 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterThrowingException.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.cpp >index 6a597416ee3403066dcdc98cceddf30de8975453..251410b5faef7004c0116666fce8e1e90a3379a9 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.cpp >@@ -28,7 +28,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.h >index 0141708395045b6f6bcd51a331f0915b2f83fd82..4ef3ec18788c40afc7ac26c9497b37d067bab1a3 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIdentifier.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.cpp >index 1f83a9a67ba88561e3ffd212211f7027b4fdc564..2758ca10a1412c4139b32584f3cf92b403abb014 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.cpp >@@ -27,8 +27,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.h >index 153db7eca306c286430c08e6c7434bbee7f10e17..b3d501787346353e479d7f626179b3a1717731e6 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedDeleterWithIndexedGetter.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterCallWith.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterCallWith.cpp >index 5d34b7b891b4edb5687928ee19313e816bb92e04..ca2bf612acbc2fd4e044a159a76467e5aacab9b2 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterCallWith.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterCallWith.cpp >@@ -27,7 +27,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterCallWith.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterCallWith.h >index 6bd2e8df879970b2d5bfd8f686fbecf8469c7ef3..36db01798c601c9cee889842ddbcec8b3393e7fd 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterCallWith.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterCallWith.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterNoIdentifier.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterNoIdentifier.cpp >index 9b0c4b71cfa7f55e2814d06fd6c0983f580cfdfa..9120f4be7f21b78d2c9bff2db1725a94974bfcd1 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterNoIdentifier.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterNoIdentifier.cpp >@@ -27,7 +27,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterNoIdentifier.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterNoIdentifier.h >index 73180d5e2bb04132d08714f254eae69eb7557cae..d37c83f80b7c79ee99eb3226b591d5406ff88ea0 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterNoIdentifier.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterNoIdentifier.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterWithIdentifier.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterWithIdentifier.cpp >index c752fd00c9a09eda75bbf498cc63d6c780f54637..3bb7d3b7e12f829c88c344babdb486822f57cba2 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterWithIdentifier.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterWithIdentifier.cpp >@@ -28,7 +28,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterWithIdentifier.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterWithIdentifier.h >index f57b9d5fc6e39754d71058a67a18a3d3049cd371..0d55fef234485013f8d761c3c19b3f270b49edc0 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterWithIdentifier.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedGetterWithIdentifier.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterNoIdentifier.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterNoIdentifier.cpp >index 48c07113a4c45d41ea350c4bb2bba67ff8f1a8c5..cbd5d31a6267ea1ee25de0914d61468bfcd925b5 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterNoIdentifier.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterNoIdentifier.cpp >@@ -27,7 +27,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterNoIdentifier.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterNoIdentifier.h >index 4544c51559cf7953304c46c6466abc7c393780f0..637570f216ee383255bc89b4e28ee9ff260aed50 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterNoIdentifier.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterNoIdentifier.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterThrowingException.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterThrowingException.cpp >index 2b7dc95a89d134c154bb35165c566546e1289088..9fcbf697b639ae03ddc0ebb2083ce799f7388353 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterThrowingException.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterThrowingException.cpp >@@ -27,7 +27,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterThrowingException.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterThrowingException.h >index ef4a26d9001f60daa0592032c61ab6563200a901..5b1713c0cf2bfe1a1214b76fb527168eb3ea3491 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterThrowingException.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterThrowingException.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIdentifier.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIdentifier.cpp >index e659eb347538fd7c75c4959731129d539ebefd15..b8a9fade85b4e987c7052a029a9dd8fcda6d3250 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIdentifier.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIdentifier.cpp >@@ -28,7 +28,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIdentifier.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIdentifier.h >index bc885b3ca95728467b1a5b73abe56223a0cc8656..0ec45f40f44e0e272fe2c3673666e37be6e1d96a 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIdentifier.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIdentifier.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetter.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetter.cpp >index 64a5ca632598657941d75652e3392b6cc6d716d9..171477550b0c38459562f6a75c2e83d8315db924 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetter.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetter.cpp >@@ -29,8 +29,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetter.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetter.h >index 2f24520fbf19fea040e112fe79e03144d23a802a..dbebe4c48628457f194f10c4807a351c1d6a727e 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetter.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetter.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetterAndSetter.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetterAndSetter.cpp >index cccdeb12760eb394f059be87e48073d4d488cde8..103f91c1baa2aa39f1e399aafece581191116dee 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetterAndSetter.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetterAndSetter.cpp >@@ -29,8 +29,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetterAndSetter.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetterAndSetter.h >index 45060c755f6575208140dc41eafb66874853a105..c160d68f251a8f6d8523ce3464ebc124e24ed7db 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetterAndSetter.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithIndexedGetterAndSetter.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithOverrideBuiltins.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithOverrideBuiltins.cpp >index fb2514cbdd035475592fc002d5a2bc734882663b..fc122a2e2bbf87ba14b16f70799e6c280f1e4c4d 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithOverrideBuiltins.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithOverrideBuiltins.cpp >@@ -27,7 +27,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithOverrideBuiltins.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithOverrideBuiltins.h >index d084ca5f42145c05ea18d0ca3c15f2fd21c35f61..fe037c31325ec1f4496fce1fd7e9574af69f8f9d 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithOverrideBuiltins.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithOverrideBuiltins.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgableProperties.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgableProperties.cpp >index c54943a3938d0450be87b24244a53e93064b3dc7..4807b36553318e042a9b67b44408119d684ed1de 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgableProperties.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgableProperties.cpp >@@ -29,7 +29,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgableProperties.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgableProperties.h >index 964a17df1268d8464aad9b59c16e1364dc8d4ed4..a16868f2f2c31156e386da03211b1e2f97fc5ef3 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgableProperties.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgableProperties.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins.cpp >index 4982e17064ba1ea40c086c484207b1415bae0e1e..dd51930733b6cdaa49e1f6856b6b71f1e117cade 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins.cpp >@@ -29,7 +29,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins.h >index 385b0a5b60229ba23342200a9aa13169fc2e6c45..9e4267cb60760532e08d19a1d1eb5f69643e9647 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNamedSetterWithUnforgablePropertiesAndOverrideBuiltins.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNode.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestNode.cpp >index 246b17a2449061820180e9fe9dbf16349f7f4cf3..de96d3b8cbf20128b39635db36e0684e9f8667c6 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNode.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNode.cpp >@@ -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) >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestNode.h b/Source/WebCore/bindings/scripts/test/JS/JSTestNode.h >index 8f8d2c388bf7bb97227a4e96866c92f3d11dfde6..e7c25d554ca284fcc251736aeb4d4736a4a474b5 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestNode.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestNode.h >@@ -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()); >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp >index 5deebbb11a1138996f802d1f4a5691741b905557..e4d988597acf92d4fd555ad2fbdf87e04a66d58f 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestObj.cpp >@@ -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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestObj.h b/Source/WebCore/bindings/scripts/test/JS/JSTestObj.h >index 85424433f82e4febd75f635507b0e7af9d58f954..1e1b467ffe17da906e8faf1d3942f88e1a15c1c8 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestObj.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestObj.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructors.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructors.cpp >index 38aa4ab268ba82ddb4f0e4bc1937e5038d2f0b71..eaf092af3f3a71e9d3c4cf6011bfd9192ab21b5a 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructors.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructors.cpp >@@ -31,7 +31,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructors.h b/Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructors.h >index b78d83a78a88a95e0a9faa20c5131e3cc7f55967..289a635abf5196673aa11bd46ab0fadb835ae913 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructors.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructors.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.cpp >index 1dc8bc98288f6cfe06a6b6f8f9ccebf81641f01f..058143ba14bb4eb22409c8d28473753d84f03e7f 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.cpp >@@ -28,7 +28,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.h b/Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.h >index e358daa4d24fc3d23e09cde4ea18e907774c471d..e0f54ebedffe2f2dd1b59ebb0a8739b6b6df1682 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestOverloadedConstructorsWithSequence.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestOverrideBuiltins.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestOverrideBuiltins.cpp >index d890d3e7197e2a056bc77934e61228dd3010a43e..0db774af125f5d1850f79a6171475e137ab7cd61 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestOverrideBuiltins.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestOverrideBuiltins.cpp >@@ -31,7 +31,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestOverrideBuiltins.h b/Source/WebCore/bindings/scripts/test/JS/JSTestOverrideBuiltins.h >index f5be072cc8d6e8a1370546955d9817db0f569082..f2a26af39a46c1879f56cb3cd81c67970cf2dbfa 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestOverrideBuiltins.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestOverrideBuiltins.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestPluginInterface.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestPluginInterface.cpp >index de490c5f09a9aaa8cd1fdba42d1764a4c09af804..28362473a709f59646bbeb604be3da111a0a8ced 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestPluginInterface.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestPluginInterface.cpp >@@ -26,7 +26,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestPluginInterface.h b/Source/WebCore/bindings/scripts/test/JS/JSTestPluginInterface.h >index 37a30ec9bf25254d26d23bcb328b681d24d46f10..6ddb79c5c5cf01ad04febfd7133577c60516f7e8 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestPluginInterface.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestPluginInterface.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestPromiseRejectionEvent.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestPromiseRejectionEvent.cpp >index 07a93b39e11ed663fa2c3e8d6af6077b67db1808..8b0f51ed31941c84aeb24a373be9b17c07f763d7 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestPromiseRejectionEvent.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestPromiseRejectionEvent.cpp >@@ -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) >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestPromiseRejectionEvent.h b/Source/WebCore/bindings/scripts/test/JS/JSTestPromiseRejectionEvent.h >index 442682434b02c1495ed55067fb94f3a23ffb477f..f4695fa4c5ad6665805026918ee9fd6ddc9646e9 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestPromiseRejectionEvent.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestPromiseRejectionEvent.h >@@ -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()); >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestSerialization.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestSerialization.cpp >index 2b2cc626b4908131f99bf2a14bae216c6c4511d8..e3c1cc259a1d27879a267d9f4458d5d489a68792 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestSerialization.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestSerialization.cpp >@@ -35,7 +35,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestSerialization.h b/Source/WebCore/bindings/scripts/test/JS/JSTestSerialization.h >index 009d66f4bcdd4e147bceb9805976b8780a00681e..d272847f7b43d9ed5381367b3541bbbf31347ef8 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestSerialization.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestSerialization.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationIndirectInheritance.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationIndirectInheritance.cpp >index 86e1cd99f6636b5ba90e4bc70e75f669eec4104c..96368f3e6f7bffa8e1a7efbfe7f5063f646dbda7 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationIndirectInheritance.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationIndirectInheritance.cpp >@@ -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); >+} >+ > > } >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationIndirectInheritance.h b/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationIndirectInheritance.h >index a1335fadc915d454cc5a4b88775ed48da5323b80..0dd045ae685eddacf95ecdbab3eddae15c8a5bee 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationIndirectInheritance.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationIndirectInheritance.h >@@ -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()); >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInherit.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInherit.cpp >index a77a5888f3072d185f95a123269b37127e8d1976..37f654ddfcd7c15b78eb671c4aac6785d5400bb7 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInherit.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInherit.cpp >@@ -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); >+} >+ > > } >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInherit.h b/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInherit.h >index 0673854c2f01cce43c8ef8ad1fea4164bb81edd1..02873a26fcc041bc98a64a557b3ec978e3ebca50 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInherit.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInherit.h >@@ -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()); >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInheritFinal.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInheritFinal.cpp >index 52504f18136472a1261b34747905ccb742295be6..5e86910ab52088e317793649d4c6072ac4e72b94 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInheritFinal.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInheritFinal.cpp >@@ -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); >+} >+ > > } >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInheritFinal.h b/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInheritFinal.h >index d16f85fc53fb0de09f91bd69df5e681c9163cd48..7c475752d40c301b244933ce0103968943101682 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInheritFinal.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestSerializationInheritFinal.h >@@ -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()); >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestSerializedScriptValueInterface.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestSerializedScriptValueInterface.cpp >index 32af6939f07a5c899f9bcb3ddc5470f6eb752453..342ed1aa50b46868bfb39166ae0f83d08c6802a8 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestSerializedScriptValueInterface.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestSerializedScriptValueInterface.cpp >@@ -35,8 +35,11 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestSerializedScriptValueInterface.h b/Source/WebCore/bindings/scripts/test/JS/JSTestSerializedScriptValueInterface.h >index 069a1d5de134cf050ffb9a1a87da4f4f14aa1bf8..feaec894c070202752c76f5da4b3eea80fc59a00 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestSerializedScriptValueInterface.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestSerializedScriptValueInterface.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifier.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifier.cpp >index ac39bc84e91dea974c7594d3c31c9707753eea6a..ff2cad2caffc9adf1affa53cdf0977cfc83e8715 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifier.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifier.cpp >@@ -27,7 +27,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifier.h b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifier.h >index f432bee618a68fbfb024efbf87c76dda6d1a62b7..55381f70a52d8d53b33bfe059c78ad5031815284 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifier.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifier.h >@@ -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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierAnonymousOperation.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierAnonymousOperation.cpp >index 1e4730eb20e9495b2da8040d74ea713e36d2eaf9..89edfb4d54ffce29312e9dc370a2904e8638948f 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierAnonymousOperation.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierAnonymousOperation.cpp >@@ -27,7 +27,10 @@ > #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; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierAnonymousOperation.h b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierAnonymousOperation.h >index f29d3e0fde5aae9e97d3d46936e743f96f573ecf..14aa0ed3ee9aced16a57bcb45932282d0d49aa82 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierAnonymousOperation.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierAnonymousOperation.h >@@ -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>&&); > >@@ -57,7 +58,7 @@ protected: > > class JSTestStringifierAnonymousOperationOwner : 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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierNamedOperation.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierNamedOperation.cpp >index d16ed4bb9ecc0e657d0884c317317fe38b852df4..b16b6fb4bd14e24d2dae0f44babea64d84700f44 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierNamedOperation.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierNamedOperation.cpp >@@ -27,7 +27,10 @@ > #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> >@@ -194,10 +197,20 @@ EncodedJSValue JSC_HOST_CALL jsTestStringifierNamedOperationPrototypeFunctionToS > return IDLOperation<JSTestStringifierNamedOperation>::call<jsTestStringifierNamedOperationPrototypeFunctionToStringBody>(*state, "toString"); > } > >-bool JSTestStringifierNamedOperationOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor) >+void JSTestStringifierNamedOperation::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder) >+{ >+ auto* thisObject = jsCast<JSTestStringifierNamedOperation*>(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 JSTestStringifierNamedOperationOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason) > { > UNUSED_PARAM(handle); > UNUSED_PARAM(visitor); >+ UNUSED_PARAM(reason); > return false; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierNamedOperation.h b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierNamedOperation.h >index 860de6cbb5aa6358347bc93e0853c3cd452793f9..5bc10ef65d2194401a53e3e5cc2318fd45fbbe54 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierNamedOperation.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierNamedOperation.h >@@ -49,6 +49,7 @@ public: > } > > static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*); >+ static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&); > protected: > JSTestStringifierNamedOperation(JSC::Structure*, JSDOMGlobalObject&, Ref<TestStringifierNamedOperation>&&); > >@@ -57,7 +58,7 @@ protected: > > class JSTestStringifierNamedOperationOwner : 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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationImplementedAs.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationImplementedAs.cpp >index b8da5d6f5dcc3f1e5c22522aef406073ebf510d1..5a54ac143cb279364e646c3334b0cbc17ae83435 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationImplementedAs.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationImplementedAs.cpp >@@ -27,7 +27,10 @@ > #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> >@@ -194,10 +197,20 @@ EncodedJSValue JSC_HOST_CALL jsTestStringifierOperationImplementedAsPrototypeFun > return IDLOperation<JSTestStringifierOperationImplementedAs>::call<jsTestStringifierOperationImplementedAsPrototypeFunctionToStringBody>(*state, "toString"); > } > >-bool JSTestStringifierOperationImplementedAsOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor) >+void JSTestStringifierOperationImplementedAs::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder) >+{ >+ auto* thisObject = jsCast<JSTestStringifierOperationImplementedAs*>(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 JSTestStringifierOperationImplementedAsOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason) > { > UNUSED_PARAM(handle); > UNUSED_PARAM(visitor); >+ UNUSED_PARAM(reason); > return false; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationImplementedAs.h b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationImplementedAs.h >index 9d407009141bdacb6decc6e3cb3831de80d2c63a..f93ff116869596bf7efc28c9ee6275adffb586ec 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationImplementedAs.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationImplementedAs.h >@@ -49,6 +49,7 @@ public: > } > > static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*); >+ static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&); > protected: > JSTestStringifierOperationImplementedAs(JSC::Structure*, JSDOMGlobalObject&, Ref<TestStringifierOperationImplementedAs>&&); > >@@ -57,7 +58,7 @@ protected: > > class JSTestStringifierOperationImplementedAsOwner : 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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationNamedToString.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationNamedToString.cpp >index c2edea8d3bc91c926a3c77be9c4646629db81123..f2518a71ed6861c5a8caf6beb34c5fcf6bd30def 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationNamedToString.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationNamedToString.cpp >@@ -27,7 +27,10 @@ > #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 jsTestStringifierOperationNamedToStringPrototypeFun > return IDLOperation<JSTestStringifierOperationNamedToString>::call<jsTestStringifierOperationNamedToStringPrototypeFunctionToStringBody>(*state, "toString"); > } > >-bool JSTestStringifierOperationNamedToStringOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor) >+void JSTestStringifierOperationNamedToString::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder) >+{ >+ auto* thisObject = jsCast<JSTestStringifierOperationNamedToString*>(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 JSTestStringifierOperationNamedToStringOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason) > { > UNUSED_PARAM(handle); > UNUSED_PARAM(visitor); >+ UNUSED_PARAM(reason); > return false; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationNamedToString.h b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationNamedToString.h >index ff84566bc8f27480a9706c081fbcb15a8fa2d2ab..12de238e0f628d609fb18c9c05c5f800c6b24ac8 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationNamedToString.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierOperationNamedToString.h >@@ -49,6 +49,7 @@ public: > } > > static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*); >+ static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&); > protected: > JSTestStringifierOperationNamedToString(JSC::Structure*, JSDOMGlobalObject&, Ref<TestStringifierOperationNamedToString>&&); > >@@ -57,7 +58,7 @@ protected: > > class JSTestStringifierOperationNamedToStringOwner : 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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadOnlyAttribute.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadOnlyAttribute.cpp >index d1e37d163d76109c63af969514940771df5e7e53..812372b4d4ee70c423a284334651d1158eaace59 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadOnlyAttribute.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadOnlyAttribute.cpp >@@ -28,7 +28,10 @@ > #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> >@@ -201,10 +204,20 @@ EncodedJSValue JSC_HOST_CALL jsTestStringifierReadOnlyAttributePrototypeFunction > return IDLOperation<JSTestStringifierReadOnlyAttribute>::call<jsTestStringifierReadOnlyAttributePrototypeFunctionToStringBody>(*state, "toString"); > } > >-bool JSTestStringifierReadOnlyAttributeOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor) >+void JSTestStringifierReadOnlyAttribute::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder) >+{ >+ auto* thisObject = jsCast<JSTestStringifierReadOnlyAttribute*>(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 JSTestStringifierReadOnlyAttributeOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason) > { > UNUSED_PARAM(handle); > UNUSED_PARAM(visitor); >+ UNUSED_PARAM(reason); > return false; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadOnlyAttribute.h b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadOnlyAttribute.h >index 342ca59fa1dd818984f8340c9fd1ec44badf0cb5..6dcbdc8d955e5b2deb5eb0125053c22528b5d491 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadOnlyAttribute.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadOnlyAttribute.h >@@ -49,6 +49,7 @@ public: > } > > static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*); >+ static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&); > protected: > JSTestStringifierReadOnlyAttribute(JSC::Structure*, JSDOMGlobalObject&, Ref<TestStringifierReadOnlyAttribute>&&); > >@@ -57,7 +58,7 @@ protected: > > class JSTestStringifierReadOnlyAttributeOwner : 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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadWriteAttribute.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadWriteAttribute.cpp >index aa54121f8c270b317e4bcecb27824eb3bb0301cb..3917b4d9296ba523dc13070619cf4ced38a83fb1 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadWriteAttribute.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadWriteAttribute.cpp >@@ -28,7 +28,10 @@ > #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> >@@ -219,10 +222,20 @@ EncodedJSValue JSC_HOST_CALL jsTestStringifierReadWriteAttributePrototypeFunctio > return IDLOperation<JSTestStringifierReadWriteAttribute>::call<jsTestStringifierReadWriteAttributePrototypeFunctionToStringBody>(*state, "toString"); > } > >-bool JSTestStringifierReadWriteAttributeOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor) >+void JSTestStringifierReadWriteAttribute::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder) >+{ >+ auto* thisObject = jsCast<JSTestStringifierReadWriteAttribute*>(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 JSTestStringifierReadWriteAttributeOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason) > { > UNUSED_PARAM(handle); > UNUSED_PARAM(visitor); >+ UNUSED_PARAM(reason); > return false; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadWriteAttribute.h b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadWriteAttribute.h >index dda4d9d1041ee057077a6263d407623f99d189a7..cb21c3ed45501284a35d2f645cfa9b1035bf9398 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadWriteAttribute.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestStringifierReadWriteAttribute.h >@@ -49,6 +49,7 @@ public: > } > > static JSC::JSValue getConstructor(JSC::VM&, const JSC::JSGlobalObject*); >+ static void heapSnapshot(JSCell*, JSC::HeapSnapshotBuilder&); > protected: > JSTestStringifierReadWriteAttribute(JSC::Structure*, JSDOMGlobalObject&, Ref<TestStringifierReadWriteAttribute>&&); > >@@ -57,7 +58,7 @@ protected: > > class JSTestStringifierReadWriteAttributeOwner : 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); > }; > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestTypedefs.cpp b/Source/WebCore/bindings/scripts/test/JS/JSTestTypedefs.cpp >index ad7fa7fe057229b2bc99d3dfec6b1595598c6e80..1e613aab06524af5560633d8822497fd1c01e0a2 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestTypedefs.cpp >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestTypedefs.cpp >@@ -43,8 +43,11 @@ > #include "JSTestCallbackInterface.h" > #include "JSTestEventTarget.h" > #include "JSTestSubObj.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> >@@ -741,10 +744,20 @@ EncodedJSValue JSC_HOST_CALL jsTestTypedefsPrototypeFunctionMethodWithException( > return IDLOperation<JSTestTypedefs>::call<jsTestTypedefsPrototypeFunctionMethodWithExceptionBody>(*state, "methodWithException"); > } > >-bool JSTestTypedefsOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor) >+void JSTestTypedefs::heapSnapshot(JSCell* cell, HeapSnapshotBuilder& builder) >+{ >+ auto* thisObject = jsCast<JSTestTypedefs*>(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 JSTestTypedefsOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, SlotVisitor& visitor, const char** reason) > { > UNUSED_PARAM(handle); > UNUSED_PARAM(visitor); >+ UNUSED_PARAM(reason); > return false; > } > >diff --git a/Source/WebCore/bindings/scripts/test/JS/JSTestTypedefs.h b/Source/WebCore/bindings/scripts/test/JS/JSTestTypedefs.h >index d8fb0f5c5566717dc7b19c949b9fddeb7eca1e5e..36f2aed83a4a1a617ccfd38285745b0eb895f6ee 100644 >--- a/Source/WebCore/bindings/scripts/test/JS/JSTestTypedefs.h >+++ b/Source/WebCore/bindings/scripts/test/JS/JSTestTypedefs.h >@@ -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 JSTestTypedefsOwner : 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); > }; > >diff --git a/Source/WebCore/dom/Document.idl b/Source/WebCore/dom/Document.idl >index edf34a9e0a71b2bb7b04317e47f047ad93942897..35ff9c057c3e473ff0fe97485ec0dc48cc848b28 100644 >--- a/Source/WebCore/dom/Document.idl >+++ b/Source/WebCore/dom/Document.idl >@@ -35,6 +35,7 @@ typedef ( > Constructor, > ConstructorCallWith=Document, > CustomToJSObject, >+ CustomHeapSnapshot, > DOMJIT, > ExportMacro=WEBCORE_EXPORT, > JSCustomHeader, >diff --git a/Source/WebCore/page/DOMWindow.idl b/Source/WebCore/page/DOMWindow.idl >index a32d0f60839510c1353e802c6dad31c825ff223d..2b4150f6387d057c107eedeff56149d1ac730fe0 100644 >--- a/Source/WebCore/page/DOMWindow.idl >+++ b/Source/WebCore/page/DOMWindow.idl >@@ -33,6 +33,7 @@ typedef USVString CSSOMString; > CustomGetOwnPropertyNames, > CustomGetOwnPropertySlot, > CustomGetPrototype, >+ CustomHeapSnapshot, > CustomPreventExtensions, > CustomProxyToJSObject, > CustomPut, >diff --git a/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js b/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js >index a8f2c3303177a65f869ef0aca50ceb1bbc2f83b0..745774bb39abb60ecc230ce34b1d4f3fdc402d44 100644 >--- a/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js >+++ b/Source/WebInspectorUI/UserInterface/Workers/HeapSnapshot/HeapSnapshot.js >@@ -84,6 +84,7 @@ HeapSnapshot = class HeapSnapshot > > let {version, nodes, nodeClassNames, edges, edgeTypes, edgeNames} = json; > console.assert(version === 1, "Expect JavaScriptCore Heap Snapshot version 1"); >+ console.assert(!type || type === "Inspector", "Expect an Inspector Heap Snapshot"); > > this._nodes = nodes; > this._nodeCount = nodes.length / nodeFieldCount; >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index f038e3809fb958d6ddb93f464f5fe26c2009b7d0..afe75f9a89f251b9190686671b70569385adcbdb 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,20 @@ >+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. >+ >+ 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. >+ > 2018-08-23 Myles C. Maxfield <mmaxfield@apple.com> > > [WHLSL] Allow native types to have type arguments (like "vector<float, 4>") >diff --git a/Tools/GCHeapInspector/gc-heap-inspector.html b/Tools/GCHeapInspector/gc-heap-inspector.html >new file mode 100644 >index 0000000000000000000000000000000000000000..2739a93ae96b1bd123d897a8ea32187263f2c99a >--- /dev/null >+++ b/Tools/GCHeapInspector/gc-heap-inspector.html >@@ -0,0 +1,178 @@ >+<!DOCTYPE html> >+<head> >+ <title>GC Heap Inspector</title> >+ <meta charset="utf8"> >+ <style type="text/css" media="screen"> >+ >+ body { >+ font-family: "Helvetica Neue"; >+ line-height: 1.3; >+ } >+ >+ h1 { >+ margin-bottom: 0.2em; >+ font-size: 32px; >+ } >+ >+ label { >+ font-size: 13px; >+ } >+ >+ #dropTarget { >+ font-size: 12pt; >+ font-weight: bold; >+ color: #888; >+ position: absolute; >+ top: 20px; >+ right: 20px; >+ border: 2px solid rgba(0, 0, 0, 0.3); >+ background-color: rgba(0, 0, 0, 0.1); >+ padding: 10px; >+ border-radius: 10px; >+ } >+ >+ #dropTarget.dragOver { >+ border: 2px solid rgba(0, 0, 0, 0.1); >+ background-color: rgba(0, 0, 0, 0.5); >+ color: #ddd; >+ } >+ >+ details { >+ margin-left: 20px; >+ } >+ >+ ul.path { >+ margin-top: 5px; >+ } >+ >+ ul.instance-list { >+ margin-top: 0.3em; >+ padding-left: 1.2em; >+ list-style-type: none; >+ } >+ >+ .node-id::before { >+ content: '@'; >+ } >+ >+ .node-id { >+ font-size: smaller; >+ color: silver; >+ display: none; /* Remove if you want to see cell identifiers. */ >+ } >+ >+ .node-address, .node-size, .node-label { >+ font-family: monospace; >+ color: gray; >+ } >+ >+ .node-size { >+ display: none; >+ } >+ >+ .node-gc-root { >+ font-size: smaller; >+ color: maroon; >+ } >+ >+ .node-gc-root img { >+ margin: 0 3px; >+ height: 1.4em; >+ width: 1.4em; >+ vertical-align: middle; >+ cursor: pointer; >+ display: none; >+ } >+ >+ .edge::before { >+ content: ' â¹ '; >+ color: gray; >+ } >+ >+ .edge::after { >+ content: ' â¹'; >+ color: gray; >+ } >+ >+ .edge-data { >+ font-family: monospace; >+ color: gray; >+ } >+ >+ ul.path { >+ list-style-type: none; >+ } >+ >+ #description { >+ position: fixed; >+ margin: 300px calc((100vw - 500px) / 2); >+ border: 2px solid rgba(0, 0, 0, 0.3); >+ background-color: rgba(0, 0, 0, 0.1); >+ padding: 20px 50px; >+ border-radius: 10px; >+ width: 500px; >+ } >+ >+ #description > h1 { >+ margin-top: 10px; >+ margin-bottom: 15px; >+ } >+ >+ #description code { >+ display: block; >+ margin: 15px 0; >+ } >+ >+ #description.hidden { >+ display: none; >+ } >+ >+ #uiContainer { >+ display: none; >+ } >+ >+ </style> >+ >+ <script src="script/interface.js"></script> >+ <script src="heap-analysis/HeapSnapshot.js"></script> >+</head> >+<body> >+ <header> >+ <div id="dropTarget">Drop GC heap JSON file here to load.</div> >+ </header> >+ >+ <section id="description"> >+ <h1>GC heap debugger</h2> >+ <p>This page is for analyzing JSON dumps of the GC heap. To debug an issue that you think might be a leaked or abandoned object (often a Document or JSGlobalObject), load the test page, then navigate to about:blank or other simple page. Now simulate a memory warning (to clear the page cache) by issuing the following command in a Terminal window: >+ <code>notifyutil -p org.WebKit.lowMemory</code> >+ >+ You can now inspect the list of live documents via: >+ <code>notifyutil -p com.apple.WebKit.showAllDocuments</code> >+ >+ which prints its output to the system log. If this lists documents other than the current page, you may have a leaked or abandoned Document. To see if the GC heap is referencing that Document, obtain a GC heap dump: >+ <code>notifyutil -p com.apple.WebKit.dumpGCHeap</code> >+ >+ That command will generate a JSON file in /tmp (or equivalent); the file path is dumped to the system log. Drag that file onto the drop target in the top right (or use the ?filename= URL parameter). >+ </p> >+ </section> >+ >+ <section id="uiContainer"> >+ >+ <div id="rooted"> >+ </div> >+ >+ <h1>All paths toâ¦</h1> >+ <div id="all-paths"> >+ </div> >+ >+ <h1>Objects</h1> >+ <section id="categories"> >+ </section> >+ >+ <h1>Roots</h1> >+ <section id="roots"> >+ </section> >+ </section> >+ >+</body> >+</html> >diff --git a/Tools/GCHeapInspector/heap-analysis/HeapSnapshot.js b/Tools/GCHeapInspector/heap-analysis/HeapSnapshot.js >new file mode 100644 >index 0000000000000000000000000000000000000000..727598845a65170ed7e2b8a3bbe920e34c4a3363 >--- /dev/null >+++ b/Tools/GCHeapInspector/heap-analysis/HeapSnapshot.js >@@ -0,0 +1,849 @@ >+/* >+ * Copyright (C) 2011 Google Inc. All rights reserved. >+ * Copyright (C) 2016 Apple Inc. All rights reserved. >+ * >+ * Redistribution and use in source and binary forms, with or without >+ * modification, are permitted provided that the following conditions are >+ * met: >+ * >+ * * Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * * Redistributions in binary form must reproduce the above >+ * copyright notice, this list of conditions and the following disclaimer >+ * in the documentation and/or other materials provided with the >+ * distribution. >+ * * Neither the name of Google Inc. nor the names of its >+ * contributors may be used to endorse or promote products derived from >+ * this software without specific prior written permission. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS >+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR >+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT >+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, >+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT >+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, >+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY >+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT >+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE >+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. >+ */ >+ >+// nodes >+// [<0:id>, <1:size>, <2:classNameTableIndex>, <3:internal>, <4:labelIndex>, <5:address>, <6:wrapped address>] >+let nodeFieldCount = 7; >+const nodeIdOffset = 0; >+const nodeSizeOffset = 1; >+const nodeClassNameOffset = 2; >+const nodeInternalOffset = 3; >+const nodeLabelOffset = 4; >+const nodeAddressOffset = 5; >+const nodeWrappedAddressOffset = 6; >+ >+// edges >+// [<0:fromId>, <1:toId>, <2:typeTableIndex>, <3:edgeDataIndexOrEdgeNameIndex>] >+const edgeFieldCount = 4; >+const edgeFromIdOffset = 0; >+const edgeToIdOffset = 1; >+const edgeTypeOffset = 2; >+const edgeDataOffset = 3; >+ >+// roots >+// [<0:id>, <1:labelIndex>] >+let rootFieldCount = 3; >+const rootIdOffset = 0; >+const rootLabelOffset = 1; >+const reachabilityReasonOffset = 2; >+ >+// Other constants. >+const rootNodeIndex = 0; >+const rootNodeOrdinal = 0; >+const rootNodeIdentifier = 0; >+ >+// Terminology: >+// - `nodeIndex` is an index into the `nodes` list. >+// - `nodeOrdinal` is the order of the node in the `nodes` list. (nodeIndex / nodeFieldCount). >+// - `nodeIdentifier` is the node's id value. (nodes[nodeIndex + nodeIdOffset]). >+// - `edgeIndex` is an index into the `edges` list. >+// >+// Lists: >+// - _nodeOrdinalToFirstOutgoingEdge - `nodeOrdinal` to `edgeIndex` in `edges`. >+// Iterate edges by walking `edges` (edgeFieldCount) and checking if fromIdentifier is current. >+// - _nodeOrdinalToFirstIncomingEdge - `nodeOrdinal` to `incomingEdgeIndex` in `incomingEdges`. >+// Iterate edges by walking `incomingEdges` until `nodeOrdinal+1`'s first incoming edge index. >+// - _nodeOrdinalToDominatorNodeOrdinal - `nodeOrdinal` to `nodeOrdinal` of dominator. >+// - _nodeOrdinalToRetainedSizes - `nodeOrdinal` to retain size value. >+// - _nodeOrdinalIsDead - `nodeOrdinal` is dead or alive. >+// >+// Temporary Lists: >+// - nodeOrdinalToPostOrderIndex - `nodeOrdinal` to a `postOrderIndex`. >+// - postOrderIndexToNodeOrdinal - `postOrderIndex` to a `nodeOrdinal`. >+ >+let nextSnapshotIdentifier = 1; >+ >+HeapSnapshot = class HeapSnapshot >+{ >+ constructor(objectId, snapshotDataString, title = null) >+ { >+ this._identifier = nextSnapshotIdentifier++; >+ this._objectId = objectId; >+ this._title = title; >+ >+ let json = JSON.parse(snapshotDataString); >+ snapshotDataString = null; >+ >+ let {version, type, nodes, nodeClassNames, edges, edgeTypes, edgeNames, roots, labels} = json; >+ console.assert(version === 1, "Expect JavaScriptCore Heap Snapshot version 1"); >+ console.assert(type === "GCDebugging", "Expect a GCDebugging-type snapshot"); >+ >+ this._nodes = nodes; >+ this._nodeCount = nodes.length / nodeFieldCount; >+ >+ this._roots = roots; >+ this._rootCount = roots.length / rootFieldCount; >+ >+ this._edges = edges; >+ this._edgeCount = edges.length / edgeFieldCount; >+ >+ this._edgeTypesTable = edgeTypes; >+ this._edgeNamesTable = edgeNames; >+ this._nodeClassNamesTable = nodeClassNames; >+ this._labelsTable = labels; >+ >+ this._totalSize = 0; >+ this._nodeIdentifierToOrdinal = new Map; // <node identifier> => nodeOrdinal >+ this._lastNodeIdentifier = 0; >+ for (let nodeIndex = 0; nodeIndex < nodes.length; nodeIndex += nodeFieldCount) { >+ let nodeOrdinal = nodeIndex / nodeFieldCount; >+ let nodeIdentifier = nodes[nodeIndex + nodeIdOffset]; >+ this._nodeIdentifierToOrdinal.set(nodeIdentifier, nodeOrdinal); >+ this._totalSize += nodes[nodeIndex + nodeSizeOffset]; >+ if (nodeIdentifier > this._lastNodeIdentifier) >+ this._lastNodeIdentifier = nodeIdentifier; >+ } >+ >+ this._rootIdentifierToReasons = new Map; // <node identifier> => Set of root reasons >+ for (let rootIndex = 0; rootIndex < roots.length; rootIndex += rootFieldCount) { >+ let rootOrdinal = rootIndex / rootFieldCount; >+ let rootIdentifier = roots[rootIndex + rootIdOffset]; >+ let rootReasonIndex = roots[rootIndex + rootLabelOffset]; >+ let rootReachabilityIndex = roots[rootIndex + reachabilityReasonOffset]; >+ >+ let existingReasons = this._rootIdentifierToReasons.get(rootIdentifier); >+ if (existingReasons) { >+ existingReasons.add(rootReasonIndex); >+ existingReasons.add(rootReachabilityIndex); >+ } else >+ this._rootIdentifierToReasons.set(rootIdentifier, new Set([rootReasonIndex, rootReachabilityIndex])); >+ } >+ >+ // FIXME: Replace toIdentifier and fromIdentifier in edges with nodeIndex to reduce hash lookups? >+ >+ this._nodeOrdinalToFirstOutgoingEdge = new Uint32Array(this._nodeCount); // nodeOrdinal => edgeIndex >+ this._buildOutgoingEdges(); >+ >+ this._nodeOrdinalToFirstIncomingEdge = new Uint32Array(this._nodeCount + 1); // nodeOrdinal => incomingNodes/incomingEdges index >+ this._incomingNodes = new Uint32Array(this._edgeCount); // from nodeOrdinals. >+ this._incomingEdges = new Uint32Array(this._edgeCount); // edgeIndex. >+ this._buildIncomingEdges(); >+ >+ let {nodeOrdinalToPostOrderIndex, postOrderIndexToNodeOrdinal} = this._buildPostOrderIndexes(); >+ >+ this._nodeOrdinalToDominatorNodeOrdinal = new Uint32Array(this._nodeCount); >+ this._nodeOrdinalIsGCRoot = new Uint8Array(this._nodeCount); >+ this._buildDominatorIndexes(nodeOrdinalToPostOrderIndex, postOrderIndexToNodeOrdinal); >+ >+ nodeOrdinalToPostOrderIndex = null; >+ >+ this._nodeOrdinalToRetainedSizes = new Uint32Array(this._nodeCount); >+ this._buildRetainedSizes(postOrderIndexToNodeOrdinal); >+ >+ postOrderIndexToNodeOrdinal = null; >+ >+ this._nodeOrdinalIsDead = new Uint8Array(this._nodeCount); >+ >+ let {liveSize, categories} = HeapSnapshot.updateCategoriesAndMetadata(this); >+ this._liveSize = liveSize; >+ this._categories = categories; >+ } >+ >+ get proxyObjectId() { return this._proxyObjectId; } >+ get identifier() { return this._identifier; } >+ get title() { return this._title; } >+ get totalSize() { return this._totalSize; } >+ get totalObjectCount() { return this._totalObjectCount; } >+ get liveSize() { return this._liveSize; } >+ get categories() { return this._categories; } >+ get invalid() { return this._proxyObjectId === 0; } >+ >+ // Static >+ >+ static updateCategoriesAndMetadata(snapshot, allowNodeIdentifierCallback) >+ { >+ let liveSize = 0; >+ let categories = {}; >+ >+ let nodes = snapshot._nodes; >+ let nodeClassNamesTable = snapshot._nodeClassNamesTable; >+ let nodeOrdinalToRetainedSizes = snapshot._nodeOrdinalToRetainedSizes; >+ let nodeOrdinalIsDead = snapshot._nodeOrdinalIsDead; >+ >+ // Skip the <root> node. >+ let firstNodeIndex = nodeFieldCount; >+ let firstNodeOrdinal = 1; >+ for (let nodeIndex = firstNodeIndex, nodeOrdinal = firstNodeOrdinal; nodeIndex < nodes.length; nodeIndex += nodeFieldCount, nodeOrdinal++) { >+ if (allowNodeIdentifierCallback && !allowNodeIdentifierCallback(nodes[nodeIndex + nodeIdOffset])) >+ continue; >+ >+ let classNameTableIndex = nodes[nodeIndex + nodeClassNameOffset]; >+ let className = nodeClassNamesTable[classNameTableIndex]; >+ let size = nodes[nodeIndex + nodeSizeOffset]; >+ let retainedSize = nodeOrdinalToRetainedSizes[nodeOrdinal]; >+ let internal = nodes[nodeIndex + nodeInternalOffset] ? true : false; >+ let dead = nodeOrdinalIsDead[nodeOrdinal] ? true : false; >+ >+ let category = categories[className]; >+ if (!category) >+ category = categories[className] = {className, size: 0, retainedSize: 0, count: 0, internalCount: 0, deadCount: 0}; >+ >+ category.size += size; >+ category.retainedSize += retainedSize; >+ category.count += 1; >+ if (internal) >+ category.internalCount += 1; >+ if (dead) >+ category.deadCount += 1; >+ else >+ liveSize += size; >+ } >+ >+ return {liveSize, categories}; >+ } >+ >+ static allocationBucketCounts(snapshot, bucketSizes, allowNodeIdentifierCallback) >+ { >+ let counts = new Array(bucketSizes.length + 1); >+ let remainderBucket = counts.length - 1; >+ counts.fill(0); >+ >+ let nodes = snapshot._nodes; >+ >+ // Skip the <root> node. >+ let firstNodeIndex = nodeFieldCount; >+ >+ outer: >+ for (let nodeIndex = firstNodeIndex; nodeIndex < nodes.length; nodeIndex += nodeFieldCount) { >+ if (allowNodeIdentifierCallback && !allowNodeIdentifierCallback(nodes[nodeIndex + nodeIdOffset])) >+ continue; >+ >+ let size = nodes[nodeIndex + nodeSizeOffset]; >+ for (let i = 0; i < bucketSizes.length; ++i) { >+ if (size < bucketSizes[i]) { >+ counts[i]++; >+ continue outer; >+ } >+ } >+ counts[remainderBucket]++; >+ } >+ >+ return counts; >+ } >+ >+ static instancesWithClassName(snapshot, className, allowNodeIdentifierCallback) >+ { >+ let instances = []; >+ >+ let nodes = snapshot._nodes; >+ let nodeClassNamesTable = snapshot._nodeClassNamesTable; >+ >+ // Skip the <root> node. >+ let firstNodeIndex = nodeFieldCount; >+ let firstNodeOrdinal = 1; >+ for (let nodeIndex = firstNodeIndex, nodeOrdinal = firstNodeOrdinal; nodeIndex < nodes.length; nodeIndex += nodeFieldCount, nodeOrdinal++) { >+ if (allowNodeIdentifierCallback && !allowNodeIdentifierCallback(nodes[nodeIndex + nodeIdOffset])) >+ continue; >+ >+ let classNameTableIndex = nodes[nodeIndex + nodeClassNameOffset]; >+ if (nodeClassNamesTable[classNameTableIndex] === className) >+ instances.push(nodeIndex); >+ } >+ >+ return instances.map(snapshot.serializeNode, snapshot); >+ } >+ >+ // Worker Methods >+ >+ allocationBucketCounts(bucketSizes) >+ { >+ return HeapSnapshot.allocationBucketCounts(this, bucketSizes); >+ } >+ >+ instancesWithClassName(className) >+ { >+ return HeapSnapshot.instancesWithClassName(this, className); >+ } >+ >+ update() >+ { >+ return HeapSnapshot.updateCategoriesAndMetadata(this); >+ } >+ >+ nodeWithIdentifier(nodeIdentifier) >+ { >+ let nodeOrdinal = this._nodeIdentifierToOrdinal.get(nodeIdentifier); >+ let nodeIndex = nodeOrdinal * nodeFieldCount; >+ return this.serializeNode(nodeIndex); >+ } >+ >+ shortestGCRootPath(nodeIdentifier) >+ { >+ // Returns an array from this node to a gcRoot node. >+ // E.g. [Node (target), Edge, Node, Edge, Node (root)]. >+ // Internal nodes are avoided, so if the path is empty this >+ // node is either a gcRoot or only reachable via Internal nodes. >+ >+ let paths = this._gcRootPaths(nodeIdentifier); >+ if (!paths.length) >+ return []; >+ >+ paths.sort((a, b) => a.length - b.length); >+ >+ let shortestPathWithGlobalObject = null; >+ for (let path of paths) { >+ let lastNodeIndex = path[path.length - 1].node; >+ if (this._isNodeGlobalObject(lastNodeIndex)) { >+ shortestPathWithGlobalObject = path; >+ break; >+ } >+ } >+ >+ let shortestPath = shortestPathWithGlobalObject || paths[0]; >+ console.assert("node" in shortestPath[0], "Path should start with a node"); >+ console.assert("node" in shortestPath[shortestPath.length - 1], "Path should end with a node"); >+ >+ return shortestPath.map((component) => { >+ if (component.node) >+ return this.serializeNode(component.node); >+ return this.serializeEdge(component.edge); >+ }); >+ } >+ >+ rootNodes() >+ { >+ let rootNodeIndexSet = new Set; >+ >+ // Identifiers can occur multiple times in the roots list. >+ for (let rootIndex = 0; rootIndex < this._roots.length; rootIndex += rootFieldCount) { >+ let rootOrdinal = rootIndex / rootFieldCount; >+ let rootIdentifier = this._roots[rootIndex + rootIdOffset]; >+ >+ let toNodeOrdinal = this._nodeIdentifierToOrdinal.get(rootIdentifier); >+ let toNodeIndex = toNodeOrdinal * nodeFieldCount; >+ >+ rootNodeIndexSet.add(toNodeIndex); >+ } >+ >+ return Array.from(rootNodeIndexSet.values()).map(this.serializeNode, this); >+ } >+ >+ reasonNamesForRoot(rootIdentifier) >+ { >+ let reasonIndexes = this._rootIdentifierToReasons.get(rootIdentifier); >+ if (!reasonIndexes) >+ return []; >+ return Array.from(reasonIndexes).map(this.labelForIndex, this).filter(a => a != 0) >+ } >+ >+ dominatedNodes(nodeIdentifier) >+ { >+ let dominatedNodes = []; >+ >+ let targetNodeOrdinal = this._nodeIdentifierToOrdinal.get(nodeIdentifier); >+ for (let nodeOrdinal = 0; nodeOrdinal < this._nodeCount; ++nodeOrdinal) { >+ if (this._nodeOrdinalToDominatorNodeOrdinal[nodeOrdinal] === targetNodeOrdinal) >+ dominatedNodes.push(nodeOrdinal * nodeFieldCount); >+ } >+ >+ return dominatedNodes.map(this.serializeNode, this); >+ } >+ >+ retainedNodes(nodeIdentifier) >+ { >+ let retainedNodes = []; >+ let edges = []; >+ >+ let nodeOrdinal = this._nodeIdentifierToOrdinal.get(nodeIdentifier); >+ let edgeIndex = this._nodeOrdinalToFirstOutgoingEdge[nodeOrdinal]; >+ for (; this._edges[edgeIndex + edgeFromIdOffset] === nodeIdentifier; edgeIndex += edgeFieldCount) { >+ let toNodeIdentifier = this._edges[edgeIndex + edgeToIdOffset]; >+ let toNodeOrdinal = this._nodeIdentifierToOrdinal.get(toNodeIdentifier); >+ let toNodeIndex = toNodeOrdinal * nodeFieldCount; >+ retainedNodes.push(toNodeIndex); >+ edges.push(edgeIndex); >+ } >+ >+ return { >+ retainedNodes: retainedNodes.map(this.serializeNode, this), >+ edges: edges.map(this.serializeEdge, this), >+ }; >+ } >+ >+ retainers(nodeIdentifier) >+ { >+ let retainers = []; >+ let edges = []; >+ >+ let nodeOrdinal = this._nodeIdentifierToOrdinal.get(nodeIdentifier); >+ let incomingEdgeIndex = this._nodeOrdinalToFirstIncomingEdge[nodeOrdinal]; >+ let incomingEdgeIndexEnd = this._nodeOrdinalToFirstIncomingEdge[nodeOrdinal + 1]; >+ for (let edgeIndex = incomingEdgeIndex; edgeIndex < incomingEdgeIndexEnd; ++edgeIndex) { >+ let fromNodeOrdinal = this._incomingNodes[edgeIndex]; >+ let fromNodeIndex = fromNodeOrdinal * nodeFieldCount; >+ retainers.push(fromNodeIndex); >+ edges.push(this._incomingEdges[edgeIndex]); >+ } >+ >+ return { >+ retainers: retainers.map(this.serializeNode, this), >+ edges: edges.map(this.serializeEdge, this), >+ }; >+ } >+ >+ updateDeadNodesAndGatherCollectionData(snapshots) >+ { >+ let previousSnapshotIndex = snapshots.indexOf(this) - 1; >+ let previousSnapshot = snapshots[previousSnapshotIndex]; >+ if (!previousSnapshot) >+ return null; >+ >+ let lastNodeIdentifier = previousSnapshot._lastNodeIdentifier; >+ >+ // All of the node identifiers that could have existed prior to this snapshot. >+ let known = new Map; >+ for (let nodeIndex = 0; nodeIndex < this._nodes.length; nodeIndex += nodeFieldCount) { >+ let nodeIdentifier = this._nodes[nodeIndex + nodeIdOffset]; >+ if (nodeIdentifier > lastNodeIdentifier) >+ continue; >+ known.set(nodeIdentifier, nodeIndex); >+ } >+ >+ // Determine which node identifiers have since been deleted. >+ let collectedNodesList = []; >+ for (let nodeIndex = 0; nodeIndex < previousSnapshot._nodes.length; nodeIndex += nodeFieldCount) { >+ let nodeIdentifier = previousSnapshot._nodes[nodeIndex + nodeIdOffset]; >+ let wasDeleted = !known.has(nodeIdentifier); >+ if (wasDeleted) >+ collectedNodesList.push(nodeIdentifier); >+ } >+ >+ // Update dead nodes in previous snapshots. >+ let affectedSnapshots = []; >+ for (let snapshot of snapshots) { >+ if (snapshot === this) >+ break; >+ if (snapshot._markDeadNodes(collectedNodesList)) >+ affectedSnapshots.push(snapshot._identifier); >+ } >+ >+ // Convert list to a map. >+ let collectedNodes = {}; >+ for (let i = 0; i < collectedNodesList.length; ++i) >+ collectedNodes[collectedNodesList[i]] = true; >+ >+ return { >+ collectedNodes, >+ affectedSnapshots, >+ }; >+ } >+ >+ // Public >+ >+ serialize() >+ { >+ return { >+ identifier: this._identifier, >+ title: this._title, >+ totalSize: this._totalSize, >+ totalObjectCount: this._nodeCount - 1, // <root>. >+ liveSize: this._liveSize, >+ categories: this._categories, >+ }; >+ } >+ >+ serializeNode(nodeIndex) >+ { >+ console.assert((nodeIndex % nodeFieldCount) === 0, "Invalid nodeIndex to serialize: " + nodeIndex); >+ >+ let nodeIdentifier = this._nodes[nodeIndex + nodeIdOffset]; >+ let nodeOrdinal = nodeIndex / nodeFieldCount; >+ let edgeIndex = this._nodeOrdinalToFirstOutgoingEdge[nodeOrdinal]; >+ let hasChildren = this._edges[edgeIndex + edgeFromIdOffset] === nodeIdentifier; >+ >+ let dominatorNodeOrdinal = this._nodeOrdinalToDominatorNodeOrdinal[nodeOrdinal]; >+ let dominatorNodeIndex = dominatorNodeOrdinal * nodeFieldCount; >+ let dominatorNodeIdentifier = this._nodes[dominatorNodeIndex + nodeIdOffset]; >+ >+ let result = { >+ id: nodeIdentifier, >+ className: this._nodeClassNamesTable[this._nodes[nodeIndex + nodeClassNameOffset]], >+ size: this._nodes[nodeIndex + nodeSizeOffset], >+ retainedSize: this._nodeOrdinalToRetainedSizes[nodeOrdinal], >+ internal: this._nodes[nodeIndex + nodeInternalOffset] ? true : false, >+ gcRoot: this._nodeOrdinalIsGCRoot[nodeOrdinal] ? true : false, >+ markedRoot : this._rootIdentifierToReasons.has(nodeIdentifier), >+ dead: this._nodeOrdinalIsDead[nodeOrdinal] ? true : false, >+ address: this._nodes[nodeIndex + nodeAddressOffset], >+ label: this._labelsTable[this._nodes[nodeIndex + nodeLabelOffset]], >+ dominatorNodeIdentifier, >+ hasChildren, >+ }; >+ >+ let wrappedAddr = this._nodes[nodeIndex + nodeWrappedAddressOffset]; >+ if (wrappedAddr !== "0x0") >+ result.wrappedAddress = wrappedAddr; >+ >+ return result; >+ } >+ >+ labelForIndex(index) >+ { >+ return this._labelsTable[index]; >+ } >+ >+ serializeEdge(edgeIndex) >+ { >+ console.assert((edgeIndex % edgeFieldCount) === 0, "Invalid edgeIndex to serialize"); >+ >+ let edgeType = this._edgeTypesTable[this._edges[edgeIndex + edgeTypeOffset]]; >+ let edgeData = this._edges[edgeIndex + edgeDataOffset]; >+ switch (edgeType) { >+ case "Internal": >+ // edgeData can be ignored. >+ break; >+ case "Property": >+ case "Variable": >+ // edgeData is a table index. >+ edgeData = this._edgeNamesTable[edgeData]; >+ break; >+ case "Index": >+ // edgeData is the index. >+ break; >+ default: >+ console.error("Unexpected edge type: " + edgeType); >+ break; >+ } >+ >+ return { >+ from: this._edges[edgeIndex + edgeFromIdOffset], >+ to: this._edges[edgeIndex + edgeToIdOffset], >+ type: edgeType, >+ data: edgeData, >+ }; >+ } >+ >+ // Private >+ >+ _buildOutgoingEdges() >+ { >+ let lastFromIdentifier = -1; >+ for (let edgeIndex = 0; edgeIndex < this._edges.length; edgeIndex += edgeFieldCount) { >+ let fromIdentifier = this._edges[edgeIndex + edgeFromIdOffset]; >+ console.assert(lastFromIdentifier <= fromIdentifier, "Edge list should be ordered by from node identifier"); >+ if (fromIdentifier !== lastFromIdentifier) { >+ let nodeOrdinal = this._nodeIdentifierToOrdinal.get(fromIdentifier); >+ this._nodeOrdinalToFirstOutgoingEdge[nodeOrdinal] = edgeIndex; >+ lastFromIdentifier = fromIdentifier; >+ } >+ } >+ } >+ >+ _buildIncomingEdges() >+ { >+ // First calculate the count of incoming edges for each node. >+ for (let edgeIndex = 0; edgeIndex < this._edges.length; edgeIndex += edgeFieldCount) { >+ let toIdentifier = this._edges[edgeIndex + edgeToIdOffset]; >+ let toNodeOrdinal = this._nodeIdentifierToOrdinal.get(toIdentifier); >+ this._nodeOrdinalToFirstIncomingEdge[toNodeOrdinal]++; >+ } >+ >+ // Replace the counts with what will be the resulting index by running up the counts. >+ // Store the counts in what will be the edges list to use when placing edges in the list. >+ let runningFirstIndex = 0; >+ for (let nodeOrdinal = 0; nodeOrdinal < this._nodeCount; ++nodeOrdinal) { >+ let count = this._nodeOrdinalToFirstIncomingEdge[nodeOrdinal]; >+ this._nodeOrdinalToFirstIncomingEdge[nodeOrdinal] = runningFirstIndex; >+ this._incomingNodes[runningFirstIndex] = count; >+ runningFirstIndex += count; >+ } >+ >+ // Fill in the incoming edges list. Use the count as an offset when placing edges in the list. >+ for (let edgeIndex = 0; edgeIndex < this._edges.length; edgeIndex += edgeFieldCount) { >+ let fromIdentifier = this._edges[edgeIndex + edgeFromIdOffset]; >+ let fromNodeOrdinal = this._nodeIdentifierToOrdinal.get(fromIdentifier); >+ let toIdentifier = this._edges[edgeIndex + edgeToIdOffset]; >+ let toNodeOrdinal = this._nodeIdentifierToOrdinal.get(toIdentifier); >+ >+ let firstIncomingEdgeIndex = this._nodeOrdinalToFirstIncomingEdge[toNodeOrdinal]; >+ console.assert(this._incomingNodes[firstIncomingEdgeIndex] > 0, "Should be expecting edges for this node"); >+ let countAsOffset = this._incomingNodes[firstIncomingEdgeIndex]--; >+ let index = firstIncomingEdgeIndex + countAsOffset - 1; >+ this._incomingNodes[index] = fromNodeOrdinal; >+ this._incomingEdges[index] = edgeIndex; >+ } >+ >+ // Duplicate value on the end. Incoming edge iteration walks firstIncomingEdge(ordinal) to firstIncomingEdge(ordinal+1). >+ this._nodeOrdinalToFirstIncomingEdge[this._nodeCount] = this._nodeOrdinalToFirstIncomingEdge[this._nodeCount - 1]; >+ } >+ >+ _buildPostOrderIndexes() >+ { >+ let postOrderIndex = 0; >+ let nodeOrdinalToPostOrderIndex = new Uint32Array(this._nodeCount); >+ let postOrderIndexToNodeOrdinal = new Uint32Array(this._nodeCount); >+ >+ let stackNodes = new Uint32Array(this._nodeCount); // nodeOrdinal. >+ let stackEdges = new Uint32Array(this._nodeCount); // edgeIndex. >+ let visited = new Uint8Array(this._nodeCount); >+ >+ let stackTop = 0; >+ stackNodes[stackTop] = rootNodeOrdinal; >+ stackEdges[stackTop] = this._nodeOrdinalToFirstOutgoingEdge[rootNodeOrdinal]; >+ >+ while (stackTop >= 0) { >+ let nodeOrdinal = stackNodes[stackTop]; >+ let nodeIdentifier = this._nodes[(nodeOrdinal * nodeFieldCount) + nodeIdOffset]; >+ let edgeIndex = stackEdges[stackTop]; >+ >+ if (this._edges[edgeIndex + edgeFromIdOffset] === nodeIdentifier) { >+ // Prepare the next child for the current node. >+ stackEdges[stackTop] += edgeFieldCount; >+ >+ let toIdentifier = this._edges[edgeIndex + edgeToIdOffset]; >+ let toNodeOrdinal = this._nodeIdentifierToOrdinal.get(toIdentifier); >+ if (visited[toNodeOrdinal]) >+ continue; >+ >+ // Child. >+ stackTop++; >+ stackNodes[stackTop] = toNodeOrdinal; >+ stackEdges[stackTop] = this._nodeOrdinalToFirstOutgoingEdge[toNodeOrdinal]; >+ visited[toNodeOrdinal] = 1; >+ } else { >+ // Self. >+ nodeOrdinalToPostOrderIndex[nodeOrdinal] = postOrderIndex; >+ postOrderIndexToNodeOrdinal[postOrderIndex] = nodeOrdinal; >+ postOrderIndex++; >+ stackTop--; >+ } >+ } >+ >+ // Unvisited nodes. >+ // This can happen if the parent node was disallowed on the backend, but other nodes >+ // that were only referenced from that disallowed node were eventually allowed because >+ // they may be generic system objects. Give these nodes a postOrderIndex anyways. >+ if (postOrderIndex !== this._nodeCount) { >+ // Root was the last node visited. Revert assigning it an index, add it back at the end. >+ postOrderIndex--; >+ >+ // Visit unvisited nodes. >+ for (let nodeOrdinal = 1; nodeOrdinal < this._nodeCount; ++nodeOrdinal) { >+ if (visited[nodeOrdinal]) >+ continue; >+ nodeOrdinalToPostOrderIndex[nodeOrdinal] = postOrderIndex; >+ postOrderIndexToNodeOrdinal[postOrderIndex] = nodeOrdinal; >+ postOrderIndex++; >+ } >+ >+ // Visit root again. >+ nodeOrdinalToPostOrderIndex[rootNodeOrdinal] = postOrderIndex; >+ postOrderIndexToNodeOrdinal[postOrderIndex] = rootNodeOrdinal; >+ postOrderIndex++; >+ } >+ >+ console.assert(postOrderIndex === this._nodeCount, "All nodes were visited"); >+ console.assert(nodeOrdinalToPostOrderIndex[rootNodeOrdinal] === this._nodeCount - 1, "Root node should have the last possible postOrderIndex"); >+ >+ return {nodeOrdinalToPostOrderIndex, postOrderIndexToNodeOrdinal}; >+ } >+ >+ _buildDominatorIndexes(nodeOrdinalToPostOrderIndex, postOrderIndexToNodeOrdinal) >+ { >+ // The algorithm is based on the article: >+ // K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm" >+ >+ let rootPostOrderIndex = this._nodeCount - 1; >+ let noEntry = this._nodeCount; >+ >+ let affected = new Uint8Array(this._nodeCount); >+ let dominators = new Uint32Array(this._nodeCount); >+ >+ // Initialize with unset value. >+ dominators.fill(noEntry); >+ >+ // Mark the root's dominator value. >+ dominators[rootPostOrderIndex] = rootPostOrderIndex; >+ >+ // Affect the root's children. Also use this opportunity to mark them as GC roots. >+ let rootEdgeIndex = this._nodeOrdinalToFirstOutgoingEdge[rootNodeOrdinal]; >+ for (let edgeIndex = rootEdgeIndex; this._edges[edgeIndex + edgeFromIdOffset] === rootNodeIdentifier; edgeIndex += edgeFieldCount) { >+ let toIdentifier = this._edges[edgeIndex + edgeToIdOffset]; >+ let toNodeOrdinal = this._nodeIdentifierToOrdinal.get(toIdentifier); >+ let toPostOrderIndex = nodeOrdinalToPostOrderIndex[toNodeOrdinal]; >+ affected[toPostOrderIndex] = 1; >+ this._nodeOrdinalIsGCRoot[toNodeOrdinal] = 1; >+ } >+ >+ let changed = true; >+ while (changed) { >+ changed = false; >+ >+ for (let postOrderIndex = rootPostOrderIndex - 1; postOrderIndex >= 0; --postOrderIndex) { >+ if (!affected[postOrderIndex]) >+ continue; >+ affected[postOrderIndex] = 0; >+ >+ // The dominator is already the root, nothing to do. >+ if (dominators[postOrderIndex] === rootPostOrderIndex) >+ continue; >+ >+ let newDominatorIndex = noEntry; >+ let nodeOrdinal = postOrderIndexToNodeOrdinal[postOrderIndex]; >+ let incomingEdgeIndex = this._nodeOrdinalToFirstIncomingEdge[nodeOrdinal]; >+ let incomingEdgeIndexEnd = this._nodeOrdinalToFirstIncomingEdge[nodeOrdinal + 1]; >+ for (let edgeIndex = incomingEdgeIndex; edgeIndex < incomingEdgeIndexEnd; ++edgeIndex) { >+ let fromNodeOrdinal = this._incomingNodes[edgeIndex]; >+ let fromPostOrderIndex = nodeOrdinalToPostOrderIndex[fromNodeOrdinal]; >+ if (dominators[fromPostOrderIndex] !== noEntry) { >+ if (newDominatorIndex === noEntry) >+ newDominatorIndex = fromPostOrderIndex; >+ else { >+ while (fromPostOrderIndex !== newDominatorIndex) { >+ while (fromPostOrderIndex < newDominatorIndex) >+ fromPostOrderIndex = dominators[fromPostOrderIndex]; >+ while (newDominatorIndex < fromPostOrderIndex) >+ newDominatorIndex = dominators[newDominatorIndex]; >+ } >+ } >+ } >+ if (newDominatorIndex === rootPostOrderIndex) >+ break; >+ } >+ >+ // Changed. Affect children. >+ if (newDominatorIndex !== noEntry && dominators[postOrderIndex] !== newDominatorIndex) { >+ dominators[postOrderIndex] = newDominatorIndex; >+ changed = true; >+ >+ let outgoingEdgeIndex = this._nodeOrdinalToFirstOutgoingEdge[nodeOrdinal]; >+ let nodeIdentifier = this._nodes[(nodeOrdinal * nodeFieldCount) + nodeIdOffset]; >+ for (let edgeIndex = outgoingEdgeIndex; this._edges[edgeIndex + edgeFromIdOffset] === nodeIdentifier; edgeIndex += edgeFieldCount) { >+ let toNodeIdentifier = this._edges[edgeIndex + edgeToIdOffset]; >+ let toNodeOrdinal = this._nodeIdentifierToOrdinal.get(toNodeIdentifier); >+ let toNodePostOrder = nodeOrdinalToPostOrderIndex[toNodeOrdinal]; >+ affected[toNodePostOrder] = 1; >+ } >+ } >+ } >+ } >+ >+ for (let postOrderIndex = 0; postOrderIndex < this._nodeCount; ++postOrderIndex) { >+ let nodeOrdinal = postOrderIndexToNodeOrdinal[postOrderIndex]; >+ let dominatorNodeOrdinal = postOrderIndexToNodeOrdinal[dominators[postOrderIndex]]; >+ this._nodeOrdinalToDominatorNodeOrdinal[nodeOrdinal] = dominatorNodeOrdinal; >+ } >+ } >+ >+ _buildRetainedSizes(postOrderIndexToNodeOrdinal) >+ { >+ // Self size. >+ for (let nodeIndex = 0, nodeOrdinal = 0; nodeOrdinal < this._nodeCount; nodeIndex += nodeFieldCount, nodeOrdinal++) >+ this._nodeOrdinalToRetainedSizes[nodeOrdinal] = this._nodes[nodeIndex + nodeSizeOffset]; >+ >+ // Attribute size to dominator. >+ for (let postOrderIndex = 0; postOrderIndex < this._nodeCount - 1; ++postOrderIndex) { >+ let nodeOrdinal = postOrderIndexToNodeOrdinal[postOrderIndex]; >+ let nodeRetainedSize = this._nodeOrdinalToRetainedSizes[nodeOrdinal]; >+ let dominatorNodeOrdinal = this._nodeOrdinalToDominatorNodeOrdinal[nodeOrdinal]; >+ this._nodeOrdinalToRetainedSizes[dominatorNodeOrdinal] += nodeRetainedSize; >+ } >+ } >+ >+ _markDeadNodes(collectedNodesList) >+ { >+ let affected = false; >+ >+ for (let i = 0; i < collectedNodesList.length; ++i) { >+ let nodeIdentifier = collectedNodesList[i]; >+ if (nodeIdentifier > this._lastNodeIdentifier) >+ continue; >+ let nodeOrdinal = this._nodeIdentifierToOrdinal.get(nodeIdentifier); >+ this._nodeOrdinalIsDead[nodeOrdinal] = 1; >+ affected = true; >+ } >+ >+ return affected; >+ } >+ >+ _isNodeGlobalObject(nodeIndex) >+ { >+ let className = this._nodeClassNamesTable[this._nodes[nodeIndex + nodeClassNameOffset]]; >+ return className === "Window" >+ || className === "JSWindowProxy" >+ || className === "GlobalObject"; >+ } >+ >+ _gcRootPaths(nodeIdentifier) >+ { >+ let targetNodeOrdinal = this._nodeIdentifierToOrdinal.get(nodeIdentifier); >+ >+ if (this._nodeOrdinalIsGCRoot[targetNodeOrdinal]) >+ return []; >+ >+ // FIXME: Array push/pop can affect performance here, but in practice it hasn't been an issue. >+ >+ let paths = []; >+ let currentPath = []; >+ let visited = new Uint8Array(this._nodeCount); >+ >+ function visitNode(nodeOrdinal) >+ { >+ if (this._nodeOrdinalIsGCRoot[nodeOrdinal]) { >+ let fullPath = currentPath.slice(); >+ let nodeIndex = nodeOrdinal * nodeFieldCount; >+ fullPath.push({node: nodeIndex}); >+ paths.push(fullPath); >+ return; >+ } >+ >+ if (visited[nodeOrdinal]) >+ return; >+ visited[nodeOrdinal] = 1; >+ >+ let nodeIndex = nodeOrdinal * nodeFieldCount; >+ currentPath.push({node: nodeIndex}); >+ >+ // Loop in reverse order because edges were added in reverse order. >+ // It doesn't particularly matter other then consistency with previous code. >+ let incomingEdgeIndexStart = this._nodeOrdinalToFirstIncomingEdge[nodeOrdinal]; >+ let incomingEdgeIndexEnd = this._nodeOrdinalToFirstIncomingEdge[nodeOrdinal + 1]; >+ for (let incomingEdgeIndex = incomingEdgeIndexEnd - 1; incomingEdgeIndex >= incomingEdgeIndexStart; --incomingEdgeIndex) { >+ let fromNodeOrdinal = this._incomingNodes[incomingEdgeIndex]; >+ let fromNodeIndex = fromNodeOrdinal * nodeFieldCount; >+ // let fromNodeIsInternal = this._nodes[fromNodeIndex + nodeInternalOffset]; >+ // if (fromNodeIsInternal) >+ // continue; >+ >+ let edgeIndex = this._incomingEdges[incomingEdgeIndex]; >+ currentPath.push({edge: edgeIndex}); >+ visitNode.call(this, fromNodeOrdinal); >+ currentPath.pop(); >+ } >+ >+ currentPath.pop(); >+ } >+ >+ visitNode.call(this, targetNodeOrdinal); >+ >+ return paths; >+ } >+}; >diff --git a/Tools/GCHeapInspector/script/interface.js b/Tools/GCHeapInspector/script/interface.js >new file mode 100644 >index 0000000000000000000000000000000000000000..ae3ad5b00b29551da9d210e2edc7f59376278a3c >--- /dev/null >+++ b/Tools/GCHeapInspector/script/interface.js >@@ -0,0 +1,515 @@ >+ >+ >+// DOM Helpers >+class DOMUtils >+{ >+ static removeAllChildren(node) >+ { >+ while (node.lastChild) >+ node.removeChild(node.lastChild); >+ } >+ >+ static createDetails(summaryText) >+ { >+ let summary = document.createElement('summary'); >+ summary.textContent = summaryText; >+ >+ let details = document.createElement('details'); >+ details.appendChild(summary); >+ >+ details.addEventListener('keydown', function(event) { >+ const rightArrowKeyCode = 39; >+ const leftArrowKeyCode = 37; >+ if (event.keyCode == rightArrowKeyCode) >+ this.open = true; >+ else if (event.keyCode == leftArrowKeyCode) >+ this.open = false; >+ }, false); >+ >+ return details; >+ } >+}; >+ >+// Heap Inspector Helpers >+class HeapInspectorUtils >+{ >+ static humanReadableSize(sizeInBytes) >+ { >+ var i = -1; >+ if (sizeInBytes < 512) >+ return sizeInBytes + ' B'; >+ var byteUnits = [' KB', ' MB', ' GB']; >+ do { >+ sizeInBytes = sizeInBytes / 1024; >+ i++; >+ } while (sizeInBytes > 1024); >+ >+ return Math.max(sizeInBytes, 0.1).toFixed(1) + byteUnits[i]; >+ } >+ >+ static addressForNode(node) >+ { >+ return node.wrappedAddress ? node.wrappedAddress : node.address; >+ } >+ >+ static nodeName(snapshot, node) >+ { >+ if (node.type == "Internal") >+ return 'Internal node'; >+ >+ let result = node.className + ' @' + node.id + ' (' + HeapInspectorUtils.addressForNode(node) + ' ' + node.label + ')'; >+ if (node.gcRoot || node.markedRoot) >+ result += ' (GC rootâ' + snapshot.reasonNamesForRoot(node.id).join(', ') + ')'; >+ >+ return result; >+ } >+ >+ static spanForNode(inspector, node, showPathButton) >+ { >+ let nodeSpan = document.createElement('span'); >+ >+ if (node.type == "Internal") { >+ nodeSpan.textContent = 'Internal node'; >+ return nodeSpan; >+ } >+ >+ let wrappedAddressString = node.wrappedAddress ? `wrapped ${node.wrappedAddress}` : ''; >+ >+ let nodeHTML = node.className + ` <span class="node-id">${node.id}</span> <span class="node-address">cell ${node.address} ${wrappedAddressString}</span> <span class="node-size">(retains ${HeapInspectorUtils.humanReadableSize(node.retainedSize)})</span>`; >+ >+ if (node.label.length) >+ nodeHTML += ` <span class="node-label">â${node.label}â</span>`; >+ >+ nodeSpan.innerHTML = nodeHTML; >+ >+ if (node.gcRoot || node.markedRoot) { >+ let gcRootSpan = document.createElement('span'); >+ gcRootSpan.className = 'node-gc-root'; >+ gcRootSpan.textContent = ' (GC rootâ' + inspector.snapshot.reasonNamesForRoot(node.id).join(', ') + ')'; >+ nodeSpan.appendChild(gcRootSpan); >+ } else if (showPathButton) { >+ let showAllPathsAnchor = document.createElement('button'); >+ showAllPathsAnchor.className = 'node-show-all-paths'; >+ showAllPathsAnchor.textContent = 'Show all paths'; >+ showAllPathsAnchor.addEventListener('click', (e) => { >+ inspector.showAllPathsToNode(node); >+ }, false); >+ nodeSpan.appendChild(showAllPathsAnchor); >+ } >+ >+ return nodeSpan; >+ } >+ >+ static spanForEdge(snapshot, edge) >+ { >+ let edgeSpan = document.createElement('span'); >+ edgeSpan.className = 'edge'; >+ edgeSpan.innerHTML = '<span class="edge-type">' + edge.type + '</span> <span class="edge-data">' + edge.data + '</span>'; >+ return edgeSpan; >+ } >+ >+ static summarySpanForPath(inspector, path) >+ { >+ let pathSpan = document.createElement('span'); >+ pathSpan.className = 'path-summary'; >+ >+ if (path.length > 0) { >+ let pathLength = (path.length - 1) / 2; >+ pathSpan.textContent = pathLength + ' step' + (pathLength > 1 ? 's' : '') + ' from '; >+ pathSpan.appendChild(HeapInspectorUtils.spanForNode(inspector, path[0]), true); >+ } >+ >+ return pathSpan; >+ } >+ >+ static edgeName(edge) >+ { >+ return 'â ' + edge.type + ' ' + edge.data + ' â'; >+ } >+}; >+ >+ >+// Manages a list of heap snapshot nodes that can dynamically build the contents of an HTMLListElement. >+class InstanceList >+{ >+ constructor(listElement, snapshot, listGeneratorFunc) >+ { >+ this.listElement = listElement; >+ this.snapshot = snapshot; >+ this.nodeList = listGeneratorFunc(this.snapshot); >+ this.entriesAdded = 0; >+ this.initialEntries = 100; >+ this.entriesQuantum = 50; >+ this.showMoreItem = undefined; >+ } >+ >+ buildList(inspector) >+ { >+ DOMUtils.removeAllChildren(this.listElement); >+ if (this.nodeList.length == 0) >+ return; >+ >+ let maxIndex = Math.min(this.nodeList.length, this.initialEntries); >+ this.appendItemsForRange(inspector, 0, maxIndex); >+ >+ if (maxIndex < this.nodeList.length) { >+ this.showMoreItem = this.makeShowMoreItem(inspector); >+ this.listElement.appendChild(this.showMoreItem); >+ } >+ >+ this.entriesAdded = maxIndex; >+ } >+ >+ appendItemsForRange(inspector, startIndex, endIndex) >+ { >+ for (let index = startIndex; index < endIndex; ++index) { >+ let instance = this.nodeList[index]; >+ let listItem = document.createElement('li'); >+ listItem.appendChild(HeapInspectorUtils.spanForNode(inspector, instance, true)); >+ this.listElement.appendChild(listItem); >+ } >+ >+ this.entriesAdded = endIndex; >+ } >+ >+ appendMoreEntries(inspector) >+ { >+ let numRemaining = this.nodeList.length - this.entriesAdded; >+ if (numRemaining == 0) >+ return; >+ >+ this.showMoreItem.remove(); >+ >+ let fromIndex = this.entriesAdded; >+ let toIndex = Math.min(this.nodeList.length, fromIndex + this.entriesQuantum); >+ this.appendItemsForRange(inspector, fromIndex, toIndex); >+ >+ if (toIndex < this.nodeList.length) { >+ this.showMoreItem = this.makeShowMoreItem(inspector); >+ this.listElement.appendChild(this.showMoreItem); >+ } >+ } >+ >+ makeShowMoreItem(inspector) >+ { >+ let numberRemaining = this.nodeList.length - this.entriesAdded; >+ >+ let listItem = document.createElement('li'); >+ listItem.className = 'show-more'; >+ listItem.appendChild(document.createTextNode(`${numberRemaining} more `)); >+ >+ let moreButton = document.createElement('button'); >+ moreButton.textContent = `Show ${Math.min(this.entriesQuantum, numberRemaining)} more`; >+ >+ let thisList = this; >+ moreButton.addEventListener('click', function(e) { >+ thisList.appendMoreEntries(inspector, 10); >+ }, false); >+ >+ listItem.appendChild(moreButton); >+ return listItem; >+ } >+}; >+ >+ >+class HeapSnapshotInspector >+{ >+ constructor(containerElement, heapJSONData, filename) >+ { >+ this.containerElement = containerElement; >+ this.resetUI(); >+ >+ this.snapshot = new HeapSnapshot(1, heapJSONData, filename); >+ >+ this.buildRoots(); >+ this.buildAllObjectsByType(); >+ >+ this.buildPathsToRootsOfType('Window'); >+ this.buildPathsToRootsOfType('HTMLDocument'); >+ } >+ >+ resetUI() >+ { >+ DOMUtils.removeAllChildren(this.containerElement); >+ >+ this.objectByTypeContainer = document.createElement('section'); >+ this.objectByTypeContainer.id = 'all-objects-by-type'; >+ >+ let header = document.createElement('h1'); >+ header.textContent = 'All Objects by Type' >+ this.objectByTypeContainer.appendChild(header); >+ >+ this.rootsContainer = document.createElement('section'); >+ this.rootsContainer.id = 'roots'; >+ header = document.createElement('h1'); >+ header.textContent = 'Roots' >+ this.rootsContainer.appendChild(header); >+ >+ this.pathsToRootsContainer = document.createElement('section'); >+ this.pathsToRootsContainer.id = 'paths-to-roots'; >+ header = document.createElement('h1'); >+ header.textContent = 'Paths to roots' >+ this.pathsToRootsContainer.appendChild(header); >+ >+ this.allPathsContainer = document.createElement('section'); >+ this.allPathsContainer.id = 'all-paths'; >+ header = document.createElement('h1'); >+ header.textContent = 'All paths toâ¦' >+ this.allPathsContainer.appendChild(header); >+ >+ this.containerElement.appendChild(this.pathsToRootsContainer); >+ this.containerElement.appendChild(this.allPathsContainer); >+ this.containerElement.appendChild(this.rootsContainer); >+ this.containerElement.appendChild(this.objectByTypeContainer); >+ } >+ >+ buildAllObjectsByType() >+ { >+ let categories = this.snapshot._categories; >+ let categoryNames = Object.keys(categories).sort(); >+ >+ for (var categoryName of categoryNames) { >+ let category = categories[categoryName]; >+ >+ let details = DOMUtils.createDetails(`${category.className} (${category.count})`); >+ >+ let instanceListElement = document.createElement('ul'); >+ instanceListElement.className = 'instance-list'; >+ >+ let instanceList = new InstanceList(instanceListElement, this.snapshot, function(snapshot) { >+ return HeapSnapshot.instancesWithClassName(snapshot, categoryName); >+ }); >+ >+ instanceList.buildList(this); >+ >+ details.appendChild(instanceListElement); >+ this.objectByTypeContainer.appendChild(details); >+ } >+ } >+ >+ buildRoots() >+ { >+ let roots = this.snapshot.rootNodes(); >+ if (roots.length == 0) >+ return; >+ >+ let groupings = roots.reduce(function(accumulator, node) { >+ var key = node.className; >+ if (!accumulator[key]) { >+ accumulator[key] = []; >+ } >+ accumulator[key].push(node); >+ return accumulator; >+ }, {}); >+ >+ let rootNames = Object.keys(groupings).sort(); >+ >+ for (var rootClassName of rootNames) { >+ let rootsOfType = groupings[rootClassName]; >+ >+ rootsOfType.sort(function(a, b) { >+ let addressA = HeapInspectorUtils.addressForNode(a); >+ let addressB = HeapInspectorUtils.addressForNode(b); >+ return (addressA < addressB) ? -1 : (addressA > addressB) ? 1 : 0; >+ }) >+ >+ let details = DOMUtils.createDetails(`${rootClassName} (${rootsOfType.length})`); >+ let rootsTypeList = document.createElement('ul') >+ rootsTypeList.className = 'instance-list'; >+ >+ for (let root of rootsOfType) { >+ let rootListItem = document.createElement('li'); >+ rootListItem.appendChild(HeapInspectorUtils.spanForNode(this, root, true)); >+ rootsTypeList.appendChild(rootListItem); >+ } >+ >+ details.appendChild(rootsTypeList); >+ >+ this.rootsContainer.appendChild(details); >+ } >+ } >+ >+ buildPathsToRootsOfType(type) >+ { >+ let instances = HeapSnapshot.instancesWithClassName(this.snapshot, type); >+ if (instances.length == 0) >+ return; >+ >+ let header = document.createElement('h2'); >+ header.textContent = 'Shortest paths to all ' + type + 's'; >+ >+ let detailsContainer = document.createElement('section') >+ detailsContainer.className = 'path'; >+ >+ for (var instance of instances) { >+ let shortestPath = this.snapshot.shortestGCRootPath(instance.id).reverse(); >+ >+ let details = DOMUtils.createDetails(''); >+ let summary = details.firstChild; >+ summary.appendChild(HeapInspectorUtils.spanForNode(this, instance, true)); >+ summary.appendChild(document.createTextNode('â')); >+ summary.appendChild(HeapInspectorUtils.summarySpanForPath(this, shortestPath)); >+ >+ let pathList = document.createElement('ul'); >+ pathList.className = 'path'; >+ >+ let isNode = true; >+ let currItem = undefined; >+ for (let item of shortestPath) { >+ if (isNode) { >+ currItem = document.createElement('li'); >+ currItem.appendChild(HeapInspectorUtils.spanForNode(this, item)); >+ pathList.appendChild(currItem); >+ } else { >+ currItem.appendChild(HeapInspectorUtils.spanForEdge(this.snapshot, item)); >+ currItem = undefined; >+ } >+ isNode = !isNode; >+ } >+ >+ details.appendChild(pathList); >+ detailsContainer.appendChild(details); >+ } >+ >+ this.pathsToRootsContainer.appendChild(header); >+ this.pathsToRootsContainer.appendChild(detailsContainer); >+ } >+ >+ showAllPathsToNode(node) >+ { >+ let paths = this.snapshot._gcRootPaths(node.id); >+ >+ let details = DOMUtils.createDetails(''); >+ let summary = details.firstChild; >+ summary.appendChild(document.createTextNode(`${paths.length} path${paths.length > 1 ? 's' : ''} to `)); >+ summary.appendChild(HeapInspectorUtils.spanForNode(this, node, false)); >+ >+ let detailsContainer = document.createElement('section') >+ detailsContainer.className = 'path'; >+ >+ for (let path of paths) { >+ let pathNodes = path.map((component) => { >+ if (component.node) >+ return this.snapshot.serializeNode(component.node); >+ return this.snapshot.serializeEdge(component.edge); >+ }).reverse(); >+ >+ let pathDetails = DOMUtils.createDetails(''); >+ let pathSummary = pathDetails.firstChild; >+ pathSummary.appendChild(HeapInspectorUtils.summarySpanForPath(this, pathNodes)); >+ >+ let pathList = document.createElement('ul'); >+ pathList.className = 'path'; >+ >+ let isNode = true; >+ let currItem = undefined; >+ for (let item of pathNodes) { >+ if (isNode) { >+ currItem = document.createElement('li'); >+ currItem.appendChild(HeapInspectorUtils.spanForNode(this, item)); >+ pathList.appendChild(currItem); >+ } else { >+ currItem.appendChild(HeapInspectorUtils.spanForEdge(this.snapshot, item)); >+ currItem = undefined; >+ } >+ isNode = !isNode; >+ } >+ >+ pathDetails.appendChild(pathList); >+ detailsContainer.appendChild(pathDetails); >+ } >+ >+ details.appendChild(detailsContainer); >+ this.allPathsContainer.appendChild(details); >+ } >+ >+}; >+ >+ >+function loadResults(dataString, filename) >+{ >+ let inspectorContainer = document.getElementById('uiContainer'); >+ inspector = new HeapSnapshotInspector(inspectorContainer, dataString, filename) >+} >+ >+function filenameForPath(filepath) >+{ >+ return filepath.match(/([^\/]+)(?=\.\w+$)/)[0]; >+} >+ >+function hideDescription() >+{ >+ document.getElementById('description').classList.add('hidden'); >+} >+ >+var inspector; >+ >+function setupInterface() >+{ >+ // See if we have a file to load specified in the query string. >+ var query_parameters = {}; >+ var pairs = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); >+ var filename = "test-heap.json"; >+ >+ for (var i = 0; i < pairs.length; i++) { >+ var pair = pairs[i].split('='); >+ query_parameters[pair[0]] = decodeURIComponent(pair[1]); >+ } >+ >+ if ("filename" in query_parameters) >+ filename = query_parameters["filename"]; >+ >+ fetch(filename) >+ .then(function(response) { >+ if (response.ok) >+ return response.text(); >+ throw new Error('Failed to load data file ' + filename); >+ }) >+ .then(function(dataString) { >+ loadResults(dataString, filenameForPath(filename)); >+ hideDescription(); >+ document.getElementById('uiContainer').style.display = 'block'; >+ }); >+ >+ var drop_target = document.getElementById("dropTarget"); >+ >+ drop_target.addEventListener("dragenter", function (e) { >+ drop_target.className = "dragOver"; >+ e.stopPropagation(); >+ e.preventDefault(); >+ }, false); >+ >+ drop_target.addEventListener("dragover", function (e) { >+ e.stopPropagation(); >+ e.preventDefault(); >+ }, false); >+ >+ drop_target.addEventListener("dragleave", function (e) { >+ drop_target.className = ""; >+ e.stopPropagation(); >+ e.preventDefault(); >+ }, false); >+ >+ drop_target.addEventListener("drop", function (e) { >+ drop_target.className = ""; >+ e.stopPropagation(); >+ e.preventDefault(); >+ >+ for (var i = 0; i < e.dataTransfer.files.length; ++i) { >+ var file = e.dataTransfer.files[i]; >+ >+ var reader = new FileReader(); >+ reader.filename = file.name; >+ reader.onload = function(e) { >+ loadResults(e.target.result, filenameForPath(this.filename)); >+ hideDescription(); >+ document.getElementById('uiContainer').style.display = 'block'; >+ }; >+ >+ reader.readAsText(file); >+ document.title = "GC Heap: " + reader.filename; >+ } >+ }, false); >+} >+ >+window.addEventListener('load', setupInterface, false);
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 186416
:
342231
|
347981
| 347982