Bug 842561 - Assert that our inheritance chain is correct for WebIDL objects. r=peterv, a=lsblakk
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 22 Feb 2013 09:56:29 -0500
changeset 128445 6b56e7dcd0c6f2793324668a2c7e3b693a8a7ec7
parent 128444 236b2aa5d24f72c81803a3113c1091fe0a2c6c4e
child 128446 22d26a3e75e37604f0c4f5c73dcee8a7b03edb7e
push id3413
push userryanvm@gmail.com
push dateMon, 25 Feb 2013 20:16:49 +0000
treeherdermozilla-aurora@f16d6c390b5d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv, lsblakk
bugs842561
milestone21.0a2
Bug 842561 - Assert that our inheritance chain is correct for WebIDL objects. r=peterv, a=lsblakk We could drop the descriptor for Text if we changed nsIDocument::CreateTextNode to return an already_AddRefed<Text>, but then we'd need more casting in nsDocument.cpp for the XPCOM CreateTextNode. Not sure which way is better, really.
content/base/src/Makefile.in
content/base/src/Text.cpp
content/base/src/Text.h
content/base/src/nsTextNode.cpp
content/base/src/nsTextNode.h
content/xml/content/src/CDATASection.h
dom/bindings/Bindings.conf
dom/bindings/Codegen.py
--- a/content/base/src/Makefile.in
+++ b/content/base/src/Makefile.in
@@ -46,16 +46,17 @@ EXPORTS_NAMESPACES = mozilla/dom
 
 EXPORTS_mozilla/dom = \
   Comment.h \
   DocumentFragment.h \
   DocumentType.h \
   DOMImplementation.h \
   EventSource.h \
   Link.h \
+  Text.h \
   $(NULL)
 
 CPPSRCS		= \
 		Comment.cpp \
 		DirectionalityUtils.cpp \
 		DocumentType.cpp \
 		DOMImplementation.cpp \
 		EventSource.cpp \
@@ -115,16 +116,17 @@ CPPSRCS		= \
 		nsReferencedElement.cpp \
 		nsScriptElement.cpp \
 		nsScriptLoader.cpp \
 		nsStubDocumentObserver.cpp \
 		nsStubMutationObserver.cpp \
 		nsStyledElement.cpp \
 		nsStyleLinkElement.cpp \
 		nsSyncLoadService.cpp \
+		Text.cpp \
 		nsTextFragment.cpp \
 		nsTextNode.cpp \
 		nsTraversal.cpp \
 		nsTreeSanitizer.cpp \
 		nsTreeWalker.cpp \
                 nsViewportInfo.cpp \
 		WebSocket.cpp \
 		nsXHTMLContentSerializer.cpp \
