Commit b38855a8 authored by Ulan Degenbaev's avatar Ulan Degenbaev Committed by Commit Bot

Reland "Capture all DOM nodes reachable from V8 in heap snapshot."

This reverts commit 0c264842.

The new iframe test is fragile and is not properly waiting for the
iframe onload event. Since the problem is in the test, relanding
without the test for now to unblock other changes.

Original change's description:
> Capture all DOM nodes reachable from V8 in heap snapshot.
>
> This patch uses the new EmbedderGraph API to provide the heap snapshot
> generator with all DOM nodes and references reachable from V8.
>
> Bug: 749490
> Change-Id: I26750a8b80dab4f88508e504b431d976a598c6c3
> Reviewed-on: https://chromium-review.googlesource.com/890260
> Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
> Reviewed-by: Alexei Filippov <alph@chromium.org>
> Reviewed-by: Kentaro Hara <haraken@chromium.org>

Change-Id: I1d736a74b2f39443c490aecbfe7f6d305a669711

TBR=haraken@chromium.org,alph@chromium.org

Change-Id: I1d736a74b2f39443c490aecbfe7f6d305a669711
Reviewed-on: https://chromium-review.googlesource.com/897644
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: default avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#533831}
parent d9e95344
...@@ -35,8 +35,8 @@ crbug.com/704360 [ Linux ] shapedetection/detection-ImageData.html [ Timeout Pas ...@@ -35,8 +35,8 @@ crbug.com/704360 [ Linux ] shapedetection/detection-ImageData.html [ Timeout Pas
# Times out on MSAN # Times out on MSAN
crbug.com/462190 [ Linux ] inspector-protocol/heap-profiler/heap-samples-in-snapshot.js [ Timeout ] crbug.com/462190 [ Linux ] inspector-protocol/heap-profiler/heap-samples-in-snapshot.js [ Timeout ]
crbug.com/462190 [ Linux ] inspector-protocol/heap-profiler/heap-snapshot-with-active-dom-object.js [ Timeout ] crbug.com/462190 [ Linux ] inspector-protocol/heap-profiler/heap-snapshot-with-active-dom-object.js [ Timeout ]
crbug.com/462190 [ Linux ] inspector-protocol/heap-profiler/heap-snapshot-with-detached-dom-tree.js [ Timeout ]
crbug.com/462190 [ Linux ] inspector-protocol/heap-profiler/heap-snapshot-with-event-listener.js [ Timeout ] crbug.com/462190 [ Linux ] inspector-protocol/heap-profiler/heap-snapshot-with-event-listener.js [ Timeout ]
crbug.com/462190 [ Linux ] inspector-protocol/heap-profiler/heap-snapshot-with-multiple-retainers.js [ Timeout ]
crbug.com/667560 [ Linux ] http/tests/devtools/startup/console/console-format-startup.js [ Timeout Pass ] crbug.com/667560 [ Linux ] http/tests/devtools/startup/console/console-format-startup.js [ Timeout Pass ]
crbug.com/751906 [ Linux ] http/tests/devtools/console/console-correct-suggestions.js [ Timeout Pass ] crbug.com/751906 [ Linux ] http/tests/devtools/console/console-correct-suggestions.js [ Timeout Pass ]
......
Test that all ActiveDOMObjects with pending activities will get into one group in the heap snapshot. Bug 426809. Test that all ActiveDOMObjects with pending activities will get into one group in the heap snapshot. Bug 426809.
Took heap snapshot Took heap snapshot
Parsed snapshot Parsed snapshot
SUCCESS: found (Pending activities group) SUCCESS: found Pending activities
SUCCESS: found Pending activities / 3 entries SUCCESS: found 2 MediaQueryLists in Pending activities
SUCCESS: found 2 MediaQueryLists in Pending activities / 3 entries
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
var snapshot = await helper.takeHeapSnapshot(); var snapshot = await helper.takeHeapSnapshot();
var node; var node;
for (var it = snapshot._allNodes(); it.hasNext(); it.next()) { for (var it = snapshot._allNodes(); it.hasNext(); it.next()) {
if (it.node.name() === '(Pending activities group)') { if (it.node.name() === 'Pending activities') {
node = it.node; node = it.node;
break; break;
} }
...@@ -40,23 +40,9 @@ ...@@ -40,23 +40,9 @@
if (node) if (node)
testRunner.log('SUCCESS: found ' + node.name()); testRunner.log('SUCCESS: found ' + node.name());
else else
return testRunner.fail(`cannot find '(Pending activities group)'`); return testRunner.fail(`cannot find 'Pending activities'`);
checkPendingActivities(node);
var pendingActivitiesRE = /^Pending activities/;
var pendingActivitiesFound = false;
for (var iter = node.edges(); iter.hasNext(); iter.next()) {
var node = iter.edge.node();
if (pendingActivitiesRE.test(node.className())) {
if ('Pending activities / 3 entries' === node.name()) {
if (pendingActivitiesFound)
return testRunner.fail('second ' + node.name());
pendingActivitiesFound = true;
testRunner.log('SUCCESS: found ' + node.name());
checkPendingActivities(node);
} else {
return testRunner.fail(`unexpected 'Pending activities': ${node.name()}`);
}
}
}
testRunner.completeTest(); testRunner.completeTest();
}) })
Test that all nodes from the detached DOM tree will get into one group in the heap snapshot. Bug 107819.
Took heap snapshot
Parsed snapshot
SUCCESS: found (Detached DOM trees)
SUCCESS: found Detached DOM tree / 3 entries
SUCCESS: found 3 DIVs in Detached DOM tree / 3 entries
(async function(testRunner) {
var {page, session, dp} = await testRunner.startBlank(
`Test that all nodes from the detached DOM tree will get into one group in the heap snapshot. Bug 107819.`);
await session.evaluate(`
if (window.gc)
window.gc();
window.retaining_wrapper = document.createElement('div');
var t = document.createElement('div');
retaining_wrapper.appendChild(t);
t.appendChild(document.createElement('div'));
`);
function checkDetachedDOMTreeNodes(treeNode) {
var divCount = 0;
for (var iter = treeNode.edges(); iter.hasNext(); iter.next()) {
var node = iter.edge.node();
if (node.name() === 'HTMLDivElement')
++divCount;
else
return testRunner.fail('unexpected DOM wrapper: ' + node.name());
}
if (divCount === 3)
testRunner.log('SUCCESS: found ' + divCount + ' DIVs in ' + treeNode.name());
else
return testRunner.fail('unexpected DIV count: ' + divCount);
}
var Helper = await testRunner.loadScript('resources/heap-snapshot-common.js');
var helper = await Helper(testRunner, session);
var snapshot = await helper.takeHeapSnapshot();
var node;
for (var it = snapshot._allNodes(); it.hasNext(); it.next()) {
if (it.node.name() === '(Detached DOM trees)') {
node = it.node;
break;
}
}
if (node)
testRunner.log('SUCCESS: found ' + node.name());
else
return testRunner.fail('cannot find detached DOM trees root');
var detachedDOMTreeRE = /^Detached DOM tree/;
var detachedDomTreeFound = false;
for (var iter = node.edges(); iter.hasNext(); iter.next()) {
var node = iter.edge.node();
if (detachedDOMTreeRE.test(node.className())) {
if ('Detached DOM tree / 3 entries' === node.name()) {
if (detachedDomTreeFound)
return testRunner.fail('second ' + node.name());
detachedDomTreeFound = true;
testRunner.log('SUCCESS: found ' + node.name());
checkDetachedDOMTreeNodes(node);
} else
return testRunner.fail('unexpected detached DOM tree: ' + node.name());
}
}
testRunner.completeTest();
})
Test that all nodes from the detached DOM tree will get into one group in the heap snapshot. Bug 107819. Test retaining path for an event listener.
Took heap snapshot Took heap snapshot
Parsed snapshot Parsed snapshot
SUCCESS: found myEventListener SUCCESS: found myEventListener
SUCCESS: found link from HTMLBodyElement to myEventListener SUCCESS: retaining path = [EventListener, InternalNode, HTMLBodyElement, HTMLHtmlElement, HTMLDocument]
(async function(testRunner) { (async function(testRunner) {
var {page, session, dp} = await testRunner.startBlank( var {page, session, dp} = await testRunner.startBlank(
`Test that all nodes from the detached DOM tree will get into one group in the heap snapshot. Bug 107819.`); `Test retaining path for an event listener.`);
await session.evaluate(` await session.evaluate(`
function addEventListenerAndRunTest() { function addEventListenerAndRunTest() {
...@@ -26,24 +26,13 @@ ...@@ -26,24 +26,13 @@
if (node) if (node)
testRunner.log('SUCCESS: found ' + node.name()); testRunner.log('SUCCESS: found ' + node.name());
else else
return testRunner.fail('cannot find detached DOM trees root'); return testRunner.fail('cannot find myEventListener node');
var nativeRetainers = 0; var retainers = helper.firstRetainingPath(node).map(node => node.name());
for (var iter = node.retainers(); iter.hasNext(); iter.next()) { // Limit to the retainers until the Window object to keep the test robust
var retainingEdge = iter.retainer; // against root node name changes.
if (retainingEdge.isInternal() && retainingEdge.name() === 'native') { retainers = retainers.slice(0, retainers.indexOf('Window'));
if (++nativeRetainers === 1) { var actual = retainers.join(', ');
var retainerName = retainingEdge.node().name(); testRunner.log(`SUCCESS: retaining path = [${actual}]`);
if (retainerName === 'HTMLBodyElement')
testRunner.log('SUCCESS: found link from HTMLBodyElement to ' + node.name());
else
return testRunner.fail('unexpected retainer of ' + node.name() + ': ' + retainerName);
} else
return testRunner.fail('too many retainers of ' + node.name());
} else if (!retainingEdge.isWeak())
return testRunner.fail('unexpected retaining edge of ' + node.name() + ' type: ' + retainingEdge.type() + ', name: ' + retainingEdge.name());
}
if (!nativeRetainers)
return testRunner.fail('cannot find HTMLBodyElement among retainers of ' + node.name());
testRunner.completeTest(); testRunner.completeTest();
}) })
Test multiple retaining path for an object.
Took heap snapshot
Parsed snapshot
SUCCESS: found leaking
SUCCESS: immediate retainer is EventListener.
SUCCESS: found multiple retaining paths.
SUCCESS: path1 = [HTMLBodyElement, HTMLHtmlElement, HTMLDocument]
SUCCESS: path2 = [HTMLDivElement, HTMLBodyElement, HTMLHtmlElement, HTMLDocument]
(async function(testRunner) {
var {page, session, dp} = await testRunner.startBlank(
`Test multiple retaining path for an object.`);
await session.evaluate(`
function run() {
function leaking() {
console.log('leaking');
}
var div = document.createElement('div');
document.body.appendChild(div);
div.addEventListener('click', leaking, true);
document.body.addEventListener('click', leaking, true);
}
run();
`);
var Helper = await testRunner.loadScript('resources/heap-snapshot-common.js');
var helper = await Helper(testRunner, session);
var snapshot = await helper.takeHeapSnapshot();
var node;
for (var it = snapshot._allNodes(); it.hasNext(); it.next()) {
if (it.node.type() === 'closure' && it.node.name() === 'leaking') {
node = it.node;
break;
}
}
if (node)
testRunner.log('SUCCESS: found ' + node.name());
else
return testRunner.fail('cannot find the leaking node');
var eventListener = helper.firstRetainingPath(node)[0];
if (eventListener.name() == 'EventListener') {
testRunner.log('SUCCESS: immediate retainer is EventListener.');
} else {
return testRunner.fail('cannot find the EventListener.');
}
var retainingPaths = [];
for (var iter = eventListener.retainers(); iter.hasNext(); iter.next()) {
var path = helper.firstRetainingPath(iter.retainer.node());
path = path.map(node => node.name());
// Limit the path until the Window object to keep the test robust
// against root node name changes.
path = path.slice(0, path.indexOf('Window'));
retainingPaths.push(path.join(', '));
}
if (retainingPaths.length >= 2) {
testRunner.log('SUCCESS: found multiple retaining paths.');
} else {
return testRunner.fail('cannot find multiple retaining paths.');
}
// Sort alphabetically to make the test robust.
retainingPaths.sort((a, b) => (a < b ? -1 : (a == b ? 0 : 1)));
testRunner.log(`SUCCESS: path1 = [${retainingPaths[0]}]`);
testRunner.log(`SUCCESS: path2 = [${retainingPaths[1]}]`);
testRunner.completeTest();
})
...@@ -28,7 +28,22 @@ ...@@ -28,7 +28,22 @@
return snapshot; return snapshot;
} }
function firstRetainingPath(node) {
for (var iter = node.retainers(); iter.hasNext(); iter.next()) {
var retainingEdge = iter.retainer;
var retainer = retainingEdge.node();
if (retainingEdge.isWeak() ||
retainer.distance() >= node.distance()) continue;
var path = firstRetainingPath(retainer);
path.unshift(retainer);
return path;
}
return [];
}
return { return {
firstRetainingPath: firstRetainingPath,
takeHeapSnapshot: function() { takeHeapSnapshot: function() {
return takeHeapSnapshotInternal(() => session.protocol.HeapProfiler.takeHeapSnapshot()); return takeHeapSnapshotInternal(() => session.protocol.HeapProfiler.takeHeapSnapshot());
}, },
......
...@@ -112,6 +112,8 @@ bindings_core_v8_files = ...@@ -112,6 +112,8 @@ bindings_core_v8_files =
"core/v8/V8CrossOriginSetterInfo.h", "core/v8/V8CrossOriginSetterInfo.h",
"core/v8/V8DOMConfiguration.cpp", "core/v8/V8DOMConfiguration.cpp",
"core/v8/V8DOMConfiguration.h", "core/v8/V8DOMConfiguration.h",
"core/v8/V8EmbedderGraphBuilder.cpp",
"core/v8/V8EmbedderGraphBuilder.h",
"core/v8/V8ErrorHandler.cpp", "core/v8/V8ErrorHandler.cpp",
"core/v8/V8ErrorHandler.h", "core/v8/V8ErrorHandler.h",
"core/v8/V8EventListener.cpp", "core/v8/V8EventListener.cpp",
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "bindings/core/v8/V8EmbedderGraphBuilder.h"
#include "bindings/core/v8/ActiveScriptWrappable.h"
#include "bindings/core/v8/V8Node.h"
#include "platform/bindings/DOMWrapperMap.h"
#include "platform/bindings/ScriptWrappable.h"
#include "platform/bindings/ScriptWrappableVisitor.h"
#include "platform/bindings/WrapperTypeInfo.h"
namespace blink {
V8EmbedderGraphBuilder::V8EmbedderGraphBuilder(v8::Isolate* isolate,
Graph* graph)
: isolate_(isolate), current_parent_(nullptr), graph_(graph) {}
void V8EmbedderGraphBuilder::BuildEmbedderGraphCallback(
v8::Isolate* isolate,
v8::EmbedderGraph* graph) {
V8EmbedderGraphBuilder builder(isolate, graph);
builder.BuildEmbedderGraph();
}
void V8EmbedderGraphBuilder::BuildEmbedderGraph() {
isolate_->VisitHandlesWithClassIds(this);
VisitPendingActivities();
VisitTransitiveClosure();
}
void V8EmbedderGraphBuilder::VisitPersistentHandle(
v8::Persistent<v8::Value>* value,
uint16_t class_id) {
if (class_id != WrapperTypeInfo::kNodeClassId &&
class_id != WrapperTypeInfo::kObjectClassId)
return;
v8::Local<v8::Object> v8_value = v8::Local<v8::Object>::New(
isolate_, v8::Persistent<v8::Object>::Cast(*value));
ScriptWrappable* traceable = ToScriptWrappable(v8_value);
if (traceable) {
// Add v8_value => traceable edge.
Graph::Node* graph_node =
GraphNode(traceable, traceable->NameInHeapSnapshot());
graph_->AddEdge(GraphNode(v8_value), graph_node);
// Visit traceable members. This will also add traceable => v8_value edge.
ParentScope parent(this, graph_node);
traceable->TraceWrappers(this);
}
}
void V8EmbedderGraphBuilder::Visit(
const TraceWrapperV8Reference<v8::Value>& traced_wrapper) const {
const v8::PersistentBase<v8::Value>* value = &traced_wrapper.Get();
// Add an edge from the current parent to the V8 object.
v8::Local<v8::Value> v8_value = v8::Local<v8::Value>::New(isolate_, *value);
if (!v8_value.IsEmpty()) {
graph_->AddEdge(current_parent_, GraphNode(v8_value));
}
}
void V8EmbedderGraphBuilder::Visit(
const WrapperDescriptor& wrapper_descriptor) const {
// Add an edge from the current parent to this object.
// Also push the object to the worklist in order to process its members.
const void* traceable = wrapper_descriptor.traceable;
Graph::Node* graph_node =
GraphNode(traceable, wrapper_descriptor.name_callback(traceable));
graph_->AddEdge(current_parent_, graph_node);
if (!visited_.Contains(traceable)) {
visited_.insert(traceable);
worklist_.push_back(ToWorklistItem(graph_node, wrapper_descriptor));
}
}
void V8EmbedderGraphBuilder::Visit(DOMWrapperMap<ScriptWrappable>* wrapper_map,
const ScriptWrappable* key) const {
// Add an edge from the current parent to the V8 object.
v8::Local<v8::Value> v8_value =
wrapper_map->NewLocal(isolate_, const_cast<ScriptWrappable*>(key));
if (!v8_value.IsEmpty())
graph_->AddEdge(current_parent_, GraphNode(v8_value));
}
v8::EmbedderGraph::Node* V8EmbedderGraphBuilder::GraphNode(
const v8::Local<v8::Value>& value) const {
return graph_->V8Node(value);
}
v8::EmbedderGraph::Node* V8EmbedderGraphBuilder::GraphNode(
Traceable traceable,
const char* name) const {
auto iter = graph_node_.find(traceable);
if (iter != graph_node_.end())
return iter->value;
// Ownership of the new node is transferred to the graph_.
// graph_node_.at(tracable) is valid for all BuildEmbedderGraph execution.
auto node =
graph_->AddNode(std::unique_ptr<Graph::Node>(new EmbedderNode(name)));
graph_node_.insert(traceable, node);
return node;
}
void V8EmbedderGraphBuilder::VisitPendingActivities() {
// Ownership of the new node is transferred to the graph_.
Graph::Node* root = graph_->AddNode(
std::unique_ptr<Graph::Node>(new EmbedderRootNode("Pending activities")));
ParentScope parent(this, root);
ActiveScriptWrappableBase::TraceActiveScriptWrappables(isolate_, this);
}
V8EmbedderGraphBuilder::WorklistItem V8EmbedderGraphBuilder::ToWorklistItem(
Graph::Node* node,
const WrapperDescriptor& wrapper_descriptor) const {
return {node, wrapper_descriptor.traceable,
wrapper_descriptor.trace_wrappers_callback};
}
void V8EmbedderGraphBuilder::VisitTransitiveClosure() {
// Depth-first search.
while (!worklist_.empty()) {
auto item = worklist_.back();
worklist_.pop_back();
ParentScope parent(this, item.node);
item.trace_wrappers_callback(this, item.traceable);
}
}
} // namespace blink
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8EmbedderGraphBuilder_h
#define V8EmbedderGraphBuilder_h
#include "platform/bindings/ScriptWrappableVisitor.h"
#include "v8/include/v8-profiler.h"
#include "v8/include/v8.h"
namespace blink {
class V8EmbedderGraphBuilder : public ScriptWrappableVisitor,
public v8::PersistentHandleVisitor {
public:
using Traceable = const void*;
using Graph = v8::EmbedderGraph;
V8EmbedderGraphBuilder(v8::Isolate*, Graph*);
static void BuildEmbedderGraphCallback(v8::Isolate*, v8::EmbedderGraph*);
void BuildEmbedderGraph();
// v8::PersistentHandleVisitor override.
void VisitPersistentHandle(v8::Persistent<v8::Value>*,
uint16_t class_id) override;
protected:
// ScriptWrappableVisitor overrides.
void Visit(const TraceWrapperV8Reference<v8::Value>&) const final;
void Visit(const WrapperDescriptor&) const final;
void Visit(DOMWrapperMap<ScriptWrappable>*,
const ScriptWrappable*) const final;
private:
class EmbedderNode : public Graph::Node {
public:
explicit EmbedderNode(const char* name) : name_(name) {}
// Graph::Node overrides.
const char* Name() override { return name_; }
size_t SizeInBytes() override { return 0; }
private:
const char* name_;
};
class EmbedderRootNode : public EmbedderNode {
public:
explicit EmbedderRootNode(const char* name) : EmbedderNode(name) {}
// Graph::Node override.
bool IsRootNode() { return true; }
};
class ParentScope {
STACK_ALLOCATED();
public:
ParentScope(V8EmbedderGraphBuilder* visitor, Graph::Node* parent)
: visitor_(visitor) {
DCHECK_EQ(visitor->current_parent_, nullptr);
visitor->current_parent_ = parent;
}
~ParentScope() { visitor_->current_parent_ = nullptr; }
private:
V8EmbedderGraphBuilder* visitor_;
};
struct WorklistItem {
Graph::Node* node;
Traceable traceable;
TraceWrappersCallback trace_wrappers_callback;
};
WorklistItem ToWorklistItem(Graph::Node*, const WrapperDescriptor&) const;
Graph::Node* GraphNode(const v8::Local<v8::Value>&) const;
Graph::Node* GraphNode(Traceable, const char* name) const;
void VisitPendingActivities();
void VisitTransitiveClosure();
v8::Isolate* isolate_;
Graph::Node* current_parent_;
mutable Graph* graph_;
mutable HashSet<Traceable> visited_;
mutable HashMap<Traceable, Graph::Node*> graph_node_;
mutable Deque<WorklistItem> worklist_;
};
} // namespace blink
#endif // V8EmbedderGraphBuilder_h
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "bindings/core/v8/V8BindingForCore.h" #include "bindings/core/v8/V8BindingForCore.h"
#include "bindings/core/v8/V8ContextSnapshot.h" #include "bindings/core/v8/V8ContextSnapshot.h"
#include "bindings/core/v8/V8DOMException.h" #include "bindings/core/v8/V8DOMException.h"
#include "bindings/core/v8/V8EmbedderGraphBuilder.h"
#include "bindings/core/v8/V8ErrorEvent.h" #include "bindings/core/v8/V8ErrorEvent.h"
#include "bindings/core/v8/V8ErrorHandler.h" #include "bindings/core/v8/V8ErrorHandler.h"
#include "bindings/core/v8/V8GCController.h" #include "bindings/core/v8/V8GCController.h"
...@@ -673,6 +674,8 @@ void V8Initializer::InitializeMainThread(const intptr_t* reference_table) { ...@@ -673,6 +674,8 @@ void V8Initializer::InitializeMainThread(const intptr_t* reference_table) {
profiler->SetWrapperClassInfoProvider( profiler->SetWrapperClassInfoProvider(
WrapperTypeInfo::kNodeClassId, &RetainedDOMInfo::CreateRetainedDOMInfo); WrapperTypeInfo::kNodeClassId, &RetainedDOMInfo::CreateRetainedDOMInfo);
profiler->SetGetRetainerInfosCallback(&V8GCController::GetRetainerInfos); profiler->SetGetRetainerInfosCallback(&V8GCController::GetRetainerInfos);
profiler->SetBuildEmbedderGraphCallback(
&V8EmbedderGraphBuilder::BuildEmbedderGraphCallback);
} }
DCHECK(ThreadState::MainThreadState()); DCHECK(ThreadState::MainThreadState());
......
...@@ -39,7 +39,6 @@ using NameCallback = const char* (*)(const void* self); ...@@ -39,7 +39,6 @@ using NameCallback = const char* (*)(const void* self);
inline void TraceTrait<ClassName>::TraceMarkedWrapper( \ inline void TraceTrait<ClassName>::TraceMarkedWrapper( \
const ScriptWrappableVisitor* visitor, const void* t) { \ const ScriptWrappableVisitor* visitor, const void* t) { \
const ClassName* traceable = ToWrapperTracingType(t); \ const ClassName* traceable = ToWrapperTracingType(t); \
DCHECK(GetHeapObjectHeader(traceable)->IsWrapperHeaderMarked()); \
traceable->TraceWrappers(visitor); \ traceable->TraceWrappers(visitor); \
} }
......
...@@ -251,7 +251,6 @@ template <typename T> ...@@ -251,7 +251,6 @@ template <typename T>
void TraceTrait<T>::TraceMarkedWrapper(const ScriptWrappableVisitor* visitor, void TraceTrait<T>::TraceMarkedWrapper(const ScriptWrappableVisitor* visitor,
const void* t) { const void* t) {
const T* traceable = ToWrapperTracingType(t); const T* traceable = ToWrapperTracingType(t);
DCHECK(GetHeapObjectHeader(traceable)->IsWrapperHeaderMarked());
AdjustAndMarkTrait<T>::TraceMarkedWrapper(visitor, traceable); AdjustAndMarkTrait<T>::TraceMarkedWrapper(visitor, traceable);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment