Bug 842561. Assert that our inheritance chain is correct for WebIDL objects. r=peterv
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 22 Feb 2013 09:56:29 -0500
changeset 122723 62f3d4a4421a775a3870901db8b8a11179037759
parent 122722 af5152ddbf225df680985e061f86c183b6629d1a
child 122724 76f5d877e6f6638cd061e703d27ce2d4e1e5ee23
push id23462
push userbzbarsky@mozilla.com
push dateSat, 23 Feb 2013 06:01:39 +0000
treeherdermozilla-inbound@76f5d877e6f6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspeterv
bugs842561
milestone22.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 842561. Assert that our inheritance chain is correct for WebIDL objects. r=peterv 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
@@ -820,17 +820,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
@@ -1814,16 +1814,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()
@@ -1834,17 +1846,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
@@ -1863,17 +1876,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'),
@@ -1894,26 +1908,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',