new file mode 100644
--- /dev/null
+++ b/content/base/src/Text.cpp
@@ -0,0 +1,23 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/Text.h"
+
+namespace mozilla {
+namespace dom {
+
+already_AddRefed<Text>
+Text::SplitText(uint32_t aOffset, ErrorResult& rv)
+{
+  nsCOMPtr<nsIContent> newChild;
+  rv = SplitData(aOffset, getter_AddRefs(newChild));
+  if (rv.Failed()) {
+    return nullptr;
+  }
+  return static_cast<Text*>(newChild.forget().get());
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/content/base/src/Text.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_Text_h
+#define mozilla_dom_Text_h
+
+#include "nsGenericDOMDataNode.h"
+#include "mozilla/ErrorResult.h"
+
+namespace mozilla {
+namespace dom {
+
+class Text : public nsGenericDOMDataNode
+{
+public:
+  Text(already_AddRefed<nsINodeInfo> aNodeInfo)
+    : nsGenericDOMDataNode(aNodeInfo)
+  {}
+
+  using nsGenericDOMDataNode::GetWholeText;
+
+  // WebIDL API
+  already_AddRefed<Text> SplitText(uint32_t aOffset, ErrorResult& rv);
+  void GetWholeText(nsAString& aWholeText, ErrorResult& rv)
+  {
+    rv = GetWholeText(aWholeText);
+  }
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_Text_h
--- a/content/base/src/nsTextNode.cpp
+++ b/content/base/src/nsTextNode.cpp
@@ -180,27 +180,16 @@ nsTextNode::BindToTree(nsIDocument* aDoc
 
 void nsTextNode::UnbindFromTree(bool aDeep, bool aNullParent)
 {
   ResetDirectionSetByTextNode(this);
 
   nsGenericDOMDataNode::UnbindFromTree(aDeep, aNullParent);
 }
 
-already_AddRefed<nsTextNode>
-nsTextNode::SplitText(uint32_t aOffset, ErrorResult& rv)
-{
-  nsCOMPtr<nsIContent> newChild;
-  rv = SplitData(aOffset, getter_AddRefs(newChild));
-  if (rv.Failed()) {
-    return nullptr;
-  }
-  return static_cast<nsTextNode*>(newChild.forget().get());
-}
-
 #ifdef DEBUG
 void
 nsTextNode::List(FILE* out, int32_t aIndent) const
 {
   int32_t index;
   for (index = aIndent; --index >= 0; ) fputs("  ", out);
 
   fprintf(out, "Text@%p", static_cast<const void*>(this));
--- a/content/base/src/nsTextNode.h
+++ b/content/base/src/nsTextNode.h
@@ -5,29 +5,29 @@
 
 #ifndef nsTextNode_h
 #define nsTextNode_h
 
 /*
  * Implementation of DOM Core's nsIDOMText node.
  */
 
-#include "nsGenericDOMDataNode.h"
+#include "mozilla/dom/Text.h"
 #include "nsIDOMText.h"
 #include "nsDebug.h"
 
 /**
  * Class used to implement DOM text nodes
  */
-class nsTextNode : public nsGenericDOMDataNode,
+class nsTextNode : public mozilla::dom::Text,
                    public nsIDOMText
 {
 public:
   nsTextNode(already_AddRefed<nsINodeInfo> aNodeInfo)
-    : nsGenericDOMDataNode(aNodeInfo)
+    : mozilla::dom::Text(aNodeInfo)
   {
     NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::TEXT_NODE,
                       "Bad NodeType in aNodeInfo");
     SetIsDOMBinding();
   }
 
   virtual ~nsTextNode();
 
@@ -57,24 +57,16 @@ public:
   virtual void UnbindFromTree(bool aDeep = true,
                               bool aNullParent = true);
 
   nsresult AppendTextForNormalize(const PRUnichar* aBuffer, uint32_t aLength,
                                   bool aNotify, nsIContent* aNextSibling);
 
   virtual nsIDOMNode* AsDOMNode() { return this; }
 
-  // WebIDL API
-  already_AddRefed<nsTextNode> SplitText(uint32_t aOffset,
-                                         mozilla::ErrorResult& rv);
-  void GetWholeText(nsAString& aWholeText, mozilla::ErrorResult& rv)
-  {
-    rv = GetWholeText(aWholeText);
-  }
-
 #ifdef DEBUG
   virtual void List(FILE* out, int32_t aIndent) const;
   virtual void DumpContent(FILE* out, int32_t aIndent, bool aDumpAll) const;
 #endif
 
 protected:
   virtual JSObject* WrapNode(JSContext *aCx, JSObject *aScope,
                              bool *aTriedToWrap) MOZ_OVERRIDE;
--- a/content/xml/content/src/CDATASection.h
+++ b/content/xml/content/src/CDATASection.h
@@ -2,27 +2,27 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_CDATASection_h
 #define mozilla_dom_CDATASection_h
 
 #include "nsIDOMCDATASection.h"
-#include "nsGenericDOMDataNode.h"
+#include "mozilla/dom/Text.h"
 
 namespace mozilla {
 namespace dom {
 
-class CDATASection : public nsGenericDOMDataNode,
+class CDATASection : public Text,
                      public nsIDOMCDATASection
 {
 public:
   CDATASection(already_AddRefed<nsINodeInfo> aNodeInfo)
-    : nsGenericDOMDataNode(aNodeInfo)
+    : Text(aNodeInfo)
   {
     NS_ABORT_IF_FALSE(mNodeInfo->NodeType() == nsIDOMNode::CDATA_SECTION_NODE,
                       "Bad NodeType in aNodeInfo");
     SetIsDOMBinding();
   }
   virtual ~CDATASection();
 
   // nsISupports
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -811,17 +811,19 @@ DOMInterfaces = {
     'resultNotAddRefed': [ 'getItem' ]
 },
 
 'SVGSVGElement': {
     'resultNotAddRefed': [ 'getElementById' ]
 },
 
 'Text': {
-    'nativeType': 'nsTextNode',
+    # Total hack to allow binding code to realize that nsTextNode can
+    # in fact be cast to Text.
+    'headerFile': 'nsTextNode.h',
 },
 
 'TextDecoder': [
 {
     'nativeOwnership': 'refcounted',
 },
 {
     'workers': True,
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1724,16 +1724,28 @@ def InitUnforgeableProperties(descriptor
             CGList(unforgeables, "\n"),
             pre=("\n"
             "// Important: do unforgeable property setup after we have handed\n"
             "// over ownership of the C++ object to obj as needed, so that if\n"
             "// we fail and it ends up GCed it won't have problems in the\n"
             "// finalizer trying to drop its ownership of the C++ object.\n"),
             post="\n")).define() if len(unforgeables) > 0 else ""
 
+def AssertInheritanceChain(descriptor):
+    asserts = ""
+    iface = descriptor.interface
+    while iface:
+        desc = descriptor.getDescriptor(iface.identifier.name)
+        asserts += (
+            "  MOZ_ASSERT(static_cast<%s*>(aObject) == \n"
+            "             reinterpret_cast<%s*>(aObject));\n" %
+            (desc.nativeType, desc.nativeType))
+        iface = iface.parent
+    return asserts
+
 class CGWrapWithCacheMethod(CGAbstractMethod):
     """
     Create a wrapper JSObject for a given native that implements nsWrapperCache.
 
     properties should be a PropertyArrays instance.
     """
     def __init__(self, descriptor, properties):
         assert descriptor.interface.hasInterfacePrototypeObject()
@@ -1744,17 +1756,18 @@ class CGWrapWithCacheMethod(CGAbstractMe
         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
         self.properties = properties
 
     def definition_body(self):
         if self.descriptor.workers:
             return """  *aTriedToWrap = true;
   return aObject->GetJSObject();"""
 
-        return """  *aTriedToWrap = true;
+        return """%s
+  *aTriedToWrap = true;
 
   JSObject* parent = WrapNativeParent(aCx, aScope, aObject->GetParentObject());
   if (!parent) {
     return NULL;
   }
 
   // That might have ended up wrapping us already, due to the wonders
   // of XBL.  Check for that, and bail out as needed.  Scope so we don't
@@ -1773,17 +1786,18 @@ class CGWrapWithCacheMethod(CGAbstractMe
   if (!proto) {
     return NULL;
   }
 
 %s
 %s
   aCache->SetWrapper(obj);
 
-  return obj;""" % (CheckPref(self.descriptor, "global", "*aTriedToWrap", "NULL", "aCache"),
+  return obj;""" % (AssertInheritanceChain(self.descriptor),
+                    CheckPref(self.descriptor, "global", "*aTriedToWrap", "NULL", "aCache"),
                     CreateBindingJSObject(self.descriptor, "parent"),
                     InitUnforgeableProperties(self.descriptor, self.properties))
 
 class CGWrapMethod(CGAbstractMethod):
     def __init__(self, descriptor):
         # XXX can we wrap if we don't have an interface prototype object?
         assert descriptor.interface.hasInterfacePrototypeObject()
         args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'),
@@ -1804,26 +1818,27 @@ class CGWrapNonWrapperCacheMethod(CGAbst
         # XXX can we wrap if we don't have an interface prototype object?
         assert descriptor.interface.hasInterfacePrototypeObject()
         args = [Argument('JSContext*', 'aCx'), Argument('JSObject*', 'aScope'),
                 Argument(descriptor.nativeType + '*', 'aObject')]
         CGAbstractMethod.__init__(self, descriptor, 'Wrap', 'JSObject*', args)
         self.properties = properties
 
     def definition_body(self):
-        return """
+        return """%s
   JSObject* global = JS_GetGlobalForObject(aCx, aScope);
   JSObject* proto = GetProtoObject(aCx, global);
   if (!proto) {
     return NULL;
   }
 
 %s
 %s
-  return obj;""" % (CreateBindingJSObject(self.descriptor, "global"),
+  return obj;""" % (AssertInheritanceChain(self.descriptor),
+                    CreateBindingJSObject(self.descriptor, "global"),
                     InitUnforgeableProperties(self.descriptor, self.properties))
 
 builtinNames = {
     IDLType.Tags.bool: 'bool',
     IDLType.Tags.int8: 'int8_t',
     IDLType.Tags.int16: 'int16_t',
     IDLType.Tags.int32: 'int32_t',
     IDLType.Tags.int64: 'int64_t',