Diff
Modified: trunk/LayoutTests/ChangeLog (133043 => 133044)
--- trunk/LayoutTests/ChangeLog 2012-10-31 17:21:36 UTC (rev 133043)
+++ trunk/LayoutTests/ChangeLog 2012-10-31 17:33:32 UTC (rev 133044)
@@ -1,3 +1,14 @@
+2012-10-31 Adam Barth <[email protected]>
+
+ [V8] Garbage collection should use opaque roots rather than implicit references
+ https://bugs.webkit.org/show_bug.cgi?id=100707
+
+ Reviewed by Kentaro Hara.
+
+ Test progression.
+
+ * platform/chromium/fast/dom/gc-9-expected.txt:
+
2012-10-31 Stephen White <[email protected]>
[chromium] Added skipped expectations for new test
Modified: trunk/LayoutTests/platform/chromium/fast/dom/gc-9-expected.txt (133043 => 133044)
--- trunk/LayoutTests/platform/chromium/fast/dom/gc-9-expected.txt 2012-10-31 17:21:36 UTC (rev 133043)
+++ trunk/LayoutTests/platform/chromium/fast/dom/gc-9-expected.txt 2012-10-31 17:33:32 UTC (rev 133044)
@@ -69,8 +69,8 @@
FAIL: document.body.style.myCustomProperty should be 1 but instead is undefined.
FAIL: document.body.style.getPropertyCSSValue('color').myCustomProperty should be 1 but instead is undefined.
PASS: document.styleSheets.myCustomProperty should be 1 and is.
-FAIL: document.styleSheets[0].myCustomProperty should be 1 but instead is undefined.
-FAIL: document.styleSheets[0].cssRules.myCustomProperty should be 1 but instead is undefined.
+PASS: document.styleSheets[0].myCustomProperty should be 1 and is.
+PASS: document.styleSheets[0].cssRules.myCustomProperty should be 1 and is.
FAIL: document.styleSheets[0].cssRules[0].myCustomProperty should be 1 but instead is undefined.
PASS: new XPathEvaluator().myCustomProperty should be undefined and is.
PASS: new XPathEvaluator().evaluate('/', document, null, 0, null).myCustomProperty should be undefined and is.
Modified: trunk/Source/WebCore/ChangeLog (133043 => 133044)
--- trunk/Source/WebCore/ChangeLog 2012-10-31 17:21:36 UTC (rev 133043)
+++ trunk/Source/WebCore/ChangeLog 2012-10-31 17:33:32 UTC (rev 133044)
@@ -1,3 +1,69 @@
+2012-10-31 Adam Barth <[email protected]>
+
+ [V8] Garbage collection should use opaque roots rather than implicit references
+ https://bugs.webkit.org/show_bug.cgi?id=100707
+
+ Reviewed by Kentaro Hara.
+
+ This patch replaces visitDOMWrapper with opaqueRootForGC. The
+ former used to inform V8 of implicit relationships between wrapper
+ objects on a per-wrapper basis. That meant that we needed to know which
+ DOMDataStore a given wrapper was in during garbage collection.
+
+ After this patch, we now use object groups rather than implicit
+ references to inform V8 of these relationships. That has two benefits:
+
+ 1) We no longer need to know which DOMDataStore a wrapper belongs
+ because we don't need to find the exact source wrapper for the
+ implicit connection.
+
+ 2) We can now handle more complicated implicit relationships, for
+ example when some of the intervening objects haven't had their
+ _javascript_ wrappers created yet.
+
+ This patch also unlocks to paths of future development:
+ A) Fixing the remaining failures in fast/dom/gc-9.html
+ B) Enumerating DOM wrappers entirely from V8 rather than from the
+ DOMWrapperMaps (so that we can move more object towards using
+ IntrusiveDOMWrapperMaps, which aren't enumerable from WebCore).
+
+ * bindings/scripts/CodeGeneratorV8.pm:
+ (NeedsCustomOpaqueRootForGC):
+ (GenerateOpaqueRootForGC):
+ (GenerateHeader):
+ (GenerateImplementation):
+ * bindings/v8/V8GCController.cpp:
+ (ImplicitConnection):
+ (WebCore::ImplicitConnection::ImplicitConnection):
+ (WebCore::ImplicitConnection::root):
+ (WebCore::ImplicitConnection::wrapper):
+ (WebCore):
+ (WebCore::operator<):
+ (WrapperGrouper):
+ (WebCore::WrapperGrouper::WrapperGrouper):
+ (WebCore::WrapperGrouper::addToGroup):
+ (WebCore::WrapperGrouper::keepAlive):
+ (WebCore::WrapperGrouper::apply):
+ (WebCore::ObjectVisitor::ObjectVisitor):
+ (WebCore::ObjectVisitor::visitDOMWrapper):
+ (ObjectVisitor):
+ (WebCore::V8GCController::opaqueRootForGC):
+ (WebCore::NodeVisitor::NodeVisitor):
+ (WebCore::NodeVisitor::visitNodeWrapper):
+ (NodeVisitor):
+ (WebCore::V8GCController::majorGCPrologue):
+ * bindings/v8/V8GCController.h:
+ (WebCore):
+ (V8GCController):
+ * bindings/v8/WrapperTypeInfo.h:
+ (WebCore):
+ (WebCore::WrapperTypeInfo::opaqueRootForGC):
+ (WrapperTypeInfo):
+ * bindings/v8/custom/V8NodeListCustom.cpp:
+ (WebCore::V8NodeList::opaqueRootForGC):
+ * bindings/v8/custom/V8SpeechRecognitionResultCustom.cpp:
+ (WebCore::V8SpeechRecognitionResult::opaqueRootForGC):
+
2012-10-31 Alexei Filippov <[email protected]>
Web Inspector: Add total node to native memory snapshot tree
Modified: trunk/Source/WebCore/bindings/scripts/CodeGeneratorV8.pm (133043 => 133044)
--- trunk/Source/WebCore/bindings/scripts/CodeGeneratorV8.pm 2012-10-31 17:21:36 UTC (rev 133043)
+++ trunk/Source/WebCore/bindings/scripts/CodeGeneratorV8.pm 2012-10-31 17:33:32 UTC (rev 133044)
@@ -181,7 +181,7 @@
}
}
-sub NeedsToVisitDOMWrapper
+sub NeedsCustomOpaqueRootForGC
{
my $dataNode = shift;
return GetGenerateIsReachable($dataNode) || GetCustomIsReachable($dataNode);
@@ -199,7 +199,7 @@
return $dataNode->extendedAttributes->{"CustomIsReachable"} || $dataNode->extendedAttributes->{"V8CustomIsReachable"};
}
-sub GenerateVisitDOMWrapper
+sub GenerateOpaqueRootForGC
{
my ($dataNode, $implClassName) = @_;
@@ -208,7 +208,7 @@
}
push(@implContent, <<END);
-void V8${implClassName}::visitDOMWrapper(DOMDataStore* store, void* object, v8::Persistent<v8::Object> wrapper)
+void* V8${implClassName}::opaqueRootForGC(void* object, v8::Persistent<v8::Object> wrapper)
{
${implClassName}* impl = static_cast<${implClassName}*>(object);
END
@@ -218,6 +218,8 @@
GetGenerateIsReachable($dataNode) eq "ImplOwnerNodeRoot" ||
GetGenerateIsReachable($dataNode) eq "ImplBaseRoot") {
+ $implIncludes{"V8GCController.h"} = 1;
+
my $methodName;
$methodName = "document" if (GetGenerateIsReachable($dataNode) eq "ImplDocument");
$methodName = "element" if (GetGenerateIsReachable($dataNode) eq "ImplElementRoot");
@@ -226,17 +228,13 @@
$methodName = "base" if (GetGenerateIsReachable($dataNode) eq "ImplBaseRoot");
push(@implContent, <<END);
- if (Node* owner = impl->${methodName}()) {
- v8::Persistent<v8::Object> ownerWrapper = store->domNodeMap().get(owner);
- if (!ownerWrapper.IsEmpty()) {
- v8::Persistent<v8::Value> value = wrapper;
- v8::V8::AddImplicitReferences(ownerWrapper, &value, 1);
- }
- }
+ if (Node* owner = impl->${methodName}())
+ return V8GCController::opaqueRootForGC(owner);
END
}
push(@implContent, <<END);
+ return object;
}
END
@@ -387,8 +385,8 @@
static WrapperTypeInfo info;
END
- if (NeedsToVisitDOMWrapper($dataNode)) {
- push(@headerContent, " static void visitDOMWrapper(DOMDataStore*, void*, v8::Persistent<v8::Object>);\n");
+ if (NeedsCustomOpaqueRootForGC($dataNode)) {
+ push(@headerContent, " static void* opaqueRootForGC(void*, v8::Persistent<v8::Object>);\n");
}
if ($dataNode->extendedAttributes->{"ActiveDOMObject"}) {
@@ -2594,7 +2592,7 @@
AddIncludesForType($interfaceName);
my $toActive = $dataNode->extendedAttributes->{"ActiveDOMObject"} ? "${className}::toActiveDOMObject" : "0";
- my $domVisitor = NeedsToVisitDOMWrapper($dataNode) ? "${className}::visitDOMWrapper" : "0";
+ my $rootForGC = NeedsCustomOpaqueRootForGC($dataNode) ? "${className}::opaqueRootForGC" : "0";
# Find the super descriptor.
my $parentClass = "";
@@ -2611,7 +2609,7 @@
my $WrapperTypePrototype = $dataNode->isException ? "WrapperTypeErrorPrototype" : "WrapperTypeObjectPrototype";
- push(@implContentDecls, "WrapperTypeInfo ${className}::info = { ${className}::GetTemplate, ${className}::derefObject, $toActive, $domVisitor, ${className}::installPerContextPrototypeProperties, $parentClassInfo, $WrapperTypePrototype };\n\n");
+ push(@implContentDecls, "WrapperTypeInfo ${className}::info = { ${className}::GetTemplate, ${className}::derefObject, $toActive, $rootForGC, ${className}::installPerContextPrototypeProperties, $parentClassInfo, $WrapperTypePrototype };\n\n");
push(@implContentDecls, "namespace ${interfaceName}V8Internal {\n\n");
push(@implContentDecls, "template <typename T> void V8_USE(T) { }\n\n");
@@ -2672,8 +2670,8 @@
GenerateReplaceableAttrSetter($dataNode, $implClassName);
}
- if (NeedsToVisitDOMWrapper($dataNode)) {
- GenerateVisitDOMWrapper($dataNode, $implClassName);
+ if (NeedsCustomOpaqueRootForGC($dataNode)) {
+ GenerateOpaqueRootForGC($dataNode, $implClassName);
}
if ($dataNode->extendedAttributes->{"TypedArray"}) {
Modified: trunk/Source/WebCore/bindings/v8/V8GCController.cpp (133043 => 133044)
--- trunk/Source/WebCore/bindings/v8/V8GCController.cpp 2012-10-31 17:21:36 UTC (rev 133043)
+++ trunk/Source/WebCore/bindings/v8/V8GCController.cpp 2012-10-31 17:33:32 UTC (rev 133044)
@@ -67,14 +67,79 @@
namespace WebCore {
+class ImplicitConnection {
+public:
+ ImplicitConnection(void* root, v8::Persistent<v8::Value> wrapper)
+ : m_root(root)
+ , m_wrapper(wrapper)
+ {
+ }
+
+ void* root() const { return m_root; }
+ v8::Persistent<v8::Value> wrapper() const { return m_wrapper; }
+
+private:
+ void* m_root;
+ v8::Persistent<v8::Value> m_wrapper;
+};
+
+bool operator<(const ImplicitConnection& left, const ImplicitConnection& right)
+{
+ return left.root() < right.root();
+}
+
+class WrapperGrouper {
+public:
+ WrapperGrouper()
+ {
+ m_liveObjects.append(V8PerIsolateData::current()->ensureLiveRoot());
+ }
+
+ void addToGroup(void* root, v8::Persistent<v8::Value> wrapper)
+ {
+ m_connections.append(ImplicitConnection(root, wrapper));
+ }
+
+ void keepAlive(v8::Persistent<v8::Value> wrapper)
+ {
+ m_liveObjects.append(wrapper);
+ }
+
+ void apply()
+ {
+ if (m_liveObjects.size() > 1)
+ v8::V8::AddObjectGroup(m_liveObjects.data(), m_liveObjects.size());
+
+ std::sort(m_connections.begin(), m_connections.end());
+ Vector<v8::Persistent<v8::Value> > group;
+ size_t i = 0;
+ while (i < m_connections.size()) {
+ void* root = m_connections[i].root();
+
+ do {
+ group.append(m_connections[i++].wrapper());
+ } while (i < m_connections.size() && root == m_connections[i].root());
+
+ if (group.size() > 1)
+ v8::V8::AddObjectGroup(group.data(), group.size(), 0);
+
+ group.shrink(0);
+ }
+ }
+
+private:
+ Vector<v8::Persistent<v8::Value> > m_liveObjects;
+ Vector<ImplicitConnection> m_connections;
+};
+
class ObjectVisitor : public DOMWrapperVisitor<void> {
public:
- explicit ObjectVisitor(Vector<v8::Persistent<v8::Value> >* liveObjects)
- : m_liveObjects(liveObjects)
+ explicit ObjectVisitor(WrapperGrouper* grouper)
+ : m_grouper(grouper)
{
}
- void visitDOMWrapper(DOMDataStore* store, void* object, v8::Persistent<v8::Object> wrapper)
+ void visitDOMWrapper(DOMDataStore*, void* object, v8::Persistent<v8::Object> wrapper)
{
WrapperTypeInfo* type = V8DOMWrapper::domWrapperType(wrapper);
@@ -84,20 +149,21 @@
// implementation can't tell the difference.
MessagePort* port = static_cast<MessagePort*>(object);
if (port->isEntangled() || port->hasPendingActivity())
- m_liveObjects->append(wrapper);
+ m_grouper->keepAlive(wrapper);
} else {
ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(wrapper);
if (activeDOMObject && activeDOMObject->hasPendingActivity())
- m_liveObjects->append(wrapper);
+ m_grouper->keepAlive(wrapper);
}
- type->visitDOMWrapper(store, object, wrapper);
+ m_grouper->addToGroup(type->opaqueRootForGC(object, wrapper), wrapper);
}
private:
- Vector<v8::Persistent<v8::Value> >* m_liveObjects;
+ WrapperGrouper* m_grouper;
};
+// FIXME: This should use opaque GC roots.
static void addImplicitReferencesForNodeWithEventListeners(Node* node, v8::Persistent<v8::Object> wrapper)
{
ASSERT(node->hasEventListeners());
@@ -120,15 +186,16 @@
v8::V8::AddImplicitReferences(wrapper, listeners.data(), listeners.size());
}
-static Node* rootForGC(Node* node)
+void* V8GCController::opaqueRootForGC(Node* node)
{
if (node->inDocument() || (node->hasTagName(HTMLNames::imgTag) && static_cast<HTMLImageElement*>(node)->hasPendingActivity()))
return node->document();
if (node->isAttributeNode()) {
- node = static_cast<Attr*>(node)->ownerElement();
- if (!node)
- return 0;
+ Node* ownerElement = static_cast<Attr*>(node)->ownerElement();
+ if (!ownerElement)
+ return node;
+ node = ownerElement;
}
while (Node* parent = node->parentOrHostNode())
@@ -137,31 +204,10 @@
return node;
}
-class ImplicitConnection {
-public:
- ImplicitConnection(Node* root, v8::Persistent<v8::Value> wrapper)
- : m_root(root)
- , m_wrapper(wrapper)
- {
- }
-
- Node* root() const { return m_root; }
- v8::Persistent<v8::Value> wrapper() const { return m_wrapper; }
-
-public:
- Node* m_root;
- v8::Persistent<v8::Value> m_wrapper;
-};
-
-bool operator<(const ImplicitConnection& left, const ImplicitConnection& right)
-{
- return left.root() < right.root();
-}
-
class NodeVisitor : public NodeWrapperVisitor {
public:
- explicit NodeVisitor(Vector<v8::Persistent<v8::Value> >* liveObjects)
- : m_liveObjects(liveObjects)
+ explicit NodeVisitor(WrapperGrouper* grouper)
+ : m_grouper(grouper)
{
}
@@ -174,36 +220,13 @@
ActiveDOMObject* activeDOMObject = type->toActiveDOMObject(wrapper);
if (activeDOMObject && activeDOMObject->hasPendingActivity())
- m_liveObjects->append(wrapper);
+ m_grouper->keepAlive(wrapper);
- Node* root = rootForGC(node);
- if (!root)
- return;
- m_connections.append(ImplicitConnection(root, wrapper));
+ m_grouper->addToGroup(V8GCController::opaqueRootForGC(node), wrapper);
}
- void applyGrouping()
- {
- std::sort(m_connections.begin(), m_connections.end());
- Vector<v8::Persistent<v8::Value> > group;
- size_t i = 0;
- while (i < m_connections.size()) {
- Node* root = m_connections[i].root();
-
- do {
- group.append(m_connections[i++].wrapper());
- } while (i < m_connections.size() && root == m_connections[i].root());
-
- if (group.size() > 1)
- v8::V8::AddObjectGroup(group.data(), group.size(), new RetainedDOMInfo(root));
-
- group.shrink(0);
- }
- }
-
private:
- Vector<v8::Persistent<v8::Value> >* m_liveObjects;
- Vector<ImplicitConnection> m_connections;
+ WrapperGrouper* m_grouper;
};
void V8GCController::gcPrologue(v8::GCType type, v8::GCCallbackFlags flags)
@@ -224,17 +247,14 @@
v8::HandleScope scope;
- Vector<v8::Persistent<v8::Value> > liveObjects;
- liveObjects.append(V8PerIsolateData::current()->ensureLiveRoot());
+ WrapperGrouper grouper;
- NodeVisitor nodeVisitor(&liveObjects);
+ NodeVisitor nodeVisitor(&grouper);
+ ObjectVisitor objectVisitor(&grouper);
visitAllDOMNodes(&nodeVisitor);
- nodeVisitor.applyGrouping();
-
- ObjectVisitor objectVisitor(&liveObjects);
visitDOMObjects(&objectVisitor);
- v8::V8::AddObjectGroup(liveObjects.data(), liveObjects.size());
+ grouper.apply();
V8PerIsolateData* data = ""
data->stringCache()->clearOnGC();
Modified: trunk/Source/WebCore/bindings/v8/V8GCController.h (133043 => 133044)
--- trunk/Source/WebCore/bindings/v8/V8GCController.h 2012-10-31 17:21:36 UTC (rev 133043)
+++ trunk/Source/WebCore/bindings/v8/V8GCController.h 2012-10-31 17:33:32 UTC (rev 133044)
@@ -35,6 +35,8 @@
namespace WebCore {
+class Node;
+
class V8GCController {
public:
static void gcPrologue(v8::GCType, v8::GCCallbackFlags);
@@ -47,6 +49,8 @@
static void checkMemoryUsage();
static void hintForCollectGarbage();
static void collectGarbage();
+
+ static void* opaqueRootForGC(Node*);
};
}
Modified: trunk/Source/WebCore/bindings/v8/WrapperTypeInfo.h (133043 => 133044)
--- trunk/Source/WebCore/bindings/v8/WrapperTypeInfo.h 2012-10-31 17:21:36 UTC (rev 133043)
+++ trunk/Source/WebCore/bindings/v8/WrapperTypeInfo.h 2012-10-31 17:33:32 UTC (rev 133044)
@@ -47,7 +47,7 @@
typedef v8::Persistent<v8::FunctionTemplate> (*GetTemplateFunction)();
typedef void (*DerefObjectFunction)(void*);
typedef ActiveDOMObject* (*ToActiveDOMObjectFunction)(v8::Handle<v8::Object>);
- typedef void (*DOMWrapperVisitorFunction)(DOMDataStore*, void*, v8::Persistent<v8::Object>);
+ typedef void* (*OpaqueRootForGC)(void*, v8::Persistent<v8::Object>);
typedef void (*InstallPerContextPrototypePropertiesFunction)(v8::Handle<v8::Object>);
enum WrapperTypePrototype {
@@ -102,16 +102,17 @@
return toActiveDOMObjectFunction(object);
}
- void visitDOMWrapper(DOMDataStore* store, void* object, v8::Persistent<v8::Object> wrapper)
+ void* opaqueRootForGC(void* object, v8::Persistent<v8::Object> wrapper)
{
- if (domWrapperVisitorFunction)
- domWrapperVisitorFunction(store, object, wrapper);
+ if (!opaqueRootForGCFunction)
+ return object;
+ return opaqueRootForGCFunction(object, wrapper);
}
const GetTemplateFunction getTemplateFunction;
const DerefObjectFunction derefObjectFunction;
const ToActiveDOMObjectFunction toActiveDOMObjectFunction;
- const DOMWrapperVisitorFunction domWrapperVisitorFunction;
+ const OpaqueRootForGC opaqueRootForGCFunction;
const InstallPerContextPrototypePropertiesFunction installPerContextPrototypePropertiesFunction;
const WrapperTypeInfo* parentClass;
const WrapperTypePrototype wrapperTypePrototype;
Modified: trunk/Source/WebCore/bindings/v8/custom/V8NodeListCustom.cpp (133043 => 133044)
--- trunk/Source/WebCore/bindings/v8/custom/V8NodeListCustom.cpp 2012-10-31 17:21:36 UTC (rev 133043)
+++ trunk/Source/WebCore/bindings/v8/custom/V8NodeListCustom.cpp 2012-10-31 17:33:32 UTC (rev 133044)
@@ -34,6 +34,7 @@
#include "DynamicNodeList.h"
#include "NodeList.h"
#include "V8Binding.h"
+#include "V8GCController.h"
#include "V8Node.h"
#include <wtf/RefPtr.h>
@@ -59,19 +60,16 @@
return toV8(result.release(), info.Holder(), info.GetIsolate());
}
-void V8NodeList::visitDOMWrapper(DOMDataStore* store, void* object, v8::Persistent<v8::Object> wrapper)
+void* V8NodeList::opaqueRootForGC(void* object, v8::Persistent<v8::Object> wrapper)
{
+ ASSERT(V8NodeList::HasInstance(wrapper));
NodeList* impl = static_cast<NodeList*>(object);
- if (impl->isDynamicNodeList()) {
- Node* owner = static_cast<DynamicNodeList*>(impl)->ownerNode();
- if (owner) {
- v8::Persistent<v8::Object> ownerWrapper = store->domNodeMap().get(owner);
- if (!ownerWrapper.IsEmpty()) {
- v8::Persistent<v8::Value> value = wrapper;
- v8::V8::AddImplicitReferences(ownerWrapper, &value, 1);
- }
- }
- }
+ if (!impl->isDynamicNodeList())
+ return object;
+ Node* owner = static_cast<DynamicNodeList*>(impl)->ownerNode();
+ if (!owner)
+ return object;
+ return V8GCController::opaqueRootForGC(owner);
}
} // namespace WebCore
Modified: trunk/Source/WebCore/bindings/v8/custom/V8SpeechRecognitionResultCustom.cpp (133043 => 133044)
--- trunk/Source/WebCore/bindings/v8/custom/V8SpeechRecognitionResultCustom.cpp 2012-10-31 17:21:36 UTC (rev 133043)
+++ trunk/Source/WebCore/bindings/v8/custom/V8SpeechRecognitionResultCustom.cpp 2012-10-31 17:33:32 UTC (rev 133044)
@@ -31,16 +31,15 @@
#include "SpeechRecognitionResult.h"
#include "V8Binding.h"
+#include "V8GCController.h"
namespace WebCore {
-void V8SpeechRecognitionResult::visitDOMWrapper(DOMDataStore* store, void* object, v8::Persistent<v8::Object> wrapper)
+void* V8SpeechRecognitionResult::opaqueRootForGC(void* object, v8::Persistent<v8::Object> wrapper)
{
+ ASSERT(V8SpeechRecognitionResult::HasInstance(wrapper));
SpeechRecognitionResult* impl = static_cast<SpeechRecognitionResult*>(object);
- Document* emma = impl->emma();
- v8::Persistent<v8::Value> emmaWrapper = store->domNodeMap().get(emma);
- if (!emmaWrapper.IsEmpty())
- v8::V8::AddImplicitReferences(wrapper, &emmaWrapper, 1);
+ return V8GCController::opaqueRootForGC(impl->emma());
}
} // namespace WebCore